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()),
37 if (RenderFormats !=
nullptr)
49 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
50 QString(
"Reset: Video %1, Seek %2, File %3")
51 .arg(reset_video_data).arg(seek_reset).arg(reset_file));
107 if (m_fps < 26 && m_fps > 24)
117 if (m_fps < 26 && m_fps > 24)
123 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
124 QString(
"%1 TotalTimeOfTitle() in ticks, %2 TotalReadPosition() "
125 "in bytes, %3 is fps")
149 if (m_fps < 26 && m_fps > 24)
181 for (
auto it = posMap.cbegin(); it != posMap.cend(); ++it)
192 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
193 QString(
"Position map filled from DB to: %1")
198 for (
auto it = durMap.cbegin(); it != durMap.cend(); ++it)
207 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
208 QString(
"Duration map filled from DB to: %1").arg(last));
227 unsigned long long start = 0;
244 long long last_index = 0;
247 for (
auto it = posMap.cbegin(); it != posMap.cend(); ++it)
249 if (it.key() <= last_index)
261 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
262 QString(
"Position map filled from Encoder to: %1")
271 last_index = it.key();
273 for (frm_pos_map_t::const_iterator it = durMap.cbegin();
274 it != durMap.cend(); ++it)
276 if (!isEmpty && it.key() <= last_index)
286 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
287 QString(
"Duration map filled from Encoder to: %1").arg(it.key()));
323 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
324 QString(
"Resyncing position map. posmapStarted = %1"
325 " livetv(%2) watchingRec(%3)")
332 unsigned long new_posmap_size = old_posmap_size;
341 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
342 QString(
"SyncPositionMap watchingrecording, from DB: "
343 "%1 entries") .arg(new_posmap_size));
348 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
349 QString(
"SyncPositionMap watchingrecording no entries "
350 "from encoder, try DB"));
355 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
356 QString(
"SyncPositionMap watchingrecording total: %1 entries")
357 .arg(new_posmap_size));
367 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
368 QString(
"SyncPositionMap prerecorded, from DB: %1 entries")
369 .arg(new_posmap_size));
373 bool ret_val = new_posmap_size > old_posmap_size;
377 long long totframes = 0;
378 std::chrono::seconds length = 0s;
404 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
405 QString(
"SyncPositionMap, new totframes: %1, new length: %2, "
407 .arg(totframes).arg(length.count()).arg(new_posmap_size));
420 int &lower_bound,
int &upper_bound)
425 long long lower = -1;
426 long long upper = size;
431 while (upper - 1 > lower)
433 long long i = (upper + lower) / 2;
439 if (value == desired_value)
445 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
446 QString(
"FindPosition(%1, search%2 adjusted)")
447 .arg(desired_value).arg((search_adjusted) ?
"" :
" not") +
448 QString(
" --> [%1:%2(%3)]")
454 if (value > desired_value)
463 while (lower >= 0 &&
m_positionMap[lower].adjFrame > desired_value)
465 while (upper < size &&
m_positionMap[upper].adjFrame < desired_value)
473 while (upper < size &&
478 lower = std::max(lower, 0LL);
479 upper = std::min(upper, size - 1LL);
485 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
486 QString(
"FindPosition(%1, search%3 adjusted)")
487 .arg(desired_value).arg((search_adjusted) ?
"" :
" not") +
488 QString(
" --> \n\t\t\t[%1:%2(%3),%4:%5(%6)]")
517 if (entry.index < first)
519 if (entry.index > last)
522 posMap[entry.index] = entry.pos;
529 if (it.key() < first)
533 durMap[it.key()] = it.value();
543 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
544 QString(
"Saving position map [%1,%2] w/%3 keyframes, "
545 "took (%4,%5,%6) ms")
546 .arg(first).arg(last).arg(saved)
556 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
557 QString(
"DoRewind(%1 (%2), %3 discard frames)")
559 .arg((discardFrames) ?
"do" :
"don't"));
572 normalframes = std::max(normalframes, 0);
594 LOG(VB_GENERAL, LOG_ERR,
LOC +
"PosMap is empty, can't seek");
600 LOG(VB_GENERAL, LOG_ERR,
LOC +
"No ringBuffer yet, can't seek");
614 int pos_idx = pre_idx;
618 GetKey(e_post) - desiredFrame <= desiredFrame -
GetKey(e_pre))
657 long long last_frame = 0;
670 if (desiredFrame < 0)
675 if (desiredFrame < last_frame)
678 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
679 "ConditionallyUpdatePosMap: Not enough info in positionMap," +
680 QString(
"\n\t\t\twe need frame %1 but highest we have is %2.")
681 .arg(desiredFrame).arg(last_frame));
687 if (desiredFrame > last_frame)
689 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
690 "ConditionallyUpdatePosMap: Still not "
691 "enough info in positionMap after sync, " +
692 QString(
"\n\t\t\twe need frame %1 but highest we have "
693 "is %2. Will attempt to seek frame-by-frame")
694 .arg(desiredFrame).arg(last_frame));
711 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
712 QString(
"DoFastForward(%1 (%2), %3 discard frames)")
714 .arg((discardFrames) ?
"do" :
"don't"));
718 LOG(VB_GENERAL, LOG_ERR,
LOC +
"No ringBuffer yet, can't fast forward");
734 return DoRewind(desiredFrame, discardFrames);
744 bool needflush =
false;
745 if (desiredFrame > last_frame)
747 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
748 QString(
"DoFastForward(): desiredFrame(%1) > last_frame(%2)")
749 .arg(desiredFrame).arg(last_frame));
751 if (desiredFrame - last_frame > 32)
753 LOG(VB_GENERAL, LOG_ERR,
LOC +
"DoFastForward(): "
754 "Desired frame is way past the end of the keyframe map!"
755 "\n\t\t\tSeeking to last keyframe instead.");
756 desiredFrame = last_frame;
765 while ((desiredFrame > last_frame) && !
m_atEof)
795 normalframes = std::max(normalframes, 0);
822 LOG(VB_GENERAL, LOG_ERR,
LOC +
823 "No ringBuffer yet, can't fast forward seek");
844 GetKey(e_post) - desiredFrame < desiredFrame -
GetKey(e_pre)))
914 for (
size_t i = 0; i <
m_tracks[Type].size(); i++)
922 if (TrackNo >=
m_tracks[Type].size())
924 return static_cast<int>(
m_tracks[Type][TrackNo].m_language_index);
930 if (TrackNo >=
m_tracks[Type].size())
934 int lang =
m_tracks[Type][TrackNo].m_language;
935 int hnum =
static_cast<int>(TrackNo + 1);
937 hnum =
m_tracks[Type][TrackNo].m_stream_id;
940 return type_msg + QString(
" %1").arg(hnum);
942 return type_msg + QString(
" %1: %2").arg(hnum).arg(lang_msg);
954 if (TrackNo >=
static_cast<int>(
m_tracks[Type].size()))
970 if (
m_tracks[Type][forcedTrackIndex].m_forced)
981 if (TrackNo >=
m_tracks[Type].size())
994 int size =
static_cast<int>(
m_tracks[Type].size());
1000 next_track = (std::max(+0,
m_currentTrack[Type]) + size - 1) % size;
1009 int next_track = -1;
1010 int size =
static_cast<int>(
m_tracks[Type].size());
1036 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Trying to select track (w/lang & %1forced)")
1037 .arg(forcedPreferred ?
"" :
"!"));
1038 const int kForcedWeight = forcedPreferred ? (1 << 20) : -(1 << 20);
1039 const int kLanguageWeight = (1 << 10);
1040 const int kPositionWeight = (1 << 0);
1045 for (
uint i = 0; i < numStreams; i++)
1049 int position =
static_cast<int>(numStreams) -
static_cast<int>(i);
1051 if (preferredLanguage != 0 &&
m_tracks[Type][i].m_language == preferredLanguage)
1060 int score = (1 << 20) +
1061 (kForcedWeight *
static_cast<int>(forced)) +
1062 (kLanguageWeight * language) +
1063 (kPositionWeight * position);
1064 if (score > bestScore)
1067 selTrack =
static_cast<int>(i);
1105 int selTrack = (1 == numStreams) ? 0 : -1;
1109 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Trying to reselect track");
1115 for (
uint i = 0; i < numStreams; i++)
1117 if (wlang ==
m_tracks[Type][i].m_language)
1119 selTrack =
static_cast<int>(i);
1120 if (windx ==
m_tracks[Type][i].m_language_index)
1133 if (
m_tracks[Type][selTrack].m_forced)
1139 int nonForcedTrack =
BestTrack(Type,
false);
1141 if (!
m_tracks[Type][nonForcedTrack].m_forced)
1144 selTrack = nonForcedTrack;
1159 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Selected track #%1 (type %2) in the %3 language(%4)")
1182 QString str = QObject::tr(
"Track");
1185 str = QObject::tr(
"Audio track");
1187 str = QObject::tr(
"Video track");
1189 str = QObject::tr(
"Subtitle track");
1191 str = QObject::tr(
"CC",
"EIA-608 closed captions");
1193 str = QObject::tr(
"ATSC CC",
"EIA-708 closed captions");
1195 str = QObject::tr(
"TT CC",
"Teletext closed captions");
1197 str = QObject::tr(
"TT Menu",
"Teletext Menu");
1199 str = QObject::tr(
"Text",
"Text stream");
1201 str = QObject::tr(
"TXT File",
"Text File");
1209 if (str.startsWith(
"AUDIO"))
1211 else if (str.startsWith(
"VIDEO"))
1213 else if (str.startsWith(
"SUBTITLE"))
1215 else if (str.startsWith(
"CC608"))
1217 else if (str.startsWith(
"CC708"))
1219 else if (str.startsWith(
"TTC"))
1221 else if (str.startsWith(
"TTM"))
1223 else if (str.startsWith(
"TFL"))
1225 else if (str.startsWith(
"RAWTEXT"))
1237 str = QObject::tr(
"Audio Description",
1238 "On-screen events described for the visually impaired");
1241 str = QObject::tr(
"Clean Effects",
1242 "No dialog, background audio only");
1245 str = QObject::tr(
"Hearing Impaired",
1246 "Clear dialog for the hearing impaired");
1249 str = QObject::tr(
"Spoken Subtitles",
1250 "Subtitles are read out for the visually impaired");
1253 str = QObject::tr(
"Commentary",
"Director/Cast commentary track");
1257 str = QObject::tr(
"Normal",
"Ordinary audio track");
1285 float fallback_ratio)
1292 frm_pos_map_t::const_iterator lower = map.lowerBound(key);
1295 if (lower != map.begin() && (lower == map.end() || lower.key() > key))
1297 if (lower == map.end() || lower.key() > key)
1301 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
1302 QString(
"TranslatePosition(key=%1): extrapolating to (0,0)")
1308 val1 = lower.value();
1312 frm_pos_map_t::const_iterator upper = map.lowerBound(key);
1313 if (upper == map.end())
1317 val2 = llroundf(val1 + (fallback_ratio * (key2 - key1)));
1318 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
1319 QString(
"TranslatePosition(key=%1, ratio=%2): "
1320 "extrapolating to (%3,%4)")
1321 .arg(key).arg(fallback_ratio).arg(key2).arg(val2));
1325 val2 = upper.value();
1329 return llround(val1 + ((
double) (key - key1) * (val2 - val1) / (key2 - key1)));
1335 float fallback_framerate,
1348 if (position > it.key())
1351 (QDateTime::currentDateTime() >
1357 1000 / fallback_framerate));
1363 float fallback_framerate,
1370 1000 / fallback_framerate);
1387 uint64_t absPosition,
1389 float fallback_ratio)
1391 uint64_t subtraction = 0;
1392 uint64_t startOfCutRegion = 0;
1393 bool withinCut =
false;
1395 for (frm_dir_map_t::const_iterator i = deleteMap.begin();
1396 i != deleteMap.end(); ++i)
1401 if (i.key() > absPosition)
1407 startOfCutRegion = mappedKey;
1412 subtraction += (mappedKey - startOfCutRegion);
1417 subtraction += (mappedPos - startOfCutRegion);
1418 return mappedPos - subtraction;
1436 uint64_t relPosition,
1438 float fallback_ratio)
1440 uint64_t addition = 0;
1441 uint64_t startOfCutRegion = 0;
1442 bool withinCut =
false;
1444 for (frm_dir_map_t::const_iterator i = deleteMap.begin();
1445 i != deleteMap.end(); ++i)
1454 startOfCutRegion = mappedKey;
1455 if (relPosition + addition <= startOfCutRegion)
1461 addition += (mappedKey - startOfCutRegion);
1464 return relPosition + addition;
1473 for (AVPixelFormat *format = Formats; *format != AV_PIX_FMT_NONE; format++)
1475 for (
auto fmt : *RenderFormats)
1479 return AV_PIX_FMT_NONE;
virtual bool DoFastForward(long long desiredFrame, bool discardFrames=true)
Skips ahead or rewinds to desiredFrame.
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
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)
MythAVRational m_totalDuration
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
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
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 void tracksChanged([[maybe_unused]] uint TrackType)
@ kAudioTypeHearingImpaired
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.
@ kTrackTypeTeletextCaptions
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.
C++ wrapper for FFmpeg libavutil AVRational.
long long GetTotalReadPosition(void) const
virtual void Reset(bool reset_video_data, bool seek_reset, bool reset_file)
@ kAudioTypeAudioDescription
virtual QStringList GetTracks(uint Type)
long long GetLastFrameInPosMap(void) const
virtual void SetEofState(EofState eof)
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)
long long toFixed(long long base) const
Convert the rational number to fixed point.
bool m_recordingHasPositionMap
virtual int GetTrackLanguageIndex(uint Type, uint TrackNo)
void SaveTotalFrames(void)