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())
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  {
53  SeekReset(0, 0, true, true);
54  }
55 
56  if (reset_video_data)
57  {
58  ResetPosMap();
59  m_framesPlayed = 0;
60  m_fpsSkip = 0;
61  m_framesRead = 0;
63  m_dontSyncPositionMap = false;
64  }
65 
66  if (reset_file)
67  {
68  m_waitingForChange = false;
70  }
71 }
72 
73 void DecoderBase::SeekReset(long long /*newkey*/, uint /*skipFrames*/,
74  bool /*doFlush*/, bool /*discardFrames*/)
75 {
76  m_readAdjust = 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  long long 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  GetFrame(kDecodeNothing); // don't need to return frame...
769  SyncPositionMap();
770  last_frame = GetLastFrameInPosMap();
771  }
772  m_exitafterdecoded = false; // allow frames to be returned again
773 
774  if (m_ateof)
775  {
776  // Re-enable rawframe state if it was enabled before FF
777  m_getrawframes = oldrawstate;
778  return false;
779  }
780  }
781 
782  {
783  QMutexLocker locker(&m_positionMapLock);
784  if (m_positionMap.empty())
785  {
786  // Re-enable rawframe state if it was enabled before FF
787  m_getrawframes = oldrawstate;
788  return false;
789  }
790  }
791 
792  // Handle non-frame-by-frame seeking
793  DoFastForwardSeek(desiredFrame, needflush);
794 
795  // Do any Extra frame-by-frame seeking for exactseeks mode
796  // And flush pre-seek frame if we are allowed to and need to..
797  int normalframes = (uint64_t)(desiredFrame - (m_framesPlayed - 1)) > m_seeksnap
798  ? desiredFrame - m_framesPlayed : 0;
799  normalframes = max(normalframes, 0);
800  SeekReset(m_lastKey, normalframes, needflush, discardFrames);
801 
802  if (discardFrames || m_transcoding)
804 
805  // Re-enable rawframe state if it was enabled before FF
806  m_getrawframes = oldrawstate;
807 
808  return true;
809 }
810 
825 void DecoderBase::DoFastForwardSeek(long long desiredFrame, bool &needflush)
826 {
827  if (!ringBuffer)
828  {
829  LOG(VB_GENERAL, LOG_ERR, LOC +
830  "No ringBuffer yet, can't fast forward seek");
831  return;
832  }
833 
834  int pre_idx, post_idx;
835  FindPosition(desiredFrame, m_hasKeyFrameAdjustTable, pre_idx, post_idx);
836 
837  // if exactseeks, use keyframe <= desiredFrame
838 
839  PosMapEntry e, e_pre, e_post;
840  {
841  QMutexLocker locker(&m_positionMapLock);
842  e_pre = m_positionMap[pre_idx];
843  e_post = m_positionMap[post_idx];
844  }
845  e = e_pre;
846  if (((uint64_t) (GetKey(e_post) - desiredFrame)) <= m_seeksnap &&
847  (m_framesPlayed - 1 >= GetKey(e_pre) ||
848  GetKey(e_post) - desiredFrame < desiredFrame - GetKey(e_pre)))
849  {
850  // Snap to the right if e_post is within snap distance and is
851  // a closer snap than e_pre. Take into account that if
852  // framesPlayed has already reached e_pre, we should only snap
853  // to the right.
854  e = e_post;
855  }
856  m_lastKey = GetKey(e);
857 
859  {
860  ringBuffer->Seek(e.pos, SEEK_SET);
861  needflush = true;
863  m_fpsSkip = 0;
865  }
866 }
867 
869 {
871 }
872 
874 {
875  ResetPosMap();
876  m_framesPlayed = 0;
877  m_framesRead = 0;
879 
880  m_waitingForChange = false;
881  m_justAfterChange = true;
882 
884 }
885 
886 void DecoderBase::SetReadAdjust(long long adjust)
887 {
888  m_readAdjust = adjust;
889 }
890 
892 {
893  m_waitingForChange = true;
894 }
895 
897 {
898  return m_waitingForChange;
899 }
900 
901 QStringList DecoderBase::GetTracks(uint type) const
902 {
903  QStringList list;
904 
905  QMutexLocker locker(avcodeclock);
906 
907  for (size_t i = 0; i < m_tracks[type].size(); i++)
908  list += GetTrackDesc(type, i);
909 
910  return list;
911 }
912 
914 {
915  if (trackNo >= m_tracks[type].size())
916  return 0;
917 
918  return m_tracks[type][trackNo].m_language_index;
919 }
920 
921 QString DecoderBase::GetTrackDesc(uint type, uint trackNo) const
922 {
923  if (trackNo >= m_tracks[type].size())
924  return "";
925 
926  QMutexLocker locker(avcodeclock);
927 
928  QString type_msg = toString((TrackType)type);
929  int lang = m_tracks[type][trackNo].m_language;
930  int hnum = trackNo + 1;
931  if (kTrackTypeCC608 == type)
932  hnum = m_tracks[type][trackNo].m_stream_id;
933 
934  if (!lang)
935  return type_msg + QString(" %1").arg(hnum);
936  QString lang_msg = iso639_key_toName(lang);
937  return type_msg + QString(" %1: %2").arg(hnum).arg(lang_msg);
938 }
939 
940 int DecoderBase::SetTrack(uint type, int trackNo)
941 {
942  if (trackNo >= (int)m_tracks[type].size())
943  return -1;
944 
945  QMutexLocker locker(avcodeclock);
946 
947  m_currentTrack[type] = max(-1, trackNo);
948 
949  if (m_currentTrack[type] < 0)
951  else
952  {
955  }
956 
957  return m_currentTrack[type];
958 }
959 
961 {
962  // This locker causes a deadlock with DVDRingBuffer
963  // which is waiting while holding the lock.
964  // QMutexLocker locker(avcodeclock);
965 
966  if (trackNo >= m_tracks[type].size())
967  {
968  StreamInfo si;
969  return si;
970  }
971 
972  return m_tracks[type][trackNo];
973 }
974 
976 {
977  QMutexLocker locker(avcodeclock);
978 
979  for (size_t i = 0; i < m_tracks[type].size(); i++)
980  if (info.m_stream_id == m_tracks[type][i].m_stream_id)
981  return false;
982 
983  m_tracks[type].push_back(info);
984 
985  if (m_parent)
987 
988  return true;
989 }
990 
1007 {
1008  uint numStreams = m_tracks[type].size();
1009 
1010  if ((m_currentTrack[type] >= 0) &&
1011  (m_currentTrack[type] < (int)numStreams))
1012  {
1013  return m_currentTrack[type]; // track already selected
1014  }
1015 
1016  if (!numStreams)
1017  {
1018  m_currentTrack[type] = -1;
1020  return -1; // no tracks available
1021  }
1022 
1023  int selTrack = (1 == numStreams) ? 0 : -1;
1024 
1025  if ((selTrack < 0) &&
1027  {
1028  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Trying to reselect track");
1029  // Try to reselect user selected track stream.
1030  // This should find the stream after a commercial
1031  // break and in some cases after a channel change.
1032  int wlang = m_wantedTrack[type].m_language;
1034  for (uint i = 0; i < numStreams; i++)
1035  {
1036  if (wlang == m_tracks[type][i].m_language)
1037  {
1038  selTrack = i;
1039 
1040  if (windx == m_tracks[type][i].m_language_index)
1041  break;
1042  }
1043  }
1044  }
1045 
1046  if (selTrack < 0)
1047  {
1048  // Select the best track. Primary attribute is to favor a
1049  // forced track. Secondary attribute is language preference,
1050  // in order of most preferred to least preferred language.
1051  // Third attribute is track order, preferring the earliest
1052  // track.
1053  LOG(VB_PLAYBACK, LOG_INFO,
1054  LOC + "Trying to select track (w/lang & forced)");
1055  const int kForcedWeight = (1 << 20);
1056  const int kLanguageWeight = (1 << 10);
1057  const int kPositionWeight = (1 << 0);
1058  int bestScore = -1;
1059  selTrack = 0;
1060  for (uint i = 0; i < numStreams; i++)
1061  {
1062  int forced = (type == kTrackTypeSubtitle &&
1063  m_tracks[type][i].m_forced &&
1065  int position = numStreams - i;
1066  int language = 0;
1067  for (uint j = 0;
1068  (language == 0) && (j < m_languagePreference.size()); ++j)
1069  {
1070  if (m_tracks[type][i].m_language == m_languagePreference[j])
1071  language = m_languagePreference.size() - j;
1072  }
1073  int score = kForcedWeight * forced
1074  + kLanguageWeight * language
1075  + kPositionWeight * position;
1076  if (score > bestScore)
1077  {
1078  bestScore = score;
1079  selTrack = i;
1080  }
1081  }
1082  }
1083 
1084  int oldTrack = m_currentTrack[type];
1085  m_currentTrack[type] = selTrack;
1088 
1089  if (m_wantedTrack[type].m_av_stream_index < 0)
1090  m_wantedTrack[type] = tmp;
1091 
1092  int lang = m_tracks[type][m_currentTrack[type]].m_language;
1093  LOG(VB_PLAYBACK, LOG_INFO, LOC +
1094  QString("Selected track #%1 (type %2) in the %3 language(%4)")
1095  .arg(m_currentTrack[type]+1)
1096  .arg(type)
1097  .arg(iso639_key_toName(lang)).arg(lang));
1098 
1099  if (m_parent && (oldTrack != m_currentTrack[type]))
1101 
1102  return selTrack;
1103 }
1104 
1106 {
1107  QString str = QObject::tr("Track");
1108 
1109  if (kTrackTypeAudio == type)
1110  str = QObject::tr("Audio track");
1111  else if (kTrackTypeVideo == type)
1112  str = QObject::tr("Video track");
1113  else if (kTrackTypeSubtitle == type)
1114  str = QObject::tr("Subtitle track");
1115  else if (kTrackTypeCC608 == type)
1116  str = QObject::tr("CC", "EIA-608 closed captions");
1117  else if (kTrackTypeCC708 == type)
1118  str = QObject::tr("ATSC CC", "EIA-708 closed captions");
1119  else if (kTrackTypeTeletextCaptions == type)
1120  str = QObject::tr("TT CC", "Teletext closed captions");
1121  else if (kTrackTypeTeletextMenu == type)
1122  str = QObject::tr("TT Menu", "Teletext Menu");
1123  else if (kTrackTypeRawText == type)
1124  str = QObject::tr("Text", "Text stream");
1125  else if (kTrackTypeTextSubtitle == type)
1126  str = QObject::tr("TXT File", "Text File");
1127  return str;
1128 }
1129 
1130 int to_track_type(const QString &str)
1131 {
1132  int ret = -1;
1133 
1134  if (str.startsWith("AUDIO"))
1135  ret = kTrackTypeAudio;
1136  else if (str.startsWith("VIDEO"))
1137  ret = kTrackTypeVideo;
1138  else if (str.startsWith("SUBTITLE"))
1139  ret = kTrackTypeSubtitle;
1140  else if (str.startsWith("CC608"))
1141  ret = kTrackTypeCC608;
1142  else if (str.startsWith("CC708"))
1143  ret = kTrackTypeCC708;
1144  else if (str.startsWith("TTC"))
1146  else if (str.startsWith("TTM"))
1147  ret = kTrackTypeTeletextMenu;
1148  else if (str.startsWith("TFL"))
1149  ret = kTrackTypeTextSubtitle;
1150  else if (str.startsWith("RAWTEXT"))
1151  ret = kTrackTypeRawText;
1152  return ret;
1153 }
1154 
1156 {
1157  QString str;
1158 
1159  switch (type)
1160  {
1162  str = QObject::tr("Audio Description",
1163  "On-screen events described for the visually impaired");
1164  break;
1165  case kAudioTypeCleanEffects :
1166  str = QObject::tr("Clean Effects",
1167  "No dialog, background audio only");
1168  break;
1170  str = QObject::tr("Hearing Impaired",
1171  "Clear dialog for the hearing impaired");
1172  break;
1173  case kAudioTypeSpokenSubs :
1174  str = QObject::tr("Spoken Subtitles",
1175  "Subtitles are read out for the visually impaired");
1176  break;
1177  case kAudioTypeCommentary :
1178  str = QObject::tr("Commentary", "Director/Cast commentary track");
1179  break;
1180  case kAudioTypeNormal :
1181  default:
1182  str = QObject::tr("Normal", "Ordinary audio track");
1183  break;
1184  }
1185 
1186  return str;
1187 }
1188 
1190 {
1191  if (!m_playbackinfo || av_q2d(m_totalDuration) == 0)
1192  return;
1193 
1194  m_playbackinfo->SaveTotalDuration(1000000 * av_q2d(m_totalDuration));
1195 }
1196 
1198 {
1199  if (!m_playbackinfo || !m_framesRead)
1200  return;
1201 
1203 }
1204 
1205 // Linearly interpolate the value for a given key in the map. If the
1206 // key is outside the range of keys in the map, linearly extrapolate
1207 // using the fallback ratio.
1209  long long key,
1210  float fallback_ratio)
1211 {
1212  uint64_t key1, key2;
1213  uint64_t val1, val2;
1214 
1215  frm_pos_map_t::const_iterator lower = map.lowerBound(key);
1216  // QMap::lowerBound() finds a key >= the given key. We want one
1217  // <= the given key, so back up one element upon > condition.
1218  if (lower != map.begin() && (lower == map.end() || lower.key() > key))
1219  --lower;
1220  if (lower == map.end() || lower.key() > key)
1221  {
1222  key1 = 0;
1223  val1 = 0;
1224  LOG(VB_PLAYBACK, LOG_DEBUG, LOC +
1225  QString("TranslatePosition(key=%1): extrapolating to (0,0)")
1226  .arg(key));
1227  }
1228  else
1229  {
1230  key1 = lower.key();
1231  val1 = lower.value();
1232  }
1233  // Find the next key >= the given key. QMap::lowerBound() is
1234  // precisely correct in this case.
1235  frm_pos_map_t::const_iterator upper = map.lowerBound(key);
1236  if (upper == map.end())
1237  {
1238  // Extrapolate from (key1,val1) based on fallback_ratio
1239  key2 = key;
1240  val2 = llroundf(val1 + fallback_ratio * (key2 - key1));
1241  LOG(VB_PLAYBACK, LOG_DEBUG, LOC +
1242  QString("TranslatePosition(key=%1, ratio=%2): "
1243  "extrapolating to (%3,%4)")
1244  .arg(key).arg(fallback_ratio).arg(key2).arg(val2));
1245  return val2;
1246  }
1247  key2 = upper.key();
1248  val2 = upper.value();
1249  if (key1 == key2) // this happens for an exact keyframe match
1250  return val2; // can also set key2 = key1 + 1 avoid dividing by zero
1251 
1252  return llround(val1 + (double) (key - key1) * (val2 - val1) / (key2 - key1));
1253 }
1254 
1255 // Convert from an absolute frame number (not cutlist adjusted) to its
1256 // cutlist-adjusted position in milliseconds.
1257 uint64_t DecoderBase::TranslatePositionFrameToMs(long long position,
1258  float fallback_framerate,
1259  const frm_dir_map_t &cutlist)
1260 {
1261  QMutexLocker locker(&m_positionMapLock);
1262  // Accurate calculation of duration requires an up-to-date
1263  // duration map. However, the last frame (total duration) will
1264  // almost always appear to be past the end of the duration map, so
1265  // we limit duration map syncing to once every 3 seconds (a
1266  // somewhat arbitrary value).
1267  if (!m_frameToDurMap.empty())
1268  {
1269  frm_pos_map_t::const_iterator it = m_frameToDurMap.end();
1270  --it;
1271  if (position > it.key())
1272  {
1273  if (!m_lastPositionMapUpdate.isValid() ||
1274  (QDateTime::currentDateTime() >
1275  m_lastPositionMapUpdate.addSecs(3)))
1276  SyncPositionMap();
1277  }
1278  }
1279  return TranslatePositionAbsToRel(cutlist, position, m_frameToDurMap,
1280  1000 / fallback_framerate);
1281 }
1282 
1283 // Convert from a cutlist-adjusted position in milliseconds to its
1284 // absolute frame number (not cutlist-adjusted).
1286  float fallback_framerate,
1287  const frm_dir_map_t &cutlist)
1288 {
1289  QMutexLocker locker(&m_positionMapLock);
1290  // Convert relative position in milliseconds (cutlist-adjusted) to
1291  // its absolute position in milliseconds (not cutlist-adjusted).
1292  uint64_t ms = TranslatePositionRelToAbs(cutlist, dur_ms, m_frameToDurMap,
1293  1000 / fallback_framerate);
1294  // Convert absolute position in milliseconds to its absolute frame
1295  // number.
1296  return TranslatePosition(m_durToFrameMap, ms, fallback_framerate / 1000);
1297 }
1298 
1299 // Convert from an "absolute" (not cutlist-adjusted) value to its
1300 // "relative" (cutlist-adjusted) mapped value. Usually the position
1301 // argument is a frame number, the map argument maps frames to
1302 // milliseconds, the fallback_ratio is 1000/framerate_fps, and the
1303 // return value is in milliseconds.
1304 //
1305 // If the map and fallback_ratio arguments are omitted, it simply
1306 // converts from an absolute frame number to a relative
1307 // (cutlist-adjusted) frame number.
1308 uint64_t
1310  uint64_t absPosition, // frames
1311  const frm_pos_map_t &map, // frame->ms
1312  float fallback_ratio)
1313 {
1314  uint64_t subtraction = 0;
1315  uint64_t startOfCutRegion = 0;
1316  bool withinCut = false;
1317  bool first = true;
1318  for (frm_dir_map_t::const_iterator i = deleteMap.begin();
1319  i != deleteMap.end(); ++i)
1320  {
1321  if (first)
1322  withinCut = (i.value() == MARK_CUT_END);
1323  first = false;
1324  if (i.key() > absPosition)
1325  break;
1326  uint64_t mappedKey = TranslatePosition(map, i.key(), fallback_ratio);
1327  if (i.value() == MARK_CUT_START && !withinCut)
1328  {
1329  withinCut = true;
1330  startOfCutRegion = mappedKey;
1331  }
1332  else if (i.value() == MARK_CUT_END && withinCut)
1333  {
1334  withinCut = false;
1335  subtraction += (mappedKey - startOfCutRegion);
1336  }
1337  }
1338  uint64_t mappedPos = TranslatePosition(map, absPosition, fallback_ratio);
1339  if (withinCut)
1340  subtraction += (mappedPos - startOfCutRegion);
1341  return mappedPos - subtraction;
1342 }
1343 
1344 // Convert from a "relative" (cutlist-adjusted) value to its
1345 // "absolute" (not cutlist-adjusted) mapped value. Usually the
1346 // position argument is in milliseconds, the map argument maps frames
1347 // to milliseconds, the fallback_ratio is 1000/framerate_fps, and the
1348 // return value is also in milliseconds. Upon return, if necessary,
1349 // the result may need a separate, non-cutlist adjusted conversion
1350 // from milliseconds to frame number, using the inverse
1351 // millisecond-to-frame map and the inverse fallback_ratio; see for
1352 // example TranslatePositionMsToFrame().
1353 //
1354 // If the map and fallback_ratio arguments are omitted, it simply
1355 // converts from a relatve (cutlist-adjusted) frame number to an
1356 // absolute frame number.
1357 uint64_t
1359  uint64_t relPosition, // ms
1360  const frm_pos_map_t &map, // frame->ms
1361  float fallback_ratio)
1362 {
1363  uint64_t addition = 0;
1364  uint64_t startOfCutRegion = 0;
1365  bool withinCut = false;
1366  bool first = true;
1367  for (frm_dir_map_t::const_iterator i = deleteMap.begin();
1368  i != deleteMap.end(); ++i)
1369  {
1370  if (first)
1371  withinCut = (i.value() == MARK_CUT_END);
1372  first = false;
1373  uint64_t mappedKey = TranslatePosition(map, i.key(), fallback_ratio);
1374  if (i.value() == MARK_CUT_START && !withinCut)
1375  {
1376  withinCut = true;
1377  startOfCutRegion = mappedKey;
1378  if (relPosition + addition <= startOfCutRegion)
1379  break;
1380  }
1381  else if (i.value() == MARK_CUT_END && withinCut)
1382  {
1383  withinCut = false;
1384  addition += (mappedKey - startOfCutRegion);
1385  }
1386  }
1387  return relPosition + addition;
1388 }
1389 
1390 
1391 /* vim: set expandtab tabstop=4 shiftwidth=4: */
virtual bool DoRewind(long long desiredFrame, bool discardFrames=true)
bool ForcedSubtitlesFavored(void) const
Definition: mythplayer.h:304
void SetKeyframeDistance(int keyframedistance)
Definition: mythplayer.cpp:680
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:303
struct exc__state * last
Definition: pxsup2dast.c:98
virtual void SetEofState(EofState eof)
Definition: decoderbase.h:133
const DVDRingBuffer * DVD(void) const
long long m_readAdjust
Definition: decoderbase.h:349
virtual void SeekReset(long long newkey, uint skipFrames, bool doFlush, bool discardFrames)
Definition: decoderbase.cpp:73
virtual bool IsInDiscMenuOrStillFrame(void) const
int m_currentTrack[kTrackTypeCount]
Definition: decoderbase.h:355
virtual bool GetFrame(DecodeType)=0
Demux, preprocess and possibly decode a frame of video/audio.
void ResetTracks(void)
Definition: decoderbase.h:397
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:341
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:322
MarkTypes m_positionMapType
Definition: decoderbase.h:328
QString toString(TrackType type)
void SaveTotalDuration(void)
ProgramInfo * m_playbackinfo
Definition: decoderbase.h:296
uint64_t GetTotalReadPosition(void)
DecoderBase(MythPlayer *parent, const ProgramInfo &pginfo)
Definition: decoderbase.cpp:18
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)
QMap< uint64_t, MarkTypes > frm_dir_map_t
Frame # -> Mark map.
Definition: programtypes.h:81
unsigned int uint
Definition: compat.h:140
QDateTime m_lastPositionMapUpdate
Definition: decoderbase.h:335
long long m_indexOffset
Definition: decoderbase.h:313
vector< int > m_languagePreference
language preferences for auto-selection of streams
Definition: decoderbase.h:360
bool m_watchingrecording
Definition: decoderbase.h:339
static guint32 * tmp
Definition: goom_core.c:35
#define LOC
Definition: decoderbase.cpp:16
bool m_posmapStarted
Definition: decoderbase.h:327
void SaveTotalFrames(int64_t frames)
Store the Total Frames at frame 0 in the recordedmarkup table.
void SetFramesPlayed(uint64_t played)
void SetWaitForChange(void)
void SetFileLength(int total, int frames)
Definition: mythplayer.cpp:893
RingBuffer * ringBuffer
Definition: decoderbase.h:298
MarkTypes
Definition: programtypes.h:48
bool IsDVD(void) const
Holds information on recordings and videos.
Definition: programinfo.h:66
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:332
bool GetWaitForChange(void) const
uint TitleTimeLeft(void)
returns seconds left in the title
bool m_justAfterChange
Definition: decoderbase.h:350
virtual bool InsertTrack(uint type, const StreamInfo &)
void FileChangedCallback()
virtual bool DoRewindSeek(long long desiredFrame)
bool m_dontSyncPositionMap
Definition: decoderbase.h:334
enum TrackTypes TrackType
Track types.
sinfo_vec_t m_tracks[kTrackTypeCount]
Definition: decoderbase.h:356
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)
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:330
long long m_framesPlayed
Definition: decoderbase.h:308
uint64_t TranslatePositionMsToFrame(uint64_t dur_ms, float fallback_framerate, const frm_dir_map_t &cutlist)
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:310
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...
unsigned long GetPositionMapSize(void) const
static uint64_t TranslatePosition(const frm_pos_map_t &map, long long key, float fallback_ratio)
int elapsed(void) const
Returns milliseconds elapsed since last start() or restart()
Definition: mythtimer.cpp:90
bool m_waitingForChange
Definition: decoderbase.h:348
virtual bool SyncPositionMap(void)
Updates the position map used for skipping frames.
long long m_lastKey
Definition: decoderbase.h:311
#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:333
virtual void SetWatchingRecording(bool mode)
Definition: decoderbase.cpp:79
void SetReadAdjust(long long adjust)
StreamInfo m_wantedTrack[kTrackTypeCount]
Definition: decoderbase.h:357
StreamInfo GetTrackInfo(uint type, uint trackNo) const
bool IsDisc(void) const
vector< PosMapEntry > m_positionMap
Definition: decoderbase.h:331
QMutex * avcodeclock
This global variable is used to makes certain calls to avlib threadsafe.
uint m_language_index
Definition: decoderbase.h:98
virtual bool PosMapFromDb(void)
Definition: decoderbase.cpp:92
void FileChanged(void)
bool m_transcoding
Definition: decoderbase.h:323
StreamInfo m_selectedTrack[(uint) kTrackTypeCount]
Definition: decoderbase.h:358
int m_keyframedist
Definition: decoderbase.h:312
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:326
virtual int AutoSelectTrack(uint type)
Select best track.
uint64_t m_seeksnap
Definition: decoderbase.h:337
virtual bool DoFastForward(long long desiredFrame, bool discardFrames=true)
Skips ahead or rewinds to desiredFrame.
int m_av_stream_index
Definition: decoderbase.h:94
QMap< long long, long long > frm_pos_map_t
Frame # -> File offset map.
Definition: programtypes.h:46
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:309
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:321
bool m_getrawframes
Definition: decoderbase.h:343
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:295
virtual int GetTrackLanguageIndex(uint type, uint trackNo) const