MythTV  master
BlankFrameDetector.cpp
Go to the documentation of this file.
1 // ANSI C headers
2 #include <cmath>
3 #include <cstdlib>
4 #include <utility>
5 
6 // MythTV headers
7 #include "mythcorecontext.h" /* gContext */
8 #include "mythplayer.h"
9 
10 // Commercial Flagging headers
11 #include "CommDetector2.h"
12 #include "FrameAnalyzer.h"
13 #include "quickselect.h"
14 #include "HistogramAnalyzer.h"
15 #include "BlankFrameDetector.h"
16 #include "TemplateMatcher.h"
17 
18 using namespace commDetector2;
19 using namespace frameAnalyzer;
20 
21 namespace {
22 
23 bool
24 isBlank(unsigned char median, float stddev, unsigned char maxmedian,
25  float maxstddev)
26 {
27  return ((median < maxmedian) ||
28  ((median == maxmedian) && (stddev <= maxstddev)));
29 }
30 
31 int
32 sort_ascending_uchar(const void *aa, const void *bb)
33 {
34  return *(unsigned char*)aa - *(unsigned char*)bb;
35 }
36 
37 int
38 sort_ascending_float(const void *aa, const void *bb)
39 {
40  float faa = *(float*)aa;
41  float fbb = *(float*)bb;
42  return faa < fbb ? -1 : faa == fbb ? 0 : 1;
43 }
44 
45 bool
46 pickmedian(const unsigned char medianval,
47  unsigned char minval, unsigned char maxval)
48 {
49  return medianval >= minval && medianval <= maxval;
50 }
51 
52 void
53 computeBlankMap(FrameAnalyzer::FrameMap *blankMap, long long nframes,
54  const unsigned char *median, const float *stddev,
55  const unsigned char *monochromatic)
56 {
57  /*
58  * Select a "black" value based on a curve, to deal with varying "black"
59  * levels.
60  */
61  const unsigned char MINBLANKMEDIAN = 1;
62  const unsigned char MAXBLANKMEDIAN = 96;
63  const float MEDIANPCTILE = 0.95;
64  const float STDDEVPCTILE = 0.85;
65 
66  long long frameno = 1;
67  long long segb = 0;
68  long long sege = 0;
69 
70  /* Count and select for monochromatic frames. */
71 
72  long long nblanks = 0;
73  for (frameno = 0; frameno < nframes; frameno++)
74  {
75  if (monochromatic[frameno] && pickmedian(median[frameno],
76  MINBLANKMEDIAN, MAXBLANKMEDIAN))
77  nblanks++;
78  }
79 
80  if (!nblanks)
81  {
82  /* No monochromatic frames. */
83  LOG(VB_COMMFLAG, LOG_INFO,
84  "BlankFrameDetector::computeBlankMap: No blank frames.");
85  return;
86  }
87 
88  /* Select percentile values from monochromatic frames. */
89 
90  auto *blankmedian = new unsigned char[nblanks];
91  auto *blankstddev = new float[nblanks];
92  long long blankno = 0;
93  for (frameno = 0; frameno < nframes; frameno++)
94  {
95  if (monochromatic[frameno] && pickmedian(median[frameno],
96  MINBLANKMEDIAN, MAXBLANKMEDIAN))
97  {
98  blankmedian[blankno] = median[frameno];
99  blankstddev[blankno] = stddev[frameno];
100  blankno++;
101  }
102  }
103 
104  qsort(blankmedian, nblanks, sizeof(*blankmedian), sort_ascending_uchar);
105  blankno = min(nblanks - 1, (long long)roundf(nblanks * MEDIANPCTILE));
106  uchar maxmedian = blankmedian[blankno];
107 
108  qsort(blankstddev, nblanks, sizeof(*blankstddev), sort_ascending_float);
109  long long stddevno = min(nblanks - 1, (long long)roundf(nblanks * STDDEVPCTILE));
110  float maxstddev = blankstddev[stddevno];
111 
112  /* Determine effective percentile ranges (for debugging). */
113 
114  long long blankno1 = blankno;
115  long long blankno2 = blankno;
116  while (blankno1 > 0 && blankmedian[blankno1] == maxmedian)
117  blankno1--;
118  if (blankmedian[blankno1] != maxmedian)
119  blankno1++;
120  while (blankno2 < nblanks && blankmedian[blankno2] == maxmedian)
121  blankno2++;
122  if (blankno2 == nblanks)
123  blankno2--;
124 
125  long long stddevno1 = stddevno;
126  long long stddevno2 = stddevno;
127  while (stddevno1 > 0 && blankstddev[stddevno1] == maxstddev)
128  stddevno1--;
129  if (blankstddev[stddevno1] != maxstddev)
130  stddevno1++;
131  while (stddevno2 < nblanks && blankstddev[stddevno2] == maxstddev)
132  stddevno2++;
133  if (stddevno2 == nblanks)
134  stddevno2--;
135 
136  LOG(VB_COMMFLAG, LOG_INFO,
137  QString("Blanks selecting median<=%1 (%2-%3%), stddev<=%4 (%5-%6%)")
138  .arg(maxmedian)
139  .arg(blankno1 * 100 / nblanks).arg(blankno2 * 100 / nblanks)
140  .arg(maxstddev)
141  .arg(stddevno1 * 100 / nblanks).arg(stddevno2 * 100 / nblanks));
142 
143  delete []blankmedian;
144  delete []blankstddev;
145 
146  blankMap->clear();
147  if (monochromatic[0] && isBlank(median[0], stddev[0], maxmedian, maxstddev))
148  {
149  segb = 0;
150  sege = 0;
151  }
152  else
153  {
154  /* Fake up a dummy blank frame for interval calculations. */
155  blankMap->insert(0, 0);
156  segb = -1;
157  sege = -1;
158  }
159  for (frameno = 1; frameno < nframes; frameno++)
160  {
161  if (monochromatic[frameno] && isBlank(median[frameno], stddev[frameno],
162  maxmedian, maxstddev))
163  {
164  /* Blank frame. */
165  if (sege < frameno - 1)
166  {
167  /* Start counting. */
168  segb = frameno;
169  sege = frameno;
170  }
171  else
172  {
173  /* Continue counting. */
174  sege = frameno;
175  }
176  }
177  else if (sege == frameno - 1)
178  {
179  /* Transition to non-blank frame. */
180  long long seglen = frameno - segb;
181  blankMap->insert(segb, seglen);
182  }
183  }
184  if (sege == frameno - 1)
185  {
186  /* Possibly ending on blank frames. */
187  long long seglen = frameno - segb;
188  blankMap->insert(segb, seglen);
189  }
190 
191  FrameAnalyzer::FrameMap::Iterator iiblank = blankMap->end();
192  --iiblank;
193  if (iiblank.key() + *iiblank < nframes)
194  {
195  /*
196  * Didn't end on blank frames, so add a dummy blank frame at the
197  * end.
198  */
199  blankMap->insert(nframes - 1, 0);
200  }
201 }
202 
203 void
204 computeBreakMap(FrameAnalyzer::FrameMap *breakMap,
205  const FrameAnalyzer::FrameMap *blankMap, float fps,
206  int debugLevel)
207 {
208  /*
209  * TUNABLE:
210  *
211  * Common commercial-break lengths.
212  */
213  static constexpr struct {
214  int m_len; /* seconds */
215  int m_delta; /* seconds */
216  } kBreakType[] = {
217  /* Sort by "len". */
218  { 15, 2 },
219  { 20, 2 },
220  { 30, 5 },
221  { 60, 5 },
222  };
223 
224  /*
225  * TUNABLE:
226  *
227  * Shortest non-commercial length, used to coalesce consecutive commercial
228  * breaks that are usually identified due to in-commercial cuts.
229  */
230  static const int kMinContentLen = (int)roundf(10 * fps);
231 
232  breakMap->clear();
233  for (FrameAnalyzer::FrameMap::const_iterator iiblank = blankMap->begin();
234  iiblank != blankMap->end();
235  ++iiblank)
236  {
237  long long brkb = iiblank.key();
238  long long iilen = *iiblank;
239  long long start = brkb + iilen / 2;
240 
241  for (auto type : kBreakType)
242  {
243  /* Look for next blank frame that is an acceptable distance away. */
244  FrameAnalyzer::FrameMap::const_iterator jjblank = iiblank;
245  for (++jjblank; jjblank != blankMap->end(); ++jjblank)
246  {
247  long long brke = jjblank.key();
248  long long jjlen = *jjblank;
249  long long end = brke + jjlen / 2;
250 
251  auto testlen = (long long)roundf((end - start) / fps);
252  if (testlen > type.m_len + type.m_delta)
253  break; /* Too far ahead; break to next break length. */
254 
255  long long delta = testlen - type.m_len;
256  if (delta < 0)
257  delta = 0 - delta;
258 
259  if (delta > type.m_delta)
260  continue; /* Outside delta range; try next end-blank. */
261 
262  /* Mark this commercial break. */
263  bool inserted = false;
264  for (unsigned int jj = 0;; jj++)
265  {
266  long long newbrkb = brkb + jj;
267  if (newbrkb >= brke)
268  {
269  LOG(VB_COMMFLAG, LOG_INFO,
270  QString("BF [%1,%2] ran out of slots")
271  .arg(brkb).arg(brke - 1));
272  break;
273  }
274  if (breakMap->find(newbrkb) == breakMap->end())
275  {
276  breakMap->insert(newbrkb, brke - newbrkb);
277  inserted = true;
278  break;
279  }
280  }
281  if (inserted)
282  break; /* next break type */
283  }
284  }
285  }
286 
287  if (debugLevel >= 1)
288  {
289  frameAnalyzerReportMap(breakMap, fps, "BF Break");
290  LOG(VB_COMMFLAG, LOG_INFO,
291  "BF coalescing overlapping/nearby breaks ...");
292  }
293 
294  /*
295  * Coalesce overlapping or very-nearby breaks (handles cut-scenes within a
296  * commercial).
297  */
298  for (;;)
299  {
300  bool coalesced = false;
301  FrameAnalyzer::FrameMap::iterator iibreak = breakMap->begin();
302  while (iibreak != breakMap->end())
303  {
304  long long iib = iibreak.key();
305  long long iie = iib + *iibreak;
306 
307  FrameAnalyzer::FrameMap::iterator jjbreak = iibreak;
308  ++jjbreak;
309  if (jjbreak == breakMap->end())
310  break;
311 
312  long long jjb = jjbreak.key();
313  long long jje = jjb + *jjbreak;
314 
315  if (jjb < iib)
316  {
317  /* (jjb,jje) is behind (iib,iie). */
318  ++iibreak;
319  continue;
320  }
321 
322  if (iie + kMinContentLen < jjb)
323  {
324  /* (jjb,jje) is too far ahead. */
325  ++iibreak;
326  continue;
327  }
328 
329  /* Coalesce. */
330  if (jje > iie)
331  {
332  breakMap->remove(iib); /* overlap */
333  breakMap->insert(iib, jje - iib); /* overlap */
334  }
335  breakMap->erase(jjbreak);
336  coalesced = true;
337  iibreak = breakMap->find(iib);
338  }
339  if (!coalesced)
340  break;
341  }
342 
343  /* Adjust for blank intervals. */
344  FrameAnalyzer::FrameMap::iterator iibreak = breakMap->begin();
345  while (iibreak != breakMap->end())
346  {
347  long long iib = iibreak.key();
348  long long iie = iib + *iibreak;
349  FrameAnalyzer::FrameMap::iterator jjbreak = iibreak;
350  ++jjbreak;
351  breakMap->erase(iibreak);
352 
353  /* Trim leading blanks from commercial break. */
354  long long addb = *blankMap->find(iib);
355  addb = addb / 2;
356  if (addb > MAX_BLANK_FRAMES)
357  addb = MAX_BLANK_FRAMES;
358  iib += addb;
359  /* Add trailing blanks to commercial break. */
360  long long adde = *blankMap->find(iie);
361  iie += adde;
362  long long sube = adde / 2;
363  if (sube > MAX_BLANK_FRAMES)
364  sube = MAX_BLANK_FRAMES;
365  iie -= sube;
366  breakMap->insert(iib, iie - iib);
367  iibreak = jjbreak;
368  }
369 }
370 
371 }; /* namespace */
372 
373 BlankFrameDetector::BlankFrameDetector(std::shared_ptr<HistogramAnalyzer>ha,
374  const QString &debugdir)
375  : m_histogramAnalyzer(std::move(ha))
376 {
377  /*
378  * debugLevel:
379  * 0: no debugging
380  * 2: extra verbosity [O(nframes)]
381  */
382  m_debugLevel = gCoreContext->GetNumSetting("BlankFrameDetectorDebugLevel", 0);
383 
384  if (m_debugLevel >= 1)
385  createDebugDirectory(debugdir,
386  QString("BlankFrameDetector debugLevel %1").arg(m_debugLevel));
387 }
388 
391 {
393  m_histogramAnalyzer->MythPlayerInited(player, nframes);
394 
395  m_fps = player->GetFrameRate();
396 
397  QSize video_disp_dim = player->GetVideoSize();
398 
399  LOG(VB_COMMFLAG, LOG_INFO,
400  QString("BlankFrameDetector::MythPlayerInited %1x%2")
401  .arg(video_disp_dim.width())
402  .arg(video_disp_dim.height()));
403 
404  return ares;
405 }
406 
408 BlankFrameDetector::analyzeFrame(const VideoFrame *frame, long long frameno,
409  long long *pNextFrame)
410 {
411  *pNextFrame = kNextFrame;
412 
413  if (m_histogramAnalyzer->analyzeFrame(frame, frameno) ==
415  return ANALYZE_OK;
416 
417  LOG(VB_COMMFLAG, LOG_INFO,
418  QString("BlankFrameDetector::analyzeFrame error at frame %1")
419  .arg(frameno));
420  return ANALYZE_ERROR;
421 }
422 
423 int
424 BlankFrameDetector::finished(long long nframes, bool final)
425 {
426  if (m_histogramAnalyzer->finished(nframes, final))
427  return -1;
428 
429  LOG(VB_COMMFLAG, LOG_INFO, QString("BlankFrameDetector::finished(%1)")
430  .arg(nframes));
431 
432  /* Identify all sequences of blank frames (blankMap). */
433  computeBlankMap(&m_blankMap, nframes,
434  m_histogramAnalyzer->getMedians(), m_histogramAnalyzer->getStdDevs(),
435  m_histogramAnalyzer->getMonochromatics());
436  if (m_debugLevel >= 2)
438 
439  return 0;
440 }
441 
442 int
444  const TemplateMatcher *templateMatcher)
445 {
446  /*
447  * See TemplateMatcher::templateCoverage; some commercial breaks have
448  * logos. Conversely, any logo breaks are probably really breaks, so prefer
449  * those over blank-frame-calculated breaks.
450  */
451  const FrameAnalyzer::FrameMap *logoBreakMap = templateMatcher->getBreaks();
452 
453  /* TUNABLE: see TemplateMatcher::adjustForBlanks */
454  const int MAXBLANKADJUSTMENT = (int)roundf(5 * m_fps); /* frames */
455 
456  LOG(VB_COMMFLAG, LOG_INFO, "BlankFrameDetector adjusting for logo surplus");
457 
458  /*
459  * For each logo break, find the blank frames closest to its beginning and
460  * end. This helps properly support CommSkipAllBlanks.
461  */
462  for (FrameAnalyzer::FrameMap::const_iterator ii =
463  logoBreakMap->constBegin();
464  ii != logoBreakMap->constEnd();
465  ++ii)
466  {
467  /* Get bounds of beginning of logo break. */
468  long long iikey = ii.key();
469  long long iibb = iikey - MAXBLANKADJUSTMENT;
470  long long iiee = iikey + MAXBLANKADJUSTMENT;
471  FrameAnalyzer::FrameMap::Iterator jjfound = m_blankMap.end();
472 
473  /* Look for a blank frame near beginning of logo break. */
474  for (auto jj = m_blankMap.begin(); jj != m_blankMap.end(); ++jj)
475  {
476  long long jjbb = jj.key();
477  long long jjee = jjbb + *jj;
478 
479  if (iiee < jjbb)
480  break; /* No nearby blank frames. */
481 
482  if (jjee < iibb)
483  continue; /* Too early; keep looking. */
484 
485  jjfound = jj;
486  if (iikey <= jjbb)
487  {
488  /*
489  * Prefer the first blank frame beginning after the logo break
490  * begins.
491  */
492  break;
493  }
494  }
495 
496  /* Adjust blank frame to begin with logo break beginning. */
497  if (jjfound != m_blankMap.end())
498  {
499  long long jjee = jjfound.key() + *jjfound;
500  m_blankMap.erase(jjfound);
501  if (jjee <= iikey)
502  {
503  /* Move blank frame to beginning of logo break. */
504  m_blankMap.remove(iikey);
505  m_blankMap.insert(iikey, 1);
506  }
507  else
508  {
509  /* Adjust blank frame to begin with logo break. */
510  m_blankMap.insert(iikey, jjee - iikey);
511  }
512  }
513 
514  /* Get bounds of end of logo break. */
515  long long kkkey = ii.key() + *ii;
516  long long kkbb = kkkey - MAXBLANKADJUSTMENT;
517  long long kkee = kkkey + MAXBLANKADJUSTMENT;
518  FrameAnalyzer::FrameMap::Iterator mmfound = m_blankMap.end();
519 
520  /* Look for a blank frame near end of logo break. */
521  for (auto mm = m_blankMap.begin(); mm != m_blankMap.end(); ++mm)
522  {
523  long long mmbb = mm.key();
524  long long mmee = mmbb + *mm;
525 
526  if (kkee < mmbb)
527  break; /* No nearby blank frames. */
528 
529  if (mmee < kkbb)
530  continue; /* Too early; keep looking. */
531 
532  /* Prefer the last blank frame ending before the logo break ends. */
533  if (mmee < kkkey || mmfound == m_blankMap.end())
534  mmfound = mm;
535  if (mmee >= kkkey)
536  break;
537  }
538 
539  /* Adjust blank frame to end with logo break end. */
540  if (mmfound != m_blankMap.end())
541  {
542  long long mmbb = mmfound.key();
543  if (mmbb < kkkey)
544  {
545  /* Adjust blank frame to end with logo break. */
546  m_blankMap.remove(mmbb);
547  m_blankMap.insert(mmbb, kkkey - mmbb);
548  }
549  else
550  {
551  /* Move blank frame to end of logo break. */
552  m_blankMap.erase(mmfound);
553  m_blankMap.remove(kkkey - 1);
554  m_blankMap.insert(kkkey - 1, 1);
555  }
556  }
557  }
558 
559  /*
560  * Compute breaks (breakMap).
561  */
562  computeBreakMap(&m_breakMap, &m_blankMap, m_fps, m_debugLevel);
563 
564  /*
565  * Expand blank-frame breaks to fully include overlapping logo breaks.
566  * Fully include logo breaks that don't include any blank-frame breaks.
567  */
568  for (FrameAnalyzer::FrameMap::const_iterator ii =
569  logoBreakMap->constBegin();
570  ii != logoBreakMap->constEnd();
571  ++ii)
572  {
573  long long iibb = ii.key();
574  long long iiee = iibb + *ii;
575  bool overlap = false;
576 
577  for (auto jj = m_breakMap.begin(); jj != m_breakMap.end(); )
578  {
579  long long jjbb = jj.key();
580  long long jjee = jjbb + *jj;
581  FrameAnalyzer::FrameMap::Iterator jjnext = jj;
582  ++jjnext;
583 
584  if (iiee < jjbb)
585  {
586  if (!overlap)
587  {
588  /* Fully incorporate logo break */
589  m_breakMap.insert(iibb, iiee - iibb);
590  }
591  break;
592  }
593 
594  if (iibb < jjbb && jjbb < iiee)
595  {
596  /* End of logo break includes beginning of blank-frame break. */
597  overlap = true;
598  m_breakMap.erase(jj);
599  m_breakMap.insert(iibb, max(iiee, jjee) - iibb);
600  }
601  else if (jjbb < iibb && iibb < jjee)
602  {
603  /* End of blank-frame break includes beginning of logo break. */
604  overlap = true;
605  if (jjee < iiee)
606  {
607  m_breakMap.remove(jjbb);
608  m_breakMap.insert(jjbb, iiee - jjbb);
609  }
610  }
611 
612  jj = jjnext;
613  }
614  }
615 
616  frameAnalyzerReportMap(&m_breakMap, m_fps, "BF Break");
617  return 0;
618 }
619 
620 int
622  const TemplateMatcher *templateMatcher)
623 {
624  (void)templateMatcher; /* gcc */
625 
626  LOG(VB_COMMFLAG, LOG_INFO, "BlankFrameDetector adjusting for "
627  "too little logo coverage (unimplemented)");
628  return 0;
629 }
630 
631 int
633 {
634  if (m_breakMap.empty())
635  {
636  /* Compute breaks (m_breakMap). */
637  computeBreakMap(&m_breakMap, &m_blankMap, m_fps, m_debugLevel);
638  frameAnalyzerReportMap(&m_breakMap, m_fps, "BF Break");
639  }
640 
641  breaks->clear();
642  for (auto bb = m_breakMap.begin(); bb != m_breakMap.end(); ++bb)
643  breaks->insert(bb.key(), *bb);
644 
645  return 0;
646 }
647 
648 int
650 {
651  return m_histogramAnalyzer->reportTime();
652 }
653 
654 /* vim: set expandtab tabstop=4 shiftwidth=4: */
BlankFrameDetector::analyzeFrame
enum analyzeFrameResult analyzeFrame(const VideoFrame *frame, long long frameno, long long *pNextFrame) override
Definition: BlankFrameDetector.cpp:408
TemplateMatcher.h
TemplateMatcher::getBreaks
const FrameAnalyzer::FrameMap * getBreaks(void) const
Definition: TemplateMatcher.h:54
FrameAnalyzer::ANALYZE_OK
@ ANALYZE_OK
Definition: FrameAnalyzer.h:37
CommDetector2.h
FrameAnalyzer::FrameMap
QMap< long long, long long > FrameMap
Definition: FrameAnalyzer.h:45
arg
arg(title).arg(filename).arg(doDelete))
quickselect.h
MythPlayer::GetFrameRate
float GetFrameRate(void) const
Definition: mythplayer.h:219
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
mythplayer.h
MythPlayer
Definition: mythplayer.h:164
BlankFrameDetector::reportTime
int reportTime(void) const override
Definition: BlankFrameDetector.cpp:649
VideoFrame
Definition: mythframe.h:137
commDetector2::createDebugDirectory
void createDebugDirectory(const QString &dirname, const QString &comment)
Definition: CommDetector2.cpp:231
BlankFrameDetector::m_histogramAnalyzer
std::shared_ptr< HistogramAnalyzer > m_histogramAnalyzer
Definition: BlankFrameDetector.h:40
BlankFrameDetector::computeForLogoSurplus
int computeForLogoSurplus(const TemplateMatcher *templateMatcher)
Definition: BlankFrameDetector.cpp:443
BlankFrameDetector::m_blankMap
FrameAnalyzer::FrameMap m_blankMap
Definition: BlankFrameDetector.h:43
BlankFrameDetector::BlankFrameDetector
BlankFrameDetector(std::shared_ptr< HistogramAnalyzer > ha, const QString &debugdir)
Definition: BlankFrameDetector.cpp:373
BlankFrameDetector.h
hardwareprofile.smolt.long
long
Definition: smolt.py:76
BlankFrameDetector::computeBreaks
int computeBreaks(FrameMap *breaks)
Definition: BlankFrameDetector.cpp:632
FrameAnalyzer::kNextFrame
static const long long kNextFrame
Definition: FrameAnalyzer.h:59
FrameAnalyzer::analyzeFrameResult
analyzeFrameResult
Definition: FrameAnalyzer.h:36
FrameAnalyzer.h
FrameAnalyzer::ANALYZE_ERROR
@ ANALYZE_ERROR
Definition: FrameAnalyzer.h:38
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:57
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:930
BlankFrameDetector::finished
int finished(long long nframes, bool final) override
Definition: BlankFrameDetector.cpp:424
HistogramAnalyzer.h
frameAnalyzer::frameAnalyzerReportMap
void frameAnalyzerReportMap(const FrameAnalyzer::FrameMap *frameMap, float fps, const char *comment)
Definition: FrameAnalyzer.cpp:17
BlankFrameDetector::m_fps
float m_fps
Definition: BlankFrameDetector.h:41
mythcorecontext.h
MythPlayer::GetVideoSize
QSize GetVideoSize(void) const
Definition: mythplayer.h:217
commDetector2
Definition: CommDetector2.cpp:195
BlankFrameDetector::m_breakMap
FrameAnalyzer::FrameMap m_breakMap
Definition: BlankFrameDetector.h:44
frameAnalyzer
Definition: FrameAnalyzer.cpp:7
MAX_BLANK_FRAMES
#define MAX_BLANK_FRAMES
Definition: CommDetectorBase.h:12
BlankFrameDetector::MythPlayerInited
enum analyzeFrameResult MythPlayerInited(MythPlayer *player, long long nframes) override
Definition: BlankFrameDetector.cpp:390
BlankFrameDetector::computeForLogoDeficit
static int computeForLogoDeficit(const TemplateMatcher *templateMatcher)
Definition: BlankFrameDetector.cpp:621
TemplateMatcher
Definition: TemplateMatcher.h:31
BlankFrameDetector::m_debugLevel
int m_debugLevel
Definition: BlankFrameDetector.h:47
frameAnalyzer::frameAnalyzerReportMapms
void frameAnalyzerReportMapms(const FrameAnalyzer::FrameMap *frameMap, float fps, const char *comment)
Definition: FrameAnalyzer.cpp:52