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