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