MythTV  master
ClassicCommDetector.cpp
Go to the documentation of this file.
1 // C++ headers
2 #include <algorithm> // for min/max, clamp
3 #include <cmath>
4 #include <iostream> // for cerr
5 #include <thread> // for sleep_for
6 
7 // Qt headers
8 #include <QCoreApplication>
9 #include <QString>
10 
11 // MythTV headers
12 #include "libmyth/mythcontext.h"
17 
18 // Commercial Flagging headers
19 #include "ClassicCommDetector.h"
20 #include "ClassicLogoDetector.h"
22 
26 } FrameAspects;
27 
28 // letter-box and pillar-box are not mutually exclusive
29 // So 3 is a valid value = (COMM_FORMAT_LETTERBOX | COMM_FORMAT_PILLARBOX)
30 // And 4 = COMM_FORMAT_MAX is the number of valid values.
36 } FrameFormats;
37 
38 static QString toStringFrameMaskValues(int mask, bool verbose)
39 {
40  QString msg;
41 
42  if (verbose)
43  {
44  if (COMM_FRAME_SKIPPED & mask)
45  msg += "skipped,";
46  if (COMM_FRAME_BLANK & mask)
47  msg += "blank,";
48  if (COMM_FRAME_SCENE_CHANGE & mask)
49  msg += "scene,";
50  if (COMM_FRAME_LOGO_PRESENT & mask)
51  msg += "logo,";
52  if (COMM_FRAME_ASPECT_CHANGE & mask)
53  msg += "aspect,";
54  if (COMM_FRAME_RATING_SYMBOL & mask)
55  msg += "rating,";
56 
57  if (!msg.isEmpty())
58  msg = msg.left(msg.length() - 1);
59  else
60  msg = "noflags";
61  }
62  else
63  {
64  msg += (COMM_FRAME_SKIPPED & mask) ? "s" : " ";
65  msg += (COMM_FRAME_BLANK & mask) ? "B" : " ";
66  msg += (COMM_FRAME_SCENE_CHANGE & mask) ? "S" : " ";
67  msg += (COMM_FRAME_LOGO_PRESENT & mask) ? "L" : " ";
68  msg += (COMM_FRAME_ASPECT_CHANGE & mask) ? "A" : " ";
69  msg += (COMM_FRAME_RATING_SYMBOL & mask) ? "R" : " ";
70  }
71 
72  return msg;
73 }
74 
75 static QString toStringFrameAspects(int aspect, bool verbose)
76 {
77  if (verbose)
78  return (COMM_ASPECT_NORMAL == aspect) ? "normal" : " wide ";
79  return (COMM_ASPECT_NORMAL == aspect) ? "n" : "w";
80 }
81 
82 static QString toStringFrameFormats(int format, bool verbose)
83 {
84  switch (format)
85  {
86  case COMM_FORMAT_NORMAL:
87  return (verbose) ? "normal" : " N ";
89  return (verbose) ? "letter" : " L ";
91  return (verbose) ? "pillar" : " P ";
93  return (verbose) ? "letter,pillar" : "L,P";
94  case COMM_FORMAT_MAX:
95  return (verbose) ? " max " : " M ";
96  }
97 
98  return (verbose) ? "unknown" : " U ";
99 }
100 
102 {
103  return {" frame min/max/avg scene aspect format flags"};
104 }
105 
106 QString FrameInfoEntry::toString(uint64_t frame, bool verbose) const
107 {
108  return QString(
109  "%1: %2/%3/%4 %5% %6 %7 %8")
110  .arg(frame,10)
111  .arg(minBrightness,3)
112  .arg(maxBrightness,3)
113  .arg(avgBrightness,3)
114  .arg(sceneChangePercent,3)
118 }
119 
121  bool showProgress_in,
122  bool fullSpeed_in,
123  MythCommFlagPlayer *player_in,
124  QDateTime startedAt_in,
125  QDateTime stopsAt_in,
126  QDateTime recordingStartedAt_in,
127  QDateTime recordingStopsAt_in) :
128 
129 
130  m_commDetectMethod(commDetectMethod_in),
131  m_player(player_in),
132  m_startedAt(std::move(startedAt_in)),
133  m_stopsAt(std::move(stopsAt_in)),
134  m_recordingStartedAt(std::move(recordingStartedAt_in)),
135  m_recordingStopsAt(std::move(recordingStopsAt_in)),
136  m_stillRecording(m_recordingStopsAt > MythDate::current()),
137  m_fullSpeed(fullSpeed_in),
138  m_showProgress(showProgress_in)
139 {
141  gCoreContext->GetNumSetting("CommDetectBlankFrameMaxDiff", 25);
143  gCoreContext->GetNumSetting("CommDetectDarkBrightness", 80);
145  gCoreContext->GetNumSetting("CommDetectDimBrightness", 120);
147  gCoreContext->GetNumSetting("CommDetectBoxBrightness", 30);
149  gCoreContext->GetNumSetting("CommDetectDimAverage", 35);
151  gCoreContext->GetNumSetting("CommDetectMaxCommBreakLength", 395);
153  gCoreContext->GetNumSetting("CommDetectMinCommBreakLength", 60);
155  gCoreContext->GetNumSetting("CommDetectMinShowLength", 65);
157  gCoreContext->GetNumSetting("CommDetectMaxCommLength", 125);
158 
160  !!gCoreContext->GetBoolSetting("CommDetectBlankCanHaveLogo", true);
161 }
162 
164 {
165  QSize video_disp_dim = m_player->GetVideoSize();
166  m_width = video_disp_dim.width();
167  m_height = video_disp_dim.height();
169 
170  m_preRoll = (long long)(
171  std::max(int64_t(0), int64_t(m_recordingStartedAt.secsTo(m_startedAt))) * m_fps);
172  m_postRoll = (long long)(
173  std::max(int64_t(0), int64_t(m_stopsAt.secsTo(m_recordingStopsAt))) * m_fps);
174 
175  // CommDetectBorder's default value of 20 predates the change to use
176  // ffmpeg's lowres decoding capability by 5 years.
177  // I believe it should be adjusted based on the height of the lowres video
178  // CommDetectBorder * height / 720 seems to produce reasonable results.
179  // source height = 480 gives border = 20 * 480 / 4 / 720 = 2
180  // source height = 720 gives border = 20 * 720 / 4 / 720 = 5
181  // source height = 1080 gives border = 20 * 1080 / 4 / 720 = 7
183  gCoreContext->GetNumSetting("CommDetectBorder", 20) * m_height / 720;
184 
185 #ifdef SHOW_DEBUG_WIN
186  comm_debug_init(m_width, m_height);
187 #endif
188 
190 
191  m_lastFrameNumber = -2;
192  m_curFrameNumber = -1;
193  m_verboseDebugging = qEnvironmentVariableIsSet("DEBUGCOMMFLAG");
194 
195  LOG(VB_COMMFLAG, LOG_INFO,
196  QString("Commercial Detection initialized: "
197  "width = %1, height = %2, fps = %3, method = %4")
198  .arg(m_width).arg(m_height)
200 
201  if ((m_width * m_height) > 1000000)
202  {
203  m_horizSpacing = 10;
204  m_vertSpacing = 10;
205  }
206  else if ((m_width * m_height) > 800000)
207  {
208  m_horizSpacing = 8;
209  m_vertSpacing = 8;
210  }
211  else if ((m_width * m_height) > 400000)
212  {
213  m_horizSpacing = 6;
214  m_vertSpacing = 6;
215  }
216  else if ((m_width * m_height) > 300000)
217  {
218  m_horizSpacing = 6;
219  m_vertSpacing = 4;
220  }
221  else
222  {
223  m_horizSpacing = 4;
224  m_vertSpacing = 4;
225  }
226 
227  LOG(VB_COMMFLAG, LOG_INFO,
228  QString("Using Sample Spacing of %1 horizontal & %2 vertical pixels.")
229  .arg(m_horizSpacing).arg(m_vertSpacing));
230 
231  m_framesProcessed = 0;
233  m_blankFrameCount = 0;
234 
235  m_aggressiveDetection = true;
238 
239  m_lastSentCommBreakMap.clear();
240 
241  // Check if close to 4:3
242  if (fabs(((m_width*1.0)/m_height) - 1.333333) < 0.1)
244 
247  connect(
250  this,
252  );
253 
254  m_frameIsBlank = false;
255  m_stationLogoPresent = false;
256 
257  m_logoInfoAvailable = false;
258 
259  ClearAllMaps();
260 
261  if (m_verboseDebugging)
262  {
263  LOG(VB_COMMFLAG, LOG_DEBUG,
264  " Fr # Min Max Avg Scn F A Mask");
265  LOG(VB_COMMFLAG, LOG_DEBUG,
266  " ------ --- --- --- --- - - ----");
267  }
268 }
269 
271 {
273  m_sceneChangeDetector->deleteLater();
274 
275  if (m_logoDetector)
276  m_logoDetector->deleteLater();
277 
278  CommDetectorBase::deleteLater();
279 }
280 
282 {
283  int secsSince = 0;
284  int requiredBuffer = 30;
285  int requiredHeadStart = requiredBuffer;
286  bool wereRecording = m_stillRecording;
287 
288  emit statusUpdate(QCoreApplication::translate("(mythcommflag)",
289  "Building Head Start Buffer"));
290  secsSince = m_recordingStartedAt.secsTo(MythDate::current());
291  while (m_stillRecording && (secsSince < requiredHeadStart))
292  {
293  emit breathe();
294  if (m_bStop)
295  return false;
296 
297  std::this_thread::sleep_for(2s);
298  secsSince = m_recordingStartedAt.secsTo(MythDate::current());
299  }
300 
301  if (m_player->OpenFile() < 0)
302  return false;
303 
304  Init();
305 
307  {
308  // Use a different border for logo detection.
309  // If we try to detect logos in letterboxed areas,
310  // chances are we won't detect the logo.
311  // Generally speaking, SD video is likely to be letter boxed
312  // and HD video is not likely to be letter boxed.
313  // To detect logos, try to exclude letterboxed area from SD video
314  // but exclude too much from HD video and you'll miss the logo.
315  // Using the same border for both with no scaling seems to be
316  // a good compromise.
317  int logoDetectBorder =
318  gCoreContext->GetNumSetting("CommDetectLogoBorder", 16);
320  logoDetectBorder);
321 
322  requiredHeadStart += std::max(
323  int64_t(0), int64_t(m_recordingStartedAt.secsTo(m_startedAt)));
324  requiredHeadStart += m_logoDetector->getRequiredAvailableBufferForSearch();
325 
326  emit statusUpdate(QCoreApplication::translate("(mythcommflag)",
327  "Building Logo Detection Buffer"));
328  secsSince = m_recordingStartedAt.secsTo(MythDate::current());
329  while (m_stillRecording && (secsSince < requiredHeadStart))
330  {
331  emit breathe();
332  if (m_bStop)
333  return false;
334 
335  std::this_thread::sleep_for(2s);
336  secsSince = m_recordingStartedAt.secsTo(MythDate::current());
337  }
338  }
339 
340  // Don't bother flagging short ~realtime recordings
341  if ((wereRecording) && (!m_stillRecording) && (secsSince < requiredHeadStart))
342  return false;
343 
345  gCoreContext->GetBoolSetting("AggressiveCommDetect", true);
346 
347  if (!m_player->InitVideo())
348  {
349  LOG(VB_GENERAL, LOG_ERR,
350  "NVP: Unable to initialize video for FlagCommercials.");
351  return false;
352  }
353 
355  {
356  emit statusUpdate(QCoreApplication::translate("(mythcommflag)",
357  "Searching for Logo"));
358 
359  if (m_showProgress)
360  {
361  std::cerr << "Finding Logo";
362  std::cerr.flush();
363  }
364  LOG(VB_GENERAL, LOG_INFO, "Finding Logo");
365 
367  if (!m_logoInfoAvailable)
368  {
370  {
371  LOG(VB_COMMFLAG, LOG_WARNING, "No logo found, abort flagging.");
372  return false;
373  }
374  }
375 
376  if (m_showProgress)
377  {
378  std::cerr << "\b\b\b\b\b\b\b\b\b\b\b\b "
379  "\b\b\b\b\b\b\b\b\b\b\b\b";
380  std::cerr.flush();
381  }
382  }
383 
384  emit breathe();
385  if (m_bStop)
386  return false;
387 
388  QElapsedTimer flagTime;
389  flagTime.start();
390 
391  long long myTotalFrames = 0;
393  myTotalFrames = m_player->GetTotalFrameCount();
394  else
395  myTotalFrames = (long long)(m_player->GetFrameRate() *
397 
398  if (m_showProgress)
399  {
400  if (myTotalFrames)
401  std::cerr << "\r 0%/ \r" << std::flush;
402  else
403  std::cerr << "\r 0/ \r" << std::flush;
404  }
405 
406 
407  float aspect = m_player->GetVideoAspect();
408  int prevpercent = -1;
409 
410  SetVideoParams(aspect);
411 
412  emit breathe();
413 
415 
416  while (m_player->GetEof() == kEofStateNone)
417  {
418  std::chrono::microseconds startTime {0us};
419  if (m_stillRecording)
420  startTime = nowAsDuration<std::chrono::microseconds>();
421 
422  MythVideoFrame* currentFrame = m_player->GetRawVideoFrame();
423  long long currentFrameNumber = currentFrame->m_frameNumber;
424 
425  //Lucas: maybe we should make the nuppelvideoplayer send out a signal
426  //when the aspect ratio changes.
427  //In order to not change too many things at a time, I"m using basic
428  //polling for now.
429  float newAspect = currentFrame->m_aspect;
430  if (newAspect != aspect)
431  {
432  SetVideoParams(aspect);
433  aspect = newAspect;
434  }
435 
436  if (((currentFrameNumber % 500) == 0) ||
437  (((currentFrameNumber % 100) == 0) &&
438  (m_stillRecording)))
439  {
440  emit breathe();
441  if (m_bStop)
442  {
443  m_player->DiscardVideoFrame(currentFrame);
444  return false;
445  }
446  }
447 
450  ((currentFrameNumber % 500) == 0)))
451  {
452  frm_dir_map_t commBreakMap;
453  frm_dir_map_t::iterator it;
454  frm_dir_map_t::iterator lastIt;
455  bool mapsAreIdentical = false;
456 
457  GetCommercialBreakList(commBreakMap);
458 
459  if ((commBreakMap.empty()) &&
460  (m_lastSentCommBreakMap.empty()))
461  {
462  mapsAreIdentical = true;
463  }
464  else if (commBreakMap.size() == m_lastSentCommBreakMap.size())
465  {
466  // assume true for now and set false if we find a difference
467  mapsAreIdentical = true;
468  for (it = commBreakMap.begin();
469  it != commBreakMap.end() && mapsAreIdentical; ++it)
470  {
471  lastIt = m_lastSentCommBreakMap.find(it.key());
472  if ((lastIt == m_lastSentCommBreakMap.end()) ||
473  (*lastIt != *it))
474  mapsAreIdentical = false;
475  }
476  }
477 
478  if (m_commBreakMapUpdateRequested || !mapsAreIdentical)
479  {
481  m_lastSentCommBreakMap = commBreakMap;
482  }
483 
486  }
487 
488  while (m_bPaused)
489  {
490  emit breathe();
491  std::this_thread::sleep_for(1s);
492  }
493 
494  // sleep a little so we don't use all cpu even if we're niced
495  if (!m_fullSpeed && !m_stillRecording)
496  std::this_thread::sleep_for(10ms);
497 
498  if (((currentFrameNumber % 500) == 0) ||
500  ((currentFrameNumber % 100) == 0)))
501  {
502  float flagFPS { 0.0 };
503  float elapsed = flagTime.elapsed() / 1000.0;
504 
505  if (elapsed != 0.0F)
506  flagFPS = currentFrameNumber / elapsed;
507  else
508  flagFPS = 0.0;
509 
510  int percentage = 0;
511  if (myTotalFrames)
512  percentage = currentFrameNumber * 100 / myTotalFrames;
513 
514  if (percentage > 100)
515  percentage = 100;
516 
517  if (m_showProgress)
518  {
519  if (myTotalFrames)
520  {
521  QString tmp = QString("\r%1%/%2fps \r")
522  .arg(percentage, 3).arg((int)flagFPS, 4);
523  std::cerr << qPrintable(tmp) << std::flush;
524  }
525  else
526  {
527  QString tmp = QString("\r%1/%2fps \r")
528  .arg(currentFrameNumber, 6).arg((int)flagFPS, 4);
529  std::cerr << qPrintable(tmp) << std::flush;
530  }
531  }
532 
533  if (myTotalFrames)
534  {
535  emit statusUpdate(QCoreApplication::translate("(mythcommflag)",
536  "%1% Completed @ %2 fps.")
537  .arg(percentage).arg(flagFPS));
538  }
539  else
540  {
541  emit statusUpdate(QCoreApplication::translate("(mythcommflag)",
542  "%1 Frames Completed @ %2 fps.")
543  .arg(currentFrameNumber).arg(flagFPS));
544  }
545 
546  if (percentage % 10 == 0 && prevpercent != percentage)
547  {
548  prevpercent = percentage;
549  LOG(VB_GENERAL, LOG_INFO, QString("%1%% Completed @ %2 fps.")
550  .arg(percentage) .arg(flagFPS));
551  }
552  }
553 
554  ProcessFrame(currentFrame, currentFrameNumber);
555 
556  if (m_stillRecording)
557  {
558  int secondsRecorded =
560  int secondsFlagged = (int)(m_framesProcessed / m_fps);
561  int secondsBehind = secondsRecorded - secondsFlagged;
562  auto usecPerFrame = floatusecs(1000000.0F / m_player->GetFrameRate());
563 
564  auto endTime = nowAsDuration<std::chrono::microseconds>();
565 
566  floatusecs usecSleep = usecPerFrame - (endTime - startTime);
567 
568  if (secondsBehind > requiredBuffer)
569  {
570  if (m_fullSpeed)
571  usecSleep = 0us;
572  else
573  usecSleep = usecSleep * 0.25;
574  }
575  else if (secondsBehind < requiredBuffer)
576  usecSleep = usecPerFrame * 1.5;
577 
578  if (usecSleep > 0us)
579  std::this_thread::sleep_for(usecSleep);
580  }
581 
582  m_player->DiscardVideoFrame(currentFrame);
583  }
584 
585  if (m_showProgress)
586  {
587 #if 0
588  float elapsed = flagTime.elapsed() / 1000.0;
589 
590  if (elapsed)
591  flagFPS = currentFrameNumber / elapsed;
592  else
593  flagFPS = 0.0;
594 #endif
595 
596  if (myTotalFrames)
597  std::cerr << "\b\b\b\b\b\b \b\b\b\b\b\b";
598  else
599  std::cerr << "\b\b\b\b\b\b\b\b\b\b\b\b\b "
600  "\b\b\b\b\b\b\b\b\b\b\b\b\b";
601  std::cerr.flush();
602  }
603 
604  return true;
605 }
606 
608  unsigned int framenum,bool isSceneChange,float debugValue)
609 {
610  if (isSceneChange)
611  {
612  m_frameInfo[framenum].flagMask |= COMM_FRAME_SCENE_CHANGE;
613  m_sceneMap[framenum] = MARK_SCENE_CHANGE;
614  }
615  else
616  {
617  m_frameInfo[framenum].flagMask &= ~COMM_FRAME_SCENE_CHANGE;
618  m_sceneMap.remove(framenum);
619  }
620 
621  m_frameInfo[framenum].sceneChangePercent = (int) (debugValue*100);
622 }
623 
625 {
626 
627  LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::GetCommBreakMap()");
628 
629  marks.clear();
630 
632 
633  bool blank = (COMM_DETECT_BLANK & m_commDetectMethod) != 0;
634  bool scene = (COMM_DETECT_SCENE & m_commDetectMethod) != 0;
635  bool logo = (COMM_DETECT_LOGO & m_commDetectMethod) != 0;
636 
638  return;
639 
640  if (!blank && !scene && !logo)
641  {
642  LOG(VB_COMMFLAG, LOG_ERR, QString("Unexpected commDetectMethod: 0x%1")
643  .arg(m_commDetectMethod,0,16));
644  return;
645  }
646 
647  if (blank && scene && logo)
648  {
651  LOG(VB_COMMFLAG, LOG_INFO, "Final Commercial Break Map");
652  return;
653  }
654 
655  if (blank)
656  {
659  }
660 
661  if (scene)
662  {
665  }
666 
667  if (logo)
668  {
671  }
672 
673  int cnt = ((blank) ? 1 : 0) + ((scene) ? 1 : 0) + ((logo) ? 1 : 0);
674  if (cnt == 2)
675  {
676  if (blank && scene)
677  {
680  }
681  else if (blank && logo)
682  {
685  }
686  else if (scene && logo)
687  {
690  }
691  }
692 
693  LOG(VB_COMMFLAG, LOG_INFO, "Final Commercial Break Map");
694 }
695 
696 void ClassicCommDetector::recordingFinished(long long totalFileSize)
697 {
698  (void)totalFileSize;
699 
700  m_stillRecording = false;
701 }
702 
704 {
707 }
708 
710 {
711  int newAspect = COMM_ASPECT_WIDE;
712 
713  LOG(VB_COMMFLAG, LOG_INFO,
714  QString("CommDetect::SetVideoParams called with aspect = %1")
715  .arg(aspect));
716  // Default to Widescreen but use the same check as VideoOutput::MoveResize()
717  // to determine if is normal 4:3 aspect
718  if (fabs(aspect - 1.333333F) < 0.1F)
719  newAspect = COMM_ASPECT_NORMAL;
720 
721  if (newAspect != m_currentAspect)
722  {
723  LOG(VB_COMMFLAG, LOG_INFO,
724  QString("Aspect Ratio changed from %1 to %2 at frame %3")
725  .arg(m_currentAspect).arg(newAspect)
726  .arg(m_curFrameNumber));
727 
728  if (m_frameInfo.contains(m_curFrameNumber))
729  {
730  // pretend that this frame is blank so that we can create test
731  // blocks on real aspect ratio change boundaries.
735  }
736  else if (m_curFrameNumber != -1)
737  {
738  LOG(VB_COMMFLAG, LOG_ERR,
739  QString("Unable to keep track of Aspect ratio change because "
740  "frameInfo for frame number %1 does not exist.")
741  .arg(m_curFrameNumber));
742  }
743  m_currentAspect = newAspect;
744  }
745 }
746 
748  long long frame_number)
749 {
750  int max = 0;
751  int min = 255;
752  int blankPixelsChecked = 0;
753  long long totBrightness = 0;
754  auto *rowMax = new unsigned char[m_height];
755  auto *colMax = new unsigned char[m_width];
756  memset(rowMax, 0, sizeof(*rowMax)*m_height);
757  memset(colMax, 0, sizeof(*colMax)*m_width);
758  int topDarkRow = m_commDetectBorder;
759  int bottomDarkRow = m_height - m_commDetectBorder - 1;
760  int leftDarkCol = m_commDetectBorder;
761  int rightDarkCol = m_width - m_commDetectBorder - 1;
762  FrameInfoEntry fInfo {};
763 
764  if (!frame || !(frame->m_buffer) || frame_number == -1 ||
765  frame->m_type != FMT_YV12)
766  {
767  LOG(VB_COMMFLAG, LOG_ERR, "CommDetect: Invalid video frame or codec, "
768  "unable to process frame.");
769  delete[] rowMax;
770  delete[] colMax;
771  return;
772  }
773 
774  if (!m_width || !m_height)
775  {
776  LOG(VB_COMMFLAG, LOG_ERR, "CommDetect: Width or Height is 0, "
777  "unable to process frame.");
778  delete[] rowMax;
779  delete[] colMax;
780  return;
781  }
782 
783  m_curFrameNumber = frame_number;
784  unsigned char* framePtr = frame->m_buffer;
785  int bytesPerLine = frame->m_pitches[0];
786 
787  fInfo.minBrightness = -1;
788  fInfo.maxBrightness = -1;
789  fInfo.avgBrightness = -1;
790  fInfo.sceneChangePercent = -1;
791  fInfo.aspect = m_currentAspect;
792  fInfo.format = COMM_FORMAT_NORMAL;
793  fInfo.flagMask = 0;
794 
795  int& flagMask = m_frameInfo[m_curFrameNumber].flagMask;
796 
797  // Fill in dummy info records for skipped frames.
798  if (m_lastFrameNumber != (m_curFrameNumber - 1))
799  {
800  if (m_lastFrameNumber > 0)
801  {
802  fInfo.aspect = m_frameInfo[m_lastFrameNumber].aspect;
803  fInfo.format = m_frameInfo[m_lastFrameNumber].format;
804  }
805  fInfo.flagMask = COMM_FRAME_SKIPPED;
806 
809  m_frameInfo[m_lastFrameNumber++] = fInfo;
810 
811  fInfo.flagMask = 0;
812  }
814 
815  m_frameInfo[m_curFrameNumber] = fInfo;
816 
818  m_frameIsBlank = false;
819 
821  {
823  }
824 
825  m_stationLogoPresent = false;
826 
827  for(int y = m_commDetectBorder; y < (m_height - m_commDetectBorder);
828  y += m_vertSpacing)
829  {
830  for(int x = m_commDetectBorder; x < (m_width - m_commDetectBorder);
831  x += m_horizSpacing)
832  {
833  uchar pixel = framePtr[y * bytesPerLine + x];
834 
836  {
837  bool checkPixel = false;
839  checkPixel = true;
840 
841  if (!m_logoInfoAvailable ||
843  checkPixel=true;
844 
845  if (checkPixel)
846  {
847  blankPixelsChecked++;
848  totBrightness += pixel;
849 
850  if (pixel < min)
851  min = pixel;
852 
853  if (pixel > max)
854  max = pixel;
855 
856  if (pixel > rowMax[y])
857  rowMax[y] = pixel;
858 
859  if (pixel > colMax[x])
860  colMax[x] = pixel;
861  }
862  }
863  }
864  }
865 
866  if ((m_commDetectMethod & COMM_DETECT_BLANKS) && blankPixelsChecked)
867  {
868  for(int y = m_commDetectBorder; y < (m_height - m_commDetectBorder);
869  y += m_vertSpacing)
870  {
871  if (rowMax[y] > m_commDetectBoxBrightness)
872  break;
873  topDarkRow = y;
874  }
875 
876  for(int y = m_commDetectBorder; y < (m_height - m_commDetectBorder);
877  y += m_vertSpacing)
878  if (rowMax[y] >= m_commDetectBoxBrightness)
879  bottomDarkRow = y;
880 
881  delete[] rowMax;
882  rowMax = nullptr;
883 
884  for(int x = m_commDetectBorder; x < (m_width - m_commDetectBorder);
885  x += m_horizSpacing)
886  {
887  if (colMax[x] > m_commDetectBoxBrightness)
888  break;
889  leftDarkCol = x;
890  }
891 
892  for(int x = m_commDetectBorder; x < (m_width - m_commDetectBorder);
893  x += m_horizSpacing)
894  if (colMax[x] >= m_commDetectBoxBrightness)
895  rightDarkCol = x;
896 
897  delete[] colMax;
898  colMax = nullptr;
899 
901  if ((topDarkRow > m_commDetectBorder) &&
902  (topDarkRow < (m_height * .20)) &&
903  (bottomDarkRow < (m_height - m_commDetectBorder)) &&
904  (bottomDarkRow > (m_height * .80)))
905  {
907  }
908  if ((leftDarkCol > m_commDetectBorder) &&
909  (leftDarkCol < (m_width * .20)) &&
910  (rightDarkCol < (m_width - m_commDetectBorder)) &&
911  (rightDarkCol > (m_width * .80)))
912  {
914  }
915 
916  int avg = totBrightness / blankPixelsChecked;
917 
918  m_frameInfo[m_curFrameNumber].minBrightness = min;
919  m_frameInfo[m_curFrameNumber].maxBrightness = max;
920  m_frameInfo[m_curFrameNumber].avgBrightness = avg;
921 
922  m_totalMinBrightness += min;
923  m_commDetectDimAverage = min + 10;
924 
925  // Is the frame really dark
926  if (((max - min) <= m_commDetectBlankFrameMaxDiff) &&
928  m_frameIsBlank = true;
929 
930  // Are we non-strict and the frame is blank
931  if ((!m_aggressiveDetection) &&
932  ((max - min) <= m_commDetectBlankFrameMaxDiff))
933  m_frameIsBlank = true;
934 
935  // Are we non-strict and the frame is dark
936  // OR the frame is dim and has a low avg brightness
937  if ((!m_aggressiveDetection) &&
938  ((max < m_commDetectDarkBrightness) ||
940  m_frameIsBlank = true;
941  }
942 
944  {
947  }
948 
949 #if 0
951  (CheckRatingSymbol()))
952  {
953  flagMask |= COMM_FRAME_RATING_SYMBOL;
954  }
955 #endif
956 
957  if (m_frameIsBlank)
958  {
960  flagMask |= COMM_FRAME_BLANK;
962  }
963 
965  flagMask |= COMM_FRAME_LOGO_PRESENT;
966 
967  //TODO: move this debugging code out of the perframe loop, and do it after
968  // we've processed all frames. this is because a scenechangedetector can
969  // now use a few frames to determine whether the frame a few frames ago was
970  // a scene change or not.. due to this lookahead possibility the values
971  // that are currently in the frameInfo array, might be changed a few frames
972  // from now. The ClassicSceneChangeDetector doesn't use this though. future
973  // scenechangedetectors might.
974 
975  if (m_verboseDebugging)
976  {
977  LOG(VB_COMMFLAG, LOG_DEBUG, QString("Frame: %1 -> %2 %3 %4 %5 %6 %7 %8")
978  .arg(m_curFrameNumber, 6)
979  .arg(m_frameInfo[m_curFrameNumber].minBrightness, 3)
980  .arg(m_frameInfo[m_curFrameNumber].maxBrightness, 3)
981  .arg(m_frameInfo[m_curFrameNumber].avgBrightness, 3)
982  .arg(m_frameInfo[m_curFrameNumber].sceneChangePercent, 3)
983  .arg(m_frameInfo[m_curFrameNumber].format, 1)
984  .arg(m_frameInfo[m_curFrameNumber].aspect, 1)
985  .arg(m_frameInfo[m_curFrameNumber].flagMask, 4, 16, QChar('0')));
986  }
987 
988 #ifdef SHOW_DEBUG_WIN
989  comm_debug_show(frame->buf);
990  getchar();
991 #endif
992 
994  delete[] rowMax;
995  delete[] colMax;
996 }
997 
999 {
1000  LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::ClearAllMaps()");
1001 
1002  m_frameInfo.clear();
1003  m_blankFrameMap.clear();
1004  m_blankCommMap.clear();
1005  m_blankCommBreakMap.clear();
1006  m_sceneMap.clear();
1007  m_sceneCommBreakMap.clear();
1008  m_commBreakMap.clear();
1009 }
1010 
1012 {
1013  LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::GetBlankCommMap()");
1014 
1015  if (m_blankCommMap.isEmpty())
1017 
1018  comms = m_blankCommMap;
1019 }
1020 
1022 {
1023  LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::GetBlankCommBreakMap()");
1024 
1025  if (m_blankCommBreakMap.isEmpty())
1027 
1028  comms = m_blankCommBreakMap;
1029 }
1030 
1032  int64_t start_frame)
1033 {
1034  LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::GetSceneChangeMap()");
1035 
1036  frm_dir_map_t::iterator it;
1037 
1038  if (start_frame == -1)
1039  scenes.clear();
1040 
1041  for (it = m_sceneMap.begin(); it != m_sceneMap.end(); ++it)
1042  if ((start_frame == -1) || ((int64_t)it.key() >= start_frame))
1043  scenes[it.key()] = *it;
1044 }
1045 
1047  const frm_dir_map_t &b) const
1048 {
1049  LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::BuildMasterCommList()");
1050 
1051  frm_dir_map_t newMap;
1052 
1053  if (!a.empty())
1054  {
1055  frm_dir_map_t::const_iterator it = a.begin();
1056  for (; it != a.end(); ++it)
1057  newMap[it.key()] = *it;
1058  }
1059 
1060  if ((a.size() > 1) &&
1061  (b.size() > 1))
1062  {
1063  // see if beginning of the recording looks like a commercial
1064  frm_dir_map_t::const_iterator it_a;
1065  frm_dir_map_t::const_iterator it_b;
1066 
1067  it_a = a.begin();
1068  it_b = b.begin();
1069 
1070  if ((it_b.key() < 2) && (it_a.key() > 2))
1071  {
1072  newMap.remove(it_a.key());
1073  newMap[0] = MARK_COMM_START;
1074  }
1075 
1076 
1077  // see if ending of recording looks like a commercial
1078  frm_dir_map_t::const_iterator it;
1079  uint64_t max_a = 0;
1080  uint64_t max_b = 0;
1081 
1082  it = a.begin();
1083  for (; it != a.end(); ++it)
1084  {
1085  if ((*it == MARK_COMM_END) && (it.key() > max_a))
1086  max_a = it.key();
1087  }
1088 
1089  it = b.begin();
1090  for (; it != b.end(); ++it)
1091  {
1092  if ((*it == MARK_COMM_END) && (it.key() > max_b))
1093  max_b = it.key();
1094  }
1095 
1096  if ((max_a < (m_framesProcessed - 2)) &&
1097  (max_b > (m_framesProcessed - 2)))
1098  {
1099  newMap.remove(max_a);
1100  newMap[m_framesProcessed] = MARK_COMM_END;
1101  }
1102  }
1103 
1104  if ((a.size() > 3) &&
1105  (b.size() > 1))
1106  {
1107  frm_dir_map_t::const_iterator it_a;
1108  frm_dir_map_t::const_iterator it_b;
1109 
1110  it_a = a.begin();
1111  ++it_a;
1112  it_b = it_a;
1113  ++it_b;
1114  while (it_b != a.end())
1115  {
1116  uint64_t fdiff = it_b.key() - it_a.key();
1117  bool allTrue = false;
1118 
1119  if (fdiff < (62 * m_fps))
1120  {
1121  uint64_t f = it_a.key() + 1;
1122 
1123  allTrue = true;
1124 
1125  while ((f <= m_framesProcessed) && (f < it_b.key()) && (allTrue))
1126  allTrue = FrameIsInBreakMap(f++, b);
1127  }
1128 
1129  if (allTrue)
1130  {
1131  newMap.remove(it_a.key());
1132  newMap.remove(it_b.key());
1133  }
1134 
1135  ++it_a; ++it_a;
1136  ++it_b;
1137  if (it_b != a.end())
1138  ++it_b;
1139  }
1140  }
1141 
1142  return newMap;
1143 }
1144 
1146  const FrameInfoEntry& finfo,
1147  int format, int aspect)
1148 {
1149  int value = 0;
1150 
1151  value = finfo.flagMask;
1152 
1153  if (value & COMM_FRAME_LOGO_PRESENT)
1154  fbp->logoCount++;
1155 
1156  if (value & COMM_FRAME_RATING_SYMBOL)
1157  fbp->ratingCount++;
1158 
1159  if (value & COMM_FRAME_SCENE_CHANGE)
1160  fbp->scCount++;
1161 
1162  if (finfo.format == format)
1163  fbp->formatMatch++;
1164 
1165  if (finfo.aspect == aspect)
1166  fbp->aspectMatch++;
1167 }
1168 
1170 {
1171  LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::BuildAllMethodsCommList()");
1172 
1173  int lastScore = 0;
1174  uint64_t lastStart = 0;
1175  uint64_t lastEnd = 0;
1176  int64_t firstLogoFrame = -1;
1177  int format = COMM_FORMAT_NORMAL;
1178  int aspect = COMM_ASPECT_NORMAL;
1179  QString msg;
1180  std::array<uint64_t,COMM_FORMAT_MAX> formatCounts {};
1181  frm_dir_map_t tmpCommMap;
1182  frm_dir_map_t::iterator it;
1183 
1184  m_commBreakMap.clear();
1185 
1186  auto *fblock = new FrameBlock[m_blankFrameCount + 2];
1187 
1188  int curBlock = 0;
1189  uint64_t curFrame = 1;
1190 
1191  FrameBlock *fbp = &fblock[curBlock];
1192  fbp->start = 0;
1193  fbp->bfCount = 0;
1194  fbp->logoCount = 0;
1195  fbp->ratingCount = 0;
1196  fbp->scCount = 0;
1197  fbp->scRate = 0.0;
1198  fbp->formatMatch = 0;
1199  fbp->aspectMatch = 0;
1200  fbp->score = 0;
1201 
1202  bool lastFrameWasBlank = true;
1203 
1205  {
1206  uint64_t aspectFrames = 0;
1207  for (int64_t i = m_preRoll;
1208  i < ((int64_t)m_framesProcessed - (int64_t)m_postRoll); i++)
1209  {
1210  if ((m_frameInfo.contains(i)) &&
1211  (m_frameInfo[i].aspect == COMM_ASPECT_NORMAL))
1212  aspectFrames++;
1213  }
1214 
1215  if (aspectFrames < ((m_framesProcessed - m_preRoll - m_postRoll) / 2))
1216  {
1217  aspect = COMM_ASPECT_WIDE;
1218 // aspectFrames = m_framesProcessed - m_preRoll - m_postRoll - aspectFrames;
1219  }
1220  }
1221  else
1222  {
1223  formatCounts.fill(0);
1224 
1225  for(int64_t i = m_preRoll;
1226  i < ((int64_t)m_framesProcessed - (int64_t)m_postRoll); i++ )
1227  {
1228  if ((m_frameInfo.contains(i)) &&
1229  (m_frameInfo[i].format >= 0) &&
1230  (m_frameInfo[i].format < COMM_FORMAT_MAX))
1231  formatCounts[m_frameInfo[i].format]++;
1232  }
1233 
1234  uint64_t formatFrames = 0;
1235  for(int i = 0; i < COMM_FORMAT_MAX; i++)
1236  {
1237  if (formatCounts[i] > formatFrames)
1238  {
1239  format = i;
1240  formatFrames = formatCounts[i];
1241  }
1242  }
1243  }
1244 
1245  while (curFrame <= m_framesProcessed)
1246  {
1247  int value = m_frameInfo[curFrame].flagMask;
1248 
1249  bool nextFrameIsBlank = ((curFrame + 1) <= m_framesProcessed) &&
1250  ((m_frameInfo[curFrame + 1].flagMask & COMM_FRAME_BLANK) != 0);
1251 
1252  if (value & COMM_FRAME_BLANK)
1253  {
1254  fbp->bfCount++;
1255 
1256  if (!nextFrameIsBlank || !lastFrameWasBlank)
1257  {
1258  UpdateFrameBlock(fbp, m_frameInfo[curFrame], format, aspect);
1259 
1260  fbp->end = curFrame;
1261  fbp->frames = fbp->end - fbp->start + 1;
1262  fbp->length = fbp->frames / m_fps;
1263 
1264  if ((fbp->scCount) && (fbp->length > 1.05))
1265  fbp->scRate = fbp->scCount / fbp->length;
1266 
1267  curBlock++;
1268 
1269  fbp = &fblock[curBlock];
1270  fbp->bfCount = 1;
1271  fbp->logoCount = 0;
1272  fbp->ratingCount = 0;
1273  fbp->scCount = 0;
1274  fbp->scRate = 0.0;
1275  fbp->score = 0;
1276  fbp->formatMatch = 0;
1277  fbp->aspectMatch = 0;
1278  fbp->start = curFrame;
1279  }
1280 
1281  lastFrameWasBlank = true;
1282  }
1283  else
1284  {
1285  lastFrameWasBlank = false;
1286  }
1287 
1288  UpdateFrameBlock(fbp, m_frameInfo[curFrame], format, aspect);
1289 
1290  if ((value & COMM_FRAME_LOGO_PRESENT) &&
1291  (firstLogoFrame == -1))
1292  firstLogoFrame = curFrame;
1293 
1294  curFrame++;
1295  }
1296 
1297  fbp->end = curFrame;
1298  fbp->frames = fbp->end - fbp->start + 1;
1299  fbp->length = fbp->frames / m_fps;
1300 
1301  if ((fbp->scCount) && (fbp->length > 1.05))
1302  fbp->scRate = fbp->scCount / fbp->length;
1303 
1304  int maxBlock = curBlock;
1305  curBlock = 0;
1306 // lastScore = 0;
1307 
1308  LOG(VB_COMMFLAG, LOG_INFO, "Initial Block pass");
1309  LOG(VB_COMMFLAG, LOG_DEBUG,
1310  "Block StTime StFrm EndFrm Frames Secs "
1311  "Bf Lg Cnt RT Cnt SC Cnt SC Rt FmtMch AspMch Score");
1312  LOG(VB_COMMFLAG, LOG_INFO,
1313  "----- ------ ------ ------ ------ ------- "
1314  "--- ------ ------ ------ ----- ------ ------ -----");
1315  while (curBlock <= maxBlock)
1316  {
1317  fbp = &fblock[curBlock];
1318 
1319  msg = FormatMsg(curBlock, fbp);
1320  LOG(VB_COMMFLAG, LOG_DEBUG, msg);
1321 
1322  if (fbp->frames > m_fps)
1323  {
1324  if (m_verboseDebugging)
1325  LOG(VB_COMMFLAG, LOG_DEBUG,
1326  QString(" FRAMES > %1").arg(m_fps));
1327 
1328  if (fbp->length > m_commDetectMaxCommLength)
1329  {
1330  if (m_verboseDebugging)
1331  LOG(VB_COMMFLAG, LOG_DEBUG,
1332  " length > max comm length, +20");
1333  fbp->score += 20;
1334  }
1335 
1337  {
1338  if (m_verboseDebugging)
1339  LOG(VB_COMMFLAG, LOG_DEBUG,
1340  " length > max comm break length, +20");
1341  fbp->score += 20;
1342  }
1343 
1344  if ((fbp->length > 4) &&
1345  (fbp->logoCount > (fbp->frames * 0.60)) &&
1346  (fbp->bfCount < (fbp->frames * 0.10)))
1347  {
1348  if (m_verboseDebugging)
1349  {
1350  LOG(VB_COMMFLAG, LOG_DEBUG,
1351  " length > 4 && logoCount > frames * 0.60 && "
1352  "bfCount < frames * .10");
1353  }
1355  {
1356  if (m_verboseDebugging)
1357  LOG(VB_COMMFLAG, LOG_DEBUG,
1358  " length > max comm break length, +20");
1359  fbp->score += 20;
1360  }
1361  else
1362  {
1363  if (m_verboseDebugging)
1364  LOG(VB_COMMFLAG, LOG_DEBUG,
1365  " length <= max comm break length, +10");
1366  fbp->score += 10;
1367  }
1368  }
1369 
1370  if ((m_logoInfoAvailable) &&
1371  (fbp->logoCount < (fbp->frames * 0.50)))
1372  {
1373  if (m_verboseDebugging)
1374  {
1375  LOG(VB_COMMFLAG, LOG_DEBUG,
1376  " logoInfoAvailable && logoCount < frames * .50, "
1377  "-10");
1378  }
1379  fbp->score -= 10;
1380  }
1381 
1382  if (fbp->ratingCount > (fbp->frames * 0.05))
1383  {
1384  if (m_verboseDebugging)
1385  LOG(VB_COMMFLAG, LOG_DEBUG,
1386  " rating symbol present > 5% of time, +20");
1387  fbp->score += 20;
1388  }
1389 
1390  if ((fbp->scRate > 1.0) &&
1391  (fbp->logoCount < (fbp->frames * .90)))
1392  {
1393  if (m_verboseDebugging)
1394  LOG(VB_COMMFLAG, LOG_DEBUG, " scRate > 1.0, -10");
1395  fbp->score -= 10;
1396 
1397  if (fbp->scRate > 2.0)
1398  {
1399  if (m_verboseDebugging)
1400  LOG(VB_COMMFLAG, LOG_DEBUG, " scRate > 2.0, -10");
1401  fbp->score -= 10;
1402  }
1403  }
1404 
1405  if ((!m_decoderFoundAspectChanges) &&
1406  (fbp->formatMatch < (fbp->frames * .10)))
1407  {
1408  if (m_verboseDebugging)
1409  {
1410  LOG(VB_COMMFLAG, LOG_DEBUG,
1411  " < 10% of frames match show letter/pillar-box "
1412  "format, -20");
1413  }
1414  fbp->score -= 20;
1415  }
1416 
1417  if ((abs((int)(fbp->frames - (15 * m_fps))) < 5 ) ||
1418  (abs((int)(fbp->frames - (30 * m_fps))) < 6 ) ||
1419  (abs((int)(fbp->frames - (60 * m_fps))) < 8 ))
1420  {
1421  if (m_verboseDebugging)
1422  LOG(VB_COMMFLAG, LOG_DEBUG,
1423  " block appears to be standard comm length, -10");
1424  fbp->score -= 10;
1425  }
1426  }
1427  else
1428  {
1429  if (m_verboseDebugging)
1430  LOG(VB_COMMFLAG, LOG_DEBUG,
1431  QString(" FRAMES <= %1").arg(m_fps));
1432 
1433  if ((m_logoInfoAvailable) &&
1434  (fbp->start >= firstLogoFrame) &&
1435  (fbp->logoCount == 0))
1436  {
1437  if (m_verboseDebugging)
1438  LOG(VB_COMMFLAG, LOG_DEBUG,
1439  " logoInfoAvailable && logoCount == 0, -10");
1440  fbp->score -= 10;
1441  }
1442 
1443  if ((!m_decoderFoundAspectChanges) &&
1444  (fbp->formatMatch < (fbp->frames * .10)))
1445  {
1446  if (m_verboseDebugging)
1447  {
1448  LOG(VB_COMMFLAG, LOG_DEBUG,
1449  " < 10% of frames match show letter/pillar-box "
1450  "format, -10");
1451  }
1452  fbp->score -= 10;
1453  }
1454 
1455  if (fbp->ratingCount > (fbp->frames * 0.25))
1456  {
1457  if (m_verboseDebugging)
1458  LOG(VB_COMMFLAG, LOG_DEBUG,
1459  " rating symbol present > 25% of time, +10");
1460  fbp->score += 10;
1461  }
1462  }
1463 
1465  (fbp->aspectMatch < (fbp->frames * .10)))
1466  {
1467  if (m_verboseDebugging)
1468  LOG(VB_COMMFLAG, LOG_DEBUG,
1469  " < 10% of frames match show aspect, -20");
1470  fbp->score -= 20;
1471  }
1472 
1473  msg = FormatMsg("NOW", fbp);
1474  LOG(VB_COMMFLAG, LOG_DEBUG, msg);
1475 
1476 // lastScore = fbp->score;
1477  curBlock++;
1478  }
1479 
1480  curBlock = 0;
1481  lastScore = 0;
1482 
1483  LOG(VB_COMMFLAG, LOG_DEBUG, "============================================");
1484  LOG(VB_COMMFLAG, LOG_INFO, "Second Block pass");
1485  LOG(VB_COMMFLAG, LOG_DEBUG,
1486  "Block StTime StFrm EndFrm Frames Secs "
1487  "Bf Lg Cnt RT Cnt SC Cnt SC Rt FmtMch AspMch Score");
1488  LOG(VB_COMMFLAG, LOG_DEBUG,
1489  "----- ------ ------ ------ ------ ------- "
1490  "--- ------ ------ ------ ----- ------ ------ -----");
1491  while (curBlock <= maxBlock)
1492  {
1493  fbp = &fblock[curBlock];
1494 
1495  msg = FormatMsg(curBlock, fbp);
1496  LOG(VB_COMMFLAG, LOG_DEBUG, msg);
1497 
1498  if ((curBlock > 0) && (curBlock < maxBlock))
1499  {
1500  int nextScore = fblock[curBlock + 1].score;
1501 
1502  if ((lastScore < 0) && (nextScore < 0) && (fbp->length < 35))
1503  {
1504  if (m_verboseDebugging)
1505  {
1506  LOG(VB_COMMFLAG, LOG_DEBUG,
1507  " lastScore < 0 && nextScore < 0 "
1508  "&& length < 35, setting -10");
1509  }
1510  fbp->score -= 10;
1511  }
1512 
1513  if ((fbp->bfCount > (fbp->frames * 0.95)) &&
1514  (fbp->frames < (2*m_fps)) &&
1515  (lastScore < 0 && nextScore < 0))
1516  {
1517  if (m_verboseDebugging)
1518  {
1519  LOG(VB_COMMFLAG, LOG_DEBUG,
1520  " blanks > frames * 0.95 && frames < 2*m_fps && "
1521  "lastScore < 0 && nextScore < 0, setting -10");
1522  }
1523  fbp->score -= 10;
1524  }
1525 
1526  if ((fbp->frames < (120*m_fps)) &&
1527  (lastScore < 0) &&
1528  (fbp->score > 0) &&
1529  (fbp->score < 20) &&
1530  (nextScore < 0))
1531  {
1532  if (m_verboseDebugging)
1533  {
1534  LOG(VB_COMMFLAG, LOG_DEBUG,
1535  " frames < 120 * m_fps && (-20 < lastScore < 0) && "
1536  "thisScore > 0 && nextScore < 0, setting score = -10");
1537  }
1538  fbp->score = -10;
1539  }
1540 
1541  if ((fbp->frames < (30*m_fps)) &&
1542  (lastScore > 0) &&
1543  (fbp->score < 0) &&
1544  (fbp->score > -20) &&
1545  (nextScore > 0))
1546  {
1547  if (m_verboseDebugging)
1548  {
1549  LOG(VB_COMMFLAG, LOG_DEBUG,
1550  " frames < 30 * m_fps && (0 < lastScore < 20) && "
1551  "thisScore < 0 && nextScore > 0, setting score = 10");
1552  }
1553  fbp->score = 10;
1554  }
1555  }
1556 
1557  if ((fbp->score == 0) && (lastScore > 30))
1558  {
1559  int offset = 1;
1560  while(((curBlock + offset) <= maxBlock) &&
1561  (fblock[curBlock + offset].frames < (2 * m_fps)) &&
1562  (fblock[curBlock + offset].score == 0))
1563  offset++;
1564 
1565  if ((curBlock + offset) <= maxBlock)
1566  {
1567  offset--;
1568  if (fblock[curBlock + offset + 1].score > 0)
1569  {
1570  for (; offset >= 0; offset--)
1571  {
1572  fblock[curBlock + offset].score += 10;
1573  if (m_verboseDebugging)
1574  {
1575  LOG(VB_COMMFLAG, LOG_DEBUG,
1576  QString(" Setting block %1 score +10")
1577  .arg(curBlock+offset));
1578  }
1579  }
1580  }
1581  else if (fblock[curBlock + offset + 1].score < 0)
1582  {
1583  for (; offset >= 0; offset--)
1584  {
1585  fblock[curBlock + offset].score -= 10;
1586  if (m_verboseDebugging)
1587  {
1588  LOG(VB_COMMFLAG, LOG_DEBUG,
1589  QString(" Setting block %1 score -10")
1590  .arg(curBlock+offset));
1591  }
1592  }
1593  }
1594  }
1595  }
1596 
1597  msg = FormatMsg("NOW", fbp);
1598  LOG(VB_COMMFLAG, LOG_DEBUG, msg);
1599 
1600  lastScore = fbp->score;
1601  curBlock++;
1602  }
1603 
1604  LOG(VB_COMMFLAG, LOG_DEBUG, "============================================");
1605  LOG(VB_COMMFLAG, LOG_INFO, "FINAL Block stats");
1606  LOG(VB_COMMFLAG, LOG_DEBUG,
1607  "Block StTime StFrm EndFrm Frames Secs "
1608  "Bf Lg Cnt RT Cnt SC Cnt SC Rt FmtMch AspMch Score");
1609  LOG(VB_COMMFLAG, LOG_DEBUG,
1610  "----- ------ ------ ------ ------ ------- "
1611  "--- ------ ------ ------ ----- ------ ------ -----");
1612  curBlock = 0;
1613  lastScore = 0;
1614  int64_t breakStart = -1;
1615  while (curBlock <= maxBlock)
1616  {
1617  fbp = &fblock[curBlock];
1618  int thisScore = fbp->score;
1619 
1620  if ((breakStart >= 0) &&
1621  ((fbp->end - breakStart) > (m_commDetectMaxCommBreakLength * m_fps)))
1622  {
1623  if (((fbp->start - breakStart) >
1625  (breakStart == 0))
1626  {
1627  if (m_verboseDebugging)
1628  {
1629  LOG(VB_COMMFLAG, LOG_DEBUG,
1630  QString("Closing commercial block at start of "
1631  "frame block %1 with length %2, frame "
1632  "block length of %3 frames would put comm "
1633  "block length over max of %4 seconds.")
1634  .arg(curBlock).arg(fbp->start - breakStart)
1635  .arg(fbp->frames)
1637  }
1638 
1639  m_commBreakMap[breakStart] = MARK_COMM_START;
1641  lastStart = breakStart;
1642  lastEnd = fbp->start;
1643  breakStart = -1;
1644  }
1645  else
1646  {
1647  if (m_verboseDebugging)
1648  {
1649  LOG(VB_COMMFLAG, LOG_DEBUG,
1650  QString("Ignoring what appears to be commercial"
1651  " block at frame %1 with length %2, "
1652  "length of %3 frames would put comm "
1653  "block length under min of %4 seconds.")
1654  .arg(breakStart)
1655  .arg(fbp->start - breakStart)
1656  .arg(fbp->frames)
1658  }
1659  breakStart = -1;
1660  }
1661  }
1662  if (thisScore == 0)
1663  {
1664  thisScore = lastScore;
1665  }
1666  else if (thisScore < 0)
1667  {
1668  if ((lastScore > 0) || (curBlock == 0))
1669  {
1670  if ((fbp->start - lastEnd) < (m_commDetectMinShowLength * m_fps))
1671  {
1672  m_commBreakMap.remove(lastStart);
1673  m_commBreakMap.remove(lastEnd);
1674  breakStart = lastStart;
1675 
1676  if (m_verboseDebugging)
1677  {
1678  if (breakStart)
1679  {
1680  LOG(VB_COMMFLAG, LOG_DEBUG,
1681  QString("ReOpening commercial block at "
1682  "frame %1 because show less than "
1683  "%2 seconds")
1684  .arg(breakStart)
1686  }
1687  else
1688  {
1689  LOG(VB_COMMFLAG, LOG_DEBUG,
1690  "Opening initial commercial block "
1691  "at start of recording, block 0.");
1692  }
1693  }
1694  }
1695  else
1696  {
1697  breakStart = fbp->start;
1698 
1699  if (m_verboseDebugging)
1700  {
1701  LOG(VB_COMMFLAG, LOG_DEBUG,
1702  QString("Starting new commercial block at "
1703  "frame %1 from start of frame block %2")
1704  .arg(fbp->start).arg(curBlock));
1705  }
1706  }
1707  }
1708  else if (curBlock == maxBlock)
1709  {
1710  if ((fbp->end - breakStart) >
1712  {
1713  if (fbp->end <=
1714  ((int64_t)m_framesProcessed - (int64_t)(2 * m_fps) - 2))
1715  {
1716  if (m_verboseDebugging)
1717  {
1718  LOG(VB_COMMFLAG, LOG_DEBUG,
1719  QString("Closing final commercial block at "
1720  "frame %1").arg(fbp->end));
1721  }
1722 
1723  m_commBreakMap[breakStart] = MARK_COMM_START;
1725  lastStart = breakStart;
1726  lastEnd = fbp->end;
1727  breakStart = -1;
1728  }
1729  }
1730  else
1731  {
1732  if (m_verboseDebugging)
1733  {
1734  LOG(VB_COMMFLAG, LOG_DEBUG,
1735  QString("Ignoring what appears to be commercial"
1736  " block at frame %1 with length %2, "
1737  "length of %3 frames would put comm "
1738  "block length under min of %4 seconds.")
1739  .arg(breakStart)
1740  .arg(fbp->start - breakStart)
1741  .arg(fbp->frames)
1743  }
1744  breakStart = -1;
1745  }
1746  }
1747  }
1748  // thisScore > 0
1749  else if ((lastScore < 0) &&
1750  (breakStart != -1))
1751  {
1752  if (((fbp->start - breakStart) >
1754  (breakStart == 0))
1755  {
1756  m_commBreakMap[breakStart] = MARK_COMM_START;
1758  lastStart = breakStart;
1759  lastEnd = fbp->start;
1760 
1761  if (m_verboseDebugging)
1762  {
1763  LOG(VB_COMMFLAG, LOG_DEBUG,
1764  QString("Closing commercial block at frame %1")
1765  .arg(fbp->start));
1766  }
1767  }
1768  else
1769  {
1770  if (m_verboseDebugging)
1771  {
1772  LOG(VB_COMMFLAG, LOG_DEBUG,
1773  QString("Ignoring what appears to be commercial "
1774  "block at frame %1 with length %2, "
1775  "length of %3 frames would put comm block "
1776  "length under min of %4 seconds.")
1777  .arg(breakStart)
1778  .arg(fbp->start - breakStart)
1779  .arg(fbp->frames)
1781  }
1782  }
1783  breakStart = -1;
1784  }
1785 
1786  msg = FormatMsg(curBlock, fbp);
1787  LOG(VB_COMMFLAG, LOG_DEBUG, msg);
1788 
1789  lastScore = thisScore;
1790  curBlock++;
1791  }
1792 
1793  if ((breakStart != -1) &&
1794  (breakStart <= ((int64_t)m_framesProcessed - (int64_t)(2 * m_fps) - 2)))
1795  {
1796  if (m_verboseDebugging)
1797  {
1798  LOG(VB_COMMFLAG, LOG_DEBUG,
1799  QString("Closing final commercial block started at "
1800  "block %1 and going to end of program. length "
1801  "is %2 frames")
1802  .arg(curBlock)
1803  .arg((m_framesProcessed - breakStart - 1)));
1804  }
1805 
1806  m_commBreakMap[breakStart] = MARK_COMM_START;
1807  // Create what is essentially an open-ended final skip region
1808  // by setting the end point 10 seconds past the end of the
1809  // recording.
1811  }
1812 
1813  // include/exclude blanks from comm breaks
1814  tmpCommMap = m_commBreakMap;
1815  m_commBreakMap.clear();
1816 
1817  if (m_verboseDebugging)
1818  LOG(VB_COMMFLAG, LOG_DEBUG,
1819  "Adjusting start/end marks according to blanks.");
1820  for (it = tmpCommMap.begin(); it != tmpCommMap.end(); ++it)
1821  {
1822  if (*it == MARK_COMM_START)
1823  {
1824  uint64_t lastStartLower = it.key();
1825  uint64_t lastStartUpper = it.key();
1826  while ((lastStartLower > 0) &&
1827  ((m_frameInfo[lastStartLower - 1].flagMask & COMM_FRAME_BLANK) != 0))
1828  lastStartLower--;
1829  while ((lastStartUpper < (m_framesProcessed - (2 * m_fps))) &&
1830  ((m_frameInfo[lastStartUpper + 1].flagMask & COMM_FRAME_BLANK) != 0))
1831  lastStartUpper++;
1832  uint64_t adj = (lastStartUpper - lastStartLower) / 2;
1833  if (adj > MAX_BLANK_FRAMES)
1834  adj = MAX_BLANK_FRAMES;
1835  lastStart = lastStartLower + adj;
1836 
1837  if (m_verboseDebugging)
1838  LOG(VB_COMMFLAG, LOG_DEBUG, QString("Start Mark: %1 -> %2")
1839  .arg(it.key()).arg(lastStart));
1840 
1841  m_commBreakMap[lastStart] = MARK_COMM_START;
1842  }
1843  else
1844  {
1845  uint64_t lastEndLower = it.key();
1846  uint64_t lastEndUpper = it.key();
1847  while ((lastEndUpper < (m_framesProcessed - (2 * m_fps))) &&
1848  ((m_frameInfo[lastEndUpper + 1].flagMask & COMM_FRAME_BLANK) != 0))
1849  lastEndUpper++;
1850  while ((lastEndLower > 0) &&
1851  ((m_frameInfo[lastEndLower - 1].flagMask & COMM_FRAME_BLANK) != 0))
1852  lastEndLower--;
1853  uint64_t adj = (lastEndUpper - lastEndLower) / 2;
1854  if (adj > MAX_BLANK_FRAMES)
1855  adj = MAX_BLANK_FRAMES;
1856  lastEnd = lastEndUpper - adj;
1857 
1858  if (m_verboseDebugging)
1859  LOG(VB_COMMFLAG, LOG_DEBUG, QString("End Mark : %1 -> %2")
1860  .arg(it.key()).arg(lastEnd));
1861 
1862  m_commBreakMap[lastEnd] = MARK_COMM_END;
1863  }
1864  }
1865 
1866  delete [] fblock;
1867 }
1868 
1869 
1871 {
1872  LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::BuildBlankFrameCommList()");
1873 
1874  if (m_blankFrameMap.count() == 0)
1875  return;
1876 
1877  auto *bframes = new long long[2_UZ * m_blankFrameMap.count()];
1878  auto *c_start = new long long[1_UZ * m_blankFrameMap.count()];
1879  auto *c_end = new long long[1_UZ * m_blankFrameMap.count()];
1880  int frames = 0;
1881  int commercials = 0;
1882 
1883  m_blankCommMap.clear();
1884 
1885  for (auto it = m_blankFrameMap.begin(); it != m_blankFrameMap.end(); ++it)
1886  bframes[frames++] = it.key();
1887 
1888  // detect individual commercials from blank frames
1889  // commercial end is set to frame right before ending blank frame to
1890  // account for instances with only a single blank frame between comms.
1891  for(int i = 0; i < frames; i++ )
1892  {
1893  for(int x=i+1; x < frames; x++ )
1894  {
1895  // check for various length spots since some channels don't
1896  // have blanks inbetween commercials just at the beginning and
1897  // end of breaks
1898  int gap_length = bframes[x] - bframes[i];
1899  if (((m_aggressiveDetection) &&
1900  ((abs((int)(gap_length - (5 * m_fps))) < 5 ) ||
1901  (abs((int)(gap_length - (10 * m_fps))) < 7 ) ||
1902  (abs((int)(gap_length - (15 * m_fps))) < 10 ) ||
1903  (abs((int)(gap_length - (20 * m_fps))) < 11 ) ||
1904  (abs((int)(gap_length - (30 * m_fps))) < 12 ) ||
1905  (abs((int)(gap_length - (40 * m_fps))) < 1 ) ||
1906  (abs((int)(gap_length - (45 * m_fps))) < 1 ) ||
1907  (abs((int)(gap_length - (60 * m_fps))) < 15 ) ||
1908  (abs((int)(gap_length - (90 * m_fps))) < 10 ) ||
1909  (abs((int)(gap_length - (120 * m_fps))) < 10 ))) ||
1910  ((!m_aggressiveDetection) &&
1911  ((abs((int)(gap_length - (5 * m_fps))) < 11 ) ||
1912  (abs((int)(gap_length - (10 * m_fps))) < 13 ) ||
1913  (abs((int)(gap_length - (15 * m_fps))) < 16 ) ||
1914  (abs((int)(gap_length - (20 * m_fps))) < 17 ) ||
1915  (abs((int)(gap_length - (30 * m_fps))) < 18 ) ||
1916  (abs((int)(gap_length - (40 * m_fps))) < 3 ) ||
1917  (abs((int)(gap_length - (45 * m_fps))) < 3 ) ||
1918  (abs((int)(gap_length - (60 * m_fps))) < 20 ) ||
1919  (abs((int)(gap_length - (90 * m_fps))) < 20 ) ||
1920  (abs((int)(gap_length - (120 * m_fps))) < 20 ))))
1921  {
1922  c_start[commercials] = bframes[i];
1923  c_end[commercials] = bframes[x] - 1;
1924  commercials++;
1925  i = x-1;
1926  x = frames;
1927  }
1928 
1929  if ((!m_aggressiveDetection) &&
1930  ((abs((int)(gap_length - (30 * m_fps))) < (int)(m_fps * 0.85)) ||
1931  (abs((int)(gap_length - (60 * m_fps))) < (int)(m_fps * 0.95)) ||
1932  (abs((int)(gap_length - (90 * m_fps))) < (int)(m_fps * 1.05)) ||
1933  (abs((int)(gap_length - (120 * m_fps))) < (int)(m_fps * 1.15))) &&
1934  ((x + 2) < frames) &&
1935  ((i + 2) < frames) &&
1936  ((bframes[i] + 1) == bframes[i+1]) &&
1937  ((bframes[x] + 1) == bframes[x+1]))
1938  {
1939  c_start[commercials] = bframes[i];
1940  c_end[commercials] = bframes[x];
1941  commercials++;
1942  i = x;
1943  x = frames;
1944  }
1945  }
1946  }
1947 
1948  int i = 0;
1949 
1950  // don't allow single commercial at head
1951  // of show unless followed by another
1952  if ((commercials > 1) &&
1953  (c_end[0] < (33 * m_fps)) &&
1954  (c_start[1] > (c_end[0] + 40 * m_fps)))
1955  i = 1;
1956 
1957  // eliminate any blank frames at end of commercials
1958  bool first_comm = true;
1959  for(; i < (commercials-1); i++)
1960  {
1961  long long r = c_start[i];
1962  long long adjustment = 0;
1963 
1964  if ((r < (30 * m_fps)) &&
1965  (first_comm))
1966  r = 1;
1967 
1969 
1970  r = c_end[i];
1971  if ( i < (commercials-1))
1972  {
1973  int x = 0;
1974  for(x = 0; x < (frames-1); x++)
1975  if (bframes[x] == r)
1976  break;
1977  while((x < (frames-1)) &&
1978  ((bframes[x] + 1 ) == bframes[x+1]) &&
1979  (bframes[x+1] < c_start[i+1]))
1980  {
1981  r++;
1982  x++;
1983  }
1984 
1985  while((m_blankFrameMap.contains(r+1)) &&
1986  (c_start[i+1] != (r+1)))
1987  {
1988  r++;
1989  adjustment++;
1990  }
1991  }
1992  else
1993  {
1994  while(m_blankFrameMap.contains(r+1))
1995  {
1996  r++;
1997  adjustment++;
1998  }
1999  }
2000 
2001  adjustment /= 2;
2002  if (adjustment > MAX_BLANK_FRAMES)
2003  adjustment = MAX_BLANK_FRAMES;
2004  r -= adjustment;
2006  first_comm = false;
2007  }
2008 
2009  m_blankCommMap[c_start[i]] = MARK_COMM_START;
2010  m_blankCommMap[c_end[i]] = MARK_COMM_END;
2011 
2012  delete[] c_start;
2013  delete[] c_end;
2014  delete[] bframes;
2015 
2016  LOG(VB_COMMFLAG, LOG_INFO, "Blank-Frame Commercial Map" );
2017  for(auto it = m_blankCommMap.begin(); it != m_blankCommMap.end(); ++it)
2018  LOG(VB_COMMFLAG, LOG_INFO, QString(" %1:%2")
2019  .arg(it.key()).arg(*it));
2020 
2022 
2023  LOG(VB_COMMFLAG, LOG_INFO, "Merged Blank-Frame Commercial Break Map" );
2024  for(auto it = m_blankCommBreakMap.begin(); it != m_blankCommBreakMap.end(); ++it)
2025  LOG(VB_COMMFLAG, LOG_INFO, QString(" %1:%2")
2026  .arg(it.key()).arg(*it));
2027 }
2028 
2029 
2031 {
2032  int section_start = -1;
2033  int seconds = (int)(m_framesProcessed / m_fps);
2034  int *sc_histogram = new int[seconds+1];
2035 
2036  m_sceneCommBreakMap.clear();
2037 
2038  memset(sc_histogram, 0, (seconds+1)*sizeof(int));
2039  for (uint64_t f = 1; f <= m_framesProcessed; f++)
2040  {
2041  if (m_sceneMap.contains(f))
2042  sc_histogram[(uint64_t)(f / m_fps)]++;
2043  }
2044 
2045  for(long long s = 0; s < (seconds + 1); s++)
2046  {
2047  if (sc_histogram[s] > 2)
2048  {
2049  if (section_start == -1)
2050  {
2051  auto f = (long long)(s * m_fps);
2052  for(int i = 0; i < m_fps; i++, f++)
2053  {
2054  if (m_sceneMap.contains(f))
2055  {
2057  i = (int)(m_fps) + 1;
2058  }
2059  }
2060  }
2061 
2062  section_start = s;
2063  }
2064 
2065  if ((section_start >= 0) &&
2066  (s > (section_start + 32)))
2067  {
2068  auto f = (long long)(section_start * m_fps);
2069  bool found_end = false;
2070 
2071  for(int i = 0; i < m_fps; i++, f++)
2072  {
2073  if (m_sceneMap.contains(f))
2074  {
2075  frm_dir_map_t::iterator dit = m_sceneCommBreakMap.find(f);
2076  if (dit != m_sceneCommBreakMap.end())
2077  m_sceneCommBreakMap.erase(dit);
2078  else
2080  i = (int)(m_fps) + 1;
2081  found_end = true;
2082  }
2083  }
2084  section_start = -1;
2085 
2086  if (!found_end)
2087  {
2088  f = (long long)(section_start * m_fps);
2090  }
2091  }
2092  }
2093  delete[] sc_histogram;
2094 
2095  if (section_start >= 0)
2097 
2098  frm_dir_map_t deleteMap;
2099  frm_dir_map_t::iterator it = m_sceneCommBreakMap.begin();
2100  frm_dir_map_t::iterator prev = it;
2101  if (it != m_sceneCommBreakMap.end())
2102  {
2103  ++it;
2104  while (it != m_sceneCommBreakMap.end())
2105  {
2106  if ((*it == MARK_COMM_END) &&
2107  (it.key() - prev.key()) < (30 * m_fps))
2108  {
2109  deleteMap[it.key()] = MARK_CUT_START;
2110  deleteMap[prev.key()] = MARK_CUT_START;
2111  }
2112  ++prev;
2113  if (it != m_sceneCommBreakMap.end())
2114  ++it;
2115  }
2116 
2117  frm_dir_map_t::iterator dit;
2118  for (dit = deleteMap.begin(); dit != deleteMap.end(); ++dit)
2119  m_sceneCommBreakMap.remove(dit.key());
2120  }
2121 
2122  LOG(VB_COMMFLAG, LOG_INFO, "Scene-Change Commercial Break Map" );
2123  for (it = m_sceneCommBreakMap.begin(); it != m_sceneCommBreakMap.end(); ++it)
2124  {
2125  LOG(VB_COMMFLAG, LOG_INFO, QString(" %1:%2")
2126  .arg(it.key()).arg(*it));
2127  }
2128 }
2129 
2130 
2132 {
2133  show_map_t showmap;
2134  GetLogoCommBreakMap(showmap);
2135  CondenseMarkMap(showmap, (int)(25 * m_fps), (int)(30 * m_fps));
2137 
2138  frm_dir_map_t::iterator it;
2139  LOG(VB_COMMFLAG, LOG_INFO, "Logo Commercial Break Map" );
2140  for(it = m_logoCommBreakMap.begin(); it != m_logoCommBreakMap.end(); ++it)
2141  LOG(VB_COMMFLAG, LOG_INFO, QString(" %1:%2")
2142  .arg(it.key()).arg(*it));
2143 }
2144 
2146 {
2147  frm_dir_map_t::iterator it;
2148  frm_dir_map_t::iterator prev;
2149  QMap<long long, long long> tmpMap;
2150  QMap<long long, long long>::Iterator tmpMap_it;
2151  QMap<long long, long long>::Iterator tmpMap_prev;
2152 
2153  m_blankCommBreakMap.clear();
2154 
2155  if (m_blankCommMap.isEmpty())
2156  return;
2157 
2158  for (it = m_blankCommMap.begin(); it != m_blankCommMap.end(); ++it)
2159  m_blankCommBreakMap[it.key()] = *it;
2160 
2161  if (m_blankCommBreakMap.isEmpty())
2162  return;
2163 
2164  it = m_blankCommMap.begin();
2165  prev = it;
2166  ++it;
2167  for(; it != m_blankCommMap.end(); ++it, ++prev)
2168  {
2169  // if next commercial starts less than 15*fps frames away then merge
2170  if ((((prev.key() + 1) == it.key()) ||
2171  ((prev.key() + (15 * m_fps)) > it.key())) &&
2172  (*prev == MARK_COMM_END) &&
2173  (*it == MARK_COMM_START))
2174  {
2175  m_blankCommBreakMap.remove(prev.key());
2176  m_blankCommBreakMap.remove(it.key());
2177  }
2178  }
2179 
2180 
2181  // make temp copy of commercial break list
2182  it = m_blankCommBreakMap.begin();
2183  prev = it;
2184  ++it;
2185  tmpMap[prev.key()] = it.key();
2186  for(; it != m_blankCommBreakMap.end(); ++it, ++prev)
2187  {
2188  if ((*prev == MARK_COMM_START) &&
2189  (*it == MARK_COMM_END))
2190  tmpMap[prev.key()] = it.key();
2191  }
2192 
2193  tmpMap_it = tmpMap.begin();
2194  tmpMap_prev = tmpMap_it;
2195  tmpMap_it++;
2196  for(; tmpMap_it != tmpMap.end(); ++tmpMap_it, ++tmpMap_prev)
2197  {
2198  // if we find any segments less than 35 seconds between commercial
2199  // breaks include those segments in the commercial break.
2200  if (((*tmpMap_prev + (35 * m_fps)) > tmpMap_it.key()) &&
2201  ((*tmpMap_prev - tmpMap_prev.key()) > (35 * m_fps)) &&
2202  ((*tmpMap_it - tmpMap_it.key()) > (35 * m_fps)))
2203  {
2204  m_blankCommBreakMap.remove(*tmpMap_prev);
2205  m_blankCommBreakMap.remove(tmpMap_it.key());
2206  }
2207  }
2208 }
2209 
2211  uint64_t f, const frm_dir_map_t &breakMap) const
2212 {
2213  for (uint64_t i = f; i < m_framesProcessed; i++)
2214  {
2215  if (breakMap.contains(i))
2216  {
2217  int type = breakMap[i];
2218  if ((type == MARK_COMM_END) || (i == f))
2219  return true;
2220  if (type == MARK_COMM_START)
2221  return false;
2222  }
2223  }
2224 
2225  // We want from f down to 0, but without wrapping the counter to negative
2226  // on an unsigned counter.
2227  for (uint64_t i = (f + 1); i-- > 0; )
2228  {
2229  if (breakMap.contains(i))
2230  {
2231  int type = breakMap[i];
2232  if ((type == MARK_COMM_START) || (i == f))
2233  return true;
2234  if (type == MARK_COMM_END)
2235  return false;
2236  }
2237  }
2238 
2239  return false;
2240 }
2241 
2243 {
2244  frm_dir_map_t::iterator it;
2245  QString msg;
2246 
2247  LOG(VB_COMMFLAG, LOG_INFO,
2248  "---------------------------------------------------");
2249  for (it = map.begin(); it != map.end(); ++it)
2250  {
2251  long long frame = it.key();
2252  int flag = *it;
2253  int my_fps = (int)ceil(m_fps);
2254  long long hour = (frame / my_fps) / 60 / 60;
2255  long long min = (frame / my_fps) / 60 - (hour * 60);
2256  long long sec = (frame / my_fps) - (min * 60) - (hour * 60 * 60);
2257  long long frm = frame - ((sec * my_fps) + (min * 60 * my_fps) +
2258  (hour * 60 * 60 * my_fps));
2259  int my_sec = (int)(frame / my_fps);
2260  msg = QString("%1 : %2 (%3:%4:%5.%6) (%7)")
2261  .arg(frame, 7).arg(flag).arg(hour, 2, 10, QChar('0')).arg(min, 2, 10, QChar('0'))
2262  .arg(sec, 2, 10, QChar('0')).arg(frm, 2, 10, QChar('0')).arg(my_sec);
2263  LOG(VB_COMMFLAG, LOG_INFO, msg);
2264  }
2265  LOG(VB_COMMFLAG, LOG_INFO,
2266  "---------------------------------------------------");
2267 }
2268 
2270  int length)
2271 {
2272  show_map_t::iterator it;
2273  show_map_t::iterator prev;
2274  show_map_t tmpMap;
2275 
2276  if (map.size() <= 2)
2277  return;
2278 
2279  // merge any segments less than 'spacing' frames apart from each other
2280  LOG(VB_COMMFLAG, LOG_INFO, "Commercial Map Before condense:" );
2281  for (it = map.begin(); it != map.end(); ++it)
2282  {
2283  LOG(VB_COMMFLAG, LOG_INFO, QString(" %1:%2")
2284  .arg(it.key()).arg(*it));
2285  tmpMap[it.key()] = *it;
2286  }
2287 
2288  prev = tmpMap.begin();
2289  it = prev;
2290  ++it;
2291  while (it != tmpMap.end())
2292  {
2293  if ((*it == MARK_START) &&
2294  (*prev == MARK_END) &&
2295  ((it.key() - prev.key()) < (uint64_t)spacing))
2296  {
2297  map.remove(prev.key());
2298  map.remove(it.key());
2299  }
2300  ++prev;
2301  ++it;
2302  }
2303 
2304  if (map.empty())
2305  return;
2306 
2307  // delete any segments less than 'length' frames in length
2308  tmpMap.clear();
2309  for (it = map.begin(); it != map.end(); ++it)
2310  tmpMap[it.key()] = *it;
2311 
2312  prev = tmpMap.begin();
2313  it = prev;
2314  ++it;
2315  while (it != tmpMap.end())
2316  {
2317  if ((*prev == MARK_START) &&
2318  (*it == MARK_END) &&
2319  ((it.key() - prev.key()) < (uint64_t)length))
2320  {
2321  map.remove(prev.key());
2322  map.remove(it.key());
2323  }
2324  ++prev;
2325  ++it;
2326  }
2327 
2328  LOG(VB_COMMFLAG, LOG_INFO, "Commercial Map After condense:" );
2329  for (it = map.begin(); it != map.end(); ++it)
2330  LOG(VB_COMMFLAG, LOG_INFO, QString(" %1:%2")
2331  .arg(it.key()).arg(*it));
2332 }
2333 
2335  frm_dir_map_t &out, const show_map_t &in)
2336 {
2337  out.clear();
2338  if (in.empty())
2339  return;
2340 
2341  show_map_t::const_iterator sit;
2342  for (sit = in.begin(); sit != in.end(); ++sit)
2343  {
2344  if (*sit == MARK_START)
2345  out[sit.key()] = MARK_COMM_END;
2346  else
2347  out[sit.key()] = MARK_COMM_START;
2348  }
2349 
2350  frm_dir_map_t::iterator it = out.begin();
2351  if (it == out.end())
2352  return;
2353 
2354  switch (out[it.key()])
2355  {
2356  case MARK_COMM_END:
2357  if (it.key() == 0)
2358  out.remove(0);
2359  else
2360  out[0] = MARK_COMM_START;
2361  break;
2362  case MARK_COMM_START:
2363  break;
2364  default:
2365  out.remove(0);
2366  break;
2367  }
2368 }
2369 
2370 
2371 /* ideas for this method ported back from comskip.c mods by Jere Jones
2372  * which are partially mods based on Myth's original commercial skip
2373  * code written by Chris Pinkham. */
2374 
2376 {
2377  LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::CleanupFrameInfo()");
2378 
2379  // try to account for noisy signal causing blank frames to be undetected
2380  if ((m_framesProcessed > (m_fps * 60)) &&
2381  (m_blankFrameCount < (m_framesProcessed * 0.0004)))
2382  {
2383  std::array<int,256> avgHistogram {};
2384  int minAvg = -1;
2385  int newThreshold = -1;
2386 
2387  LOG(VB_COMMFLAG, LOG_INFO,
2388  QString("ClassicCommDetect: Only found %1 blank frames but "
2389  "wanted at least %2, rechecking data using higher "
2390  "threshold.")
2391  .arg(m_blankFrameCount)
2392  .arg((int)(m_framesProcessed * 0.0004)));
2393  m_blankFrameMap.clear();
2394  m_blankFrameCount = 0;
2395 
2396  avgHistogram.fill(0);
2397 
2398  for (uint64_t i = 1; i <= m_framesProcessed; i++)
2399  avgHistogram[std::clamp(m_frameInfo[i].avgBrightness, 0, 255)] += 1;
2400 
2401  for (int i = 1; i <= 255 && minAvg == -1; i++)
2402  if (avgHistogram[i] > (m_framesProcessed * 0.0004))
2403  minAvg = i;
2404 
2405  newThreshold = minAvg + 3;
2406  LOG(VB_COMMFLAG, LOG_INFO,
2407  QString("Minimum Average Brightness on a frame "
2408  "was %1, will use %2 as new threshold")
2409  .arg(minAvg).arg(newThreshold));
2410 
2411  for (uint64_t i = 1; i <= m_framesProcessed; i++)
2412  {
2413  int value = m_frameInfo[i].flagMask;
2414  m_frameInfo[i].flagMask = value & ~COMM_FRAME_BLANK;
2415 
2416  if (( (m_frameInfo[i].flagMask & COMM_FRAME_BLANK) == 0) &&
2417  (m_frameInfo[i].avgBrightness < newThreshold))
2418  {
2419  m_frameInfo[i].flagMask = value | COMM_FRAME_BLANK;
2422  }
2423  }
2424 
2425  LOG(VB_COMMFLAG, LOG_INFO,
2426  QString("Found %1 blank frames using new value")
2427  .arg(m_blankFrameCount));
2428  }
2429 
2430  // try to account for fuzzy logo detection
2431  for (uint64_t i = 1; i <= m_framesProcessed; i++)
2432  {
2433  if ((i < 10) || ((i+10) > m_framesProcessed))
2434  continue;
2435 
2436  int before = 0;
2437  for (int offset = 1; offset <= 10; offset++)
2438  if ((m_frameInfo[i - offset].flagMask & COMM_FRAME_LOGO_PRESENT) != 0)
2439  before++;
2440 
2441  int after = 0;
2442  for (int offset = 1; offset <= 10; offset++)
2443  if ((m_frameInfo[i + offset].flagMask & COMM_FRAME_LOGO_PRESENT) != 0)
2444  after++;
2445 
2446  int value = m_frameInfo[i].flagMask;
2447  if (value == -1)
2448  m_frameInfo[i].flagMask = 0;
2449 
2450  if (value & COMM_FRAME_LOGO_PRESENT)
2451  {
2452  if ((before < 4) && (after < 4))
2453  m_frameInfo[i].flagMask = value & ~COMM_FRAME_LOGO_PRESENT;
2454  }
2455  else
2456  {
2457  if ((before > 6) && (after > 6))
2458  m_frameInfo[i].flagMask = value | COMM_FRAME_LOGO_PRESENT;
2459  }
2460  }
2461 }
2462 
2464 {
2465  LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::GetLogoCommBreakMap()");
2466 
2467  map.clear();
2468 
2469  bool PrevFrameLogo = false;
2470 
2471  for (uint64_t curFrame = 1 ; curFrame <= m_framesProcessed; curFrame++)
2472  {
2473  bool CurrentFrameLogo =
2474  (m_frameInfo[curFrame].flagMask & COMM_FRAME_LOGO_PRESENT) != 0;
2475 
2476  if (!PrevFrameLogo && CurrentFrameLogo)
2477  map[curFrame] = MARK_START;
2478  else if (PrevFrameLogo && !CurrentFrameLogo)
2479  map[curFrame] = MARK_END;
2480 
2481  PrevFrameLogo = CurrentFrameLogo;
2482  }
2483 }
2484 
2486 {
2487  emit breathe();
2488 }
2489 
2491  std::ostream &out, const frm_dir_map_t *comm_breaks, bool verbose) const
2492 {
2493  if (verbose)
2494  {
2495  QByteArray tmp = FrameInfoEntry::GetHeader().toLatin1();
2496  out << tmp.constData() << " mark" << std::endl;
2497  }
2498 
2499  for (long long i = 1; i < m_curFrameNumber; i++)
2500  {
2501  QMap<long long, FrameInfoEntry>::const_iterator it = m_frameInfo.find(i);
2502  if (it == m_frameInfo.end())
2503  continue;
2504 
2505  QByteArray atmp = (*it).toString(i, verbose).toLatin1();
2506  out << atmp.constData() << " ";
2507  if (comm_breaks)
2508  {
2509  frm_dir_map_t::const_iterator mit = comm_breaks->find(i);
2510  if (mit != comm_breaks->end())
2511  {
2512  QString tmp = (verbose) ?
2513  toString((MarkTypes)*mit) : QString::number(*mit);
2514  atmp = tmp.toLatin1();
2515 
2516  out << atmp.constData();
2517  }
2518  }
2519  out << "\n";
2520  }
2521 
2522  out << std::flush;
2523 }
2524 
2525 /* vim: set expandtab tabstop=4 shiftwidth=4: */
COMM_FRAME_SCENE_CHANGE
@ COMM_FRAME_SCENE_CHANGE
Definition: ClassicCommDetector.h:26
COMM_DETECT_SCENE
@ COMM_DETECT_SCENE
Definition: programtypes.h:135
ClassicCommDetector::m_lastFrameNumber
long long m_lastFrameNumber
Definition: ClassicCommDetector.h:154
ClassicCommDetector::deleteLater
virtual void deleteLater(void)
Definition: ClassicCommDetector.cpp:270
MythDate::toString
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:84
frameAspects
frameAspects
Definition: ClassicCommDetector.cpp:23
FrameInfoEntry::sceneChangePercent
int sceneChangePercent
Definition: ClassicCommDetector.h:38
COMM_DETECT_ALL
@ COMM_DETECT_ALL
Definition: programtypes.h:138
MARK_COMM_END
@ MARK_COMM_END
Definition: programtypes.h:61
frameFormats
frameFormats
Definition: ClassicCommDetector.cpp:31
COMM_FRAME_ASPECT_CHANGE
@ COMM_FRAME_ASPECT_CHANGE
Definition: ClassicCommDetector.h:28
show_map_t
QMap< uint64_t, CommMapValue > show_map_t
Definition: CommDetectorBase.h:19
ClassicCommDetector.h
ClassicLogoDetector.h
MythPlayer::GetTotalFrameCount
uint64_t GetTotalFrameCount(void) const
Definition: mythplayer.h:144
ClassicCommDetector::m_logoCommBreakMap
frm_dir_map_t m_logoCommBreakMap
Definition: ClassicCommDetector.h:177
FrameInfoEntry::maxBrightness
int maxBrightness
Definition: ClassicCommDetector.h:36
CommDetectorBase::m_bPaused
bool m_bPaused
Definition: CommDetectorBase.h:53
FrameInfoEntry::avgBrightness
int avgBrightness
Definition: ClassicCommDetector.h:37
ClassicCommDetector::m_recordingStartedAt
QDateTime m_recordingStartedAt
Definition: ClassicCommDetector.h:190
FrameFormats
enum frameFormats FrameFormats
ClassicCommDetector::m_width
int m_width
Definition: ClassicCommDetector.h:157
CommDetectorBase::breathe
void breathe()
kEofStateNone
@ kEofStateNone
Definition: decoderbase.h:69
ClassicCommDetector::ClassicCommDetector
ClassicCommDetector(SkipType commDetectMethod, bool showProgress, bool fullSpeed, MythCommFlagPlayer *player, QDateTime startedAt_in, QDateTime stopsAt_in, QDateTime recordingStartedAt_in, QDateTime recordingStopsAt_in)
Definition: ClassicCommDetector.cpp:120
ClassicCommDetector::FrameBlock::aspectMatch
int aspectMatch
Definition: ClassicCommDetector.h:88
ClassicCommDetector::m_recordingStopsAt
QDateTime m_recordingStopsAt
Definition: ClassicCommDetector.h:191
mythcommflagplayer.h
MythPlayer::OpenFile
virtual int OpenFile(int Retries=4)
Definition: mythplayer.cpp:426
ClassicCommDetector::m_commDetectBorder
int m_commDetectBorder
Definition: ClassicCommDetector.h:140
ClassicCommDetector::BuildLogoCommList
void BuildLogoCommList()
Definition: ClassicCommDetector.cpp:2131
CommDetectorBase::gotNewCommercialBreakList
void gotNewCommercialBreakList()
ClassicCommDetector::m_stationLogoPresent
bool m_stationLogoPresent
Definition: ClassicCommDetector.h:180
FrameAspects
enum frameAspects FrameAspects
COMM_ASPECT_WIDE
@ COMM_ASPECT_WIDE
Definition: ClassicCommDetector.cpp:25
COMM_FORMAT_PILLARBOX
@ COMM_FORMAT_PILLARBOX
Definition: ClassicCommDetector.cpp:34
ClassicCommDetector::ProcessFrame
void ProcessFrame(MythVideoFrame *frame, long long frame_number)
Definition: ClassicCommDetector.cpp:747
MARK_START
@ MARK_START
Definition: CommDetectorBase.h:14
ClassicCommDetector::m_commBreakMap
frm_dir_map_t m_commBreakMap
Definition: ClassicCommDetector.h:176
CommDetectorBase::statusUpdate
void statusUpdate(const QString &a)
frm_dir_map_t
QMap< uint64_t, MarkTypes > frm_dir_map_t
Frame # -> Mark map.
Definition: programtypes.h:119
ClassicCommDetector::UpdateFrameBlock
static void UpdateFrameBlock(FrameBlock *fbp, const FrameInfoEntry &finfo, int format, int aspect)
Definition: ClassicCommDetector.cpp:1145
ClassicCommDetector::logoDetectorBreathe
void logoDetectorBreathe()
Definition: ClassicCommDetector.cpp:2485
COMM_DETECT_OFF
@ COMM_DETECT_OFF
Definition: programtypes.h:132
LogoDetectorBase::searchForLogo
virtual bool searchForLogo(MythCommFlagPlayer *player)=0
MythPlayer::GetFrameRate
float GetFrameRate(void) const
Definition: mythplayer.h:135
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
ClassicCommDetector::m_sceneChangeDetector
SceneChangeDetectorBase * m_sceneChangeDetector
Definition: ClassicCommDetector.h:184
ClassicCommDetector::m_commDetectMinCommBreakLength
int m_commDetectMinCommBreakLength
Definition: ClassicCommDetector.h:147
ClassicCommDetector::m_sceneMap
frm_dir_map_t m_sceneMap
Definition: ClassicCommDetector.h:174
ClassicCommDetector::FrameBlock::end
long end
Definition: ClassicCommDetector.h:79
ClassicCommDetector::m_commDetectDimBrightness
int m_commDetectDimBrightness
Definition: ClassicCommDetector.h:143
ClassicCommDetector::FrameBlock::logoCount
int logoCount
Definition: ClassicCommDetector.h:83
pixel
static guint32 * pixel
--------------------------------------------------—**
Definition: goom_core.cpp:24
ClassicCommDetector::requestCommBreakMapUpdate
void requestCommBreakMapUpdate(void) override
Definition: ClassicCommDetector.cpp:703
MythPlayer::GetEof
EofState GetEof(void) const
Definition: mythplayer.cpp:1073
ClassicCommDetector::m_currentAspect
int m_currentAspect
Definition: ClassicCommDetector.h:163
ClassicCommDetector::m_commDetectMethod
SkipType m_commDetectMethod
Definition: ClassicCommDetector.h:135
ClassicCommDetector::Combine2Maps
frm_dir_map_t Combine2Maps(const frm_dir_map_t &a, const frm_dir_map_t &b) const
Definition: ClassicCommDetector.cpp:1046
COMM_FRAME_BLANK
@ COMM_FRAME_BLANK
Definition: ClassicCommDetector.h:25
FrameInfoEntry::minBrightness
int minBrightness
Definition: ClassicCommDetector.h:35
ClassicCommDetector::Init
void Init()
Definition: ClassicCommDetector.cpp:163
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:14
FrameInfoEntry::flagMask
int flagMask
Definition: ClassicCommDetector.h:41
COMM_FRAME_RATING_SYMBOL
@ COMM_FRAME_RATING_SYMBOL
Definition: ClassicCommDetector.h:29
ClassicCommDetector::GetBlankCommMap
void GetBlankCommMap(frm_dir_map_t &comms)
Definition: ClassicCommDetector.cpp:1011
ClassicCommDetector::FormatMsg
QString FormatMsg(T first, const FrameBlock *fbp)
Definition: ClassicCommDetector.h:93
ClassicCommDetector::PrintFullMap
void PrintFullMap(std::ostream &out, const frm_dir_map_t *comm_breaks, bool verbose) const override
Definition: ClassicCommDetector.cpp:2490
tmp
static guint32 * tmp
Definition: goom_core.cpp:26
LogoDetectorBase::getRequiredAvailableBufferForSearch
virtual unsigned int getRequiredAvailableBufferForSearch()=0
ClassicCommDetector::FrameBlock::ratingCount
int ratingCount
Definition: ClassicCommDetector.h:84
ClassicCommDetector::GetSceneChangeMap
void GetSceneChangeMap(frm_dir_map_t &scenes, int64_t start_frame)
Definition: ClassicCommDetector.cpp:1031
ClassicCommDetector::m_stillRecording
bool m_stillRecording
Definition: ClassicCommDetector.h:193
ClassicCommDetector::FrameBlock::scRate
double scRate
Definition: ClassicCommDetector.h:86
ClassicCommDetector::BuildSceneChangeCommList
void BuildSceneChangeCommList(void)
Definition: ClassicCommDetector.cpp:2030
MARK_END
@ MARK_END
Definition: CommDetectorBase.h:15
COMM_DETECT_BLANKS
@ COMM_DETECT_BLANKS
Definition: programtypes.h:134
SceneChangeDetectorBase::haveNewInformation
void haveNewInformation(unsigned int framenum, bool scenechange, float debugValue=0.0)
programinfo.h
ClassicCommDetector::BuildBlankFrameCommList
void BuildBlankFrameCommList(void)
Definition: ClassicCommDetector.cpp:1870
FrameInfoEntry::GetHeader
static QString GetHeader(void)
Definition: ClassicCommDetector.cpp:101
ClassicCommDetector::m_blankCommMap
frm_dir_map_t m_blankCommMap
Definition: ClassicCommDetector.h:172
ClassicCommDetector::m_lastSentCommBreakMap
frm_dir_map_t m_lastSentCommBreakMap
Definition: ClassicCommDetector.h:136
ClassicCommDetector::FrameBlock
Definition: ClassicCommDetector.h:76
ClassicCommDetector::m_horizSpacing
int m_horizSpacing
Definition: ClassicCommDetector.h:159
FMT_YV12
@ FMT_YV12
Definition: mythframe.h:24
ClassicCommDetector::FrameBlock::formatMatch
int formatMatch
Definition: ClassicCommDetector.h:87
ClassicCommDetector::FrameIsInBreakMap
bool FrameIsInBreakMap(uint64_t f, const frm_dir_map_t &breakMap) const
Definition: ClassicCommDetector.cpp:2210
COMM_FORMAT_MAX
@ COMM_FORMAT_MAX
Definition: ClassicCommDetector.cpp:35
COMM_FRAME_SKIPPED
@ COMM_FRAME_SKIPPED
Definition: ClassicCommDetector.h:24
ClassicCommDetector::m_frameInfo
QMap< long long, FrameInfoEntry > m_frameInfo
Definition: ClassicCommDetector.h:205
ClassicCommDetector::m_blankCommBreakMap
frm_dir_map_t m_blankCommBreakMap
Definition: ClassicCommDetector.h:173
ClassicCommDetector::m_verboseDebugging
bool m_verboseDebugging
Definition: ClassicCommDetector.h:152
ClassicCommDetector::m_commDetectBoxBrightness
int m_commDetectBoxBrightness
Definition: ClassicCommDetector.h:144
FrameInfoEntry
Definition: ClassicCommDetector.h:32
MythPlayer::InitVideo
virtual bool InitVideo(void)
Definition: mythplayer.cpp:274
ClassicCommDetector::GetLogoCommBreakMap
void GetLogoCommBreakMap(show_map_t &map)
Definition: ClassicCommDetector.cpp:2463
MythVideoFrame::m_frameNumber
long long m_frameNumber
Definition: mythframe.h:129
toStringFrameMaskValues
static QString toStringFrameMaskValues(int mask, bool verbose)
Definition: ClassicCommDetector.cpp:38
ClassicCommDetector::m_preRoll
long long m_preRoll
Definition: ClassicCommDetector.h:198
MythCommFlagPlayer
Definition: mythcommflagplayer.h:25
hardwareprofile.smolt.long
long
Definition: smolt.py:76
ClassicCommDetector::m_fullSpeed
bool m_fullSpeed
Definition: ClassicCommDetector.h:194
ClassicCommDetector::FrameBlock::frames
long frames
Definition: ClassicCommDetector.h:80
ClassicCommDetector::m_commDetectMaxCommBreakLength
int m_commDetectMaxCommBreakLength
Definition: ClassicCommDetector.h:146
LogoDetectorBase::pixelInsideLogo
virtual bool pixelInsideLogo(unsigned int x, unsigned int y)=0
ClassicCommDetector::m_stopsAt
QDateTime m_stopsAt
Definition: ClassicCommDetector.h:189
ClassicCommDetector::ClearAllMaps
void ClearAllMaps(void)
Definition: ClassicCommDetector.cpp:998
floatusecs
std::chrono::duration< double, std::micro > floatusecs
Definition: mythchrono.h:41
ClassicCommDetector::m_blankFrameCount
int m_blankFrameCount
Definition: ClassicCommDetector.h:162
sizetliteral.h
ClassicCommDetector::sceneChangeDetectorHasNewInformation
void sceneChangeDetectorHasNewInformation(unsigned int framenum, bool isSceneChange, float debugValue)
Definition: ClassicCommDetector.cpp:607
SceneChangeDetectorBase::processFrame
virtual void processFrame(MythVideoFrame *frame)=0
ClassicCommDetector::SetVideoParams
void SetVideoParams(float aspect)
Definition: ClassicCommDetector.cpp:709
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:54
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:910
ClassicCommDetector::m_framesProcessed
uint64_t m_framesProcessed
Definition: ClassicCommDetector.h:197
COMM_ASPECT_NORMAL
@ COMM_ASPECT_NORMAL
Definition: ClassicCommDetector.cpp:24
MythVideoFrame::m_pitches
FramePitches m_pitches
Definition: mythframe.h:142
CommDetectorBase::m_bStop
bool m_bStop
Definition: CommDetectorBase.h:54
MythCoreContext::GetBoolSetting
bool GetBoolSetting(const QString &key, bool defaultval=false)
Definition: mythcorecontext.cpp:904
ClassicCommDetector::m_vertSpacing
int m_vertSpacing
Definition: ClassicCommDetector.h:160
ClassicCommDetector::DumpMap
void DumpMap(frm_dir_map_t &map) const
Definition: ClassicCommDetector.cpp:2242
ClassicCommDetector::m_decoderFoundAspectChanges
bool m_decoderFoundAspectChanges
Definition: ClassicCommDetector.h:182
ClassicCommDetector::m_commDetectMinShowLength
int m_commDetectMinShowLength
Definition: ClassicCommDetector.h:148
ClassicCommDetector::m_curFrameNumber
long long m_curFrameNumber
Definition: ClassicCommDetector.h:155
MARK_CUT_START
@ MARK_CUT_START
Definition: programtypes.h:57
ClassicCommDetector::m_commDetectDimAverage
int m_commDetectDimAverage
Definition: ClassicCommDetector.h:145
ClassicCommDetector::GetBlankCommBreakMap
void GetBlankCommBreakMap(frm_dir_map_t &comms)
Definition: ClassicCommDetector.cpp:1021
toStringFrameFormats
static QString toStringFrameFormats(int format, bool verbose)
Definition: ClassicCommDetector.cpp:82
ClassicCommDetector::FrameBlock::score
int score
Definition: ClassicCommDetector.h:89
ClassicCommDetector::m_fps
double m_fps
Definition: ClassicCommDetector.h:196
ClassicCommDetector::CondenseMarkMap
static void CondenseMarkMap(show_map_t &map, int spacing, int length)
Definition: ClassicCommDetector.cpp:2269
mythmiscutil.h
ClassicCommDetector::GetCommercialBreakList
void GetCommercialBreakList(frm_dir_map_t &marks) override
Definition: ClassicCommDetector.cpp:624
ClassicCommDetector::m_logoDetector
LogoDetectorBase * m_logoDetector
Definition: ClassicCommDetector.h:169
ClassicCommDetector::m_sendCommBreakMapUpdates
bool m_sendCommBreakMapUpdates
Definition: ClassicCommDetector.h:138
FrameInfoEntry::toString
QString toString(uint64_t frame, bool verbose) const
Definition: ClassicCommDetector.cpp:106
ClassicCommDetector::MergeBlankCommList
void MergeBlankCommList(void)
Definition: ClassicCommDetector.cpp:2145
MythVideoFrame::m_type
VideoFrameType m_type
Definition: mythframe.h:119
ClassicCommDetector::BuildAllMethodsCommList
void BuildAllMethodsCommList(void)
Definition: ClassicCommDetector.cpp:1169
ClassicCommDetector::go
bool go() override
Definition: ClassicCommDetector.cpp:281
ClassicCommDetector::m_sceneCommBreakMap
frm_dir_map_t m_sceneCommBreakMap
Definition: ClassicCommDetector.h:175
MythDate
Definition: mythdate.cpp:11
COMM_FORMAT_NORMAL
@ COMM_FORMAT_NORMAL
Definition: ClassicCommDetector.cpp:32
MARK_SCENE_CHANGE
@ MARK_SCENE_CHANGE
Definition: programtypes.h:64
std
Definition: mythchrono.h:23
MarkTypes
MarkTypes
Definition: programtypes.h:48
MythPlayer::GetVideoSize
QSize GetVideoSize(void) const
Definition: mythplayer.h:133
ClassicCommDetector::m_frameIsBlank
bool m_frameIsBlank
Definition: ClassicCommDetector.h:179
MythPlayer::GetVideoAspect
float GetVideoAspect(void) const
Definition: mythplayer.h:134
ClassicCommDetector::m_totalMinBrightness
int m_totalMinBrightness
Definition: ClassicCommDetector.h:166
mythcontext.h
ClassicCommDetector::m_logoInfoAvailable
bool m_logoInfoAvailable
Definition: ClassicCommDetector.h:168
MythPlayer::ResetTotalDuration
void ResetTotalDuration(void)
Definition: mythplayer.cpp:1978
ClassicCommDetector::m_aggressiveDetection
bool m_aggressiveDetection
Definition: ClassicCommDetector.h:192
marks
static const std::array< const mark, 16 > marks
Definition: lang.cpp:23
ClassicCommDetector::m_commDetectBlankFrameMaxDiff
int m_commDetectBlankFrameMaxDiff
Definition: ClassicCommDetector.h:141
ClassicCommDetector::FrameBlock::length
double length
Definition: ClassicCommDetector.h:81
COMM_FORMAT_LETTERBOX
@ COMM_FORMAT_LETTERBOX
Definition: ClassicCommDetector.cpp:33
SkipType
SkipType
This is used as a bitmask.
Definition: programtypes.h:129
ClassicCommDetector::m_commDetectMaxCommLength
int m_commDetectMaxCommLength
Definition: ClassicCommDetector.h:149
hardwareprofile.distros.mythtv_data.makeopts.verbose
verbose
Definition: makeopts.py:60
FrameInfoEntry::format
int format
Definition: ClassicCommDetector.h:40
MAX_BLANK_FRAMES
static constexpr int64_t MAX_BLANK_FRAMES
Definition: CommDetectorBase.h:11
ClassicSceneChangeDetector.h
ClassicCommDetector::FrameBlock::start
long start
Definition: ClassicCommDetector.h:78
MythVideoFrame
Definition: mythframe.h:88
ClassicCommDetector::ClassicLogoDetector
friend class ClassicLogoDetector
Definition: ClassicCommDetector.h:70
ClassicCommDetector::m_commBreakMapUpdateRequested
bool m_commBreakMapUpdateRequested
Definition: ClassicCommDetector.h:137
ClassicCommDetector::m_commDetectDarkBrightness
int m_commDetectDarkBrightness
Definition: ClassicCommDetector.h:142
ClassicSceneChangeDetector
Definition: ClassicSceneChangeDetector.h:8
ClassicCommDetector::m_blankFrameMap
frm_dir_map_t m_blankFrameMap
Definition: ClassicCommDetector.h:171
ClassicCommDetector::CleanupFrameInfo
void CleanupFrameInfo(void)
Definition: ClassicCommDetector.cpp:2375
toStringFrameAspects
static QString toStringFrameAspects(int aspect, bool verbose)
Definition: ClassicCommDetector.cpp:75
COMM_DETECT_LOGO
@ COMM_DETECT_LOGO
Definition: programtypes.h:136
ClassicCommDetector::m_commDetectBlankCanHaveLogo
bool m_commDetectBlankCanHaveLogo
Definition: ClassicCommDetector.h:150
LogoDetectorBase::doesThisFrameContainTheFoundLogo
virtual bool doesThisFrameContainTheFoundLogo(MythVideoFrame *frame)=0
ClassicCommDetector::FrameBlock::scCount
int scCount
Definition: ClassicCommDetector.h:85
avg
static uint32_t avg(uint32_t A, uint32_t B)
Definition: mythdeinterlacer.cpp:464
ClassicCommDetector::m_postRoll
long long m_postRoll
Definition: ClassicCommDetector.h:199
MARK_COMM_START
@ MARK_COMM_START
Definition: programtypes.h:60
ClassicCommDetector::recordingFinished
void recordingFinished(long long totalFileSize) override
Definition: ClassicCommDetector.cpp:696
ClassicCommDetector::FrameBlock::bfCount
int bfCount
Definition: ClassicCommDetector.h:82
COMM_FRAME_LOGO_PRESENT
@ COMM_FRAME_LOGO_PRESENT
Definition: ClassicCommDetector.h:27
ClassicCommDetector::m_showProgress
bool m_showProgress
Definition: ClassicCommDetector.h:195
ClassicCommDetector::m_height
int m_height
Definition: ClassicCommDetector.h:158
MythVideoFrame::m_aspect
float m_aspect
Definition: mythframe.h:127
MythCommFlagPlayer::GetRawVideoFrame
MythVideoFrame * GetRawVideoFrame(long long FrameNumber=-1)
Returns a specific frame from the video.
Definition: mythcommflagplayer.cpp:226
MARK_BLANK_FRAME
@ MARK_BLANK_FRAME
Definition: programtypes.h:59
FrameInfoEntry::aspect
int aspect
Definition: ClassicCommDetector.h:39
MythVideoFrame::m_buffer
uint8_t * m_buffer
Definition: mythframe.h:120
ClassicCommDetector::ConvertShowMapToCommMap
static void ConvertShowMapToCommMap(frm_dir_map_t &out, const show_map_t &in)
Definition: ClassicCommDetector.cpp:2334
ClassicCommDetector::m_startedAt
QDateTime m_startedAt
Definition: ClassicCommDetector.h:188
ClassicCommDetector::m_player
MythCommFlagPlayer * m_player
Definition: ClassicCommDetector.h:187
COMM_DETECT_BLANK
@ COMM_DETECT_BLANK
Definition: programtypes.h:133
MythPlayer::DiscardVideoFrame
void DiscardVideoFrame(MythVideoFrame *buffer)
Places frame in the available frames queue.
Definition: mythplayer.cpp:635