MythTV  master
decoderbase.cpp
Go to the documentation of this file.
1 
2 #include <algorithm>
3 
4 #include "libmythbase/iso639.h"
5 #include "libmythbase/mythconfig.h"
8 
9 #include "Bluray/mythbdbuffer.h"
10 #include "DVD/mythdvdbuffer.h"
11 #include "decoderbase.h"
12 #include "mythcodeccontext.h"
13 #include "mythplayer.h"
14 
15 #define LOC QString("Dec: ")
16 
18  : m_parent(parent), m_playbackInfo(new ProgramInfo(pginfo)),
19  m_audio(m_parent->GetAudio()),
20  m_totalDuration(AVRationalInit(0)),
21 
22  // language preference
23  m_languagePreference(iso639_get_language_key_list())
24 {
25  ResetTracks();
26  m_tracks[kTrackTypeAudio].emplace_back(0, 0, 0, 0, 0);
27  m_tracks[kTrackTypeCC608].emplace_back(0, 0, 0, 1, 0);
28  m_tracks[kTrackTypeCC608].emplace_back(0, 0, 2, 3, 0);
29 }
30 
32 {
33  delete m_playbackInfo;
34 }
35 
37 {
38  if (RenderFormats != nullptr)
39  m_renderFormats = RenderFormats;
40 }
41 
43 {
44  delete m_playbackInfo;
45  m_playbackInfo = new ProgramInfo(pginfo);
46 }
47 
48 void DecoderBase::Reset(bool reset_video_data, bool seek_reset, bool reset_file)
49 {
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));
53 
54  if (seek_reset)
55  SeekReset(0, 0, true, true);
56 
57  if (reset_video_data)
58  {
59  ResetPosMap();
60  m_framesPlayed = 0;
61  m_frameCounter += 100;
62  m_fpsSkip = 0;
63  m_framesRead = 0;
65  m_dontSyncPositionMap = false;
66  }
67 
68  if (reset_file)
69  {
70  m_waitingForChange = false;
72  }
73 }
74 
75 void DecoderBase::SeekReset(long long /*newkey*/, uint /*skipFrames*/,
76  bool /*doFlush*/, bool /*discardFrames*/)
77 {
78  m_readAdjust = 0;
79  m_frameCounter += 100; // NB don't just set to 0
80 }
81 
83 {
84  bool wereWatchingRecording = m_watchingRecording;
85 
86  // When we switch from WatchingRecording to WatchingPreRecorded,
87  // re-get the positionmap
88  m_posmapStarted = false;
89  m_watchingRecording = mode;
90 
91  if (wereWatchingRecording && !m_watchingRecording)
93 }
94 
96 {
97  if (!m_playbackInfo)
98  return false;
99 
100  // Overwrites current positionmap with entire contents of database
101  frm_pos_map_t posMap;
102  frm_pos_map_t durMap;
103 
104  if (m_ringBuffer && m_ringBuffer->IsDVD())
105  {
106  m_keyframeDist = 15;
108  if (m_fps < 26 && m_fps > 24)
109  m_keyframeDist = 12;
110  auto totframes =
111  (long long)(m_ringBuffer->DVD()->GetTotalTimeOfTitle().count() * m_fps);
112  posMap[totframes] = m_ringBuffer->DVD()->GetTotalReadPosition();
113  }
114  else if (m_ringBuffer && m_ringBuffer->IsBD())
115  {
116  m_keyframeDist = 15;
118  if (m_fps < 26 && m_fps > 24)
119  m_keyframeDist = 12;
120  auto totframes =
121  (long long)(m_ringBuffer->BD()->GetTotalTimeOfTitle().count() * m_fps);
122  posMap[totframes] = m_ringBuffer->BD()->GetTotalReadPosition();
123 #if 0
124  LOG(VB_PLAYBACK, LOG_DEBUG, LOC +
125  QString("%1 TotalTimeOfTitle() in ticks, %2 TotalReadPosition() "
126  "in bytes, %3 is fps")
128  .arg(m_ringBuffer->BD()->GetTotalReadPosition()).arg(m_fps));
129 #endif
130  }
131  else if ((m_positionMapType == MARK_UNSET) ||
132  (m_keyframeDist == -1))
133  {
135  if (!posMap.empty())
136  {
138  if (m_keyframeDist == -1)
139  m_keyframeDist = 1;
140  }
141  else
142  {
144  if (!posMap.empty())
145  {
147  if (m_keyframeDist == -1)
148  {
149  m_keyframeDist = 15;
150  if (m_fps < 26 && m_fps > 24)
151  m_keyframeDist = 12;
152  }
153  }
154  else
155  {
157  if (!posMap.empty())
158  {
159  // keyframedist should be set in the fileheader so no
160  // need to try to determine it in this case
162  }
163  }
164  }
165  }
166  else
167  {
169  }
170 
171  if (posMap.empty())
172  return false; // no position map in recording
173 
175 
176  QMutexLocker locker(&m_positionMapLock);
177  m_positionMap.clear();
178  m_positionMap.reserve(posMap.size());
179  m_frameToDurMap.clear();
180  m_durToFrameMap.clear();
181 
182  for (auto it = posMap.cbegin(); it != posMap.cend(); ++it)
183  {
184  PosMapEntry e = {it.key(), it.key() * m_keyframeDist, *it};
185  m_positionMap.push_back(e);
186  }
187 
188  if (!m_positionMap.empty() && !(m_ringBuffer && m_ringBuffer->IsDisc()))
189  m_indexOffset = m_positionMap[0].index;
190 
191  if (!m_positionMap.empty())
192  {
193  LOG(VB_PLAYBACK, LOG_INFO, LOC +
194  QString("Position map filled from DB to: %1")
195  .arg(m_positionMap.back().index));
196  }
197 
198  uint64_t last = 0;
199  for (auto it = durMap.cbegin(); it != durMap.cend(); ++it)
200  {
201  m_frameToDurMap[it.key()] = it.value();
202  m_durToFrameMap[it.value()] = it.key();
203  last = it.key();
204  }
205 
206  if (!m_durToFrameMap.empty())
207  {
208  LOG(VB_PLAYBACK, LOG_INFO, LOC +
209  QString("Duration map filled from DB to: %1").arg(last));
210  }
211 
212  return true;
213 }
214 
224 {
225  if (!m_parent || m_keyframeDist < 1)
226  return false;
227 
228  unsigned long long start = 0;
229  {
230  QMutexLocker locker(&m_positionMapLock);
231  if (!m_positionMap.empty())
232  start = m_positionMap.back().index + 1;
233  }
234 
235  frm_pos_map_t posMap;
236  frm_pos_map_t durMap;
237  if (!m_parent->PosMapFromEnc(start, posMap, durMap))
238  return false;
239 
240  QMutexLocker locker(&m_positionMapLock);
241 
242  // append this new position map to class's
243  m_positionMap.reserve(m_positionMap.size() + posMap.size());
244 
245  long long last_index = 0;
246  if (!m_positionMap.empty())
247  last_index = m_positionMap.back().index;
248  for (auto it = posMap.cbegin(); it != posMap.cend(); ++it)
249  {
250  if (it.key() <= last_index)
251  continue;
252 
253  PosMapEntry e = {it.key(), it.key() * m_keyframeDist, *it};
254  m_positionMap.push_back(e);
255  }
256 
257  if (!m_positionMap.empty() && !(m_ringBuffer && m_ringBuffer->IsDisc()))
258  m_indexOffset = m_positionMap[0].index;
259 
260  if (!m_positionMap.empty())
261  {
262  LOG(VB_PLAYBACK, LOG_INFO, LOC +
263  QString("Position map filled from Encoder to: %1")
264  .arg(m_positionMap.back().index));
265  }
266 
267  bool isEmpty = m_frameToDurMap.empty();
268  if (!isEmpty)
269  {
270  frm_pos_map_t::const_iterator it = m_frameToDurMap.cend();
271  --it;
272  last_index = it.key();
273  }
274  for (frm_pos_map_t::const_iterator it = durMap.cbegin();
275  it != durMap.cend(); ++it)
276  {
277  if (!isEmpty && it.key() <= last_index)
278  continue; // we released the m_positionMapLock for a few ms...
279  m_frameToDurMap[it.key()] = it.value();
280  m_durToFrameMap[it.value()] = it.key();
281  }
282 
283  if (!m_frameToDurMap.empty())
284  {
285  frm_pos_map_t::const_iterator it = m_frameToDurMap.cend();
286  --it;
287  LOG(VB_PLAYBACK, LOG_INFO, LOC +
288  QString("Duration map filled from Encoder to: %1").arg(it.key()));
289  }
290 
291  return true;
292 }
293 
294 unsigned long DecoderBase::GetPositionMapSize(void) const
295 {
296  QMutexLocker locker(&m_positionMapLock);
297  return m_positionMap.size();
298 }
299 
323 {
324  LOG(VB_PLAYBACK, LOG_INFO, LOC +
325  QString("Resyncing position map. posmapStarted = %1"
326  " livetv(%2) watchingRec(%3)")
327  .arg((int) m_posmapStarted).arg(m_livetv).arg(m_watchingRecording));
328 
330  return false;
331 
332  unsigned long old_posmap_size = GetPositionMapSize();
333  unsigned long new_posmap_size = old_posmap_size;
334 
336  {
337  if (!m_posmapStarted)
338  {
339  // starting up -- try first from database
340  PosMapFromDb();
341  new_posmap_size = GetPositionMapSize();
342  LOG(VB_PLAYBACK, LOG_INFO, LOC +
343  QString("SyncPositionMap watchingrecording, from DB: "
344  "%1 entries") .arg(new_posmap_size));
345  }
346  // always try to get more from encoder
347  if (!PosMapFromEnc())
348  {
349  LOG(VB_PLAYBACK, LOG_INFO, LOC +
350  QString("SyncPositionMap watchingrecording no entries "
351  "from encoder, try DB"));
352  PosMapFromDb(); // try again from db
353  }
354 
355  new_posmap_size = GetPositionMapSize();
356  LOG(VB_PLAYBACK, LOG_INFO, LOC +
357  QString("SyncPositionMap watchingrecording total: %1 entries")
358  .arg(new_posmap_size));
359  }
360  else
361  {
362  // watching prerecorded ... just get from db
363  if (!m_posmapStarted)
364  {
365  PosMapFromDb();
366 
367  new_posmap_size = GetPositionMapSize();
368  LOG(VB_PLAYBACK, LOG_INFO, LOC +
369  QString("SyncPositionMap prerecorded, from DB: %1 entries")
370  .arg(new_posmap_size));
371  }
372  }
373 
374  bool ret_val = new_posmap_size > old_posmap_size;
375 
376  if (ret_val && m_keyframeDist > 0)
377  {
378  long long totframes = 0;
379  std::chrono::seconds length = 0s;
380 
381  if (m_ringBuffer && m_ringBuffer->IsDVD())
382  {
383  length = m_ringBuffer->DVD()->GetTotalTimeOfTitle();
384  QMutexLocker locker(&m_positionMapLock);
385  totframes = m_positionMap.back().index;
386  }
387  else if (m_ringBuffer && m_ringBuffer->IsBD())
388  {
389  length = m_ringBuffer->BD()->GetTotalTimeOfTitle();
390  QMutexLocker locker(&m_positionMapLock);
391  totframes = m_positionMap.back().index;
392  }
393  else
394  {
395  QMutexLocker locker(&m_positionMapLock);
396  totframes = m_positionMap.back().index * m_keyframeDist;
397  if (m_fps != 0.0)
398  length = secondsFromFloat((totframes * 1.0) / m_fps);
399  }
400 
401  m_parent->SetFileLength(length, totframes);
403  m_posmapStarted = true;
404 
405  LOG(VB_PLAYBACK, LOG_INFO, LOC +
406  QString("SyncPositionMap, new totframes: %1, new length: %2, "
407  "posMap size: %3")
408  .arg(totframes).arg(length.count()).arg(new_posmap_size));
409  }
410  m_recordingHasPositionMap |= (0 != new_posmap_size);
411  {
412  QMutexLocker locker(&m_positionMapLock);
413  m_lastPositionMapUpdate = QDateTime::currentDateTime();
414  }
415  return ret_val;
416 }
417 
418 // returns true iff found exactly
419 // searches position if search_pos, index otherwise
420 bool DecoderBase::FindPosition(long long desired_value, bool search_adjusted,
421  int &lower_bound, int &upper_bound)
422 {
423  QMutexLocker locker(&m_positionMapLock);
424  // Binary search
425  auto size = (long long) m_positionMap.size();
426  long long lower = -1;
427  long long upper = size;
428 
429  if (!search_adjusted && m_keyframeDist > 0)
430  desired_value /= m_keyframeDist;
431 
432  while (upper - 1 > lower)
433  {
434  long long i = (upper + lower) / 2;
435  long long value = 0;
436  if (search_adjusted)
437  value = m_positionMap[i].adjFrame;
438  else
439  value = m_positionMap[i].index - m_indexOffset;
440  if (value == desired_value)
441  {
442  // found it
443  upper_bound = i;
444  lower_bound = i;
445 
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)]")
450  .arg(i).arg(GetKey(m_positionMap[i]))
451  .arg(m_positionMap[i].pos));
452 
453  return true;
454  }
455  if (value > desired_value)
456  upper = i;
457  else
458  lower = i;
459  }
460  // Did not find it exactly -- return bounds
461 
462  if (search_adjusted)
463  {
464  while (lower >= 0 && m_positionMap[lower].adjFrame > desired_value)
465  lower--;
466  while (upper < size && m_positionMap[upper].adjFrame < desired_value)
467  upper++;
468  }
469  else
470  {
471  while (lower >= 0 &&
472  (m_positionMap[lower].index - m_indexOffset) > desired_value)
473  lower--;
474  while (upper < size &&
475  (m_positionMap[upper].index - m_indexOffset) < desired_value)
476  upper++;
477  }
478  // keep in bounds
479  lower = std::max(lower, 0LL);
480  upper = std::min(upper, size - 1LL);
481 
482  upper_bound = upper;
483  lower_bound = lower;
484  bool empty = m_positionMap.empty();
485 
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)]")
490  .arg(lower_bound)
491  .arg(empty ? -1 : GetKey(m_positionMap[lower_bound]))
492  .arg(empty ? -1 : m_positionMap[lower_bound].pos)
493  .arg(upper_bound)
494  .arg(empty ? -1 : GetKey(m_positionMap[upper_bound]))
495  .arg(empty ? -1 : m_positionMap[upper_bound].pos));
496 
497  return false;
498 }
499 
500 uint64_t DecoderBase::SavePositionMapDelta(long long first, long long last)
501 {
502  MythTimer ttm;
503  MythTimer ctm;
504  MythTimer stm;
505  ttm.start();
506 
507  QMutexLocker locker(&m_positionMapLock);
509  uint64_t saved = 0;
510 
512  return saved;
513 
514  ctm.start();
515  frm_pos_map_t posMap;
516  for (auto & entry : m_positionMap)
517  {
518  if (entry.index < first)
519  continue;
520  if (entry.index > last)
521  break;
522 
523  posMap[entry.index] = entry.pos;
524  saved++;
525  }
526 
527  frm_pos_map_t durMap;
528  for (auto it = m_frameToDurMap.cbegin(); it != m_frameToDurMap.cend(); ++it)
529  {
530  if (it.key() < first)
531  continue;
532  if (it.key() > last)
533  break;
534  durMap[it.key()] = it.value();
535  }
536 
537  locker.unlock();
538 
539  stm.start();
542 
543 #if 0
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)
548  .arg(ttm.elapsed())
549  .arg(ctm.elapsed()-stm.elapsed()).arg(stm.elapsed()));
550 #endif
551 
552  return saved;
553 }
554 
555 bool DecoderBase::DoRewind(long long desiredFrame, bool discardFrames)
556 {
557  LOG(VB_PLAYBACK, LOG_INFO, LOC +
558  QString("DoRewind(%1 (%2), %3 discard frames)")
559  .arg(desiredFrame).arg(m_framesPlayed)
560  .arg((discardFrames) ? "do" : "don't"));
561 
562  if (!DoRewindSeek(desiredFrame))
563  return false;
564 
566  m_fpsSkip = 0;
568 
569  // Do any Extra frame-by-frame seeking for exactseeks mode
570  // And flush pre-seek frame if we are allowed to and need to..
571  int normalframes = (uint64_t)(desiredFrame - (m_framesPlayed - 1)) > m_seekSnap
572  ? desiredFrame - m_framesPlayed : 0;
573  normalframes = std::max(normalframes, 0);
574  SeekReset(m_lastKey, normalframes, true, discardFrames);
575 
576  if (discardFrames || (m_ringBuffer && m_ringBuffer->IsDisc()))
578 
579  return true;
580 }
581 
582 long long DecoderBase::GetKey(const PosMapEntry &e) const
583 {
584  long long kf = (m_ringBuffer && m_ringBuffer->IsDisc()) ?
585  1LL : m_keyframeDist;
586  return (m_hasKeyFrameAdjustTable) ? e.adjFrame :(e.index - m_indexOffset) * kf;
587 }
588 
589 bool DecoderBase::DoRewindSeek(long long desiredFrame)
590 {
591  ConditionallyUpdatePosMap(desiredFrame);
592 
593  if (!GetPositionMapSize())
594  {
595  LOG(VB_GENERAL, LOG_ERR, LOC + "PosMap is empty, can't seek");
596  return false;
597  }
598 
599  if (!m_ringBuffer)
600  {
601  LOG(VB_GENERAL, LOG_ERR, LOC + "No ringBuffer yet, can't seek");
602  return false;
603  }
604 
605  // Find keyframe <= desiredFrame, store in lastKey (frames)
606  int pre_idx = 0;
607  int post_idx = 0;
608  FindPosition(desiredFrame, m_hasKeyFrameAdjustTable, pre_idx, post_idx);
609 
610  PosMapEntry e {};
611  {
612  QMutexLocker locker(&m_positionMapLock);
613  PosMapEntry e_pre = m_positionMap[pre_idx];
614  PosMapEntry e_post = m_positionMap[post_idx];
615  int pos_idx = pre_idx;
616  e = e_pre;
617  if (((uint64_t) (GetKey(e_post) - desiredFrame)) <= m_seekSnap &&
618  m_framesPlayed - 1 > GetKey(e_post) &&
619  GetKey(e_post) - desiredFrame <= desiredFrame - GetKey(e_pre))
620  {
621  // Snap to the right if e_post is within snap distance and
622  // is at least as close a snap as e_pre. Take into
623  // account that if framesPlayed has already reached
624  // e_post, we should only snap to the left.
625  pos_idx = post_idx;
626  e = e_post;
627  }
628  m_lastKey = GetKey(e);
629 
630  // ??? Don't rewind past the beginning of the file
631  while (e.pos < 0)
632  {
633  pos_idx++;
634  if (pos_idx >= (int)m_positionMap.size())
635  return false;
636 
637  e = m_positionMap[pos_idx];
638  m_lastKey = GetKey(e);
639  }
640  }
641 
642  m_ringBuffer->Seek(e.pos, SEEK_SET);
643 
644  return true;
645 }
646 
648 {
649  QMutexLocker locker(&m_positionMapLock);
650  m_posmapStarted = false;
651  m_positionMap.clear();
652  m_frameToDurMap.clear();
653  m_durToFrameMap.clear();
654 }
655 
657 {
658  long long last_frame = 0;
659 
660  QMutexLocker locker(&m_positionMapLock);
661  if (!m_positionMap.empty())
662  last_frame = GetKey(m_positionMap.back());
663 
664  return last_frame;
665 }
666 
667 long long DecoderBase::ConditionallyUpdatePosMap(long long desiredFrame)
668 {
669  long long last_frame = GetLastFrameInPosMap();
670 
671  if (desiredFrame < 0)
672  return last_frame;
673 
674  // Resync keyframe map if we are trying to seek to a frame
675  // not yet equalled or exceeded in the seek map.
676  if (desiredFrame < last_frame)
677  return last_frame;
678 
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));
683 
684  SyncPositionMap();
685 
686  last_frame = GetLastFrameInPosMap();
687 
688  if (desiredFrame > last_frame)
689  {
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));
696  }
697 
698  return last_frame;
699 }
700 
710 bool DecoderBase::DoFastForward(long long desiredFrame, bool discardFrames)
711 {
712  LOG(VB_PLAYBACK, LOG_INFO, LOC +
713  QString("DoFastForward(%1 (%2), %3 discard frames)")
714  .arg(desiredFrame).arg(m_framesPlayed)
715  .arg((discardFrames) ? "do" : "don't"));
716 
717  if (!m_ringBuffer)
718  {
719  LOG(VB_GENERAL, LOG_ERR, LOC + "No ringBuffer yet, can't fast forward");
720  return false;
721  }
722 
723  if (m_ringBuffer->IsDVD() &&
725  m_ringBuffer->DVD()->TitleTimeLeft() < 5s)
726  {
727  return false;
728  }
729  // Rewind if we have already played the desiredFrame. The +1 is for
730  // MPEG4 NUV files, which need to decode an extra frame sometimes.
731  // This shouldn't effect how this works in general because this is
732  // only triggered on the first keyframe/frame skip when paused. At
733  // that point the decoding is more than one frame ahead of display.
734  if (desiredFrame+1 < m_framesPlayed)
735  return DoRewind(desiredFrame, discardFrames);
736  desiredFrame = std::max(desiredFrame, m_framesPlayed);
737 
738  // Save rawframe state, for later restoration...
739  bool oldrawstate = m_getRawFrames;
740  m_getRawFrames = false;
741 
742  ConditionallyUpdatePosMap(desiredFrame);
743 
744  // Fetch last keyframe in position map
745  long long last_frame = GetLastFrameInPosMap();
746 
747  // If the desiredFrame is past the end of the position map,
748  // do some frame-by-frame seeking until we get to it.
749  bool needflush = false;
750  if (desiredFrame > last_frame)
751  {
752  LOG(VB_GENERAL, LOG_NOTICE, LOC +
753  QString("DoFastForward(): desiredFrame(%1) > last_frame(%2)")
754  .arg(desiredFrame).arg(last_frame));
755 
756  if (desiredFrame - last_frame > 32)
757  {
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;
762  }
763 
764  needflush = true;
765 
766  // Handle non-frame-by-frame seeking
767  DoFastForwardSeek(last_frame, needflush);
768 
769  m_exitAfterDecoded = true; // don't actualy get a frame
770  while ((desiredFrame > last_frame) && !m_atEof)
771  {
772  bool retry = false;
773  GetFrame(kDecodeNothing, retry); // don't need to return frame...
774  SyncPositionMap();
775  last_frame = GetLastFrameInPosMap();
776  }
777  m_exitAfterDecoded = false; // allow frames to be returned again
778 
779  if (m_atEof)
780  {
781  // Re-enable rawframe state if it was enabled before FF
782  m_getRawFrames = oldrawstate;
783  return false;
784  }
785  }
786 
787  {
788  QMutexLocker locker(&m_positionMapLock);
789  if (m_positionMap.empty())
790  {
791  // Re-enable rawframe state if it was enabled before FF
792  m_getRawFrames = oldrawstate;
793  return false;
794  }
795  }
796 
797  // Handle non-frame-by-frame seeking
798  DoFastForwardSeek(desiredFrame, needflush);
799 
800  // Do any Extra frame-by-frame seeking for exactseeks mode
801  // And flush pre-seek frame if we are allowed to and need to..
802  int normalframes = (uint64_t)(desiredFrame - (m_framesPlayed - 1)) > m_seekSnap
803  ? desiredFrame - m_framesPlayed : 0;
804  normalframes = std::max(normalframes, 0);
805  SeekReset(m_lastKey, normalframes, needflush, discardFrames);
806 
807  if (discardFrames || m_transcoding)
809 
810  // Re-enable rawframe state if it was enabled before FF
811  m_getRawFrames = oldrawstate;
812 
813  return true;
814 }
815 
830 void DecoderBase::DoFastForwardSeek(long long desiredFrame, bool &needflush)
831 {
832  if (!m_ringBuffer)
833  {
834  LOG(VB_GENERAL, LOG_ERR, LOC +
835  "No ringBuffer yet, can't fast forward seek");
836  return;
837  }
838 
839  int pre_idx = 0;
840  int post_idx = 0;
841  FindPosition(desiredFrame, m_hasKeyFrameAdjustTable, pre_idx, post_idx);
842 
843  // if exactseeks, use keyframe <= desiredFrame
844 
845  PosMapEntry e {};
846  PosMapEntry e_pre {};
847  PosMapEntry e_post {};
848  {
849  QMutexLocker locker(&m_positionMapLock);
850  e_pre = m_positionMap[pre_idx];
851  e_post = m_positionMap[post_idx];
852  }
853  e = e_pre;
854  if (((uint64_t) (GetKey(e_post) - desiredFrame)) <= m_seekSnap &&
855  (m_framesPlayed - 1 >= GetKey(e_pre) ||
856  GetKey(e_post) - desiredFrame < desiredFrame - GetKey(e_pre)))
857  {
858  // Snap to the right if e_post is within snap distance and is
859  // a closer snap than e_pre. Take into account that if
860  // framesPlayed has already reached e_pre, we should only snap
861  // to the right.
862  e = e_post;
863  }
864  m_lastKey = GetKey(e);
865 
867  {
868  m_ringBuffer->Seek(e.pos, SEEK_SET);
869  needflush = true;
871  m_fpsSkip = 0;
873  }
874 }
875 
877 {
879 }
880 
882 {
883  ResetPosMap();
884  m_framesPlayed = 0;
885  m_framesRead = 0;
887 
888  m_waitingForChange = false;
889  m_justAfterChange = true;
890 
892 }
893 
894 void DecoderBase::SetReadAdjust(long long adjust)
895 {
896  m_readAdjust = adjust;
897 }
898 
900 {
901  m_waitingForChange = true;
902 }
903 
905 {
906  return m_waitingForChange;
907 }
908 
910 {
911  QMutexLocker locker(&m_trackLock);
912  return static_cast<uint>(m_tracks[Type].size());
913 }
914 
916 {
917  m_trackLock.lock();
918  m_decodeAllSubtitles = DecodeAll;
919  m_trackLock.unlock();
920 }
921 
922 QStringList DecoderBase::GetTracks(uint Type)
923 {
924  QMutexLocker locker(&m_trackLock);
925  QStringList list;
926  for (size_t i = 0; i < m_tracks[Type].size(); i++)
927  list += GetTrackDesc(Type, static_cast<uint>(i));
928  return list;
929 }
930 
932 {
933  QMutexLocker locker(&m_trackLock);
934  if (TrackNo >= m_tracks[Type].size())
935  return 0;
936  return static_cast<int>(m_tracks[Type][TrackNo].m_language_index);
937 }
938 
939 QString DecoderBase::GetTrackDesc(uint Type, uint TrackNo)
940 {
941  QMutexLocker locker(&m_trackLock);
942  if (TrackNo >= m_tracks[Type].size())
943  return "";
944 
945  QString type_msg = toString(static_cast<TrackType>(Type));
946  int lang = m_tracks[Type][TrackNo].m_language;
947  int hnum = static_cast<int>(TrackNo + 1);
948  if (kTrackTypeCC608 == Type)
949  hnum = m_tracks[Type][TrackNo].m_stream_id;
950 
951  if (!lang)
952  return type_msg + QString(" %1").arg(hnum);
953  QString lang_msg = iso639_key_toName(lang);
954  return type_msg + QString(" %1: %2").arg(hnum).arg(lang_msg);
955 }
956 
958 {
959  QMutexLocker locker(&m_trackLock);
960  return m_currentTrack[Type];
961 }
962 
963 int DecoderBase::SetTrack(uint Type, int TrackNo)
964 {
965  QMutexLocker locker(&m_trackLock);
966  if (TrackNo >= static_cast<int>(m_tracks[Type].size()))
967  return -1;
968 
969  m_currentTrack[Type] = std::max(-1, TrackNo);
970  if (m_currentTrack[Type] < 0)
971  {
972  m_selectedTrack[Type].m_av_stream_index = -1;
973  }
974  else
975  {
976  m_wantedTrack[Type] = m_tracks[Type][static_cast<size_t>(m_currentTrack[Type])];
977  m_selectedTrack[Type] = m_tracks[Type][static_cast<size_t>(m_currentTrack[Type])];
978  if (Type == kTrackTypeSubtitle)
979  {
980  // Rechoose the associated forced track, preferring the same language
981  int forcedTrackIndex = BestTrack(Type, true, m_selectedTrack[Type].m_language);
982  if (m_tracks[Type][forcedTrackIndex].m_forced)
983  m_selectedForcedTrack[Type] = m_tracks[Type][forcedTrackIndex];
984  }
985  }
986 
987  return m_currentTrack[Type];
988 }
989 
991 {
992  QMutexLocker locker(&m_trackLock);
993  if (TrackNo >= m_tracks[Type].size())
994  {
995  StreamInfo si;
996  return si;
997  }
998  return m_tracks[Type][TrackNo];
999 }
1000 
1001 int DecoderBase::ChangeTrack(uint Type, int Dir)
1002 {
1003  QMutexLocker locker(&m_trackLock);
1004 
1005  int next_track = -1;
1006  int size = static_cast<int>(m_tracks[Type].size());
1007  if (size)
1008  {
1009  if (Dir > 0)
1010  next_track = (std::max(-1, m_currentTrack[Type]) + 1) % size;
1011  else
1012  next_track = (std::max(+0, m_currentTrack[Type]) + size - 1) % size;
1013  }
1014  return SetTrack(Type, next_track);
1015 }
1016 
1018 {
1019  QMutexLocker locker(&m_trackLock);
1020 
1021  int next_track = -1;
1022  int size = static_cast<int>(m_tracks[Type].size());
1023  if (size)
1024  next_track = (std::max(0, m_currentTrack[Type]) + 1) % size;
1025  return next_track;
1026 }
1027 
1029 {
1030  QMutexLocker locker(&m_trackLock);
1031 
1032  if (std::any_of(m_tracks[Type].cbegin(), m_tracks[Type].cend(),
1033  [&](const StreamInfo& Si) { return Si.m_stream_id == Info.m_stream_id; } ))
1034  {
1035  return false;
1036  }
1037 
1038  m_tracks[Type].push_back(Info);
1039 
1040  if (m_parent)
1041  emit m_parent->SignalTracksChanged(Type);
1042 
1043  return true;
1044 }
1045 
1064 int DecoderBase::BestTrack(uint Type, bool forcedPreferred, int preferredLanguage)
1065 {
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);
1071  int bestScore = -1;
1072  int selTrack = -1;
1073  uint numStreams = static_cast<uint>(m_tracks[Type].size());
1074 
1075  for (uint i = 0; i < numStreams; i++)
1076  {
1077  bool forced = (Type == kTrackTypeSubtitle &&
1078  m_tracks[Type][i].m_forced);
1079  int position = static_cast<int>(numStreams) - static_cast<int>(i);
1080  int language = 0;
1081  if (preferredLanguage != 0 && m_tracks[Type][i].m_language == preferredLanguage)
1082  {
1083  language = static_cast<int>(m_languagePreference.size()) + 1;
1084  }
1085  for (uint j = 0; (language == 0) && (j < m_languagePreference.size()); ++j)
1086  {
1087  if (m_tracks[Type][i].m_language == m_languagePreference[j])
1088  language = static_cast<int>(m_languagePreference.size()) - static_cast<int>(j);
1089  }
1090  int score = (1 << 20) +
1091  (kForcedWeight * static_cast<int>(forced)) +
1092  (kLanguageWeight * language) +
1093  (kPositionWeight * position);
1094  if (score > bestScore)
1095  {
1096  bestScore = score;
1097  selTrack = static_cast<int>(i);
1098  }
1099  }
1100 
1101  return selTrack;
1102 }
1103 
1120 {
1121  QMutexLocker locker(&m_trackLock);
1122 
1123  uint numStreams = static_cast<uint>(m_tracks[Type].size());
1124 
1125  if ((m_currentTrack[Type] >= 0) && (m_currentTrack[Type] < static_cast<int>(numStreams)))
1126  return m_currentTrack[Type]; // track already selected
1127 
1128  if (!numStreams)
1129  {
1130  m_currentTrack[Type] = -1;
1131  m_selectedTrack[Type].m_av_stream_index = -1;
1132  return -1;
1133  }
1134 
1135  int selTrack = (1 == numStreams) ? 0 : -1;
1136 
1137  if ((selTrack < 0) && m_wantedTrack[Type].m_language>=-1)
1138  {
1139  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Trying to reselect track");
1140  // Try to reselect user selected track stream.
1141  // This should find the stream after a commercial
1142  // break and in some cases after a channel change.
1143  int wlang = m_wantedTrack[Type].m_language;
1144  uint windx = m_wantedTrack[Type].m_language_index;
1145  for (uint i = 0; i < numStreams; i++)
1146  {
1147  if (wlang == m_tracks[Type][i].m_language)
1148  {
1149  selTrack = static_cast<int>(i);
1150  if (windx == m_tracks[Type][i].m_language_index)
1151  break;
1152  }
1153  }
1154  }
1155 
1156  if (selTrack < 0)
1157  {
1158  // Find best track favoring forced.
1159  selTrack = BestTrack(Type, true);
1160 
1161  if (Type == kTrackTypeSubtitle)
1162  {
1163  if (m_tracks[Type][selTrack].m_forced)
1164  {
1165  // A forced AV Subtitle tracks is handled without the user
1166  // explicitly enabling subtitles. Try to find a good non-forced
1167  // track that can be swapped to in the case the user does
1168  // explicitly enable subtitles.
1169  int nonForcedTrack = BestTrack(Type, false);
1170 
1171  if (!m_tracks[Type][nonForcedTrack].m_forced)
1172  {
1173  m_selectedForcedTrack[Type] = m_tracks[Type][selTrack];
1174  selTrack = nonForcedTrack;
1175  }
1176  }
1177  }
1178  }
1179 
1180  int oldTrack = m_currentTrack[Type];
1181  m_currentTrack[Type] = selTrack;
1182  StreamInfo tmp = m_tracks[Type][static_cast<size_t>(m_currentTrack[Type])];
1183  m_selectedTrack[Type] = tmp;
1184 
1185  if (m_wantedTrack[Type].m_av_stream_index < 0)
1186  m_wantedTrack[Type] = tmp;
1187 
1188  int lang = m_tracks[Type][static_cast<size_t>(m_currentTrack[Type])].m_language;
1189  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Selected track #%1 (type %2) in the %3 language(%4)")
1190  .arg(m_currentTrack[Type]+1).arg(Type).arg(iso639_key_toName(lang)).arg(lang));
1191 
1192  if (m_parent && (oldTrack != m_currentTrack[Type]))
1193  emit m_parent->SignalTracksChanged(Type);
1194 
1195  return selTrack;
1196 }
1197 
1199 {
1200  for (uint i = 0; i < kTrackTypeCount; i++)
1201  AutoSelectTrack(i);
1202 }
1203 
1205 {
1206  QMutexLocker locker(&m_trackLock);
1207  std::fill(m_currentTrack.begin(), m_currentTrack.end(), -1);
1208 }
1209 
1211 {
1212  QString str = QObject::tr("Track");
1213 
1214  if (kTrackTypeAudio == type)
1215  str = QObject::tr("Audio track");
1216  else if (kTrackTypeVideo == type)
1217  str = QObject::tr("Video track");
1218  else if (kTrackTypeSubtitle == type)
1219  str = QObject::tr("Subtitle track");
1220  else if (kTrackTypeCC608 == type)
1221  str = QObject::tr("CC", "EIA-608 closed captions");
1222  else if (kTrackTypeCC708 == type)
1223  str = QObject::tr("ATSC CC", "EIA-708 closed captions");
1224  else if (kTrackTypeTeletextCaptions == type)
1225  str = QObject::tr("TT CC", "Teletext closed captions");
1226  else if (kTrackTypeTeletextMenu == type)
1227  str = QObject::tr("TT Menu", "Teletext Menu");
1228  else if (kTrackTypeRawText == type)
1229  str = QObject::tr("Text", "Text stream");
1230  else if (kTrackTypeTextSubtitle == type)
1231  str = QObject::tr("TXT File", "Text File");
1232  return str;
1233 }
1234 
1235 int to_track_type(const QString &str)
1236 {
1237  int ret = -1;
1238 
1239  if (str.startsWith("AUDIO"))
1240  ret = kTrackTypeAudio;
1241  else if (str.startsWith("VIDEO"))
1242  ret = kTrackTypeVideo;
1243  else if (str.startsWith("SUBTITLE"))
1244  ret = kTrackTypeSubtitle;
1245  else if (str.startsWith("CC608"))
1246  ret = kTrackTypeCC608;
1247  else if (str.startsWith("CC708"))
1248  ret = kTrackTypeCC708;
1249  else if (str.startsWith("TTC"))
1251  else if (str.startsWith("TTM"))
1252  ret = kTrackTypeTeletextMenu;
1253  else if (str.startsWith("TFL"))
1254  ret = kTrackTypeTextSubtitle;
1255  else if (str.startsWith("RAWTEXT"))
1256  ret = kTrackTypeRawText;
1257  return ret;
1258 }
1259 
1261 {
1262  QString str;
1263 
1264  switch (type)
1265  {
1267  str = QObject::tr("Audio Description",
1268  "On-screen events described for the visually impaired");
1269  break;
1270  case kAudioTypeCleanEffects :
1271  str = QObject::tr("Clean Effects",
1272  "No dialog, background audio only");
1273  break;
1275  str = QObject::tr("Hearing Impaired",
1276  "Clear dialog for the hearing impaired");
1277  break;
1278  case kAudioTypeSpokenSubs :
1279  str = QObject::tr("Spoken Subtitles",
1280  "Subtitles are read out for the visually impaired");
1281  break;
1282  case kAudioTypeCommentary :
1283  str = QObject::tr("Commentary", "Director/Cast commentary track");
1284  break;
1285  case kAudioTypeNormal :
1286  default:
1287  str = QObject::tr("Normal", "Ordinary audio track");
1288  break;
1289  }
1290 
1291  return str;
1292 }
1293 
1295 {
1296  if (!m_playbackInfo || av_q2d(m_totalDuration) == 0)
1297  return;
1298 
1300 }
1301 
1303 {
1304  if (!m_playbackInfo || !m_framesRead)
1305  return;
1306 
1308 }
1309 
1310 // Linearly interpolate the value for a given key in the map. If the
1311 // key is outside the range of keys in the map, linearly extrapolate
1312 // using the fallback ratio.
1314  long long key,
1315  float fallback_ratio)
1316 {
1317  uint64_t key1 = 0;
1318  uint64_t key2 = 0;
1319  uint64_t val1 = 0;
1320  uint64_t val2 = 0;
1321 
1322  frm_pos_map_t::const_iterator lower = map.lowerBound(key);
1323  // QMap::lowerBound() finds a key >= the given key. We want one
1324  // <= the given key, so back up one element upon > condition.
1325  if (lower != map.begin() && (lower == map.end() || lower.key() > key))
1326  --lower;
1327  if (lower == map.end() || lower.key() > key)
1328  {
1329  key1 = 0;
1330  val1 = 0;
1331  LOG(VB_PLAYBACK, LOG_DEBUG, LOC +
1332  QString("TranslatePosition(key=%1): extrapolating to (0,0)")
1333  .arg(key));
1334  }
1335  else
1336  {
1337  key1 = lower.key();
1338  val1 = lower.value();
1339  }
1340  // Find the next key >= the given key. QMap::lowerBound() is
1341  // precisely correct in this case.
1342  frm_pos_map_t::const_iterator upper = map.lowerBound(key);
1343  if (upper == map.end())
1344  {
1345  // Extrapolate from (key1,val1) based on fallback_ratio
1346  key2 = key;
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));
1352  return val2;
1353  }
1354  key2 = upper.key();
1355  val2 = upper.value();
1356  if (key1 == key2) // this happens for an exact keyframe match
1357  return val2; // can also set key2 = key1 + 1 avoid dividing by zero
1358 
1359  return llround(val1 + (double) (key - key1) * (val2 - val1) / (key2 - key1));
1360 }
1361 
1362 // Convert from an absolute frame number (not cutlist adjusted) to its
1363 // cutlist-adjusted position in milliseconds.
1364 std::chrono::milliseconds DecoderBase::TranslatePositionFrameToMs(long long position,
1365  float fallback_framerate,
1366  const frm_dir_map_t &cutlist)
1367 {
1368  QMutexLocker locker(&m_positionMapLock);
1369  // Accurate calculation of duration requires an up-to-date
1370  // duration map. However, the last frame (total duration) will
1371  // almost always appear to be past the end of the duration map, so
1372  // we limit duration map syncing to once every 3 seconds (a
1373  // somewhat arbitrary value).
1374  if (!m_frameToDurMap.empty())
1375  {
1376  frm_pos_map_t::const_iterator it = m_frameToDurMap.cend();
1377  --it;
1378  if (position > it.key())
1379  {
1380  if (!m_lastPositionMapUpdate.isValid() ||
1381  (QDateTime::currentDateTime() >
1382  m_lastPositionMapUpdate.addSecs(3)))
1383  SyncPositionMap();
1384  }
1385  }
1386  return std::chrono::milliseconds(TranslatePositionAbsToRel(cutlist, position, m_frameToDurMap,
1387  1000 / fallback_framerate));
1388 }
1389 
1390 // Convert from a cutlist-adjusted position in milliseconds to its
1391 // absolute frame number (not cutlist-adjusted).
1392 uint64_t DecoderBase::TranslatePositionMsToFrame(std::chrono::milliseconds dur_ms,
1393  float fallback_framerate,
1394  const frm_dir_map_t &cutlist)
1395 {
1396  QMutexLocker locker(&m_positionMapLock);
1397  // Convert relative position in milliseconds (cutlist-adjusted) to
1398  // its absolute position in milliseconds (not cutlist-adjusted).
1399  uint64_t ms = TranslatePositionRelToAbs(cutlist, dur_ms.count(), m_frameToDurMap,
1400  1000 / fallback_framerate);
1401  // Convert absolute position in milliseconds to its absolute frame
1402  // number.
1403  return TranslatePosition(m_durToFrameMap, ms, fallback_framerate / 1000);
1404 }
1405 
1406 // Convert from an "absolute" (not cutlist-adjusted) value to its
1407 // "relative" (cutlist-adjusted) mapped value. Usually the position
1408 // argument is a frame number, the map argument maps frames to
1409 // milliseconds, the fallback_ratio is 1000/framerate_fps, and the
1410 // return value is in milliseconds.
1411 //
1412 // If the map and fallback_ratio arguments are omitted, it simply
1413 // converts from an absolute frame number to a relative
1414 // (cutlist-adjusted) frame number.
1415 uint64_t
1417  uint64_t absPosition, // frames
1418  const frm_pos_map_t &map, // frame->ms
1419  float fallback_ratio)
1420 {
1421  uint64_t subtraction = 0;
1422  uint64_t startOfCutRegion = 0;
1423  bool withinCut = false;
1424  bool first = true;
1425  for (frm_dir_map_t::const_iterator i = deleteMap.begin();
1426  i != deleteMap.end(); ++i)
1427  {
1428  if (first)
1429  withinCut = (i.value() == MARK_CUT_END);
1430  first = false;
1431  if (i.key() > absPosition)
1432  break;
1433  uint64_t mappedKey = TranslatePosition(map, i.key(), fallback_ratio);
1434  if (i.value() == MARK_CUT_START && !withinCut)
1435  {
1436  withinCut = true;
1437  startOfCutRegion = mappedKey;
1438  }
1439  else if (i.value() == MARK_CUT_END && withinCut)
1440  {
1441  withinCut = false;
1442  subtraction += (mappedKey - startOfCutRegion);
1443  }
1444  }
1445  uint64_t mappedPos = TranslatePosition(map, absPosition, fallback_ratio);
1446  if (withinCut)
1447  subtraction += (mappedPos - startOfCutRegion);
1448  return mappedPos - subtraction;
1449 }
1450 
1451 // Convert from a "relative" (cutlist-adjusted) value to its
1452 // "absolute" (not cutlist-adjusted) mapped value. Usually the
1453 // position argument is in milliseconds, the map argument maps frames
1454 // to milliseconds, the fallback_ratio is 1000/framerate_fps, and the
1455 // return value is also in milliseconds. Upon return, if necessary,
1456 // the result may need a separate, non-cutlist adjusted conversion
1457 // from milliseconds to frame number, using the inverse
1458 // millisecond-to-frame map and the inverse fallback_ratio; see for
1459 // example TranslatePositionMsToFrame().
1460 //
1461 // If the map and fallback_ratio arguments are omitted, it simply
1462 // converts from a relatve (cutlist-adjusted) frame number to an
1463 // absolute frame number.
1464 uint64_t
1466  uint64_t relPosition, // ms
1467  const frm_pos_map_t &map, // frame->ms
1468  float fallback_ratio)
1469 {
1470  uint64_t addition = 0;
1471  uint64_t startOfCutRegion = 0;
1472  bool withinCut = false;
1473  bool first = true;
1474  for (frm_dir_map_t::const_iterator i = deleteMap.begin();
1475  i != deleteMap.end(); ++i)
1476  {
1477  if (first)
1478  withinCut = (i.value() == MARK_CUT_END);
1479  first = false;
1480  uint64_t mappedKey = TranslatePosition(map, i.key(), fallback_ratio);
1481  if (i.value() == MARK_CUT_START && !withinCut)
1482  {
1483  withinCut = true;
1484  startOfCutRegion = mappedKey;
1485  if (relPosition + addition <= startOfCutRegion)
1486  break;
1487  }
1488  else if (i.value() == MARK_CUT_END && withinCut)
1489  {
1490  withinCut = false;
1491  addition += (mappedKey - startOfCutRegion);
1492  }
1493  }
1494  return relPosition + addition;
1495 }
1496 
1501 AVPixelFormat DecoderBase::GetBestVideoFormat(AVPixelFormat* Formats, const VideoFrameTypes* RenderFormats)
1502 {
1503  for (AVPixelFormat *format = Formats; *format != AV_PIX_FMT_NONE; format++)
1504  {
1505  for (auto fmt : *RenderFormats)
1506  if (MythAVUtil::FrameTypeToPixelFormat(fmt) == *format)
1507  return *format;
1508  }
1509  return AV_PIX_FMT_NONE;
1510 }
1511 
1512 /* vim: set expandtab tabstop=4 shiftwidth=4: */
AVRationalInit
AVRational AVRationalInit(int num, int den=1)
Definition: decoderbase.h:113
MythMediaBuffer::BD
const MythBDBuffer * BD(void) const
Definition: mythmediabuffer.cpp:1846
DecoderBase::DoFastForward
virtual bool DoFastForward(long long desiredFrame, bool discardFrames=true)
Skips ahead or rewinds to desiredFrame.
Definition: decoderbase.cpp:710
kAudioTypeHearingImpaired
@ kAudioTypeHearingImpaired
Definition: decoderbase.h:60
MythBDBuffer::GetFrameRate
double GetFrameRate(void)
Definition: mythbdbuffer.cpp:872
secondsFromFloat
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.
Definition: mythchrono.h:80
MythTimer::elapsed
std::chrono::milliseconds elapsed(void)
Returns milliseconds elapsed since last start() or restart()
Definition: mythtimer.cpp:91
MARK_KEYFRAME
@ MARK_KEYFRAME
Definition: programtypes.h:62
DecoderBase::SetTrack
virtual int SetTrack(uint Type, int TrackNo)
Definition: decoderbase.cpp:963
DecoderBase::m_readAdjust
long long m_readAdjust
Definition: decoderbase.h:345
DecoderBase::GetTrack
int GetTrack(uint Type)
Definition: decoderbase.cpp:957
DecoderBase::NextTrack
int NextTrack(uint Type)
Definition: decoderbase.cpp:1017
MythDVDBuffer::TitleTimeLeft
std::chrono::seconds TitleTimeLeft(void) const
returns seconds left in the title
Definition: mythdvdbuffer.cpp:1982
DecoderBase::PosMapEntry::adjFrame
long long adjFrame
Definition: decoderbase.h:282
MythPlayer::SetFileLength
void SetFileLength(std::chrono::seconds total, int frames)
Definition: mythplayer.cpp:387
DecoderBase::m_seekSnap
uint64_t m_seekSnap
Definition: decoderbase.h:331
AudioTrackType
AudioTrackType
Definition: decoderbase.h:55
kTrackTypeTextSubtitle
@ kTrackTypeTextSubtitle
Definition: decoderbase.h:42
DecoderBase::m_selectedTrack
std::array< StreamInfo, kTrackTypeCount > m_selectedTrack
Definition: decoderbase.h:355
DecoderBase::m_ringBuffer
MythMediaBuffer * m_ringBuffer
Definition: decoderbase.h:290
DecoderBase::m_renderFormats
const VideoFrameTypes * m_renderFormats
Definition: decoderbase.h:362
DecoderBase::PosMapEntry
Definition: decoderbase.h:279
ProgramInfo::QueryPositionMap
void QueryPositionMap(frm_pos_map_t &posMap, MarkTypes type) const
Definition: programinfo.cpp:3762
kEofStateNone
@ kEofStateNone
Definition: decoderbase.h:69
kTrackTypeCount
@ kTrackTypeCount
Definition: decoderbase.h:38
DecoderBase::m_fps
double m_fps
Definition: decoderbase.h:292
MythTimer
A QElapsedTimer based timer to replace use of QTime as a timer.
Definition: mythtimer.h:13
DecoderBase::m_indexOffset
long long m_indexOffset
Definition: decoderbase.h:306
DecoderBase::m_lastPositionMapUpdate
QDateTime m_lastPositionMapUpdate
Definition: decoderbase.h:329
to_track_type
int to_track_type(const QString &str)
Definition: decoderbase.cpp:1235
MythBDBuffer::GetTotalReadPosition
uint64_t GetTotalReadPosition(void)
Definition: mythbdbuffer.cpp:802
MythMediaBuffer::Seek
long long Seek(long long Position, int Whence, bool HasLock=false)
Definition: mythmediabuffer.cpp:473
ProgramInfo::SavePositionMapDelta
void SavePositionMapDelta(frm_pos_map_t &posMap, MarkTypes type) const
Definition: programinfo.cpp:3990
DecoderBase::m_hasKeyFrameAdjustTable
bool m_hasKeyFrameAdjustTable
Definition: decoderbase.h:336
ProgramInfo::SaveTotalFrames
void SaveTotalFrames(int64_t frames)
Store the Total Frames at frame 0 in the recordedmarkup table.
Definition: programinfo.cpp:4400
DecoderBase::ConditionallyUpdatePosMap
long long ConditionallyUpdatePosMap(long long desiredFrame)
Definition: decoderbase.cpp:667
DecoderBase::AutoSelectTrack
virtual int AutoSelectTrack(uint Type)
Select best track.
Definition: decoderbase.cpp:1119
DecoderBase::m_atEof
EofState m_atEof
Definition: decoderbase.h:310
DecoderBase::m_parent
MythPlayer * m_parent
Definition: decoderbase.h:287
DecoderBase::SavePositionMapDelta
uint64_t SavePositionMapDelta(long long first_frame, long long last_frame)
Definition: decoderbase.cpp:500
MARK_CUT_END
@ MARK_CUT_END
Definition: programtypes.h:55
StreamInfo::m_stream_id
int m_stream_id
Definition: decoderbase.h:99
kTrackTypeTeletextMenu
@ kTrackTypeTeletextMenu
Definition: decoderbase.h:35
DecoderBase::DecoderBase
DecoderBase(MythPlayer *parent, const ProgramInfo &pginfo)
Definition: decoderbase.cpp:17
mythdvdbuffer.h
DecoderBase::m_livetv
bool m_livetv
Definition: decoderbase.h:333
frm_dir_map_t
QMap< uint64_t, MarkTypes > frm_dir_map_t
Frame # -> Mark map.
Definition: programtypes.h:118
DecoderBase::ResetTracks
void ResetTracks(void)
Definition: decoderbase.cpp:1204
MythMediaBuffer::IsDVD
bool IsDVD(void) const
Definition: mythmediabuffer.cpp:1831
MythTimer::start
void start(void)
starts measuring elapsed time.
Definition: mythtimer.cpp:47
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
DecoderBase::ChangeTrack
int ChangeTrack(uint Type, int Dir)
Definition: decoderbase.cpp:1001
TrackType
TrackType
Track types.
Definition: decoderbase.h:26
DecoderBase::m_trackLock
QRecursiveMutex m_trackLock
Definition: decoderbase.h:350
kAudioTypeCleanEffects
@ kAudioTypeCleanEffects
Definition: decoderbase.h:59
mythplayer.h
DecoderBase::m_positionMapType
MarkTypes m_positionMapType
Definition: decoderbase.h:323
MythPlayer
Definition: mythplayer.h:83
MythMediaBuffer::IsBD
bool IsBD(void) const
Definition: mythmediabuffer.cpp:1836
DecoderBase::m_posmapStarted
bool m_posmapStarted
Definition: decoderbase.h:322
MythDVDBuffer::GetFrameRate
double GetFrameRate(void)
used by DecoderBase for the total frame number calculation for position map support and ffw/rew.
Definition: mythdvdbuffer.cpp:1944
DecoderBase::m_exitAfterDecoded
bool m_exitAfterDecoded
Definition: decoderbase.h:317
iso639_key_toName
QString iso639_key_toName(int iso639_2)
Converts a canonical key to language name in English.
Definition: iso639.cpp:109
iso639_get_language_key_list
std::vector< int > iso639_get_language_key_list(void)
Definition: iso639.cpp:56
DecoderBase::m_frameToDurMap
frm_pos_map_t m_frameToDurMap
Definition: decoderbase.h:327
DecoderBase::GetWaitForChange
bool GetWaitForChange(void) const
Definition: decoderbase.cpp:904
DecoderBase::SetWaitForChange
void SetWaitForChange(void)
Definition: decoderbase.cpp:899
DecoderBase::m_currentTrack
std::array< int, kTrackTypeCount > m_currentTrack
Definition: decoderbase.h:352
MythDVDBuffer::GetTotalTimeOfTitle
std::chrono::seconds GetTotalTimeOfTitle(void) const
get the total time of the title in seconds 90000 ticks = 1 sec
Definition: mythdvdbuffer.cpp:1148
tmp
static guint32 * tmp
Definition: goom_core.cpp:26
DecoderBase::m_dontSyncPositionMap
bool m_dontSyncPositionMap
Definition: decoderbase.h:332
DecoderBase::TranslatePositionMsToFrame
uint64_t TranslatePositionMsToFrame(std::chrono::milliseconds dur_ms, float fallback_framerate, const frm_dir_map_t &cutlist)
Definition: decoderbase.cpp:1392
DecoderBase::m_tracks
std::array< sinfo_vec_t, kTrackTypeCount > m_tracks
Definition: decoderbase.h:353
kAudioTypeAudioDescription
@ kAudioTypeAudioDescription
Definition: decoderbase.h:58
kAudioTypeNormal
@ kAudioTypeNormal
Definition: decoderbase.h:57
toString
QString toString(TrackType type)
Definition: decoderbase.cpp:1210
DecoderBase::GetTrackDesc
virtual QString GetTrackDesc(uint Type, uint TrackNo)
Definition: decoderbase.cpp:939
DecoderBase::SaveTotalDuration
void SaveTotalDuration(void)
Definition: decoderbase.cpp:1294
DecoderBase::GetTrackCount
virtual uint GetTrackCount(uint Type)
Definition: decoderbase.cpp:909
DecoderBase::FindPosition
virtual bool FindPosition(long long desired_value, bool search_adjusted, int &lower_bound, int &upper_bound)
Definition: decoderbase.cpp:420
DecoderBase::TranslatePositionAbsToRel
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)
Definition: decoderbase.cpp:1416
programinfo.h
DecoderBase::m_keyframeDist
int m_keyframeDist
Definition: decoderbase.h:304
DecoderBase::m_getRawFrames
bool m_getRawFrames
Definition: decoderbase.h:338
mythlogging.h
DecoderBase::GetTrackInfo
StreamInfo GetTrackInfo(uint Type, uint TrackNo)
Definition: decoderbase.cpp:990
StreamInfo
Definition: decoderbase.h:74
DecoderBase::m_languagePreference
std::vector< int > m_languagePreference
language preferences for auto-selection of streams
Definition: decoderbase.h:359
DecoderBase::DoRewindSeek
virtual bool DoRewindSeek(long long desiredFrame)
Definition: decoderbase.cpp:589
MythMediaBuffer::IsInDiscMenuOrStillFrame
virtual bool IsInDiscMenuOrStillFrame(void) const
Definition: mythmediabuffer.h:133
MARK_DURATION_MS
@ MARK_DURATION_MS
Definition: programtypes.h:74
MARK_GOP_START
@ MARK_GOP_START
Definition: programtypes.h:61
DecoderBase::~DecoderBase
virtual ~DecoderBase()
Definition: decoderbase.cpp:31
VideoFrameTypes
std::vector< VideoFrameType > VideoFrameTypes
Definition: mythframe.h:83
DecoderBase::TranslatePositionRelToAbs
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)
Definition: decoderbase.cpp:1465
DecoderBase::m_positionMap
std::vector< PosMapEntry > m_positionMap
Definition: decoderbase.h:326
LOC
#define LOC
Definition: decoderbase.cpp:15
kTrackTypeTeletextCaptions
@ kTrackTypeTeletextCaptions
Definition: decoderbase.h:34
ProgramInfo::SaveTotalDuration
void SaveTotalDuration(std::chrono::milliseconds duration)
Store the Total Duration at frame 0 in the recordedmarkup table.
Definition: programinfo.cpp:4384
DecoderBase::TranslatePositionFrameToMs
std::chrono::milliseconds TranslatePositionFrameToMs(long long position, float fallback_framerate, const frm_dir_map_t &cutlist)
Definition: decoderbase.cpp:1364
hardwareprofile.smolt.long
long
Definition: smolt.py:75
DecoderBase::m_durToFrameMap
frm_pos_map_t m_durToFrameMap
Definition: decoderbase.h:328
DecoderBase::ResetPosMap
virtual void ResetPosMap(void)
Definition: decoderbase.cpp:647
DecoderBase::SetReadAdjust
void SetReadAdjust(long long adjust)
Definition: decoderbase.cpp:894
DecoderBase::m_playbackInfo
ProgramInfo * m_playbackInfo
Definition: decoderbase.h:288
DecoderBase::m_totalDuration
AVRational m_totalDuration
Definition: decoderbase.h:303
MythPlayer::PosMapFromEnc
bool PosMapFromEnc(uint64_t start, frm_pos_map_t &posMap, frm_pos_map_t &durMap)
Definition: mythplayer.cpp:1906
DecoderBase::PosMapEntry::index
long long index
Definition: decoderbase.h:281
kTrackTypeAudio
@ kTrackTypeAudio
Definition: decoderbase.h:29
kTrackTypeCC708
@ kTrackTypeCC708
Definition: decoderbase.h:33
DecoderBase::GetPositionMapSize
unsigned long GetPositionMapSize(void) const
Definition: decoderbase.cpp:294
uint
unsigned int uint
Definition: compat.h:81
DecoderBase::AutoSelectTracks
void AutoSelectTracks(void)
Definition: decoderbase.cpp:1198
DecoderBase::FileChanged
void FileChanged(void)
Definition: decoderbase.cpp:881
DecoderBase::m_wantedTrack
std::array< StreamInfo, kTrackTypeCount > m_wantedTrack
Definition: decoderbase.h:354
DecoderBase::m_transcoding
bool m_transcoding
Definition: decoderbase.h:318
DecoderBase::m_waitingForChange
bool m_waitingForChange
Definition: decoderbase.h:343
kTrackTypeSubtitle
@ kTrackTypeSubtitle
Definition: decoderbase.h:31
DecoderBase::m_justAfterChange
bool m_justAfterChange
Definition: decoderbase.h:344
DecoderBase::SyncPositionMap
virtual bool SyncPositionMap(void)
Updates the position map used for skipping frames.
Definition: decoderbase.cpp:322
frm_pos_map_t
QMap< long long, long long > frm_pos_map_t
Frame # -> File offset map.
Definition: programtypes.h:45
kDecodeNothing
@ kDecodeNothing
Definition: decoderbase.h:49
DecoderBase::SetProgramInfo
void SetProgramInfo(const ProgramInfo &pginfo)
Definition: decoderbase.cpp:42
DecoderBase::GetKey
long long GetKey(const PosMapEntry &entry) const
Definition: decoderbase.cpp:582
DecoderBase::PosMapFromEnc
virtual bool PosMapFromEnc(void)
Queries encoder for position map data that has not been committed to the DB yet.
Definition: decoderbase.cpp:223
DecoderBase::SetWatchingRecording
virtual void SetWatchingRecording(bool mode)
Definition: decoderbase.cpp:82
DecoderBase::m_selectedForcedTrack
std::array< StreamInfo, kTrackTypeCount > m_selectedForcedTrack
Definition: decoderbase.h:356
DecoderBase::GetFrame
virtual bool GetFrame(DecodeType Type, bool &Retry)=0
Demux, preprocess and possibly decode a frame of video/audio.
DecoderBase::DoFastForwardSeek
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...
Definition: decoderbase.cpp:830
MARK_CUT_START
@ MARK_CUT_START
Definition: programtypes.h:56
mythbdbuffer.h
kTrackTypeCC608
@ kTrackTypeCC608
Definition: decoderbase.h:32
MythPlayer::SetKeyframeDistance
void SetKeyframeDistance(int keyframedistance)
Definition: mythplayer.cpp:319
DecoderBase::UpdateFramesPlayed
virtual void UpdateFramesPlayed(void)
Definition: decoderbase.cpp:876
ProgramInfo
Holds information on recordings and videos.
Definition: programinfo.h:67
DecoderBase::SetDecodeAllSubtitles
void SetDecodeAllSubtitles(bool DecodeAll)
Definition: decoderbase.cpp:915
DecoderBase::m_framesPlayed
long long m_framesPlayed
Definition: decoderbase.h:300
MythPlayer::SetFramesPlayed
void SetFramesPlayed(uint64_t played)
Definition: mythplayer.cpp:562
MythPlayer::FileChangedCallback
void FileChangedCallback()
Definition: mythplayer.cpp:938
DecoderBase::m_positionMapLock
QRecursiveMutex m_positionMapLock
Definition: decoderbase.h:325
MARK_GOP_BYFRAME
@ MARK_GOP_BYFRAME
Definition: programtypes.h:64
DecoderBase::SetRenderFormats
void SetRenderFormats(const VideoFrameTypes *RenderFormats)
Definition: decoderbase.cpp:36
DecoderBase::m_decodeAllSubtitles
bool m_decodeAllSubtitles
Definition: decoderbase.h:351
MarkTypes
MarkTypes
Definition: programtypes.h:47
DecoderBase::m_watchingRecording
bool m_watchingRecording
Definition: decoderbase.h:334
MythAVUtil::FrameTypeToPixelFormat
static AVPixelFormat FrameTypeToPixelFormat(VideoFrameType Type)
Definition: mythavutil.cpp:27
DecoderBase::BestTrack
int BestTrack(uint Type, bool forcedPreferred, int preferredLanguage=0)
Determine the best track according to weights.
Definition: decoderbase.cpp:1064
MythMediaBuffer::IsDisc
bool IsDisc(void) const
Definition: mythmediabuffer.cpp:1826
DecoderBase::TranslatePosition
static uint64_t TranslatePosition(const frm_pos_map_t &map, long long key, float fallback_ratio)
Definition: decoderbase.cpp:1313
decoderbase.h
DecoderBase::PosMapFromDb
virtual bool PosMapFromDb(void)
Definition: decoderbase.cpp:95
kTrackTypeRawText
@ kTrackTypeRawText
Definition: decoderbase.h:36
DecoderBase::GetBestVideoFormat
static AVPixelFormat GetBestVideoFormat(AVPixelFormat *Formats, const VideoFrameTypes *RenderFormats)
Find a suitable frame format that is mutually acceptable to the decoder and render device.
Definition: decoderbase.cpp:1501
iso639.h
ISO 639-1 and ISO 639-2 support functions.
MARK_UNSET
@ MARK_UNSET
Definition: programtypes.h:50
mythcodeccontext.h
DecoderBase::m_lastKey
long long m_lastKey
Definition: decoderbase.h:305
MythDVDBuffer::GetTotalReadPosition
long long GetTotalReadPosition(void) const
Definition: mythdvdbuffer.cpp:455
MythMediaBuffer::DVD
const MythDVDBuffer * DVD(void) const
Definition: mythmediabuffer.cpp:1841
kTrackTypeVideo
@ kTrackTypeVideo
Definition: decoderbase.h:30
MythPlayer::SignalTracksChanged
void SignalTracksChanged(uint Type)
DecoderBase::m_framesRead
long long m_framesRead
Definition: decoderbase.h:301
DecoderBase::Reset
virtual void Reset(bool reset_video_data, bool seek_reset, bool reset_file)
Definition: decoderbase.cpp:48
DecoderBase::GetTracks
virtual QStringList GetTracks(uint Type)
Definition: decoderbase.cpp:922
DecoderBase::m_fpsSkip
int m_fpsSkip
Definition: decoderbase.h:294
kAudioTypeSpokenSubs
@ kAudioTypeSpokenSubs
Definition: decoderbase.h:61
DecoderBase::GetLastFrameInPosMap
long long GetLastFrameInPosMap(void) const
Definition: decoderbase.cpp:656
DecoderBase::SetEofState
virtual void SetEofState(EofState eof)
Definition: decoderbase.h:131
DecoderBase::InsertTrack
virtual bool InsertTrack(uint Type, const StreamInfo &Info)
Definition: decoderbase.cpp:1028
MythBDBuffer::GetTotalTimeOfTitle
std::chrono::seconds GetTotalTimeOfTitle(void) const
Definition: mythbdbuffer.cpp:628
DecoderBase::SeekReset
virtual void SeekReset(long long newkey, uint skipFrames, bool doFlush, bool discardFrames)
Definition: decoderbase.cpp:75
DecoderBase::DoRewind
virtual bool DoRewind(long long desiredFrame, bool discardFrames=true)
Definition: decoderbase.cpp:555
DecoderBase::m_recordingHasPositionMap
bool m_recordingHasPositionMap
Definition: decoderbase.h:321
DecoderBase::GetTrackLanguageIndex
virtual int GetTrackLanguageIndex(uint Type, uint TrackNo)
Definition: decoderbase.cpp:931
millisecondsFromFloat
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.
Definition: mythchrono.h:91
DecoderBase::SaveTotalFrames
void SaveTotalFrames(void)
Definition: decoderbase.cpp:1302
kAudioTypeCommentary
@ kAudioTypeCommentary
Definition: decoderbase.h:62
DecoderBase::m_frameCounter
uint64_t m_frameCounter
Definition: decoderbase.h:302