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