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  int percentage = 0;
69  uint64_t myFramesPlayed = 0, pmap_first = 0, pmap_last = 0;
70 
71  killdecoder = false;
72  framesPlayed = 0;
73 
74  // clear out any existing seektables
75  player_ctx->LockPlayingInfo(__FILE__, __LINE__);
76  if (player_ctx->playingInfo)
77  {
78  player_ctx->playingInfo->ClearPositionMap(MARK_KEYFRAME);
79  player_ctx->playingInfo->ClearPositionMap(MARK_GOP_START);
80  player_ctx->playingInfo->ClearPositionMap(MARK_GOP_BYFRAME);
81  player_ctx->playingInfo->ClearPositionMap(MARK_DURATION_MS);
82  }
83  player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
84 
85  if (OpenFile() < 0)
86  return false;
87 
88  SetPlaying(true);
89 
90  if (!InitVideo())
91  {
92  LOG(VB_GENERAL, LOG_ERR,
93  "RebuildSeekTable unable to initialize video");
94  SetPlaying(false);
95  return false;
96  }
97 
98  ClearAfterSeek();
99 
100  int save_timeout = 1001;
101  MythTimer flagTime, ui_timer, inuse_timer, save_timer;
102  flagTime.start();
103  ui_timer.start();
104  inuse_timer.start();
105  save_timer.start();
106 
107  decoder->TrackTotalDuration(true);
108 
109  if (showPercentage)
110  cout << "\r \r" << flush;
111 
112  int prevperc = -1;
113  bool usingIframes = false;
114  while (GetEof() == kEofStateNone)
115  {
116  if (inuse_timer.elapsed() > 2534)
117  {
118  inuse_timer.restart();
119  player_ctx->LockPlayingInfo(__FILE__, __LINE__);
120  if (player_ctx->playingInfo)
121  player_ctx->playingInfo->UpdateInUseMark();
122  player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
123  }
124 
125  if (save_timer.elapsed() > save_timeout)
126  {
127  // Give DB some breathing room if it gets far behind..
128  if (myFramesPlayed - pmap_last > 5000)
129  usleep(200 * 1000);
130 
131  // If we're already saving, just save a larger block next time..
132  if (RebuildSaver::GetCount(decoder) < 1)
133  {
134  pmap_last = myFramesPlayed;
136  new RebuildSaver(decoder, pmap_first, pmap_last),
137  "RebuildSaver");
138  pmap_first = pmap_last + 1;
139  }
140 
141  save_timer.restart();
142  }
143 
144  if (ui_timer.elapsed() > 98)
145  {
146  ui_timer.restart();
147 
148  if (totalFrames)
149  {
150  float elapsed = flagTime.elapsed() * 0.001f;
151  int flagFPS = (elapsed > 0.0f) ?
152  (int)(myFramesPlayed / elapsed) : 0;
153 
154  percentage = myFramesPlayed * 100 / totalFrames;
155  if (cb)
156  (*cb)(percentage, cbData);
157 
158  if (showPercentage)
159  {
160  QString str = QString("\r%1%/%2fps \r")
161  .arg(percentage,3).arg(flagFPS,5);
162  cout << qPrintable(str) << flush;
163  }
164  else if (percentage % 10 == 0 && prevperc != percentage)
165  {
166  prevperc = percentage;
167  LOG(VB_COMMFLAG, LOG_INFO, QString("Progress %1% @ %2fps")
168  .arg(percentage,3).arg(flagFPS,5));
169  }
170  }
171  else
172  {
173  if (showPercentage)
174  {
175  QString str = QString("\r%1 \r").arg(myFramesPlayed,6);
176  cout << qPrintable(str) << flush;
177  }
178  else if (myFramesPlayed % 1000 == 0)
179  {
180  LOG(VB_COMMFLAG, LOG_INFO, QString("Frames processed %1")
181  .arg(myFramesPlayed));
182  }
183  }
184  }
185 
186  if (DecoderGetFrame(kDecodeNothing,true))
187  myFramesPlayed = decoder->GetFramesRead();
188 
189  // H.264 recordings from an HD-PVR contain IDR keyframes,
190  // which are the only valid cut points for lossless cuts.
191  // However, DVB-S h.264 recordings may lack IDR keyframes, in
192  // which case we need to allow non-IDR I-frames. If we get
193  // far enough into the rebuild without having created any
194  // seektable entries, we can assume it is because of the IDR
195  // keyframe setting, and so we rewind and allow h.264 non-IDR
196  // I-frames to be treated as keyframes.
197  uint64_t frames = decoder->GetFramesRead();
198  if (!usingIframes &&
199  (GetEof() != kEofStateNone || (frames > 1000 && frames < 1100)) &&
200  !decoder->HasPositionMap())
201  {
202  cout << "No I-frames found, rewinding..." << endl;
203  decoder->DoRewind(0);
204  decoder->Reset(true, true, true);
205  pmap_first = pmap_last = myFramesPlayed = 0;
206  decoder->SetIdrOnlyKeyframes(false);
207  usingIframes = true;
208  }
209  }
210 
211  if (showPercentage)
212  cout << "\r \r" << flush;
213 
214  SaveTotalDuration();
215  SaveTotalFrames();
216 
217  SetPlaying(false);
218  killdecoder = true;
219 
221  new RebuildSaver(decoder, pmap_first, myFramesPlayed),
222  "RebuildSaver");
223  RebuildSaver::Wait(decoder);
224 
225  return true;
226 }
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 start(QRunnable *runnable, QString debugName, int priority=0)
DecoderBase * m_decoder
unsigned int uint
Definition: compat.h:140
static QMap< DecoderBase *, uint > s_cnt
bool RebuildSeekTable(bool showPercentage=true, StatusCallback cb=nullptr, void *cbData=nullptr)
static const uint16_t * d
void(* StatusCallback)(int, void *)
Definition: mythplayer.h:58
static QWaitCondition s_wait
static void Wait(DecoderBase *d)
int elapsed(void) const
Returns milliseconds elapsed since last start() or restart()
Definition: mythtimer.cpp:90
static MThreadPool * globalInstance(void)
static uint GetCount(DecoderBase *d)
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
static QMutex s_lock
const char * frames[3]
Definition: element.c:46
void run(void) override
void start(void)
starts measuring elapsed time.
Definition: mythtimer.cpp:47