MythTV  master
PrePostRollFlagger.cpp
Go to the documentation of this file.
1 #include <chrono> // for milliseconds
2 #include <thread> // for sleep_for
3 
4 #include "PrePostRollFlagger.h"
5 
6 // Qt headers
7 #include <QCoreApplication>
8 
9 // MythTV headers
10 #include "mythcorecontext.h"
11 #include "programinfo.h"
12 #include "mythplayer.h"
13 
15  bool showProgress,bool fullSpeed,
16  MythPlayer* player,
17  const QDateTime& startedAt_in,
18  const QDateTime& stopsAt_in,
19  const QDateTime& recordingStartedAt_in,
20  const QDateTime& recordingStopsAt_in):
21  ClassicCommDetector( commDetectMethod, showProgress, fullSpeed,
22  player, startedAt_in, stopsAt_in,
23  recordingStartedAt_in, recordingStopsAt_in)
24 {
25 }
26 
28 {
30 }
31 
33 {
34  int secsSince = 0;
35  int requiredBuffer = 120;
36  int requiredHeadStart = requiredBuffer;
37  bool wereRecording = m_stillRecording;
38 
39  secsSince = m_startedAt.secsTo(MythDate::current());
40  while (m_stillRecording && (secsSince < requiredHeadStart))
41  {
42  emit statusUpdate(QCoreApplication::translate("(mythcommflag)",
43  "Waiting to pass preroll + head start"));
44 
45  emit breathe();
46  if (m_bStop)
47  return false;
48 
49  std::this_thread::sleep_for(std::chrono::seconds(5));
50  secsSince = m_startedAt.secsTo(MythDate::current());
51  }
52 
53  if (m_player->OpenFile() < 0)
54  return false;
55 
56  Init();
57 
58 
59  // Don't bother flagging short ~realtime recordings
60  if ((wereRecording) && (!m_stillRecording) && (secsSince < requiredHeadStart))
61  return false;
62 
64  gCoreContext->GetBoolSetting("AggressiveCommDetect", true);
65 
66  if (!m_player->InitVideo())
67  {
68  LOG(VB_GENERAL, LOG_ERR,
69  "NVP: Unable to initialize video for FlagCommercials.");
70  return false;
71  }
72  m_player->EnableSubtitles(false);
73 
74  emit breathe();
75  if (m_bStop)
76  return false;
77 
78  QElapsedTimer flagTime;
79  flagTime.start();
80 
83  else
86 
87 
88 
89  if (m_showProgress)
90  {
91  if (m_myTotalFrames)
92  cerr << " 0%/ ";
93  else
94  cerr << " 0/ ";
95  cerr.flush();
96  }
97 
98  float aspect = m_player->GetVideoAspect();
99 
100  SetVideoParams(aspect);
101 
102  emit breathe();
103 
104  long long stopFrame = m_preRoll + m_fps * 120; //look up to 2 minutes past
105  long long framesToProcess = 0;
106  if(m_preRoll)
107  framesToProcess += stopFrame;
108  if(m_postRoll)
109  //guess two minutes before
110  framesToProcess += m_myTotalFrames - m_postRoll + m_fps * 120;
111 
112 
113  long long framesProcessed = 0;
114  if(m_preRoll > 0)
115  {
116  //check from preroll after
117  LOG(VB_COMMFLAG, LOG_INFO,
118  QString("Finding closest after preroll(%1-%2)")
119  .arg(m_preRoll).arg(stopFrame));
120 
121  m_closestAfterPre = findBreakInrange(m_preRoll, stopFrame, framesToProcess,
122  framesProcessed, flagTime, false);
123 
124  LOG(VB_COMMFLAG, LOG_INFO, QString("Closest after preroll: %1")
125  .arg(m_closestAfterPre));
126 
127 
128  //check before preroll
129  long long startFrame = 0;
131  startFrame = m_preRoll - (m_closestAfterPre - m_preRoll) - 1;
132 
133  LOG(VB_COMMFLAG, LOG_INFO, QString("Finding before preroll (%1-%2)")
134  .arg(startFrame).arg(m_preRoll));
136  framesToProcess, framesProcessed,
137  flagTime, true);
138  LOG(VB_COMMFLAG, LOG_INFO, QString("Closest before preroll: %1")
139  .arg(m_closestBeforePre));
140 
143 
144  // for better processing percent
145  framesToProcess -= (stopFrame - framesProcessed);
146 
147  }
148 
149  if(m_stillRecording)
150  {
152  {
153  emit breathe();
154  if (m_bStop)
155  return false;
156  emit statusUpdate(QCoreApplication::translate("(mythcommflag)",
157  "Waiting for recording to finish"));
158  std::this_thread::sleep_for(std::chrono::seconds(5));
159  }
160  m_stillRecording = false;
162  }
163 
164  if(m_postRoll > 0)
165  {
166  //check from preroll after
167  long long postRollStartLoc = m_myTotalFrames - m_postRoll;
168  LOG(VB_COMMFLAG, LOG_INFO,
169  QString("Finding closest after postroll(%1-%2)")
170  .arg(postRollStartLoc).arg(m_myTotalFrames));
172  framesToProcess, framesProcessed,
173  flagTime, false);
174  LOG(VB_COMMFLAG, LOG_INFO, QString("Closest after postRoll: %1")
175  .arg(m_closestAfterPost));
176 
177  //check before preroll
178  long long startFrame = 0;
180  startFrame = postRollStartLoc
181  - (m_closestAfterPost - postRollStartLoc) - 1;
182 
183  LOG(VB_COMMFLAG, LOG_INFO,
184  QString("finding closest before preroll(%1-%2)")
185  .arg(startFrame).arg(postRollStartLoc));
186  m_closestBeforePost = findBreakInrange(startFrame, postRollStartLoc,
187  framesToProcess, framesProcessed,
188  flagTime, true);
189  LOG(VB_COMMFLAG, LOG_INFO, QString("Closest before postroll: %1")
190  .arg(m_closestBeforePost));
191 
192 // framesToProcess = framesProcessed;
193  }
194 
195  if (m_showProgress)
196  {
197  //float elapsed = flagTime.elapsed() / 1000.0;
198 
199  //float flagFPS = (elapsed > 0.0F) ? (framesProcessed / elapsed) : 0.0F;
200 
201  if (m_myTotalFrames)
202  cerr << "\b\b\b\b\b\b \b\b\b\b\b\b";
203  else
204  cerr << "\b\b\b\b\b\b\b\b\b\b\b\b\b "
205  "\b\b\b\b\b\b\b\b\b\b\b\b\b";
206  cerr.flush();
207  }
208 
209  return true;
210 }
211 
212 
213 long long PrePostRollFlagger::findBreakInrange(long long startFrame,
214  long long stopFrame,
215  long long totalFrames,
216  long long &framesProcessed,
217  QElapsedTimer&flagTime, bool findLast)
218 {
219  int requiredBuffer = 30;
220  int prevpercent = -1;
221 
222  if(startFrame > 0)
223  startFrame--;
224  else
225  startFrame = 0;
226 
228 
229  long long tmpStartFrame = startFrame;
230  VideoFrame* f = m_player->GetRawVideoFrame(tmpStartFrame);
231  float aspect = m_player->GetVideoAspect();
232  long long currentFrameNumber = f->frameNumber;
233  LOG(VB_COMMFLAG, LOG_INFO, QString("Starting with frame %1")
234  .arg(currentFrameNumber));
236 
237  long long foundFrame = 0;
238 
239  while (m_player->GetEof() == kEofStateNone)
240  {
241  struct timeval startTime {};
242  if (m_stillRecording)
243  gettimeofday(&startTime, nullptr);
244 
245  VideoFrame* currentFrame = m_player->GetRawVideoFrame();
246  currentFrameNumber = currentFrame->frameNumber;
247 
248  if(currentFrameNumber % 1000 == 0)
249  {
250  LOG(VB_COMMFLAG, LOG_INFO, QString("Processing frame %1")
251  .arg(currentFrameNumber));
252  }
253 
254  if(currentFrameNumber > stopFrame || (!findLast && foundFrame))
255  {
256  m_player->DiscardVideoFrame(currentFrame);
257  break;
258  }
259 
260  float newAspect = currentFrame->aspect;
261  if (newAspect != aspect)
262  {
263  SetVideoParams(aspect);
264  aspect = newAspect;
265  }
266 
267  if (((currentFrameNumber % 500) == 0) ||
268  (((currentFrameNumber % 100) == 0) &&
269  (m_stillRecording)))
270  {
271  emit breathe();
272  if (m_bStop)
273  {
274  m_player->DiscardVideoFrame(currentFrame);
275  return 0;
276  }
277  }
278 
279  while (m_bPaused)
280  {
281  emit breathe();
282  std::this_thread::sleep_for(std::chrono::seconds(1));
283  }
284 
285  // sleep a little so we don't use all cpu even if we're niced
286  if (!m_fullSpeed && !m_stillRecording)
287  std::this_thread::sleep_for(std::chrono::milliseconds(10));
288 
289  if (((currentFrameNumber % 500) == 0) ||
291  ((currentFrameNumber % 100) == 0)))
292  {
293  float elapsed = flagTime.elapsed() / 1000.0;
294 
295  float flagFPS = 0.0F;
296  if (elapsed)
297  flagFPS = framesProcessed / elapsed;
298 
299  int percentage = 0;
300  if (stopFrame)
301  percentage = framesProcessed * 100 / totalFrames;
302  if (percentage > 100)
303  percentage = 100;
304 
305  if (m_showProgress)
306  {
307  if (stopFrame)
308  {
309  QString tmp = QString("\b\b\b\b\b\b\b\b\b\b\b%1%/%2fps")
310  .arg(percentage, 3).arg((int)flagFPS, 3);
311  QByteArray ba = tmp.toLatin1();
312  cerr << ba.constData() << flush;
313  }
314  else
315  {
316  QString tmp = QString("\b\b\b\b\b\b\b\b\b\b\b\b\b%1/%2fps")
317  .arg(currentFrameNumber, 6).arg((int)flagFPS, 3);
318  QByteArray ba = tmp.toLatin1();
319  cerr << ba.constData() << flush;
320  }
321  cerr.flush();
322  }
323 
324  if (stopFrame)
325  {
326  emit statusUpdate(QCoreApplication::translate("(mythcommflag)",
327  "%1% Completed @ %2 fps.")
328  .arg(percentage).arg(flagFPS));
329  }
330  else
331  {
332  emit statusUpdate(QCoreApplication::translate("(mythcommflag)",
333  "%1 Frames Completed @ %2 fps.")
334  .arg((long)currentFrameNumber).arg(flagFPS));
335  }
336 
337  if (percentage % 10 == 0 && prevpercent != percentage)
338  {
339  prevpercent = percentage;
340  LOG(VB_GENERAL, LOG_INFO, QString("%1%% Completed @ %2 fps.")
341  .arg(percentage) .arg(flagFPS));
342  }
343  }
344 
345  ProcessFrame(currentFrame, currentFrameNumber);
346 
347  if (m_frameInfo[currentFrameNumber].flagMask &
349  {
350  foundFrame = currentFrameNumber;
351  }
352 
353  if (m_stillRecording)
354  {
355  int secondsRecorded =
357  int secondsFlagged = (int)(framesProcessed / m_fps);
358  int secondsBehind = secondsRecorded - secondsFlagged;
359  long usecPerFrame = (long)(1.0F / m_player->GetFrameRate() * 1000000);
360 
361  struct timeval endTime {};
362  gettimeofday(&endTime, nullptr);
363 
364  long long usecSleep =
365  usecPerFrame -
366  (((endTime.tv_sec - startTime.tv_sec) * 1000000) +
367  (endTime.tv_usec - startTime.tv_usec));
368 
369  if (secondsBehind > requiredBuffer)
370  {
371  if (m_fullSpeed)
372  usecSleep = 0;
373  else
374  usecSleep = (long)(usecSleep * 0.25);
375  }
376  else if (secondsBehind < requiredBuffer)
377  usecSleep = (long)(usecPerFrame * 1.5);
378 
379  if (usecSleep > 0)
380  std::this_thread::sleep_for(std::chrono::microseconds(usecSleep));
381  }
382 
383  m_player->DiscardVideoFrame(currentFrame);
384  framesProcessed++;
385  }
386  return foundFrame;
387 }
388 
389 
391 {
392  LOG(VB_COMMFLAG, LOG_INFO, "PrePostRollFlagger::GetCommBreakMap()");
393  marks.clear();
394 
395  long long end = 0;
397  {
398  //choose closest
400  end = m_closestAfterPre;
401  else
402  end = m_closestBeforePre;
403  }
404  else if(m_closestBeforePre)
405  end = m_closestBeforePre;
406  else if(m_closestAfterPre)
407  end = m_closestAfterPre;
408  else
409  end = m_preRoll;
410 
411  if(end)
412  {
413  marks[0] = MARK_COMM_START;
414  marks[end] = MARK_COMM_END;
415  }
416 
417  long long start = 0;
419  {
420  //choose closest
422  start = m_closestAfterPost;
423  else
424  start = m_closestBeforePost;
425  }
426  else if(m_closestBeforePost)
427  start = m_closestBeforePost;
428  else if(m_closestAfterPost)
429  start = m_closestAfterPost;
430  else if(m_postRoll)
431  start = m_myTotalFrames - m_postRoll;
432 
433  if(start)
434  {
435  marks[start] = MARK_COMM_START;
437  }
438 }
float GetVideoAspect(void) const
Definition: mythplayer.h:212
PrePostRollFlagger(SkipType commDetectMethod, bool showProgress, bool fullSpeed, MythPlayer *player, const QDateTime &startedAt_in, const QDateTime &stopsAt_in, const QDateTime &recordingStartedAt_in, const QDateTime &recordingStopsAt_in)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
static guint32 * tmp
Definition: goom_core.c:35
long long findBreakInrange(long long start, long long stopFrame, long long totalFrames, long long &framesProcessed, QElapsedTimer &flagTime, bool findLast)
float aspect
Definition: mythframe.h:143
virtual int OpenFile(int Retries=4)
Definition: mythplayer.cpp:782
SkipType
This is used as a bitmask.
Definition: programtypes.h:91
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
VideoFrame * GetRawVideoFrame(long long frameNumber=-1)
Returns a specific frame from the video.
float GetFrameRate(void) const
Definition: mythplayer.h:213
EofState GetEof(void) const
void ProcessFrame(VideoFrame *frame, long long frame_number)
QMap< long long, FrameInfoEntry > m_frameInfo
static struct mark marks[16]
void GetCommercialBreakList(frm_dir_map_t &marks) override
long long frameNumber
Definition: mythframe.h:147
void statusUpdate(const QString &a)
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
void gotNewCommercialBreakList()
bool GetBoolSetting(const QString &key, bool defaultval=false)
void DiscardVideoFrame(VideoFrame *buffer)
Places frame in the available frames queue.
Definition: mythplayer.cpp:996
void EnableSubtitles(bool enable)
uint64_t GetTotalFrameCount(void) const
Definition: mythplayer.h:230
bool InitVideo(void)
Definition: mythplayer.cpp:364
QMap< uint64_t, MarkTypes > frm_dir_map_t
Frame # -> Mark map.
Definition: programtypes.h:81
void SetVideoParams(float aspect)