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),
00031 totalDuration(AVRationalInit(0)),
00032 lastKey(0), keyframedist(-1), indexOffset(0),
00033 trackTotalDuration(false),
00034
00035 ateof(kEofStateNone), exitafterdecoded(false), transcoding(false),
00036
00037 hasFullPositionMap(false), recordingHasPositionMap(false),
00038 posmapStarted(false), positionMapType(MARK_UNSET),
00039
00040 m_positionMapLock(QMutex::Recursive),
00041 dontSyncPositionMap(false),
00042
00043 seeksnap(UINT64_MAX), livetv(false), watchingrecording(false),
00044
00045 hasKeyFrameAdjustTable(false), lowbuffers(false),
00046 getrawframes(false), getrawvideo(false),
00047 errored(false), waitingForChange(false), readAdjust(0),
00048 justAfterChange(false),
00049 video_inverted(false),
00050 decodeAllSubtitles(false),
00051
00052 languagePreference(iso639_get_language_key_list())
00053 {
00054 ResetTracks();
00055 tracks[kTrackTypeAudio].push_back(StreamInfo(0, 0, 0, 0, 0));
00056 tracks[kTrackTypeCC608].push_back(StreamInfo(0, 0, 0, 1, 0));
00057 tracks[kTrackTypeCC608].push_back(StreamInfo(0, 0, 2, 3, 0));
00058 }
00059
00060 DecoderBase::~DecoderBase()
00061 {
00062 if (m_playbackinfo)
00063 delete m_playbackinfo;
00064 }
00065
00066 void DecoderBase::SetProgramInfo(const ProgramInfo &pginfo)
00067 {
00068 if (m_playbackinfo)
00069 delete m_playbackinfo;
00070 m_playbackinfo = new ProgramInfo(pginfo);
00071 }
00072
00073 void DecoderBase::Reset(bool reset_video_data, bool seek_reset, bool reset_file)
00074 {
00075 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00076 QString("Reset: Video %1, Seek %2, File %3")
00077 .arg(reset_video_data).arg(seek_reset).arg(reset_file));
00078
00079 if (seek_reset)
00080 {
00081 SeekReset(0, 0, true, true);
00082 }
00083
00084 if (reset_video_data)
00085 {
00086 ResetPosMap();
00087 framesPlayed = 0;
00088 framesRead = 0;
00089 totalDuration = AVRationalInit(0);
00090 dontSyncPositionMap = false;
00091 }
00092
00093 if (reset_file)
00094 {
00095 waitingForChange = false;
00096 SetEofState(kEofStateNone);
00097 }
00098 }
00099
00100 void DecoderBase::SeekReset(long long, uint, bool, bool)
00101 {
00102 readAdjust = 0;
00103 }
00104
00105 void DecoderBase::SetWatchingRecording(bool mode)
00106 {
00107 bool wereWatchingRecording = watchingrecording;
00108
00109
00110
00111 posmapStarted = false;
00112 watchingrecording = mode;
00113
00114 if (wereWatchingRecording && !watchingrecording)
00115 SyncPositionMap();
00116 }
00117
00118 bool DecoderBase::PosMapFromDb(void)
00119 {
00120 if (!m_playbackinfo)
00121 return false;
00122
00123
00124 frm_pos_map_t posMap, durMap;
00125
00126 if (ringBuffer && ringBuffer->IsDVD())
00127 {
00128 long long totframes;
00129 keyframedist = 15;
00130 fps = ringBuffer->DVD()->GetFrameRate();
00131 if (fps < 26 && fps > 24)
00132 keyframedist = 12;
00133 totframes = (long long)(ringBuffer->DVD()->GetTotalTimeOfTitle() * fps);
00134 posMap[totframes] = ringBuffer->DVD()->GetTotalReadPosition();
00135 }
00136 else if (ringBuffer && ringBuffer->IsBD())
00137 {
00138 long long totframes;
00139 keyframedist = 15;
00140 fps = ringBuffer->BD()->GetFrameRate();
00141 if (fps < 26 && fps > 24)
00142 keyframedist = 12;
00143 totframes = (long long)(ringBuffer->BD()->GetTotalTimeOfTitle() * fps);
00144 posMap[totframes] = ringBuffer->BD()->GetTotalReadPosition();
00145 #if 0
00146 LOG(VB_PLAYBACK, LOG_DEBUG, LOC +
00147 QString("%1 TotalTimeOfTitle() in ticks, %2 TotalReadPosition() "
00148 "in bytes, %3 is fps")
00149 .arg(ringBuffer->BD()->GetTotalTimeOfTitle())
00150 .arg(ringBuffer->BD()->GetTotalReadPosition()).arg(fps));
00151 #endif
00152 }
00153 else if ((positionMapType == MARK_UNSET) ||
00154 (keyframedist == -1))
00155 {
00156 m_playbackinfo->QueryPositionMap(posMap, MARK_GOP_BYFRAME);
00157 if (!posMap.empty())
00158 {
00159 positionMapType = MARK_GOP_BYFRAME;
00160 if (keyframedist == -1)
00161 keyframedist = 1;
00162 }
00163 else
00164 {
00165 m_playbackinfo->QueryPositionMap(posMap, MARK_GOP_START);
00166 if (!posMap.empty())
00167 {
00168 positionMapType = MARK_GOP_START;
00169 if (keyframedist == -1)
00170 {
00171 keyframedist = 15;
00172 if (fps < 26 && fps > 24)
00173 keyframedist = 12;
00174 }
00175 }
00176 else
00177 {
00178 m_playbackinfo->QueryPositionMap(posMap, MARK_KEYFRAME);
00179 if (!posMap.empty())
00180 {
00181
00182
00183 positionMapType = MARK_KEYFRAME;
00184 }
00185 }
00186 }
00187 }
00188 else
00189 {
00190 m_playbackinfo->QueryPositionMap(posMap, positionMapType);
00191 }
00192
00193 if (posMap.empty())
00194 return false;
00195
00196 m_playbackinfo->QueryPositionMap(durMap, MARK_DURATION_MS);
00197
00198 QMutexLocker locker(&m_positionMapLock);
00199 m_positionMap.clear();
00200 m_positionMap.reserve(posMap.size());
00201
00202 for (frm_pos_map_t::const_iterator it = posMap.begin();
00203 it != posMap.end(); ++it)
00204 {
00205 PosMapEntry e = {it.key(), it.key() * keyframedist, *it};
00206 m_positionMap.push_back(e);
00207 }
00208
00209 if (!m_positionMap.empty() && !(ringBuffer && ringBuffer->IsDisc()))
00210 indexOffset = m_positionMap[0].index;
00211
00212 if (!m_positionMap.empty())
00213 {
00214 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00215 QString("Position map filled from DB to: %1")
00216 .arg(m_positionMap.back().index));
00217 }
00218
00219 uint64_t last = 0;
00220 for (frm_pos_map_t::const_iterator it = durMap.begin();
00221 it != durMap.end(); ++it)
00222 {
00223 m_frameToDurMap[it.key()] = it.value();
00224 m_durToFrameMap[it.value()] = it.key();
00225 last = it.key();
00226 }
00227
00228 if (!m_durToFrameMap.empty())
00229 {
00230 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00231 QString("Duration map filled from DB to: %1").arg(last));
00232 }
00233
00234 return true;
00235 }
00236
00245 bool DecoderBase::PosMapFromEnc(void)
00246 {
00247 if (!m_parent || keyframedist < 1)
00248 return false;
00249
00250 unsigned long long start = 0;
00251 {
00252 QMutexLocker locker(&m_positionMapLock);
00253 if (!m_positionMap.empty())
00254 start = m_positionMap.back().index + 1;
00255 }
00256
00257 frm_pos_map_t posMap, durMap;
00258 if (!m_parent->PosMapFromEnc(start, posMap, durMap))
00259 return false;
00260
00261 QMutexLocker locker(&m_positionMapLock);
00262
00263
00264 m_positionMap.reserve(m_positionMap.size() + posMap.size());
00265 uint64_t last_index = m_positionMap.back().index;
00266 for (frm_pos_map_t::const_iterator it = posMap.begin();
00267 it != posMap.end(); ++it)
00268 {
00269 if (it.key() <= last_index)
00270 continue;
00271
00272 PosMapEntry e = {it.key(), it.key() * keyframedist, *it};
00273 m_positionMap.push_back(e);
00274 }
00275
00276 if (!m_positionMap.empty() && !(ringBuffer && ringBuffer->IsDisc()))
00277 indexOffset = m_positionMap[0].index;
00278
00279 if (!m_positionMap.empty())
00280 {
00281 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00282 QString("Position map filled from Encoder to: %1")
00283 .arg(m_positionMap.back().index));
00284 }
00285
00286 bool isEmpty = m_frameToDurMap.empty();
00287 if (!isEmpty)
00288 {
00289 frm_pos_map_t::const_iterator it = m_frameToDurMap.end();
00290 --it;
00291 last_index = it.key();
00292 }
00293 for (frm_pos_map_t::const_iterator it = durMap.begin();
00294 it != durMap.end(); ++it)
00295 {
00296 if (!isEmpty && it.key() <= last_index)
00297 continue;
00298 m_frameToDurMap[it.key()] = it.value();
00299 m_durToFrameMap[it.value()] = it.key();
00300 }
00301
00302 if (!m_frameToDurMap.empty())
00303 {
00304 frm_pos_map_t::const_iterator it = m_frameToDurMap.end();
00305 --it;
00306 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00307 QString("Duration map filled from Encoder to: %1").arg(it.key()));
00308 }
00309
00310 return true;
00311 }
00312
00313 unsigned long DecoderBase::GetPositionMapSize(void) const
00314 {
00315 QMutexLocker locker(&m_positionMapLock);
00316 return (unsigned long) m_positionMap.size();
00317 }
00318
00341 bool DecoderBase::SyncPositionMap(void)
00342 {
00343 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00344 QString("Resyncing position map. posmapStarted = %1"
00345 " livetv(%2) watchingRec(%3)")
00346 .arg((int) posmapStarted).arg(livetv).arg(watchingrecording));
00347
00348 if (dontSyncPositionMap)
00349 return false;
00350
00351 unsigned long old_posmap_size = GetPositionMapSize();
00352 unsigned long new_posmap_size = old_posmap_size;
00353
00354 if (livetv || watchingrecording)
00355 {
00356 if (!posmapStarted)
00357 {
00358
00359 PosMapFromDb();
00360 new_posmap_size = GetPositionMapSize();
00361 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00362 QString("SyncPositionMap watchingrecording, from DB: "
00363 "%1 entries") .arg(new_posmap_size));
00364 }
00365
00366 if (!PosMapFromEnc())
00367 {
00368 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00369 QString("SyncPositionMap watchingrecording no entries "
00370 "from encoder, try DB"));
00371 PosMapFromDb();
00372 }
00373
00374 new_posmap_size = GetPositionMapSize();
00375 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00376 QString("SyncPositionMap watchingrecording total: %1 entries")
00377 .arg(new_posmap_size));
00378 }
00379 else
00380 {
00381
00382 if (!posmapStarted)
00383 {
00384 PosMapFromDb();
00385
00386 new_posmap_size = GetPositionMapSize();
00387 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00388 QString("SyncPositionMap prerecorded, from DB: %1 entries")
00389 .arg(new_posmap_size));
00390 }
00391 }
00392
00393 bool ret_val = new_posmap_size > old_posmap_size;
00394
00395 if (ret_val && keyframedist > 0)
00396 {
00397 long long totframes = 0;
00398 int length = 0;
00399
00400 if (ringBuffer && ringBuffer->IsDVD())
00401 {
00402 length = ringBuffer->DVD()->GetTotalTimeOfTitle();
00403 QMutexLocker locker(&m_positionMapLock);
00404 totframes = m_positionMap.back().index;
00405 }
00406 else if (ringBuffer && ringBuffer->IsBD())
00407 {
00408 length = ringBuffer->BD()->GetTotalTimeOfTitle();
00409 QMutexLocker locker(&m_positionMapLock);
00410 totframes = m_positionMap.back().index;
00411 }
00412 else
00413 {
00414 QMutexLocker locker(&m_positionMapLock);
00415 totframes = m_positionMap.back().index * keyframedist;
00416 if (fps)
00417 length = (int)((totframes * 1.0) / fps);
00418 }
00419
00420 m_parent->SetFileLength(length, totframes);
00421 m_parent->SetKeyframeDistance(keyframedist);
00422 posmapStarted = true;
00423
00424 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00425 QString("SyncPositionMap, new totframes: %1, new length: %2, "
00426 "posMap size: %3")
00427 .arg(totframes).arg(length).arg(new_posmap_size));
00428 }
00429 recordingHasPositionMap |= (0 != new_posmap_size);
00430 {
00431 QMutexLocker locker(&m_positionMapLock);
00432 m_lastPositionMapUpdate = QDateTime::currentDateTime();
00433 }
00434 return ret_val;
00435 }
00436
00437
00438
00439 bool DecoderBase::FindPosition(long long desired_value, bool search_adjusted,
00440 int &lower_bound, int &upper_bound)
00441 {
00442 QMutexLocker locker(&m_positionMapLock);
00443
00444 long long size = (long long) m_positionMap.size();
00445 long long lower = -1;
00446 long long upper = size;
00447
00448 if (!search_adjusted && keyframedist > 0)
00449 desired_value /= keyframedist;
00450
00451 while (upper - 1 > lower)
00452 {
00453 long long i = (upper + lower) / 2;
00454 long long value;
00455 if (search_adjusted)
00456 value = m_positionMap[i].adjFrame;
00457 else
00458 value = m_positionMap[i].index - indexOffset;
00459 if (value == desired_value)
00460 {
00461
00462 upper_bound = i;
00463 lower_bound = i;
00464
00465 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00466 QString("FindPosition(%1, search%2 adjusted)")
00467 .arg(desired_value).arg((search_adjusted) ? "" : " not") +
00468 QString(" --> [%1:%2(%3)]")
00469 .arg(i).arg(GetKey(m_positionMap[i]))
00470 .arg(m_positionMap[i].pos));
00471
00472 return true;
00473 }
00474 else if (value > desired_value)
00475 upper = i;
00476 else
00477 lower = i;
00478 }
00479
00480
00481 if (search_adjusted)
00482 {
00483 while (lower >= 0 && m_positionMap[lower].adjFrame > desired_value)
00484 lower--;
00485 while (upper < size && m_positionMap[upper].adjFrame < desired_value)
00486 upper++;
00487 }
00488 else
00489 {
00490 while (lower >= 0 &&
00491 (m_positionMap[lower].index - indexOffset) > desired_value)
00492 lower--;
00493 while (upper < size &&
00494 (m_positionMap[upper].index - indexOffset) < desired_value)
00495 upper++;
00496 }
00497
00498 lower = max(lower, 0LL);
00499 upper = min(upper, size - 1LL);
00500
00501 upper_bound = upper;
00502 lower_bound = lower;
00503 bool empty = m_positionMap.empty();
00504
00505 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00506 QString("FindPosition(%1, search%3 adjusted)")
00507 .arg(desired_value).arg((search_adjusted) ? "" : " not") +
00508 QString(" --> \n\t\t\t[%1:%2(%3),%4:%5(%6)]")
00509 .arg(lower_bound)
00510 .arg(empty ? -1 : GetKey(m_positionMap[lower_bound]))
00511 .arg(m_positionMap[lower_bound].pos)
00512 .arg(upper_bound)
00513 .arg(empty ? -1 : GetKey(m_positionMap[upper_bound]))
00514 .arg(empty ? -1 : m_positionMap[upper_bound].pos));
00515
00516 return false;
00517 }
00518
00519 uint64_t DecoderBase::SavePositionMapDelta(uint64_t first, uint64_t last)
00520 {
00521 MythTimer ttm, ctm, stm;
00522 ttm.start();
00523
00524 QMutexLocker locker(&m_positionMapLock);
00525 MarkTypes type = positionMapType;
00526 uint64_t saved = 0;
00527
00528 if (!m_playbackinfo || (positionMapType == MARK_UNSET))
00529 return saved;
00530
00531 ctm.start();
00532 frm_pos_map_t posMap;
00533 for (uint i = 0; i < m_positionMap.size(); i++)
00534 {
00535 if ((uint64_t)m_positionMap[i].index < first)
00536 continue;
00537 if ((uint64_t)m_positionMap[i].index > last)
00538 break;
00539
00540 posMap[m_positionMap[i].index] = m_positionMap[i].pos;
00541 saved++;
00542 }
00543
00544 frm_pos_map_t durMap;
00545 for (frm_pos_map_t::const_iterator it = m_frameToDurMap.begin();
00546 it != m_frameToDurMap.end(); ++it)
00547 {
00548 if (it.key() < first)
00549 continue;
00550 if (it.key() > last)
00551 break;
00552 durMap[it.key()] = it.value();
00553 }
00554
00555 locker.unlock();
00556
00557 stm.start();
00558 m_playbackinfo->SavePositionMapDelta(posMap, type);
00559 m_playbackinfo->SavePositionMapDelta(durMap, MARK_DURATION_MS);
00560
00561 #if 0
00562 LOG(VB_GENERAL, LOG_DEBUG, LOC +
00563 QString("Saving position map [%1,%2] w/%3 keyframes, "
00564 "took (%4,%5,%6) ms")
00565 .arg(first).arg(last).arg(saved)
00566 .arg(ttm.elapsed())
00567 .arg(ctm.elapsed()-stm.elapsed()).arg(stm.elapsed()));
00568 #endif
00569
00570 return saved;
00571 }
00572
00573 bool DecoderBase::DoRewind(long long desiredFrame, bool discardFrames)
00574 {
00575 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00576 QString("DoRewind(%1 (%2), %3 discard frames)")
00577 .arg(desiredFrame).arg(framesPlayed)
00578 .arg((discardFrames) ? "do" : "don't"));
00579
00580 if (!DoRewindSeek(desiredFrame))
00581 return false;
00582
00583 framesPlayed = lastKey;
00584 framesRead = lastKey;
00585
00586
00587
00588 int normalframes = (uint64_t)(desiredFrame - (framesPlayed - 1)) > seeksnap
00589 ? desiredFrame - framesPlayed : 0;
00590 normalframes = max(normalframes, 0);
00591 SeekReset(lastKey, normalframes, true, discardFrames);
00592
00593 if (discardFrames || (ringBuffer && ringBuffer->IsDisc()))
00594 m_parent->SetFramesPlayed(framesPlayed+1);
00595
00596 return true;
00597 }
00598
00599 long long DecoderBase::GetKey(const PosMapEntry &e) const
00600 {
00601 long long kf = (ringBuffer && ringBuffer->IsDisc()) ?
00602 1LL : keyframedist;
00603 return (hasKeyFrameAdjustTable) ? e.adjFrame :(e.index - indexOffset) * kf;
00604 }
00605
00606 bool DecoderBase::DoRewindSeek(long long desiredFrame)
00607 {
00608 ConditionallyUpdatePosMap(desiredFrame);
00609
00610 if (!GetPositionMapSize())
00611 {
00612 LOG(VB_GENERAL, LOG_ERR, LOC + "PosMap is empty, can't seek");
00613 return false;
00614 }
00615
00616 if (!ringBuffer)
00617 {
00618 LOG(VB_GENERAL, LOG_ERR, LOC + "No ringBuffer yet, can't seek");
00619 return false;
00620 }
00621
00622
00623 int pre_idx, post_idx;
00624 FindPosition(desiredFrame, hasKeyFrameAdjustTable, pre_idx, post_idx);
00625
00626 PosMapEntry e;
00627 {
00628 QMutexLocker locker(&m_positionMapLock);
00629 PosMapEntry e_pre = m_positionMap[pre_idx];
00630 PosMapEntry e_post = m_positionMap[post_idx];
00631 int pos_idx = pre_idx;
00632 e = e_pre;
00633 if (((uint64_t) (GetKey(e_post) - desiredFrame)) <= seeksnap &&
00634 framesPlayed - 1 > GetKey(e_post) &&
00635 GetKey(e_post) - desiredFrame <= desiredFrame - GetKey(e_pre))
00636 {
00637
00638
00639
00640
00641 pos_idx = post_idx;
00642 e = e_post;
00643 }
00644 lastKey = GetKey(e);
00645
00646
00647 while (e.pos < 0)
00648 {
00649 pos_idx++;
00650 if (pos_idx >= (int)m_positionMap.size())
00651 return false;
00652
00653 e = m_positionMap[pos_idx];
00654 lastKey = GetKey(e);
00655 }
00656 }
00657
00658 ringBuffer->Seek(e.pos, SEEK_SET);
00659
00660 return true;
00661 }
00662
00663 void DecoderBase::ResetPosMap(void)
00664 {
00665 QMutexLocker locker(&m_positionMapLock);
00666 posmapStarted = false;
00667 m_positionMap.clear();
00668 }
00669
00670 long long DecoderBase::GetLastFrameInPosMap(void) const
00671 {
00672 long long last_frame = 0;
00673
00674 QMutexLocker locker(&m_positionMapLock);
00675 if (!m_positionMap.empty())
00676 last_frame = GetKey(m_positionMap.back());
00677
00678 return last_frame;
00679 }
00680
00681 long long DecoderBase::ConditionallyUpdatePosMap(long long desiredFrame)
00682 {
00683 long long last_frame = GetLastFrameInPosMap();
00684
00685 if (desiredFrame < 0)
00686 return last_frame;
00687
00688
00689
00690 if (desiredFrame < last_frame)
00691 return last_frame;
00692
00693 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00694 "ConditionallyUpdatePosMap: Not enough info in positionMap," +
00695 QString("\n\t\t\twe need frame %1 but highest we have is %2.")
00696 .arg(desiredFrame).arg(last_frame));
00697
00698 SyncPositionMap();
00699
00700 last_frame = GetLastFrameInPosMap();
00701
00702 if (desiredFrame > last_frame)
00703 {
00704 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00705 "ConditionallyUpdatePosMap: Still not "
00706 "enough info in positionMap after sync, " +
00707 QString("\n\t\t\twe need frame %1 but highest we have "
00708 "is %2. Will attempt to seek frame-by-frame")
00709 .arg(desiredFrame).arg(last_frame));
00710 }
00711
00712 return last_frame;
00713 }
00714
00724 bool DecoderBase::DoFastForward(long long desiredFrame, bool discardFrames)
00725 {
00726 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00727 QString("DoFastForward(%1 (%2), %3 discard frames)")
00728 .arg(desiredFrame).arg(framesPlayed)
00729 .arg((discardFrames) ? "do" : "don't"));
00730
00731 if (!ringBuffer)
00732 {
00733 LOG(VB_GENERAL, LOG_ERR, LOC + "No ringBuffer yet, can't fast forward");
00734 return false;
00735 }
00736
00737 if (ringBuffer->IsDVD() &&
00738 !ringBuffer->IsInDiscMenuOrStillFrame() &&
00739 ringBuffer->DVD()->TitleTimeLeft() < 5)
00740 {
00741 return false;
00742 }
00743
00744
00745
00746
00747
00748 if (desiredFrame+1 < framesPlayed)
00749 return DoRewind(desiredFrame, discardFrames);
00750 desiredFrame = max(desiredFrame, framesPlayed);
00751
00752
00753 bool oldrawstate = getrawframes;
00754 getrawframes = false;
00755
00756 ConditionallyUpdatePosMap(desiredFrame);
00757
00758
00759 long long last_frame = GetLastFrameInPosMap();
00760
00761
00762
00763 bool needflush = false;
00764 if (desiredFrame > last_frame)
00765 {
00766 LOG(VB_GENERAL, LOG_NOTICE, LOC +
00767 QString("DoFastForward(): desiredFrame(%1) > last_frame(%2)")
00768 .arg(desiredFrame).arg(last_frame));
00769
00770 if (desiredFrame - last_frame > 32)
00771 {
00772 LOG(VB_GENERAL, LOG_ERR, LOC + "DoFastForward(): "
00773 "Desired frame is way past the end of the keyframe map!"
00774 "\n\t\t\tSeeking to last keyframe instead.");
00775 desiredFrame = last_frame;
00776 }
00777
00778 needflush = true;
00779
00780
00781 DoFastForwardSeek(last_frame, needflush);
00782
00783 exitafterdecoded = true;
00784 while ((desiredFrame > last_frame) && !ateof)
00785 {
00786 GetFrame(kDecodeNothing);
00787 SyncPositionMap();
00788 last_frame = GetLastFrameInPosMap();
00789 }
00790 exitafterdecoded = false;
00791
00792 if (ateof)
00793 {
00794
00795 getrawframes = oldrawstate;
00796 return false;
00797 }
00798 }
00799
00800 {
00801 QMutexLocker locker(&m_positionMapLock);
00802 if (m_positionMap.empty())
00803 {
00804
00805 getrawframes = oldrawstate;
00806 return false;
00807 }
00808 }
00809
00810
00811 DoFastForwardSeek(desiredFrame, needflush);
00812
00813
00814
00815 int normalframes = (uint64_t)(desiredFrame - (framesPlayed - 1)) > seeksnap
00816 ? desiredFrame - framesPlayed : 0;
00817 normalframes = max(normalframes, 0);
00818 SeekReset(lastKey, normalframes, needflush, discardFrames);
00819
00820 if (discardFrames)
00821 m_parent->SetFramesPlayed(framesPlayed+1);
00822
00823
00824 getrawframes = oldrawstate;
00825
00826 return true;
00827 }
00828
00843 void DecoderBase::DoFastForwardSeek(long long desiredFrame, bool &needflush)
00844 {
00845 if (!ringBuffer)
00846 {
00847 LOG(VB_GENERAL, LOG_ERR, LOC +
00848 "No ringBuffer yet, can't fast forward seek");
00849 return;
00850 }
00851
00852 int pre_idx, post_idx;
00853 FindPosition(desiredFrame, hasKeyFrameAdjustTable, pre_idx, post_idx);
00854
00855
00856
00857 PosMapEntry e, e_pre, e_post;
00858 {
00859 QMutexLocker locker(&m_positionMapLock);
00860 e_pre = m_positionMap[pre_idx];
00861 e_post = m_positionMap[post_idx];
00862 }
00863 e = e_pre;
00864 if (((uint64_t) (GetKey(e_post) - desiredFrame)) <= seeksnap &&
00865 (framesPlayed - 1 >= GetKey(e_pre) ||
00866 GetKey(e_post) - desiredFrame < desiredFrame - GetKey(e_pre)))
00867 {
00868
00869
00870
00871
00872 e = e_post;
00873 }
00874 lastKey = GetKey(e);
00875
00876 if (framesPlayed < lastKey)
00877 {
00878 ringBuffer->Seek(e.pos, SEEK_SET);
00879 needflush = true;
00880 framesPlayed = lastKey;
00881 framesRead = lastKey;
00882 }
00883 }
00884
00885 void DecoderBase::UpdateFramesPlayed(void)
00886 {
00887 m_parent->SetFramesPlayed(framesPlayed);
00888 }
00889
00890 void DecoderBase::FileChanged(void)
00891 {
00892 ResetPosMap();
00893 framesPlayed = 0;
00894 framesRead = 0;
00895 totalDuration = AVRationalInit(0);
00896
00897 waitingForChange = false;
00898 justAfterChange = true;
00899
00900 m_parent->FileChangedCallback();
00901 }
00902
00903 void DecoderBase::SetReadAdjust(long long adjust)
00904 {
00905 readAdjust = adjust;
00906 }
00907
00908 void DecoderBase::SetWaitForChange(void)
00909 {
00910 waitingForChange = true;
00911 }
00912
00913 bool DecoderBase::GetWaitForChange(void) const
00914 {
00915 return waitingForChange;
00916 }
00917
00918 QStringList DecoderBase::GetTracks(uint type) const
00919 {
00920 QStringList list;
00921
00922 QMutexLocker locker(avcodeclock);
00923
00924 for (uint i = 0; i < tracks[type].size(); i++)
00925 list += GetTrackDesc(type, i);
00926
00927 return list;
00928 }
00929
00930 int DecoderBase::GetTrackLanguageIndex(uint type, uint trackNo) const
00931 {
00932 if (trackNo >= tracks[type].size())
00933 return 0;
00934
00935 return tracks[type][trackNo].language_index;
00936 }
00937
00938 QString DecoderBase::GetTrackDesc(uint type, uint trackNo) const
00939 {
00940 if (trackNo >= tracks[type].size())
00941 return "";
00942
00943 QMutexLocker locker(avcodeclock);
00944
00945 QString type_msg = toString((TrackType)type);
00946 int lang = tracks[type][trackNo].language;
00947 int hnum = trackNo + 1;
00948 if (kTrackTypeCC608 == type)
00949 hnum = tracks[type][trackNo].stream_id;
00950
00951 if (!lang)
00952 return type_msg + QString(" %1").arg(hnum);
00953 else
00954 {
00955 QString lang_msg = iso639_key_toName(lang);
00956 return type_msg + QString(" %1: %2").arg(hnum).arg(lang_msg);
00957 }
00958 }
00959
00960 int DecoderBase::SetTrack(uint type, int trackNo)
00961 {
00962 if (trackNo >= (int)tracks[type].size())
00963 return false;
00964
00965 QMutexLocker locker(avcodeclock);
00966
00967 currentTrack[type] = max(-1, trackNo);
00968
00969 if (currentTrack[type] < 0)
00970 selectedTrack[type].av_stream_index = -1;
00971 else
00972 {
00973 wantedTrack[type] = tracks[type][currentTrack[type]];
00974 selectedTrack[type] = tracks[type][currentTrack[type]];
00975 }
00976
00977 return currentTrack[type];
00978 }
00979
00980 StreamInfo DecoderBase::GetTrackInfo(uint type, uint trackNo) const
00981 {
00982 QMutexLocker locker(avcodeclock);
00983
00984 if (trackNo >= tracks[type].size())
00985 {
00986 StreamInfo si;
00987 return si;
00988 }
00989
00990 return tracks[type][trackNo];
00991 }
00992
00993 bool DecoderBase::InsertTrack(uint type, const StreamInfo &info)
00994 {
00995 QMutexLocker locker(avcodeclock);
00996
00997 for (uint i = 0; i < tracks[type].size(); i++)
00998 if (info.stream_id == tracks[type][i].stream_id)
00999 return false;
01000
01001 tracks[type].push_back(info);
01002
01003 if (m_parent)
01004 m_parent->TracksChanged(type);
01005
01006 return true;
01007 }
01008
01024 int DecoderBase::AutoSelectTrack(uint type)
01025 {
01026 uint numStreams = tracks[type].size();
01027
01028 if ((currentTrack[type] >= 0) &&
01029 (currentTrack[type] < (int)numStreams))
01030 {
01031 return true;
01032 }
01033
01034 if (!numStreams)
01035 {
01036 currentTrack[type] = -1;
01037 selectedTrack[type].av_stream_index = -1;
01038 return false;
01039 }
01040
01041 int selTrack = (1 == numStreams) ? 0 : -1;
01042
01043 if ((selTrack < 0) &&
01044 wantedTrack[type].language>=-1 && numStreams)
01045 {
01046 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Trying to reselect track");
01047
01048
01049
01050 int wlang = wantedTrack[type].language;
01051 uint windx = wantedTrack[type].language_index;
01052 for (uint i = 0; i < numStreams; i++)
01053 {
01054 if (wlang == tracks[type][i].language)
01055 selTrack = i;
01056 if (windx == tracks[type][i].language_index)
01057 break;
01058 }
01059 }
01060
01061 if (selTrack < 0 && numStreams)
01062 {
01063
01064
01065
01066
01067
01068 LOG(VB_PLAYBACK, LOG_INFO,
01069 LOC + "Trying to select track (w/lang & forced)");
01070 const int kForcedWeight = (1 << 20);
01071 const int kLanguageWeight = (1 << 10);
01072 const int kPositionWeight = (1 << 0);
01073 int bestScore = -1;
01074 selTrack = 0;
01075 for (uint i = 0; i < numStreams; i++)
01076 {
01077 int forced = (type == kTrackTypeSubtitle &&
01078 tracks[type][i].forced &&
01079 m_parent->ForcedSubtitlesFavored());
01080 int position = numStreams - i;
01081 int language = 0;
01082 for (uint j = 0;
01083 (language == 0) && (j < languagePreference.size()); ++j)
01084 {
01085 if (tracks[type][i].language == languagePreference[j])
01086 language = languagePreference.size() - j;
01087 }
01088 int score = kForcedWeight * forced
01089 + kLanguageWeight * language
01090 + kPositionWeight * position;
01091 if (score > bestScore)
01092 {
01093 bestScore = score;
01094 selTrack = i;
01095 }
01096 }
01097 }
01098
01099 int oldTrack = currentTrack[type];
01100 currentTrack[type] = (selTrack < 0) ? -1 : selTrack;
01101 StreamInfo tmp = tracks[type][currentTrack[type]];
01102 selectedTrack[type] = tmp;
01103
01104 if (wantedTrack[type].av_stream_index < 0)
01105 wantedTrack[type] = tmp;
01106
01107 int lang = tracks[type][currentTrack[type]].language;
01108 LOG(VB_PLAYBACK, LOG_INFO, LOC +
01109 QString("Selected track #%1 in the %2 language(%3)")
01110 .arg(currentTrack[type]+1)
01111 .arg(iso639_key_toName(lang)).arg(lang));
01112
01113 if (m_parent && (oldTrack != currentTrack[type]))
01114 m_parent->TracksChanged(type);
01115
01116 return selTrack;
01117 }
01118
01119 QString toString(TrackType type)
01120 {
01121 QString str = QObject::tr("Track");
01122
01123 if (kTrackTypeAudio == type)
01124 str = QObject::tr("Audio track");
01125 else if (kTrackTypeVideo == type)
01126 str = QObject::tr("Video track");
01127 else if (kTrackTypeSubtitle == type)
01128 str = QObject::tr("Subtitle track");
01129 else if (kTrackTypeCC608 == type)
01130 str = QObject::tr("CC", "EIA-608 closed captions");
01131 else if (kTrackTypeCC708 == type)
01132 str = QObject::tr("ATSC CC", "EIA-708 closed captions");
01133 else if (kTrackTypeTeletextCaptions == type)
01134 str = QObject::tr("TT CC", "Teletext closed captions");
01135 else if (kTrackTypeTeletextMenu == type)
01136 str = QObject::tr("TT Menu", "Teletext Menu");
01137 else if (kTrackTypeRawText == type)
01138 str = QObject::tr("Text", "Text stream");
01139 else if (kTrackTypeTextSubtitle == type)
01140 str = QObject::tr("TXT File", "Text File");
01141 return str;
01142 }
01143
01144 int to_track_type(const QString &str)
01145 {
01146 int ret = -1;
01147
01148 if (str.startsWith("AUDIO"))
01149 ret = kTrackTypeAudio;
01150 else if (str.startsWith("VIDEO"))
01151 ret = kTrackTypeVideo;
01152 else if (str.startsWith("SUBTITLE"))
01153 ret = kTrackTypeSubtitle;
01154 else if (str.startsWith("CC608"))
01155 ret = kTrackTypeCC608;
01156 else if (str.startsWith("CC708"))
01157 ret = kTrackTypeCC708;
01158 else if (str.startsWith("TTC"))
01159 ret = kTrackTypeTeletextCaptions;
01160 else if (str.startsWith("TTM"))
01161 ret = kTrackTypeTeletextMenu;
01162 else if (str.startsWith("TFL"))
01163 ret = kTrackTypeTextSubtitle;
01164 else if (str.startsWith("RAWTEXT"))
01165 ret = kTrackTypeRawText;
01166 return ret;
01167 }
01168
01169 QString toString(AudioTrackType type)
01170 {
01171 QString str;
01172
01173 switch (type)
01174 {
01175 case kAudioTypeAudioDescription :
01176 str = QObject::tr("Audio Description",
01177 "On-screen events described for the visually impaired");
01178 break;
01179 case kAudioTypeCleanEffects :
01180 str = QObject::tr("Clean Effects",
01181 "No dialog, background audio only");
01182 break;
01183 case kAudioTypeHearingImpaired :
01184 str = QObject::tr("Hearing Impaired",
01185 "Clear dialog for the hearing impaired");
01186 break;
01187 case kAudioTypeSpokenSubs :
01188 str = QObject::tr("Spoken Subtitles",
01189 "Subtitles are read out for the visually impaired");
01190 break;
01191 case kAudioTypeCommentary :
01192 str = QObject::tr("Commentary", "Director/Cast commentary track");
01193 break;
01194 case kAudioTypeNormal :
01195 default:
01196 str = QObject::tr("Normal", "Ordinary audio track");
01197 break;
01198 }
01199
01200 return str;
01201 }
01202
01203 void DecoderBase::SaveTotalDuration(void)
01204 {
01205 if (!m_playbackinfo || av_q2d(totalDuration) == 0)
01206 return;
01207
01208 m_playbackinfo->SaveTotalDuration(1000000 * av_q2d(totalDuration));
01209 }
01210
01211 void DecoderBase::SaveTotalFrames(void)
01212 {
01213 if (!m_playbackinfo || !framesRead)
01214 return;
01215
01216 m_playbackinfo->SaveTotalFrames(framesRead);
01217 }
01218
01219
01220
01221
01222 uint64_t DecoderBase::TranslatePosition(const frm_pos_map_t &map,
01223 uint64_t key,
01224 float fallback_ratio)
01225 {
01226 uint64_t key1, key2;
01227 uint64_t val1, val2;
01228
01229 frm_pos_map_t::const_iterator lower = map.lowerBound(key);
01230
01231
01232 if (lower != map.begin() && (lower == map.end() || lower.key() > key))
01233 --lower;
01234 if (lower == map.end() || lower.key() > key)
01235 {
01236 key1 = 0;
01237 val1 = 0;
01238 LOG(VB_PLAYBACK, LOG_DEBUG, LOC +
01239 QString("TranslatePosition(key=%1): extrapolating to (0,0)")
01240 .arg(key));
01241 }
01242 else
01243 {
01244 key1 = lower.key();
01245 val1 = lower.value();
01246 }
01247
01248
01249 frm_pos_map_t::const_iterator upper = map.lowerBound(key);
01250 if (upper == map.end())
01251 {
01252
01253 key2 = key;
01254 val2 = val1 + fallback_ratio * (key2 - key1) + 0.5;
01255 LOG(VB_PLAYBACK, LOG_DEBUG, LOC +
01256 QString("TranslatePosition(key=%1, ratio=%2): "
01257 "extrapolating to (%3,%4)")
01258 .arg(key).arg(fallback_ratio).arg(key2).arg(val2));
01259 return val2;
01260 }
01261 else
01262 {
01263 key2 = upper.key();
01264 val2 = upper.value();
01265 }
01266 if (key1 == key2)
01267 return val2;
01268
01269 return val1 + (double) (key - key1) * (val2 - val1) / (key2 - key1) + 0.5;
01270 }
01271
01272
01273
01274 uint64_t DecoderBase::TranslatePositionFrameToMs(uint64_t position,
01275 float fallback_framerate,
01276 const frm_dir_map_t &cutlist)
01277 {
01278 QMutexLocker locker(&m_positionMapLock);
01279
01280
01281
01282
01283
01284 if (!m_frameToDurMap.empty())
01285 {
01286 frm_pos_map_t::const_iterator it = m_frameToDurMap.end();
01287 --it;
01288 if (position > it.key())
01289 {
01290 if (!m_lastPositionMapUpdate.isValid() ||
01291 (QDateTime::currentDateTime() >
01292 m_lastPositionMapUpdate.addSecs(3)))
01293 SyncPositionMap();
01294 }
01295 }
01296 return TranslatePositionAbsToRel(cutlist, position, m_frameToDurMap,
01297 1000 / fallback_framerate);
01298 }
01299
01300
01301
01302 uint64_t DecoderBase::TranslatePositionMsToFrame(uint64_t dur_ms,
01303 float fallback_framerate,
01304 const frm_dir_map_t &cutlist)
01305 {
01306 QMutexLocker locker(&m_positionMapLock);
01307
01308
01309 uint64_t ms = TranslatePositionRelToAbs(cutlist, dur_ms, m_frameToDurMap,
01310 1000 / fallback_framerate);
01311
01312
01313 return TranslatePosition(m_durToFrameMap, ms, fallback_framerate / 1000);
01314 }
01315
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325 uint64_t
01326 DecoderBase::TranslatePositionAbsToRel(const frm_dir_map_t &deleteMap,
01327 uint64_t absPosition,
01328 const frm_pos_map_t &map,
01329 float fallback_ratio)
01330 {
01331 uint64_t subtraction = 0;
01332 uint64_t startOfCutRegion = 0;
01333 bool withinCut = false;
01334 bool first = true;
01335 for (frm_dir_map_t::const_iterator i = deleteMap.begin();
01336 i != deleteMap.end(); ++i)
01337 {
01338 if (first)
01339 withinCut = (i.value() == MARK_CUT_END);
01340 first = false;
01341 if (i.key() > absPosition)
01342 break;
01343 uint64_t mappedKey = TranslatePosition(map, i.key(), fallback_ratio);
01344 if (i.value() == MARK_CUT_START && !withinCut)
01345 {
01346 withinCut = true;
01347 startOfCutRegion = mappedKey;
01348 }
01349 else if (i.value() == MARK_CUT_END && withinCut)
01350 {
01351 withinCut = false;
01352 subtraction += (mappedKey - startOfCutRegion);
01353 }
01354 }
01355 uint64_t mappedPos = TranslatePosition(map, absPosition, fallback_ratio);
01356 if (withinCut)
01357 subtraction += (mappedPos - startOfCutRegion);
01358 return mappedPos - subtraction;
01359 }
01360
01361
01362
01363
01364
01365
01366
01367
01368
01369
01370
01371
01372
01373
01374 uint64_t
01375 DecoderBase::TranslatePositionRelToAbs(const frm_dir_map_t &deleteMap,
01376 uint64_t relPosition,
01377 const frm_pos_map_t &map,
01378 float fallback_ratio)
01379 {
01380 uint64_t addition = 0;
01381 uint64_t startOfCutRegion = 0;
01382 bool withinCut = false;
01383 bool first = true;
01384 for (frm_dir_map_t::const_iterator i = deleteMap.begin();
01385 i != deleteMap.end(); ++i)
01386 {
01387 if (first)
01388 withinCut = (i.value() == MARK_CUT_END);
01389 first = false;
01390 uint64_t mappedKey = TranslatePosition(map, i.key(), fallback_ratio);
01391 if (i.value() == MARK_CUT_START && !withinCut)
01392 {
01393 withinCut = true;
01394 startOfCutRegion = mappedKey;
01395 if (relPosition + addition <= startOfCutRegion)
01396 break;
01397 }
01398 else if (i.value() == MARK_CUT_END && withinCut)
01399 {
01400 withinCut = false;
01401 addition += (mappedKey - startOfCutRegion);
01402 }
01403 }
01404 return relPosition + addition;
01405 }
01406
01407
01408