MythTV master
PrePostRollFlagger.cpp
Go to the documentation of this file.
1#include <algorithm>
2#include <thread> // for sleep_for
3
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
90 {
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
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
213long 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};
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) &&
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
287 std::this_thread::sleep_for(10ms);
288
289 if (((currentFrameNumber % 500) == 0) ||
291 ((currentFrameNumber % 100) == 0)))
292 {
293 float elapsed = flagTime.elapsed() / 1000.0F;
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
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}
@ COMM_FRAME_BLANK
@ COMM_FRAME_SCENE_CHANGE
QMap< long long, FrameInfoEntry > m_frameInfo
void ProcessFrame(MythVideoFrame *frame, long long frame_number)
void SetVideoParams(float aspect)
MythCommFlagPlayer * m_player
void statusUpdate(const QString &a)
void gotNewCommercialBreakList()
MythVideoFrame * GetRawVideoFrame(long long FrameNumber=-1)
Returns a specific frame from the video.
bool GetBoolSetting(const QString &key, bool defaultval=false)
uint64_t GetTotalFrameCount(void) const
Definition: mythplayer.h:142
virtual int OpenFile(int Retries=4)
Definition: mythplayer.cpp:417
float GetVideoAspect(void) const
Definition: mythplayer.h:132
EofState GetEof(void) const
float GetFrameRate(void) const
Definition: mythplayer.h:133
void DiscardVideoFrame(MythVideoFrame *buffer)
Places frame in the available frames queue.
Definition: mythplayer.cpp:626
virtual bool InitVideo(void)
Definition: mythplayer.cpp:270
long long m_frameNumber
Definition: mythframe.h:128
float m_aspect
Definition: mythframe.h:126
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)
void GetCommercialBreakList(frm_dir_map_t &marks) override
long long findBreakInrange(long long startFrame, long long stopFrame, long long totalFrames, long long &framesProcessed, QElapsedTimer &flagTime, bool findLast)
@ kEofStateNone
Definition: decoderbase.h:69
static guint32 * tmp
Definition: goom_core.cpp:26
std::chrono::duration< double, std::micro > floatusecs
Definition: mythchrono.h:41
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:15
@ MARK_COMM_END
Definition: programtypes.h:59
@ MARK_COMM_START
Definition: programtypes.h:58
SkipType
This is used as a bitmask.
Definition: programtypes.h:127
QMap< uint64_t, MarkTypes > frm_dir_map_t
Frame # -> Mark map.
Definition: programtypes.h:117