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  // this will be deleted and recreated once decoder is set up
26  m_mythcodecctx(new MythCodecContext(this, kCodec_NONE))
27 {
28  ResetTracks();
29  m_tracks[kTrackTypeAudio].push_back(StreamInfo(0, 0, 0, 0, 0));
30  m_tracks[kTrackTypeCC608].push_back(StreamInfo(0, 0, 0, 1, 0));
31  m_tracks[kTrackTypeCC608].push_back(StreamInfo(0, 0, 2, 3, 0));
32 }
33 
35 {
36  delete m_playbackinfo;
37 }
38 
40 {
41  delete m_playbackinfo;
42  m_playbackinfo = new ProgramInfo(pginfo);
43 }
44 
45 void DecoderBase::Reset(bool reset_video_data, bool seek_reset, bool reset_file)
46 {
47  LOG(VB_PLAYBACK, LOG_INFO, LOC +
48  QString("Reset: Video %1, Seek %2, File %3")
49  .arg(reset_video_data).arg(seek_reset).arg(reset_file));
50 
51  if (seek_reset)
52  SeekReset(0, 0, true, true);
53 
54  if (reset_video_data)
55  {
56  ResetPosMap();
57  m_framesPlayed = 0;
58  m_frameCounter += 100;
59  m_fpsSkip = 0;
60  m_framesRead = 0;
62  m_dontSyncPositionMap = false;
63  }
64 
65  if (reset_file)
66  {
67  m_waitingForChange = false;
69  }
70 }
71 
72 void DecoderBase::SeekReset(long long /*newkey*/, uint /*skipFrames*/,
73  bool /*doFlush*/, bool /*discardFrames*/)
74 {
75  m_readAdjust = 0;
76  m_frameCounter += 100; // NB don't just set to 0
77 }
78 
80 {
81  bool wereWatchingRecording = m_watchingrecording;
82 
83  // When we switch from WatchingRecording to WatchingPreRecorded,
84  // re-get the positionmap
85  m_posmapStarted = false;
86  m_watchingrecording = mode;
87 
88  if (wereWatchingRecording && !m_watchingrecording)
90 }
91 
93 {
94  if (!m_playbackinfo)
95  return false;
96 
97  // Overwrites current positionmap with entire contents of database
98  frm_pos_map_t posMap, durMap;
99 
100  if (ringBuffer && ringBuffer->IsDVD())
101  {
102  long long totframes;
103  m_keyframedist = 15;
105  if (m_fps < 26 && m_fps > 24)
106  m_keyframedist = 12;
107  totframes = (long long)(ringBuffer->DVD()->GetTotalTimeOfTitle() * m_fps);
108  posMap[totframes] = ringBuffer->DVD()->GetTotalReadPosition();
109  }
110  else if (ringBuffer && ringBuffer->IsBD())
111  {
112  long long totframes;
113  m_keyframedist = 15;
115  if (m_fps < 26 && m_fps > 24)
116  m_keyframedist = 12;
117  totframes = (long long)(ringBuffer->BD()->GetTotalTimeOfTitle() * m_fps);
118  posMap[totframes] = ringBuffer->BD()->GetTotalReadPosition();
119 #if 0
120  LOG(VB_PLAYBACK, LOG_DEBUG, LOC +
121  QString("%1 TotalTimeOfTitle() in ticks, %2 TotalReadPosition() "
122  "in bytes, %3 is fps")
123  .arg(ringBuffer->BD()->GetTotalTimeOfTitle())
124  .arg(ringBuffer->BD()->GetTotalReadPosition()).arg(m_fps));
125 #endif
126  }
127  else if ((m_positionMapType == MARK_UNSET) ||
128  (m_keyframedist == -1))
129  {
131  if (!posMap.empty())
132  {
134  if (m_keyframedist == -1)
135  m_keyframedist = 1;
136  }
137  else
138  {
140  if (!posMap.empty())
141  {
143  if (m_keyframedist == -1)
144  {
145  m_keyframedist = 15;
146  if (m_fps < 26 && m_fps > 24)
147  m_keyframedist = 12;
148  }
149  }
150  else
151  {
153  if (!posMap.empty())
154  {
155  // keyframedist should be set in the fileheader so no
156  // need to try to determine it in this case
158  }
159  }
160  }
161  }
162  else
163  {
165  }
166 
167  if (posMap.empty())
168  return false; // no position map in recording
169 
171 
172  QMutexLocker locker(&m_positionMapLock);
173  m_positionMap.clear();
174  m_positionMap.reserve(posMap.size());
175  m_frameToDurMap.clear();
176  m_durToFrameMap.clear();
177 
178  for (frm_pos_map_t::const_iterator it = posMap.begin();
179  it != posMap.end(); ++it)
180  {
181  PosMapEntry e = {it.key(), it.key() * m_keyframedist, *it};
182  m_positionMap.push_back(e);
183  }
184 
185  if (!m_positionMap.empty() && !(ringBuffer && ringBuffer->IsDisc()))
186  m_indexOffset = m_positionMap[0].index;
187 
188  if (!m_positionMap.empty())
189  {
190  LOG(VB_PLAYBACK, LOG_INFO, LOC +
191  QString("Position map filled from DB to: %1")
192  .arg(m_positionMap.back().index));
193  }
194 
195  uint64_t last = 0;
196  for (frm_pos_map_t::const_iterator it = durMap.begin();
197  it != durMap.end(); ++it)
198  {
199  m_frameToDurMap[it.key()] = it.value();
200  m_durToFrameMap[it.value()] = it.key();
201  last = it.key();
202  }
203 
204  if (!m_durToFrameMap.empty())
205  {
206  LOG(VB_PLAYBACK, LOG_INFO, LOC +
207  QString("Duration map filled from DB to: %1").arg(last));
208  }
209 
210  return true;
211 }
212 
222 {
223  if (!m_parent || m_keyframedist < 1)
224  return false;
225 
226  unsigned long long start = 0;
227  {
228  QMutexLocker locker(&m_positionMapLock);
229  if (!m_positionMap.empty())
230  start = m_positionMap.back().index + 1;
231  }
232 
233  frm_pos_map_t posMap, 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() && !(ringBuffer && 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 (ringBuffer && ringBuffer->IsDVD())
380  {
381  length = ringBuffer->DVD()->GetTotalTimeOfTitle();
382  QMutexLocker locker(&m_positionMapLock);
383  totframes = m_positionMap.back().index;
384  }
385  else if (ringBuffer && ringBuffer->IsBD())
386  {
387  length = 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;
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, ctm, stm;
501  ttm.start();
502 
503  QMutexLocker locker(&m_positionMapLock);
505  uint64_t saved = 0;
506 
508  return saved;
509 
510  ctm.start();
511  frm_pos_map_t posMap;
512  for (size_t i = 0; i < m_positionMap.size(); i++)
513  {
514  if (m_positionMap[i].index < first)
515  continue;
516  if (m_positionMap[i].index > last)
517  break;
518 
519  posMap[m_positionMap[i].index] = m_positionMap[i].pos;
520  saved++;
521  }
522 
523  frm_pos_map_t durMap;
524  for (frm_pos_map_t::const_iterator it = m_frameToDurMap.begin();
525  it != m_frameToDurMap.end(); ++it)
526  {
527  if (it.key() < first)
528  continue;
529  if (it.key() > last)
530  break;
531  durMap[it.key()] = it.value();
532  }
533 
534  locker.unlock();
535 
536  stm.start();
539 
540 #if 0
541  LOG(VB_GENERAL, LOG_DEBUG, LOC +
542  QString("Saving position map [%1,%2] w/%3 keyframes, "
543  "took (%4,%5,%6) ms")
544  .arg(first).arg(last).arg(saved)
545  .arg(ttm.elapsed())
546  .arg(ctm.elapsed()-stm.elapsed()).arg(stm.elapsed()));
547 #endif
548 
549  return saved;
550 }
551 
552 bool DecoderBase::DoRewind(long long desiredFrame, bool discardFrames)
553 {
554  LOG(VB_PLAYBACK, LOG_INFO, LOC +
555  QString("DoRewind(%1 (%2), %3 discard frames)")
556  .arg(desiredFrame).arg(m_framesPlayed)
557  .arg((discardFrames) ? "do" : "don't"));
558 
559  if (!DoRewindSeek(desiredFrame))
560  return false;
561 
563  m_fpsSkip = 0;
565 
566  // Do any Extra frame-by-frame seeking for exactseeks mode
567  // And flush pre-seek frame if we are allowed to and need to..
568  int normalframes = (uint64_t)(desiredFrame - (m_framesPlayed - 1)) > m_seeksnap
569  ? desiredFrame - m_framesPlayed : 0;
570  normalframes = max(normalframes, 0);
571  SeekReset(m_lastKey, normalframes, true, discardFrames);
572 
573  if (discardFrames || (ringBuffer && ringBuffer->IsDisc()))
575 
576  return true;
577 }
578 
579 long long DecoderBase::GetKey(const PosMapEntry &e) const
580 {
581  long long kf = (ringBuffer && ringBuffer->IsDisc()) ?
582  1LL : m_keyframedist;
583  return (m_hasKeyFrameAdjustTable) ? e.adjFrame :(e.index - m_indexOffset) * kf;
584 }
585 
586 bool DecoderBase::DoRewindSeek(long long desiredFrame)
587 {
588  ConditionallyUpdatePosMap(desiredFrame);
589 
590  if (!GetPositionMapSize())
591  {
592  LOG(VB_GENERAL, LOG_ERR, LOC + "PosMap is empty, can't seek");
593  return false;
594  }
595 
596  if (!ringBuffer)
597  {
598  LOG(VB_GENERAL, LOG_ERR, LOC + "No ringBuffer yet, can't seek");
599  return false;
600  }
601 
602  // Find keyframe <= desiredFrame, store in lastKey (frames)
603  int pre_idx, post_idx;
604  FindPosition(desiredFrame, m_hasKeyFrameAdjustTable, pre_idx, post_idx);
605 
606  PosMapEntry e;
607  {
608  QMutexLocker locker(&m_positionMapLock);
609  PosMapEntry e_pre = m_positionMap[pre_idx];
610  PosMapEntry e_post = m_positionMap[post_idx];
611  int pos_idx = pre_idx;
612  e = e_pre;
613  if (((uint64_t) (GetKey(e_post) - desiredFrame)) <= m_seeksnap &&
614  m_framesPlayed - 1 > GetKey(e_post) &&
615  GetKey(e_post) - desiredFrame <= desiredFrame - GetKey(e_pre))
616  {
617  // Snap to the right if e_post is within snap distance and
618  // is at least as close a snap as e_pre. Take into
619  // account that if framesPlayed has already reached
620  // e_post, we should only snap to the left.
621  pos_idx = post_idx;
622  e = e_post;
623  }
624  m_lastKey = GetKey(e);
625 
626  // ??? Don't rewind past the beginning of the file
627  while (e.pos < 0)
628  {
629  pos_idx++;
630  if (pos_idx >= (int)m_positionMap.size())
631  return false;
632 
633  e = m_positionMap[pos_idx];
634  m_lastKey = GetKey(e);
635  }
636  }
637 
638  ringBuffer->Seek(e.pos, SEEK_SET);
639 
640  return true;
641 }
642 
644 {
645  QMutexLocker locker(&m_positionMapLock);
646  m_posmapStarted = false;
647  m_positionMap.clear();
648  m_frameToDurMap.clear();
649  m_durToFrameMap.clear();
650 }
651 
653 {
654  long long last_frame = 0;
655 
656  QMutexLocker locker(&m_positionMapLock);
657  if (!m_positionMap.empty())
658  last_frame = GetKey(m_positionMap.back());
659 
660  return last_frame;
661 }
662 
663 long long DecoderBase::ConditionallyUpdatePosMap(long long desiredFrame)
664 {
665  long long last_frame = GetLastFrameInPosMap();
666 
667  if (desiredFrame < 0)
668  return last_frame;
669 
670  // Resync keyframe map if we are trying to seek to a frame
671  // not yet equalled or exceeded in the seek map.
672  if (desiredFrame < last_frame)
673  return last_frame;
674 
675  LOG(VB_PLAYBACK, LOG_INFO, LOC +
676  "ConditionallyUpdatePosMap: Not enough info in positionMap," +
677  QString("\n\t\t\twe need frame %1 but highest we have is %2.")
678  .arg(desiredFrame).arg(last_frame));
679 
680  SyncPositionMap();
681 
682  last_frame = GetLastFrameInPosMap();
683 
684  if (desiredFrame > last_frame)
685  {
686  LOG(VB_PLAYBACK, LOG_INFO, LOC +
687  "ConditionallyUpdatePosMap: Still not "
688  "enough info in positionMap after sync, " +
689  QString("\n\t\t\twe need frame %1 but highest we have "
690  "is %2. Will attempt to seek frame-by-frame")
691  .arg(desiredFrame).arg(last_frame));
692  }
693 
694  return last_frame;
695 }
696 
706 bool DecoderBase::DoFastForward(long long desiredFrame, bool discardFrames)
707 {
708  LOG(VB_PLAYBACK, LOG_INFO, LOC +
709  QString("DoFastForward(%1 (%2), %3 discard frames)")
710  .arg(desiredFrame).arg(m_framesPlayed)
711  .arg((discardFrames) ? "do" : "don't"));
712 
713  if (!ringBuffer)
714  {
715  LOG(VB_GENERAL, LOG_ERR, LOC + "No ringBuffer yet, can't fast forward");
716  return false;
717  }
718 
719  if (ringBuffer->IsDVD() &&
721  ringBuffer->DVD()->TitleTimeLeft() < 5)
722  {
723  return false;
724  }
725  // Rewind if we have already played the desiredFrame. The +1 is for
726  // MPEG4 NUV files, which need to decode an extra frame sometimes.
727  // This shouldn't effect how this works in general because this is
728  // only triggered on the first keyframe/frame skip when paused. At
729  // that point the decoding is more than one frame ahead of display.
730  if (desiredFrame+1 < m_framesPlayed)
731  return DoRewind(desiredFrame, discardFrames);
732  desiredFrame = max(desiredFrame, m_framesPlayed);
733 
734  // Save rawframe state, for later restoration...
735  bool oldrawstate = m_getrawframes;
736  m_getrawframes = false;
737 
738  ConditionallyUpdatePosMap(desiredFrame);
739 
740  // Fetch last keyframe in position map
741  long long last_frame = GetLastFrameInPosMap();
742 
743  // If the desiredFrame is past the end of the position map,
744  // do some frame-by-frame seeking until we get to it.
745  bool needflush = false;
746  if (desiredFrame > last_frame)
747  {
748  LOG(VB_GENERAL, LOG_NOTICE, LOC +
749  QString("DoFastForward(): desiredFrame(%1) > last_frame(%2)")
750  .arg(desiredFrame).arg(last_frame));
751 
752  if (desiredFrame - last_frame > 32)
753  {
754  LOG(VB_GENERAL, LOG_ERR, LOC + "DoFastForward(): "
755  "Desired frame is way past the end of the keyframe map!"
756  "\n\t\t\tSeeking to last keyframe instead.");
757  desiredFrame = last_frame;
758  }
759 
760  needflush = true;
761 
762  // Handle non-frame-by-frame seeking
763  DoFastForwardSeek(last_frame, needflush);
764 
765  m_exitafterdecoded = true; // don't actualy get a frame
766  while ((desiredFrame > last_frame) && !m_ateof)
767  {
768  bool retry = false;
769  GetFrame(kDecodeNothing, retry); // don't need to return frame...
770  SyncPositionMap();
771  last_frame = GetLastFrameInPosMap();
772  }
773  m_exitafterdecoded = false; // allow frames to be returned again
774 
775  if (m_ateof)
776  {
777  // Re-enable rawframe state if it was enabled before FF
778  m_getrawframes = oldrawstate;
779  return false;
780  }
781  }
782 
783  {
784  QMutexLocker locker(&m_positionMapLock);
785  if (m_positionMap.empty())
786  {
787  // Re-enable rawframe state if it was enabled before FF
788  m_getrawframes = oldrawstate;
789  return false;
790  }
791  }
792 
793  // Handle non-frame-by-frame seeking
794  DoFastForwardSeek(desiredFrame, needflush);
795 
796  // Do any Extra frame-by-frame seeking for exactseeks mode
797  // And flush pre-seek frame if we are allowed to and need to..
798  int normalframes = (uint64_t)(desiredFrame - (m_framesPlayed - 1)) > m_seeksnap
799  ? desiredFrame - m_framesPlayed : 0;
800  normalframes = max(normalframes, 0);
801  SeekReset(m_lastKey, normalframes, needflush, discardFrames);
802 
803  if (discardFrames || m_transcoding)
805 
806  // Re-enable rawframe state if it was enabled before FF
807  m_getrawframes = oldrawstate;
808 
809  return true;
810 }
811 
826 void DecoderBase::DoFastForwardSeek(long long desiredFrame, bool &needflush)
827 {
828  if (!ringBuffer)
829  {
830  LOG(VB_GENERAL, LOG_ERR, LOC +
831  "No ringBuffer yet, can't fast forward seek");
832  return;
833  }
834 
835  int pre_idx, post_idx;
836  FindPosition(desiredFrame, m_hasKeyFrameAdjustTable, pre_idx, post_idx);
837 
838  // if exactseeks, use keyframe <= desiredFrame
839 
840  PosMapEntry e, e_pre, e_post;
841  {
842  QMutexLocker locker(&m_positionMapLock);
843  e_pre = m_positionMap[pre_idx];
844  e_post = m_positionMap[post_idx];
845  }
846  e = e_pre;
847  if (((uint64_t) (GetKey(e_post) - desiredFrame)) <= m_seeksnap &&
848  (m_framesPlayed - 1 >= GetKey(e_pre) ||
849  GetKey(e_post) - desiredFrame < desiredFrame - GetKey(e_pre)))
850  {
851  // Snap to the right if e_post is within snap distance and is
852  // a closer snap than e_pre. Take into account that if
853  // framesPlayed has already reached e_pre, we should only snap
854  // to the right.
855  e = e_post;
856  }
857  m_lastKey = GetKey(e);
858 
860  {
861  ringBuffer->Seek(e.pos, SEEK_SET);
862  needflush = true;
864  m_fpsSkip = 0;
866  }
867 }
868 
870 {
872 }
873 
875 {
876  ResetPosMap();
877  m_framesPlayed = 0;
878  m_framesRead = 0;
880 
881  m_waitingForChange = false;
882  m_justAfterChange = true;
883 
885 }
886 
887 void DecoderBase::SetReadAdjust(long long adjust)
888 {
889  m_readAdjust = adjust;
890 }
891 
893 {
894  m_waitingForChange = true;
895 }
896 
898 {
899  return m_waitingForChange;
900 }
901 
902 QStringList DecoderBase::GetTracks(uint type) const
903 {
904  QStringList list;
905 
906  QMutexLocker locker(avcodeclock);
907 
908  for (size_t i = 0; i < m_tracks[type].size(); i++)
909  list += GetTrackDesc(type, i);
910 
911  return list;
912 }
913 
915 {
916  if (trackNo >= m_tracks[type].size())
917  return 0;
918 
919  return m_tracks[type][trackNo].m_language_index;
920 }
921 
922 QString DecoderBase::GetTrackDesc(uint type, uint trackNo) const
923 {
924  if (trackNo >= m_tracks[type].size())
925  return "";
926 
927  QMutexLocker locker(avcodeclock);
928 
929  QString type_msg = toString((TrackType)type);
930  int lang = m_tracks[type][trackNo].m_language;
931  int hnum = trackNo + 1;
932  if (kTrackTypeCC608 == type)
933  hnum = m_tracks[type][trackNo].m_stream_id;
934 
935  if (!lang)
936  return type_msg + QString(" %1").arg(hnum);
937  QString lang_msg = iso639_key_toName(lang);
938  return type_msg + QString(" %1: %2").arg(hnum).arg(lang_msg);
939 }
940 
941 int DecoderBase::SetTrack(uint type, int trackNo)
942 {
943  if (trackNo >= (int)m_tracks[type].size())
944  return -1;
945 
946  QMutexLocker locker(avcodeclock);
947 
948  m_currentTrack[type] = max(-1, trackNo);
949 
950  if (m_currentTrack[type] < 0)
952  else
953  {
956  }
957 
958  return m_currentTrack[type];
959 }
960 
962 {
963  // This locker causes a deadlock with DVDRingBuffer
964  // which is waiting while holding the lock.
965  // QMutexLocker locker(avcodeclock);
966 
967  if (trackNo >= m_tracks[type].size())
968  {
969  StreamInfo si;
970  return si;
971  }
972 
973  return m_tracks[type][trackNo];
974 }
975 
977 {
978  QMutexLocker locker(avcodeclock);
979 
980  for (size_t i = 0; i < m_tracks[type].size(); i++)
981  if (info.m_stream_id == m_tracks[type][i].m_stream_id)
982  return false;
983 
984  m_tracks[type].push_back(info);
985 
986  if (m_parent)
988 
989  return true;
990 }
991 
1008 {
1009  uint numStreams = m_tracks[type].size();
1010 
1011  if ((m_currentTrack[type] >= 0) &&
1012  (m_currentTrack[type] < (int)numStreams))
1013  {
1014  return m_currentTrack[type]; // track already selected
1015  }
1016 
1017  if (!numStreams)
1018  {
1019  m_currentTrack[type] = -1;
1021  return -1; // no tracks available
1022  }
1023 
1024  int selTrack = (1 == numStreams) ? 0 : -1;
1025 
1026  if ((selTrack < 0) &&
1028  {
1029  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Trying to reselect track");
1030  // Try to reselect user selected track stream.
1031  // This should find the stream after a commercial
1032  // break and in some cases after a channel change.
1033  int wlang = m_wantedTrack[type].m_language;
1035  for (uint i = 0; i < numStreams; i++)
1036  {
1037  if (wlang == m_tracks[type][i].m_language)
1038  {
1039  selTrack = i;
1040 
1041  if (windx == m_tracks[type][i].m_language_index)
1042  break;
1043  }
1044  }
1045  }
1046 
1047  if (selTrack < 0)
1048  {
1049  // Select the best track. Primary attribute is to favor a
1050  // forced track. Secondary attribute is language preference,
1051  // in order of most preferred to least preferred language.
1052  // Third attribute is track order, preferring the earliest
1053  // track.
1054  LOG(VB_PLAYBACK, LOG_INFO,
1055  LOC + "Trying to select track (w/lang & forced)");
1056  const int kForcedWeight = (1 << 20);
1057  const int kLanguageWeight = (1 << 10);
1058  const int kPositionWeight = (1 << 0);
1059  int bestScore = -1;
1060  selTrack = 0;
1061  for (uint i = 0; i < numStreams; i++)
1062  {
1063  int forced = (type == kTrackTypeSubtitle &&
1064  m_tracks[type][i].m_forced &&
1066  int position = numStreams - i;
1067  int language = 0;
1068  for (uint j = 0;
1069  (language == 0) && (j < m_languagePreference.size()); ++j)
1070  {
1071  if (m_tracks[type][i].m_language == m_languagePreference[j])
1072  language = m_languagePreference.size() - j;
1073  }
1074  int score = kForcedWeight * forced
1075  + kLanguageWeight * language
1076  + kPositionWeight * position;
1077  if (score > bestScore)
1078  {
1079  bestScore = score;
1080  selTrack = i;
1081  }
1082  }
1083  }
1084 
1085  int oldTrack = m_currentTrack[type];
1086  m_currentTrack[type] = selTrack;
1089 
1090  if (m_wantedTrack[type].m_av_stream_index < 0)
1091  m_wantedTrack[type] = tmp;
1092 
1093  int lang = m_tracks[type][m_currentTrack[type]].m_language;
1094  LOG(VB_PLAYBACK, LOG_INFO, LOC +
1095  QString("Selected track #%1 (type %2) in the %3 language(%4)")
1096  .arg(m_currentTrack[type]+1)
1097  .arg(type)
1098  .arg(iso639_key_toName(lang)).arg(lang));
1099 
1100  if (m_parent && (oldTrack != m_currentTrack[type]))
1102 
1103  return selTrack;
1104 }
1105 
1107 {
1108  QString str = QObject::tr("Track");
1109 
1110  if (kTrackTypeAudio == type)
1111  str = QObject::tr("Audio track");
1112  else if (kTrackTypeVideo == type)
1113  str = QObject::tr("Video track");
1114  else if (kTrackTypeSubtitle == type)
1115  str = QObject::tr("Subtitle track");
1116  else if (kTrackTypeCC608 == type)
1117  str = QObject::tr("CC", "EIA-608 closed captions");
1118  else if (kTrackTypeCC708 == type)
1119  str = QObject::tr("ATSC CC", "EIA-708 closed captions");
1120  else if (kTrackTypeTeletextCaptions == type)
1121  str = QObject::tr("TT CC", "Teletext closed captions");
1122  else if (kTrackTypeTeletextMenu == type)
1123  str = QObject::tr("TT Menu", "Teletext Menu");
1124  else if (kTrackTypeRawText == type)
1125  str = QObject::tr("Text", "Text stream");
1126  else if (kTrackTypeTextSubtitle == type)
1127  str = QObject::tr("TXT File", "Text File");
1128  return str;
1129 }
1130 
1131 int to_track_type(const QString &str)
1132 {
1133  int ret = -1;
1134 
1135  if (str.startsWith("AUDIO"))
1136  ret = kTrackTypeAudio;
1137  else if (str.startsWith("VIDEO"))
1138  ret = kTrackTypeVideo;
1139  else if (str.startsWith("SUBTITLE"))
1140  ret = kTrackTypeSubtitle;
1141  else if (str.startsWith("CC608"))
1142  ret = kTrackTypeCC608;
1143  else if (str.startsWith("CC708"))
1144  ret = kTrackTypeCC708;
1145  else if (str.startsWith("TTC"))
1147  else if (str.startsWith("TTM"))
1148  ret = kTrackTypeTeletextMenu;
1149  else if (str.startsWith("TFL"))
1150  ret = kTrackTypeTextSubtitle;
1151  else if (str.startsWith("RAWTEXT"))
1152  ret = kTrackTypeRawText;
1153  return ret;
1154 }
1155 
1157 {
1158  QString str;
1159 
1160  switch (type)
1161  {
1163  str = QObject::tr("Audio Description",
1164  "On-screen events described for the visually impaired");
1165  break;
1166  case kAudioTypeCleanEffects :
1167  str = QObject::tr("Clean Effects",
1168  "No dialog, background audio only");
1169  break;
1171  str = QObject::tr("Hearing Impaired",
1172  "Clear dialog for the hearing impaired");
1173  break;
1174  case kAudioTypeSpokenSubs :
1175  str = QObject::tr("Spoken Subtitles",
1176  "Subtitles are read out for the visually impaired");
1177  break;
1178  case kAudioTypeCommentary :
1179  str = QObject::tr("Commentary", "Director/Cast commentary track");
1180  break;
1181  case kAudioTypeNormal :
1182  default:
1183  str = QObject::tr("Normal", "Ordinary audio track");
1184  break;
1185  }
1186 
1187  return str;
1188 }
1189 
1191 {
1192  if (!m_playbackinfo || av_q2d(m_totalDuration) == 0)
1193  return;
1194 
1195  m_playbackinfo->SaveTotalDuration(1000000 * av_q2d(m_totalDuration));
1196 }
1197 
1199 {
1200  if (!m_playbackinfo || !m_framesRead)
1201  return;
1202 
1204 }
1205 
1206 // Linearly interpolate the value for a given key in the map. If the
1207 // key is outside the range of keys in the map, linearly extrapolate
1208 // using the fallback ratio.
1210  long long key,
1211  float fallback_ratio)
1212 {
1213  uint64_t key1, key2;
1214  uint64_t val1, val2;
1215 
1216  frm_pos_map_t::const_iterator lower = map.lowerBound(key);
1217  // QMap::lowerBound() finds a key >= the given key. We want one
1218  // <= the given key, so back up one element upon > condition.
1219  if (lower != map.begin() && (lower == map.end() || lower.key() > key))
1220  --lower;
1221  if (lower == map.end() || lower.key() > key)
1222  {
1223  key1 = 0;
1224  val1 = 0;
1225  LOG(VB_PLAYBACK, LOG_DEBUG, LOC +
1226  QString("TranslatePosition(key=%1): extrapolating to (0,0)")
1227  .arg(key));
1228  }
1229  else
1230  {
1231  key1 = lower.key();
1232  val1 = lower.value();
1233  }
1234  // Find the next key >= the given key. QMap::lowerBound() is
1235  // precisely correct in this case.
1236  frm_pos_map_t::const_iterator upper = map.lowerBound(key);
1237  if (upper == map.end())
1238  {
1239  // Extrapolate from (key1,val1) based on fallback_ratio
1240  key2 = key;
1241  val2 = llroundf(val1 + fallback_ratio * (key2 - key1));
1242  LOG(VB_PLAYBACK, LOG_DEBUG, LOC +
1243  QString("TranslatePosition(key=%1, ratio=%2): "
1244  "extrapolating to (%3,%4)")
1245  .arg(key).arg(fallback_ratio).arg(key2).arg(val2));
1246  return val2;
1247  }
1248  key2 = upper.key();
1249  val2 = upper.value();
1250  if (key1 == key2) // this happens for an exact keyframe match
1251  return val2; // can also set key2 = key1 + 1 avoid dividing by zero
1252 
1253  return llround(val1 + (double) (key - key1) * (val2 - val1) / (key2 - key1));
1254 }
1255 
1256 // Convert from an absolute frame number (not cutlist adjusted) to its
1257 // cutlist-adjusted position in milliseconds.
1258 uint64_t DecoderBase::TranslatePositionFrameToMs(long long position,
1259  float fallback_framerate,
1260  const frm_dir_map_t &cutlist)
1261 {
1262  QMutexLocker locker(&m_positionMapLock);
1263  // Accurate calculation of duration requires an up-to-date
1264  // duration map. However, the last frame (total duration) will
1265  // almost always appear to be past the end of the duration map, so
1266  // we limit duration map syncing to once every 3 seconds (a
1267  // somewhat arbitrary value).
1268  if (!m_frameToDurMap.empty())
1269  {
1270  frm_pos_map_t::const_iterator it = m_frameToDurMap.end();
1271  --it;
1272  if (position > it.key())
1273  {
1274  if (!m_lastPositionMapUpdate.isValid() ||
1275  (QDateTime::currentDateTime() >
1276  m_lastPositionMapUpdate.addSecs(3)))
1277  SyncPositionMap();
1278  }
1279  }
1280  return TranslatePositionAbsToRel(cutlist, position, m_frameToDurMap,
1281  1000 / fallback_framerate);
1282 }
1283 
1284 // Convert from a cutlist-adjusted position in milliseconds to its
1285 // absolute frame number (not cutlist-adjusted).
1287  float fallback_framerate,
1288  const frm_dir_map_t &cutlist)
1289 {
1290  QMutexLocker locker(&m_positionMapLock);
1291  // Convert relative position in milliseconds (cutlist-adjusted) to
1292  // its absolute position in milliseconds (not cutlist-adjusted).
1293  uint64_t ms = TranslatePositionRelToAbs(cutlist, dur_ms, m_frameToDurMap,
1294  1000 / fallback_framerate);
1295  // Convert absolute position in milliseconds to its absolute frame
1296  // number.
1297  return TranslatePosition(m_durToFrameMap, ms, fallback_framerate / 1000);
1298 }
1299 
1300 // Convert from an "absolute" (not cutlist-adjusted) value to its
1301 // "relative" (cutlist-adjusted) mapped value. Usually the position
1302 // argument is a frame number, the map argument maps frames to
1303 // milliseconds, the fallback_ratio is 1000/framerate_fps, and the
1304 // return value is in milliseconds.
1305 //
1306 // If the map and fallback_ratio arguments are omitted, it simply
1307 // converts from an absolute frame number to a relative
1308 // (cutlist-adjusted) frame number.
1309 uint64_t
1311  uint64_t absPosition, // frames
1312  const frm_pos_map_t &map, // frame->ms
1313  float fallback_ratio)
1314 {
1315  uint64_t subtraction = 0;
1316  uint64_t startOfCutRegion = 0;
1317  bool withinCut = false;
1318  bool first = true;
1319  for (frm_dir_map_t::const_iterator i = deleteMap.begin();
1320  i != deleteMap.end(); ++i)
1321  {
1322  if (first)
1323  withinCut = (i.value() == MARK_CUT_END);
1324  first = false;
1325  if (i.key() > absPosition)
1326  break;
1327  uint64_t mappedKey = TranslatePosition(map, i.key(), fallback_ratio);
1328  if (i.value() == MARK_CUT_START && !withinCut)
1329  {
1330  withinCut = true;
1331  startOfCutRegion = mappedKey;
1332  }
1333  else if (i.value() == MARK_CUT_END && withinCut)
1334  {
1335  withinCut = false;
1336  subtraction += (mappedKey - startOfCutRegion);
1337  }
1338  }
1339  uint64_t mappedPos = TranslatePosition(map, absPosition, fallback_ratio);
1340  if (withinCut)
1341  subtraction += (mappedPos - startOfCutRegion);
1342  return mappedPos - subtraction;
1343 }
1344 
1345 // Convert from a "relative" (cutlist-adjusted) value to its
1346 // "absolute" (not cutlist-adjusted) mapped value. Usually the
1347 // position argument is in milliseconds, the map argument maps frames
1348 // to milliseconds, the fallback_ratio is 1000/framerate_fps, and the
1349 // return value is also in milliseconds. Upon return, if necessary,
1350 // the result may need a separate, non-cutlist adjusted conversion
1351 // from milliseconds to frame number, using the inverse
1352 // millisecond-to-frame map and the inverse fallback_ratio; see for
1353 // example TranslatePositionMsToFrame().
1354 //
1355 // If the map and fallback_ratio arguments are omitted, it simply
1356 // converts from a relatve (cutlist-adjusted) frame number to an
1357 // absolute frame number.
1358 uint64_t
1360  uint64_t relPosition, // ms
1361  const frm_pos_map_t &map, // frame->ms
1362  float fallback_ratio)
1363 {
1364  uint64_t addition = 0;
1365  uint64_t startOfCutRegion = 0;
1366  bool withinCut = false;
1367  bool first = true;
1368  for (frm_dir_map_t::const_iterator i = deleteMap.begin();
1369  i != deleteMap.end(); ++i)
1370  {
1371  if (first)
1372  withinCut = (i.value() == MARK_CUT_END);
1373  first = false;
1374  uint64_t mappedKey = TranslatePosition(map, i.key(), fallback_ratio);
1375  if (i.value() == MARK_CUT_START && !withinCut)
1376  {
1377  withinCut = true;
1378  startOfCutRegion = mappedKey;
1379  if (relPosition + addition <= startOfCutRegion)
1380  break;
1381  }
1382  else if (i.value() == MARK_CUT_END && withinCut)
1383  {
1384  withinCut = false;
1385  addition += (mappedKey - startOfCutRegion);
1386  }
1387  }
1388  return relPosition + addition;
1389 }
1390 
1395 AVPixelFormat DecoderBase::GetBestVideoFormat(AVPixelFormat* Formats)
1396 {
1397  if (m_parent)
1398  {
1400  for (AVPixelFormat *format = Formats; *format != AV_PIX_FMT_NONE; format++)
1401  for (VideoFrameType* mythfmt = mythfmts; *mythfmt != FMT_NONE; mythfmt++)
1402  if (FrameTypeToPixelFormat(*mythfmt) == *format)
1403  return *format;
1404  }
1405  return AV_PIX_FMT_NONE;
1406 }
1407 
1408 /* vim: set expandtab tabstop=4 shiftwidth=4: */
virtual bool DoRewind(long long desiredFrame, bool discardFrames=true)
bool ForcedSubtitlesFavored(void) const
Definition: mythplayer.h:307
void SetKeyframeDistance(int keyframedistance)
Definition: mythplayer.cpp:562
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
long long m_readAdjust
Definition: decoderbase.h:348
virtual void SeekReset(long long newkey, uint skipFrames, bool doFlush, bool discardFrames)
Definition: decoderbase.cpp:72
virtual bool IsInDiscMenuOrStillFrame(void) const
int m_currentTrack[kTrackTypeCount]
Definition: decoderbase.h:354
unsigned long long m_frameCounter
Definition: decoderbase.h:308
void ResetTracks(void)
Definition: decoderbase.h:396
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:111
uint64_t SavePositionMapDelta(long long first_frame, long long last_frame)
bool m_exitafterdecoded
Definition: decoderbase.h:321
MarkTypes m_positionMapType
Definition: decoderbase.h:327
QString toString(TrackType type)
void SaveTotalDuration(void)
ProgramInfo * m_playbackinfo
Definition: decoderbase.h:294
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
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
bool m_watchingrecording
Definition: decoderbase.h:338
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:893
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:714
RingBuffer * ringBuffer
Definition: decoderbase.h:296
MarkTypes
Definition: programtypes.h:48
bool IsDVD(void) const
Holds information on recordings and videos.
Definition: programinfo.h:66
VideoFrameType * DirectRenderFormats(void)
Return a list of frame types that can be rendered directly.
Definition: mythplayer.cpp:912
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
virtual bool InsertTrack(uint type, const StreamInfo &)
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:34
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
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:39
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
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:79
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:92
void FileChanged(void)
bool m_transcoding
Definition: decoderbase.h:322
StreamInfo m_selectedTrack[(uint) kTrackTypeCount]
Definition: decoderbase.h:357
int m_keyframedist
Definition: decoderbase.h:311
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.
uint64_t m_seeksnap
Definition: decoderbase.h:336
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
void QueryPositionMap(frm_pos_map_t &, MarkTypes type) const
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
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:45
bool PosMapFromEnc(uint64_t start, frm_pos_map_t &posMap, frm_pos_map_t &durMap)
EofState m_ateof
Definition: decoderbase.h:320
bool m_getrawframes
Definition: decoderbase.h:342
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)
void SavePositionMapDelta(frm_pos_map_t &, MarkTypes type) const
MythPlayer * m_parent
Definition: decoderbase.h:293
virtual int GetTrackLanguageIndex(uint type, uint trackNo) const