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