7 #include "mythconfig.h"
20 #define LOC QString("Dec: ")
23 : m_parent(parent), m_playbackinfo(new
ProgramInfo(pginfo)),
24 m_audio(m_parent->GetAudio()), ringBuffer(NULL),
26 current_width(640), current_height(480),
27 current_aspect(1.33333), fps(29.97),
30 framesPlayed(0), framesRead(0),
32 lastKey(0), keyframedist(-1), indexOffset(0),
33 trackTotalDuration(
false),
37 hasFullPositionMap(
false), recordingHasPositionMap(
false),
40 m_positionMapLock(QMutex::Recursive),
41 dontSyncPositionMap(
false),
43 seeksnap(UINT64_MAX), livetv(
false), watchingrecording(
false),
45 hasKeyFrameAdjustTable(
false), lowbuffers(
false),
47 errored(
false), waitingForChange(
false), readAdjust(0),
48 justAfterChange(
false),
49 video_inverted(
false),
50 decodeAllSubtitles(
false),
75 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
76 QString(
"Reset: Video %1, Seek %2, File %3")
77 .arg(reset_video_data).arg(seek_reset).arg(reset_file));
131 if (fps < 26 && fps > 24)
141 if (fps < 26 && fps > 24)
146 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
147 QString(
"%1 TotalTimeOfTitle() in ticks, %2 TotalReadPosition() "
148 "in bytes, %3 is fps")
172 if (fps < 26 && fps > 24)
202 for (frm_pos_map_t::const_iterator it = posMap.begin();
203 it != posMap.end(); ++it)
214 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
215 QString(
"Position map filled from DB to: %1")
220 for (frm_pos_map_t::const_iterator it = durMap.begin();
221 it != durMap.end(); ++it)
230 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
231 QString(
"Duration map filled from DB to: %1").arg(last));
250 unsigned long long start = 0;
266 for (frm_pos_map_t::const_iterator it = posMap.begin();
267 it != posMap.end(); ++it)
269 if (it.key() <= last_index)
281 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
282 QString(
"Position map filled from Encoder to: %1")
291 last_index = it.key();
293 for (frm_pos_map_t::const_iterator it = durMap.begin();
294 it != durMap.end(); ++it)
296 if (!isEmpty && it.key() <= last_index)
306 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
307 QString(
"Duration map filled from Encoder to: %1").arg(it.key()));
343 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
344 QString(
"Resyncing position map. posmapStarted = %1"
345 " livetv(%2) watchingRec(%3)")
352 unsigned long new_posmap_size = old_posmap_size;
361 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
362 QString(
"SyncPositionMap watchingrecording, from DB: "
363 "%1 entries") .arg(new_posmap_size));
368 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
369 QString(
"SyncPositionMap watchingrecording no entries "
370 "from encoder, try DB"));
375 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
376 QString(
"SyncPositionMap watchingrecording total: %1 entries")
377 .arg(new_posmap_size));
387 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
388 QString(
"SyncPositionMap prerecorded, from DB: %1 entries")
389 .arg(new_posmap_size));
393 bool ret_val = new_posmap_size > old_posmap_size;
397 long long totframes = 0;
417 length = (
int)((totframes * 1.0) /
fps);
422 posmapStarted =
true;
424 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
425 QString(
"SyncPositionMap, new totframes: %1, new length: %2, "
427 .arg(totframes).arg(length).arg(new_posmap_size));
440 int &lower_bound,
int &upper_bound)
445 long long lower = -1;
446 long long upper =
size;
451 while (upper - 1 > lower)
453 long long i = (upper + lower) / 2;
459 if (value == desired_value)
465 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
466 QString(
"FindPosition(%1, search%2 adjusted)")
467 .arg(desired_value).arg((search_adjusted) ?
"" :
" not") +
468 QString(
" --> [%1:%2(%3)]")
474 else if (value > desired_value)
483 while (lower >= 0 &&
m_positionMap[lower].adjFrame > desired_value)
485 while (upper < size &&
m_positionMap[upper].adjFrame < desired_value)
493 while (upper < size &&
498 lower = max(lower, 0LL);
499 upper = min(upper, size - 1LL);
505 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
506 QString(
"FindPosition(%1, search%3 adjusted)")
507 .arg(desired_value).arg((search_adjusted) ?
"" :
" not") +
508 QString(
" --> \n\t\t\t[%1:%2(%3),%4:%5(%6)]")
548 if (it.key() < first)
552 durMap[it.key()] = it.value();
562 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
563 QString(
"Saving position map [%1,%2] w/%3 keyframes, "
564 "took (%4,%5,%6) ms")
565 .arg(first).arg(last).arg(saved)
575 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
576 QString(
"DoRewind(%1 (%2), %3 discard frames)")
578 .arg((discardFrames) ?
"do" :
"don't"));
590 normalframes = max(normalframes, 0);
612 LOG(VB_GENERAL, LOG_ERR,
LOC +
"PosMap is empty, can't seek");
618 LOG(VB_GENERAL, LOG_ERR,
LOC +
"No ringBuffer yet, can't seek");
623 int pre_idx, post_idx;
631 int pos_idx = pre_idx;
635 GetKey(e_post) - desiredFrame <= desiredFrame -
GetKey(e_pre))
672 long long last_frame = 0;
685 if (desiredFrame < 0)
690 if (desiredFrame < last_frame)
693 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
694 "ConditionallyUpdatePosMap: Not enough info in positionMap," +
695 QString(
"\n\t\t\twe need frame %1 but highest we have is %2.")
696 .arg(desiredFrame).arg(last_frame));
702 if (desiredFrame > last_frame)
704 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
705 "ConditionallyUpdatePosMap: Still not "
706 "enough info in positionMap after sync, " +
707 QString(
"\n\t\t\twe need frame %1 but highest we have "
708 "is %2. Will attempt to seek frame-by-frame")
709 .arg(desiredFrame).arg(last_frame));
726 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
727 QString(
"DoFastForward(%1 (%2), %3 discard frames)")
729 .arg((discardFrames) ?
"do" :
"don't"));
733 LOG(VB_GENERAL, LOG_ERR,
LOC +
"No ringBuffer yet, can't fast forward");
749 return DoRewind(desiredFrame, discardFrames);
763 bool needflush =
false;
764 if (desiredFrame > last_frame)
766 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
767 QString(
"DoFastForward(): desiredFrame(%1) > last_frame(%2)")
768 .arg(desiredFrame).arg(last_frame));
770 if (desiredFrame - last_frame > 32)
772 LOG(VB_GENERAL, LOG_ERR,
LOC +
"DoFastForward(): "
773 "Desired frame is way past the end of the keyframe map!"
774 "\n\t\t\tSeeking to last keyframe instead.");
775 desiredFrame = last_frame;
784 while ((desiredFrame > last_frame) && !
ateof)
817 normalframes = max(normalframes, 0);
847 LOG(VB_GENERAL, LOG_ERR,
LOC +
848 "No ringBuffer yet, can't fast forward seek");
852 int pre_idx, post_idx;
866 GetKey(e_post) - desiredFrame < desiredFrame -
GetKey(e_pre)))
947 int hnum = trackNo + 1;
952 return type_msg + QString(
" %1").arg(hnum);
956 return type_msg + QString(
" %1: %2").arg(hnum).arg(lang_msg);
1041 int selTrack = (1 == numStreams) ? 0 : -1;
1043 if ((selTrack < 0) &&
1046 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Trying to reselect track");
1052 for (
uint i = 0; i < numStreams; i++)
1054 if (wlang ==
tracks[type][i].language)
1056 if (windx ==
tracks[type][i].language_index)
1061 if (selTrack < 0 && numStreams)
1068 LOG(VB_PLAYBACK, LOG_INFO,
1069 LOC +
"Trying to select track (w/lang & forced)");
1070 const int kForcedWeight = (1 << 20);
1071 const int kLanguageWeight = (1 << 10);
1072 const int kPositionWeight = (1 << 0);
1075 for (
uint i = 0; i < numStreams; i++)
1080 int position = numStreams - i;
1088 int score = kForcedWeight * forced
1089 + kLanguageWeight * language
1090 + kPositionWeight * position;
1091 if (score > bestScore)
1108 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1109 QString(
"Selected track #%1 in the %2 language(%3)")
1110 .arg(currentTrack[type]+1)
1113 if (
m_parent && (oldTrack != currentTrack[type]))
1121 QString str = QObject::tr(
"Track");
1124 str = QObject::tr(
"Audio track");
1126 str = QObject::tr(
"Video track");
1128 str = QObject::tr(
"Subtitle track");
1130 str = QObject::tr(
"CC",
"EIA-608 closed captions");
1132 str = QObject::tr(
"ATSC CC",
"EIA-708 closed captions");
1134 str = QObject::tr(
"TT CC",
"Teletext closed captions");
1136 str = QObject::tr(
"TT Menu",
"Teletext Menu");
1138 str = QObject::tr(
"Text",
"Text stream");
1140 str = QObject::tr(
"TXT File",
"Text File");
1148 if (str.startsWith(
"AUDIO"))
1150 else if (str.startsWith(
"VIDEO"))
1152 else if (str.startsWith(
"SUBTITLE"))
1154 else if (str.startsWith(
"CC608"))
1156 else if (str.startsWith(
"CC708"))
1158 else if (str.startsWith(
"TTC"))
1160 else if (str.startsWith(
"TTM"))
1162 else if (str.startsWith(
"TFL"))
1164 else if (str.startsWith(
"RAWTEXT"))
1176 str = QObject::tr(
"Audio Description",
1177 "On-screen events described for the visually impaired");
1180 str = QObject::tr(
"Clean Effects",
1181 "No dialog, background audio only");
1184 str = QObject::tr(
"Hearing Impaired",
1185 "Clear dialog for the hearing impaired");
1188 str = QObject::tr(
"Spoken Subtitles",
1189 "Subtitles are read out for the visually impaired");
1192 str = QObject::tr(
"Commentary",
"Director/Cast commentary track");
1196 str = QObject::tr(
"Normal",
"Ordinary audio track");
1224 float fallback_ratio)
1226 uint64_t key1, key2;
1227 uint64_t val1, val2;
1229 frm_pos_map_t::const_iterator lower = map.lowerBound(key);
1232 if (lower != map.begin() && (lower == map.end() || lower.key() > key))
1234 if (lower == map.end() || lower.key() > key)
1238 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
1239 QString(
"TranslatePosition(key=%1): extrapolating to (0,0)")
1245 val1 = lower.value();
1249 frm_pos_map_t::const_iterator upper = map.lowerBound(key);
1250 if (upper == map.end())
1254 val2 = val1 + fallback_ratio * (key2 - key1) + 0.5;
1255 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
1256 QString(
"TranslatePosition(key=%1, ratio=%2): "
1257 "extrapolating to (%3,%4)")
1258 .arg(key).arg(fallback_ratio).arg(key2).arg(val2));
1264 val2 = upper.value();
1269 return val1 + (double) (key - key1) * (val2 - val1) / (key2 - key1) + 0.5;
1275 float fallback_framerate,
1288 if (position > it.key())
1291 (QDateTime::currentDateTime() >
1297 1000 / fallback_framerate);
1303 float fallback_framerate,
1310 1000 / fallback_framerate);
1327 uint64_t absPosition,
1329 float fallback_ratio)
1331 uint64_t subtraction = 0;
1332 uint64_t startOfCutRegion = 0;
1333 bool withinCut =
false;
1335 for (frm_dir_map_t::const_iterator i = deleteMap.begin();
1336 i != deleteMap.end(); ++i)
1341 if (i.key() > absPosition)
1347 startOfCutRegion = mappedKey;
1352 subtraction += (mappedKey - startOfCutRegion);
1357 subtraction += (mappedPos - startOfCutRegion);
1358 return mappedPos - subtraction;
1376 uint64_t relPosition,
1378 float fallback_ratio)
1380 uint64_t addition = 0;
1381 uint64_t startOfCutRegion = 0;
1382 bool withinCut =
false;
1384 for (frm_dir_map_t::const_iterator i = deleteMap.begin();
1385 i != deleteMap.end(); ++i)
1394 startOfCutRegion = mappedKey;
1395 if (relPosition + addition <= startOfCutRegion)
1401 addition += (mappedKey - startOfCutRegion);
1404 return relPosition + addition;