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