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([[maybe_unused]] long long totalFileSize)
697 {
698  m_stillRecording = false;
699 }
700 
702 {
705 }
706 
708 {
709  int newAspect = COMM_ASPECT_WIDE;
710 
711  LOG(VB_COMMFLAG, LOG_INFO,
712  QString("CommDetect::SetVideoParams called with aspect = %1")
713  .arg(aspect));
714  // Default to Widescreen but use the same check as VideoOutput::MoveResize()
715  // to determine if is normal 4:3 aspect
716  if (fabs(aspect - 1.333333F) < 0.1F)
717  newAspect = COMM_ASPECT_NORMAL;
718 
719  if (newAspect != m_currentAspect)
720  {
721  LOG(VB_COMMFLAG, LOG_INFO,
722  QString("Aspect Ratio changed from %1 to %2 at frame %3")
723  .arg(m_currentAspect).arg(newAspect)
724  .arg(m_curFrameNumber));
725 
726  if (m_frameInfo.contains(m_curFrameNumber))
727  {
728  // pretend that this frame is blank so that we can create test
729  // blocks on real aspect ratio change boundaries.
733  }
734  else if (m_curFrameNumber != -1)
735  {
736  LOG(VB_COMMFLAG, LOG_ERR,
737  QString("Unable to keep track of Aspect ratio change because "
738  "frameInfo for frame number %1 does not exist.")
739  .arg(m_curFrameNumber));
740  }
741  m_currentAspect = newAspect;
742  }
743 }
744 
746  long long frame_number)
747 {
748  int max = 0;
749  int min = 255;
750  int blankPixelsChecked = 0;
751  long long totBrightness = 0;
752  auto *rowMax = new unsigned char[m_height];
753  auto *colMax = new unsigned char[m_width];
754  memset(rowMax, 0, sizeof(*rowMax)*m_height);
755  memset(colMax, 0, sizeof(*colMax)*m_width);
756  int topDarkRow = m_commDetectBorder;
757  int bottomDarkRow = m_height - m_commDetectBorder - 1;
758  int leftDarkCol = m_commDetectBorder;
759  int rightDarkCol = m_width - m_commDetectBorder - 1;
760  FrameInfoEntry fInfo {};
761 
762  if (!frame || !(frame->m_buffer) || frame_number == -1 ||
763  frame->m_type != FMT_YV12)
764  {
765  LOG(VB_COMMFLAG, LOG_ERR, "CommDetect: Invalid video frame or codec, "
766  "unable to process frame.");
767  delete[] rowMax;
768  delete[] colMax;
769  return;
770  }
771 
772  if (!m_width || !m_height)
773  {
774  LOG(VB_COMMFLAG, LOG_ERR, "CommDetect: Width or Height is 0, "
775  "unable to process frame.");
776  delete[] rowMax;
777  delete[] colMax;
778  return;
779  }
780 
781  m_curFrameNumber = frame_number;
782  unsigned char* framePtr = frame->m_buffer;
783  int bytesPerLine = frame->m_pitches[0];
784 
785  fInfo.minBrightness = -1;
786  fInfo.maxBrightness = -1;
787  fInfo.avgBrightness = -1;
788  fInfo.sceneChangePercent = -1;
789  fInfo.aspect = m_currentAspect;
790  fInfo.format = COMM_FORMAT_NORMAL;
791  fInfo.flagMask = 0;
792 
793  int& flagMask = m_frameInfo[m_curFrameNumber].flagMask;
794 
795  // Fill in dummy info records for skipped frames.
796  if (m_lastFrameNumber != (m_curFrameNumber - 1))
797  {
798  if (m_lastFrameNumber > 0)
799  {
800  fInfo.aspect = m_frameInfo[m_lastFrameNumber].aspect;
801  fInfo.format = m_frameInfo[m_lastFrameNumber].format;
802  }
803  fInfo.flagMask = COMM_FRAME_SKIPPED;
804 
807  m_frameInfo[m_lastFrameNumber++] = fInfo;
808 
809  fInfo.flagMask = 0;
810  }
812 
813  m_frameInfo[m_curFrameNumber] = fInfo;
814 
816  m_frameIsBlank = false;
817 
819  {
821  }
822 
823  m_stationLogoPresent = false;
824 
825  for(int y = m_commDetectBorder; y < (m_height - m_commDetectBorder);
826  y += m_vertSpacing)
827  {
828  for(int x = m_commDetectBorder; x < (m_width - m_commDetectBorder);
829  x += m_horizSpacing)
830  {
831  uchar pixel = framePtr[y * bytesPerLine + x];
832 
834  {
835  bool checkPixel = false;
837  checkPixel = true;
838 
839  if (!m_logoInfoAvailable ||
841  checkPixel=true;
842 
843  if (checkPixel)
844  {
845  blankPixelsChecked++;
846  totBrightness += pixel;
847 
848  if (pixel < min)
849  min = pixel;
850 
851  if (pixel > max)
852  max = pixel;
853 
854  if (pixel > rowMax[y])
855  rowMax[y] = pixel;
856 
857  if (pixel > colMax[x])
858  colMax[x] = pixel;
859  }
860  }
861  }
862  }
863 
864  if ((m_commDetectMethod & COMM_DETECT_BLANKS) && blankPixelsChecked)
865  {
866  for(int y = m_commDetectBorder; y < (m_height - m_commDetectBorder);
867  y += m_vertSpacing)
868  {
869  if (rowMax[y] > m_commDetectBoxBrightness)
870  break;
871  topDarkRow = y;
872  }
873 
874  for(int y = m_commDetectBorder; y < (m_height - m_commDetectBorder);
875  y += m_vertSpacing)
876  if (rowMax[y] >= m_commDetectBoxBrightness)
877  bottomDarkRow = y;
878 
879  delete[] rowMax;
880  rowMax = nullptr;
881 
882  for(int x = m_commDetectBorder; x < (m_width - m_commDetectBorder);
883  x += m_horizSpacing)
884  {
885  if (colMax[x] > m_commDetectBoxBrightness)
886  break;
887  leftDarkCol = x;
888  }
889 
890  for(int x = m_commDetectBorder; x < (m_width - m_commDetectBorder);
891  x += m_horizSpacing)
892  if (colMax[x] >= m_commDetectBoxBrightness)
893  rightDarkCol = x;
894 
895  delete[] colMax;
896  colMax = nullptr;
897 
899  if ((topDarkRow > m_commDetectBorder) &&
900  (topDarkRow < (m_height * .20)) &&
901  (bottomDarkRow < (m_height - m_commDetectBorder)) &&
902  (bottomDarkRow > (m_height * .80)))
903  {
905  }
906  if ((leftDarkCol > m_commDetectBorder) &&
907  (leftDarkCol < (m_width * .20)) &&
908  (rightDarkCol < (m_width - m_commDetectBorder)) &&
909  (rightDarkCol > (m_width * .80)))
910  {
912  }
913 
914  int avg = totBrightness / blankPixelsChecked;
915 
916  m_frameInfo[m_curFrameNumber].minBrightness = min;
917  m_frameInfo[m_curFrameNumber].maxBrightness = max;
918  m_frameInfo[m_curFrameNumber].avgBrightness = avg;
919 
920  m_totalMinBrightness += min;
921  m_commDetectDimAverage = min + 10;
922 
923  // Is the frame really dark
924  if (((max - min) <= m_commDetectBlankFrameMaxDiff) &&
926  m_frameIsBlank = true;
927 
928  // Are we non-strict and the frame is blank
929  if ((!m_aggressiveDetection) &&
930  ((max - min) <= m_commDetectBlankFrameMaxDiff))
931  m_frameIsBlank = true;
932 
933  // Are we non-strict and the frame is dark
934  // OR the frame is dim and has a low avg brightness
935  if ((!m_aggressiveDetection) &&
936  ((max < m_commDetectDarkBrightness) ||
938  m_frameIsBlank = true;
939  }
940 
942  {
945  }
946 
947 #if 0
949  (CheckRatingSymbol()))
950  {
951  flagMask |= COMM_FRAME_RATING_SYMBOL;
952  }
953 #endif
954 
955  if (m_frameIsBlank)
956  {
958  flagMask |= COMM_FRAME_BLANK;
960  }
961 
963  flagMask |= COMM_FRAME_LOGO_PRESENT;
964 
965  //TODO: move this debugging code out of the perframe loop, and do it after
966  // we've processed all frames. this is because a scenechangedetector can
967  // now use a few frames to determine whether the frame a few frames ago was
968  // a scene change or not.. due to this lookahead possibility the values
969  // that are currently in the frameInfo array, might be changed a few frames
970  // from now. The ClassicSceneChangeDetector doesn't use this though. future
971  // scenechangedetectors might.
972 
973  if (m_verboseDebugging)
974  {
975  LOG(VB_COMMFLAG, LOG_DEBUG, QString("Frame: %1 -> %2 %3 %4 %5 %6 %7 %8")
976  .arg(m_curFrameNumber, 6)
977  .arg(m_frameInfo[m_curFrameNumber].minBrightness, 3)
978  .arg(m_frameInfo[m_curFrameNumber].maxBrightness, 3)
979  .arg(m_frameInfo[m_curFrameNumber].avgBrightness, 3)
980  .arg(m_frameInfo[m_curFrameNumber].sceneChangePercent, 3)
981  .arg(m_frameInfo[m_curFrameNumber].format, 1)
982  .arg(m_frameInfo[m_curFrameNumber].aspect, 1)
983  .arg(m_frameInfo[m_curFrameNumber].flagMask, 4, 16, QChar('0')));
984  }
985 
986 #ifdef SHOW_DEBUG_WIN
987  comm_debug_show(frame->buf);
988  getchar();
989 #endif
990 
992  delete[] rowMax;
993  delete[] colMax;
994 }
995 
997 {
998  LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::ClearAllMaps()");
999 
1000  m_frameInfo.clear();
1001  m_blankFrameMap.clear();
1002  m_blankCommMap.clear();
1003  m_blankCommBreakMap.clear();
1004  m_sceneMap.clear();
1005  m_sceneCommBreakMap.clear();
1006  m_commBreakMap.clear();
1007 }
1008 
1010 {
1011  LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::GetBlankCommMap()");
1012 
1013  if (m_blankCommMap.isEmpty())
1015 
1016  comms = m_blankCommMap;
1017 }
1018 
1020 {
1021  LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::GetBlankCommBreakMap()");
1022 
1023  if (m_blankCommBreakMap.isEmpty())
1025 
1026  comms = m_blankCommBreakMap;
1027 }
1028 
1030  int64_t start_frame)
1031 {
1032  LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::GetSceneChangeMap()");
1033 
1034  frm_dir_map_t::iterator it;
1035 
1036  if (start_frame == -1)
1037  scenes.clear();
1038 
1039  for (it = m_sceneMap.begin(); it != m_sceneMap.end(); ++it)
1040  if ((start_frame == -1) || ((int64_t)it.key() >= start_frame))
1041  scenes[it.key()] = *it;
1042 }
1043 
1045  const frm_dir_map_t &b) const
1046 {
1047  LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::BuildMasterCommList()");
1048 
1049  frm_dir_map_t newMap;
1050 
1051  if (!a.empty())
1052  {
1053  frm_dir_map_t::const_iterator it = a.begin();
1054  for (; it != a.end(); ++it)
1055  newMap[it.key()] = *it;
1056  }
1057 
1058  if ((a.size() > 1) &&
1059  (b.size() > 1))
1060  {
1061  // see if beginning of the recording looks like a commercial
1062  frm_dir_map_t::const_iterator it_a;
1063  frm_dir_map_t::const_iterator it_b;
1064 
1065  it_a = a.begin();
1066  it_b = b.begin();
1067 
1068  if ((it_b.key() < 2) && (it_a.key() > 2))
1069  {
1070  newMap.remove(it_a.key());
1071  newMap[0] = MARK_COMM_START;
1072  }
1073 
1074 
1075  // see if ending of recording looks like a commercial
1076  frm_dir_map_t::const_iterator it;
1077  uint64_t max_a = 0;
1078  uint64_t max_b = 0;
1079 
1080  it = a.begin();
1081  for (; it != a.end(); ++it)
1082  {
1083  if ((*it == MARK_COMM_END) && (it.key() > max_a))
1084  max_a = it.key();
1085  }
1086 
1087  it = b.begin();
1088  for (; it != b.end(); ++it)
1089  {
1090  if ((*it == MARK_COMM_END) && (it.key() > max_b))
1091  max_b = it.key();
1092  }
1093 
1094  if ((max_a < (m_framesProcessed - 2)) &&
1095  (max_b > (m_framesProcessed - 2)))
1096  {
1097  newMap.remove(max_a);
1098  newMap[m_framesProcessed] = MARK_COMM_END;
1099  }
1100  }
1101 
1102  if ((a.size() > 3) &&
1103  (b.size() > 1))
1104  {
1105  frm_dir_map_t::const_iterator it_a;
1106  frm_dir_map_t::const_iterator it_b;
1107 
1108  it_a = a.begin();
1109  ++it_a;
1110  it_b = it_a;
1111  ++it_b;
1112  while (it_b != a.end())
1113  {
1114  uint64_t fdiff = it_b.key() - it_a.key();
1115  bool allTrue = false;
1116 
1117  if (fdiff < (62 * m_fps))
1118  {
1119  uint64_t f = it_a.key() + 1;
1120 
1121  allTrue = true;
1122 
1123  while ((f <= m_framesProcessed) && (f < it_b.key()) && (allTrue))
1124  allTrue = FrameIsInBreakMap(f++, b);
1125  }
1126 
1127  if (allTrue)
1128  {
1129  newMap.remove(it_a.key());
1130  newMap.remove(it_b.key());
1131  }
1132 
1133  ++it_a; ++it_a;
1134  ++it_b;
1135  if (it_b != a.end())
1136  ++it_b;
1137  }
1138  }
1139 
1140  return newMap;
1141 }
1142 
1144  const FrameInfoEntry& finfo,
1145  int format, int aspect)
1146 {
1147  int value = 0;
1148 
1149  value = finfo.flagMask;
1150 
1151  if (value & COMM_FRAME_LOGO_PRESENT)
1152  fbp->logoCount++;
1153 
1154  if (value & COMM_FRAME_RATING_SYMBOL)
1155  fbp->ratingCount++;
1156 
1157  if (value & COMM_FRAME_SCENE_CHANGE)
1158  fbp->scCount++;
1159 
1160  if (finfo.format == format)
1161  fbp->formatMatch++;
1162 
1163  if (finfo.aspect == aspect)
1164  fbp->aspectMatch++;
1165 }
1166 
1168 {
1169  LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::BuildAllMethodsCommList()");
1170 
1171  int lastScore = 0;
1172  uint64_t lastStart = 0;
1173  uint64_t lastEnd = 0;
1174  int64_t firstLogoFrame = -1;
1175  int format = COMM_FORMAT_NORMAL;
1176  int aspect = COMM_ASPECT_NORMAL;
1177  QString msg;
1178  std::array<uint64_t,COMM_FORMAT_MAX> formatCounts {};
1179  frm_dir_map_t tmpCommMap;
1180  frm_dir_map_t::iterator it;
1181 
1182  m_commBreakMap.clear();
1183 
1184  auto *fblock = new FrameBlock[m_blankFrameCount + 2];
1185 
1186  int curBlock = 0;
1187  uint64_t curFrame = 1;
1188 
1189  FrameBlock *fbp = &fblock[curBlock];
1190  fbp->start = 0;
1191  fbp->bfCount = 0;
1192  fbp->logoCount = 0;
1193  fbp->ratingCount = 0;
1194  fbp->scCount = 0;
1195  fbp->scRate = 0.0;
1196  fbp->formatMatch = 0;
1197  fbp->aspectMatch = 0;
1198  fbp->score = 0;
1199 
1200  bool lastFrameWasBlank = true;
1201 
1203  {
1204  uint64_t aspectFrames = 0;
1205  for (int64_t i = m_preRoll;
1206  i < ((int64_t)m_framesProcessed - (int64_t)m_postRoll); i++)
1207  {
1208  if ((m_frameInfo.contains(i)) &&
1209  (m_frameInfo[i].aspect == COMM_ASPECT_NORMAL))
1210  aspectFrames++;
1211  }
1212 
1213  if (aspectFrames < ((m_framesProcessed - m_preRoll - m_postRoll) / 2))
1214  {
1215  aspect = COMM_ASPECT_WIDE;
1216 // aspectFrames = m_framesProcessed - m_preRoll - m_postRoll - aspectFrames;
1217  }
1218  }
1219  else
1220  {
1221  formatCounts.fill(0);
1222 
1223  for(int64_t i = m_preRoll;
1224  i < ((int64_t)m_framesProcessed - (int64_t)m_postRoll); i++ )
1225  {
1226  if ((m_frameInfo.contains(i)) &&
1227  (m_frameInfo[i].format >= 0) &&
1228  (m_frameInfo[i].format < COMM_FORMAT_MAX))
1229  formatCounts[m_frameInfo[i].format]++;
1230  }
1231 
1232  uint64_t formatFrames = 0;
1233  for(int i = 0; i < COMM_FORMAT_MAX; i++)
1234  {
1235  if (formatCounts[i] > formatFrames)
1236  {
1237  format = i;
1238  formatFrames = formatCounts[i];
1239  }
1240  }
1241  }
1242 
1243  while (curFrame <= m_framesProcessed)
1244  {
1245  int value = m_frameInfo[curFrame].flagMask;
1246 
1247  bool nextFrameIsBlank = ((curFrame + 1) <= m_framesProcessed) &&
1248  ((m_frameInfo[curFrame + 1].flagMask & COMM_FRAME_BLANK) != 0);
1249 
1250  if (value & COMM_FRAME_BLANK)
1251  {
1252  fbp->bfCount++;
1253 
1254  if (!nextFrameIsBlank || !lastFrameWasBlank)
1255  {
1256  UpdateFrameBlock(fbp, m_frameInfo[curFrame], format, aspect);
1257 
1258  fbp->end = curFrame;
1259  fbp->frames = fbp->end - fbp->start + 1;
1260  fbp->length = fbp->frames / m_fps;
1261 
1262  if ((fbp->scCount) && (fbp->length > 1.05))
1263  fbp->scRate = fbp->scCount / fbp->length;
1264 
1265  curBlock++;
1266 
1267  fbp = &fblock[curBlock];
1268  fbp->bfCount = 1;
1269  fbp->logoCount = 0;
1270  fbp->ratingCount = 0;
1271  fbp->scCount = 0;
1272  fbp->scRate = 0.0;
1273  fbp->score = 0;
1274  fbp->formatMatch = 0;
1275  fbp->aspectMatch = 0;
1276  fbp->start = curFrame;
1277  }
1278 
1279  lastFrameWasBlank = true;
1280  }
1281  else
1282  {
1283  lastFrameWasBlank = false;
1284  }
1285 
1286  UpdateFrameBlock(fbp, m_frameInfo[curFrame], format, aspect);
1287 
1288  if ((value & COMM_FRAME_LOGO_PRESENT) &&
1289  (firstLogoFrame == -1))
1290  firstLogoFrame = curFrame;
1291 
1292  curFrame++;
1293  }
1294 
1295  fbp->end = curFrame;
1296  fbp->frames = fbp->end - fbp->start + 1;
1297  fbp->length = fbp->frames / m_fps;
1298 
1299  if ((fbp->scCount) && (fbp->length > 1.05))
1300  fbp->scRate = fbp->scCount / fbp->length;
1301 
1302  int maxBlock = curBlock;
1303  curBlock = 0;
1304 // lastScore = 0;
1305 
1306  LOG(VB_COMMFLAG, LOG_INFO, "Initial Block pass");
1307  LOG(VB_COMMFLAG, LOG_DEBUG,
1308  "Block StTime StFrm EndFrm Frames Secs "
1309  "Bf Lg Cnt RT Cnt SC Cnt SC Rt FmtMch AspMch Score");
1310  LOG(VB_COMMFLAG, LOG_INFO,
1311  "----- ------ ------ ------ ------ ------- "
1312  "--- ------ ------ ------ ----- ------ ------ -----");
1313  while (curBlock <= maxBlock)
1314  {
1315  fbp = &fblock[curBlock];
1316 
1317  msg = FormatMsg(curBlock, fbp);
1318  LOG(VB_COMMFLAG, LOG_DEBUG, msg);
1319 
1320  if (fbp->frames > m_fps)
1321  {
1322  if (m_verboseDebugging)
1323  LOG(VB_COMMFLAG, LOG_DEBUG,
1324  QString(" FRAMES > %1").arg(m_fps));
1325 
1326  if (fbp->length > m_commDetectMaxCommLength)
1327  {
1328  if (m_verboseDebugging)
1329  LOG(VB_COMMFLAG, LOG_DEBUG,
1330  " length > max comm length, +20");
1331  fbp->score += 20;
1332  }
1333 
1335  {
1336  if (m_verboseDebugging)
1337  LOG(VB_COMMFLAG, LOG_DEBUG,
1338  " length > max comm break length, +20");
1339  fbp->score += 20;
1340  }
1341 
1342  if ((fbp->length > 4) &&
1343  (fbp->logoCount > (fbp->frames * 0.60)) &&
1344  (fbp->bfCount < (fbp->frames * 0.10)))
1345  {
1346  if (m_verboseDebugging)
1347  {
1348  LOG(VB_COMMFLAG, LOG_DEBUG,
1349  " length > 4 && logoCount > frames * 0.60 && "
1350  "bfCount < frames * .10");
1351  }
1353  {
1354  if (m_verboseDebugging)
1355  LOG(VB_COMMFLAG, LOG_DEBUG,
1356  " length > max comm break length, +20");
1357  fbp->score += 20;
1358  }
1359  else
1360  {
1361  if (m_verboseDebugging)
1362  LOG(VB_COMMFLAG, LOG_DEBUG,
1363  " length <= max comm break length, +10");
1364  fbp->score += 10;
1365  }
1366  }
1367 
1368  if ((m_logoInfoAvailable) &&
1369  (fbp->logoCount < (fbp->frames * 0.50)))
1370  {
1371  if (m_verboseDebugging)
1372  {
1373  LOG(VB_COMMFLAG, LOG_DEBUG,
1374  " logoInfoAvailable && logoCount < frames * .50, "
1375  "-10");
1376  }
1377  fbp->score -= 10;
1378  }
1379 
1380  if (fbp->ratingCount > (fbp->frames * 0.05))
1381  {
1382  if (m_verboseDebugging)
1383  LOG(VB_COMMFLAG, LOG_DEBUG,
1384  " rating symbol present > 5% of time, +20");
1385  fbp->score += 20;
1386  }
1387 
1388  if ((fbp->scRate > 1.0) &&
1389  (fbp->logoCount < (fbp->frames * .90)))
1390  {
1391  if (m_verboseDebugging)
1392  LOG(VB_COMMFLAG, LOG_DEBUG, " scRate > 1.0, -10");
1393  fbp->score -= 10;
1394 
1395  if (fbp->scRate > 2.0)
1396  {
1397  if (m_verboseDebugging)
1398  LOG(VB_COMMFLAG, LOG_DEBUG, " scRate > 2.0, -10");
1399  fbp->score -= 10;
1400  }
1401  }
1402 
1403  if ((!m_decoderFoundAspectChanges) &&
1404  (fbp->formatMatch < (fbp->frames * .10)))
1405  {
1406  if (m_verboseDebugging)
1407  {
1408  LOG(VB_COMMFLAG, LOG_DEBUG,
1409  " < 10% of frames match show letter/pillar-box "
1410  "format, -20");
1411  }
1412  fbp->score -= 20;
1413  }
1414 
1415  if ((abs((int)(fbp->frames - (15 * m_fps))) < 5 ) ||
1416  (abs((int)(fbp->frames - (30 * m_fps))) < 6 ) ||
1417  (abs((int)(fbp->frames - (60 * m_fps))) < 8 ))
1418  {
1419  if (m_verboseDebugging)
1420  LOG(VB_COMMFLAG, LOG_DEBUG,
1421  " block appears to be standard comm length, -10");
1422  fbp->score -= 10;
1423  }
1424  }
1425  else
1426  {
1427  if (m_verboseDebugging)
1428  LOG(VB_COMMFLAG, LOG_DEBUG,
1429  QString(" FRAMES <= %1").arg(m_fps));
1430 
1431  if ((m_logoInfoAvailable) &&
1432  (fbp->start >= firstLogoFrame) &&
1433  (fbp->logoCount == 0))
1434  {
1435  if (m_verboseDebugging)
1436  LOG(VB_COMMFLAG, LOG_DEBUG,
1437  " logoInfoAvailable && logoCount == 0, -10");
1438  fbp->score -= 10;
1439  }
1440 
1441  if ((!m_decoderFoundAspectChanges) &&
1442  (fbp->formatMatch < (fbp->frames * .10)))
1443  {
1444  if (m_verboseDebugging)
1445  {
1446  LOG(VB_COMMFLAG, LOG_DEBUG,
1447  " < 10% of frames match show letter/pillar-box "
1448  "format, -10");
1449  }
1450  fbp->score -= 10;
1451  }
1452 
1453  if (fbp->ratingCount > (fbp->frames * 0.25))
1454  {
1455  if (m_verboseDebugging)
1456  LOG(VB_COMMFLAG, LOG_DEBUG,
1457  " rating symbol present > 25% of time, +10");
1458  fbp->score += 10;
1459  }
1460  }
1461 
1463  (fbp->aspectMatch < (fbp->frames * .10)))
1464  {
1465  if (m_verboseDebugging)
1466  LOG(VB_COMMFLAG, LOG_DEBUG,
1467  " < 10% of frames match show aspect, -20");
1468  fbp->score -= 20;
1469  }
1470 
1471  msg = FormatMsg("NOW", fbp);
1472  LOG(VB_COMMFLAG, LOG_DEBUG, msg);
1473 
1474 // lastScore = fbp->score;
1475  curBlock++;
1476  }
1477 
1478  curBlock = 0;
1479  lastScore = 0;
1480 
1481  LOG(VB_COMMFLAG, LOG_DEBUG, "============================================");
1482  LOG(VB_COMMFLAG, LOG_INFO, "Second Block pass");
1483  LOG(VB_COMMFLAG, LOG_DEBUG,
1484  "Block StTime StFrm EndFrm Frames Secs "
1485  "Bf Lg Cnt RT Cnt SC Cnt SC Rt FmtMch AspMch Score");
1486  LOG(VB_COMMFLAG, LOG_DEBUG,
1487  "----- ------ ------ ------ ------ ------- "
1488  "--- ------ ------ ------ ----- ------ ------ -----");
1489  while (curBlock <= maxBlock)
1490  {
1491  fbp = &fblock[curBlock];
1492 
1493  msg = FormatMsg(curBlock, fbp);
1494  LOG(VB_COMMFLAG, LOG_DEBUG, msg);
1495 
1496  if ((curBlock > 0) && (curBlock < maxBlock))
1497  {
1498  int nextScore = fblock[curBlock + 1].score;
1499 
1500  if ((lastScore < 0) && (nextScore < 0) && (fbp->length < 35))
1501  {
1502  if (m_verboseDebugging)
1503  {
1504  LOG(VB_COMMFLAG, LOG_DEBUG,
1505  " lastScore < 0 && nextScore < 0 "
1506  "&& length < 35, setting -10");
1507  }
1508  fbp->score -= 10;
1509  }
1510 
1511  if ((fbp->bfCount > (fbp->frames * 0.95)) &&
1512  (fbp->frames < (2*m_fps)) &&
1513  (lastScore < 0 && nextScore < 0))
1514  {
1515  if (m_verboseDebugging)
1516  {
1517  LOG(VB_COMMFLAG, LOG_DEBUG,
1518  " blanks > frames * 0.95 && frames < 2*m_fps && "
1519  "lastScore < 0 && nextScore < 0, setting -10");
1520  }
1521  fbp->score -= 10;
1522  }
1523 
1524  if ((fbp->frames < (120*m_fps)) &&
1525  (lastScore < 0) &&
1526  (fbp->score > 0) &&
1527  (fbp->score < 20) &&
1528  (nextScore < 0))
1529  {
1530  if (m_verboseDebugging)
1531  {
1532  LOG(VB_COMMFLAG, LOG_DEBUG,
1533  " frames < 120 * m_fps && (-20 < lastScore < 0) && "
1534  "thisScore > 0 && nextScore < 0, setting score = -10");
1535  }
1536  fbp->score = -10;
1537  }
1538 
1539  if ((fbp->frames < (30*m_fps)) &&
1540  (lastScore > 0) &&
1541  (fbp->score < 0) &&
1542  (fbp->score > -20) &&
1543  (nextScore > 0))
1544  {
1545  if (m_verboseDebugging)
1546  {
1547  LOG(VB_COMMFLAG, LOG_DEBUG,
1548  " frames < 30 * m_fps && (0 < lastScore < 20) && "
1549  "thisScore < 0 && nextScore > 0, setting score = 10");
1550  }
1551  fbp->score = 10;
1552  }
1553  }
1554 
1555  if ((fbp->score == 0) && (lastScore > 30))
1556  {
1557  int offset = 1;
1558  while(((curBlock + offset) <= maxBlock) &&
1559  (fblock[curBlock + offset].frames < (2 * m_fps)) &&
1560  (fblock[curBlock + offset].score == 0))
1561  offset++;
1562 
1563  if ((curBlock + offset) <= maxBlock)
1564  {
1565  offset--;
1566  if (fblock[curBlock + offset + 1].score > 0)
1567  {
1568  for (; offset >= 0; offset--)
1569  {
1570  fblock[curBlock + offset].score += 10;
1571  if (m_verboseDebugging)
1572  {
1573  LOG(VB_COMMFLAG, LOG_DEBUG,
1574  QString(" Setting block %1 score +10")
1575  .arg(curBlock+offset));
1576  }
1577  }
1578  }
1579  else if (fblock[curBlock + offset + 1].score < 0)
1580  {
1581  for (; offset >= 0; offset--)
1582  {
1583  fblock[curBlock + offset].score -= 10;
1584  if (m_verboseDebugging)
1585  {
1586  LOG(VB_COMMFLAG, LOG_DEBUG,
1587  QString(" Setting block %1 score -10")
1588  .arg(curBlock+offset));
1589  }
1590  }
1591  }
1592  }
1593  }
1594 
1595  msg = FormatMsg("NOW", fbp);
1596  LOG(VB_COMMFLAG, LOG_DEBUG, msg);
1597 
1598  lastScore = fbp->score;
1599  curBlock++;
1600  }
1601 
1602  LOG(VB_COMMFLAG, LOG_DEBUG, "============================================");
1603  LOG(VB_COMMFLAG, LOG_INFO, "FINAL Block stats");
1604  LOG(VB_COMMFLAG, LOG_DEBUG,
1605  "Block StTime StFrm EndFrm Frames Secs "
1606  "Bf Lg Cnt RT Cnt SC Cnt SC Rt FmtMch AspMch Score");
1607  LOG(VB_COMMFLAG, LOG_DEBUG,
1608  "----- ------ ------ ------ ------ ------- "
1609  "--- ------ ------ ------ ----- ------ ------ -----");
1610  curBlock = 0;
1611  lastScore = 0;
1612  int64_t breakStart = -1;
1613  while (curBlock <= maxBlock)
1614  {
1615  fbp = &fblock[curBlock];
1616  int thisScore = fbp->score;
1617 
1618  if ((breakStart >= 0) &&
1619  ((fbp->end - breakStart) > (m_commDetectMaxCommBreakLength * m_fps)))
1620  {
1621  if (((fbp->start - breakStart) >
1623  (breakStart == 0))
1624  {
1625  if (m_verboseDebugging)
1626  {
1627  LOG(VB_COMMFLAG, LOG_DEBUG,
1628  QString("Closing commercial block at start of "
1629  "frame block %1 with length %2, frame "
1630  "block length of %3 frames would put comm "
1631  "block length over max of %4 seconds.")
1632  .arg(curBlock).arg(fbp->start - breakStart)
1633  .arg(fbp->frames)
1635  }
1636 
1637  m_commBreakMap[breakStart] = MARK_COMM_START;
1639  lastStart = breakStart;
1640  lastEnd = fbp->start;
1641  breakStart = -1;
1642  }
1643  else
1644  {
1645  if (m_verboseDebugging)
1646  {
1647  LOG(VB_COMMFLAG, LOG_DEBUG,
1648  QString("Ignoring what appears to be commercial"
1649  " block at frame %1 with length %2, "
1650  "length of %3 frames would put comm "
1651  "block length under min of %4 seconds.")
1652  .arg(breakStart)
1653  .arg(fbp->start - breakStart)
1654  .arg(fbp->frames)
1656  }
1657  breakStart = -1;
1658  }
1659  }
1660  if (thisScore == 0)
1661  {
1662  thisScore = lastScore;
1663  }
1664  else if (thisScore < 0)
1665  {
1666  if ((lastScore > 0) || (curBlock == 0))
1667  {
1668  if ((fbp->start - lastEnd) < (m_commDetectMinShowLength * m_fps))
1669  {
1670  m_commBreakMap.remove(lastStart);
1671  m_commBreakMap.remove(lastEnd);
1672  breakStart = lastStart;
1673 
1674  if (m_verboseDebugging)
1675  {
1676  if (breakStart)
1677  {
1678  LOG(VB_COMMFLAG, LOG_DEBUG,
1679  QString("ReOpening commercial block at "
1680  "frame %1 because show less than "
1681  "%2 seconds")
1682  .arg(breakStart)
1684  }
1685  else
1686  {
1687  LOG(VB_COMMFLAG, LOG_DEBUG,
1688  "Opening initial commercial block "
1689  "at start of recording, block 0.");
1690  }
1691  }
1692  }
1693  else
1694  {
1695  breakStart = fbp->start;
1696 
1697  if (m_verboseDebugging)
1698  {
1699  LOG(VB_COMMFLAG, LOG_DEBUG,
1700  QString("Starting new commercial block at "
1701  "frame %1 from start of frame block %2")
1702  .arg(fbp->start).arg(curBlock));
1703  }
1704  }
1705  }
1706  else if (curBlock == maxBlock)
1707  {
1708  if ((fbp->end - breakStart) >
1710  {
1711  if (fbp->end <=
1712  ((int64_t)m_framesProcessed - (int64_t)(2 * m_fps) - 2))
1713  {
1714  if (m_verboseDebugging)
1715  {
1716  LOG(VB_COMMFLAG, LOG_DEBUG,
1717  QString("Closing final commercial block at "
1718  "frame %1").arg(fbp->end));
1719  }
1720 
1721  m_commBreakMap[breakStart] = MARK_COMM_START;
1723  lastStart = breakStart;
1724  lastEnd = fbp->end;
1725  breakStart = -1;
1726  }
1727  }
1728  else
1729  {
1730  if (m_verboseDebugging)
1731  {
1732  LOG(VB_COMMFLAG, LOG_DEBUG,
1733  QString("Ignoring what appears to be commercial"
1734  " block at frame %1 with length %2, "
1735  "length of %3 frames would put comm "
1736  "block length under min of %4 seconds.")
1737  .arg(breakStart)
1738  .arg(fbp->start - breakStart)
1739  .arg(fbp->frames)
1741  }
1742  breakStart = -1;
1743  }
1744  }
1745  }
1746  // thisScore > 0
1747  else if ((lastScore < 0) &&
1748  (breakStart != -1))
1749  {
1750  if (((fbp->start - breakStart) >
1752  (breakStart == 0))
1753  {
1754  m_commBreakMap[breakStart] = MARK_COMM_START;
1756  lastStart = breakStart;
1757  lastEnd = fbp->start;
1758 
1759  if (m_verboseDebugging)
1760  {
1761  LOG(VB_COMMFLAG, LOG_DEBUG,
1762  QString("Closing commercial block at frame %1")
1763  .arg(fbp->start));
1764  }
1765  }
1766  else
1767  {
1768  if (m_verboseDebugging)
1769  {
1770  LOG(VB_COMMFLAG, LOG_DEBUG,
1771  QString("Ignoring what appears to be commercial "
1772  "block at frame %1 with length %2, "
1773  "length of %3 frames would put comm block "
1774  "length under min of %4 seconds.")
1775  .arg(breakStart)
1776  .arg(fbp->start - breakStart)
1777  .arg(fbp->frames)
1779  }
1780  }
1781  breakStart = -1;
1782  }
1783 
1784  msg = FormatMsg(curBlock, fbp);
1785  LOG(VB_COMMFLAG, LOG_DEBUG, msg);
1786 
1787  lastScore = thisScore;
1788  curBlock++;
1789  }
1790 
1791  if ((breakStart != -1) &&
1792  (breakStart <= ((int64_t)m_framesProcessed - (int64_t)(2 * m_fps) - 2)))
1793  {
1794  if (m_verboseDebugging)
1795  {
1796  LOG(VB_COMMFLAG, LOG_DEBUG,
1797  QString("Closing final commercial block started at "
1798  "block %1 and going to end of program. length "
1799  "is %2 frames")
1800  .arg(curBlock)
1801  .arg((m_framesProcessed - breakStart - 1)));
1802  }
1803 
1804  m_commBreakMap[breakStart] = MARK_COMM_START;
1805  // Create what is essentially an open-ended final skip region
1806  // by setting the end point 10 seconds past the end of the
1807  // recording.
1809  }
1810 
1811  // include/exclude blanks from comm breaks
1812  tmpCommMap = m_commBreakMap;
1813  m_commBreakMap.clear();
1814 
1815  if (m_verboseDebugging)
1816  LOG(VB_COMMFLAG, LOG_DEBUG,
1817  "Adjusting start/end marks according to blanks.");
1818  for (it = tmpCommMap.begin(); it != tmpCommMap.end(); ++it)
1819  {
1820  if (*it == MARK_COMM_START)
1821  {
1822  uint64_t lastStartLower = it.key();
1823  uint64_t lastStartUpper = it.key();
1824  while ((lastStartLower > 0) &&
1825  ((m_frameInfo[lastStartLower - 1].flagMask & COMM_FRAME_BLANK) != 0))
1826  lastStartLower--;
1827  while ((lastStartUpper < (m_framesProcessed - (2 * m_fps))) &&
1828  ((m_frameInfo[lastStartUpper + 1].flagMask & COMM_FRAME_BLANK) != 0))
1829  lastStartUpper++;
1830  uint64_t adj = (lastStartUpper - lastStartLower) / 2;
1831  if (adj > MAX_BLANK_FRAMES)
1832  adj = MAX_BLANK_FRAMES;
1833  lastStart = lastStartLower + adj;
1834 
1835  if (m_verboseDebugging)
1836  LOG(VB_COMMFLAG, LOG_DEBUG, QString("Start Mark: %1 -> %2")
1837  .arg(it.key()).arg(lastStart));
1838 
1839  m_commBreakMap[lastStart] = MARK_COMM_START;
1840  }
1841  else
1842  {
1843  uint64_t lastEndLower = it.key();
1844  uint64_t lastEndUpper = it.key();
1845  while ((lastEndUpper < (m_framesProcessed - (2 * m_fps))) &&
1846  ((m_frameInfo[lastEndUpper + 1].flagMask & COMM_FRAME_BLANK) != 0))
1847  lastEndUpper++;
1848  while ((lastEndLower > 0) &&
1849  ((m_frameInfo[lastEndLower - 1].flagMask & COMM_FRAME_BLANK) != 0))
1850  lastEndLower--;
1851  uint64_t adj = (lastEndUpper - lastEndLower) / 2;
1852  if (adj > MAX_BLANK_FRAMES)
1853  adj = MAX_BLANK_FRAMES;
1854  lastEnd = lastEndUpper - adj;
1855 
1856  if (m_verboseDebugging)
1857  LOG(VB_COMMFLAG, LOG_DEBUG, QString("End Mark : %1 -> %2")
1858  .arg(it.key()).arg(lastEnd));
1859 
1860  m_commBreakMap[lastEnd] = MARK_COMM_END;
1861  }
1862  }
1863 
1864  delete [] fblock;
1865 }
1866 
1867 
1869 {
1870  LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::BuildBlankFrameCommList()");
1871 
1872  if (m_blankFrameMap.count() == 0)
1873  return;
1874 
1875  auto *bframes = new long long[2_UZ * m_blankFrameMap.count()];
1876  auto *c_start = new long long[1_UZ * m_blankFrameMap.count()];
1877  auto *c_end = new long long[1_UZ * m_blankFrameMap.count()];
1878  int frames = 0;
1879  int commercials = 0;
1880 
1881  m_blankCommMap.clear();
1882 
1883  for (auto it = m_blankFrameMap.begin(); it != m_blankFrameMap.end(); ++it)
1884  bframes[frames++] = it.key();
1885 
1886  // detect individual commercials from blank frames
1887  // commercial end is set to frame right before ending blank frame to
1888  // account for instances with only a single blank frame between comms.
1889  for(int i = 0; i < frames; i++ )
1890  {
1891  for(int x=i+1; x < frames; x++ )
1892  {
1893  // check for various length spots since some channels don't
1894  // have blanks inbetween commercials just at the beginning and
1895  // end of breaks
1896  int gap_length = bframes[x] - bframes[i];
1897  if (((m_aggressiveDetection) &&
1898  ((abs((int)(gap_length - (5 * m_fps))) < 5 ) ||
1899  (abs((int)(gap_length - (10 * m_fps))) < 7 ) ||
1900  (abs((int)(gap_length - (15 * m_fps))) < 10 ) ||
1901  (abs((int)(gap_length - (20 * m_fps))) < 11 ) ||
1902  (abs((int)(gap_length - (30 * m_fps))) < 12 ) ||
1903  (abs((int)(gap_length - (40 * m_fps))) < 1 ) ||
1904  (abs((int)(gap_length - (45 * m_fps))) < 1 ) ||
1905  (abs((int)(gap_length - (60 * m_fps))) < 15 ) ||
1906  (abs((int)(gap_length - (90 * m_fps))) < 10 ) ||
1907  (abs((int)(gap_length - (120 * m_fps))) < 10 ))) ||
1908  ((!m_aggressiveDetection) &&
1909  ((abs((int)(gap_length - (5 * m_fps))) < 11 ) ||
1910  (abs((int)(gap_length - (10 * m_fps))) < 13 ) ||
1911  (abs((int)(gap_length - (15 * m_fps))) < 16 ) ||
1912  (abs((int)(gap_length - (20 * m_fps))) < 17 ) ||
1913  (abs((int)(gap_length - (30 * m_fps))) < 18 ) ||
1914  (abs((int)(gap_length - (40 * m_fps))) < 3 ) ||
1915  (abs((int)(gap_length - (45 * m_fps))) < 3 ) ||
1916  (abs((int)(gap_length - (60 * m_fps))) < 20 ) ||
1917  (abs((int)(gap_length - (90 * m_fps))) < 20 ) ||
1918  (abs((int)(gap_length - (120 * m_fps))) < 20 ))))
1919  {
1920  c_start[commercials] = bframes[i];
1921  c_end[commercials] = bframes[x] - 1;
1922  commercials++;
1923  i = x-1;
1924  x = frames;
1925  }
1926 
1927  if ((!m_aggressiveDetection) &&
1928  ((abs((int)(gap_length - (30 * m_fps))) < (int)(m_fps * 0.85)) ||
1929  (abs((int)(gap_length - (60 * m_fps))) < (int)(m_fps * 0.95)) ||
1930  (abs((int)(gap_length - (90 * m_fps))) < (int)(m_fps * 1.05)) ||
1931  (abs((int)(gap_length - (120 * m_fps))) < (int)(m_fps * 1.15))) &&
1932  ((x + 2) < frames) &&
1933  ((i + 2) < frames) &&
1934  ((bframes[i] + 1) == bframes[i+1]) &&
1935  ((bframes[x] + 1) == bframes[x+1]))
1936  {
1937  c_start[commercials] = bframes[i];
1938  c_end[commercials] = bframes[x];
1939  commercials++;
1940  i = x;
1941  x = frames;
1942  }
1943  }
1944  }
1945 
1946  int i = 0;
1947 
1948  // don't allow single commercial at head
1949  // of show unless followed by another
1950  if ((commercials > 1) &&
1951  (c_end[0] < (33 * m_fps)) &&
1952  (c_start[1] > (c_end[0] + 40 * m_fps)))
1953  i = 1;
1954 
1955  // eliminate any blank frames at end of commercials
1956  bool first_comm = true;
1957  for(; i < (commercials-1); i++)
1958  {
1959  long long r = c_start[i];
1960  long long adjustment = 0;
1961 
1962  if ((r < (30 * m_fps)) &&
1963  (first_comm))
1964  r = 1;
1965 
1967 
1968  r = c_end[i];
1969  if ( i < (commercials-1))
1970  {
1971  int x = 0;
1972  for(x = 0; x < (frames-1); x++)
1973  if (bframes[x] == r)
1974  break;
1975  while((x < (frames-1)) &&
1976  ((bframes[x] + 1 ) == bframes[x+1]) &&
1977  (bframes[x+1] < c_start[i+1]))
1978  {
1979  r++;
1980  x++;
1981  }
1982 
1983  while((m_blankFrameMap.contains(r+1)) &&
1984  (c_start[i+1] != (r+1)))
1985  {
1986  r++;
1987  adjustment++;
1988  }
1989  }
1990  else
1991  {
1992  while(m_blankFrameMap.contains(r+1))
1993  {
1994  r++;
1995  adjustment++;
1996  }
1997  }
1998 
1999  adjustment /= 2;
2000  if (adjustment > MAX_BLANK_FRAMES)
2001  adjustment = MAX_BLANK_FRAMES;
2002  r -= adjustment;
2004  first_comm = false;
2005  }
2006 
2007  m_blankCommMap[c_start[i]] = MARK_COMM_START;
2008  m_blankCommMap[c_end[i]] = MARK_COMM_END;
2009 
2010  delete[] c_start;
2011  delete[] c_end;
2012  delete[] bframes;
2013 
2014  LOG(VB_COMMFLAG, LOG_INFO, "Blank-Frame Commercial Map" );
2015  for(auto it = m_blankCommMap.begin(); it != m_blankCommMap.end(); ++it)
2016  LOG(VB_COMMFLAG, LOG_INFO, QString(" %1:%2")
2017  .arg(it.key()).arg(*it));
2018 
2020 
2021  LOG(VB_COMMFLAG, LOG_INFO, "Merged Blank-Frame Commercial Break Map" );
2022  for(auto it = m_blankCommBreakMap.begin(); it != m_blankCommBreakMap.end(); ++it)
2023  LOG(VB_COMMFLAG, LOG_INFO, QString(" %1:%2")
2024  .arg(it.key()).arg(*it));
2025 }
2026 
2027 
2029 {
2030  int section_start = -1;
2031  int seconds = (int)(m_framesProcessed / m_fps);
2032  int *sc_histogram = new int[seconds+1];
2033 
2034  m_sceneCommBreakMap.clear();
2035 
2036  memset(sc_histogram, 0, (seconds+1)*sizeof(int));
2037  for (uint64_t f = 1; f <= m_framesProcessed; f++)
2038  {
2039  if (m_sceneMap.contains(f))
2040  sc_histogram[(uint64_t)(f / m_fps)]++;
2041  }
2042 
2043  for(long long s = 0; s < (seconds + 1); s++)
2044  {
2045  if (sc_histogram[s] > 2)
2046  {
2047  if (section_start == -1)
2048  {
2049  auto f = (long long)(s * m_fps);
2050  for(int i = 0; i < m_fps; i++, f++)
2051  {
2052  if (m_sceneMap.contains(f))
2053  {
2055  i = (int)(m_fps) + 1;
2056  }
2057  }
2058  }
2059 
2060  section_start = s;
2061  }
2062 
2063  if ((section_start >= 0) &&
2064  (s > (section_start + 32)))
2065  {
2066  auto f = (long long)(section_start * m_fps);
2067  bool found_end = false;
2068 
2069  for(int i = 0; i < m_fps; i++, f++)
2070  {
2071  if (m_sceneMap.contains(f))
2072  {
2073  frm_dir_map_t::iterator dit = m_sceneCommBreakMap.find(f);
2074  if (dit != m_sceneCommBreakMap.end())
2075  m_sceneCommBreakMap.erase(dit);
2076  else
2078  i = (int)(m_fps) + 1;
2079  found_end = true;
2080  }
2081  }
2082  section_start = -1;
2083 
2084  if (!found_end)
2085  {
2086  f = (long long)(section_start * m_fps);
2088  }
2089  }
2090  }
2091  delete[] sc_histogram;
2092 
2093  if (section_start >= 0)
2095 
2096  frm_dir_map_t deleteMap;
2097  frm_dir_map_t::iterator it = m_sceneCommBreakMap.begin();
2098  frm_dir_map_t::iterator prev = it;
2099  if (it != m_sceneCommBreakMap.end())
2100  {
2101  ++it;
2102  while (it != m_sceneCommBreakMap.end())
2103  {
2104  if ((*it == MARK_COMM_END) &&
2105  (it.key() - prev.key()) < (30 * m_fps))
2106  {
2107  deleteMap[it.key()] = MARK_CUT_START;
2108  deleteMap[prev.key()] = MARK_CUT_START;
2109  }
2110  ++prev;
2111  if (it != m_sceneCommBreakMap.end())
2112  ++it;
2113  }
2114 
2115  frm_dir_map_t::iterator dit;
2116  for (dit = deleteMap.begin(); dit != deleteMap.end(); ++dit)
2117  m_sceneCommBreakMap.remove(dit.key());
2118  }
2119 
2120  LOG(VB_COMMFLAG, LOG_INFO, "Scene-Change Commercial Break Map" );
2121  for (it = m_sceneCommBreakMap.begin(); it != m_sceneCommBreakMap.end(); ++it)
2122  {
2123  LOG(VB_COMMFLAG, LOG_INFO, QString(" %1:%2")
2124  .arg(it.key()).arg(*it));
2125  }
2126 }
2127 
2128 
2130 {
2131  show_map_t showmap;
2132  GetLogoCommBreakMap(showmap);
2133  CondenseMarkMap(showmap, (int)(25 * m_fps), (int)(30 * m_fps));
2135 
2136  frm_dir_map_t::iterator it;
2137  LOG(VB_COMMFLAG, LOG_INFO, "Logo Commercial Break Map" );
2138  for(it = m_logoCommBreakMap.begin(); it != m_logoCommBreakMap.end(); ++it)
2139  LOG(VB_COMMFLAG, LOG_INFO, QString(" %1:%2")
2140  .arg(it.key()).arg(*it));
2141 }
2142 
2144 {
2145  frm_dir_map_t::iterator it;
2146  frm_dir_map_t::iterator prev;
2147  QMap<long long, long long> tmpMap;
2148  QMap<long long, long long>::Iterator tmpMap_it;
2149  QMap<long long, long long>::Iterator tmpMap_prev;
2150 
2151  m_blankCommBreakMap.clear();
2152 
2153  if (m_blankCommMap.isEmpty())
2154  return;
2155 
2156  for (it = m_blankCommMap.begin(); it != m_blankCommMap.end(); ++it)
2157  m_blankCommBreakMap[it.key()] = *it;
2158 
2159  if (m_blankCommBreakMap.isEmpty())
2160  return;
2161 
2162  it = m_blankCommMap.begin();
2163  prev = it;
2164  ++it;
2165  for(; it != m_blankCommMap.end(); ++it, ++prev)
2166  {
2167  // if next commercial starts less than 15*fps frames away then merge
2168  if ((((prev.key() + 1) == it.key()) ||
2169  ((prev.key() + (15 * m_fps)) > it.key())) &&
2170  (*prev == MARK_COMM_END) &&
2171  (*it == MARK_COMM_START))
2172  {
2173  m_blankCommBreakMap.remove(prev.key());
2174  m_blankCommBreakMap.remove(it.key());
2175  }
2176  }
2177 
2178 
2179  // make temp copy of commercial break list
2180  it = m_blankCommBreakMap.begin();
2181  prev = it;
2182  ++it;
2183  tmpMap[prev.key()] = it.key();
2184  for(; it != m_blankCommBreakMap.end(); ++it, ++prev)
2185  {
2186  if ((*prev == MARK_COMM_START) &&
2187  (*it == MARK_COMM_END))
2188  tmpMap[prev.key()] = it.key();
2189  }
2190 
2191  tmpMap_it = tmpMap.begin();
2192  tmpMap_prev = tmpMap_it;
2193  tmpMap_it++;
2194  for(; tmpMap_it != tmpMap.end(); ++tmpMap_it, ++tmpMap_prev)
2195  {
2196  // if we find any segments less than 35 seconds between commercial
2197  // breaks include those segments in the commercial break.
2198  if (((*tmpMap_prev + (35 * m_fps)) > tmpMap_it.key()) &&
2199  ((*tmpMap_prev - tmpMap_prev.key()) > (35 * m_fps)) &&
2200  ((*tmpMap_it - tmpMap_it.key()) > (35 * m_fps)))
2201  {
2202  m_blankCommBreakMap.remove(*tmpMap_prev);
2203  m_blankCommBreakMap.remove(tmpMap_it.key());
2204  }
2205  }
2206 }
2207 
2209  uint64_t f, const frm_dir_map_t &breakMap) const
2210 {
2211  for (uint64_t i = f; i < m_framesProcessed; i++)
2212  {
2213  if (breakMap.contains(i))
2214  {
2215  int type = breakMap[i];
2216  if ((type == MARK_COMM_END) || (i == f))
2217  return true;
2218  if (type == MARK_COMM_START)
2219  return false;
2220  }
2221  }
2222 
2223  // We want from f down to 0, but without wrapping the counter to negative
2224  // on an unsigned counter.
2225  for (uint64_t i = (f + 1); i-- > 0; )
2226  {
2227  if (breakMap.contains(i))
2228  {
2229  int type = breakMap[i];
2230  if ((type == MARK_COMM_START) || (i == f))
2231  return true;
2232  if (type == MARK_COMM_END)
2233  return false;
2234  }
2235  }
2236 
2237  return false;
2238 }
2239 
2241 {
2242  frm_dir_map_t::iterator it;
2243  QString msg;
2244 
2245  LOG(VB_COMMFLAG, LOG_INFO,
2246  "---------------------------------------------------");
2247  for (it = map.begin(); it != map.end(); ++it)
2248  {
2249  long long frame = it.key();
2250  int flag = *it;
2251  int my_fps = (int)ceil(m_fps);
2252  long long hour = (frame / my_fps) / 60 / 60;
2253  long long min = (frame / my_fps) / 60 - (hour * 60);
2254  long long sec = (frame / my_fps) - (min * 60) - (hour * 60 * 60);
2255  long long frm = frame - ((sec * my_fps) + (min * 60 * my_fps) +
2256  (hour * 60 * 60 * my_fps));
2257  int my_sec = (int)(frame / my_fps);
2258  msg = QString("%1 : %2 (%3:%4:%5.%6) (%7)")
2259  .arg(frame, 7).arg(flag).arg(hour, 2, 10, QChar('0')).arg(min, 2, 10, QChar('0'))
2260  .arg(sec, 2, 10, QChar('0')).arg(frm, 2, 10, QChar('0')).arg(my_sec);
2261  LOG(VB_COMMFLAG, LOG_INFO, msg);
2262  }
2263  LOG(VB_COMMFLAG, LOG_INFO,
2264  "---------------------------------------------------");
2265 }
2266 
2268  int length)
2269 {
2270  show_map_t::iterator it;
2271  show_map_t::iterator prev;
2272  show_map_t tmpMap;
2273 
2274  if (map.size() <= 2)
2275  return;
2276 
2277  // merge any segments less than 'spacing' frames apart from each other
2278  LOG(VB_COMMFLAG, LOG_INFO, "Commercial Map Before condense:" );
2279  for (it = map.begin(); it != map.end(); ++it)
2280  {
2281  LOG(VB_COMMFLAG, LOG_INFO, QString(" %1:%2")
2282  .arg(it.key()).arg(*it));
2283  tmpMap[it.key()] = *it;
2284  }
2285 
2286  prev = tmpMap.begin();
2287  it = prev;
2288  ++it;
2289  while (it != tmpMap.end())
2290  {
2291  if ((*it == MARK_START) &&
2292  (*prev == MARK_END) &&
2293  ((it.key() - prev.key()) < (uint64_t)spacing))
2294  {
2295  map.remove(prev.key());
2296  map.remove(it.key());
2297  }
2298  ++prev;
2299  ++it;
2300  }
2301 
2302  if (map.empty())
2303  return;
2304 
2305  // delete any segments less than 'length' frames in length
2306  tmpMap.clear();
2307  for (it = map.begin(); it != map.end(); ++it)
2308  tmpMap[it.key()] = *it;
2309 
2310  prev = tmpMap.begin();
2311  it = prev;
2312  ++it;
2313  while (it != tmpMap.end())
2314  {
2315  if ((*prev == MARK_START) &&
2316  (*it == MARK_END) &&
2317  ((it.key() - prev.key()) < (uint64_t)length))
2318  {
2319  map.remove(prev.key());
2320  map.remove(it.key());
2321  }
2322  ++prev;
2323  ++it;
2324  }
2325 
2326  LOG(VB_COMMFLAG, LOG_INFO, "Commercial Map After condense:" );
2327  for (it = map.begin(); it != map.end(); ++it)
2328  LOG(VB_COMMFLAG, LOG_INFO, QString(" %1:%2")
2329  .arg(it.key()).arg(*it));
2330 }
2331 
2333  frm_dir_map_t &out, const show_map_t &in)
2334 {
2335  out.clear();
2336  if (in.empty())
2337  return;
2338 
2339  show_map_t::const_iterator sit;
2340  for (sit = in.begin(); sit != in.end(); ++sit)
2341  {
2342  if (*sit == MARK_START)
2343  out[sit.key()] = MARK_COMM_END;
2344  else
2345  out[sit.key()] = MARK_COMM_START;
2346  }
2347 
2348  frm_dir_map_t::iterator it = out.begin();
2349  if (it == out.end())
2350  return;
2351 
2352  switch (out[it.key()])
2353  {
2354  case MARK_COMM_END:
2355  if (it.key() == 0)
2356  out.remove(0);
2357  else
2358  out[0] = MARK_COMM_START;
2359  break;
2360  case MARK_COMM_START:
2361  break;
2362  default:
2363  out.remove(0);
2364  break;
2365  }
2366 }
2367 
2368 
2369 /* ideas for this method ported back from comskip.c mods by Jere Jones
2370  * which are partially mods based on Myth's original commercial skip
2371  * code written by Chris Pinkham. */
2372 
2374 {
2375  LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::CleanupFrameInfo()");
2376 
2377  // try to account for noisy signal causing blank frames to be undetected
2378  if ((m_framesProcessed > (m_fps * 60)) &&
2379  (m_blankFrameCount < (m_framesProcessed * 0.0004)))
2380  {
2381  std::array<int,256> avgHistogram {};
2382  int minAvg = -1;
2383  int newThreshold = -1;
2384 
2385  LOG(VB_COMMFLAG, LOG_INFO,
2386  QString("ClassicCommDetect: Only found %1 blank frames but "
2387  "wanted at least %2, rechecking data using higher "
2388  "threshold.")
2389  .arg(m_blankFrameCount)
2390  .arg((int)(m_framesProcessed * 0.0004)));
2391  m_blankFrameMap.clear();
2392  m_blankFrameCount = 0;
2393 
2394  avgHistogram.fill(0);
2395 
2396  for (uint64_t i = 1; i <= m_framesProcessed; i++)
2397  avgHistogram[std::clamp(m_frameInfo[i].avgBrightness, 0, 255)] += 1;
2398 
2399  for (int i = 1; i <= 255 && minAvg == -1; i++)
2400  if (avgHistogram[i] > (m_framesProcessed * 0.0004))
2401  minAvg = i;
2402 
2403  newThreshold = minAvg + 3;
2404  LOG(VB_COMMFLAG, LOG_INFO,
2405  QString("Minimum Average Brightness on a frame "
2406  "was %1, will use %2 as new threshold")
2407  .arg(minAvg).arg(newThreshold));
2408 
2409  for (uint64_t i = 1; i <= m_framesProcessed; i++)
2410  {
2411  int value = m_frameInfo[i].flagMask;
2412  m_frameInfo[i].flagMask = value & ~COMM_FRAME_BLANK;
2413 
2414  if (( (m_frameInfo[i].flagMask & COMM_FRAME_BLANK) == 0) &&
2415  (m_frameInfo[i].avgBrightness < newThreshold))
2416  {
2417  m_frameInfo[i].flagMask = value | COMM_FRAME_BLANK;
2420  }
2421  }
2422 
2423  LOG(VB_COMMFLAG, LOG_INFO,
2424  QString("Found %1 blank frames using new value")
2425  .arg(m_blankFrameCount));
2426  }
2427 
2428  // try to account for fuzzy logo detection
2429  for (uint64_t i = 1; i <= m_framesProcessed; i++)
2430  {
2431  if ((i < 10) || ((i+10) > m_framesProcessed))
2432  continue;
2433 
2434  int before = 0;
2435  for (int offset = 1; offset <= 10; offset++)
2436  if ((m_frameInfo[i - offset].flagMask & COMM_FRAME_LOGO_PRESENT) != 0)
2437  before++;
2438 
2439  int after = 0;
2440  for (int offset = 1; offset <= 10; offset++)
2441  if ((m_frameInfo[i + offset].flagMask & COMM_FRAME_LOGO_PRESENT) != 0)
2442  after++;
2443 
2444  int value = m_frameInfo[i].flagMask;
2445  if (value == -1)
2446  m_frameInfo[i].flagMask = 0;
2447 
2448  if (value & COMM_FRAME_LOGO_PRESENT)
2449  {
2450  if ((before < 4) && (after < 4))
2451  m_frameInfo[i].flagMask = value & ~COMM_FRAME_LOGO_PRESENT;
2452  }
2453  else
2454  {
2455  if ((before > 6) && (after > 6))
2456  m_frameInfo[i].flagMask = value | COMM_FRAME_LOGO_PRESENT;
2457  }
2458  }
2459 }
2460 
2462 {
2463  LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::GetLogoCommBreakMap()");
2464 
2465  map.clear();
2466 
2467  bool PrevFrameLogo = false;
2468 
2469  for (uint64_t curFrame = 1 ; curFrame <= m_framesProcessed; curFrame++)
2470  {
2471  bool CurrentFrameLogo =
2472  (m_frameInfo[curFrame].flagMask & COMM_FRAME_LOGO_PRESENT) != 0;
2473 
2474  if (!PrevFrameLogo && CurrentFrameLogo)
2475  map[curFrame] = MARK_START;
2476  else if (PrevFrameLogo && !CurrentFrameLogo)
2477  map[curFrame] = MARK_END;
2478 
2479  PrevFrameLogo = CurrentFrameLogo;
2480  }
2481 }
2482 
2484 {
2485  emit breathe();
2486 }
2487 
2489  std::ostream &out, const frm_dir_map_t *comm_breaks, bool verbose) const
2490 {
2491  if (verbose)
2492  {
2493  QByteArray tmp = FrameInfoEntry::GetHeader().toLatin1();
2494  out << tmp.constData() << " mark" << std::endl;
2495  }
2496 
2497  for (long long i = 1; i < m_curFrameNumber; i++)
2498  {
2499  QMap<long long, FrameInfoEntry>::const_iterator it = m_frameInfo.find(i);
2500  if (it == m_frameInfo.end())
2501  continue;
2502 
2503  QByteArray atmp = (*it).toString(i, verbose).toLatin1();
2504  out << atmp.constData() << " ";
2505  if (comm_breaks)
2506  {
2507  frm_dir_map_t::const_iterator mit = comm_breaks->find(i);
2508  if (mit != comm_breaks->end())
2509  {
2510  QString tmp = (verbose) ?
2511  toString((MarkTypes)*mit) : QString::number(*mit);
2512  atmp = tmp.toLatin1();
2513 
2514  out << atmp.constData();
2515  }
2516  }
2517  out << "\n";
2518  }
2519 
2520  out << std::flush;
2521 }
2522 
2523 /* vim: set expandtab tabstop=4 shiftwidth=4: */
COMM_FRAME_SCENE_CHANGE
@ COMM_FRAME_SCENE_CHANGE
Definition: ClassicCommDetector.h:27
COMM_DETECT_SCENE
@ COMM_DETECT_SCENE
Definition: programtypes.h:134
ClassicCommDetector::m_lastFrameNumber
long long m_lastFrameNumber
Definition: ClassicCommDetector.h:155
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:39
COMM_DETECT_ALL
@ COMM_DETECT_ALL
Definition: programtypes.h:137
MARK_COMM_END
@ MARK_COMM_END
Definition: programtypes.h:60
frameFormats
frameFormats
Definition: ClassicCommDetector.cpp:31
COMM_FRAME_ASPECT_CHANGE
@ COMM_FRAME_ASPECT_CHANGE
Definition: ClassicCommDetector.h:29
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:143
ClassicCommDetector::m_logoCommBreakMap
frm_dir_map_t m_logoCommBreakMap
Definition: ClassicCommDetector.h:178
FrameInfoEntry::maxBrightness
int maxBrightness
Definition: ClassicCommDetector.h:37
CommDetectorBase::m_bPaused
bool m_bPaused
Definition: CommDetectorBase.h:52
FrameInfoEntry::avgBrightness
int avgBrightness
Definition: ClassicCommDetector.h:38
ClassicCommDetector::m_recordingStartedAt
QDateTime m_recordingStartedAt
Definition: ClassicCommDetector.h:191
FrameFormats
enum frameFormats FrameFormats
ClassicCommDetector::m_width
int m_width
Definition: ClassicCommDetector.h:158
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:89
ClassicCommDetector::m_recordingStopsAt
QDateTime m_recordingStopsAt
Definition: ClassicCommDetector.h:192
mythcommflagplayer.h
MythPlayer::OpenFile
virtual int OpenFile(int Retries=4)
Definition: mythplayer.cpp:420
ClassicCommDetector::m_commDetectBorder
int m_commDetectBorder
Definition: ClassicCommDetector.h:141
ClassicCommDetector::BuildLogoCommList
void BuildLogoCommList()
Definition: ClassicCommDetector.cpp:2129
CommDetectorBase::gotNewCommercialBreakList
void gotNewCommercialBreakList()
ClassicCommDetector::m_stationLogoPresent
bool m_stationLogoPresent
Definition: ClassicCommDetector.h:181
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:745
MARK_START
@ MARK_START
Definition: CommDetectorBase.h:14
ClassicCommDetector::m_commBreakMap
frm_dir_map_t m_commBreakMap
Definition: ClassicCommDetector.h:177
CommDetectorBase::statusUpdate
void statusUpdate(const QString &a)
frm_dir_map_t
QMap< uint64_t, MarkTypes > frm_dir_map_t
Frame # -> Mark map.
Definition: programtypes.h:118
ClassicCommDetector::UpdateFrameBlock
static void UpdateFrameBlock(FrameBlock *fbp, const FrameInfoEntry &finfo, int format, int aspect)
Definition: ClassicCommDetector.cpp:1143
ClassicCommDetector::logoDetectorBreathe
void logoDetectorBreathe()
Definition: ClassicCommDetector.cpp:2483
COMM_DETECT_OFF
@ COMM_DETECT_OFF
Definition: programtypes.h:131
LogoDetectorBase::searchForLogo
virtual bool searchForLogo(MythCommFlagPlayer *player)=0
MythPlayer::GetFrameRate
float GetFrameRate(void) const
Definition: mythplayer.h:134
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
ClassicCommDetector::m_sceneChangeDetector
SceneChangeDetectorBase * m_sceneChangeDetector
Definition: ClassicCommDetector.h:185
ClassicCommDetector::m_commDetectMinCommBreakLength
int m_commDetectMinCommBreakLength
Definition: ClassicCommDetector.h:148
ClassicCommDetector::m_sceneMap
frm_dir_map_t m_sceneMap
Definition: ClassicCommDetector.h:175
ClassicCommDetector::FrameBlock::end
long end
Definition: ClassicCommDetector.h:80
ClassicCommDetector::m_commDetectDimBrightness
int m_commDetectDimBrightness
Definition: ClassicCommDetector.h:144
ClassicCommDetector::FrameBlock::logoCount
int logoCount
Definition: ClassicCommDetector.h:84
pixel
static guint32 * pixel
--------------------------------------------------—**
Definition: goom_core.cpp:24
ClassicCommDetector::requestCommBreakMapUpdate
void requestCommBreakMapUpdate(void) override
Definition: ClassicCommDetector.cpp:701
MythPlayer::GetEof
EofState GetEof(void) const
Definition: mythplayer.cpp:1067
ClassicCommDetector::m_currentAspect
int m_currentAspect
Definition: ClassicCommDetector.h:164
ClassicCommDetector::m_commDetectMethod
SkipType m_commDetectMethod
Definition: ClassicCommDetector.h:136
ClassicCommDetector::Combine2Maps
frm_dir_map_t Combine2Maps(const frm_dir_map_t &a, const frm_dir_map_t &b) const
Definition: ClassicCommDetector.cpp:1044
COMM_FRAME_BLANK
@ COMM_FRAME_BLANK
Definition: ClassicCommDetector.h:26
FrameInfoEntry::minBrightness
int minBrightness
Definition: ClassicCommDetector.h:36
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:42
COMM_FRAME_RATING_SYMBOL
@ COMM_FRAME_RATING_SYMBOL
Definition: ClassicCommDetector.h:30
ClassicCommDetector::GetBlankCommMap
void GetBlankCommMap(frm_dir_map_t &comms)
Definition: ClassicCommDetector.cpp:1009
ClassicCommDetector::FormatMsg
QString FormatMsg(T first, const FrameBlock *fbp)
Definition: ClassicCommDetector.h:94
ClassicCommDetector::PrintFullMap
void PrintFullMap(std::ostream &out, const frm_dir_map_t *comm_breaks, bool verbose) const override
Definition: ClassicCommDetector.cpp:2488
tmp
static guint32 * tmp
Definition: goom_core.cpp:26
LogoDetectorBase::getRequiredAvailableBufferForSearch
virtual unsigned int getRequiredAvailableBufferForSearch()=0
ClassicCommDetector::FrameBlock::ratingCount
int ratingCount
Definition: ClassicCommDetector.h:85
ClassicCommDetector::GetSceneChangeMap
void GetSceneChangeMap(frm_dir_map_t &scenes, int64_t start_frame)
Definition: ClassicCommDetector.cpp:1029
ClassicCommDetector::m_stillRecording
bool m_stillRecording
Definition: ClassicCommDetector.h:194
ClassicCommDetector::FrameBlock::scRate
double scRate
Definition: ClassicCommDetector.h:87
ClassicCommDetector::BuildSceneChangeCommList
void BuildSceneChangeCommList(void)
Definition: ClassicCommDetector.cpp:2028
MARK_END
@ MARK_END
Definition: CommDetectorBase.h:15
COMM_DETECT_BLANKS
@ COMM_DETECT_BLANKS
Definition: programtypes.h:133
SceneChangeDetectorBase::haveNewInformation
void haveNewInformation(unsigned int framenum, bool scenechange, float debugValue=0.0)
programinfo.h
ClassicCommDetector::BuildBlankFrameCommList
void BuildBlankFrameCommList(void)
Definition: ClassicCommDetector.cpp:1868
FrameInfoEntry::GetHeader
static QString GetHeader(void)
Definition: ClassicCommDetector.cpp:101
ClassicCommDetector::m_blankCommMap
frm_dir_map_t m_blankCommMap
Definition: ClassicCommDetector.h:173
ClassicCommDetector::m_lastSentCommBreakMap
frm_dir_map_t m_lastSentCommBreakMap
Definition: ClassicCommDetector.h:137
ClassicCommDetector::FrameBlock
Definition: ClassicCommDetector.h:77
ClassicCommDetector::m_horizSpacing
int m_horizSpacing
Definition: ClassicCommDetector.h:160
FMT_YV12
@ FMT_YV12
Definition: mythframe.h:24
ClassicCommDetector::FrameBlock::formatMatch
int formatMatch
Definition: ClassicCommDetector.h:88
ClassicCommDetector::FrameIsInBreakMap
bool FrameIsInBreakMap(uint64_t f, const frm_dir_map_t &breakMap) const
Definition: ClassicCommDetector.cpp:2208
COMM_FORMAT_MAX
@ COMM_FORMAT_MAX
Definition: ClassicCommDetector.cpp:35
COMM_FRAME_SKIPPED
@ COMM_FRAME_SKIPPED
Definition: ClassicCommDetector.h:25
ClassicCommDetector::m_frameInfo
QMap< long long, FrameInfoEntry > m_frameInfo
Definition: ClassicCommDetector.h:206
ClassicCommDetector::m_blankCommBreakMap
frm_dir_map_t m_blankCommBreakMap
Definition: ClassicCommDetector.h:174
ClassicCommDetector::m_verboseDebugging
bool m_verboseDebugging
Definition: ClassicCommDetector.h:153
ClassicCommDetector::m_commDetectBoxBrightness
int m_commDetectBoxBrightness
Definition: ClassicCommDetector.h:145
FrameInfoEntry
Definition: ClassicCommDetector.h:33
MythPlayer::InitVideo
virtual bool InitVideo(void)
Definition: mythplayer.cpp:273
ClassicCommDetector::GetLogoCommBreakMap
void GetLogoCommBreakMap(show_map_t &map)
Definition: ClassicCommDetector.cpp:2461
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:199
MythCommFlagPlayer
Definition: mythcommflagplayer.h:25
hardwareprofile.smolt.long
long
Definition: smolt.py:75
ClassicCommDetector::m_fullSpeed
bool m_fullSpeed
Definition: ClassicCommDetector.h:195
ClassicCommDetector::FrameBlock::frames
long frames
Definition: ClassicCommDetector.h:81
ClassicCommDetector::m_commDetectMaxCommBreakLength
int m_commDetectMaxCommBreakLength
Definition: ClassicCommDetector.h:147
LogoDetectorBase::pixelInsideLogo
virtual bool pixelInsideLogo(unsigned int x, unsigned int y)=0
ClassicCommDetector::m_stopsAt
QDateTime m_stopsAt
Definition: ClassicCommDetector.h:190
ClassicCommDetector::ClearAllMaps
void ClearAllMaps(void)
Definition: ClassicCommDetector.cpp:996
floatusecs
std::chrono::duration< double, std::micro > floatusecs
Definition: mythchrono.h:41
ClassicCommDetector::m_blankFrameCount
int m_blankFrameCount
Definition: ClassicCommDetector.h:163
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:707
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:912
ClassicCommDetector::m_framesProcessed
uint64_t m_framesProcessed
Definition: ClassicCommDetector.h:198
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:53
MythCoreContext::GetBoolSetting
bool GetBoolSetting(const QString &key, bool defaultval=false)
Definition: mythcorecontext.cpp:906
ClassicCommDetector::m_vertSpacing
int m_vertSpacing
Definition: ClassicCommDetector.h:161
ClassicCommDetector::DumpMap
void DumpMap(frm_dir_map_t &map) const
Definition: ClassicCommDetector.cpp:2240
ClassicCommDetector::m_decoderFoundAspectChanges
bool m_decoderFoundAspectChanges
Definition: ClassicCommDetector.h:183
ClassicCommDetector::m_commDetectMinShowLength
int m_commDetectMinShowLength
Definition: ClassicCommDetector.h:149
ClassicCommDetector::m_curFrameNumber
long long m_curFrameNumber
Definition: ClassicCommDetector.h:156
MARK_CUT_START
@ MARK_CUT_START
Definition: programtypes.h:56
ClassicCommDetector::m_commDetectDimAverage
int m_commDetectDimAverage
Definition: ClassicCommDetector.h:146
ClassicCommDetector::GetBlankCommBreakMap
void GetBlankCommBreakMap(frm_dir_map_t &comms)
Definition: ClassicCommDetector.cpp:1019
toStringFrameFormats
static QString toStringFrameFormats(int format, bool verbose)
Definition: ClassicCommDetector.cpp:82
ClassicCommDetector::FrameBlock::score
int score
Definition: ClassicCommDetector.h:90
ClassicCommDetector::m_fps
double m_fps
Definition: ClassicCommDetector.h:197
ClassicCommDetector::CondenseMarkMap
static void CondenseMarkMap(show_map_t &map, int spacing, int length)
Definition: ClassicCommDetector.cpp:2267
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:170
ClassicCommDetector::m_sendCommBreakMapUpdates
bool m_sendCommBreakMapUpdates
Definition: ClassicCommDetector.h:139
FrameInfoEntry::toString
QString toString(uint64_t frame, bool verbose) const
Definition: ClassicCommDetector.cpp:106
ClassicCommDetector::MergeBlankCommList
void MergeBlankCommList(void)
Definition: ClassicCommDetector.cpp:2143
MythVideoFrame::m_type
VideoFrameType m_type
Definition: mythframe.h:119
ClassicCommDetector::BuildAllMethodsCommList
void BuildAllMethodsCommList(void)
Definition: ClassicCommDetector.cpp:1167
ClassicCommDetector::go
bool go() override
Definition: ClassicCommDetector.cpp:281
ClassicCommDetector::m_sceneCommBreakMap
frm_dir_map_t m_sceneCommBreakMap
Definition: ClassicCommDetector.h:176
MythDate
Definition: mythdate.cpp:11
COMM_FORMAT_NORMAL
@ COMM_FORMAT_NORMAL
Definition: ClassicCommDetector.cpp:32
MARK_SCENE_CHANGE
@ MARK_SCENE_CHANGE
Definition: programtypes.h:63
std
Definition: mythchrono.h:23
MarkTypes
MarkTypes
Definition: programtypes.h:47
MythPlayer::GetVideoSize
QSize GetVideoSize(void) const
Definition: mythplayer.h:132
ClassicCommDetector::m_frameIsBlank
bool m_frameIsBlank
Definition: ClassicCommDetector.h:180
MythPlayer::GetVideoAspect
float GetVideoAspect(void) const
Definition: mythplayer.h:133
ClassicCommDetector::m_totalMinBrightness
int m_totalMinBrightness
Definition: ClassicCommDetector.h:167
mythcontext.h
ClassicCommDetector::m_logoInfoAvailable
bool m_logoInfoAvailable
Definition: ClassicCommDetector.h:169
MythPlayer::ResetTotalDuration
void ResetTotalDuration(void)
Definition: mythplayer.cpp:1972
ClassicCommDetector::m_aggressiveDetection
bool m_aggressiveDetection
Definition: ClassicCommDetector.h:193
marks
static const std::array< const mark, 16 > marks
Definition: lang.cpp:23
ClassicCommDetector::m_commDetectBlankFrameMaxDiff
int m_commDetectBlankFrameMaxDiff
Definition: ClassicCommDetector.h:142
ClassicCommDetector::FrameBlock::length
double length
Definition: ClassicCommDetector.h:82
COMM_FORMAT_LETTERBOX
@ COMM_FORMAT_LETTERBOX
Definition: ClassicCommDetector.cpp:33
SkipType
SkipType
This is used as a bitmask.
Definition: programtypes.h:128
ClassicCommDetector::m_commDetectMaxCommLength
int m_commDetectMaxCommLength
Definition: ClassicCommDetector.h:150
hardwareprofile.distros.mythtv_data.makeopts.verbose
verbose
Definition: makeopts.py:60
FrameInfoEntry::format
int format
Definition: ClassicCommDetector.h:41
MAX_BLANK_FRAMES
static constexpr int64_t MAX_BLANK_FRAMES
Definition: CommDetectorBase.h:11
ClassicSceneChangeDetector.h
ClassicCommDetector::FrameBlock::start
long start
Definition: ClassicCommDetector.h:79
MythVideoFrame
Definition: mythframe.h:88
ClassicCommDetector::ClassicLogoDetector
friend class ClassicLogoDetector
Definition: ClassicCommDetector.h:71
ClassicCommDetector::m_commBreakMapUpdateRequested
bool m_commBreakMapUpdateRequested
Definition: ClassicCommDetector.h:138
ClassicCommDetector::m_commDetectDarkBrightness
int m_commDetectDarkBrightness
Definition: ClassicCommDetector.h:143
ClassicSceneChangeDetector
Definition: ClassicSceneChangeDetector.h:8
ClassicCommDetector::m_blankFrameMap
frm_dir_map_t m_blankFrameMap
Definition: ClassicCommDetector.h:172
ClassicCommDetector::CleanupFrameInfo
void CleanupFrameInfo(void)
Definition: ClassicCommDetector.cpp:2373
toStringFrameAspects
static QString toStringFrameAspects(int aspect, bool verbose)
Definition: ClassicCommDetector.cpp:75
COMM_DETECT_LOGO
@ COMM_DETECT_LOGO
Definition: programtypes.h:135
ClassicCommDetector::m_commDetectBlankCanHaveLogo
bool m_commDetectBlankCanHaveLogo
Definition: ClassicCommDetector.h:151
LogoDetectorBase::doesThisFrameContainTheFoundLogo
virtual bool doesThisFrameContainTheFoundLogo(MythVideoFrame *frame)=0
ClassicCommDetector::FrameBlock::scCount
int scCount
Definition: ClassicCommDetector.h:86
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:200
MARK_COMM_START
@ MARK_COMM_START
Definition: programtypes.h:59
ClassicCommDetector::recordingFinished
void recordingFinished(long long totalFileSize) override
Definition: ClassicCommDetector.cpp:696
ClassicCommDetector::FrameBlock::bfCount
int bfCount
Definition: ClassicCommDetector.h:83
COMM_FRAME_LOGO_PRESENT
@ COMM_FRAME_LOGO_PRESENT
Definition: ClassicCommDetector.h:28
ClassicCommDetector::m_showProgress
bool m_showProgress
Definition: ClassicCommDetector.h:196
ClassicCommDetector::m_height
int m_height
Definition: ClassicCommDetector.h:159
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:58
FrameInfoEntry::aspect
int aspect
Definition: ClassicCommDetector.h:40
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:2332
ClassicCommDetector::m_startedAt
QDateTime m_startedAt
Definition: ClassicCommDetector.h:189
ClassicCommDetector::m_player
MythCommFlagPlayer * m_player
Definition: ClassicCommDetector.h:188
COMM_DETECT_BLANK
@ COMM_DETECT_BLANK
Definition: programtypes.h:132
MythPlayer::DiscardVideoFrame
void DiscardVideoFrame(MythVideoFrame *buffer)
Places frame in the available frames queue.
Definition: mythplayer.cpp:629