Go to the documentation of this file.
5 #include "libmythbase/mythconfig.h"
15 #define LOC QString("Dec: ")
18 : m_parent(parent), m_playbackInfo(new
ProgramInfo(pginfo)),
19 m_audio(m_parent->GetAudio()),
38 if (RenderFormats !=
nullptr)
50 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
51 QString(
"Reset: Video %1, Seek %2, File %3")
52 .arg(reset_video_data).arg(seek_reset).arg(reset_file));
108 if (m_fps < 26 && m_fps > 24)
118 if (m_fps < 26 && m_fps > 24)
124 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
125 QString(
"%1 TotalTimeOfTitle() in ticks, %2 TotalReadPosition() "
126 "in bytes, %3 is fps")
150 if (m_fps < 26 && m_fps > 24)
182 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)
262 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
263 QString(
"Position map filled from Encoder to: %1")
272 last_index = it.key();
274 for (frm_pos_map_t::const_iterator it = durMap.cbegin();
275 it != durMap.cend(); ++it)
277 if (!isEmpty && it.key() <= last_index)
287 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
288 QString(
"Duration map filled from Encoder to: %1").arg(it.key()));
324 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
325 QString(
"Resyncing position map. posmapStarted = %1"
326 " livetv(%2) watchingRec(%3)")
333 unsigned long new_posmap_size = old_posmap_size;
342 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
343 QString(
"SyncPositionMap watchingrecording, from DB: "
344 "%1 entries") .arg(new_posmap_size));
349 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
350 QString(
"SyncPositionMap watchingrecording no entries "
351 "from encoder, try DB"));
356 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
357 QString(
"SyncPositionMap watchingrecording total: %1 entries")
358 .arg(new_posmap_size));
368 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
369 QString(
"SyncPositionMap prerecorded, from DB: %1 entries")
370 .arg(new_posmap_size));
374 bool ret_val = new_posmap_size > old_posmap_size;
378 long long totframes = 0;
379 std::chrono::seconds length = 0s;
405 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
406 QString(
"SyncPositionMap, new totframes: %1, new length: %2, "
408 .arg(totframes).arg(length.count()).arg(new_posmap_size));
421 int &lower_bound,
int &upper_bound)
426 long long lower = -1;
427 long long upper = size;
432 while (upper - 1 > lower)
434 long long i = (upper + lower) / 2;
440 if (value == desired_value)
446 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
447 QString(
"FindPosition(%1, search%2 adjusted)")
448 .arg(desired_value).arg((search_adjusted) ?
"" :
" not") +
449 QString(
" --> [%1:%2(%3)]")
455 if (value > desired_value)
464 while (lower >= 0 &&
m_positionMap[lower].adjFrame > desired_value)
466 while (upper < size &&
m_positionMap[upper].adjFrame < desired_value)
474 while (upper < size &&
479 lower = std::max(lower, 0LL);
480 upper = std::min(upper, size - 1LL);
486 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
487 QString(
"FindPosition(%1, search%3 adjusted)")
488 .arg(desired_value).arg((search_adjusted) ?
"" :
" not") +
489 QString(
" --> \n\t\t\t[%1:%2(%3),%4:%5(%6)]")
518 if (entry.index < first)
520 if (entry.index > last)
523 posMap[entry.index] = entry.pos;
530 if (it.key() < first)
534 durMap[it.key()] = it.value();
544 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
545 QString(
"Saving position map [%1,%2] w/%3 keyframes, "
546 "took (%4,%5,%6) ms")
547 .arg(first).arg(last).arg(saved)
557 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
558 QString(
"DoRewind(%1 (%2), %3 discard frames)")
560 .arg((discardFrames) ?
"do" :
"don't"));
573 normalframes = std::max(normalframes, 0);
595 LOG(VB_GENERAL, LOG_ERR,
LOC +
"PosMap is empty, can't seek");
601 LOG(VB_GENERAL, LOG_ERR,
LOC +
"No ringBuffer yet, can't seek");
615 int pos_idx = pre_idx;
619 GetKey(e_post) - desiredFrame <= desiredFrame -
GetKey(e_pre))
658 long long last_frame = 0;
671 if (desiredFrame < 0)
676 if (desiredFrame < last_frame)
679 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
680 "ConditionallyUpdatePosMap: Not enough info in positionMap," +
681 QString(
"\n\t\t\twe need frame %1 but highest we have is %2.")
682 .arg(desiredFrame).arg(last_frame));
688 if (desiredFrame > last_frame)
690 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
691 "ConditionallyUpdatePosMap: Still not "
692 "enough info in positionMap after sync, " +
693 QString(
"\n\t\t\twe need frame %1 but highest we have "
694 "is %2. Will attempt to seek frame-by-frame")
695 .arg(desiredFrame).arg(last_frame));
712 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
713 QString(
"DoFastForward(%1 (%2), %3 discard frames)")
715 .arg((discardFrames) ?
"do" :
"don't"));
719 LOG(VB_GENERAL, LOG_ERR,
LOC +
"No ringBuffer yet, can't fast forward");
735 return DoRewind(desiredFrame, discardFrames);
749 bool needflush =
false;
750 if (desiredFrame > last_frame)
752 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
753 QString(
"DoFastForward(): desiredFrame(%1) > last_frame(%2)")
754 .arg(desiredFrame).arg(last_frame));
756 if (desiredFrame - last_frame > 32)
758 LOG(VB_GENERAL, LOG_ERR,
LOC +
"DoFastForward(): "
759 "Desired frame is way past the end of the keyframe map!"
760 "\n\t\t\tSeeking to last keyframe instead.");
761 desiredFrame = last_frame;
770 while ((desiredFrame > last_frame) && !
m_atEof)
804 normalframes = std::max(normalframes, 0);
834 LOG(VB_GENERAL, LOG_ERR,
LOC +
835 "No ringBuffer yet, can't fast forward seek");
856 GetKey(e_post) - desiredFrame < desiredFrame -
GetKey(e_pre)))
926 for (
size_t i = 0; i <
m_tracks[Type].size(); i++)
934 if (TrackNo >=
m_tracks[Type].size())
936 return static_cast<int>(
m_tracks[Type][TrackNo].m_language_index);
942 if (TrackNo >=
m_tracks[Type].size())
946 int lang =
m_tracks[Type][TrackNo].m_language;
947 int hnum =
static_cast<int>(TrackNo + 1);
949 hnum =
m_tracks[Type][TrackNo].m_stream_id;
952 return type_msg + QString(
" %1").arg(hnum);
954 return type_msg + QString(
" %1: %2").arg(hnum).arg(lang_msg);
966 if (TrackNo >=
static_cast<int>(
m_tracks[Type].size()))
986 if (TrackNo >=
m_tracks[Type].size())
999 int size =
static_cast<int>(
m_tracks[Type].size());
1005 next_track = (std::max(+0,
m_currentTrack[Type]) + size - 1) % size;
1014 int next_track = -1;
1015 int size =
static_cast<int>(
m_tracks[Type].size());
1070 int selTrack = (1 == numStreams) ? 0 : -1;
1074 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Trying to reselect track");
1080 for (
uint i = 0; i < numStreams; i++)
1082 if (wlang ==
m_tracks[Type][i].m_language)
1084 selTrack =
static_cast<int>(i);
1085 if (windx ==
m_tracks[Type][i].m_language_index)
1098 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Trying to select track (w/lang & forced)");
1099 const int kForcedWeight = (1 << 20);
1100 const int kLanguageWeight = (1 << 10);
1101 const int kPositionWeight = (1 << 0);
1104 for (
uint i = 0; i < numStreams; i++)
1109 int position =
static_cast<int>(numStreams) -
static_cast<int>(i);
1116 int score = (kForcedWeight *
static_cast<int>(forced)) +
1117 (kLanguageWeight * language) +
1118 (kPositionWeight * position);
1119 if (score > bestScore)
1122 selTrack =
static_cast<int>(i);
1136 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Selected track #%1 (type %2) in the %3 language(%4)")
1159 QString str = QObject::tr(
"Track");
1162 str = QObject::tr(
"Audio track");
1164 str = QObject::tr(
"Video track");
1166 str = QObject::tr(
"Subtitle track");
1168 str = QObject::tr(
"CC",
"EIA-608 closed captions");
1170 str = QObject::tr(
"ATSC CC",
"EIA-708 closed captions");
1172 str = QObject::tr(
"TT CC",
"Teletext closed captions");
1174 str = QObject::tr(
"TT Menu",
"Teletext Menu");
1176 str = QObject::tr(
"Text",
"Text stream");
1178 str = QObject::tr(
"TXT File",
"Text File");
1186 if (str.startsWith(
"AUDIO"))
1188 else if (str.startsWith(
"VIDEO"))
1190 else if (str.startsWith(
"SUBTITLE"))
1192 else if (str.startsWith(
"CC608"))
1194 else if (str.startsWith(
"CC708"))
1196 else if (str.startsWith(
"TTC"))
1198 else if (str.startsWith(
"TTM"))
1200 else if (str.startsWith(
"TFL"))
1202 else if (str.startsWith(
"RAWTEXT"))
1214 str = QObject::tr(
"Audio Description",
1215 "On-screen events described for the visually impaired");
1218 str = QObject::tr(
"Clean Effects",
1219 "No dialog, background audio only");
1222 str = QObject::tr(
"Hearing Impaired",
1223 "Clear dialog for the hearing impaired");
1226 str = QObject::tr(
"Spoken Subtitles",
1227 "Subtitles are read out for the visually impaired");
1230 str = QObject::tr(
"Commentary",
"Director/Cast commentary track");
1234 str = QObject::tr(
"Normal",
"Ordinary audio track");
1262 float fallback_ratio)
1269 frm_pos_map_t::const_iterator lower = map.lowerBound(key);
1272 if (lower != map.begin() && (lower == map.end() || lower.key() > key))
1274 if (lower == map.end() || lower.key() > key)
1278 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
1279 QString(
"TranslatePosition(key=%1): extrapolating to (0,0)")
1285 val1 = lower.value();
1289 frm_pos_map_t::const_iterator upper = map.lowerBound(key);
1290 if (upper == map.end())
1294 val2 = llroundf(val1 + fallback_ratio * (key2 - key1));
1295 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
1296 QString(
"TranslatePosition(key=%1, ratio=%2): "
1297 "extrapolating to (%3,%4)")
1298 .arg(key).arg(fallback_ratio).arg(key2).arg(val2));
1302 val2 = upper.value();
1306 return llround(val1 + (
double) (key - key1) * (val2 - val1) / (key2 - key1));
1312 float fallback_framerate,
1325 if (position > it.key())
1328 (QDateTime::currentDateTime() >
1334 1000 / fallback_framerate));
1340 float fallback_framerate,
1347 1000 / fallback_framerate);
1364 uint64_t absPosition,
1366 float fallback_ratio)
1368 uint64_t subtraction = 0;
1369 uint64_t startOfCutRegion = 0;
1370 bool withinCut =
false;
1372 for (frm_dir_map_t::const_iterator i = deleteMap.begin();
1373 i != deleteMap.end(); ++i)
1378 if (i.key() > absPosition)
1384 startOfCutRegion = mappedKey;
1389 subtraction += (mappedKey - startOfCutRegion);
1394 subtraction += (mappedPos - startOfCutRegion);
1395 return mappedPos - subtraction;
1413 uint64_t relPosition,
1415 float fallback_ratio)
1417 uint64_t addition = 0;
1418 uint64_t startOfCutRegion = 0;
1419 bool withinCut =
false;
1421 for (frm_dir_map_t::const_iterator i = deleteMap.begin();
1422 i != deleteMap.end(); ++i)
1431 startOfCutRegion = mappedKey;
1432 if (relPosition + addition <= startOfCutRegion)
1438 addition += (mappedKey - startOfCutRegion);
1441 return relPosition + addition;
1450 for (AVPixelFormat *format = Formats; *format != AV_PIX_FMT_NONE; format++)
1452 for (
auto fmt : *RenderFormats)
1456 return AV_PIX_FMT_NONE;
AVRational AVRationalInit(int num, int den=1)
virtual bool DoFastForward(long long desiredFrame, bool discardFrames=true)
Skips ahead or rewinds to desiredFrame.
@ kAudioTypeHearingImpaired
double GetFrameRate(void)
std::enable_if_t< std::is_floating_point_v< T >, std::chrono::seconds > secondsFromFloat(T value)
Helper function for convert a floating point number to a duration.
std::chrono::milliseconds elapsed(void)
Returns milliseconds elapsed since last start() or restart()
virtual int SetTrack(uint Type, int TrackNo)
std::chrono::seconds TitleTimeLeft(void) const
returns seconds left in the title
void SetFileLength(std::chrono::seconds total, int frames)
std::array< StreamInfo, kTrackTypeCount > m_selectedTrack
MythMediaBuffer * m_ringBuffer
const VideoFrameTypes * m_renderFormats
void QueryPositionMap(frm_pos_map_t &posMap, MarkTypes type) const
A QElapsedTimer based timer to replace use of QTime as a timer.
QDateTime m_lastPositionMapUpdate
int to_track_type(const QString &str)
uint64_t GetTotalReadPosition(void)
void SavePositionMapDelta(frm_pos_map_t &posMap, MarkTypes type) const
bool m_hasKeyFrameAdjustTable
void SaveTotalFrames(int64_t frames)
Store the Total Frames at frame 0 in the recordedmarkup table.
long long ConditionallyUpdatePosMap(long long desiredFrame)
virtual int AutoSelectTrack(uint Type)
Select best track.
uint64_t SavePositionMapDelta(long long first_frame, long long last_frame)
DecoderBase(MythPlayer *parent, const ProgramInfo &pginfo)
QMap< uint64_t, MarkTypes > frm_dir_map_t
Frame # -> Mark map.
void start(void)
starts measuring elapsed time.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
int ChangeTrack(uint Type, int Dir)
QRecursiveMutex m_trackLock
MarkTypes m_positionMapType
bool ForcedSubtitlesFavored(void) const
double GetFrameRate(void)
used by DecoderBase for the total frame number calculation for position map support and ffw/rew.
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)
frm_pos_map_t m_frameToDurMap
bool GetWaitForChange(void) const
void SetWaitForChange(void)
std::array< int, kTrackTypeCount > m_currentTrack
std::chrono::seconds GetTotalTimeOfTitle(void) const
get the total time of the title in seconds 90000 ticks = 1 sec
bool m_dontSyncPositionMap
uint64_t TranslatePositionMsToFrame(std::chrono::milliseconds dur_ms, float fallback_framerate, const frm_dir_map_t &cutlist)
std::array< sinfo_vec_t, kTrackTypeCount > m_tracks
@ kAudioTypeAudioDescription
QString toString(TrackType type)
virtual QString GetTrackDesc(uint Type, uint TrackNo)
void SaveTotalDuration(void)
virtual uint GetTrackCount(uint Type)
virtual bool FindPosition(long long desired_value, bool search_adjusted, int &lower_bound, int &upper_bound)
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)
StreamInfo GetTrackInfo(uint Type, uint TrackNo)
std::vector< int > m_languagePreference
language preferences for auto-selection of streams
virtual bool DoRewindSeek(long long desiredFrame)
std::vector< VideoFrameType > VideoFrameTypes
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::vector< PosMapEntry > m_positionMap
@ kTrackTypeTeletextCaptions
void SaveTotalDuration(std::chrono::milliseconds duration)
Store the Total Duration at frame 0 in the recordedmarkup table.
std::chrono::milliseconds TranslatePositionFrameToMs(long long position, float fallback_framerate, const frm_dir_map_t &cutlist)
frm_pos_map_t m_durToFrameMap
virtual void ResetPosMap(void)
void SetReadAdjust(long long adjust)
ProgramInfo * m_playbackInfo
AVRational m_totalDuration
bool PosMapFromEnc(uint64_t start, frm_pos_map_t &posMap, frm_pos_map_t &durMap)
unsigned long GetPositionMapSize(void) const
void AutoSelectTracks(void)
std::array< StreamInfo, kTrackTypeCount > m_wantedTrack
virtual bool SyncPositionMap(void)
Updates the position map used for skipping frames.
QMap< long long, long long > frm_pos_map_t
Frame # -> File offset map.
void SetProgramInfo(const ProgramInfo &pginfo)
long long GetKey(const PosMapEntry &entry) const
virtual bool PosMapFromEnc(void)
Queries encoder for position map data that has not been committed to the DB yet.
virtual void SetWatchingRecording(bool mode)
virtual bool GetFrame(DecodeType Type, bool &Retry)=0
Demux, preprocess and possibly decode a frame of video/audio.
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...
void SetKeyframeDistance(int keyframedistance)
virtual void UpdateFramesPlayed(void)
Holds information on recordings and videos.
void SetDecodeAllSubtitles(bool DecodeAll)
void SetFramesPlayed(uint64_t played)
void FileChangedCallback()
QRecursiveMutex m_positionMapLock
void SetRenderFormats(const VideoFrameTypes *RenderFormats)
bool m_decodeAllSubtitles
static AVPixelFormat FrameTypeToPixelFormat(VideoFrameType Type)
static uint64_t TranslatePosition(const frm_pos_map_t &map, long long key, float fallback_ratio)
virtual bool PosMapFromDb(void)
static AVPixelFormat GetBestVideoFormat(AVPixelFormat *Formats, const VideoFrameTypes *RenderFormats)
Find a suitable frame format that is mutually acceptable to the decoder and render device.
ISO 639-1 and ISO 639-2 support functions.
long long GetTotalReadPosition(void) const
void SignalTracksChanged(uint Type)
virtual void Reset(bool reset_video_data, bool seek_reset, bool reset_file)
virtual QStringList GetTracks(uint Type)
long long GetLastFrameInPosMap(void) const
virtual void SetEofState(EofState eof)
virtual bool InsertTrack(uint Type, const StreamInfo &Info)
std::chrono::seconds GetTotalTimeOfTitle(void) const
virtual void SeekReset(long long newkey, uint skipFrames, bool doFlush, bool discardFrames)
virtual bool DoRewind(long long desiredFrame, bool discardFrames=true)
bool m_recordingHasPositionMap
virtual int GetTrackLanguageIndex(uint Type, uint TrackNo)
std::enable_if_t< std::is_floating_point_v< T >, std::chrono::milliseconds > millisecondsFromFloat(T value)
Helper function for convert a floating point number to a duration.
void SaveTotalFrames(void)