MythTV  master
mythcommflagplayer.cpp
Go to the documentation of this file.
1 
2 #include "mythcommflagplayer.h"
3 
4 #include <QRunnable>
5 
6 #include "mthreadpool.h"
7 #include "mythlogging.h"
8 
9 #include <unistd.h> // for usleep()
10 #include <iostream> // for cout()
11 
12 using namespace std;
13 
14 class RebuildSaver : public QRunnable
15 {
16  public:
17  RebuildSaver(DecoderBase *d, uint64_t f, uint64_t l)
18  : m_decoder(d), m_first(f), m_last(l)
19  {
20  QMutexLocker locker(&s_lock);
21  s_cnt[d]++;
22  }
23 
24  void run(void) override // QRunnable
25  {
26  m_decoder->SavePositionMapDelta(m_first, m_last);
27 
28  QMutexLocker locker(&s_lock);
29  s_cnt[m_decoder]--;
30  if (!s_cnt[m_decoder])
31  s_wait.wakeAll();
32  }
33 
35  {
36  QMutexLocker locker(&s_lock);
37  return s_cnt[d];
38  }
39 
40  static void Wait(DecoderBase *d)
41  {
42  QMutexLocker locker(&s_lock);
43  if (!s_cnt[d])
44  return;
45  while (s_wait.wait(&s_lock))
46  {
47  if (!s_cnt[d])
48  return;
49  }
50  }
51 
52  private:
54  uint64_t m_first;
55  uint64_t m_last;
56 
57  static QMutex s_lock;
58  static QWaitCondition s_wait;
59  static QMap<DecoderBase*,uint> s_cnt;
60 };
62 QWaitCondition RebuildSaver::s_wait;
63 QMap<DecoderBase*,uint> RebuildSaver::s_cnt;
64 
66  bool showPercentage, StatusCallback cb, void* cbData)
67 {
68  uint64_t myFramesPlayed = 0;
69  uint64_t pmap_first = 0;
70  uint64_t pmap_last = 0;
71 
72  m_killDecoder = false;
73  m_framesPlayed = 0;
74 
75  // clear out any existing seektables
76  m_playerCtx->LockPlayingInfo(__FILE__, __LINE__);
77  if (m_playerCtx->m_playingInfo)
78  {
79  m_playerCtx->m_playingInfo->ClearPositionMap(MARK_KEYFRAME);
80  m_playerCtx->m_playingInfo->ClearPositionMap(MARK_GOP_START);
81  m_playerCtx->m_playingInfo->ClearPositionMap(MARK_GOP_BYFRAME);
82  m_playerCtx->m_playingInfo->ClearPositionMap(MARK_DURATION_MS);
83  }
84  m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
85 
86  if (OpenFile() < 0)
87  return false;
88 
89  SetPlaying(true);
90 
91  if (!InitVideo())
92  {
93  LOG(VB_GENERAL, LOG_ERR,
94  "RebuildSeekTable unable to initialize video");
95  SetPlaying(false);
96  return false;
97  }
98 
99  ClearAfterSeek();
100 
101  int save_timeout = 1001;
102  MythTimer flagTime;
103  MythTimer ui_timer;
104  MythTimer inuse_timer;
105  MythTimer save_timer;
106  flagTime.start();
107  ui_timer.start();
108  inuse_timer.start();
109  save_timer.start();
110 
111  m_decoder->TrackTotalDuration(true);
112 
113  if (showPercentage)
114  cout << "\r \r" << flush;
115 
116  int prevperc = -1;
117  bool usingIframes = false;
118  while (GetEof() == kEofStateNone)
119  {
120  if (inuse_timer.elapsed() > 2534)
121  {
122  inuse_timer.restart();
123  m_playerCtx->LockPlayingInfo(__FILE__, __LINE__);
124  if (m_playerCtx->m_playingInfo)
125  m_playerCtx->m_playingInfo->UpdateInUseMark();
126  m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
127  }
128 
129  if (save_timer.elapsed() > save_timeout)
130  {
131  // Give DB some breathing room if it gets far behind..
132  if (myFramesPlayed - pmap_last > 5000)
133  usleep(200 * 1000);
134 
135  // If we're already saving, just save a larger block next time..
136  if (RebuildSaver::GetCount(m_decoder) < 1)
137  {
138  pmap_last = myFramesPlayed;
140  new RebuildSaver(m_decoder, pmap_first, pmap_last),
141  "RebuildSaver");
142  pmap_first = pmap_last + 1;
143  }
144 
145  save_timer.restart();
146  }
147 
148  if (ui_timer.elapsed() > 98)
149  {
150  ui_timer.restart();
151 
152  if (m_totalFrames)
153  {
154  float elapsed = flagTime.elapsed() * 0.001F;
155  int flagFPS = (elapsed > 0.0F) ?
156  (int)(myFramesPlayed / elapsed) : 0;
157 
158  int percentage = myFramesPlayed * 100 / m_totalFrames;
159  if (cb)
160  (*cb)(percentage, cbData);
161 
162  if (showPercentage)
163  {
164  QString str = QString("\r%1%/%2fps \r")
165  .arg(percentage,3).arg(flagFPS,5);
166  cout << qPrintable(str) << flush;
167  }
168  else if (percentage % 10 == 0 && prevperc != percentage)
169  {
170  prevperc = percentage;
171  LOG(VB_COMMFLAG, LOG_INFO, QString("Progress %1% @ %2fps")
172  .arg(percentage,3).arg(flagFPS,5));
173  }
174  }
175  else
176  {
177  if (showPercentage)
178  {
179  QString str = QString("\r%1 \r").arg(myFramesPlayed,6);
180  cout << qPrintable(str) << flush;
181  }
182  else if (myFramesPlayed % 1000 == 0)
183  {
184  LOG(VB_COMMFLAG, LOG_INFO, QString("Frames processed %1")
185  .arg(myFramesPlayed));
186  }
187  }
188  }
189 
190  if (DecoderGetFrame(kDecodeNothing,true))
191  myFramesPlayed = m_decoder->GetFramesRead();
192 
193  // H.264 recordings from an HD-PVR contain IDR keyframes,
194  // which are the only valid cut points for lossless cuts.
195  // However, DVB-S h.264 recordings may lack IDR keyframes, in
196  // which case we need to allow non-IDR I-frames. If we get
197  // far enough into the rebuild without having created any
198  // seektable entries, we can assume it is because of the IDR
199  // keyframe setting, and so we rewind and allow h.264 non-IDR
200  // I-frames to be treated as keyframes.
201  uint64_t frames = m_decoder->GetFramesRead();
202  if (!usingIframes &&
203  (GetEof() != kEofStateNone || (frames > 1000 && frames < 1100)) &&
204  !m_decoder->HasPositionMap())
205  {
206  cout << "No I-frames found, rewinding..." << endl;
207  m_decoder->DoRewind(0);
208  m_decoder->Reset(true, true, true);
209  pmap_first = pmap_last = myFramesPlayed = 0;
210  m_decoder->SetIdrOnlyKeyframes(false);
211  usingIframes = true;
212  }
213  }
214 
215  if (showPercentage)
216  cout << "\r \r" << flush;
217 
218  SaveTotalDuration();
219  SaveTotalFrames();
220 
221  SetPlaying(false);
222  m_killDecoder = true;
223 
225  new RebuildSaver(m_decoder, pmap_first, myFramesPlayed),
226  "RebuildSaver");
227  RebuildSaver::Wait(m_decoder);
228 
229  return true;
230 }
int restart(void)
Returns milliseconds elapsed since last start() or restart() and resets the count.
Definition: mythtimer.cpp:62
RebuildSaver(DecoderBase *d, uint64_t f, uint64_t l)
A QElapsedTimer based timer to replace use of QTime as a timer.
Definition: mythtimer.h:13
void(*)(int, void *) StatusCallback
Definition: mythplayer.h:57
DecoderBase * m_decoder
static QMap< DecoderBase *, uint > s_cnt
struct exc__state * m_last
Definition: pxsup2dast.c:94
bool RebuildSeekTable(bool showPercentage=true, StatusCallback cb=nullptr, void *cbData=nullptr)
static const uint16_t * d
unsigned int uint
Definition: compat.h:140
static QWaitCondition s_wait
static void Wait(DecoderBase *d)
static MThreadPool * globalInstance(void)
static uint GetCount(DecoderBase *d)
void start(QRunnable *runnable, const QString &debugName, int priority=0)
static QMutex s_lock
int elapsed(void)
Returns milliseconds elapsed since last start() or restart()
Definition: mythtimer.cpp:90
void run(void) override
void start(void)
starts measuring elapsed time.
Definition: mythtimer.cpp:47
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23