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 
368  if (m_showProgress)
369  {
370  std::cerr << "\b\b\b\b\b\b\b\b\b\b\b\b "
371  "\b\b\b\b\b\b\b\b\b\b\b\b";
372  std::cerr.flush();
373  }
374  }
375 
376  emit breathe();
377  if (m_bStop)
378  return false;
379 
380  QElapsedTimer flagTime;
381  flagTime.start();
382 
383  long long myTotalFrames = 0;
385  myTotalFrames = m_player->GetTotalFrameCount();
386  else
387  myTotalFrames = (long long)(m_player->GetFrameRate() *
389 
390  if (m_showProgress)
391  {
392  if (myTotalFrames)
393  std::cerr << "\r 0%/ \r" << std::flush;
394  else
395  std::cerr << "\r 0/ \r" << std::flush;
396  }
397 
398 
399  float aspect = m_player->GetVideoAspect();
400  int prevpercent = -1;
401 
402  SetVideoParams(aspect);
403 
404  emit breathe();
405 
407 
408  while (m_player->GetEof() == kEofStateNone)
409  {
410  std::chrono::microseconds startTime {0us};
411  if (m_stillRecording)
412  startTime = nowAsDuration<std::chrono::microseconds>();
413 
414  MythVideoFrame* currentFrame = m_player->GetRawVideoFrame();
415  long long currentFrameNumber = currentFrame->m_frameNumber;
416 
417  //Lucas: maybe we should make the nuppelvideoplayer send out a signal
418  //when the aspect ratio changes.
419  //In order to not change too many things at a time, I"m using basic
420  //polling for now.
421  float newAspect = currentFrame->m_aspect;
422  if (newAspect != aspect)
423  {
424  SetVideoParams(aspect);
425  aspect = newAspect;
426  }
427 
428  if (((currentFrameNumber % 500) == 0) ||
429  (((currentFrameNumber % 100) == 0) &&
430  (m_stillRecording)))
431  {
432  emit breathe();
433  if (m_bStop)
434  {
435  m_player->DiscardVideoFrame(currentFrame);
436  return false;
437  }
438  }
439 
442  ((currentFrameNumber % 500) == 0)))
443  {
444  frm_dir_map_t commBreakMap;
445  frm_dir_map_t::iterator it;
446  frm_dir_map_t::iterator lastIt;
447  bool mapsAreIdentical = false;
448 
449  GetCommercialBreakList(commBreakMap);
450 
451  if ((commBreakMap.empty()) &&
452  (m_lastSentCommBreakMap.empty()))
453  {
454  mapsAreIdentical = true;
455  }
456  else if (commBreakMap.size() == m_lastSentCommBreakMap.size())
457  {
458  // assume true for now and set false if we find a difference
459  mapsAreIdentical = true;
460  for (it = commBreakMap.begin();
461  it != commBreakMap.end() && mapsAreIdentical; ++it)
462  {
463  lastIt = m_lastSentCommBreakMap.find(it.key());
464  if ((lastIt == m_lastSentCommBreakMap.end()) ||
465  (*lastIt != *it))
466  mapsAreIdentical = false;
467  }
468  }
469 
470  if (m_commBreakMapUpdateRequested || !mapsAreIdentical)
471  {
473  m_lastSentCommBreakMap = commBreakMap;
474  }
475 
478  }
479 
480  while (m_bPaused)
481  {
482  emit breathe();
483  std::this_thread::sleep_for(1s);
484  }
485 
486  // sleep a little so we don't use all cpu even if we're niced
487  if (!m_fullSpeed && !m_stillRecording)
488  std::this_thread::sleep_for(10ms);
489 
490  if (((currentFrameNumber % 500) == 0) ||
492  ((currentFrameNumber % 100) == 0)))
493  {
494  float flagFPS { 0.0 };
495  float elapsed = flagTime.elapsed() / 1000.0;
496 
497  if (elapsed != 0.0F)
498  flagFPS = currentFrameNumber / elapsed;
499  else
500  flagFPS = 0.0;
501 
502  int percentage = 0;
503  if (myTotalFrames)
504  percentage = currentFrameNumber * 100 / myTotalFrames;
505 
506  if (percentage > 100)
507  percentage = 100;
508 
509  if (m_showProgress)
510  {
511  if (myTotalFrames)
512  {
513  QString tmp = QString("\r%1%/%2fps \r")
514  .arg(percentage, 3).arg((int)flagFPS, 4);
515  std::cerr << qPrintable(tmp) << std::flush;
516  }
517  else
518  {
519  QString tmp = QString("\r%1/%2fps \r")
520  .arg(currentFrameNumber, 6).arg((int)flagFPS, 4);
521  std::cerr << qPrintable(tmp) << std::flush;
522  }
523  }
524 
525  if (myTotalFrames)
526  {
527  emit statusUpdate(QCoreApplication::translate("(mythcommflag)",
528  "%1% Completed @ %2 fps.")
529  .arg(percentage).arg(flagFPS));
530  }
531  else
532  {
533  emit statusUpdate(QCoreApplication::translate("(mythcommflag)",
534  "%1 Frames Completed @ %2 fps.")
535  .arg(currentFrameNumber).arg(flagFPS));
536  }
537 
538  if (percentage % 10 == 0 && prevpercent != percentage)
539  {
540  prevpercent = percentage;
541  LOG(VB_GENERAL, LOG_INFO, QString("%1%% Completed @ %2 fps.")
542  .arg(percentage) .arg(flagFPS));
543  }
544  }
545 
546  ProcessFrame(currentFrame, currentFrameNumber);
547 
548  if (m_stillRecording)
549  {
550  int secondsRecorded =
552  int secondsFlagged = (int)(m_framesProcessed / m_fps);
553  int secondsBehind = secondsRecorded - secondsFlagged;
554  auto usecPerFrame = floatusecs(1000000.0F / m_player->GetFrameRate());
555 
556  auto endTime = nowAsDuration<std::chrono::microseconds>();
557 
558  floatusecs usecSleep = usecPerFrame - (endTime - startTime);
559 
560  if (secondsBehind > requiredBuffer)
561  {
562  if (m_fullSpeed)
563  usecSleep = 0us;
564  else
565  usecSleep = usecSleep * 0.25;
566  }
567  else if (secondsBehind < requiredBuffer)
568  usecSleep = usecPerFrame * 1.5;
569 
570  if (usecSleep > 0us)
571  std::this_thread::sleep_for(usecSleep);
572  }
573 
574  m_player->DiscardVideoFrame(currentFrame);
575  }
576 
577  if (m_showProgress)
578  {
579 #if 0
580  float elapsed = flagTime.elapsed() / 1000.0;
581 
582  if (elapsed)
583  flagFPS = currentFrameNumber / elapsed;
584  else
585  flagFPS = 0.0;
586 #endif
587 
588  if (myTotalFrames)
589  std::cerr << "\b\b\b\b\b\b \b\b\b\b\b\b";
590  else
591  std::cerr << "\b\b\b\b\b\b\b\b\b\b\b\b\b "
592  "\b\b\b\b\b\b\b\b\b\b\b\b\b";
593  std::cerr.flush();
594  }
595 
596  return true;
597 }
598 
600  unsigned int framenum,bool isSceneChange,float debugValue)
601 {
602  if (isSceneChange)
603  {
604  m_frameInfo[framenum].flagMask |= COMM_FRAME_SCENE_CHANGE;
605  m_sceneMap[framenum] = MARK_SCENE_CHANGE;
606  }
607  else
608  {
609  m_frameInfo[framenum].flagMask &= ~COMM_FRAME_SCENE_CHANGE;
610  m_sceneMap.remove(framenum);
611  }
612 
613  m_frameInfo[framenum].sceneChangePercent = (int) (debugValue*100);
614 }
615 
617 {
618 
619  LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::GetCommBreakMap()");
620 
621  marks.clear();
622 
624 
625  bool blank = (COMM_DETECT_BLANK & m_commDetectMethod) != 0;
626  bool scene = (COMM_DETECT_SCENE & m_commDetectMethod) != 0;
627  bool logo = (COMM_DETECT_LOGO & m_commDetectMethod) != 0;
628 
630  return;
631 
632  if (!blank && !scene && !logo)
633  {
634  LOG(VB_COMMFLAG, LOG_ERR, QString("Unexpected commDetectMethod: 0x%1")
635  .arg(m_commDetectMethod,0,16));
636  return;
637  }
638 
639  if (blank && scene && logo)
640  {
643  LOG(VB_COMMFLAG, LOG_INFO, "Final Commercial Break Map");
644  return;
645  }
646 
647  if (blank)
648  {
651  }
652 
653  if (scene)
654  {
657  }
658 
659  if (logo)
660  {
663  }
664 
665  int cnt = ((blank) ? 1 : 0) + ((scene) ? 1 : 0) + ((logo) ? 1 : 0);
666  if (cnt == 2)
667  {
668  if (blank && scene)
669  {
672  }
673  else if (blank && logo)
674  {
677  }
678  else if (scene && logo)
679  {
682  }
683  }
684 
685  LOG(VB_COMMFLAG, LOG_INFO, "Final Commercial Break Map");
686 }
687 
688 void ClassicCommDetector::recordingFinished(long long totalFileSize)
689 {
690  (void)totalFileSize;
691 
692  m_stillRecording = false;
693 }
694 
696 {
699 }
700 
702 {
703  int newAspect = COMM_ASPECT_WIDE;
704 
705  LOG(VB_COMMFLAG, LOG_INFO,
706  QString("CommDetect::SetVideoParams called with aspect = %1")
707  .arg(aspect));
708  // Default to Widescreen but use the same check as VideoOutput::MoveResize()
709  // to determine if is normal 4:3 aspect
710  if (fabs(aspect - 1.333333F) < 0.1F)
711  newAspect = COMM_ASPECT_NORMAL;
712 
713  if (newAspect != m_currentAspect)
714  {
715  LOG(VB_COMMFLAG, LOG_INFO,
716  QString("Aspect Ratio changed from %1 to %2 at frame %3")
717  .arg(m_currentAspect).arg(newAspect)
718  .arg(m_curFrameNumber));
719 
720  if (m_frameInfo.contains(m_curFrameNumber))
721  {
722  // pretend that this frame is blank so that we can create test
723  // blocks on real aspect ratio change boundaries.
727  }
728  else if (m_curFrameNumber != -1)
729  {
730  LOG(VB_COMMFLAG, LOG_ERR,
731  QString("Unable to keep track of Aspect ratio change because "
732  "frameInfo for frame number %1 does not exist.")
733  .arg(m_curFrameNumber));
734  }
735  m_currentAspect = newAspect;
736  }
737 }
738 
740  long long frame_number)
741 {
742  int max = 0;
743  int min = 255;
744  int blankPixelsChecked = 0;
745  long long totBrightness = 0;
746  auto *rowMax = new unsigned char[m_height];
747  auto *colMax = new unsigned char[m_width];
748  memset(rowMax, 0, sizeof(*rowMax)*m_height);
749  memset(colMax, 0, sizeof(*colMax)*m_width);
750  int topDarkRow = m_commDetectBorder;
751  int bottomDarkRow = m_height - m_commDetectBorder - 1;
752  int leftDarkCol = m_commDetectBorder;
753  int rightDarkCol = m_width - m_commDetectBorder - 1;
754  FrameInfoEntry fInfo {};
755 
756  if (!frame || !(frame->m_buffer) || frame_number == -1 ||
757  frame->m_type != FMT_YV12)
758  {
759  LOG(VB_COMMFLAG, LOG_ERR, "CommDetect: Invalid video frame or codec, "
760  "unable to process frame.");
761  delete[] rowMax;
762  delete[] colMax;
763  return;
764  }
765 
766  if (!m_width || !m_height)
767  {
768  LOG(VB_COMMFLAG, LOG_ERR, "CommDetect: Width or Height is 0, "
769  "unable to process frame.");
770  delete[] rowMax;
771  delete[] colMax;
772  return;
773  }
774 
775  m_curFrameNumber = frame_number;
776  unsigned char* framePtr = frame->m_buffer;
777  int bytesPerLine = frame->m_pitches[0];
778 
779  fInfo.minBrightness = -1;
780  fInfo.maxBrightness = -1;
781  fInfo.avgBrightness = -1;
782  fInfo.sceneChangePercent = -1;
783  fInfo.aspect = m_currentAspect;
784  fInfo.format = COMM_FORMAT_NORMAL;
785  fInfo.flagMask = 0;
786 
787  int& flagMask = m_frameInfo[m_curFrameNumber].flagMask;
788 
789  // Fill in dummy info records for skipped frames.
790  if (m_lastFrameNumber != (m_curFrameNumber - 1))
791  {
792  if (m_lastFrameNumber > 0)
793  {
794  fInfo.aspect = m_frameInfo[m_lastFrameNumber].aspect;
795  fInfo.format = m_frameInfo[m_lastFrameNumber].format;
796  }
797  fInfo.flagMask = COMM_FRAME_SKIPPED;
798 
801  m_frameInfo[m_lastFrameNumber++] = fInfo;
802 
803  fInfo.flagMask = 0;
804  }
806 
807  m_frameInfo[m_curFrameNumber] = fInfo;
808 
810  m_frameIsBlank = false;
811 
813  {
815  }
816 
817  m_stationLogoPresent = false;
818 
819  for(int y = m_commDetectBorder; y < (m_height - m_commDetectBorder);
820  y += m_vertSpacing)
821  {
822  for(int x = m_commDetectBorder; x < (m_width - m_commDetectBorder);
823  x += m_horizSpacing)
824  {
825  uchar pixel = framePtr[y * bytesPerLine + x];
826 
828  {
829  bool checkPixel = false;
831  checkPixel = true;
832 
833  if (!m_logoInfoAvailable ||
835  checkPixel=true;
836 
837  if (checkPixel)
838  {
839  blankPixelsChecked++;
840  totBrightness += pixel;
841 
842  if (pixel < min)
843  min = pixel;
844 
845  if (pixel > max)
846  max = pixel;
847 
848  if (pixel > rowMax[y])
849  rowMax[y] = pixel;
850 
851  if (pixel > colMax[x])
852  colMax[x] = pixel;
853  }
854  }
855  }
856  }
857 
858  if ((m_commDetectMethod & COMM_DETECT_BLANKS) && blankPixelsChecked)
859  {
860  for(int y = m_commDetectBorder; y < (m_height - m_commDetectBorder);
861  y += m_vertSpacing)
862  {
863  if (rowMax[y] > m_commDetectBoxBrightness)
864  break;
865  topDarkRow = y;
866  }
867 
868  for(int y = m_commDetectBorder; y < (m_height - m_commDetectBorder);
869  y += m_vertSpacing)
870  if (rowMax[y] >= m_commDetectBoxBrightness)
871  bottomDarkRow = y;
872 
873  delete[] rowMax;
874  rowMax = nullptr;
875 
876  for(int x = m_commDetectBorder; x < (m_width - m_commDetectBorder);
877  x += m_horizSpacing)
878  {
879  if (colMax[x] > m_commDetectBoxBrightness)
880  break;
881  leftDarkCol = x;
882  }
883 
884  for(int x = m_commDetectBorder; x < (m_width - m_commDetectBorder);
885  x += m_horizSpacing)
886  if (colMax[x] >= m_commDetectBoxBrightness)
887  rightDarkCol = x;
888 
889  delete[] colMax;
890  colMax = nullptr;
891 
893  if ((topDarkRow > m_commDetectBorder) &&
894  (topDarkRow < (m_height * .20)) &&
895  (bottomDarkRow < (m_height - m_commDetectBorder)) &&
896  (bottomDarkRow > (m_height * .80)))
897  {
899  }
900  if ((leftDarkCol > m_commDetectBorder) &&
901  (leftDarkCol < (m_width * .20)) &&
902  (rightDarkCol < (m_width - m_commDetectBorder)) &&
903  (rightDarkCol > (m_width * .80)))
904  {
906  }
907 
908  int avg = totBrightness / blankPixelsChecked;
909 
910  m_frameInfo[m_curFrameNumber].minBrightness = min;
911  m_frameInfo[m_curFrameNumber].maxBrightness = max;
912  m_frameInfo[m_curFrameNumber].avgBrightness = avg;
913 
914  m_totalMinBrightness += min;
915  m_commDetectDimAverage = min + 10;
916 
917  // Is the frame really dark
918  if (((max - min) <= m_commDetectBlankFrameMaxDiff) &&
920  m_frameIsBlank = true;
921 
922  // Are we non-strict and the frame is blank
923  if ((!m_aggressiveDetection) &&
924  ((max - min) <= m_commDetectBlankFrameMaxDiff))
925  m_frameIsBlank = true;
926 
927  // Are we non-strict and the frame is dark
928  // OR the frame is dim and has a low avg brightness
929  if ((!m_aggressiveDetection) &&
930  ((max < m_commDetectDarkBrightness) ||
932  m_frameIsBlank = true;
933  }
934 
936  {
939  }
940 
941 #if 0
943  (CheckRatingSymbol()))
944  {
945  flagMask |= COMM_FRAME_RATING_SYMBOL;
946  }
947 #endif
948 
949  if (m_frameIsBlank)
950  {
952  flagMask |= COMM_FRAME_BLANK;
954  }
955 
957  flagMask |= COMM_FRAME_LOGO_PRESENT;
958 
959  //TODO: move this debugging code out of the perframe loop, and do it after
960  // we've processed all frames. this is because a scenechangedetector can
961  // now use a few frames to determine whether the frame a few frames ago was
962  // a scene change or not.. due to this lookahead possibility the values
963  // that are currently in the frameInfo array, might be changed a few frames
964  // from now. The ClassicSceneChangeDetector doesn't use this though. future
965  // scenechangedetectors might.
966 
967  if (m_verboseDebugging)
968  {
969  LOG(VB_COMMFLAG, LOG_DEBUG, QString("Frame: %1 -> %2 %3 %4 %5 %6 %7 %8")
970  .arg(m_curFrameNumber, 6)
971  .arg(m_frameInfo[m_curFrameNumber].minBrightness, 3)
972  .arg(m_frameInfo[m_curFrameNumber].maxBrightness, 3)
973  .arg(m_frameInfo[m_curFrameNumber].avgBrightness, 3)
974  .arg(m_frameInfo[m_curFrameNumber].sceneChangePercent, 3)
975  .arg(m_frameInfo[m_curFrameNumber].format, 1)
976  .arg(m_frameInfo[m_curFrameNumber].aspect, 1)
977  .arg(m_frameInfo[m_curFrameNumber].flagMask, 4, 16, QChar('0')));
978  }
979 
980 #ifdef SHOW_DEBUG_WIN
981  comm_debug_show(frame->buf);
982  getchar();
983 #endif
984 
986  delete[] rowMax;
987  delete[] colMax;
988 }
989 
991 {
992  LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::ClearAllMaps()");
993 
994  m_frameInfo.clear();
995  m_blankFrameMap.clear();
996  m_blankCommMap.clear();
997  m_blankCommBreakMap.clear();
998  m_sceneMap.clear();
999  m_sceneCommBreakMap.clear();
1000  m_commBreakMap.clear();
1001 }
1002 
1004 {
1005  LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::GetBlankCommMap()");
1006 
1007  if (m_blankCommMap.isEmpty())
1009 
1010  comms = m_blankCommMap;
1011 }
1012 
1014 {
1015  LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::GetBlankCommBreakMap()");
1016 
1017  if (m_blankCommBreakMap.isEmpty())
1019 
1020  comms = m_blankCommBreakMap;
1021 }
1022 
1024  int64_t start_frame)
1025 {
1026  LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::GetSceneChangeMap()");
1027 
1028  frm_dir_map_t::iterator it;
1029 
1030  if (start_frame == -1)
1031  scenes.clear();
1032 
1033  for (it = m_sceneMap.begin(); it != m_sceneMap.end(); ++it)
1034  if ((start_frame == -1) || ((int64_t)it.key() >= start_frame))
1035  scenes[it.key()] = *it;
1036 }
1037 
1039  const frm_dir_map_t &b) const
1040 {
1041  LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::BuildMasterCommList()");
1042 
1043  frm_dir_map_t newMap;
1044 
1045  if (!a.empty())
1046  {
1047  frm_dir_map_t::const_iterator it = a.begin();
1048  for (; it != a.end(); ++it)
1049  newMap[it.key()] = *it;
1050  }
1051 
1052  if ((a.size() > 1) &&
1053  (b.size() > 1))
1054  {
1055  // see if beginning of the recording looks like a commercial
1056  frm_dir_map_t::const_iterator it_a;
1057  frm_dir_map_t::const_iterator it_b;
1058 
1059  it_a = a.begin();
1060  it_b = b.begin();
1061 
1062  if ((it_b.key() < 2) && (it_a.key() > 2))
1063  {
1064  newMap.remove(it_a.key());
1065  newMap[0] = MARK_COMM_START;
1066  }
1067 
1068 
1069  // see if ending of recording looks like a commercial
1070  frm_dir_map_t::const_iterator it;
1071  uint64_t max_a = 0;
1072  uint64_t max_b = 0;
1073 
1074  it = a.begin();
1075  for (; it != a.end(); ++it)
1076  {
1077  if ((*it == MARK_COMM_END) && (it.key() > max_a))
1078  max_a = it.key();
1079  }
1080 
1081  it = b.begin();
1082  for (; it != b.end(); ++it)
1083  {
1084  if ((*it == MARK_COMM_END) && (it.key() > max_b))
1085  max_b = it.key();
1086  }
1087 
1088  if ((max_a < (m_framesProcessed - 2)) &&
1089  (max_b > (m_framesProcessed - 2)))
1090  {
1091  newMap.remove(max_a);
1092  newMap[m_framesProcessed] = MARK_COMM_END;
1093  }
1094  }
1095 
1096  if ((a.size() > 3) &&
1097  (b.size() > 1))
1098  {
1099  frm_dir_map_t::const_iterator it_a;
1100  frm_dir_map_t::const_iterator it_b;
1101 
1102  it_a = a.begin();
1103  ++it_a;
1104  it_b = it_a;
1105  ++it_b;
1106  while (it_b != a.end())
1107  {
1108  uint64_t fdiff = it_b.key() - it_a.key();
1109  bool allTrue = false;
1110 
1111  if (fdiff < (62 * m_fps))
1112  {
1113  uint64_t f = it_a.key() + 1;
1114 
1115  allTrue = true;
1116 
1117  while ((f <= m_framesProcessed) && (f < it_b.key()) && (allTrue))
1118  allTrue = FrameIsInBreakMap(f++, b);
1119  }
1120 
1121  if (allTrue)
1122  {
1123  newMap.remove(it_a.key());
1124  newMap.remove(it_b.key());
1125  }
1126 
1127  ++it_a; ++it_a;
1128  ++it_b;
1129  if (it_b != a.end())
1130  ++it_b;
1131  }
1132  }
1133 
1134  return newMap;
1135 }
1136 
1138  const FrameInfoEntry& finfo,
1139  int format, int aspect)
1140 {
1141  int value = 0;
1142 
1143  value = finfo.flagMask;
1144 
1145  if (value & COMM_FRAME_LOGO_PRESENT)
1146  fbp->logoCount++;
1147 
1148  if (value & COMM_FRAME_RATING_SYMBOL)
1149  fbp->ratingCount++;
1150 
1151  if (value & COMM_FRAME_SCENE_CHANGE)
1152  fbp->scCount++;
1153 
1154  if (finfo.format == format)
1155  fbp->formatMatch++;
1156 
1157  if (finfo.aspect == aspect)
1158  fbp->aspectMatch++;
1159 }
1160 
1162 {
1163  LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::BuildAllMethodsCommList()");
1164 
1165  int lastScore = 0;
1166  uint64_t lastStart = 0;
1167  uint64_t lastEnd = 0;
1168  int64_t firstLogoFrame = -1;
1169  int format = COMM_FORMAT_NORMAL;
1170  int aspect = COMM_ASPECT_NORMAL;
1171  QString msg;
1172  std::array<uint64_t,COMM_FORMAT_MAX> formatCounts {};
1173  frm_dir_map_t tmpCommMap;
1174  frm_dir_map_t::iterator it;
1175 
1176  m_commBreakMap.clear();
1177 
1178  auto *fblock = new FrameBlock[m_blankFrameCount + 2];
1179 
1180  int curBlock = 0;
1181  uint64_t curFrame = 1;
1182 
1183  FrameBlock *fbp = &fblock[curBlock];
1184  fbp->start = 0;
1185  fbp->bfCount = 0;
1186  fbp->logoCount = 0;
1187  fbp->ratingCount = 0;
1188  fbp->scCount = 0;
1189  fbp->scRate = 0.0;
1190  fbp->formatMatch = 0;
1191  fbp->aspectMatch = 0;
1192  fbp->score = 0;
1193 
1194  bool lastFrameWasBlank = true;
1195 
1197  {
1198  uint64_t aspectFrames = 0;
1199  for (int64_t i = m_preRoll;
1200  i < ((int64_t)m_framesProcessed - (int64_t)m_postRoll); i++)
1201  {
1202  if ((m_frameInfo.contains(i)) &&
1203  (m_frameInfo[i].aspect == COMM_ASPECT_NORMAL))
1204  aspectFrames++;
1205  }
1206 
1207  if (aspectFrames < ((m_framesProcessed - m_preRoll - m_postRoll) / 2))
1208  {
1209  aspect = COMM_ASPECT_WIDE;
1210 // aspectFrames = m_framesProcessed - m_preRoll - m_postRoll - aspectFrames;
1211  }
1212  }
1213  else
1214  {
1215  formatCounts.fill(0);
1216 
1217  for(int64_t i = m_preRoll;
1218  i < ((int64_t)m_framesProcessed - (int64_t)m_postRoll); i++ )
1219  {
1220  if ((m_frameInfo.contains(i)) &&
1221  (m_frameInfo[i].format >= 0) &&
1222  (m_frameInfo[i].format < COMM_FORMAT_MAX))
1223  formatCounts[m_frameInfo[i].format]++;
1224  }
1225 
1226  uint64_t formatFrames = 0;
1227  for(int i = 0; i < COMM_FORMAT_MAX; i++)
1228  {
1229  if (formatCounts[i] > formatFrames)
1230  {
1231  format = i;
1232  formatFrames = formatCounts[i];
1233  }
1234  }
1235  }
1236 
1237  while (curFrame <= m_framesProcessed)
1238  {
1239  int value = m_frameInfo[curFrame].flagMask;
1240 
1241  bool nextFrameIsBlank = ((curFrame + 1) <= m_framesProcessed) &&
1242  ((m_frameInfo[curFrame + 1].flagMask & COMM_FRAME_BLANK) != 0);
1243 
1244  if (value & COMM_FRAME_BLANK)
1245  {
1246  fbp->bfCount++;
1247 
1248  if (!nextFrameIsBlank || !lastFrameWasBlank)
1249  {
1250  UpdateFrameBlock(fbp, m_frameInfo[curFrame], format, aspect);
1251 
1252  fbp->end = curFrame;
1253  fbp->frames = fbp->end - fbp->start + 1;
1254  fbp->length = fbp->frames / m_fps;
1255 
1256  if ((fbp->scCount) && (fbp->length > 1.05))
1257  fbp->scRate = fbp->scCount / fbp->length;
1258 
1259  curBlock++;
1260 
1261  fbp = &fblock[curBlock];
1262  fbp->bfCount = 1;
1263  fbp->logoCount = 0;
1264  fbp->ratingCount = 0;
1265  fbp->scCount = 0;
1266  fbp->scRate = 0.0;
1267  fbp->score = 0;
1268  fbp->formatMatch = 0;
1269  fbp->aspectMatch = 0;
1270  fbp->start = curFrame;
1271  }
1272 
1273  lastFrameWasBlank = true;
1274  }
1275  else
1276  {
1277  lastFrameWasBlank = false;
1278  }
1279 
1280  UpdateFrameBlock(fbp, m_frameInfo[curFrame], format, aspect);
1281 
1282  if ((value & COMM_FRAME_LOGO_PRESENT) &&
1283  (firstLogoFrame == -1))
1284  firstLogoFrame = curFrame;
1285 
1286  curFrame++;
1287  }
1288 
1289  fbp->end = curFrame;
1290  fbp->frames = fbp->end - fbp->start + 1;
1291  fbp->length = fbp->frames / m_fps;
1292 
1293  if ((fbp->scCount) && (fbp->length > 1.05))
1294  fbp->scRate = fbp->scCount / fbp->length;
1295 
1296  int maxBlock = curBlock;
1297  curBlock = 0;
1298 // lastScore = 0;
1299 
1300  LOG(VB_COMMFLAG, LOG_INFO, "Initial Block pass");
1301  LOG(VB_COMMFLAG, LOG_DEBUG,
1302  "Block StTime StFrm EndFrm Frames Secs "
1303  "Bf Lg Cnt RT Cnt SC Cnt SC Rt FmtMch AspMch Score");
1304  LOG(VB_COMMFLAG, LOG_INFO,
1305  "----- ------ ------ ------ ------ ------- "
1306  "--- ------ ------ ------ ----- ------ ------ -----");
1307  while (curBlock <= maxBlock)
1308  {
1309  fbp = &fblock[curBlock];
1310 
1311  msg = FormatMsg(curBlock, fbp);
1312  LOG(VB_COMMFLAG, LOG_DEBUG, msg);
1313 
1314  if (fbp->frames > m_fps)
1315  {
1316  if (m_verboseDebugging)
1317  LOG(VB_COMMFLAG, LOG_DEBUG,
1318  QString(" FRAMES > %1").arg(m_fps));
1319 
1320  if (fbp->length > m_commDetectMaxCommLength)
1321  {
1322  if (m_verboseDebugging)
1323  LOG(VB_COMMFLAG, LOG_DEBUG,
1324  " length > max comm length, +20");
1325  fbp->score += 20;
1326  }
1327 
1329  {
1330  if (m_verboseDebugging)
1331  LOG(VB_COMMFLAG, LOG_DEBUG,
1332  " length > max comm break length, +20");
1333  fbp->score += 20;
1334  }
1335 
1336  if ((fbp->length > 4) &&
1337  (fbp->logoCount > (fbp->frames * 0.60)) &&
1338  (fbp->bfCount < (fbp->frames * 0.10)))
1339  {
1340  if (m_verboseDebugging)
1341  {
1342  LOG(VB_COMMFLAG, LOG_DEBUG,
1343  " length > 4 && logoCount > frames * 0.60 && "
1344  "bfCount < frames * .10");
1345  }
1347  {
1348  if (m_verboseDebugging)
1349  LOG(VB_COMMFLAG, LOG_DEBUG,
1350  " length > max comm break length, +20");
1351  fbp->score += 20;
1352  }
1353  else
1354  {
1355  if (m_verboseDebugging)
1356  LOG(VB_COMMFLAG, LOG_DEBUG,
1357  " length <= max comm break length, +10");
1358  fbp->score += 10;
1359  }
1360  }
1361 
1362  if ((m_logoInfoAvailable) &&
1363  (fbp->logoCount < (fbp->frames * 0.50)))
1364  {
1365  if (m_verboseDebugging)
1366  {
1367  LOG(VB_COMMFLAG, LOG_DEBUG,
1368  " logoInfoAvailable && logoCount < frames * .50, "
1369  "-10");
1370  }
1371  fbp->score -= 10;
1372  }
1373 
1374  if (fbp->ratingCount > (fbp->frames * 0.05))
1375  {
1376  if (m_verboseDebugging)
1377  LOG(VB_COMMFLAG, LOG_DEBUG,
1378  " rating symbol present > 5% of time, +20");
1379  fbp->score += 20;
1380  }
1381 
1382  if ((fbp->scRate > 1.0) &&
1383  (fbp->logoCount < (fbp->frames * .90)))
1384  {
1385  if (m_verboseDebugging)
1386  LOG(VB_COMMFLAG, LOG_DEBUG, " scRate > 1.0, -10");
1387  fbp->score -= 10;
1388 
1389  if (fbp->scRate > 2.0)
1390  {
1391  if (m_verboseDebugging)
1392  LOG(VB_COMMFLAG, LOG_DEBUG, " scRate > 2.0, -10");
1393  fbp->score -= 10;
1394  }
1395  }
1396 
1397  if ((!m_decoderFoundAspectChanges) &&
1398  (fbp->formatMatch < (fbp->frames * .10)))
1399  {
1400  if (m_verboseDebugging)
1401  {
1402  LOG(VB_COMMFLAG, LOG_DEBUG,
1403  " < 10% of frames match show letter/pillar-box "
1404  "format, -20");
1405  }
1406  fbp->score -= 20;
1407  }
1408 
1409  if ((abs((int)(fbp->frames - (15 * m_fps))) < 5 ) ||
1410  (abs((int)(fbp->frames - (30 * m_fps))) < 6 ) ||
1411  (abs((int)(fbp->frames - (60 * m_fps))) < 8 ))
1412  {
1413  if (m_verboseDebugging)
1414  LOG(VB_COMMFLAG, LOG_DEBUG,
1415  " block appears to be standard comm length, -10");
1416  fbp->score -= 10;
1417  }
1418  }
1419  else
1420  {
1421  if (m_verboseDebugging)
1422  LOG(VB_COMMFLAG, LOG_DEBUG,
1423  QString(" FRAMES <= %1").arg(m_fps));
1424 
1425  if ((m_logoInfoAvailable) &&
1426  (fbp->start >= firstLogoFrame) &&
1427  (fbp->logoCount == 0))
1428  {
1429  if (m_verboseDebugging)
1430  LOG(VB_COMMFLAG, LOG_DEBUG,
1431  " logoInfoAvailable && logoCount == 0, -10");
1432  fbp->score -= 10;
1433  }
1434 
1435  if ((!m_decoderFoundAspectChanges) &&
1436  (fbp->formatMatch < (fbp->frames * .10)))
1437  {
1438  if (m_verboseDebugging)
1439  {
1440  LOG(VB_COMMFLAG, LOG_DEBUG,
1441  " < 10% of frames match show letter/pillar-box "
1442  "format, -10");
1443  }
1444  fbp->score -= 10;
1445  }
1446 
1447  if (fbp->ratingCount > (fbp->frames * 0.25))
1448  {
1449  if (m_verboseDebugging)
1450  LOG(VB_COMMFLAG, LOG_DEBUG,
1451  " rating symbol present > 25% of time, +10");
1452  fbp->score += 10;
1453  }
1454  }
1455 
1457  (fbp->aspectMatch < (fbp->frames * .10)))
1458  {
1459  if (m_verboseDebugging)
1460  LOG(VB_COMMFLAG, LOG_DEBUG,
1461  " < 10% of frames match show aspect, -20");
1462  fbp->score -= 20;
1463  }
1464 
1465  msg = FormatMsg("NOW", fbp);
1466  LOG(VB_COMMFLAG, LOG_DEBUG, msg);
1467 
1468 // lastScore = fbp->score;
1469  curBlock++;
1470  }
1471 
1472  curBlock = 0;
1473  lastScore = 0;
1474 
1475  LOG(VB_COMMFLAG, LOG_DEBUG, "============================================");
1476  LOG(VB_COMMFLAG, LOG_INFO, "Second Block pass");
1477  LOG(VB_COMMFLAG, LOG_DEBUG,
1478  "Block StTime StFrm EndFrm Frames Secs "
1479  "Bf Lg Cnt RT Cnt SC Cnt SC Rt FmtMch AspMch Score");
1480  LOG(VB_COMMFLAG, LOG_DEBUG,
1481  "----- ------ ------ ------ ------ ------- "
1482  "--- ------ ------ ------ ----- ------ ------ -----");
1483  while (curBlock <= maxBlock)
1484  {
1485  fbp = &fblock[curBlock];
1486 
1487  msg = FormatMsg(curBlock, fbp);
1488  LOG(VB_COMMFLAG, LOG_DEBUG, msg);
1489 
1490  if ((curBlock > 0) && (curBlock < maxBlock))
1491  {
1492  int nextScore = fblock[curBlock + 1].score;
1493 
1494  if ((lastScore < 0) && (nextScore < 0) && (fbp->length < 35))
1495  {
1496  if (m_verboseDebugging)
1497  {
1498  LOG(VB_COMMFLAG, LOG_DEBUG,
1499  " lastScore < 0 && nextScore < 0 "
1500  "&& length < 35, setting -10");
1501  }
1502  fbp->score -= 10;
1503  }
1504 
1505  if ((fbp->bfCount > (fbp->frames * 0.95)) &&
1506  (fbp->frames < (2*m_fps)) &&
1507  (lastScore < 0 && nextScore < 0))
1508  {
1509  if (m_verboseDebugging)
1510  {
1511  LOG(VB_COMMFLAG, LOG_DEBUG,
1512  " blanks > frames * 0.95 && frames < 2*m_fps && "
1513  "lastScore < 0 && nextScore < 0, setting -10");
1514  }
1515  fbp->score -= 10;
1516  }
1517 
1518  if ((fbp->frames < (120*m_fps)) &&
1519  (lastScore < 0) &&
1520  (fbp->score > 0) &&
1521  (fbp->score < 20) &&
1522  (nextScore < 0))
1523  {
1524  if (m_verboseDebugging)
1525  {
1526  LOG(VB_COMMFLAG, LOG_DEBUG,
1527  " frames < 120 * m_fps && (-20 < lastScore < 0) && "
1528  "thisScore > 0 && nextScore < 0, setting score = -10");
1529  }
1530  fbp->score = -10;
1531  }
1532 
1533  if ((fbp->frames < (30*m_fps)) &&
1534  (lastScore > 0) &&
1535  (fbp->score < 0) &&
1536  (fbp->score > -20) &&
1537  (nextScore > 0))
1538  {
1539  if (m_verboseDebugging)
1540  {
1541  LOG(VB_COMMFLAG, LOG_DEBUG,
1542  " frames < 30 * m_fps && (0 < lastScore < 20) && "
1543  "thisScore < 0 && nextScore > 0, setting score = 10");
1544  }
1545  fbp->score = 10;
1546  }
1547  }
1548 
1549  if ((fbp->score == 0) && (lastScore > 30))
1550  {
1551  int offset = 1;
1552  while(((curBlock + offset) <= maxBlock) &&
1553  (fblock[curBlock + offset].frames < (2 * m_fps)) &&
1554  (fblock[curBlock + offset].score == 0))
1555  offset++;
1556 
1557  if ((curBlock + offset) <= maxBlock)
1558  {
1559  offset--;
1560  if (fblock[curBlock + offset + 1].score > 0)
1561  {
1562  for (; offset >= 0; offset--)
1563  {
1564  fblock[curBlock + offset].score += 10;
1565  if (m_verboseDebugging)
1566  {
1567  LOG(VB_COMMFLAG, LOG_DEBUG,
1568  QString(" Setting block %1 score +10")
1569  .arg(curBlock+offset));
1570  }
1571  }
1572  }
1573  else if (fblock[curBlock + offset + 1].score < 0)
1574  {
1575  for (; offset >= 0; offset--)
1576  {
1577  fblock[curBlock + offset].score -= 10;
1578  if (m_verboseDebugging)
1579  {
1580  LOG(VB_COMMFLAG, LOG_DEBUG,
1581  QString(" Setting block %1 score -10")
1582  .arg(curBlock+offset));
1583  }
1584  }
1585  }
1586  }
1587  }
1588 
1589  msg = FormatMsg("NOW", fbp);
1590  LOG(VB_COMMFLAG, LOG_DEBUG, msg);
1591 
1592  lastScore = fbp->score;
1593  curBlock++;
1594  }
1595 
1596  LOG(VB_COMMFLAG, LOG_DEBUG, "============================================");
1597  LOG(VB_COMMFLAG, LOG_INFO, "FINAL Block stats");
1598  LOG(VB_COMMFLAG, LOG_DEBUG,
1599  "Block StTime StFrm EndFrm Frames Secs "
1600  "Bf Lg Cnt RT Cnt SC Cnt SC Rt FmtMch AspMch Score");
1601  LOG(VB_COMMFLAG, LOG_DEBUG,
1602  "----- ------ ------ ------ ------ ------- "
1603  "--- ------ ------ ------ ----- ------ ------ -----");
1604  curBlock = 0;
1605  lastScore = 0;
1606  int64_t breakStart = -1;
1607  while (curBlock <= maxBlock)
1608  {
1609  fbp = &fblock[curBlock];
1610  int thisScore = fbp->score;
1611 
1612  if ((breakStart >= 0) &&
1613  ((fbp->end - breakStart) > (m_commDetectMaxCommBreakLength * m_fps)))
1614  {
1615  if (((fbp->start - breakStart) >
1617  (breakStart == 0))
1618  {
1619  if (m_verboseDebugging)
1620  {
1621  LOG(VB_COMMFLAG, LOG_DEBUG,
1622  QString("Closing commercial block at start of "
1623  "frame block %1 with length %2, frame "
1624  "block length of %3 frames would put comm "
1625  "block length over max of %4 seconds.")
1626  .arg(curBlock).arg(fbp->start - breakStart)
1627  .arg(fbp->frames)
1629  }
1630 
1631  m_commBreakMap[breakStart] = MARK_COMM_START;
1633  lastStart = breakStart;
1634  lastEnd = fbp->start;
1635  breakStart = -1;
1636  }
1637  else
1638  {
1639  if (m_verboseDebugging)
1640  {
1641  LOG(VB_COMMFLAG, LOG_DEBUG,
1642  QString("Ignoring what appears to be commercial"
1643  " block at frame %1 with length %2, "
1644  "length of %3 frames would put comm "
1645  "block length under min of %4 seconds.")
1646  .arg(breakStart)
1647  .arg(fbp->start - breakStart)
1648  .arg(fbp->frames)
1650  }
1651  breakStart = -1;
1652  }
1653  }
1654  if (thisScore == 0)
1655  {
1656  thisScore = lastScore;
1657  }
1658  else if (thisScore < 0)
1659  {
1660  if ((lastScore > 0) || (curBlock == 0))
1661  {
1662  if ((fbp->start - lastEnd) < (m_commDetectMinShowLength * m_fps))
1663  {
1664  m_commBreakMap.remove(lastStart);
1665  m_commBreakMap.remove(lastEnd);
1666  breakStart = lastStart;
1667 
1668  if (m_verboseDebugging)
1669  {
1670  if (breakStart)
1671  {
1672  LOG(VB_COMMFLAG, LOG_DEBUG,
1673  QString("ReOpening commercial block at "
1674  "frame %1 because show less than "
1675  "%2 seconds")
1676  .arg(breakStart)
1678  }
1679  else
1680  {
1681  LOG(VB_COMMFLAG, LOG_DEBUG,
1682  "Opening initial commercial block "
1683  "at start of recording, block 0.");
1684  }
1685  }
1686  }
1687  else
1688  {
1689  breakStart = fbp->start;
1690 
1691  if (m_verboseDebugging)
1692  {
1693  LOG(VB_COMMFLAG, LOG_DEBUG,
1694  QString("Starting new commercial block at "
1695  "frame %1 from start of frame block %2")
1696  .arg(fbp->start).arg(curBlock));
1697  }
1698  }
1699  }
1700  else if (curBlock == maxBlock)
1701  {
1702  if ((fbp->end - breakStart) >
1704  {
1705  if (fbp->end <=
1706  ((int64_t)m_framesProcessed - (int64_t)(2 * m_fps) - 2))
1707  {
1708  if (m_verboseDebugging)
1709  {
1710  LOG(VB_COMMFLAG, LOG_DEBUG,
1711  QString("Closing final commercial block at "
1712  "frame %1").arg(fbp->end));
1713  }
1714 
1715  m_commBreakMap[breakStart] = MARK_COMM_START;
1717  lastStart = breakStart;
1718  lastEnd = fbp->end;
1719  breakStart = -1;
1720  }
1721  }
1722  else
1723  {
1724  if (m_verboseDebugging)
1725  {
1726  LOG(VB_COMMFLAG, LOG_DEBUG,
1727  QString("Ignoring what appears to be commercial"
1728  " block at frame %1 with length %2, "
1729  "length of %3 frames would put comm "
1730  "block length under min of %4 seconds.")
1731  .arg(breakStart)
1732  .arg(fbp->start - breakStart)
1733  .arg(fbp->frames)
1735  }
1736  breakStart = -1;
1737  }
1738  }
1739  }
1740  // thisScore > 0
1741  else if ((lastScore < 0) &&
1742  (breakStart != -1))
1743  {
1744  if (((fbp->start - breakStart) >
1746  (breakStart == 0))
1747  {
1748  m_commBreakMap[breakStart] = MARK_COMM_START;
1750  lastStart = breakStart;
1751  lastEnd = fbp->start;
1752 
1753  if (m_verboseDebugging)
1754  {
1755  LOG(VB_COMMFLAG, LOG_DEBUG,
1756  QString("Closing commercial block at frame %1")
1757  .arg(fbp->start));
1758  }
1759  }
1760  else
1761  {
1762  if (m_verboseDebugging)
1763  {
1764  LOG(VB_COMMFLAG, LOG_DEBUG,
1765  QString("Ignoring what appears to be commercial "
1766  "block at frame %1 with length %2, "
1767  "length of %3 frames would put comm block "
1768  "length under min of %4 seconds.")
1769  .arg(breakStart)
1770  .arg(fbp->start - breakStart)
1771  .arg(fbp->frames)
1773  }
1774  }
1775  breakStart = -1;
1776  }
1777 
1778  msg = FormatMsg(curBlock, fbp);
1779  LOG(VB_COMMFLAG, LOG_DEBUG, msg);
1780 
1781  lastScore = thisScore;
1782  curBlock++;
1783  }
1784 
1785  if ((breakStart != -1) &&
1786  (breakStart <= ((int64_t)m_framesProcessed - (int64_t)(2 * m_fps) - 2)))
1787  {
1788  if (m_verboseDebugging)
1789  {
1790  LOG(VB_COMMFLAG, LOG_DEBUG,
1791  QString("Closing final commercial block started at "
1792  "block %1 and going to end of program. length "
1793  "is %2 frames")
1794  .arg(curBlock)
1795  .arg((m_framesProcessed - breakStart - 1)));
1796  }
1797 
1798  m_commBreakMap[breakStart] = MARK_COMM_START;
1799  // Create what is essentially an open-ended final skip region
1800  // by setting the end point 10 seconds past the end of the
1801  // recording.
1803  }
1804 
1805  // include/exclude blanks from comm breaks
1806  tmpCommMap = m_commBreakMap;
1807  m_commBreakMap.clear();
1808 
1809  if (m_verboseDebugging)
1810  LOG(VB_COMMFLAG, LOG_DEBUG,
1811  "Adjusting start/end marks according to blanks.");
1812  for (it = tmpCommMap.begin(); it != tmpCommMap.end(); ++it)
1813  {
1814  if (*it == MARK_COMM_START)
1815  {
1816  uint64_t lastStartLower = it.key();
1817  uint64_t lastStartUpper = it.key();
1818  while ((lastStartLower > 0) &&
1819  ((m_frameInfo[lastStartLower - 1].flagMask & COMM_FRAME_BLANK) != 0))
1820  lastStartLower--;
1821  while ((lastStartUpper < (m_framesProcessed - (2 * m_fps))) &&
1822  ((m_frameInfo[lastStartUpper + 1].flagMask & COMM_FRAME_BLANK) != 0))
1823  lastStartUpper++;
1824  uint64_t adj = (lastStartUpper - lastStartLower) / 2;
1825  if (adj > MAX_BLANK_FRAMES)
1826  adj = MAX_BLANK_FRAMES;
1827  lastStart = lastStartLower + adj;
1828 
1829  if (m_verboseDebugging)
1830  LOG(VB_COMMFLAG, LOG_DEBUG, QString("Start Mark: %1 -> %2")
1831  .arg(it.key()).arg(lastStart));
1832 
1833  m_commBreakMap[lastStart] = MARK_COMM_START;
1834  }
1835  else
1836  {
1837  uint64_t lastEndLower = it.key();
1838  uint64_t lastEndUpper = it.key();
1839  while ((lastEndUpper < (m_framesProcessed - (2 * m_fps))) &&
1840  ((m_frameInfo[lastEndUpper + 1].flagMask & COMM_FRAME_BLANK) != 0))
1841  lastEndUpper++;
1842  while ((lastEndLower > 0) &&
1843  ((m_frameInfo[lastEndLower - 1].flagMask & COMM_FRAME_BLANK) != 0))
1844  lastEndLower--;
1845  uint64_t adj = (lastEndUpper - lastEndLower) / 2;
1846  if (adj > MAX_BLANK_FRAMES)
1847  adj = MAX_BLANK_FRAMES;
1848  lastEnd = lastEndUpper - adj;
1849 
1850  if (m_verboseDebugging)
1851  LOG(VB_COMMFLAG, LOG_DEBUG, QString("End Mark : %1 -> %2")
1852  .arg(it.key()).arg(lastEnd));
1853 
1854  m_commBreakMap[lastEnd] = MARK_COMM_END;
1855  }
1856  }
1857 
1858  delete [] fblock;
1859 }
1860 
1861 
1863 {
1864  LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::BuildBlankFrameCommList()");
1865 
1866  if (m_blankFrameMap.count() == 0)
1867  return;
1868 
1869  auto *bframes = new long long[2_UZ * m_blankFrameMap.count()];
1870  auto *c_start = new long long[1_UZ * m_blankFrameMap.count()];
1871  auto *c_end = new long long[1_UZ * m_blankFrameMap.count()];
1872  int frames = 0;
1873  int commercials = 0;
1874 
1875  m_blankCommMap.clear();
1876 
1877  for (auto it = m_blankFrameMap.begin(); it != m_blankFrameMap.end(); ++it)
1878  bframes[frames++] = it.key();
1879 
1880  // detect individual commercials from blank frames
1881  // commercial end is set to frame right before ending blank frame to
1882  // account for instances with only a single blank frame between comms.
1883  for(int i = 0; i < frames; i++ )
1884  {
1885  for(int x=i+1; x < frames; x++ )
1886  {
1887  // check for various length spots since some channels don't
1888  // have blanks inbetween commercials just at the beginning and
1889  // end of breaks
1890  int gap_length = bframes[x] - bframes[i];
1891  if (((m_aggressiveDetection) &&
1892  ((abs((int)(gap_length - (5 * m_fps))) < 5 ) ||
1893  (abs((int)(gap_length - (10 * m_fps))) < 7 ) ||
1894  (abs((int)(gap_length - (15 * m_fps))) < 10 ) ||
1895  (abs((int)(gap_length - (20 * m_fps))) < 11 ) ||
1896  (abs((int)(gap_length - (30 * m_fps))) < 12 ) ||
1897  (abs((int)(gap_length - (40 * m_fps))) < 1 ) ||
1898  (abs((int)(gap_length - (45 * m_fps))) < 1 ) ||
1899  (abs((int)(gap_length - (60 * m_fps))) < 15 ) ||
1900  (abs((int)(gap_length - (90 * m_fps))) < 10 ) ||
1901  (abs((int)(gap_length - (120 * m_fps))) < 10 ))) ||
1902  ((!m_aggressiveDetection) &&
1903  ((abs((int)(gap_length - (5 * m_fps))) < 11 ) ||
1904  (abs((int)(gap_length - (10 * m_fps))) < 13 ) ||
1905  (abs((int)(gap_length - (15 * m_fps))) < 16 ) ||
1906  (abs((int)(gap_length - (20 * m_fps))) < 17 ) ||
1907  (abs((int)(gap_length - (30 * m_fps))) < 18 ) ||
1908  (abs((int)(gap_length - (40 * m_fps))) < 3 ) ||
1909  (abs((int)(gap_length - (45 * m_fps))) < 3 ) ||
1910  (abs((int)(gap_length - (60 * m_fps))) < 20 ) ||
1911  (abs((int)(gap_length - (90 * m_fps))) < 20 ) ||
1912  (abs((int)(gap_length - (120 * m_fps))) < 20 ))))
1913  {
1914  c_start[commercials] = bframes[i];
1915  c_end[commercials] = bframes[x] - 1;
1916  commercials++;
1917  i = x-1;
1918  x = frames;
1919  }
1920 
1921  if ((!m_aggressiveDetection) &&
1922  ((abs((int)(gap_length - (30 * m_fps))) < (int)(m_fps * 0.85)) ||
1923  (abs((int)(gap_length - (60 * m_fps))) < (int)(m_fps * 0.95)) ||
1924  (abs((int)(gap_length - (90 * m_fps))) < (int)(m_fps * 1.05)) ||
1925  (abs((int)(gap_length - (120 * m_fps))) < (int)(m_fps * 1.15))) &&
1926  ((x + 2) < frames) &&
1927  ((i + 2) < frames) &&
1928  ((bframes[i] + 1) == bframes[i+1]) &&
1929  ((bframes[x] + 1) == bframes[x+1]))
1930  {
1931  c_start[commercials] = bframes[i];
1932  c_end[commercials] = bframes[x];
1933  commercials++;
1934  i = x;
1935  x = frames;
1936  }
1937  }
1938  }
1939 
1940  int i = 0;
1941 
1942  // don't allow single commercial at head
1943  // of show unless followed by another
1944  if ((commercials > 1) &&
1945  (c_end[0] < (33 * m_fps)) &&
1946  (c_start[1] > (c_end[0] + 40 * m_fps)))
1947  i = 1;
1948 
1949  // eliminate any blank frames at end of commercials
1950  bool first_comm = true;
1951  for(; i < (commercials-1); i++)
1952  {
1953  long long r = c_start[i];
1954  long long adjustment = 0;
1955 
1956  if ((r < (30 * m_fps)) &&
1957  (first_comm))
1958  r = 1;
1959 
1961 
1962  r = c_end[i];
1963  if ( i < (commercials-1))
1964  {
1965  int x = 0;
1966  for(x = 0; x < (frames-1); x++)
1967  if (bframes[x] == r)
1968  break;
1969  while((x < (frames-1)) &&
1970  ((bframes[x] + 1 ) == bframes[x+1]) &&
1971  (bframes[x+1] < c_start[i+1]))
1972  {
1973  r++;
1974  x++;
1975  }
1976 
1977  while((m_blankFrameMap.contains(r+1)) &&
1978  (c_start[i+1] != (r+1)))
1979  {
1980  r++;
1981  adjustment++;
1982  }
1983  }
1984  else
1985  {
1986  while(m_blankFrameMap.contains(r+1))
1987  {
1988  r++;
1989  adjustment++;
1990  }
1991  }
1992 
1993  adjustment /= 2;
1994  if (adjustment > MAX_BLANK_FRAMES)
1995  adjustment = MAX_BLANK_FRAMES;
1996  r -= adjustment;
1998  first_comm = false;
1999  }
2000 
2001  m_blankCommMap[c_start[i]] = MARK_COMM_START;
2002  m_blankCommMap[c_end[i]] = MARK_COMM_END;
2003 
2004  delete[] c_start;
2005  delete[] c_end;
2006  delete[] bframes;
2007 
2008  LOG(VB_COMMFLAG, LOG_INFO, "Blank-Frame Commercial Map" );
2009  for(auto it = m_blankCommMap.begin(); it != m_blankCommMap.end(); ++it)
2010  LOG(VB_COMMFLAG, LOG_INFO, QString(" %1:%2")
2011  .arg(it.key()).arg(*it));
2012 
2014 
2015  LOG(VB_COMMFLAG, LOG_INFO, "Merged Blank-Frame Commercial Break Map" );
2016  for(auto it = m_blankCommBreakMap.begin(); it != m_blankCommBreakMap.end(); ++it)
2017  LOG(VB_COMMFLAG, LOG_INFO, QString(" %1:%2")
2018  .arg(it.key()).arg(*it));
2019 }
2020 
2021 
2023 {
2024  int section_start = -1;
2025  int seconds = (int)(m_framesProcessed / m_fps);
2026  int *sc_histogram = new int[seconds+1];
2027 
2028  m_sceneCommBreakMap.clear();
2029 
2030  memset(sc_histogram, 0, (seconds+1)*sizeof(int));
2031  for (uint64_t f = 1; f <= m_framesProcessed; f++)
2032  {
2033  if (m_sceneMap.contains(f))
2034  sc_histogram[(uint64_t)(f / m_fps)]++;
2035  }
2036 
2037  for(long long s = 0; s < (seconds + 1); s++)
2038  {
2039  if (sc_histogram[s] > 2)
2040  {
2041  if (section_start == -1)
2042  {
2043  auto f = (long long)(s * m_fps);
2044  for(int i = 0; i < m_fps; i++, f++)
2045  {
2046  if (m_sceneMap.contains(f))
2047  {
2049  i = (int)(m_fps) + 1;
2050  }
2051  }
2052  }
2053 
2054  section_start = s;
2055  }
2056 
2057  if ((section_start >= 0) &&
2058  (s > (section_start + 32)))
2059  {
2060  auto f = (long long)(section_start * m_fps);
2061  bool found_end = false;
2062 
2063  for(int i = 0; i < m_fps; i++, f++)
2064  {
2065  if (m_sceneMap.contains(f))
2066  {
2067  frm_dir_map_t::iterator dit = m_sceneCommBreakMap.find(f);
2068  if (dit != m_sceneCommBreakMap.end())
2069  m_sceneCommBreakMap.erase(dit);
2070  else
2072  i = (int)(m_fps) + 1;
2073  found_end = true;
2074  }
2075  }
2076  section_start = -1;
2077 
2078  if (!found_end)
2079  {
2080  f = (long long)(section_start * m_fps);
2082  }
2083  }
2084  }
2085  delete[] sc_histogram;
2086 
2087  if (section_start >= 0)
2089 
2090  frm_dir_map_t deleteMap;
2091  frm_dir_map_t::iterator it = m_sceneCommBreakMap.begin();
2092  frm_dir_map_t::iterator prev = it;
2093  if (it != m_sceneCommBreakMap.end())
2094  {
2095  ++it;
2096  while (it != m_sceneCommBreakMap.end())
2097  {
2098  if ((*it == MARK_COMM_END) &&
2099  (it.key() - prev.key()) < (30 * m_fps))
2100  {
2101  deleteMap[it.key()] = MARK_CUT_START;
2102  deleteMap[prev.key()] = MARK_CUT_START;
2103  }
2104  ++prev;
2105  if (it != m_sceneCommBreakMap.end())
2106  ++it;
2107  }
2108 
2109  frm_dir_map_t::iterator dit;
2110  for (dit = deleteMap.begin(); dit != deleteMap.end(); ++dit)
2111  m_sceneCommBreakMap.remove(dit.key());
2112  }
2113 
2114  LOG(VB_COMMFLAG, LOG_INFO, "Scene-Change Commercial Break Map" );
2115  for (it = m_sceneCommBreakMap.begin(); it != m_sceneCommBreakMap.end(); ++it)
2116  {
2117  LOG(VB_COMMFLAG, LOG_INFO, QString(" %1:%2")
2118  .arg(it.key()).arg(*it));
2119  }
2120 }
2121 
2122 
2124 {
2125  show_map_t showmap;
2126  GetLogoCommBreakMap(showmap);
2127  CondenseMarkMap(showmap, (int)(25 * m_fps), (int)(30 * m_fps));
2129 
2130  frm_dir_map_t::iterator it;
2131  LOG(VB_COMMFLAG, LOG_INFO, "Logo Commercial Break Map" );
2132  for(it = m_logoCommBreakMap.begin(); it != m_logoCommBreakMap.end(); ++it)
2133  LOG(VB_COMMFLAG, LOG_INFO, QString(" %1:%2")
2134  .arg(it.key()).arg(*it));
2135 }
2136 
2138 {
2139  frm_dir_map_t::iterator it;
2140  frm_dir_map_t::iterator prev;
2141  QMap<long long, long long> tmpMap;
2142  QMap<long long, long long>::Iterator tmpMap_it;
2143  QMap<long long, long long>::Iterator tmpMap_prev;
2144 
2145  m_blankCommBreakMap.clear();
2146 
2147  if (m_blankCommMap.isEmpty())
2148  return;
2149 
2150  for (it = m_blankCommMap.begin(); it != m_blankCommMap.end(); ++it)
2151  m_blankCommBreakMap[it.key()] = *it;
2152 
2153  if (m_blankCommBreakMap.isEmpty())
2154  return;
2155 
2156  it = m_blankCommMap.begin();
2157  prev = it;
2158  ++it;
2159  for(; it != m_blankCommMap.end(); ++it, ++prev)
2160  {
2161  // if next commercial starts less than 15*fps frames away then merge
2162  if ((((prev.key() + 1) == it.key()) ||
2163  ((prev.key() + (15 * m_fps)) > it.key())) &&
2164  (*prev == MARK_COMM_END) &&
2165  (*it == MARK_COMM_START))
2166  {
2167  m_blankCommBreakMap.remove(prev.key());
2168  m_blankCommBreakMap.remove(it.key());
2169  }
2170  }
2171 
2172 
2173  // make temp copy of commercial break list
2174  it = m_blankCommBreakMap.begin();
2175  prev = it;
2176  ++it;
2177  tmpMap[prev.key()] = it.key();
2178  for(; it != m_blankCommBreakMap.end(); ++it, ++prev)
2179  {
2180  if ((*prev == MARK_COMM_START) &&
2181  (*it == MARK_COMM_END))
2182  tmpMap[prev.key()] = it.key();
2183  }
2184 
2185  tmpMap_it = tmpMap.begin();
2186  tmpMap_prev = tmpMap_it;
2187  tmpMap_it++;
2188  for(; tmpMap_it != tmpMap.end(); ++tmpMap_it, ++tmpMap_prev)
2189  {
2190  // if we find any segments less than 35 seconds between commercial
2191  // breaks include those segments in the commercial break.
2192  if (((*tmpMap_prev + (35 * m_fps)) > tmpMap_it.key()) &&
2193  ((*tmpMap_prev - tmpMap_prev.key()) > (35 * m_fps)) &&
2194  ((*tmpMap_it - tmpMap_it.key()) > (35 * m_fps)))
2195  {
2196  m_blankCommBreakMap.remove(*tmpMap_prev);
2197  m_blankCommBreakMap.remove(tmpMap_it.key());
2198  }
2199  }
2200 }
2201 
2203  uint64_t f, const frm_dir_map_t &breakMap) const
2204 {
2205  for (uint64_t i = f; i < m_framesProcessed; i++)
2206  {
2207  if (breakMap.contains(i))
2208  {
2209  int type = breakMap[i];
2210  if ((type == MARK_COMM_END) || (i == f))
2211  return true;
2212  if (type == MARK_COMM_START)
2213  return false;
2214  }
2215  }
2216 
2217  // We want from f down to 0, but without wrapping the counter to negative
2218  // on an unsigned counter.
2219  for (uint64_t i = (f + 1); i-- > 0; )
2220  {
2221  if (breakMap.contains(i))
2222  {
2223  int type = breakMap[i];
2224  if ((type == MARK_COMM_START) || (i == f))
2225  return true;
2226  if (type == MARK_COMM_END)
2227  return false;
2228  }
2229  }
2230 
2231  return false;
2232 }
2233 
2235 {
2236  frm_dir_map_t::iterator it;
2237  QString msg;
2238 
2239  LOG(VB_COMMFLAG, LOG_INFO,
2240  "---------------------------------------------------");
2241  for (it = map.begin(); it != map.end(); ++it)
2242  {
2243  long long frame = it.key();
2244  int flag = *it;
2245  int my_fps = (int)ceil(m_fps);
2246  long long hour = (frame / my_fps) / 60 / 60;
2247  long long min = (frame / my_fps) / 60 - (hour * 60);
2248  long long sec = (frame / my_fps) - (min * 60) - (hour * 60 * 60);
2249  long long frm = frame - ((sec * my_fps) + (min * 60 * my_fps) +
2250  (hour * 60 * 60 * my_fps));
2251  int my_sec = (int)(frame / my_fps);
2252  msg = QString("%1 : %2 (%3:%4:%5.%6) (%7)")
2253  .arg(frame, 7).arg(flag).arg(hour, 2, 10, QChar('0')).arg(min, 2, 10, QChar('0'))
2254  .arg(sec, 2, 10, QChar('0')).arg(frm, 2, 10, QChar('0')).arg(my_sec);
2255  LOG(VB_COMMFLAG, LOG_INFO, msg);
2256  }
2257  LOG(VB_COMMFLAG, LOG_INFO,
2258  "---------------------------------------------------");
2259 }
2260 
2262  int length)
2263 {
2264  show_map_t::iterator it;
2265  show_map_t::iterator prev;
2266  show_map_t tmpMap;
2267 
2268  if (map.size() <= 2)
2269  return;
2270 
2271  // merge any segments less than 'spacing' frames apart from each other
2272  LOG(VB_COMMFLAG, LOG_INFO, "Commercial Map Before condense:" );
2273  for (it = map.begin(); it != map.end(); ++it)
2274  {
2275  LOG(VB_COMMFLAG, LOG_INFO, QString(" %1:%2")
2276  .arg(it.key()).arg(*it));
2277  tmpMap[it.key()] = *it;
2278  }
2279 
2280  prev = tmpMap.begin();
2281  it = prev;
2282  ++it;
2283  while (it != tmpMap.end())
2284  {
2285  if ((*it == MARK_START) &&
2286  (*prev == MARK_END) &&
2287  ((it.key() - prev.key()) < (uint64_t)spacing))
2288  {
2289  map.remove(prev.key());
2290  map.remove(it.key());
2291  }
2292  ++prev;
2293  ++it;
2294  }
2295 
2296  if (map.empty())
2297  return;
2298 
2299  // delete any segments less than 'length' frames in length
2300  tmpMap.clear();
2301  for (it = map.begin(); it != map.end(); ++it)
2302  tmpMap[it.key()] = *it;
2303 
2304  prev = tmpMap.begin();
2305  it = prev;
2306  ++it;
2307  while (it != tmpMap.end())
2308  {
2309  if ((*prev == MARK_START) &&
2310  (*it == MARK_END) &&
2311  ((it.key() - prev.key()) < (uint64_t)length))
2312  {
2313  map.remove(prev.key());
2314  map.remove(it.key());
2315  }
2316  ++prev;
2317  ++it;
2318  }
2319 
2320  LOG(VB_COMMFLAG, LOG_INFO, "Commercial Map After condense:" );
2321  for (it = map.begin(); it != map.end(); ++it)
2322  LOG(VB_COMMFLAG, LOG_INFO, QString(" %1:%2")
2323  .arg(it.key()).arg(*it));
2324 }
2325 
2327  frm_dir_map_t &out, const show_map_t &in)
2328 {
2329  out.clear();
2330  if (in.empty())
2331  return;
2332 
2333  show_map_t::const_iterator sit;
2334  for (sit = in.begin(); sit != in.end(); ++sit)
2335  {
2336  if (*sit == MARK_START)
2337  out[sit.key()] = MARK_COMM_END;
2338  else
2339  out[sit.key()] = MARK_COMM_START;
2340  }
2341 
2342  frm_dir_map_t::iterator it = out.begin();
2343  if (it == out.end())
2344  return;
2345 
2346  switch (out[it.key()])
2347  {
2348  case MARK_COMM_END:
2349  if (it.key() == 0)
2350  out.remove(0);
2351  else
2352  out[0] = MARK_COMM_START;
2353  break;
2354  case MARK_COMM_START:
2355  break;
2356  default:
2357  out.remove(0);
2358  break;
2359  }
2360 }
2361 
2362 
2363 /* ideas for this method ported back from comskip.c mods by Jere Jones
2364  * which are partially mods based on Myth's original commercial skip
2365  * code written by Chris Pinkham. */
2366 
2368 {
2369  LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::CleanupFrameInfo()");
2370 
2371  // try to account for noisy signal causing blank frames to be undetected
2372  if ((m_framesProcessed > (m_fps * 60)) &&
2373  (m_blankFrameCount < (m_framesProcessed * 0.0004)))
2374  {
2375  std::array<int,256> avgHistogram {};
2376  int minAvg = -1;
2377  int newThreshold = -1;
2378 
2379  LOG(VB_COMMFLAG, LOG_INFO,
2380  QString("ClassicCommDetect: Only found %1 blank frames but "
2381  "wanted at least %2, rechecking data using higher "
2382  "threshold.")
2383  .arg(m_blankFrameCount)
2384  .arg((int)(m_framesProcessed * 0.0004)));
2385  m_blankFrameMap.clear();
2386  m_blankFrameCount = 0;
2387 
2388  avgHistogram.fill(0);
2389 
2390  for (uint64_t i = 1; i <= m_framesProcessed; i++)
2391  avgHistogram[std::clamp(m_frameInfo[i].avgBrightness, 0, 255)] += 1;
2392 
2393  for (int i = 1; i <= 255 && minAvg == -1; i++)
2394  if (avgHistogram[i] > (m_framesProcessed * 0.0004))
2395  minAvg = i;
2396 
2397  newThreshold = minAvg + 3;
2398  LOG(VB_COMMFLAG, LOG_INFO,
2399  QString("Minimum Average Brightness on a frame "
2400  "was %1, will use %2 as new threshold")
2401  .arg(minAvg).arg(newThreshold));
2402 
2403  for (uint64_t i = 1; i <= m_framesProcessed; i++)
2404  {
2405  int value = m_frameInfo[i].flagMask;
2406  m_frameInfo[i].flagMask = value & ~COMM_FRAME_BLANK;
2407 
2408  if (( (m_frameInfo[i].flagMask & COMM_FRAME_BLANK) == 0) &&
2409  (m_frameInfo[i].avgBrightness < newThreshold))
2410  {
2411  m_frameInfo[i].flagMask = value | COMM_FRAME_BLANK;
2414  }
2415  }
2416 
2417  LOG(VB_COMMFLAG, LOG_INFO,
2418  QString("Found %1 blank frames using new value")
2419  .arg(m_blankFrameCount));
2420  }
2421 
2422  // try to account for fuzzy logo detection
2423  for (uint64_t i = 1; i <= m_framesProcessed; i++)
2424  {
2425  if ((i < 10) || ((i+10) > m_framesProcessed))
2426  continue;
2427 
2428  int before = 0;
2429  for (int offset = 1; offset <= 10; offset++)
2430  if ((m_frameInfo[i - offset].flagMask & COMM_FRAME_LOGO_PRESENT) != 0)
2431  before++;
2432 
2433  int after = 0;
2434  for (int offset = 1; offset <= 10; offset++)
2435  if ((m_frameInfo[i + offset].flagMask & COMM_FRAME_LOGO_PRESENT) != 0)
2436  after++;
2437 
2438  int value = m_frameInfo[i].flagMask;
2439  if (value == -1)
2440  m_frameInfo[i].flagMask = 0;
2441 
2442  if (value & COMM_FRAME_LOGO_PRESENT)
2443  {
2444  if ((before < 4) && (after < 4))
2445  m_frameInfo[i].flagMask = value & ~COMM_FRAME_LOGO_PRESENT;
2446  }
2447  else
2448  {
2449  if ((before > 6) && (after > 6))
2450  m_frameInfo[i].flagMask = value | COMM_FRAME_LOGO_PRESENT;
2451  }
2452  }
2453 }
2454 
2456 {
2457  LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::GetLogoCommBreakMap()");
2458 
2459  map.clear();
2460 
2461  bool PrevFrameLogo = false;
2462 
2463  for (uint64_t curFrame = 1 ; curFrame <= m_framesProcessed; curFrame++)
2464  {
2465  bool CurrentFrameLogo =
2466  (m_frameInfo[curFrame].flagMask & COMM_FRAME_LOGO_PRESENT) != 0;
2467 
2468  if (!PrevFrameLogo && CurrentFrameLogo)
2469  map[curFrame] = MARK_START;
2470  else if (PrevFrameLogo && !CurrentFrameLogo)
2471  map[curFrame] = MARK_END;
2472 
2473  PrevFrameLogo = CurrentFrameLogo;
2474  }
2475 }
2476 
2478 {
2479  emit breathe();
2480 }
2481 
2483  std::ostream &out, const frm_dir_map_t *comm_breaks, bool verbose) const
2484 {
2485  if (verbose)
2486  {
2487  QByteArray tmp = FrameInfoEntry::GetHeader().toLatin1();
2488  out << tmp.constData() << " mark" << std::endl;
2489  }
2490 
2491  for (long long i = 1; i < m_curFrameNumber; i++)
2492  {
2493  QMap<long long, FrameInfoEntry>::const_iterator it = m_frameInfo.find(i);
2494  if (it == m_frameInfo.end())
2495  continue;
2496 
2497  QByteArray atmp = (*it).toString(i, verbose).toLatin1();
2498  out << atmp.constData() << " ";
2499  if (comm_breaks)
2500  {
2501  frm_dir_map_t::const_iterator mit = comm_breaks->find(i);
2502  if (mit != comm_breaks->end())
2503  {
2504  QString tmp = (verbose) ?
2505  toString((MarkTypes)*mit) : QString::number(*mit);
2506  atmp = tmp.toLatin1();
2507 
2508  out << atmp.constData();
2509  }
2510  }
2511  out << "\n";
2512  }
2513 
2514  out << std::flush;
2515 }
2516 
2517 /* 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:143
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:424
ClassicCommDetector::m_commDetectBorder
int m_commDetectBorder
Definition: ClassicCommDetector.h:140
ClassicCommDetector::BuildLogoCommList
void BuildLogoCommList()
Definition: ClassicCommDetector.cpp:2123
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:739
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:1137
ClassicCommDetector::logoDetectorBreathe
void logoDetectorBreathe()
Definition: ClassicCommDetector.cpp:2477
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:134
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:695
MythPlayer::GetEof
EofState GetEof(void) const
Definition: mythplayer.cpp:1071
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:1038
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:1003
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:2482
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:1023
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:2022
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:1862
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:2202
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:272
ClassicCommDetector::GetLogoCommBreakMap
void GetLogoCommBreakMap(show_map_t &map)
Definition: ClassicCommDetector.cpp:2455
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:990
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:599
SceneChangeDetectorBase::processFrame
virtual void processFrame(MythVideoFrame *frame)=0
ClassicCommDetector::SetVideoParams
void SetVideoParams(float aspect)
Definition: ClassicCommDetector.cpp:701
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:2234
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:1013
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:2261
mythmiscutil.h
ClassicCommDetector::GetCommercialBreakList
void GetCommercialBreakList(frm_dir_map_t &marks) override
Definition: ClassicCommDetector.cpp:616
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:2137
MythVideoFrame::m_type
VideoFrameType m_type
Definition: mythframe.h:119
ClassicCommDetector::BuildAllMethodsCommList
void BuildAllMethodsCommList(void)
Definition: ClassicCommDetector.cpp:1161
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:132
ClassicCommDetector::m_frameIsBlank
bool m_frameIsBlank
Definition: ClassicCommDetector.h:179
MythPlayer::GetVideoAspect
float GetVideoAspect(void) const
Definition: mythplayer.h:133
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:1974
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:2367
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:688
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:2326
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:633