MythTV master
CommDetector2.cpp
Go to the documentation of this file.
1// C++ headers
2#include <algorithm>
3#include <cerrno>
4#include <cmath>
5#include <thread> // for sleep_for
6
7// Qt headers
8#include <QCoreApplication>
9#include <QDir>
10#include <QFileInfo>
11
12// MythTV headers
13#include "libmythbase/compat.h"
15#include "libmythbase/mythdb.h"
20
21// Commercial Flagging headers
22#include "BlankFrameDetector.h"
23#include "BorderDetector.h"
24#include "CannyEdgeDetector.h"
25#include "CommDetector2.h"
26#include "FrameAnalyzer.h"
27#include "HistogramAnalyzer.h"
28#include "PGMConverter.h"
29#include "SceneChangeDetector.h"
30#include "TemplateFinder.h"
31#include "TemplateMatcher.h"
32
33namespace {
34
35bool stopForBreath(bool isrecording, long long frameno)
36{
37 return (isrecording && (frameno % 100) == 0) || (frameno % 500) == 0;
38}
39
40bool needToReportState(bool showprogress, bool isrecording, long long frameno)
41{
42 return ((showprogress || isrecording) && (frameno % 100) == 0) ||
43 (frameno % 500) == 0;
44}
45
46void waitForBuffer(std::chrono::microseconds framestart, int minlag, int flaglag,
47 float fps, bool fullspeed)
48{
49 auto usperframe = floatusecs(1000000.0F / fps);
50
51 auto now = nowAsDuration<std::chrono::microseconds>();
52 auto elapsed = (now - framestart);
53
54 // Sleep for one frame's worth of time.
55 auto sleepus = usperframe - duration_cast<floatusecs>(elapsed);
56 if (sleepus <= 0us)
57 return;
58
59 if (flaglag > minlag)
60 {
61 // Try to catch up; reduce sleep time.
62 if (fullspeed)
63 return;
64 sleepus /= 4;
65 }
66 else if (flaglag < minlag)
67 {
68 // Slow down; increase sleep time
69 sleepus = sleepus * 3 / 2;
70 }
71 std::this_thread::sleep_for(sleepus);
72}
73
75 FrameAnalyzerItem &finishedAnalyzers,
76 FrameAnalyzerItem &deadAnalyzers,
77 MythPlayer *player,
78 long long nframes)
79{
80 auto it = pass.begin();
81 while (it != pass.end())
82 {
84 (*it)->MythPlayerInited(player, nframes);
85
86 if ((FrameAnalyzer::ANALYZE_OK == ares) ||
88 {
89 ++it;
90 }
91 else if (FrameAnalyzer::ANALYZE_FINISHED == ares)
92 {
93 finishedAnalyzers.push_back(*it);
94 it = pass.erase(it);
95 }
96 else if (FrameAnalyzer::ANALYZE_FATAL == ares)
97 {
98 deadAnalyzers.push_back(*it);
99 it = pass.erase(it);
100 }
101 else
102 {
103 LOG(VB_GENERAL, LOG_ERR,
104 QString("Unexpected return value from %1::MythPlayerInited: %2")
105 .arg((*it)->name()).arg(ares));
106 return false;
107 }
108 }
109
110 return true;
111}
112
114 FrameAnalyzerItem &finishedAnalyzers,
115 FrameAnalyzerItem &deadAnalyzers,
116 const MythVideoFrame *frame,
117 long long frameno)
118{
119 long long nextFrame = 0;
120 long long minNextFrame = FrameAnalyzer::kAnyFrame;
121
122 auto it = pass.begin();
123 while (it != pass.end())
124 {
126 (*it)->analyzeFrame(frame, frameno, &nextFrame);
127
128 if ((FrameAnalyzer::ANALYZE_OK == ares) ||
130 {
131 minNextFrame = std::min(minNextFrame, nextFrame);
132 ++it;
133 }
134 else if (ares == FrameAnalyzer::ANALYZE_FINISHED)
135 {
136 finishedAnalyzers.push_back(*it);
137 it = pass.erase(it);
138 }
139 else
140 {
142 {
143 LOG(VB_GENERAL, LOG_ERR,
144 QString("Unexpected return value from %1::analyzeFrame: %2")
145 .arg((*it)->name()).arg(ares));
146 }
147
148 deadAnalyzers.push_back(*it);
149 it = pass.erase(it);
150 }
151 }
152
153 if (minNextFrame == FrameAnalyzer::kAnyFrame)
154 minNextFrame = FrameAnalyzer::kNextFrame;
155
156 if (minNextFrame == FrameAnalyzer::kNextFrame)
157 minNextFrame = frameno + 1;
158
159 return minNextFrame;
160}
161
162int passFinished(FrameAnalyzerItem &pass, long long nframes, bool final)
163{
164 for (auto & pas : pass)
165 (void)pas->finished(nframes, final);
166
167 return 0;
168}
169
171{
172 for (auto *pas : pass)
173 (void)pas->reportTime();
174
175 return 0;
176}
177
179{
180 if (!tf)
181 return false;
182
183 auto it = std::find(pass.cbegin(), pass.cend(), tf);
184 return it != pass.end();
185}
186
187}; // namespace
188
189namespace commDetector2 {
190
191QString debugDirectory(int chanid, const QDateTime& recstartts)
192{
193 /*
194 * Should deleting a recording also delete its associated debug directory?
195 */
197 query.prepare("SELECT basename"
198 " FROM recorded"
199 " WHERE chanid = :CHANID"
200 " AND starttime = :STARTTIME"
201 ";");
202 query.bindValue(":CHANID", chanid);
203 query.bindValue(":STARTTIME", recstartts);
204 if (!query.exec() || !query.next())
205 {
206 MythDB::DBError("Error in CommDetector2::CommDetector2", query);
207 return "";
208 }
209
210 ProgramInfo pginfo(chanid, recstartts);
211
212 if (!pginfo.GetChanID())
213 return "";
214
215 QString pburl = pginfo.GetPlaybackURL(true);
216 if (!pburl.startsWith("/"))
217 return "";
218
219 QString basename(query.value(0).toString());
220 QString m_debugdir = pburl.section('/',0,-2) + "/" + basename + "-debug";
221
222 return m_debugdir;
223}
224
225void createDebugDirectory(const QString& dirname, const QString& comment)
226{
227 QDir qdir(dirname);
228 if (qdir.exists())
229 {
230 LOG(VB_COMMFLAG, LOG_INFO, QString("%1 using debug directory \"%2\"")
231 .arg(comment, dirname));
232 }
233 else
234 {
235 if (qdir.mkdir(dirname))
236 {
237 LOG(VB_COMMFLAG, LOG_INFO,
238 QString("%1 created debug directory \"%1\"")
239 .arg(comment, dirname));
240 }
241 else
242 {
243 LOG(VB_COMMFLAG, LOG_INFO, QString("%1 failed to create \"%2\": %3")
244 .arg(comment, dirname, strerror(errno)));
245 }
246 }
247}
248
249QString frameToTimestamp(long long frameno, float fps)
250{
251 auto ms = millisecondsFromFloat(frameno / fps * 1000);
252 auto secs = std::chrono::ceil<std::chrono::seconds>(ms);
253 return MythDate::formatTime(secs, "HH:mm:ss");
254}
255
256QString frameToTimestampms(long long frameno, float fps)
257{
258 auto ms = millisecondsFromFloat(frameno / fps * 1000);
259 QString timestr = MythDate::formatTime(ms, "mm:ss.zz");
260 return timestr;
261}
262
263QString strftimeval(std::chrono::microseconds usecs)
264{
265 auto msecs = duration_cast<std::chrono::milliseconds>(usecs);
266 return MythDate::formatTime(msecs, "s.zzz");
267}
268
269}; /* namespace */
270
271using namespace commDetector2;
272
274 SkipType commDetectMethod_in,
275 bool showProgress_in,
276 bool fullSpeed_in,
277 MythCommFlagPlayer *player_in,
278 int chanid,
279 QDateTime startts_in,
280 QDateTime endts_in,
281 QDateTime recstartts_in,
282 QDateTime recendts_in,
283 bool useDB) :
284 m_commDetectMethod((SkipType)(commDetectMethod_in & ~COMM_DETECT_2)),
285 m_showProgress(showProgress_in), m_fullSpeed(fullSpeed_in),
286 m_player(player_in),
287 m_startts(std::move(startts_in)), m_endts(std::move(endts_in)),
288 m_recstartts(std::move(recstartts_in)), m_recendts(std::move(recendts_in)),
289 m_isRecording(MythDate::current() < m_recendts),
290 m_debugdir("")
291{
292 FrameAnalyzerItem pass0;
293 FrameAnalyzerItem pass1;
294
295 if (useDB)
297
298 std::shared_ptr<PGMConverter> pgmConverter =
299 std::make_shared<PGMConverter>();
300 std::shared_ptr<BorderDetector> borderDetector =
301 std::make_shared<BorderDetector>();
302 std::shared_ptr<HistogramAnalyzer> histogramAnalyzer =
303 std::make_shared<HistogramAnalyzer>(pgmConverter, borderDetector,
304 m_debugdir);
305
306 /*
307 * Look for blank frames to use as delimiters between commercial and
308 * non-commercial segments.
309 */
311 {
313 {
314 m_blankFrameDetector = new BlankFrameDetector(histogramAnalyzer,
315 m_debugdir);
316 pass1.push_back(m_blankFrameDetector);
317 }
318 }
319
320 /*
321 * Look for "scene changes" to use as delimiters between commercial and
322 * non-commercial segments.
323 */
325 {
327 {
328 m_sceneChangeDetector = new SceneChangeDetector(histogramAnalyzer,
329 m_debugdir);
330 pass1.push_back(m_sceneChangeDetector);
331 }
332 }
333
334 /*
335 * Logo Detection requires two passes. The first pass looks for static
336 * areas of the screen to look for logos and generate a template. The
337 * second pass matches the template against the frame and computes the
338 * closeness of the match.
339 */
341 {
342 std::shared_ptr<CannyEdgeDetector> cannyEdgeDetector =
343 std::make_shared<CannyEdgeDetector>();
344
345 if (!m_logoFinder)
346 {
347 m_logoFinder = new TemplateFinder(pgmConverter, borderDetector,
348 cannyEdgeDetector, m_player, m_recstartts.secsTo(m_recendts),
349 m_debugdir);
350 pass0.push_back(m_logoFinder);
351 }
352
353 if (!m_logoMatcher)
354 {
355 m_logoMatcher = new TemplateMatcher(pgmConverter, cannyEdgeDetector,
357 pass1.push_back(m_logoMatcher);
358 }
359 }
360
361 if (histogramAnalyzer && m_logoFinder)
362 histogramAnalyzer->setLogoState(m_logoFinder);
363
364 /* Aggregate them all together. */
365 m_frameAnalyzers.push_back(pass0);
366 m_frameAnalyzers.push_back(pass1);
367}
368
369void CommDetector2::reportState(int elapsedms, long long frameno,
370 long long nframes, unsigned int passno, unsigned int npasses)
371{
372 float fps = elapsedms ? (float)frameno * 1000 / elapsedms : 0;
373 static int s_prevpercent = -1;
374
375 /* Assume that 0-th pass is negligible in terms of computational cost. */
376 int percentage = (passno == 0 || npasses == 1 || nframes == 0) ? 0 :
377 ((passno - 1) * 100 / (npasses - 1)) +
378 std::min((long long)100, (frameno * 100 / nframes) / (npasses - 1));
379
380 if (m_showProgress)
381 {
382 QString tmp = "";
383
384 if (nframes)
385 tmp = QString("\r%1%/ %2fps").arg(percentage,3).arg(fps,6,'f',2);
386 else
387 tmp = QString("\r%1/ %2fps").arg(frameno,6).arg(fps,6,'f',2);
388
389 QByteArray tmp2 = tmp.toLocal8Bit();
390 std::cerr << tmp2.constData() << " \r";
391 std::cerr.flush();
392 }
393
394 if (nframes)
395 {
396 emit statusUpdate(QCoreApplication::translate("(mythcommflag)",
397 "%1% Completed @ %2 fps.").arg(percentage).arg(fps));
398 }
399 else
400 {
401 emit statusUpdate(QCoreApplication::translate("(mythcommflag)",
402 "%1 Frames Completed @ %2 fps.").arg(frameno).arg(fps));
403 }
404
405 if (percentage % 10 == 0 && s_prevpercent != percentage)
406 {
407 s_prevpercent = percentage;
408 LOG(VB_GENERAL, LOG_INFO, QString("%1%% Completed @ %2 fps.")
409 .arg(percentage) .arg(fps));
410 }
411}
412
413int CommDetector2::computeBreaks(long long nframes)
414{
415 int trow = 0;
416 int tcol = 0;
417 int twidth = 0;
418 int theight = 0;
419
420 m_breaks.clear();
421
422 TemplateMatcher *matcher = nullptr;
423 if (m_logoFinder && m_logoFinder->getTemplate(&trow, &tcol, &twidth, &theight))
424 matcher = m_logoMatcher;
425
426 if (matcher && m_blankFrameDetector)
427 {
428 int cmp = matcher->templateCoverage(nframes, m_finished);
429 if (cmp == 0)
430 {
431 if (matcher->adjustForBlanks(m_blankFrameDetector, nframes))
432 return -1;
433 if (matcher->computeBreaks(&m_breaks))
434 return -1;
435 }
436 else
437 {
438 if (cmp > 0 &&
440 return -1;
441 if (cmp < 0 &&
443 return -1;
444
446 return -1;
447 }
448 }
449 else if (matcher)
450 {
451 if (matcher->computeBreaks(&m_breaks))
452 return -1;
453 }
454 else if (m_blankFrameDetector)
455 {
457 return -1;
458 }
459
460 return 0;
461}
462
464{
465 int minlag = 7; // seconds
466
467 if (m_player->OpenFile() < 0)
468 return false;
469
470 if (!m_player->InitVideo())
471 {
472 LOG(VB_GENERAL, LOG_ERR,
473 "NVP: Unable to initialize video for FlagCommercials.");
474 return false;
475 }
476
477 QElapsedTimer totalFlagTime;
478 totalFlagTime.start();
479
480 /* If still recording, estimate the eventual total number of frames. */
481 long long nframes = m_isRecording ?
482 (long long)roundf((m_recstartts.secsTo(m_recendts) + 5) *
485 bool postprocessing = !m_isRecording;
486
487 if (m_showProgress)
488 {
489 if (nframes)
490 std::cerr << " 0%/ ";
491 else
492 std::cerr << " 0/ ";
493 std::cerr.flush();
494 }
495
496 frm_dir_map_t lastBreakMap;
497 unsigned int passno = 0;
498 unsigned int npasses = m_frameAnalyzers.size();
499 for (m_currentPass = m_frameAnalyzers.begin();
501 ++m_currentPass, passno++)
502 {
503 FrameAnalyzerItem deadAnalyzers;
504
505 LOG(VB_COMMFLAG, LOG_INFO,
506 QString("CommDetector2::go pass %1 of %2 (%3 frames, %4 fps)")
507 .arg(passno + 1).arg(npasses)
509 .arg(m_player->GetFrameRate(), 0, 'f', 2));
510
511 if (!MythPlayerInited(
512 *m_currentPass, m_finishedAnalyzers, deadAnalyzers, m_player, nframes))
513 {
514 return false;
515 }
516
518 long long nextFrame = -1;
520 long long lastLoggedFrame = m_currentFrameNumber;
521 QElapsedTimer passTime;
522 QElapsedTimer clock;
523 std::chrono::microseconds getframetime {0us};
524
526
528 emit statusUpdate(QCoreApplication::translate("(mythcommflag)",
529 "Performing Logo Identification"));
530
531 clock.start();
532 passTime.start();
533 while (!(*m_currentPass).empty() && m_player->GetEof() == kEofStateNone)
534 {
535 auto start = nowAsDuration<std::chrono::microseconds>();
536 bool fetchNext = (nextFrame == m_currentFrameNumber + 1);
537 MythVideoFrame *currentFrame =
538 m_player->GetRawVideoFrame(fetchNext ? -1 : nextFrame);
539 long long lastFrameNumber = m_currentFrameNumber;
540 m_currentFrameNumber = currentFrame->m_frameNumber + 1;
541 auto end = nowAsDuration<std::chrono::microseconds>();
542 getframetime += (end - start);
543
544 if (nextFrame != -1 && nextFrame == lastFrameNumber + 1 &&
545 m_currentFrameNumber != nextFrame)
546 {
547 /*
548 * Don't log "Jumped" when we know we're skipping frames (e.g.,
549 * logo detection).
550 */
551 LOG(VB_COMMFLAG, LOG_INFO,
552 QString("Jumped from frame %1 to frame %2")
553 .arg(lastFrameNumber).arg(m_currentFrameNumber));
554 }
555
557 {
558 emit breathe();
559 if (m_bStop)
560 {
561 m_player->DiscardVideoFrame(currentFrame);
562 return false;
563 }
564 }
565
566 while (m_bPaused)
567 {
568 emit breathe();
569 std::this_thread::sleep_for(1s);
570 }
571
575 {
576 reportState(passTime.elapsed(), m_currentFrameNumber,
577 nframes, passno, npasses);
578 }
579
580 nextFrame = processFrame(
582 deadAnalyzers, currentFrame, m_currentFrameNumber);
583
584 if (((m_currentFrameNumber >= 1) && (nframes > 0) &&
585 (((nextFrame * 10) / nframes) !=
586 ((m_currentFrameNumber * 10) / nframes))) ||
587 (nextFrame >= nframes))
588 {
589 /* Log something every 10%. */
590 int elapsed = clock.restart();
591 LOG(VB_COMMFLAG, LOG_INFO,
592 QString("processFrame %1 of %2 (%3%) - %4 fps")
594 .arg(nframes)
595 .arg((nframes == 0) ? 0 :
596 (int)roundf(m_currentFrameNumber * 100.0 / nframes))
597 .arg((m_currentFrameNumber - lastLoggedFrame) * 1000 /
598 (elapsed ? elapsed : 1)));
599 lastLoggedFrame = m_currentFrameNumber;
600 }
601
602 if (m_isRecording)
603 {
604 waitForBuffer(start, minlag,
606 (totalFlagTime.elapsed() / 1000), m_player->GetFrameRate(),
608 }
609
610 // sleep a little so we don't use all cpu even if we're niced
611 if (!m_fullSpeed && !m_isRecording)
612 std::this_thread::sleep_for(10ms);
613
615 !(m_currentFrameNumber % 500)))
616 {
617 frm_dir_map_t breakMap;
618
619 GetCommercialBreakList(breakMap);
620
621 auto ii = breakMap.cbegin();
622 auto jj = lastBreakMap.cbegin();
623 while (ii != breakMap.cend() && jj != lastBreakMap.cend())
624 {
625 if (ii.key() != jj.key())
626 break;
627 if (*ii != *jj)
628 break;
629 ++ii;
630 ++jj;
631 }
632 bool same = ii == breakMap.cend() && jj == lastBreakMap.cend();
633 lastBreakMap = breakMap;
634
635 if (m_breakMapUpdateRequested || !same)
637
639 }
640
641 m_player->DiscardVideoFrame(currentFrame);
642 }
643
644 // Save total duration only on the last pass, which hopefully does
645 // no skipping.
646 if (passno + 1 == npasses)
648
649 m_currentPass->insert(m_currentPass->end(),
650 m_finishedAnalyzers.begin(),
651 m_finishedAnalyzers.end());
652 m_finishedAnalyzers.clear();
653
654 if (postprocessing)
657 return false;
658
659 LOG(VB_COMMFLAG, LOG_INFO, QString("NVP Time: GetRawVideoFrame=%1s")
660 .arg(strftimeval(getframetime)));
662 return false;
663 }
664
665 if (m_showProgress)
666 {
667 if (nframes)
668 std::cerr << "\b\b\b\b\b\b \b\b\b\b\b\b";
669 else
670 std::cerr << "\b\b\b\b\b\b\b\b\b\b\b\b\b "
671 "\b\b\b\b\b\b\b\b\b\b\b\b\b";
672 std::cerr.flush();
673 }
674
675 m_finished = true;
676 return true;
677}
678
680{
681 if (!m_finished)
682 {
683 for (auto & analyzer : m_frameAnalyzers)
684 {
685 if (analyzer == *m_currentPass &&
687 {
688 return;
689 }
690
691 if (passFinished(analyzer, m_currentFrameNumber + 1, false))
692 return;
693 }
694 }
695
697 return;
698
699 marks.clear();
700
701 /* Create break list. */
702 long long breakframes = 0;
703 for (auto bb = m_breaks.begin(); bb != m_breaks.end(); ++bb)
704 {
705 long long segb = bb.key();
706 long long seglen = *bb;
707 long long sege = segb + seglen - 1;
708
709 if (segb < sege)
710 {
711 marks[segb] = MARK_COMM_START;
712 marks[sege] = MARK_COMM_END;
713
714 breakframes += seglen;
715 }
716 }
717
718 /* Report results. */
719 const float fps = m_player->GetFrameRate();
720 for (auto iimark = marks.cbegin(); iimark != marks.cend(); ++iimark)
721 {
722 /* Display as 1-based frame numbers. */
723 long long markstart = iimark.key() + 1; /* MARK_COMM_BEGIN */
724 ++iimark; /* MARK_COMM_END */
725 if (iimark == marks.cend())
726 break;
727 long long markend = iimark.key() + 1;
728
729 LOG(VB_COMMFLAG, LOG_INFO, QString("Break: frame %1-%2 (%3-%4, %5)")
730 .arg(markstart, 6).arg(markend, 6)
731 .arg(frameToTimestamp(markstart, fps),
732 frameToTimestamp(markend, fps),
733 frameToTimestamp(markend - markstart + 1, fps)));
734 }
735
736 const long long nframes = m_player->GetTotalFrameCount();
737 LOG(VB_COMMFLAG, LOG_INFO,
738 QString("Flagged %1 of %2 frames (%3 of %4), %5% commercials (%6)")
739 .arg(m_currentFrameNumber + 1).arg(nframes)
741 frameToTimestamp(nframes, fps),
742 QString::number(breakframes * 100 / m_currentFrameNumber),
743 frameToTimestamp(breakframes, fps)));
744}
745
746void CommDetector2::recordingFinished(long long totalFileSize)
747{
749 m_isRecording = false;
750 LOG(VB_COMMFLAG, LOG_INFO,
751 QString("CommDetector2::recordingFinished: %1 bytes")
752 .arg(totalFileSize));
753}
754
756{
758 {
759 LOG(VB_COMMFLAG, LOG_INFO, "Ignoring request for commBreakMapUpdate; "
760 "still doing logo detection");
761 return;
762 }
763
764 LOG(VB_COMMFLAG, LOG_INFO,
765 QString("commBreakMapUpdate requested at frame %1")
766 .arg(m_currentFrameNumber + 1));
769}
770
771static void PrintReportMap(std::ostream &out,
772 const FrameAnalyzer::FrameMap &frameMap)
773{
774 FrameAnalyzer::FrameMap::const_iterator it = frameMap.begin();
775 for (; it != frameMap.end(); ++it)
776 {
777 /*
778 * QMap'd as 0-based index, but display as 1-based index to match "Edit
779 * Recording" OSD.
780 */
781
782 long long bb = it.key() + 1;
783 long long ee = (*it) ? (bb + *it) : 1;
784 QString tmp = QString("%1: %2").arg(bb, 10).arg(ee - 1, 10);
785
786 out << qPrintable(tmp) << "\n";
787 }
788 out << std::flush;
789}
790
792 std::ostream &out, const frm_dir_map_t */*comm_breaks*/, bool /*verbose*/) const
793{
796 FrameAnalyzer::FrameMap blankBreakMap;
798 if (m_logoFinder)
799 logoMap = m_logoFinder->GetMap(0);
800
802 {
803 blankBreakMap = m_blankFrameDetector->GetMap(0);
804 blankMap = m_blankFrameDetector->GetMap(1);
805 }
806
808 sceneMap = m_sceneChangeDetector->GetMap(0);
809
810 out << "Logo Break Map" << std::endl;
811 PrintReportMap(out, logoMap);
812 out << "Blank Break Map" << std::endl;
813 PrintReportMap(out, blankBreakMap);
814 out << "Blank Map" << std::endl;
815 PrintReportMap(out, blankMap);
816 out << "Scene Break Map" << std::endl;
817 PrintReportMap(out, sceneMap);
818}
819
820/* vim: set expandtab tabstop=4 shiftwidth=4: */
static void PrintReportMap(std::ostream &out, const FrameAnalyzer::FrameMap &frameMap)
std::vector< FrameAnalyzer * > FrameAnalyzerItem
Definition: CommDetector2.h:33
int computeBreaks(FrameMap *breaks)
int computeForLogoSurplus(const TemplateMatcher *templateMatcher)
static int computeForLogoDeficit(const TemplateMatcher *templateMatcher)
FrameMap GetMap(unsigned int index) const override
void reportState(int elapsedms, long long frameno, long long nframes, unsigned int passno, unsigned int npasses)
TemplateFinder * m_logoFinder
Definition: CommDetector2.h:81
FrameAnalyzerList m_frameAnalyzers
Definition: CommDetector2.h:75
FrameAnalyzerItem m_finishedAnalyzers
Definition: CommDetector2.h:77
void recordingFinished(long long totalFileSize) override
QDateTime m_recendts
Definition: CommDetector2.h:66
bool m_breakMapUpdateRequested
Definition: CommDetector2.h:71
bool go(void) override
SkipType m_commDetectMethod
Definition: CommDetector2.h:59
FrameAnalyzerList::iterator m_currentPass
Definition: CommDetector2.h:76
MythCommFlagPlayer * m_player
Definition: CommDetector2.h:62
BlankFrameDetector * m_blankFrameDetector
Definition: CommDetector2.h:83
bool m_sendBreakMapUpdates
Definition: CommDetector2.h:70
void requestCommBreakMapUpdate(void) override
void PrintFullMap(std::ostream &out, const frm_dir_map_t *comm_breaks, bool verbose) const override
void GetCommercialBreakList(frm_dir_map_t &marks) override
TemplateMatcher * m_logoMatcher
Definition: CommDetector2.h:82
int computeBreaks(long long nframes)
FrameAnalyzer::FrameMap m_breaks
Definition: CommDetector2.h:79
CommDetector2(SkipType commDetectMethod, bool showProgress, bool fullSpeed, MythCommFlagPlayer *player, int chanid, QDateTime startts, QDateTime endts, QDateTime recstartts, QDateTime recendts, bool useDB)
SceneChangeDetector * m_sceneChangeDetector
Definition: CommDetector2.h:84
long long m_currentFrameNumber
Definition: CommDetector2.h:74
QDateTime m_recstartts
Definition: CommDetector2.h:65
QString m_debugdir
Definition: CommDetector2.h:86
virtual void recordingFinished(long long totalFileSize)
void statusUpdate(const QString &a)
void gotNewCommercialBreakList()
static const long long kNextFrame
Definition: FrameAnalyzer.h:59
static const long long kAnyFrame
Definition: FrameAnalyzer.h:58
QMap< long long, long long > FrameMap
Definition: FrameAnalyzer.h:45
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:128
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:837
QVariant value(int i) const
Definition: mythdbcon.h:204
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:618
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:888
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:812
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:550
MythVideoFrame * GetRawVideoFrame(long long FrameNumber=-1)
Returns a specific frame from the video.
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:226
void SaveTotalDuration(void)
uint64_t GetTotalFrameCount(void) const
Definition: mythplayer.h:141
virtual int OpenFile(int Retries=4)
Definition: mythplayer.cpp:417
void ResetTotalDuration(void)
EofState GetEof(void) const
float GetFrameRate(void) const
Definition: mythplayer.h:132
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
Holds information on recordings and videos.
Definition: programinfo.h:70
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
Definition: programinfo.h:375
QString GetPlaybackURL(bool checkMaster=false, bool forceCheckLocal=false)
Returns filename or URL to be used to play back this recording.
FrameMap GetMap(unsigned int) const override
FrameMap GetMap(unsigned int) const override
const struct AVFrame * getTemplate(int *prow, int *pcol, int *pwidth, int *pheight) const
int computeBreaks(FrameMap *breaks)
int templateCoverage(long long nframes, bool final) const
int adjustForBlanks(const BlankFrameDetector *blankFrameDetector, long long nframes)
@ kEofStateNone
Definition: decoderbase.h:69
static pid_list_t::iterator find(const PIDInfoMap &map, pid_list_t &list, pid_list_t::iterator begin, pid_list_t::iterator end, bool find_open)
static guint32 * tmp
Definition: goom_core.cpp:26
std::enable_if_t< std::is_floating_point_v< T >, std::chrono::milliseconds > millisecondsFromFloat(T value)
Helper function for convert a floating point number to a duration.
Definition: mythchrono.h:91
std::chrono::duration< double, std::micro > floatusecs
Definition: mythchrono.h:41
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
QString formatTime(std::chrono::milliseconds msecs, QString fmt)
Format a milliseconds time value.
Definition: mythdate.cpp:242
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:15
bool needToReportState(bool showprogress, bool isrecording, long long frameno)
bool stopForBreath(bool isrecording, long long frameno)
bool MythPlayerInited(FrameAnalyzerItem &pass, FrameAnalyzerItem &finishedAnalyzers, FrameAnalyzerItem &deadAnalyzers, MythPlayer *player, long long nframes)
long long processFrame(FrameAnalyzerItem &pass, FrameAnalyzerItem &finishedAnalyzers, FrameAnalyzerItem &deadAnalyzers, const MythVideoFrame *frame, long long frameno)
int passFinished(FrameAnalyzerItem &pass, long long nframes, bool final)
bool searchingForLogo(TemplateFinder *tf, const FrameAnalyzerItem &pass)
int passReportTime(const FrameAnalyzerItem &pass)
void waitForBuffer(std::chrono::microseconds framestart, int minlag, int flaglag, float fps, bool fullspeed)
QString frameToTimestamp(long long frameno, float fps)
void createDebugDirectory(const QString &dirname, const QString &comment)
QString frameToTimestampms(long long frameno, float fps)
QString strftimeval(std::chrono::microseconds usecs)
QString debugDirectory(int chanid, const QDateTime &recstartts)
STL namespace.
@ 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
@ COMM_DETECT_2_SCENE
Definition: programtypes.h:142
@ COMM_DETECT_2_LOGO
Definition: programtypes.h:140
@ COMM_DETECT_2_BLANK
Definition: programtypes.h:141
@ COMM_DETECT_2
Definition: programtypes.h:139
QMap< uint64_t, MarkTypes > frm_dir_map_t
Frame # -> Mark map.
Definition: programtypes.h:117