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"
14 #include "libmythbase/mythdate.h"
15 #include "libmythbase/mythdb.h"
18 #include "libmythtv/channelutil.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 
33 namespace {
34 
35 bool stopForBreath(bool isrecording, long long frameno)
36 {
37  return (isrecording && (frameno % 100) == 0) || (frameno % 500) == 0;
38 }
39 
40 bool needToReportState(bool showprogress, bool isrecording, long long frameno)
41 {
42  return ((showprogress || isrecording) && (frameno % 100) == 0) ||
43  (frameno % 500) == 0;
44 }
45 
46 void 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 
74 bool MythPlayerInited(FrameAnalyzerItem &pass,
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 
113 long long processFrame(FrameAnalyzerItem &pass,
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  {
141  if (ares != FrameAnalyzer::ANALYZE_FATAL)
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 
162 int 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 
170 int passReportTime(const FrameAnalyzerItem &pass)
171 {
172  for (auto *pas : pass)
173  (void)pas->reportTime();
174 
175  return 0;
176 }
177 
178 bool searchingForLogo(TemplateFinder *tf, const FrameAnalyzerItem &pass)
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 
189 namespace commDetector2 {
190 
191 QString debugDirectory(int chanid, const QDateTime& recstartts)
192 {
193  /*
194  * Should deleting a recording also delete its associated debug directory?
195  */
196  MSqlQuery query(MSqlQuery::InitCon());
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 
225 void 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 
249 QString 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 
256 QString 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 
263 QString 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 
271 using 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 
369 void 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 
413 int 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) *
483  m_player->GetFrameRate()) :
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 
527  if (searchingForLogo(m_logoFinder, *m_currentPass))
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 
556  if (stopForBreath(m_isRecording, m_currentFrameNumber))
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 
572  if (!searchingForLogo(m_logoFinder, *m_currentPass) &&
573  needToReportState(m_showProgress, m_isRecording,
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,
605  m_recstartts.secsTo(MythDate::current()) -
606  totalFlagTime.elapsed() / 1000, m_player->GetFrameRate(),
607  m_fullSpeed);
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)
656  if (passFinished(*m_currentPass, m_currentFrameNumber + 1, true))
657  return false;
658 
659  LOG(VB_COMMFLAG, LOG_INFO, QString("NVP Time: GetRawVideoFrame=%1s")
660  .arg(strftimeval(getframetime)));
661  if (passReportTime(*m_currentPass))
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 &&
686  passFinished(m_finishedAnalyzers, m_currentFrameNumber + 1, false))
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)
740  .arg(frameToTimestamp(m_currentFrameNumber + 1, fps),
741  frameToTimestamp(nframes, fps),
742  QString::number(breakframes * 100 / m_currentFrameNumber),
743  frameToTimestamp(breakframes, fps)));
744 }
745 
746 void 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 {
757  if (searchingForLogo(m_logoFinder, *m_currentPass))
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));
767  m_sendBreakMapUpdates = true;
769 }
770 
771 static 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 {
794  FrameAnalyzer::FrameMap logoMap;
795  FrameAnalyzer::FrameMap blankMap;
796  FrameAnalyzer::FrameMap blankBreakMap;
797  FrameAnalyzer::FrameMap sceneMap;
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: */
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:813
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:127
TemplateMatcher.h
MARK_COMM_END
@ MARK_COMM_END
Definition: programtypes.h:60
MythPlayer::GetTotalFrameCount
uint64_t GetTotalFrameCount(void) const
Definition: mythplayer.h:143
CommDetectorBase::m_bPaused
bool m_bPaused
Definition: CommDetectorBase.h:52
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:369
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:463
CommDetector2::recordingFinished
void recordingFinished(long long totalFileSize) override
Definition: CommDetector2.cpp:746
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:204
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
MythDate::formatTime
QString formatTime(std::chrono::milliseconds msecs, QString fmt)
Format a milliseconds time value.
Definition: mythdate.cpp:233
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:619
CommDetector2::m_breaks
FrameAnalyzer::FrameMap m_breaks
Definition: CommDetector2.h:79
MythPlayer::GetFrameRate
float GetFrameRate(void) const
Definition: mythplayer.h:134
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
PrintReportMap
static void PrintReportMap(std::ostream &out, const FrameAnalyzer::FrameMap &frameMap)
Definition: CommDetector2.cpp:771
CommDetector2::requestCommBreakMapUpdate
void requestCommBreakMapUpdate(void) override
Definition: CommDetector2.cpp:755
CommDetector2::m_recstartts
QDateTime m_recstartts
Definition: CommDetector2.h:65
MythPlayer::GetEof
EofState GetEof(void) const
Definition: mythplayer.cpp:1067
MythPlayer
Definition: mythplayer.h:83
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:225
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:14
commDetector2::debugDirectory
QString debugDirectory(int chanid, const QDateTime &recstartts)
Definition: CommDetector2.cpp:191
tmp
static guint32 * tmp
Definition: goom_core.cpp:26
COMM_DETECT_2_BLANK
@ COMM_DETECT_2_BLANK
Definition: programtypes.h:142
CommDetector2::computeBreaks
int computeBreaks(long long nframes)
Definition: CommDetector2.cpp:413
mythdate.h
BlankFrameDetector::computeForLogoSurplus
int computeForLogoSurplus(const TemplateMatcher *templateMatcher)
Definition: BlankFrameDetector.cpp:446
TemplateFinder
Definition: TemplateFinder.h:30
CommDetectorBase::recordingFinished
virtual void recordingFinished([[maybe_unused]] long long totalFileSize)
Definition: CommDetectorBase.h:39
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:273
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:551
CommDetector2::PrintFullMap
void PrintFullMap(std::ostream &out, const frm_dir_map_t *comm_breaks, bool verbose) const override
Definition: CommDetector2.cpp:791
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:273
MythVideoFrame::m_frameNumber
long long m_frameNumber
Definition: mythframe.h:129
TemplateMatcher::templateCoverage
int templateCoverage(long long nframes, bool final) const
Definition: TemplateMatcher.cpp:583
CannyEdgeDetector.h
MythCommFlagPlayer
Definition: mythcommflagplayer.h:25
hardwareprofile.smolt.long
long
Definition: smolt.py:75
BlankFrameDetector::computeBreaks
int computeBreaks(FrameMap *breaks)
Definition: BlankFrameDetector.cpp:632
CommDetector2::GetCommercialBreakList
void GetCommercialBreakList(frm_dir_map_t &marks) override
Definition: CommDetector2.cpp:679
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
commDetector2::strftimeval
QString strftimeval(std::chrono::microseconds usecs)
Definition: CommDetector2.cpp:263
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:53
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
CommDetector2::m_logoFinder
TemplateFinder * m_logoFinder
Definition: CommDetector2.h:81
CommDetector2::m_commDetectMethod
SkipType m_commDetectMethod
Definition: CommDetector2.h:59
MythDate
Definition: mythdate.cpp:11
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:2546
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:889
std
Definition: mythchrono.h:23
FrameAnalyzer::ANALYZE_FATAL
@ ANALYZE_FATAL
Definition: FrameAnalyzer.h:40
commDetector2
Definition: CommDetector2.cpp:189
MythPlayer::ResetTotalDuration
void ResetTotalDuration(void)
Definition: mythplayer.cpp:1972
SceneChangeDetector::GetMap
FrameMap GetMap(unsigned int) const override
Definition: SceneChangeDetector.h:32
marks
static const std::array< const mark, 16 > marks
Definition: lang.cpp:23
FrameAnalyzer::ANALYZE_FINISHED
@ ANALYZE_FINISHED
Definition: FrameAnalyzer.h:39
SkipType
SkipType
This is used as a bitmask.
Definition: programtypes.h:128
TemplateMatcher::computeBreaks
int computeBreaks(FrameMap *breaks)
Definition: TemplateMatcher.cpp:807
MythPlayer::SaveTotalDuration
void SaveTotalDuration(void)
Definition: mythplayer.cpp:1964
COMM_DETECT_2_SCENE
@ COMM_DETECT_2_SCENE
Definition: programtypes.h:143
TemplateFinder.h
MythVideoFrame
Definition: mythframe.h:88
commDetector2::frameToTimestampms
QString frameToTimestampms(long long frameno, float fps)
Definition: CommDetector2.cpp:256
commDetector2::frameToTimestamp
QString frameToTimestamp(long long frameno, float fps)
Definition: CommDetector2.cpp:249
CommDetector2::m_fullSpeed
bool m_fullSpeed
Definition: CommDetector2.h:61
TemplateMatcher::adjustForBlanks
int adjustForBlanks(const BlankFrameDetector *blankFrameDetector, long long nframes)
Definition: TemplateMatcher.cpp:639
CommDetector2::m_blankFrameDetector
BlankFrameDetector * m_blankFrameDetector
Definition: CommDetector2.h:83
BlankFrameDetector::computeForLogoDeficit
static int computeForLogoDeficit(const TemplateMatcher *templateMatcher)
Definition: BlankFrameDetector.cpp:623
MARK_COMM_START
@ MARK_COMM_START
Definition: programtypes.h:59
TemplateFinder::getTemplate
const struct AVFrame * getTemplate(int *prow, int *pcol, int *pwidth, int *pheight) const
Definition: TemplateFinder.cpp:1046
CommDetector2::m_isRecording
bool m_isRecording
Definition: CommDetector2.h:69
TemplateMatcher
Definition: TemplateMatcher.h:31
COMM_DETECT_2
@ COMM_DETECT_2
Definition: programtypes.h:140
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:141
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:363
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:838
MythPlayer::DiscardVideoFrame
void DiscardVideoFrame(MythVideoFrame *buffer)
Places frame in the available frames queue.
Definition: mythplayer.cpp:629