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