00001 #include <unistd.h>
00002 #include <math.h>
00003
00004 #include <algorithm>
00005 using namespace std;
00006
00007 #include "mythconfig.h"
00008
00009 #include "mythplayer.h"
00010 #include "remoteencoder.h"
00011 #include "mythdbcon.h"
00012 #include "mythlogging.h"
00013 #include "decoderbase.h"
00014 #include "programinfo.h"
00015 #include "livetvchain.h"
00016 #include "iso639.h"
00017 #include "DVD/dvdringbuffer.h"
00018 #include "Bluray/bdringbuffer.h"
00019
00020 #define LOC QString("Dec: ")
00021
00022 DecoderBase::DecoderBase(MythPlayer *parent, const ProgramInfo &pginfo)
00023 : m_parent(parent), m_playbackinfo(new ProgramInfo(pginfo)),
00024 m_audio(m_parent->GetAudio()), ringBuffer(NULL),
00025
00026 current_width(640), current_height(480),
00027 current_aspect(1.33333), fps(29.97),
00028 bitrate(4000),
00029
00030 framesPlayed(0), framesRead(0), totalDuration(0),
00031 lastKey(0), keyframedist(-1), indexOffset(0),
00032
00033 ateof(false), exitafterdecoded(false), transcoding(false),
00034
00035 hasFullPositionMap(false), recordingHasPositionMap(false),
00036 posmapStarted(false), positionMapType(MARK_UNSET),
00037
00038 m_positionMapLock(QMutex::Recursive),
00039 dontSyncPositionMap(false),
00040
00041 seeksnap(-1), livetv(false), watchingrecording(false),
00042
00043 hasKeyFrameAdjustTable(false), lowbuffers(false),
00044 getrawframes(false), getrawvideo(false),
00045 errored(false), waitingForChange(false), readAdjust(0),
00046 justAfterChange(false),
00047 decodeAllSubtitles(false),
00048
00049 languagePreference(iso639_get_language_key_list())
00050 {
00051 ResetTracks();
00052 tracks[kTrackTypeAudio].push_back(StreamInfo(0, 0, 0, 0, 0));
00053 tracks[kTrackTypeCC608].push_back(StreamInfo(0, 0, 0, 1, 0));
00054 tracks[kTrackTypeCC608].push_back(StreamInfo(0, 0, 2, 3, 0));
00055 }
00056
00057 DecoderBase::~DecoderBase()
00058 {
00059 if (m_playbackinfo)
00060 delete m_playbackinfo;
00061 }
00062
00063 void DecoderBase::SetProgramInfo(const ProgramInfo &pginfo)
00064 {
00065 if (m_playbackinfo)
00066 delete m_playbackinfo;
00067 m_playbackinfo = new ProgramInfo(pginfo);
00068 }
00069
00070 void DecoderBase::Reset(bool reset_video_data, bool seek_reset, bool reset_file)
00071 {
00072 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00073 QString("Reset: Video %1, Seek %2, File %3")
00074 .arg(reset_video_data).arg(seek_reset).arg(reset_file));
00075
00076 if (seek_reset)
00077 {
00078 SeekReset(0, 0, true, true);
00079 }
00080
00081 if (reset_video_data)
00082 {
00083 ResetPosMap();
00084 framesPlayed = 0;
00085 framesRead = 0;
00086 totalDuration = 0;
00087 dontSyncPositionMap = false;
00088 }
00089
00090 if (reset_file)
00091 {
00092 waitingForChange = false;
00093 SetEof(false);
00094 }
00095 }
00096
00097 void DecoderBase::SeekReset(long long, uint, bool, bool)
00098 {
00099 readAdjust = 0;
00100 }
00101
00102 void DecoderBase::SetWatchingRecording(bool mode)
00103 {
00104 bool wereWatchingRecording = watchingrecording;
00105
00106
00107
00108 posmapStarted = false;
00109 watchingrecording = mode;
00110
00111 if (wereWatchingRecording && !watchingrecording)
00112 SyncPositionMap();
00113 }
00114
00115 bool DecoderBase::PosMapFromDb(void)
00116 {
00117 if (!m_playbackinfo)
00118 return false;
00119
00120
00121 frm_pos_map_t posMap;
00122
00123 if (ringBuffer->IsDVD())
00124 {
00125 long long totframes;
00126 keyframedist = 15;
00127 fps = ringBuffer->DVD()->GetFrameRate();
00128 if (fps < 26 && fps > 24)
00129 keyframedist = 12;
00130 totframes = (long long)(ringBuffer->DVD()->GetTotalTimeOfTitle() * fps);
00131 posMap[totframes] = ringBuffer->DVD()->GetTotalReadPosition();
00132 }
00133 else if (ringBuffer->IsBD())
00134 {
00135 long long totframes;
00136 keyframedist = 15;
00137 fps = ringBuffer->BD()->GetFrameRate();
00138 if (fps < 26 && fps > 24)
00139 keyframedist = 12;
00140 totframes = (long long)(ringBuffer->BD()->GetTotalTimeOfTitle() * fps);
00141 posMap[totframes] = ringBuffer->BD()->GetTotalReadPosition();
00142 #if 0
00143 LOG(VB_PLAYBACK, LOG_DEBUG, LOC +
00144 QString("%1 TotalTimeOfTitle() in ticks, %2 TotalReadPosition() "
00145 "in bytes, %3 is fps")
00146 .arg(ringBuffer->BD()->GetTotalTimeOfTitle())
00147 .arg(ringBuffer->BD()->GetTotalReadPosition()).arg(fps));
00148 #endif
00149 }
00150 else if ((positionMapType == MARK_UNSET) ||
00151 (keyframedist == -1))
00152 {
00153 m_playbackinfo->QueryPositionMap(posMap, MARK_GOP_BYFRAME);
00154 if (!posMap.empty())
00155 {
00156 positionMapType = MARK_GOP_BYFRAME;
00157 if (keyframedist == -1)
00158 keyframedist = 1;
00159 }
00160 else
00161 {
00162 m_playbackinfo->QueryPositionMap(posMap, MARK_GOP_START);
00163 if (!posMap.empty())
00164 {
00165 positionMapType = MARK_GOP_START;
00166 if (keyframedist == -1)
00167 {
00168 keyframedist = 15;
00169 if (fps < 26 && fps > 24)
00170 keyframedist = 12;
00171 }
00172 }
00173 else
00174 {
00175 m_playbackinfo->QueryPositionMap(posMap, MARK_KEYFRAME);
00176 if (!posMap.empty())
00177 {
00178
00179
00180 positionMapType = MARK_KEYFRAME;
00181 }
00182 }
00183 }
00184 }
00185 else
00186 {
00187 m_playbackinfo->QueryPositionMap(posMap, positionMapType);
00188 }
00189
00190 if (posMap.empty())
00191 return false;
00192
00193 QMutexLocker locker(&m_positionMapLock);
00194 m_positionMap.clear();
00195 m_positionMap.reserve(posMap.size());
00196
00197 for (frm_pos_map_t::const_iterator it = posMap.begin();
00198 it != posMap.end(); ++it)
00199 {
00200 PosMapEntry e = {it.key(), it.key() * keyframedist, *it};
00201 m_positionMap.push_back(e);
00202 }
00203
00204 if (!m_positionMap.empty() && !ringBuffer->IsDisc())
00205 indexOffset = m_positionMap[0].index;
00206
00207 if (!m_positionMap.empty())
00208 {
00209 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00210 QString("Position map filled from DB to: %1")
00211 .arg(m_positionMap.back().index));
00212 }
00213
00214 return true;
00215 }
00216
00225 bool DecoderBase::PosMapFromEnc(void)
00226 {
00227 if (!m_parent || keyframedist < 1)
00228 return false;
00229
00230 unsigned long long start = 0;
00231 {
00232 QMutexLocker locker(&m_positionMapLock);
00233 if (!m_positionMap.empty())
00234 start = m_positionMap.back().index + 1;
00235 }
00236
00237 QMap<long long, long long> posMap;
00238 if (!m_parent->PosMapFromEnc(start, posMap))
00239 return false;
00240
00241 QMutexLocker locker(&m_positionMapLock);
00242
00243
00244 m_positionMap.reserve(m_positionMap.size() + posMap.size());
00245 long long last_index = m_positionMap.back().index;
00246 for (QMap<long long,long long>::const_iterator it = posMap.begin();
00247 it != posMap.end(); ++it)
00248 {
00249 if (it.key() <= last_index)
00250 continue;
00251
00252 PosMapEntry e = {it.key(), it.key() * keyframedist, *it};
00253 m_positionMap.push_back(e);
00254 }
00255
00256 if (!m_positionMap.empty() && !ringBuffer->IsDisc())
00257 indexOffset = m_positionMap[0].index;
00258
00259 if (!m_positionMap.empty())
00260 {
00261 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00262 QString("Position map filled from Encoder to: %1")
00263 .arg(m_positionMap.back().index));
00264 }
00265
00266 return true;
00267 }
00268
00269 unsigned long DecoderBase::GetPositionMapSize(void) const
00270 {
00271 QMutexLocker locker(&m_positionMapLock);
00272 return (unsigned long) m_positionMap.size();
00273 }
00274
00297 bool DecoderBase::SyncPositionMap(void)
00298 {
00299 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00300 QString("Resyncing position map. posmapStarted = %1"
00301 " livetv(%2) watchingRec(%3)")
00302 .arg((int) posmapStarted).arg(livetv).arg(watchingrecording));
00303
00304 if (dontSyncPositionMap)
00305 return false;
00306
00307 unsigned long old_posmap_size = GetPositionMapSize();
00308 unsigned long new_posmap_size = old_posmap_size;
00309
00310 if (livetv || watchingrecording)
00311 {
00312 if (!posmapStarted)
00313 {
00314
00315 PosMapFromDb();
00316 new_posmap_size = GetPositionMapSize();
00317 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00318 QString("SyncPositionMap watchingrecording, from DB: "
00319 "%1 entries") .arg(new_posmap_size));
00320 }
00321
00322 if (!PosMapFromEnc())
00323 {
00324 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00325 QString("SyncPositionMap watchingrecording no entries "
00326 "from encoder, try DB"));
00327 PosMapFromDb();
00328 }
00329
00330 new_posmap_size = GetPositionMapSize();
00331 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00332 QString("SyncPositionMap watchingrecording total: %1 entries")
00333 .arg(new_posmap_size));
00334 }
00335 else
00336 {
00337
00338 if (!posmapStarted)
00339 {
00340 PosMapFromDb();
00341
00342 new_posmap_size = GetPositionMapSize();
00343 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00344 QString("SyncPositionMap prerecorded, from DB: %1 entries")
00345 .arg(new_posmap_size));
00346 }
00347 }
00348
00349 bool ret_val = new_posmap_size > old_posmap_size;
00350
00351 if (ret_val && keyframedist > 0)
00352 {
00353 long long totframes = 0;
00354 int length = 0;
00355
00356 if (ringBuffer->IsDVD())
00357 {
00358 length = ringBuffer->DVD()->GetTotalTimeOfTitle();
00359 QMutexLocker locker(&m_positionMapLock);
00360 totframes = m_positionMap.back().index;
00361 }
00362 else if (ringBuffer->IsBD())
00363 {
00364 length = ringBuffer->BD()->GetTotalTimeOfTitle();
00365 QMutexLocker locker(&m_positionMapLock);
00366 totframes = m_positionMap.back().index;
00367 }
00368 else
00369 {
00370 QMutexLocker locker(&m_positionMapLock);
00371 totframes = m_positionMap.back().index * keyframedist;
00372 if (fps)
00373 length = (int)((totframes * 1.0) / fps);
00374 }
00375
00376 m_parent->SetFileLength(length, totframes);
00377 m_parent->SetKeyframeDistance(keyframedist);
00378 posmapStarted = true;
00379
00380 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00381 QString("SyncPositionMap, new totframes: %1, new length: %2, "
00382 "posMap size: %3")
00383 .arg(totframes).arg(length).arg(new_posmap_size));
00384 }
00385 recordingHasPositionMap |= (0 != new_posmap_size);
00386 return ret_val;
00387 }
00388
00389
00390
00391 bool DecoderBase::FindPosition(long long desired_value, bool search_adjusted,
00392 int &lower_bound, int &upper_bound)
00393 {
00394 QMutexLocker locker(&m_positionMapLock);
00395
00396 long long size = (long long) m_positionMap.size();
00397 long long lower = -1;
00398 long long upper = size;
00399
00400 if (!search_adjusted && keyframedist > 0)
00401 desired_value /= keyframedist;
00402
00403 while (upper - 1 > lower)
00404 {
00405 long long i = (upper + lower) / 2;
00406 long long value;
00407 if (search_adjusted)
00408 value = m_positionMap[i].adjFrame;
00409 else
00410 value = m_positionMap[i].index - indexOffset;
00411 if (value == desired_value)
00412 {
00413
00414 upper_bound = i;
00415 lower_bound = i;
00416
00417 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00418 QString("FindPosition(%1, search%2 adjusted)")
00419 .arg(desired_value).arg((search_adjusted) ? "" : " not") +
00420 QString(" --> [%1:%2(%3)]")
00421 .arg(i).arg(GetKey(m_positionMap[i]))
00422 .arg(m_positionMap[i].pos));
00423
00424 return true;
00425 }
00426 else if (value > desired_value)
00427 upper = i;
00428 else
00429 lower = i;
00430 }
00431
00432
00433 if (search_adjusted)
00434 {
00435 while (lower >= 0 && m_positionMap[lower].adjFrame > desired_value)
00436 lower--;
00437 while (upper < size && m_positionMap[upper].adjFrame < desired_value)
00438 upper++;
00439 }
00440 else
00441 {
00442 while (lower >= 0 &&
00443 (m_positionMap[lower].index - indexOffset) > desired_value)
00444 lower--;
00445 while (upper < size &&
00446 (m_positionMap[upper].index - indexOffset) < desired_value)
00447 upper++;
00448 }
00449
00450 lower = max(lower, 0LL);
00451 upper = min(upper, size - 1LL);
00452
00453 upper_bound = upper;
00454 lower_bound = lower;
00455
00456 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00457 QString("FindPosition(%1, search%3 adjusted)")
00458 .arg(desired_value).arg((search_adjusted) ? "" : " not") +
00459 QString(" --> \n\t\t\t[%1:%2(%3),%4:%5(%6)]")
00460 .arg(lower_bound).arg(GetKey(m_positionMap[lower_bound]))
00461 .arg(m_positionMap[lower_bound].pos)
00462 .arg(upper_bound).arg(GetKey(m_positionMap[upper_bound]))
00463 .arg(m_positionMap[upper_bound].pos));
00464
00465 return false;
00466 }
00467
00468 uint64_t DecoderBase::SavePositionMapDelta(uint64_t first, uint64_t last)
00469 {
00470 MythTimer ttm, ctm, stm;
00471 ttm.start();
00472
00473 QMutexLocker locker(&m_positionMapLock);
00474 MarkTypes type = positionMapType;
00475 uint64_t saved = 0;
00476
00477 if (!m_playbackinfo || (positionMapType == MARK_UNSET))
00478 return saved;
00479
00480 ctm.start();
00481 frm_pos_map_t posMap;
00482 for (uint i = 0; i < m_positionMap.size(); i++)
00483 {
00484 if ((uint64_t)m_positionMap[i].index < first)
00485 continue;
00486 if ((uint64_t)m_positionMap[i].index > last)
00487 break;
00488
00489 posMap[m_positionMap[i].index] = m_positionMap[i].pos;
00490 saved++;
00491 }
00492
00493 locker.unlock();
00494
00495 stm.start();
00496 m_playbackinfo->SavePositionMapDelta(posMap, type);
00497
00498 #if 0
00499 LOG(VB_GENERAL, LOG_DEBUG, LOC +
00500 QString("Saving position map [%1,%2] w/%3 keyframes, "
00501 "took (%4,%5,%6) ms")
00502 .arg(first).arg(last).arg(saved)
00503 .arg(ttm.elapsed())
00504 .arg(ctm.elapsed()-stm.elapsed()).arg(stm.elapsed()));
00505 #endif
00506
00507 return saved;
00508 }
00509
00510 bool DecoderBase::DoRewind(long long desiredFrame, bool discardFrames)
00511 {
00512 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00513 QString("DoRewind(%1 (%2), %3 discard frames)")
00514 .arg(desiredFrame).arg(framesPlayed)
00515 .arg((discardFrames) ? "do" : "don't"));
00516
00517 if (!DoRewindSeek(desiredFrame))
00518 return false;
00519
00520 framesPlayed = lastKey;
00521 framesRead = lastKey;
00522
00523
00524
00525 int normalframes = (uint64_t)(desiredFrame - (framesPlayed - 1)) > seeksnap
00526 ? desiredFrame - framesPlayed : 0;
00527 normalframes = max(normalframes, 0);
00528 SeekReset(lastKey, normalframes, true, discardFrames);
00529
00530 if (ringBuffer->IsDisc() || discardFrames)
00531 m_parent->SetFramesPlayed(framesPlayed+1);
00532
00533 return true;
00534 }
00535
00536 long long DecoderBase::GetKey(const PosMapEntry &e) const
00537 {
00538 long long kf = (ringBuffer->IsDisc()) ? 1LL : keyframedist;
00539 return (hasKeyFrameAdjustTable) ? e.adjFrame :(e.index - indexOffset) * kf;
00540 }
00541
00542 bool DecoderBase::DoRewindSeek(long long desiredFrame)
00543 {
00544 ConditionallyUpdatePosMap(desiredFrame);
00545
00546 if (!GetPositionMapSize())
00547 {
00548 LOG(VB_GENERAL, LOG_ERR, LOC + "PosMap is empty, can't seek");
00549 return false;
00550 }
00551
00552
00553 int pre_idx, post_idx;
00554 FindPosition(desiredFrame, hasKeyFrameAdjustTable, pre_idx, post_idx);
00555
00556 PosMapEntry e;
00557 {
00558 QMutexLocker locker(&m_positionMapLock);
00559 PosMapEntry e_pre = m_positionMap[pre_idx];
00560 PosMapEntry e_post = m_positionMap[post_idx];
00561 int pos_idx = pre_idx;
00562 e = e_pre;
00563 if (((uint64_t) (GetKey(e_post) - desiredFrame)) <= seeksnap &&
00564 framesPlayed - 1 > GetKey(e_post) &&
00565 GetKey(e_post) - desiredFrame <= desiredFrame - GetKey(e_pre))
00566 {
00567
00568
00569
00570
00571 pos_idx = post_idx;
00572 e = e_post;
00573 }
00574 lastKey = GetKey(e);
00575
00576
00577 while (e.pos < 0)
00578 {
00579 pos_idx++;
00580 if (pos_idx >= (int)m_positionMap.size())
00581 return false;
00582
00583 e = m_positionMap[pos_idx];
00584 lastKey = GetKey(e);
00585 }
00586 }
00587
00588 ringBuffer->Seek(e.pos, SEEK_SET);
00589
00590 return true;
00591 }
00592
00593 void DecoderBase::ResetPosMap(void)
00594 {
00595 QMutexLocker locker(&m_positionMapLock);
00596 posmapStarted = false;
00597 m_positionMap.clear();
00598 }
00599
00600 long long DecoderBase::GetLastFrameInPosMap(void) const
00601 {
00602 long long last_frame = 0;
00603
00604 QMutexLocker locker(&m_positionMapLock);
00605 if (!m_positionMap.empty())
00606 last_frame = GetKey(m_positionMap.back());
00607
00608 return last_frame;
00609 }
00610
00611 long long DecoderBase::ConditionallyUpdatePosMap(long long desiredFrame)
00612 {
00613 long long last_frame = GetLastFrameInPosMap();
00614
00615 if (desiredFrame < 0)
00616 return last_frame;
00617
00618
00619
00620 if (desiredFrame < last_frame)
00621 return last_frame;
00622
00623 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00624 "ConditionallyUpdatePosMap: Not enough info in positionMap," +
00625 QString("\n\t\t\twe need frame %1 but highest we have is %2.")
00626 .arg(desiredFrame).arg(last_frame));
00627
00628 SyncPositionMap();
00629
00630 last_frame = GetLastFrameInPosMap();
00631
00632 if (desiredFrame > last_frame)
00633 {
00634 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00635 "ConditionallyUpdatePosMap: Still not "
00636 "enough info in positionMap after sync, " +
00637 QString("\n\t\t\twe need frame %1 but highest we have "
00638 "is %2. Will attempt to seek frame-by-frame")
00639 .arg(desiredFrame).arg(last_frame));
00640 }
00641
00642 return last_frame;
00643 }
00644
00654 bool DecoderBase::DoFastForward(long long desiredFrame, bool discardFrames)
00655 {
00656 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00657 QString("DoFastForward(%1 (%2), %3 discard frames)")
00658 .arg(desiredFrame).arg(framesPlayed)
00659 .arg((discardFrames) ? "do" : "don't"));
00660
00661 if (ringBuffer->IsDVD() &&
00662 !ringBuffer->IsInDiscMenuOrStillFrame() &&
00663 ringBuffer->DVD()->TitleTimeLeft() < 5)
00664 {
00665 return false;
00666 }
00667
00668
00669
00670
00671
00672 if (desiredFrame+1 < framesPlayed)
00673 return DoRewind(desiredFrame, discardFrames);
00674 desiredFrame = max(desiredFrame, framesPlayed);
00675
00676
00677 bool oldrawstate = getrawframes;
00678 getrawframes = false;
00679
00680 ConditionallyUpdatePosMap(desiredFrame);
00681
00682
00683 long long last_frame = GetLastFrameInPosMap();
00684
00685
00686
00687 bool needflush = false;
00688 if (desiredFrame > last_frame)
00689 {
00690 LOG(VB_GENERAL, LOG_NOTICE, LOC +
00691 QString("DoFastForward(): desiredFrame(%1) > last_frame(%2)")
00692 .arg(desiredFrame).arg(last_frame));
00693
00694 if (desiredFrame - last_frame > 32)
00695 {
00696 LOG(VB_GENERAL, LOG_ERR, LOC + "DoFastForward(): "
00697 "Desired frame is way past the end of the keyframe map!"
00698 "\n\t\t\tSeeking to last keyframe instead.");
00699 desiredFrame = last_frame;
00700 }
00701
00702 needflush = true;
00703
00704
00705 DoFastForwardSeek(last_frame, needflush);
00706
00707 exitafterdecoded = true;
00708 while ((desiredFrame > last_frame) && !ateof)
00709 {
00710 GetFrame(kDecodeNothing);
00711 SyncPositionMap();
00712 last_frame = GetLastFrameInPosMap();
00713 }
00714 exitafterdecoded = false;
00715
00716 if (ateof)
00717 {
00718
00719 getrawframes = oldrawstate;
00720 return false;
00721 }
00722 }
00723
00724 {
00725 QMutexLocker locker(&m_positionMapLock);
00726 if (m_positionMap.empty())
00727 {
00728
00729 getrawframes = oldrawstate;
00730 return false;
00731 }
00732 }
00733
00734
00735 DoFastForwardSeek(desiredFrame, needflush);
00736
00737
00738
00739 int normalframes = (uint64_t)(desiredFrame - (framesPlayed - 1)) > seeksnap
00740 ? desiredFrame - framesPlayed : 0;
00741 normalframes = max(normalframes, 0);
00742 SeekReset(lastKey, normalframes, needflush, discardFrames);
00743
00744 if (discardFrames)
00745 m_parent->SetFramesPlayed(framesPlayed+1);
00746
00747
00748 getrawframes = oldrawstate;
00749
00750 return true;
00751 }
00752
00767 void DecoderBase::DoFastForwardSeek(long long desiredFrame, bool &needflush)
00768 {
00769 int pre_idx, post_idx;
00770 FindPosition(desiredFrame, hasKeyFrameAdjustTable, pre_idx, post_idx);
00771
00772
00773
00774 PosMapEntry e, e_pre, e_post;
00775 {
00776 QMutexLocker locker(&m_positionMapLock);
00777 e_pre = m_positionMap[pre_idx];
00778 e_post = m_positionMap[post_idx];
00779 }
00780 e = e_pre;
00781 if (((uint64_t) (GetKey(e_post) - desiredFrame)) <= seeksnap &&
00782 (framesPlayed - 1 >= GetKey(e_pre) ||
00783 GetKey(e_post) - desiredFrame < desiredFrame - GetKey(e_pre)))
00784 {
00785
00786
00787
00788
00789 e = e_post;
00790 }
00791 lastKey = GetKey(e);
00792
00793 if (framesPlayed < lastKey)
00794 {
00795 ringBuffer->Seek(e.pos, SEEK_SET);
00796 needflush = true;
00797 framesPlayed = lastKey;
00798 framesRead = lastKey;
00799 }
00800 }
00801
00802 void DecoderBase::UpdateFramesPlayed(void)
00803 {
00804 m_parent->SetFramesPlayed(framesPlayed);
00805 }
00806
00807 void DecoderBase::FileChanged(void)
00808 {
00809 ResetPosMap();
00810 framesPlayed = 0;
00811 framesRead = 0;
00812 totalDuration = 0;
00813
00814 waitingForChange = false;
00815 justAfterChange = true;
00816
00817 m_parent->FileChangedCallback();
00818 }
00819
00820 void DecoderBase::SetReadAdjust(long long adjust)
00821 {
00822 readAdjust = adjust;
00823 }
00824
00825 void DecoderBase::SetWaitForChange(void)
00826 {
00827 waitingForChange = true;
00828 }
00829
00830 bool DecoderBase::GetWaitForChange(void) const
00831 {
00832 return waitingForChange;
00833 }
00834
00835 QStringList DecoderBase::GetTracks(uint type) const
00836 {
00837 QStringList list;
00838
00839 QMutexLocker locker(avcodeclock);
00840
00841 for (uint i = 0; i < tracks[type].size(); i++)
00842 list += GetTrackDesc(type, i);
00843
00844 return list;
00845 }
00846
00847 int DecoderBase::GetTrackLanguageIndex(uint type, uint trackNo) const
00848 {
00849 if (trackNo >= tracks[type].size())
00850 return 0;
00851
00852 return tracks[type][trackNo].language_index;
00853 }
00854
00855 QString DecoderBase::GetTrackDesc(uint type, uint trackNo) const
00856 {
00857 if (trackNo >= tracks[type].size())
00858 return "";
00859
00860 QMutexLocker locker(avcodeclock);
00861
00862 QString type_msg = toString((TrackType)type);
00863 int lang = tracks[type][trackNo].language;
00864 int hnum = trackNo + 1;
00865 if (kTrackTypeCC608 == type)
00866 hnum = tracks[type][trackNo].stream_id;
00867
00868 if (!lang)
00869 return type_msg + QString(" %1").arg(hnum);
00870 else
00871 {
00872 QString lang_msg = iso639_key_toName(lang);
00873 return type_msg + QString(" %1: %2").arg(hnum).arg(lang_msg);
00874 }
00875 }
00876
00877 int DecoderBase::SetTrack(uint type, int trackNo)
00878 {
00879 if (trackNo >= (int)tracks[type].size())
00880 return false;
00881
00882 QMutexLocker locker(avcodeclock);
00883
00884 currentTrack[type] = max(-1, trackNo);
00885
00886 if (currentTrack[type] < 0)
00887 selectedTrack[type].av_stream_index = -1;
00888 else
00889 {
00890 wantedTrack[type] = tracks[type][currentTrack[type]];
00891 selectedTrack[type] = tracks[type][currentTrack[type]];
00892 }
00893
00894 return currentTrack[type];
00895 }
00896
00897 StreamInfo DecoderBase::GetTrackInfo(uint type, uint trackNo) const
00898 {
00899 QMutexLocker locker(avcodeclock);
00900
00901 if (trackNo >= tracks[type].size())
00902 {
00903 StreamInfo si;
00904 return si;
00905 }
00906
00907 return tracks[type][trackNo];
00908 }
00909
00910 bool DecoderBase::InsertTrack(uint type, const StreamInfo &info)
00911 {
00912 QMutexLocker locker(avcodeclock);
00913
00914 for (uint i = 0; i < tracks[type].size(); i++)
00915 if (info.stream_id == tracks[type][i].stream_id)
00916 return false;
00917
00918 tracks[type].push_back(info);
00919
00920 if (m_parent)
00921 m_parent->TracksChanged(type);
00922
00923 return true;
00924 }
00925
00941 int DecoderBase::AutoSelectTrack(uint type)
00942 {
00943 uint numStreams = tracks[type].size();
00944
00945 if ((currentTrack[type] >= 0) &&
00946 (currentTrack[type] < (int)numStreams))
00947 {
00948 return true;
00949 }
00950
00951 if (!numStreams)
00952 {
00953 currentTrack[type] = -1;
00954 selectedTrack[type].av_stream_index = -1;
00955 return false;
00956 }
00957
00958 int selTrack = (1 == numStreams) ? 0 : -1;
00959
00960 if ((selTrack < 0) &&
00961 wantedTrack[type].language>=-1 && numStreams)
00962 {
00963 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Trying to reselect track");
00964
00965
00966
00967 int wlang = wantedTrack[type].language;
00968 uint windx = wantedTrack[type].language_index;
00969 for (uint i = 0; i < numStreams; i++)
00970 {
00971 if (wlang == tracks[type][i].language)
00972 selTrack = i;
00973 if (windx == tracks[type][i].language_index)
00974 break;
00975 }
00976 }
00977
00978 if (selTrack < 0 && numStreams)
00979 {
00980 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Trying to select track (w/lang)");
00981
00982
00983 vector<int>::iterator it = languagePreference.begin();
00984 for (; it != languagePreference.end() && (selTrack < 0); ++it)
00985 {
00986 for (uint i = 0; i < numStreams; i++)
00987 {
00988 if (*it == tracks[type][i].language)
00989 {
00990 selTrack = i;
00991 break;
00992 }
00993 }
00994 }
00995 }
00996
00997 if (selTrack < 0 && numStreams)
00998 {
00999 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Selecting first track");
01000 selTrack = 0;
01001 }
01002
01003 int oldTrack = currentTrack[type];
01004 currentTrack[type] = (selTrack < 0) ? -1 : selTrack;
01005 StreamInfo tmp = tracks[type][currentTrack[type]];
01006 selectedTrack[type] = tmp;
01007
01008 if (wantedTrack[type].av_stream_index < 0)
01009 wantedTrack[type] = tmp;
01010
01011 int lang = tracks[type][currentTrack[type]].language;
01012 LOG(VB_PLAYBACK, LOG_INFO, LOC +
01013 QString("Selected track #%1 in the %2 language(%3)")
01014 .arg(currentTrack[type]+1)
01015 .arg(iso639_key_toName(lang)).arg(lang));
01016
01017 if (m_parent && (oldTrack != currentTrack[type]))
01018 m_parent->TracksChanged(type);
01019
01020 return selTrack;
01021 }
01022
01023 QString toString(TrackType type)
01024 {
01025 QString str = QObject::tr("Track");
01026
01027 if (kTrackTypeAudio == type)
01028 str = QObject::tr("Audio track");
01029 else if (kTrackTypeVideo == type)
01030 str = QObject::tr("Video track");
01031 else if (kTrackTypeSubtitle == type)
01032 str = QObject::tr("Subtitle track");
01033 else if (kTrackTypeCC608 == type)
01034 str = QObject::tr("CC", "EIA-608 closed captions");
01035 else if (kTrackTypeCC708 == type)
01036 str = QObject::tr("ATSC CC", "EIA-708 closed captions");
01037 else if (kTrackTypeTeletextCaptions == type)
01038 str = QObject::tr("TT CC", "Teletext closed captions");
01039 else if (kTrackTypeTeletextMenu == type)
01040 str = QObject::tr("TT Menu", "Teletext Menu");
01041 else if (kTrackTypeRawText == type)
01042 str = QObject::tr("Text", "Text stream");
01043 else if (kTrackTypeTextSubtitle == type)
01044 str = QObject::tr("TXT File", "Text File");
01045 return str;
01046 }
01047
01048 int to_track_type(const QString &str)
01049 {
01050 int ret = -1;
01051
01052 if (str.left(5) == "AUDIO")
01053 ret = kTrackTypeAudio;
01054 else if (str.left(5) == "VIDEO")
01055 ret = kTrackTypeVideo;
01056 else if (str.left(8) == "SUBTITLE")
01057 ret = kTrackTypeSubtitle;
01058 else if (str.left(5) == "CC608")
01059 ret = kTrackTypeCC608;
01060 else if (str.left(5) == "CC708")
01061 ret = kTrackTypeCC708;
01062 else if (str.left(3) == "TTC")
01063 ret = kTrackTypeTeletextCaptions;
01064 else if (str.left(3) == "TTM")
01065 ret = kTrackTypeTeletextMenu;
01066 else if (str.left(3) == "TFL")
01067 ret = kTrackTypeTextSubtitle;
01068 else if (str.left(7) == "RAWTEXT")
01069 ret = kTrackTypeRawText;
01070 return ret;
01071 }
01072
01073 void DecoderBase::SaveTotalDuration(void)
01074 {
01075 if (!m_playbackinfo || !totalDuration)
01076 return;
01077
01078 m_playbackinfo->SaveTotalDuration(totalDuration);
01079 }
01080
01081 void DecoderBase::SaveTotalFrames(void)
01082 {
01083 if (!m_playbackinfo || !framesRead)
01084 return;
01085
01086 m_playbackinfo->SaveTotalFrames(framesRead);
01087 }
01088
01089
01090