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()))
982 if (
m_tracks[Type][forcedTrackIndex].m_forced)
993 if (TrackNo >=
m_tracks[Type].size())
1005 int next_track = -1;
1006 int size =
static_cast<int>(
m_tracks[Type].size());
1012 next_track = (std::max(+0,
m_currentTrack[Type]) + size - 1) % size;
1021 int next_track = -1;
1022 int size =
static_cast<int>(
m_tracks[Type].size());
1066 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Trying to select track (w/lang & %1forced)")
1067 .arg(forcedPreferred ?
"" :
"!"));
1068 const int kForcedWeight = forcedPreferred ? (1 << 20) : -(1 << 20);
1069 const int kLanguageWeight = (1 << 10);
1070 const int kPositionWeight = (1 << 0);
1075 for (
uint i = 0; i < numStreams; i++)
1079 int position =
static_cast<int>(numStreams) -
static_cast<int>(i);
1081 if (preferredLanguage != 0 &&
m_tracks[Type][i].m_language == preferredLanguage)
1090 int score = (1 << 20) +
1091 (kForcedWeight *
static_cast<int>(forced)) +
1092 (kLanguageWeight * language) +
1093 (kPositionWeight * position);
1094 if (score > bestScore)
1097 selTrack =
static_cast<int>(i);
1135 int selTrack = (1 == numStreams) ? 0 : -1;
1139 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Trying to reselect track");
1145 for (
uint i = 0; i < numStreams; i++)
1147 if (wlang ==
m_tracks[Type][i].m_language)
1149 selTrack =
static_cast<int>(i);
1150 if (windx ==
m_tracks[Type][i].m_language_index)
1163 if (
m_tracks[Type][selTrack].m_forced)
1169 int nonForcedTrack =
BestTrack(Type,
false);
1171 if (!
m_tracks[Type][nonForcedTrack].m_forced)
1174 selTrack = nonForcedTrack;
1189 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Selected track #%1 (type %2) in the %3 language(%4)")
1212 QString str = QObject::tr(
"Track");
1215 str = QObject::tr(
"Audio track");
1217 str = QObject::tr(
"Video track");
1219 str = QObject::tr(
"Subtitle track");
1221 str = QObject::tr(
"CC",
"EIA-608 closed captions");
1223 str = QObject::tr(
"ATSC CC",
"EIA-708 closed captions");
1225 str = QObject::tr(
"TT CC",
"Teletext closed captions");
1227 str = QObject::tr(
"TT Menu",
"Teletext Menu");
1229 str = QObject::tr(
"Text",
"Text stream");
1231 str = QObject::tr(
"TXT File",
"Text File");
1239 if (str.startsWith(
"AUDIO"))
1241 else if (str.startsWith(
"VIDEO"))
1243 else if (str.startsWith(
"SUBTITLE"))
1245 else if (str.startsWith(
"CC608"))
1247 else if (str.startsWith(
"CC708"))
1249 else if (str.startsWith(
"TTC"))
1251 else if (str.startsWith(
"TTM"))
1253 else if (str.startsWith(
"TFL"))
1255 else if (str.startsWith(
"RAWTEXT"))
1267 str = QObject::tr(
"Audio Description",
1268 "On-screen events described for the visually impaired");
1271 str = QObject::tr(
"Clean Effects",
1272 "No dialog, background audio only");
1275 str = QObject::tr(
"Hearing Impaired",
1276 "Clear dialog for the hearing impaired");
1279 str = QObject::tr(
"Spoken Subtitles",
1280 "Subtitles are read out for the visually impaired");
1283 str = QObject::tr(
"Commentary",
"Director/Cast commentary track");
1287 str = QObject::tr(
"Normal",
"Ordinary audio track");
1315 float fallback_ratio)
1322 frm_pos_map_t::const_iterator lower = map.lowerBound(key);
1325 if (lower != map.begin() && (lower == map.end() || lower.key() > key))
1327 if (lower == map.end() || lower.key() > key)
1331 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
1332 QString(
"TranslatePosition(key=%1): extrapolating to (0,0)")
1338 val1 = lower.value();
1342 frm_pos_map_t::const_iterator upper = map.lowerBound(key);
1343 if (upper == map.end())
1347 val2 = llroundf(val1 + fallback_ratio * (key2 - key1));
1348 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
1349 QString(
"TranslatePosition(key=%1, ratio=%2): "
1350 "extrapolating to (%3,%4)")
1351 .arg(key).arg(fallback_ratio).arg(key2).arg(val2));
1355 val2 = upper.value();
1359 return llround(val1 + (
double) (key - key1) * (val2 - val1) / (key2 - key1));
1365 float fallback_framerate,
1378 if (position > it.key())
1381 (QDateTime::currentDateTime() >
1387 1000 / fallback_framerate));
1393 float fallback_framerate,
1400 1000 / fallback_framerate);
1417 uint64_t absPosition,
1419 float fallback_ratio)
1421 uint64_t subtraction = 0;
1422 uint64_t startOfCutRegion = 0;
1423 bool withinCut =
false;
1425 for (frm_dir_map_t::const_iterator i = deleteMap.begin();
1426 i != deleteMap.end(); ++i)
1431 if (i.key() > absPosition)
1437 startOfCutRegion = mappedKey;
1442 subtraction += (mappedKey - startOfCutRegion);
1447 subtraction += (mappedPos - startOfCutRegion);
1448 return mappedPos - subtraction;
1466 uint64_t relPosition,
1468 float fallback_ratio)
1470 uint64_t addition = 0;
1471 uint64_t startOfCutRegion = 0;
1472 bool withinCut =
false;
1474 for (frm_dir_map_t::const_iterator i = deleteMap.begin();
1475 i != deleteMap.end(); ++i)
1484 startOfCutRegion = mappedKey;
1485 if (relPosition + addition <= startOfCutRegion)
1491 addition += (mappedKey - startOfCutRegion);
1494 return relPosition + addition;
1503 for (AVPixelFormat *format = Formats; *format != AV_PIX_FMT_NONE; format++)
1505 for (
auto fmt : *RenderFormats)
1509 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
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)
std::array< StreamInfo, kTrackTypeCount > m_selectedForcedTrack
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)
int BestTrack(uint Type, bool forcedPreferred, int preferredLanguage=0)
Determine the best track according to weights.
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)