MythTV  master
PrePostRollFlagger.cpp
Go to the documentation of this file.
1 #include <algorithm>
2 #include <thread> // for sleep_for
3 
4 #include "PrePostRollFlagger.h"
5 
6 // Qt headers
7 #include <QCoreApplication>
8 
9 // MythTV headers
14 
16  bool showProgress, bool fullSpeed,
17  MythCommFlagPlayer *player,
18  const QDateTime& startedAt_in,
19  const QDateTime& stopsAt_in,
20  const QDateTime& recordingStartedAt_in,
21  const QDateTime& recordingStopsAt_in):
22  ClassicCommDetector( commDetectMethod, showProgress, fullSpeed,
23  player, startedAt_in, stopsAt_in,
24  recordingStartedAt_in, recordingStopsAt_in)
25 {
26 }
27 
29 {
31 }
32 
34 {
35  int secsSince = 0;
36  int requiredBuffer = 120;
37  int requiredHeadStart = requiredBuffer;
38  bool wereRecording = m_stillRecording;
39 
40  secsSince = m_startedAt.secsTo(MythDate::current());
41  while (m_stillRecording && (secsSince < requiredHeadStart))
42  {
43  emit statusUpdate(QCoreApplication::translate("(mythcommflag)",
44  "Waiting to pass preroll + head start"));
45 
46  emit breathe();
47  if (m_bStop)
48  return false;
49 
50  std::this_thread::sleep_for(5s);
51  secsSince = m_startedAt.secsTo(MythDate::current());
52  }
53 
54  if (m_player->OpenFile() < 0)
55  return false;
56 
57  Init();
58 
59 
60  // Don't bother flagging short ~realtime recordings
61  if ((wereRecording) && (!m_stillRecording) && (secsSince < requiredHeadStart))
62  return false;
63 
65  gCoreContext->GetBoolSetting("AggressiveCommDetect", true);
66 
67  if (!m_player->InitVideo())
68  {
69  LOG(VB_GENERAL, LOG_ERR,
70  "NVP: Unable to initialize video for FlagCommercials.");
71  return false;
72  }
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  std::cerr << " 0%/ ";
93  else
94  std::cerr << " 0/ ";
95  std::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(5s);
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  std::cerr << "\b\b\b\b\b\b \b\b\b\b\b\b";
203  else
204  std::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  std::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  MythVideoFrame* f = m_player->GetRawVideoFrame(tmpStartFrame);
231  float aspect = m_player->GetVideoAspect();
232  long long currentFrameNumber = f->m_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  std::chrono::microseconds startTime {0us};
242  if (m_stillRecording)
243  startTime = nowAsDuration<std::chrono::microseconds>();
244 
245  MythVideoFrame* currentFrame = m_player->GetRawVideoFrame();
246  currentFrameNumber = currentFrame->m_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->m_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(1s);
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(10ms);
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 != 0.0F)
297  flagFPS = framesProcessed / elapsed;
298 
299  int percentage = 0;
300  if (stopFrame)
301  percentage = framesProcessed * 100 / totalFrames;
302  percentage = std::min(percentage, 100);
303 
304  if (m_showProgress)
305  {
306  if (stopFrame)
307  {
308  QString tmp = QString("\b\b\b\b\b\b\b\b\b\b\b%1%/%2fps")
309  .arg(percentage, 3).arg((int)flagFPS, 3);
310  QByteArray ba = tmp.toLatin1();
311  std::cerr << ba.constData() << std::flush;
312  }
313  else
314  {
315  QString tmp = QString("\b\b\b\b\b\b\b\b\b\b\b\b\b%1/%2fps")
316  .arg(currentFrameNumber, 6).arg((int)flagFPS, 3);
317  QByteArray ba = tmp.toLatin1();
318  std::cerr << ba.constData() << std::flush;
319  }
320  std::cerr.flush();
321  }
322 
323  if (stopFrame)
324  {
325  emit statusUpdate(QCoreApplication::translate("(mythcommflag)",
326  "%1% Completed @ %2 fps.")
327  .arg(percentage).arg(flagFPS));
328  }
329  else
330  {
331  emit statusUpdate(QCoreApplication::translate("(mythcommflag)",
332  "%1 Frames Completed @ %2 fps.")
333  .arg((long)currentFrameNumber).arg(flagFPS));
334  }
335 
336  if (percentage % 10 == 0 && prevpercent != percentage)
337  {
338  prevpercent = percentage;
339  LOG(VB_GENERAL, LOG_INFO, QString("%1%% Completed @ %2 fps.")
340  .arg(percentage) .arg(flagFPS));
341  }
342  }
343 
344  ProcessFrame(currentFrame, currentFrameNumber);
345 
346  if (m_frameInfo[currentFrameNumber].flagMask &
348  {
349  foundFrame = currentFrameNumber;
350  }
351 
352  if (m_stillRecording)
353  {
354  int secondsRecorded =
356  int secondsFlagged = (int)(framesProcessed / m_fps);
357  int secondsBehind = secondsRecorded - secondsFlagged;
358  auto usecPerFrame = floatusecs(1000000.0F / m_player->GetFrameRate());
359 
360  auto endTime = nowAsDuration<std::chrono::microseconds>();
361 
362  floatusecs usecSleep = usecPerFrame - (endTime - startTime);
363 
364  if (secondsBehind > requiredBuffer)
365  {
366  if (m_fullSpeed)
367  usecSleep = 0us;
368  else
369  usecSleep = usecSleep * 0.25;
370  }
371  else if (secondsBehind < requiredBuffer)
372  {
373  usecSleep = usecPerFrame * 1.5;
374  }
375 
376  if (usecSleep > 0us)
377  std::this_thread::sleep_for(usecSleep);
378  }
379 
380  m_player->DiscardVideoFrame(currentFrame);
381  framesProcessed++;
382  }
383  return foundFrame;
384 }
385 
386 
388 {
389  LOG(VB_COMMFLAG, LOG_INFO, "PrePostRollFlagger::GetCommBreakMap()");
390  marks.clear();
391 
392  long long end = 0;
394  {
395  //choose closest
397  end = m_closestAfterPre;
398  else
399  end = m_closestBeforePre;
400  }
401  else if(m_closestBeforePre)
402  {
403  end = m_closestBeforePre;
404  }
405  else if(m_closestAfterPre)
406  {
407  end = m_closestAfterPre;
408  }
409  else
410  {
411  end = m_preRoll;
412  }
413 
414  if(end)
415  {
416  marks[0] = MARK_COMM_START;
417  marks[end] = MARK_COMM_END;
418  }
419 
420  long long start = 0;
422  {
423  //choose closest
425  start = m_closestAfterPost;
426  else
427  start = m_closestBeforePost;
428  }
429  else if(m_closestBeforePost)
430  {
431  start = m_closestBeforePost;
432  }
433  else if(m_closestAfterPost)
434  {
435  start = m_closestAfterPost;
436  }
437  else if(m_postRoll)
438  {
439  start = m_myTotalFrames - m_postRoll;
440  }
441 
442  if(start)
443  {
444  marks[start] = MARK_COMM_START;
446  }
447 }
MARK_COMM_END
@ MARK_COMM_END
Definition: programtypes.h:59
MythPlayer::GetTotalFrameCount
uint64_t GetTotalFrameCount(void) const
Definition: mythplayer.h:142
PrePostRollFlagger::PrePostRollFlagger
PrePostRollFlagger(SkipType commDetectMethod, bool showProgress, bool fullSpeed, MythCommFlagPlayer *player, const QDateTime &startedAt_in, const QDateTime &stopsAt_in, const QDateTime &recordingStartedAt_in, const QDateTime &recordingStopsAt_in)
Definition: PrePostRollFlagger.cpp:15
CommDetectorBase::m_bPaused
bool m_bPaused
Definition: CommDetectorBase.h:52
ClassicCommDetector::m_recordingStartedAt
QDateTime m_recordingStartedAt
Definition: ClassicCommDetector.h:191
CommDetectorBase::breathe
void breathe()
PrePostRollFlagger.h
ClassicCommDetector::m_recordingStopsAt
QDateTime m_recordingStopsAt
Definition: ClassicCommDetector.h:192
mythcommflagplayer.h
MythPlayer::OpenFile
virtual int OpenFile(int Retries=4)
Definition: mythplayer.cpp:417
CommDetectorBase::gotNewCommercialBreakList
void gotNewCommercialBreakList()
ClassicCommDetector::ProcessFrame
void ProcessFrame(MythVideoFrame *frame, long long frame_number)
Definition: ClassicCommDetector.cpp:747
CommDetectorBase::statusUpdate
void statusUpdate(const QString &a)
frm_dir_map_t
QMap< uint64_t, MarkTypes > frm_dir_map_t
Frame # -> Mark map.
Definition: programtypes.h:117
MythPlayer::GetFrameRate
float GetFrameRate(void) const
Definition: mythplayer.h:133
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MythPlayer::GetEof
EofState GetEof(void) const
Definition: mythplayer.cpp:1064
PrePostRollFlagger::m_closestAfterPost
long long m_closestAfterPost
Definition: PrePostRollFlagger.h:24
PrePostRollFlagger::m_closestAfterPre
long long m_closestAfterPre
Definition: PrePostRollFlagger.h:22
PrePostRollFlagger::findBreakInrange
long long findBreakInrange(long long startFrame, long long stopFrame, long long totalFrames, long long &framesProcessed, QElapsedTimer &flagTime, bool findLast)
Definition: PrePostRollFlagger.cpp:213
ClassicCommDetector::Init
void Init()
Definition: ClassicCommDetector.cpp:164
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:15
tmp
static guint32 * tmp
Definition: goom_core.cpp:26
ClassicCommDetector::m_stillRecording
bool m_stillRecording
Definition: ClassicCommDetector.h:194
kEofStateNone
@ kEofStateNone
Definition: decoderbase.h:69
programinfo.h
mythlogging.h
PrePostRollFlagger::GetCommercialBreakList
void GetCommercialBreakList(frm_dir_map_t &marks) override
Definition: PrePostRollFlagger.cpp:387
ClassicCommDetector::m_frameInfo
QMap< long long, FrameInfoEntry > m_frameInfo
Definition: ClassicCommDetector.h:206
MythPlayer::InitVideo
virtual bool InitVideo(void)
Definition: mythplayer.cpp:270
MythVideoFrame::m_frameNumber
long long m_frameNumber
Definition: mythframe.h:128
ClassicCommDetector::m_preRoll
long long m_preRoll
Definition: ClassicCommDetector.h:199
MythCommFlagPlayer
Definition: mythcommflagplayer.h:25
hardwareprofile.smolt.long
long
Definition: smolt.py:74
ClassicCommDetector::m_fullSpeed
bool m_fullSpeed
Definition: ClassicCommDetector.h:195
ClassicCommDetector
Definition: ClassicCommDetector.h:47
PrePostRollFlagger::m_closestBeforePre
long long m_closestBeforePre
Definition: PrePostRollFlagger.h:23
floatusecs
std::chrono::duration< double, std::micro > floatusecs
Definition: mythchrono.h:41
MARK_COMM_START
@ MARK_COMM_START
Definition: programtypes.h:58
ClassicCommDetector::SetVideoParams
void SetVideoParams(float aspect)
Definition: ClassicCommDetector.cpp:709
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:57
CommDetectorBase::m_bStop
bool m_bStop
Definition: CommDetectorBase.h:53
SkipType
SkipType
This is used as a bitmask.
Definition: programtypes.h:127
MythCoreContext::GetBoolSetting
bool GetBoolSetting(const QString &key, bool defaultval=false)
Definition: mythcorecontext.cpp:912
PrePostRollFlagger::m_myTotalFrames
long long m_myTotalFrames
Definition: PrePostRollFlagger.h:21
ClassicCommDetector::m_fps
double m_fps
Definition: ClassicCommDetector.h:197
mythcorecontext.h
MythPlayer::GetVideoAspect
float GetVideoAspect(void) const
Definition: mythplayer.h:132
ClassicCommDetector::m_aggressiveDetection
bool m_aggressiveDetection
Definition: ClassicCommDetector.h:193
PrePostRollFlagger::m_closestBeforePost
long long m_closestBeforePost
Definition: PrePostRollFlagger.h:25
MythVideoFrame
Definition: mythframe.h:87
COMM_FRAME_BLANK
@ COMM_FRAME_BLANK
Definition: ClassicCommDetector.h:26
PrePostRollFlagger::Init
void Init()
Definition: PrePostRollFlagger.cpp:28
ClassicCommDetector::m_postRoll
long long m_postRoll
Definition: ClassicCommDetector.h:200
COMM_FRAME_SCENE_CHANGE
@ COMM_FRAME_SCENE_CHANGE
Definition: ClassicCommDetector.h:27
PrePostRollFlagger::go
bool go() override
Definition: PrePostRollFlagger.cpp:33
ClassicCommDetector::m_showProgress
bool m_showProgress
Definition: ClassicCommDetector.h:196
MythVideoFrame::m_aspect
float m_aspect
Definition: mythframe.h:126
MythCommFlagPlayer::GetRawVideoFrame
MythVideoFrame * GetRawVideoFrame(long long FrameNumber=-1)
Returns a specific frame from the video.
Definition: mythcommflagplayer.cpp:226
ClassicCommDetector::m_startedAt
QDateTime m_startedAt
Definition: ClassicCommDetector.h:189
ClassicCommDetector::m_player
MythCommFlagPlayer * m_player
Definition: ClassicCommDetector.h:188
MythPlayer::DiscardVideoFrame
void DiscardVideoFrame(MythVideoFrame *buffer)
Places frame in the available frames queue.
Definition: mythplayer.cpp:626