00001 #include <unistd.h>
00002 #include <math.h>
00003
00004 #include <algorithm>
00005 using namespace std;
00006
00007 #include "NuppelVideoPlayer.h"
00008 #include "remoteencoder.h"
00009 #include "mythcontext.h"
00010 #include "mythdbcon.h"
00011 #include "decoderbase.h"
00012 #include "programinfo.h"
00013 #include "livetvchain.h"
00014 #include "DVDRingBuffer.h"
00015 #include "iso639.h"
00016
00017 #define LOC QString("Dec: ")
00018 #define LOC_ERR QString("Dec, Error: ")
00019
00020 DecoderBase::DecoderBase(NuppelVideoPlayer *parent, ProgramInfo *pginfo)
00021 : m_parent(parent), m_playbackinfo(NULL),
00022
00023 ringBuffer(NULL), nvr_enc(NULL),
00024
00025 current_width(640), current_height(480),
00026 current_aspect(1.33333), fps(29.97),
00027 bitrate(4000),
00028
00029 framesPlayed(0), framesRead(0), lastKey(0), keyframedist(-1),
00030 indexOffset(0),
00031
00032 ateof(false), exitafterdecoded(false), transcoding(false),
00033
00034 hasFullPositionMap(false), recordingHasPositionMap(false),
00035 posmapStarted(false), positionMapType(MARK_UNSET),
00036 dontSyncPositionMap(false),
00037
00038 exactseeks(false), livetv(false), watchingrecording(false),
00039
00040 hasKeyFrameAdjustTable(false), lowbuffers(false),
00041 getrawframes(false), getrawvideo(false),
00042 errored(false), waitingForChange(false), readAdjust(0),
00043 justAfterChange(false),
00044
00045 languagePreference(iso639_get_language_key_list())
00046 {
00047 ResetTracks();
00048 tracks[kTrackTypeAudio].push_back(StreamInfo(0, 0, 0, 0));
00049 tracks[kTrackTypeCC608].push_back(StreamInfo(0, 0, 0, 1));
00050 tracks[kTrackTypeCC608].push_back(StreamInfo(0, 0, 2, 3));
00051
00052 if (pginfo)
00053 m_playbackinfo = new ProgramInfo(*pginfo);
00054 }
00055
00056 DecoderBase::~DecoderBase()
00057 {
00058 if (m_playbackinfo)
00059 delete m_playbackinfo;
00060 }
00061
00062 void DecoderBase::SetProgramInfo(ProgramInfo *pginfo)
00063 {
00064 if (m_playbackinfo)
00065 delete m_playbackinfo;
00066 m_playbackinfo = NULL;
00067
00068 if (pginfo)
00069 m_playbackinfo = new ProgramInfo(*pginfo);
00070 }
00071
00072 void DecoderBase::Reset(void)
00073 {
00074 SeekReset(0, 0, true, true);
00075
00076 m_positionMap.clear();
00077 framesPlayed = 0;
00078 framesRead = 0;
00079
00080 ateof = false;
00081 }
00082
00083 void DecoderBase::SeekReset(long long, uint, bool, bool)
00084 {
00085 readAdjust = 0;
00086 }
00087
00088 void DecoderBase::setWatchingRecording(bool mode)
00089 {
00090 bool wereWatchingRecording = watchingrecording;
00091
00092
00093
00094 posmapStarted = false;
00095 watchingrecording = mode;
00096
00097 if (wereWatchingRecording && !watchingrecording)
00098 SyncPositionMap();
00099 }
00100
00101 bool DecoderBase::PosMapFromDb(void)
00102 {
00103 if (!m_playbackinfo)
00104 return false;
00105
00106
00107 QMap<long long, long long> posMap;
00108
00109 if (ringBuffer->isDVD())
00110 {
00111 long long totframes;
00112 keyframedist = 15;
00113 fps = ringBuffer->DVD()->GetFrameRate();
00114 if (fps < 26 && fps > 24)
00115 keyframedist = 12;
00116 totframes = (long long)(ringBuffer->DVD()->GetTotalTimeOfTitle() * fps);
00117 posMap[totframes] = ringBuffer->DVD()->GetTotalReadPosition();
00118 }
00119 else if ((positionMapType == MARK_UNSET) ||
00120 (keyframedist == -1))
00121 {
00122 m_playbackinfo->GetPositionMap(posMap, MARK_GOP_BYFRAME);
00123 if (!posMap.empty())
00124 {
00125 positionMapType = MARK_GOP_BYFRAME;
00126 if (keyframedist == -1)
00127 keyframedist = 1;
00128 }
00129 else
00130 {
00131 m_playbackinfo->GetPositionMap(posMap, MARK_GOP_START);
00132 if (!posMap.empty())
00133 {
00134 positionMapType = MARK_GOP_START;
00135 if (keyframedist == -1)
00136 {
00137 keyframedist = 15;
00138 if (fps < 26 && fps > 24)
00139 keyframedist = 12;
00140 }
00141 }
00142 else
00143 {
00144 m_playbackinfo->GetPositionMap(posMap, MARK_KEYFRAME);
00145 if (!posMap.empty())
00146 {
00147
00148
00149 positionMapType = MARK_KEYFRAME;
00150 }
00151 }
00152 }
00153 }
00154 else
00155 {
00156 m_playbackinfo->GetPositionMap(posMap, positionMapType);
00157 }
00158
00159 if (posMap.empty())
00160 return false;
00161
00162 m_positionMap.clear();
00163 m_positionMap.reserve(posMap.size());
00164
00165 for (QMap<long long,long long>::const_iterator it = posMap.begin();
00166 it != posMap.end(); it++)
00167 {
00168 PosMapEntry e = {it.key(), it.key() * keyframedist, it.data()};
00169 m_positionMap.push_back(e);
00170 }
00171 if (!m_positionMap.empty())
00172 {
00173 VERBOSE(VB_PLAYBACK, QString("Position map filled from DB to: %1")
00174 .arg((long int) m_positionMap[m_positionMap.size()-1].index));
00175 if (!ringBuffer->isDVD())
00176 indexOffset = m_positionMap[0].index;
00177 }
00178
00179 return true;
00180 }
00181
00182 bool DecoderBase::PosMapFromEnc(void)
00183 {
00184
00185 if (!(livetv || (nvr_enc && nvr_enc->IsValidRecorder())))
00186 return false;
00187
00188
00189 if (livetv)
00190 {
00191 LiveTVChain *chain = m_parent->GetTVChain();
00192 if (chain->HasNext())
00193 return false;
00194 }
00195
00196 QMap<long long, long long> posMap;
00197
00198 int start = 0;
00199 unsigned int size = m_positionMap.size();
00200 if (size > 0)
00201 start = m_positionMap[size-1].index + 1;
00202
00203 int end = nvr_enc->GetFramesWritten();
00204
00205 if (!end)
00206 {
00207 VERBOSE(VB_PLAYBACK, QString("PosMapFromEnc: Warning, tried to fetch "
00208 "PositionMap from Encoder but encoder "
00209 "returned framesWritten == 0"));
00210 return false;
00211 }
00212
00213 if (size > 0 && keyframedist > 0)
00214 end /= keyframedist;
00215
00216 VERBOSE(VB_PLAYBACK, QString("Filling position map from %1 to %2")
00217 .arg(start).arg(end));
00218
00219 nvr_enc->FillPositionMap(start, end, posMap);
00220 if (keyframedist == -1 && posMap.size() > 1)
00221 {
00222
00223
00224 QMap<long long,long long>::const_iterator i1 = posMap.begin();
00225 QMap<long long,long long>::const_iterator i2 = i1;
00226 i2++;
00227 if (i1.key() + 1 == i2.key())
00228 {
00229
00230 positionMapType = MARK_GOP_START;
00231 keyframedist = 15;
00232 if (fps < 26 && fps > 24)
00233 keyframedist = 12;
00234 }
00235 else
00236 {
00237
00238 positionMapType = MARK_GOP_BYFRAME;
00239 keyframedist = 1;
00240 }
00241 }
00242
00243
00244 m_positionMap.reserve(m_positionMap.size() + posMap.size());
00245 for (QMap<long long,long long>::const_iterator it = posMap.begin();
00246 it != posMap.end(); it++)
00247 {
00248 PosMapEntry e = {it.key(), it.key() * keyframedist, it.data()};
00249 m_positionMap.push_back(e);
00250 }
00251 if (!m_positionMap.empty())
00252 {
00253 VERBOSE(VB_PLAYBACK, QString("Position map filled from Encoder to: %1")
00254 .arg((long int) m_positionMap[m_positionMap.size()-1].index));
00255 }
00256
00257 return true;
00258 }
00259
00282 bool DecoderBase::SyncPositionMap(void)
00283 {
00284 VERBOSE(VB_PLAYBACK, "Resyncing position map. posmapStarted = "
00285 << (int) posmapStarted << " livetv(" << livetv << ") "
00286 << "watchingRec(" << watchingrecording << ")");
00287
00288 if (dontSyncPositionMap)
00289 return false;
00290
00291 unsigned int old_posmap_size = m_positionMap.size();
00292
00293 if (livetv || watchingrecording)
00294 {
00295 if (!posmapStarted)
00296 {
00297
00298 PosMapFromDb();
00299 VERBOSE(VB_PLAYBACK,
00300 QString("SyncPositionMap watchingrecording, from DB: "
00301 "%1 entries")
00302 .arg(m_positionMap.size()));
00303 }
00304
00305 if (!PosMapFromEnc())
00306 {
00307 VERBOSE(VB_PLAYBACK,
00308 QString("SyncPositionMap watchingrecording no entries "
00309 "from encoder, try DB"));
00310 PosMapFromDb();
00311 }
00312 VERBOSE(VB_PLAYBACK,
00313 QString("SyncPositionMap watchingrecording total: %1 entries")
00314 .arg(m_positionMap.size()));
00315 }
00316 else
00317 {
00318
00319 if (!posmapStarted)
00320 {
00321 PosMapFromDb();
00322 VERBOSE(VB_PLAYBACK,
00323 QString("SyncPositionMap prerecorded, from DB: %1 entries")
00324 .arg(m_positionMap.size()));
00325 }
00326 }
00327
00328 bool ret_val = m_positionMap.size() > old_posmap_size;
00329 if (ret_val && keyframedist > 0)
00330 {
00331 long long totframes;
00332 int length;
00333
00334 if (ringBuffer->isDVD())
00335 {
00336 totframes = m_positionMap[m_positionMap.size() - 1].index;
00337 length = ringBuffer->DVD()->GetTotalTimeOfTitle();
00338 }
00339 else
00340 {
00341 totframes =
00342 m_positionMap[m_positionMap.size()-1].index * keyframedist;
00343 length = (int)((totframes * 1.0) / fps);
00344 }
00345
00346 GetNVP()->SetFileLength(length, totframes);
00347 GetNVP()->SetKeyframeDistance(keyframedist);
00348 posmapStarted = true;
00349
00350 VERBOSE(VB_PLAYBACK,
00351 QString("SyncPositionMap, new totframes: %1, new length: %2, "
00352 "posMap size: %3")
00353 .arg((long)totframes).arg(length)
00354 .arg(m_positionMap.size()));
00355 }
00356 recordingHasPositionMap |= !m_positionMap.empty();
00357 return ret_val;
00358 }
00359
00360
00361
00362 bool DecoderBase::FindPosition(long long desired_value, bool search_adjusted,
00363 int &lower_bound, int &upper_bound)
00364 {
00365
00366 long long size = (long long) m_positionMap.size();
00367 long long lower = -1;
00368 long long upper = size;
00369
00370 if (!search_adjusted && keyframedist > 0)
00371 desired_value /= keyframedist;
00372
00373 while (upper - 1 > lower)
00374 {
00375 long long i = (upper + lower) / 2;
00376 long long value;
00377 if (search_adjusted)
00378 value = m_positionMap[i].adjFrame;
00379 else
00380 value = m_positionMap[i].index - indexOffset;
00381 if (value == desired_value)
00382 {
00383
00384 upper_bound = i;
00385 lower_bound = i;
00386 return true;
00387 }
00388 else if (value > desired_value)
00389 upper = i;
00390 else
00391 lower = i;
00392 }
00393
00394
00395 if (search_adjusted)
00396 {
00397 while (lower >= 0 && m_positionMap[lower].adjFrame > desired_value)
00398 lower--;
00399 while (upper < size && m_positionMap[upper].adjFrame < desired_value)
00400 upper++;
00401 }
00402 else
00403 {
00404 while (lower >= 0 &&
00405 (m_positionMap[lower].index - indexOffset) > desired_value)
00406 lower--;
00407 while (upper < size &&
00408 (m_positionMap[upper].index - indexOffset) < desired_value)
00409 upper++;
00410 }
00411
00412 lower = max(lower, 0LL);
00413 upper = min(upper, size - 1LL);
00414
00415 upper_bound = upper;
00416 lower_bound = lower;
00417 return false;
00418 }
00419
00420 void DecoderBase::SetPositionMap(void)
00421 {
00422 if (m_playbackinfo && (positionMapType != MARK_UNSET))
00423 {
00424 QMap<long long, long long> posMap;
00425 for (unsigned int i=0; i < m_positionMap.size(); i++)
00426 posMap[m_positionMap[i].index] = m_positionMap[i].pos;
00427
00428 m_playbackinfo->SetPositionMap(posMap, positionMapType);
00429 }
00430 }
00431
00432 bool DecoderBase::DoRewind(long long desiredFrame, bool discardFrames)
00433 {
00434 VERBOSE(VB_PLAYBACK, LOC +
00435 QString("DoRewind(%1 (%2), %3 discard frames)")
00436 .arg(desiredFrame).arg(framesPlayed)
00437 .arg((discardFrames) ? "do" : "don't"));
00438
00439 if (m_positionMap.empty())
00440 return false;
00441
00442 if (!DoRewindSeek(desiredFrame))
00443 return false;
00444
00445 framesPlayed = lastKey;
00446 framesRead = lastKey;
00447
00448
00449
00450 int normalframes = (exactseeks) ? desiredFrame - framesPlayed : 0;
00451 normalframes = max(normalframes, 0);
00452 SeekReset(lastKey, normalframes, true, discardFrames);
00453
00454 if (ringBuffer->isDVD() || discardFrames)
00455 {
00456
00457 GetNVP()->SetFramesPlayed(framesPlayed+1);
00458 GetNVP()->getVideoOutput()->SetFramesPlayed(framesPlayed+1);
00459 }
00460
00461 return true;
00462 }
00463
00464 long long DecoderBase::GetKey(PosMapEntry &e) const
00465 {
00466 long long kf = (ringBuffer->isDVD()) ? 1LL : keyframedist;
00467 return (hasKeyFrameAdjustTable) ? e.adjFrame :(e.index - indexOffset) * kf;
00468 }
00469
00470 bool DecoderBase::DoRewindSeek(long long desiredFrame)
00471 {
00472 if (ringBuffer->isDVD())
00473 {
00474 long long pos = DVDFindPosition(desiredFrame);
00475 ringBuffer->Seek(pos, SEEK_SET);
00476 lastKey = desiredFrame + 1;
00477 return true;
00478 }
00479
00480
00481 int pre_idx, post_idx;
00482 FindPosition(desiredFrame, hasKeyFrameAdjustTable, pre_idx, post_idx);
00483
00484 uint pos_idx = min(pre_idx, post_idx);
00485 PosMapEntry e = m_positionMap[pos_idx];
00486 lastKey = GetKey(e);
00487
00488
00489 while (e.pos < 0)
00490 {
00491 pos_idx++;
00492 if (pos_idx >= m_positionMap.size())
00493 return false;
00494
00495 e = m_positionMap[pos_idx];
00496 lastKey = GetKey(e);
00497 }
00498
00499 ringBuffer->Seek(e.pos, SEEK_SET);
00500
00501 return true;
00502 }
00503
00504 long long DecoderBase::GetLastFrameInPosMap(long long desiredFrame)
00505 {
00506 long long last_frame = 0;
00507 if (!m_positionMap.empty())
00508 last_frame = GetKey(m_positionMap.back());
00509
00510
00511
00512 if ((desiredFrame >= 0) && (desiredFrame > last_frame))
00513 {
00514 VERBOSE(VB_PLAYBACK, LOC + "DoFastForward: "
00515 "Not enough info in positionMap," +
00516 QString("\n\t\t\twe need frame %1 but highest we have is %2.")
00517 .arg((long int)desiredFrame).arg((long int)last_frame));
00518
00519 SyncPositionMap();
00520
00521 if (!m_positionMap.empty())
00522 last_frame = GetKey(m_positionMap.back());
00523
00524 if (desiredFrame > last_frame)
00525 {
00526 VERBOSE(VB_PLAYBACK, LOC + "DoFastForward: "
00527 "Still not enough info in positionMap after sync, " +
00528 QString("\n\t\t\twe need frame %1 but highest we have "
00529 "is %2. Will seek frame-by-frame")
00530 .arg((long int)desiredFrame).arg((long int)last_frame));
00531 }
00532 }
00533 return last_frame;
00534 }
00535
00545 bool DecoderBase::DoFastForward(long long desiredFrame, bool discardFrames)
00546 {
00547 VERBOSE(VB_PLAYBACK, LOC +
00548 QString("DoFastForward(%1 (%2), %3 discard frames)")
00549 .arg(desiredFrame).arg(framesPlayed)
00550 .arg((discardFrames) ? "do" : "don't"));
00551
00552 if (ringBuffer->isDVD() &&
00553 ringBuffer->DVD()->TitleTimeLeft() < 5 &&
00554 !ringBuffer->InDVDMenuOrStillFrame())
00555 {
00556 return false;
00557 }
00558
00559
00560
00561
00562
00563 if (desiredFrame+1 < framesPlayed)
00564 return DoRewind(desiredFrame, discardFrames);
00565 desiredFrame = max(desiredFrame, framesPlayed);
00566
00567
00568 bool oldrawstate = getrawframes;
00569 getrawframes = false;
00570
00571
00572 long long last_frame = GetLastFrameInPosMap(desiredFrame);
00573
00574
00575
00576 bool needflush = false;
00577 if (desiredFrame > last_frame)
00578 {
00579 needflush = true;
00580
00581 exitafterdecoded = true;
00582 while ((desiredFrame > last_frame) && !ateof)
00583 {
00584 GetFrame(-1);
00585 last_frame = GetLastFrameInPosMap(-1);
00586 }
00587 exitafterdecoded = false;
00588
00589 if (ateof)
00590 {
00591
00592 getrawframes = oldrawstate;
00593 return false;
00594 }
00595 }
00596
00597 if (m_positionMap.empty())
00598 {
00599
00600 getrawframes = oldrawstate;
00601 return false;
00602 }
00603
00604
00605 DoFastForwardSeek(desiredFrame, needflush);
00606
00607
00608
00609 int normalframes = (exactseeks) ? desiredFrame - framesPlayed : 0;
00610 normalframes = max(normalframes, 0);
00611 SeekReset(lastKey, normalframes, needflush, discardFrames);
00612
00613 if (discardFrames)
00614 {
00615
00616 GetNVP()->SetFramesPlayed(framesPlayed+1);
00617 GetNVP()->getVideoOutput()->SetFramesPlayed(framesPlayed+1);
00618 }
00619
00620
00621 getrawframes = oldrawstate;
00622
00623 return true;
00624 }
00625
00640 void DecoderBase::DoFastForwardSeek(long long desiredFrame, bool &needflush)
00641 {
00642 if (ringBuffer->isDVD())
00643 {
00644 long long pos = DVDFindPosition(desiredFrame);
00645 ringBuffer->Seek(pos,SEEK_SET);
00646 needflush = true;
00647 lastKey = desiredFrame+1;
00648 framesPlayed = lastKey;
00649 framesRead = lastKey;
00650 return;
00651 }
00652
00653 int pre_idx, post_idx;
00654 FindPosition(desiredFrame, hasKeyFrameAdjustTable, pre_idx, post_idx);
00655
00656
00657 uint pos_idx = (exactseeks) ? pre_idx : max(pre_idx, post_idx);
00658
00659 PosMapEntry e = m_positionMap[pos_idx];
00660 lastKey = GetKey(e);
00661
00662 if (framesPlayed < lastKey)
00663 {
00664 ringBuffer->Seek(e.pos, SEEK_SET);
00665 needflush = true;
00666 framesPlayed = lastKey;
00667 framesRead = lastKey;
00668 }
00669 }
00670
00671 void DecoderBase::UpdateFramesPlayed(void)
00672 {
00673 GetNVP()->SetFramesPlayed(framesPlayed);
00674 }
00675
00676 void DecoderBase::FileChanged(void)
00677 {
00678 m_positionMap.clear();
00679 framesPlayed = 0;
00680 framesRead = 0;
00681
00682 waitingForChange = false;
00683 justAfterChange = true;
00684
00685 GetNVP()->FileChangedCallback();
00686 }
00687
00688 void DecoderBase::SetReadAdjust(long long adjust)
00689 {
00690 readAdjust = adjust;
00691 }
00692
00693 void DecoderBase::SetWaitForChange(void)
00694 {
00695 waitingForChange = true;
00696 }
00697
00698 bool DecoderBase::GetWaitForChange(void)
00699 {
00700 return waitingForChange;
00701 }
00702
00703 void DecoderBase::ChangeDVDTrack(bool ffw)
00704 {
00705 if (!ringBuffer->isDVD())
00706 return;
00707
00708 bool result = true;
00709
00710 if (ffw)
00711 result = ringBuffer->DVD()->nextTrack();
00712 else
00713 ringBuffer->DVD()->prevTrack();
00714
00715 if (result)
00716 {
00717 uint elapsed = ringBuffer->DVD()->GetCellStart();
00718
00719 UpdateDVDFramesPlayed();
00720
00721 if (elapsed == 0)
00722 SeekReset(framesPlayed, 0, true, true);
00723 }
00724 }
00725
00726 long long DecoderBase::DVDFindPosition(long long desiredFrame)
00727 {
00728 if (!ringBuffer->isDVD())
00729 return 0;
00730 int diffTime = 0;
00731 long long desiredTimePos;
00732 int ffrewSkip = 1;
00733 int current_speed = 0;
00734 if (GetNVP())
00735 {
00736 ffrewSkip = GetNVP()->GetFFRewSkip();
00737 current_speed = (int)GetNVP()->GetNextPlaySpeed();
00738 }
00739
00740 if (ffrewSkip == 1)
00741 {
00742 diffTime = (int)ceil((desiredFrame - framesPlayed) / fps);
00743 desiredTimePos = ringBuffer->DVD()->GetCurrentTime() +
00744 diffTime;
00745 if (diffTime <= 0)
00746 desiredTimePos--;
00747 else
00748 desiredTimePos++;
00749
00750 if (desiredTimePos < 0)
00751 desiredTimePos = 0;
00752 return (desiredTimePos * 90000LL);
00753 }
00754 return current_speed;
00755 }
00756
00757
00758 void DecoderBase::UpdateDVDFramesPlayed(void)
00759 {
00760 if (!ringBuffer->isDVD())
00761 return;
00762 long long currentpos = (long long)(ringBuffer->DVD()->GetCurrentTime() * fps);
00763 framesPlayed = framesRead = currentpos ;
00764 GetNVP()->getVideoOutput()->SetFramesPlayed(currentpos + 1);
00765 GetNVP()->SetFramesPlayed(currentpos + 1);
00766 }
00767
00768 QStringList DecoderBase::GetTracks(uint type) const
00769 {
00770 QStringList list;
00771
00772 QMutexLocker locker(&avcodeclock);
00773
00774 for (uint i = 0; i < tracks[type].size(); i++)
00775 list += GetTrackDesc(type, i);
00776
00777 return list;
00778 }
00779
00780 int DecoderBase::GetTrackLanguageIndex(uint type, uint trackNo) const
00781 {
00782 if (trackNo >= tracks[type].size())
00783 return 0;
00784
00785 return tracks[type][trackNo].language_index;
00786 }
00787
00788 QString DecoderBase::GetTrackDesc(uint type, uint trackNo) const
00789 {
00790 if (trackNo >= tracks[type].size())
00791 return "";
00792
00793 QMutexLocker locker(&avcodeclock);
00794
00795 QString type_msg = track_type_to_string(type);
00796 int lang = tracks[type][trackNo].language;
00797 int hnum = trackNo + 1;
00798 if (kTrackTypeCC608 == type)
00799 hnum = tracks[type][trackNo].stream_id;
00800
00801 if (!lang)
00802 return type_msg + QString(" %1").arg(hnum);
00803 else
00804 {
00805 QString lang_msg = iso639_key_toName(lang);
00806 return type_msg + QString(" %1: %2").arg(hnum).arg(lang_msg);
00807 }
00808 }
00809
00810 int DecoderBase::SetTrack(uint type, int trackNo)
00811 {
00812 if (trackNo >= (int)tracks[type].size())
00813 return false;
00814
00815 QMutexLocker locker(&avcodeclock);
00816
00817 currentTrack[type] = max(-1, trackNo);
00818
00819 if (currentTrack[type] < 0)
00820 selectedTrack[type].av_stream_index = -1;
00821 else
00822 {
00823 wantedTrack[type] = tracks[type][currentTrack[type]];
00824 selectedTrack[type] = tracks[type][currentTrack[type]];
00825 }
00826
00827 return currentTrack[type];
00828 }
00829
00830 StreamInfo DecoderBase::GetTrackInfo(uint type, uint trackNo) const
00831 {
00832 QMutexLocker locker(&avcodeclock);
00833
00834 if (trackNo >= tracks[type].size())
00835 {
00836 StreamInfo si;
00837 return si;
00838 }
00839
00840 return tracks[type][trackNo];
00841 }
00842
00843 bool DecoderBase::InsertTrack(uint type, const StreamInfo &info)
00844 {
00845 QMutexLocker locker(&avcodeclock);
00846
00847 for (uint i = 0; i < tracks[type].size(); i++)
00848 if (info.stream_id == tracks[type][i].stream_id)
00849 return false;
00850
00851 tracks[type].push_back(info);
00852
00853 if (GetNVP())
00854 GetNVP()->TracksChanged(type);
00855
00856 return true;
00857 }
00858
00874 int DecoderBase::AutoSelectTrack(uint type)
00875 {
00876 uint numStreams = tracks[type].size();
00877
00878 if ((currentTrack[type] >= 0) &&
00879 (currentTrack[type] < (int)numStreams))
00880 {
00881 return true;
00882 }
00883
00884 if (!numStreams)
00885 {
00886 currentTrack[type] = -1;
00887 selectedTrack[type].av_stream_index = -1;
00888 return false;
00889 }
00890
00891 int selTrack = (1 == numStreams) ? 0 : -1;
00892
00893 if ((selTrack < 0) &&
00894 wantedTrack[type].language>=-1 && numStreams)
00895 {
00896 VERBOSE(VB_PLAYBACK, LOC + "Trying to reselect track");
00897
00898
00899
00900 int wlang = wantedTrack[type].language;
00901 uint windx = wantedTrack[type].language_index;
00902 for (uint i = 0; i < numStreams; i++)
00903 {
00904 if (wlang == tracks[type][i].language)
00905 selTrack = i;
00906 if (windx == tracks[type][i].language_index)
00907 break;
00908 }
00909 }
00910
00911 if (selTrack < 0 && numStreams)
00912 {
00913 VERBOSE(VB_PLAYBACK, LOC + "Trying to select track (w/lang)");
00914
00915
00916 vector<int>::iterator it = languagePreference.begin();
00917 for (; it != languagePreference.end() && (selTrack < 0); ++it)
00918 {
00919 for (uint i = 0; i < numStreams; i++)
00920 {
00921 if (*it == tracks[type][i].language)
00922 {
00923 selTrack = i;
00924 break;
00925 }
00926 }
00927 }
00928 }
00929
00930 if (selTrack < 0 && numStreams)
00931 {
00932 VERBOSE(VB_PLAYBACK, LOC + "Selecting first track");
00933 selTrack = 0;
00934 }
00935
00936 int oldTrack = currentTrack[type];
00937 currentTrack[type] = (selTrack < 0) ? -1 : selTrack;
00938 StreamInfo tmp = tracks[type][currentTrack[type]];
00939 selectedTrack[type] = tmp;
00940
00941 if (wantedTrack[type].av_stream_index < 0)
00942 wantedTrack[type] = tmp;
00943
00944 int lang = tracks[type][currentTrack[type]].language;
00945 VERBOSE(VB_PLAYBACK, LOC +
00946 QString("Selected track #%1 in the %2 language(%3)")
00947 .arg(currentTrack[type]+1)
00948 .arg(iso639_key_toName(lang)).arg(lang));
00949
00950 if (GetNVP() && (oldTrack != currentTrack[type]))
00951 GetNVP()->TracksChanged(type);
00952
00953 return selTrack;
00954 }
00955
00956