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