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());
1054 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Trying to select track (w/lang & %1forced)")
1055 .arg(forcedPreferred ?
"" :
"!"));
1056 const int kForcedWeight = forcedPreferred ? (1 << 20) : -(1 << 20);
1057 const int kLanguageWeight = (1 << 10);
1058 const int kPositionWeight = (1 << 0);
1063 for (
uint i = 0; i < numStreams; i++)
1067 int position =
static_cast<int>(numStreams) -
static_cast<int>(i);
1069 if (preferredLanguage != 0 &&
m_tracks[Type][i].m_language == preferredLanguage)
1078 int score = (1 << 20) +
1079 (kForcedWeight *
static_cast<int>(forced)) +
1080 (kLanguageWeight * language) +
1081 (kPositionWeight * position);
1082 if (score > bestScore)
1085 selTrack =
static_cast<int>(i);
1123 int selTrack = (1 == numStreams) ? 0 : -1;
1127 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Trying to reselect track");
1133 for (
uint i = 0; i < numStreams; i++)
1135 if (wlang ==
m_tracks[Type][i].m_language)
1137 selTrack =
static_cast<int>(i);
1138 if (windx ==
m_tracks[Type][i].m_language_index)
1151 if (
m_tracks[Type][selTrack].m_forced)
1157 int nonForcedTrack =
BestTrack(Type,
false);
1159 if (!
m_tracks[Type][nonForcedTrack].m_forced)
1162 selTrack = nonForcedTrack;
1177 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Selected track #%1 (type %2) in the %3 language(%4)")
1200 QString str = QObject::tr(
"Track");
1203 str = QObject::tr(
"Audio track");
1205 str = QObject::tr(
"Video track");
1207 str = QObject::tr(
"Subtitle track");
1209 str = QObject::tr(
"CC",
"EIA-608 closed captions");
1211 str = QObject::tr(
"ATSC CC",
"EIA-708 closed captions");
1213 str = QObject::tr(
"TT CC",
"Teletext closed captions");
1215 str = QObject::tr(
"TT Menu",
"Teletext Menu");
1217 str = QObject::tr(
"Text",
"Text stream");
1219 str = QObject::tr(
"TXT File",
"Text File");
1227 if (str.startsWith(
"AUDIO"))
1229 else if (str.startsWith(
"VIDEO"))
1231 else if (str.startsWith(
"SUBTITLE"))
1233 else if (str.startsWith(
"CC608"))
1235 else if (str.startsWith(
"CC708"))
1237 else if (str.startsWith(
"TTC"))
1239 else if (str.startsWith(
"TTM"))
1241 else if (str.startsWith(
"TFL"))
1243 else if (str.startsWith(
"RAWTEXT"))
1255 str = QObject::tr(
"Audio Description",
1256 "On-screen events described for the visually impaired");
1259 str = QObject::tr(
"Clean Effects",
1260 "No dialog, background audio only");
1263 str = QObject::tr(
"Hearing Impaired",
1264 "Clear dialog for the hearing impaired");
1267 str = QObject::tr(
"Spoken Subtitles",
1268 "Subtitles are read out for the visually impaired");
1271 str = QObject::tr(
"Commentary",
"Director/Cast commentary track");
1275 str = QObject::tr(
"Normal",
"Ordinary audio track");
1303 float fallback_ratio)
1310 frm_pos_map_t::const_iterator lower = map.lowerBound(key);
1313 if (lower != map.begin() && (lower == map.end() || lower.key() > key))
1315 if (lower == map.end() || lower.key() > key)
1319 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
1320 QString(
"TranslatePosition(key=%1): extrapolating to (0,0)")
1326 val1 = lower.value();
1330 frm_pos_map_t::const_iterator upper = map.lowerBound(key);
1331 if (upper == map.end())
1335 val2 = llroundf(val1 + (fallback_ratio * (key2 - key1)));
1336 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
1337 QString(
"TranslatePosition(key=%1, ratio=%2): "
1338 "extrapolating to (%3,%4)")
1339 .arg(key).arg(fallback_ratio).arg(key2).arg(val2));
1343 val2 = upper.value();
1347 return llround(val1 + ((
double) (key - key1) * (val2 - val1) / (key2 - key1)));
1353 float fallback_framerate,
1366 if (position > it.key())
1369 (QDateTime::currentDateTime() >
1375 1000 / fallback_framerate));
1381 float fallback_framerate,
1388 1000 / fallback_framerate);
1405 uint64_t absPosition,
1407 float fallback_ratio)
1409 uint64_t subtraction = 0;
1410 uint64_t startOfCutRegion = 0;
1411 bool withinCut =
false;
1413 for (frm_dir_map_t::const_iterator i = deleteMap.begin();
1414 i != deleteMap.end(); ++i)
1419 if (i.key() > absPosition)
1425 startOfCutRegion = mappedKey;
1430 subtraction += (mappedKey - startOfCutRegion);
1435 subtraction += (mappedPos - startOfCutRegion);
1436 return mappedPos - subtraction;
1454 uint64_t relPosition,
1456 float fallback_ratio)
1458 uint64_t addition = 0;
1459 uint64_t startOfCutRegion = 0;
1460 bool withinCut =
false;
1462 for (frm_dir_map_t::const_iterator i = deleteMap.begin();
1463 i != deleteMap.end(); ++i)
1472 startOfCutRegion = mappedKey;
1473 if (relPosition + addition <= startOfCutRegion)
1479 addition += (mappedKey - startOfCutRegion);
1482 return relPosition + addition;
1491 for (AVPixelFormat *format = Formats; *format != AV_PIX_FMT_NONE; format++)
1493 for (
auto fmt : *RenderFormats)
1497 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
@ 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
void SignalTracksChanged(uint Type)
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)
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)
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)