14#define LOC QString("Dec: ")
17 : m_parent(parent), m_playbackInfo(new
ProgramInfo(pginfo)),
18 m_audio(m_parent->GetAudio()),
36 if (RenderFormats !=
nullptr)
48 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
49 QString(
"Reset: Video %1, Seek %2, File %3")
50 .arg(reset_video_data).arg(seek_reset).arg(reset_file));
106 if (m_fps < 26 && m_fps > 24)
116 if (m_fps < 26 && m_fps > 24)
122 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
123 QString(
"%1 TotalTimeOfTitle() in ticks, %2 TotalReadPosition() "
124 "in bytes, %3 is fps")
148 if (m_fps < 26 && m_fps > 24)
180 for (
auto it = posMap.cbegin(); it != posMap.cend(); ++it)
193 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
194 QString(
"Position map filled from DB to: %1")
199 for (
auto it = durMap.cbegin(); it != durMap.cend(); ++it)
208 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
209 QString(
"Duration map filled from DB to: %1").arg(last));
228 unsigned long long start = 0;
245 long long last_index = 0;
248 for (
auto it = posMap.cbegin(); it != posMap.cend(); ++it)
250 if (it.key() <= last_index)
264 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
265 QString(
"Position map filled from Encoder to: %1")
274 last_index = it.key();
276 for (frm_pos_map_t::const_iterator it = durMap.cbegin();
277 it != durMap.cend(); ++it)
279 if (!isEmpty && it.key() <= last_index)
289 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
290 QString(
"Duration map filled from Encoder to: %1").arg(it.key()));
326 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
327 QString(
"Resyncing position map. posmapStarted = %1"
328 " livetv(%2) watchingRec(%3)")
335 unsigned long new_posmap_size = old_posmap_size;
344 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
345 QString(
"SyncPositionMap watchingrecording, from DB: "
346 "%1 entries") .arg(new_posmap_size));
351 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
352 QString(
"SyncPositionMap watchingrecording no entries "
353 "from encoder, try DB"));
358 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
359 QString(
"SyncPositionMap watchingrecording total: %1 entries")
360 .arg(new_posmap_size));
370 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
371 QString(
"SyncPositionMap prerecorded, from DB: %1 entries")
372 .arg(new_posmap_size));
376 bool ret_val = new_posmap_size > old_posmap_size;
380 long long totframes = 0;
381 std::chrono::seconds length = 0s;
407 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
408 QString(
"SyncPositionMap, new totframes: %1, new length: %2, "
410 .arg(totframes).arg(length.count()).arg(new_posmap_size));
423 int &lower_bound,
int &upper_bound)
428 long long lower = -1;
429 long long upper = size;
434 while (upper - 1 > lower)
436 long long i = (upper + lower) / 2;
442 if (value == desired_value)
448 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
449 QString(
"FindPosition(%1, search%2 adjusted)")
450 .arg(desired_value).arg((search_adjusted) ?
"" :
" not") +
451 QString(
" --> [%1:%2(%3)]")
457 if (value > desired_value)
466 while (lower >= 0 &&
m_positionMap[lower].adjFrame > desired_value)
468 while (upper < size &&
m_positionMap[upper].adjFrame < desired_value)
476 while (upper < size &&
481 lower = std::max(lower, 0LL);
482 upper = std::min(upper, size - 1LL);
488 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
489 QString(
"FindPosition(%1, search%3 adjusted)")
490 .arg(desired_value).arg((search_adjusted) ?
"" :
" not") +
491 QString(
" --> \n\t\t\t[%1:%2(%3),%4:%5(%6)]")
520 if (entry.index < first)
522 if (entry.index > last)
525 posMap[entry.index] = entry.pos;
532 if (it.key() < first)
536 durMap[it.key()] = it.value();
546 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
547 QString(
"Saving position map [%1,%2] w/%3 keyframes, "
548 "took (%4,%5,%6) ms")
549 .arg(first).arg(last).arg(saved)
560 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
561 QString(
"DoRewind(%1 (%2), %3 discard frames)")
563 .arg((discardFrames) ?
"do" :
"don't"));
576 normalframes = std::max(normalframes, 0);
598 LOG(VB_GENERAL, LOG_ERR,
LOC +
"PosMap is empty, can't seek");
604 LOG(VB_GENERAL, LOG_ERR,
LOC +
"No ringBuffer yet, can't seek");
618 int pos_idx = pre_idx;
622 GetKey(e_post) - desiredFrame <= desiredFrame -
GetKey(e_pre))
661 long long last_frame = 0;
674 if (desiredFrame < 0)
679 if (desiredFrame < last_frame)
682 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
683 "ConditionallyUpdatePosMap: Not enough info in positionMap," +
684 QString(
"\n\t\t\twe need frame %1 but highest we have is %2.")
685 .arg(desiredFrame).arg(last_frame));
691 if (desiredFrame > last_frame)
693 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
694 "ConditionallyUpdatePosMap: Still not "
695 "enough info in positionMap after sync, " +
696 QString(
"\n\t\t\twe need frame %1 but highest we have "
697 "is %2. Will attempt to seek frame-by-frame")
698 .arg(desiredFrame).arg(last_frame));
715 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
716 QString(
"DoFastForward(%1 (%2), %3 discard frames)")
718 .arg((discardFrames) ?
"do" :
"don't"));
722 LOG(VB_GENERAL, LOG_ERR,
LOC +
"No ringBuffer yet, can't fast forward");
738 return DoRewind(desiredFrame, discardFrames);
748 bool needflush =
false;
749 if (desiredFrame > last_frame)
751 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
752 QString(
"DoFastForward(): desiredFrame(%1) > last_frame(%2)")
753 .arg(desiredFrame).arg(last_frame));
755 if (desiredFrame - last_frame > 32)
757 LOG(VB_GENERAL, LOG_ERR,
LOC +
"DoFastForward(): "
758 "Desired frame is way past the end of the keyframe map!"
759 "\n\t\t\tSeeking to last keyframe instead.");
760 desiredFrame = last_frame;
769 while ((desiredFrame > last_frame) && !
m_atEof)
799 normalframes = std::max(normalframes, 0);
826 LOG(VB_GENERAL, LOG_ERR,
LOC +
827 "No ringBuffer yet, can't fast forward seek");
848 GetKey(e_post) - desiredFrame < desiredFrame -
GetKey(e_pre)))
918 for (
size_t i = 0; i <
m_tracks[Type].size(); i++)
926 if (TrackNo >=
m_tracks[Type].size())
928 return static_cast<int>(
m_tracks[Type][TrackNo].m_language_index);
934 if (TrackNo >=
m_tracks[Type].size())
938 int lang =
m_tracks[Type][TrackNo].m_language;
939 int hnum =
static_cast<int>(TrackNo + 1);
941 hnum =
m_tracks[Type][TrackNo].m_stream_id;
944 return type_msg + QString(
" %1").arg(hnum);
946 return type_msg + QString(
" %1: %2").arg(hnum).arg(lang_msg);
958 if (TrackNo >=
static_cast<int>(
m_tracks[Type].size()))
974 if (
m_tracks[Type][forcedTrackIndex].m_forced)
985 if (TrackNo >=
m_tracks[Type].size())
998 int size =
static_cast<int>(
m_tracks[Type].size());
1004 next_track = (std::max(+0,
m_currentTrack[Type]) + size - 1) % size;
1013 int next_track = -1;
1014 int size =
static_cast<int>(
m_tracks[Type].size());
1040 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Trying to select track (w/lang & %1forced)")
1041 .arg(forcedPreferred ?
"" :
"!"));
1042 const int kForcedWeight = forcedPreferred ? (1 << 20) : -(1 << 20);
1043 const int kLanguageWeight = (1 << 10);
1044 const int kPositionWeight = (1 << 0);
1049 for (
uint i = 0; i < numStreams; i++)
1053 int position =
static_cast<int>(numStreams) -
static_cast<int>(i);
1055 if (preferredLanguage != 0 &&
m_tracks[Type][i].m_language == preferredLanguage)
1064 int score = (1 << 20) +
1065 (kForcedWeight *
static_cast<int>(forced)) +
1066 (kLanguageWeight * language) +
1067 (kPositionWeight * position);
1068 if (score > bestScore)
1071 selTrack =
static_cast<int>(i);
1109 int selTrack = (1 == numStreams) ? 0 : -1;
1113 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Trying to reselect track");
1119 for (
uint i = 0; i < numStreams; i++)
1121 if (wlang ==
m_tracks[Type][i].m_language)
1123 selTrack =
static_cast<int>(i);
1124 if (windx ==
m_tracks[Type][i].m_language_index)
1137 if (
m_tracks[Type][selTrack].m_forced)
1143 int nonForcedTrack =
BestTrack(Type,
false);
1145 if (!
m_tracks[Type][nonForcedTrack].m_forced)
1148 selTrack = nonForcedTrack;
1163 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Selected track #%1 (type %2) in the %3 language(%4)")
1186 QString str = QObject::tr(
"Track");
1189 str = QObject::tr(
"Audio track");
1191 str = QObject::tr(
"Video track");
1193 str = QObject::tr(
"Subtitle track");
1195 str = QObject::tr(
"CC",
"EIA-608 closed captions");
1197 str = QObject::tr(
"ATSC CC",
"EIA-708 closed captions");
1199 str = QObject::tr(
"TT CC",
"Teletext closed captions");
1201 str = QObject::tr(
"TT Menu",
"Teletext Menu");
1203 str = QObject::tr(
"Text",
"Text stream");
1205 str = QObject::tr(
"TXT File",
"Text File");
1213 if (str.startsWith(
"AUDIO"))
1215 else if (str.startsWith(
"VIDEO"))
1217 else if (str.startsWith(
"SUBTITLE"))
1219 else if (str.startsWith(
"CC608"))
1221 else if (str.startsWith(
"CC708"))
1223 else if (str.startsWith(
"TTC"))
1225 else if (str.startsWith(
"TTM"))
1227 else if (str.startsWith(
"TFL"))
1229 else if (str.startsWith(
"RAWTEXT"))
1241 str = QObject::tr(
"Audio Description",
1242 "On-screen events described for the visually impaired");
1245 str = QObject::tr(
"Clean Effects",
1246 "No dialog, background audio only");
1249 str = QObject::tr(
"Hearing Impaired",
1250 "Clear dialog for the hearing impaired");
1253 str = QObject::tr(
"Spoken Subtitles",
1254 "Subtitles are read out for the visually impaired");
1257 str = QObject::tr(
"Commentary",
"Director/Cast commentary track");
1261 str = QObject::tr(
"Normal",
"Ordinary audio track");
1289 float fallback_ratio)
1296 frm_pos_map_t::const_iterator lower = map.lowerBound(key);
1299 if (lower != map.begin() && (lower == map.end() || lower.key() > key))
1301 if (lower == map.end() || lower.key() > key)
1305 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
1306 QString(
"TranslatePosition(key=%1): extrapolating to (0,0)")
1312 val1 = lower.value();
1316 frm_pos_map_t::const_iterator upper = map.lowerBound(key);
1317 if (upper == map.end())
1321 val2 = llroundf(val1 + (fallback_ratio * (key2 - key1)));
1322 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
1323 QString(
"TranslatePosition(key=%1, ratio=%2): "
1324 "extrapolating to (%3,%4)")
1325 .arg(key).arg(fallback_ratio).arg(key2).arg(val2));
1329 val2 = upper.value();
1333 return llround(val1 + ((
double) (key - key1) * (val2 - val1) / (key2 - key1)));
1339 float fallback_framerate,
1352 if (position > it.key())
1355 (QDateTime::currentDateTime() >
1361 1000 / fallback_framerate));
1367 float fallback_framerate,
1374 1000 / fallback_framerate);
1391 uint64_t absPosition,
1393 float fallback_ratio)
1395 uint64_t subtraction = 0;
1396 uint64_t startOfCutRegion = 0;
1397 bool withinCut =
false;
1399 for (frm_dir_map_t::const_iterator i = deleteMap.begin();
1400 i != deleteMap.end(); ++i)
1405 if (i.key() > absPosition)
1411 startOfCutRegion = mappedKey;
1416 subtraction += (mappedKey - startOfCutRegion);
1421 subtraction += (mappedPos - startOfCutRegion);
1422 return mappedPos - subtraction;
1440 uint64_t relPosition,
1442 float fallback_ratio)
1444 uint64_t addition = 0;
1445 uint64_t startOfCutRegion = 0;
1446 bool withinCut =
false;
1448 for (frm_dir_map_t::const_iterator i = deleteMap.begin();
1449 i != deleteMap.end(); ++i)
1458 startOfCutRegion = mappedKey;
1459 if (relPosition + addition <= startOfCutRegion)
1465 addition += (mappedKey - startOfCutRegion);
1468 return relPosition + addition;
1477 for (AVPixelFormat *format = Formats; *format != AV_PIX_FMT_NONE; format++)
1479 for (
auto fmt : *RenderFormats)
1483 return AV_PIX_FMT_NONE;
MythAVRational m_totalDuration
QRecursiveMutex m_positionMapLock
virtual uint GetTrackCount(uint Type)
MarkTypes m_positionMapType
frm_pos_map_t m_frameToDurMap
virtual void SetWatchingRecording(bool mode)
virtual void DoFastForwardSeek(long long desiredFrame, bool &needflush)
Seeks to the keyframe just before the desiredFrame if exact seeks is enabled, or the frame just after...
int ChangeTrack(uint Type, int Dir)
void SetProgramInfo(const ProgramInfo &pginfo)
long long GetKey(const PosMapEntry &entry) const
virtual bool GetFrame(DecodeType Type, bool &Retry)=0
Demux, preprocess and possibly decode a frame of video/audio.
bool m_dontSyncPositionMap
virtual QString GetTrackDesc(uint Type, uint TrackNo)
virtual int SetTrack(uint Type, int TrackNo)
virtual void UpdateFramesPlayed(void)
void SetReadAdjust(long long adjust)
MythMediaBuffer * m_ringBuffer
QRecursiveMutex m_trackLock
void SetRenderFormats(const VideoFrameTypes *RenderFormats)
bool m_decodeAllSubtitles
virtual bool PosMapFromEnc(void)
Queries encoder for position map data that has not been committed to the DB yet.
void AutoSelectTracks(void)
std::vector< int > m_languagePreference
language preferences for auto-selection of streams
void SaveTotalDuration(void)
virtual void Reset(bool reset_video_data, bool seek_reset, bool reset_file)
virtual void ResetPosMap(void)
virtual void SetEofState(EofState eof)
long long GetLastFrameInPosMap(void) const
static uint64_t TranslatePosition(const frm_pos_map_t &map, long long key, float fallback_ratio)
std::array< StreamInfo, kTrackTypeCount > m_wantedTrack
frm_pos_map_t m_durToFrameMap
static uint64_t TranslatePositionAbsToRel(const frm_dir_map_t &deleteMap, uint64_t absPosition, const frm_pos_map_t &map=frm_pos_map_t(), float fallback_ratio=1.0)
void SetWaitForChange(void)
uint64_t SavePositionMapDelta(long long first_frame, long long last_frame)
bool GetWaitForChange(void) const
DecoderBase(MythPlayer *parent, const ProgramInfo &pginfo)
virtual bool FindPosition(long long desired_value, bool search_adjusted, int &lower_bound, int &upper_bound)
const VideoFrameTypes * m_renderFormats
virtual bool PosMapFromDb(void)
virtual bool DoFastForward(long long desiredFrame, bool discardFrames=true)
Skips ahead or rewinds to desiredFrame.
uint64_t TranslatePositionMsToFrame(std::chrono::milliseconds dur_ms, float fallback_framerate, const frm_dir_map_t &cutlist)
void SaveTotalFrames(void)
long long ConditionallyUpdatePosMap(long long desiredFrame)
static AVPixelFormat GetBestVideoFormat(AVPixelFormat *Formats, const VideoFrameTypes *RenderFormats)
Find a suitable frame format that is mutually acceptable to the decoder and render device.
bool m_hasKeyFrameAdjustTable
virtual void SeekReset(long long newkey, uint skipFrames, bool doFlush, bool discardFrames)
std::array< sinfo_vec_t, kTrackTypeCount > m_tracks
virtual bool SyncPositionMap(void)
Updates the position map used for skipping frames.
virtual int AutoSelectTrack(uint Type)
Select best track.
virtual QStringList GetTracks(uint Type)
QDateTime m_lastPositionMapUpdate
StreamInfo GetTrackInfo(uint Type, uint TrackNo)
virtual int GetTrackLanguageIndex(uint Type, uint TrackNo)
unsigned long GetPositionMapSize(void) const
static uint64_t TranslatePositionRelToAbs(const frm_dir_map_t &deleteMap, uint64_t relPosition, const frm_pos_map_t &map=frm_pos_map_t(), float fallback_ratio=1.0)
std::array< StreamInfo, kTrackTypeCount > m_selectedForcedTrack
std::vector< PosMapEntry > m_positionMap
std::array< int, kTrackTypeCount > m_currentTrack
virtual bool DoRewindSeek(long long desiredFrame)
void SetDecodeAllSubtitles(bool DecodeAll)
bool m_recordingHasPositionMap
virtual bool DoRewind(long long desiredFrame, bool discardFrames=true)
int BestTrack(uint Type, bool forcedPreferred, int preferredLanguage=0)
Determine the best track according to weights.
ProgramInfo * m_playbackInfo
std::chrono::milliseconds TranslatePositionFrameToMs(long long position, float fallback_framerate, const frm_dir_map_t &cutlist)
std::array< StreamInfo, kTrackTypeCount > m_selectedTrack
C++ wrapper for FFmpeg libavutil AVRational.
long long toFixed(long long base) const
Convert the rational number to fixed point.
static AVPixelFormat FrameTypeToPixelFormat(VideoFrameType Type)
uint64_t GetTotalReadPosition(void)
std::chrono::seconds GetTotalTimeOfTitle(void) const
double GetFrameRate(void)
long long GetTotalReadPosition(void) const
std::chrono::seconds GetTotalTimeOfTitle(void) const
get the total time of the title in seconds 90000 ticks = 1 sec
std::chrono::seconds TitleTimeLeft(void) const
returns seconds left in the title
double GetFrameRate(void)
used by DecoderBase for the total frame number calculation for position map support and ffw/rew.
void SetFramesPlayed(uint64_t played)
void SetKeyframeDistance(int keyframedistance)
virtual void tracksChanged(uint TrackType)
void FileChangedCallback()
void SetFileLength(std::chrono::seconds total, int frames)
bool PosMapFromEnc(uint64_t start, frm_pos_map_t &posMap, frm_pos_map_t &durMap)
A QElapsedTimer based timer to replace use of QTime as a timer.
std::chrono::milliseconds elapsed(void)
Returns milliseconds elapsed since last start() or restart()
void start(void)
starts measuring elapsed time.
Holds information on recordings and videos.
void QueryPositionMap(frm_pos_map_t &posMap, MarkTypes type) const
void SaveTotalDuration(std::chrono::milliseconds duration)
Store the Total Duration at frame 0 in the recordedmarkup table.
void SaveTotalFrames(int64_t frames)
Store the Total Frames at frame 0 in the recordedmarkup table.
void SavePositionMapDelta(frm_pos_map_t &posMap, MarkTypes type) const
int to_track_type(const QString &str)
QString toString(TrackType type)
@ kAudioTypeAudioDescription
@ kAudioTypeHearingImpaired
@ kTrackTypeTeletextCaptions
QString iso639_key_toName(int iso639_2)
Converts a canonical key to language name in English.
std::vector< int > iso639_get_language_key_list(void)
ISO 639-1 and ISO 639-2 support functions.
std::chrono::seconds secondsFromFloat(T value)
Helper function for convert a floating point number to a duration.
std::vector< VideoFrameType > VideoFrameTypes
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
QMap< uint64_t, MarkTypes > frm_dir_map_t
Frame # -> Mark map.
QMap< long long, long long > frm_pos_map_t
Frame # -> File offset map.