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 
23 enum frameAspects : std::uint8_t {
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.
31 enum frameFormats : std::uint8_t {
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  percentage = std::min(percentage, 100);
515 
516  if (m_showProgress)
517  {
518  if (myTotalFrames)
519  {
520  QString tmp = QString("\r%1%/%2fps \r")
521  .arg(percentage, 3).arg((int)flagFPS, 4);
522  std::cerr << qPrintable(tmp) << std::flush;
523  }
524  else
525  {
526  QString tmp = QString("\r%1/%2fps \r")
527  .arg(currentFrameNumber, 6).arg((int)flagFPS, 4);
528  std::cerr << qPrintable(tmp) << std::flush;
529  }
530  }
531 
532  if (myTotalFrames)
533  {
534  emit statusUpdate(QCoreApplication::translate("(mythcommflag)",
535  "%1% Completed @ %2 fps.")
536  .arg(percentage).arg(flagFPS));
537  }
538  else
539  {
540  emit statusUpdate(QCoreApplication::translate("(mythcommflag)",
541  "%1 Frames Completed @ %2 fps.")
542  .arg(currentFrameNumber).arg(flagFPS));
543  }
544 
545  if (percentage % 10 == 0 && prevpercent != percentage)
546  {
547  prevpercent = percentage;
548  LOG(VB_GENERAL, LOG_INFO, QString("%1%% Completed @ %2 fps.")
549  .arg(percentage) .arg(flagFPS));
550  }
551  }
552 
553  ProcessFrame(currentFrame, currentFrameNumber);
554 
555  if (m_stillRecording)
556  {
557  int secondsRecorded =
559  int secondsFlagged = (int)(m_framesProcessed / m_fps);
560  int secondsBehind = secondsRecorded - secondsFlagged;
561  auto usecPerFrame = floatusecs(1000000.0F / m_player->GetFrameRate());
562 
563  auto endTime = nowAsDuration<std::chrono::microseconds>();
564 
565  floatusecs usecSleep = usecPerFrame - (endTime - startTime);
566 
567  if (secondsBehind > requiredBuffer)
568  {
569  if (m_fullSpeed)
570  usecSleep = 0us;
571  else
572  usecSleep = usecSleep * 0.25;
573  }
574  else if (secondsBehind < requiredBuffer)
575  {
576  usecSleep = usecPerFrame * 1.5;
577  }
578 
579  if (usecSleep > 0us)
580  std::this_thread::sleep_for(usecSleep);
581  }
582 
583  m_player->DiscardVideoFrame(currentFrame);
584  }
585 
586  if (m_showProgress)
587  {
588 #if 0
589  float elapsed = flagTime.elapsed() / 1000.0;
590 
591  if (elapsed)
592  flagFPS = currentFrameNumber / elapsed;
593  else
594  flagFPS = 0.0;
595 #endif
596 
597  if (myTotalFrames)
598  std::cerr << "\b\b\b\b\b\b \b\b\b\b\b\b";
599  else
600  std::cerr << "\b\b\b\b\b\b\b\b\b\b\b\b\b "
601  "\b\b\b\b\b\b\b\b\b\b\b\b\b";
602  std::cerr.flush();
603  }
604 
605  return true;
606 }
607 
609  unsigned int framenum,bool isSceneChange,float debugValue)
610 {
611  if (isSceneChange)
612  {
613  m_frameInfo[framenum].flagMask |= COMM_FRAME_SCENE_CHANGE;
614  m_sceneMap[framenum] = MARK_SCENE_CHANGE;
615  }
616  else
617  {
618  m_frameInfo[framenum].flagMask &= ~COMM_FRAME_SCENE_CHANGE;
619  m_sceneMap.remove(framenum);
620  }
621 
622  m_frameInfo[framenum].sceneChangePercent = (int) (debugValue*100);
623 }
624 
626 {
627 
628  LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::GetCommBreakMap()");
629 
630  marks.clear();
631 
633 
634  bool blank = (COMM_DETECT_BLANK & m_commDetectMethod) != 0;
635  bool scene = (COMM_DETECT_SCENE & m_commDetectMethod) != 0;
636  bool logo = (COMM_DETECT_LOGO & m_commDetectMethod) != 0;
637 
639  return;
640 
641  if (!blank && !scene && !logo)
642  {
643  LOG(VB_COMMFLAG, LOG_ERR, QString("Unexpected commDetectMethod: 0x%1")
644  .arg(m_commDetectMethod,0,16));
645  return;
646  }
647 
648  if (blank && scene && logo)
649  {
651  marks = m_commBreakMap;
652  LOG(VB_COMMFLAG, LOG_INFO, "Final Commercial Break Map");
653  return;
654  }
655 
656  if (blank)
657  {
659  marks = m_blankCommBreakMap;
660  }
661 
662  if (scene)
663  {
665  marks = m_sceneCommBreakMap;
666  }
667 
668  if (logo)
669  {
671  marks = m_logoCommBreakMap;
672  }
673 
674  int cnt = ((blank) ? 1 : 0) + ((scene) ? 1 : 0) + ((logo) ? 1 : 0);
675  if (cnt == 2)
676  {
677  if (blank && scene)
678  {
679  marks = m_commBreakMap = Combine2Maps(
681  }
682  else if (blank && logo)
683  {
684  marks = m_commBreakMap = Combine2Maps(
686  }
687  else if (scene && logo)
688  {
689  marks = m_commBreakMap = Combine2Maps(
691  }
692  }
693 
694  LOG(VB_COMMFLAG, LOG_INFO, "Final Commercial Break Map");
695 }
696 
697 void ClassicCommDetector::recordingFinished([[maybe_unused]] long long totalFileSize)
698 {
699  m_stillRecording = false;
700 }
701 
703 {
706 }
707 
709 {
710  int newAspect = COMM_ASPECT_WIDE;
711 
712  LOG(VB_COMMFLAG, LOG_INFO,
713  QString("CommDetect::SetVideoParams called with aspect = %1")
714  .arg(aspect));
715  // Default to Widescreen but use the same check as VideoOutput::MoveResize()
716  // to determine if is normal 4:3 aspect
717  if (fabs(aspect - 1.333333F) < 0.1F)
718  newAspect = COMM_ASPECT_NORMAL;
719 
720  if (newAspect != m_currentAspect)
721  {
722  LOG(VB_COMMFLAG, LOG_INFO,
723  QString("Aspect Ratio changed from %1 to %2 at frame %3")
724  .arg(m_currentAspect).arg(newAspect)
725  .arg(m_curFrameNumber));
726 
727  if (m_frameInfo.contains(m_curFrameNumber))
728  {
729  // pretend that this frame is blank so that we can create test
730  // blocks on real aspect ratio change boundaries.
734  }
735  else if (m_curFrameNumber != -1)
736  {
737  LOG(VB_COMMFLAG, LOG_ERR,
738  QString("Unable to keep track of Aspect ratio change because "
739  "frameInfo for frame number %1 does not exist.")
740  .arg(m_curFrameNumber));
741  }
742  m_currentAspect = newAspect;
743  }
744 }
745 
747  long long frame_number)
748 {
749  int max = 0;
750  int min = 255;
751  int blankPixelsChecked = 0;
752  long long totBrightness = 0;
753  auto *rowMax = new unsigned char[m_height];
754  auto *colMax = new unsigned char[m_width];
755  memset(rowMax, 0, sizeof(*rowMax)*m_height);
756  memset(colMax, 0, sizeof(*colMax)*m_width);
757  int topDarkRow = m_commDetectBorder;
758  int bottomDarkRow = m_height - m_commDetectBorder - 1;
759  int leftDarkCol = m_commDetectBorder;
760  int rightDarkCol = m_width - m_commDetectBorder - 1;
761  FrameInfoEntry fInfo {};
762 
763  if (!frame || !(frame->m_buffer) || frame_number == -1 ||
764  frame->m_type != FMT_YV12)
765  {
766  LOG(VB_COMMFLAG, LOG_ERR, "CommDetect: Invalid video frame or codec, "
767  "unable to process frame.");
768  delete[] rowMax;
769  delete[] colMax;
770  return;
771  }
772 
773  if (!m_width || !m_height)
774  {
775  LOG(VB_COMMFLAG, LOG_ERR, "CommDetect: Width or Height is 0, "
776  "unable to process frame.");
777  delete[] rowMax;
778  delete[] colMax;
779  return;
780  }
781 
782  m_curFrameNumber = frame_number;
783  unsigned char* framePtr = frame->m_buffer;
784  int bytesPerLine = frame->m_pitches[0];
785 
786  fInfo.minBrightness = -1;
787  fInfo.maxBrightness = -1;
788  fInfo.avgBrightness = -1;
789  fInfo.sceneChangePercent = -1;
790  fInfo.aspect = m_currentAspect;
791  fInfo.format = COMM_FORMAT_NORMAL;
792  fInfo.flagMask = 0;
793 
794  int& flagMask = m_frameInfo[m_curFrameNumber].flagMask;
795 
796  // Fill in dummy info records for skipped frames.
797  if (m_lastFrameNumber != (m_curFrameNumber - 1))
798  {
799  if (m_lastFrameNumber > 0)
800  {
801  fInfo.aspect = m_frameInfo[m_lastFrameNumber].aspect;
802  fInfo.format = m_frameInfo[m_lastFrameNumber].format;
803  }
804  fInfo.flagMask = COMM_FRAME_SKIPPED;
805 
808  m_frameInfo[m_lastFrameNumber++] = fInfo;
809 
810  fInfo.flagMask = 0;
811  }
813 
814  m_frameInfo[m_curFrameNumber] = fInfo;
815 
817  m_frameIsBlank = false;
818 
820  {
822  }
823 
824  m_stationLogoPresent = false;
825 
826  for(int y = m_commDetectBorder; y < (m_height - m_commDetectBorder);
827  y += m_vertSpacing)
828  {
829  for(int x = m_commDetectBorder; x < (m_width - m_commDetectBorder);
830  x += m_horizSpacing)
831  {
832  uchar pixel = framePtr[(y * bytesPerLine) + x];
833 
835  {
836  bool checkPixel = false;
838  checkPixel = true;
839 
840  if (!m_logoInfoAvailable ||
842  checkPixel=true;
843 
844  if (checkPixel)
845  {
846  blankPixelsChecked++;
847  totBrightness += pixel;
848 
849  min = std::min<int>(pixel, min);
850  max = std::max<int>(pixel, max);
851  rowMax[y] = std::max(pixel, rowMax[y]);
852  colMax[x] = std::max(pixel, colMax[x]);
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  adj = std::min<uint64_t>(adj, MAX_BLANK_FRAMES);
1826  lastStart = lastStartLower + adj;
1827 
1828  if (m_verboseDebugging)
1829  LOG(VB_COMMFLAG, LOG_DEBUG, QString("Start Mark: %1 -> %2")
1830  .arg(it.key()).arg(lastStart));
1831 
1832  m_commBreakMap[lastStart] = MARK_COMM_START;
1833  }
1834  else
1835  {
1836  uint64_t lastEndLower = it.key();
1837  uint64_t lastEndUpper = it.key();
1838  while ((lastEndUpper < (m_framesProcessed - (2 * m_fps))) &&
1839  ((m_frameInfo[lastEndUpper + 1].flagMask & COMM_FRAME_BLANK) != 0))
1840  lastEndUpper++;
1841  while ((lastEndLower > 0) &&
1842  ((m_frameInfo[lastEndLower - 1].flagMask & COMM_FRAME_BLANK) != 0))
1843  lastEndLower--;
1844  uint64_t adj = (lastEndUpper - lastEndLower) / 2;
1845  adj = std::min<uint64_t>(adj, MAX_BLANK_FRAMES);
1846  lastEnd = lastEndUpper - adj;
1847 
1848  if (m_verboseDebugging)
1849  LOG(VB_COMMFLAG, LOG_DEBUG, QString("End Mark : %1 -> %2")
1850  .arg(it.key()).arg(lastEnd));
1851 
1852  m_commBreakMap[lastEnd] = MARK_COMM_END;
1853  }
1854  }
1855 
1856  delete [] fblock;
1857 }
1858 
1859 
1861 {
1862  LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::BuildBlankFrameCommList()");
1863 
1864  if (m_blankFrameMap.count() == 0)
1865  return;
1866 
1867  auto *bframes = new long long[2_UZ * m_blankFrameMap.count()];
1868  auto *c_start = new long long[1_UZ * m_blankFrameMap.count()];
1869  auto *c_end = new long long[1_UZ * m_blankFrameMap.count()];
1870  int frames = 0;
1871  int commercials = 0;
1872 
1873  m_blankCommMap.clear();
1874 
1875  for (auto it = m_blankFrameMap.begin(); it != m_blankFrameMap.end(); ++it)
1876  bframes[frames++] = it.key();
1877 
1878  // detect individual commercials from blank frames
1879  // commercial end is set to frame right before ending blank frame to
1880  // account for instances with only a single blank frame between comms.
1881  for(int i = 0; i < frames; i++ )
1882  {
1883  for(int x=i+1; x < frames; x++ )
1884  {
1885  // check for various length spots since some channels don't
1886  // have blanks inbetween commercials just at the beginning and
1887  // end of breaks
1888  int gap_length = bframes[x] - bframes[i];
1889  if (((m_aggressiveDetection) &&
1890  ((abs((int)(gap_length - (5 * m_fps))) < 5 ) ||
1891  (abs((int)(gap_length - (10 * m_fps))) < 7 ) ||
1892  (abs((int)(gap_length - (15 * m_fps))) < 10 ) ||
1893  (abs((int)(gap_length - (20 * m_fps))) < 11 ) ||
1894  (abs((int)(gap_length - (30 * m_fps))) < 12 ) ||
1895  (abs((int)(gap_length - (40 * m_fps))) < 1 ) ||
1896  (abs((int)(gap_length - (45 * m_fps))) < 1 ) ||
1897  (abs((int)(gap_length - (60 * m_fps))) < 15 ) ||
1898  (abs((int)(gap_length - (90 * m_fps))) < 10 ) ||
1899  (abs((int)(gap_length - (120 * m_fps))) < 10 ))) ||
1900  ((!m_aggressiveDetection) &&
1901  ((abs((int)(gap_length - (5 * m_fps))) < 11 ) ||
1902  (abs((int)(gap_length - (10 * m_fps))) < 13 ) ||
1903  (abs((int)(gap_length - (15 * m_fps))) < 16 ) ||
1904  (abs((int)(gap_length - (20 * m_fps))) < 17 ) ||
1905  (abs((int)(gap_length - (30 * m_fps))) < 18 ) ||
1906  (abs((int)(gap_length - (40 * m_fps))) < 3 ) ||
1907  (abs((int)(gap_length - (45 * m_fps))) < 3 ) ||
1908  (abs((int)(gap_length - (60 * m_fps))) < 20 ) ||
1909  (abs((int)(gap_length - (90 * m_fps))) < 20 ) ||
1910  (abs((int)(gap_length - (120 * m_fps))) < 20 ))))
1911  {
1912  c_start[commercials] = bframes[i];
1913  c_end[commercials] = bframes[x] - 1;
1914  commercials++;
1915  i = x-1;
1916  x = frames;
1917  }
1918 
1919  if ((!m_aggressiveDetection) &&
1920  ((abs((int)(gap_length - (30 * m_fps))) < (int)(m_fps * 0.85)) ||
1921  (abs((int)(gap_length - (60 * m_fps))) < (int)(m_fps * 0.95)) ||
1922  (abs((int)(gap_length - (90 * m_fps))) < (int)(m_fps * 1.05)) ||
1923  (abs((int)(gap_length - (120 * m_fps))) < (int)(m_fps * 1.15))) &&
1924  ((x + 2) < frames) &&
1925  ((i + 2) < frames) &&
1926  ((bframes[i] + 1) == bframes[i+1]) &&
1927  ((bframes[x] + 1) == bframes[x+1]))
1928  {
1929  c_start[commercials] = bframes[i];
1930  c_end[commercials] = bframes[x];
1931  commercials++;
1932  i = x;
1933  x = frames;
1934  }
1935  }
1936  }
1937 
1938  int i = 0;
1939 
1940  // don't allow single commercial at head
1941  // of show unless followed by another
1942  if ((commercials > 1) &&
1943  (c_end[0] < (33 * m_fps)) &&
1944  (c_start[1] > (c_end[0] + 40 * m_fps)))
1945  i = 1;
1946 
1947  // eliminate any blank frames at end of commercials
1948  bool first_comm = true;
1949  for(; i < (commercials-1); i++)
1950  {
1951  long long r = c_start[i];
1952  long long adjustment = 0;
1953 
1954  if ((r < (30 * m_fps)) &&
1955  (first_comm))
1956  r = 1;
1957 
1959 
1960  r = c_end[i];
1961  if ( i < (commercials-1))
1962  {
1963  int x = 0;
1964  for(x = 0; x < (frames-1); x++)
1965  if (bframes[x] == r)
1966  break;
1967  while((x < (frames-1)) &&
1968  ((bframes[x] + 1 ) == bframes[x+1]) &&
1969  (bframes[x+1] < c_start[i+1]))
1970  {
1971  r++;
1972  x++;
1973  }
1974 
1975  while((m_blankFrameMap.contains(r+1)) &&
1976  (c_start[i+1] != (r+1)))
1977  {
1978  r++;
1979  adjustment++;
1980  }
1981  }
1982  else
1983  {
1984  while(m_blankFrameMap.contains(r+1))
1985  {
1986  r++;
1987  adjustment++;
1988  }
1989  }
1990 
1991  adjustment /= 2;
1992  adjustment = std::min<long long>(adjustment, MAX_BLANK_FRAMES);
1993  r -= adjustment;
1995  first_comm = false;
1996  }
1997 
1998  m_blankCommMap[c_start[i]] = MARK_COMM_START;
1999  m_blankCommMap[c_end[i]] = MARK_COMM_END;
2000 
2001  delete[] c_start;
2002  delete[] c_end;
2003  delete[] bframes;
2004 
2005  LOG(VB_COMMFLAG, LOG_INFO, "Blank-Frame Commercial Map" );
2006  for(auto it = m_blankCommMap.begin(); it != m_blankCommMap.end(); ++it)
2007  LOG(VB_COMMFLAG, LOG_INFO, QString(" %1:%2")
2008  .arg(it.key()).arg(*it));
2009 
2011 
2012  LOG(VB_COMMFLAG, LOG_INFO, "Merged Blank-Frame Commercial Break Map" );
2013  for(auto it = m_blankCommBreakMap.begin(); it != m_blankCommBreakMap.end(); ++it)
2014  LOG(VB_COMMFLAG, LOG_INFO, QString(" %1:%2")
2015  .arg(it.key()).arg(*it));
2016 }
2017 
2018 
2020 {
2021  int section_start = -1;
2022  int seconds = (int)(m_framesProcessed / m_fps);
2023  int *sc_histogram = new int[seconds+1];
2024 
2025  m_sceneCommBreakMap.clear();
2026 
2027  memset(sc_histogram, 0, (seconds+1)*sizeof(int));
2028  for (uint64_t f = 1; f <= m_framesProcessed; f++)
2029  {
2030  if (m_sceneMap.contains(f))
2031  sc_histogram[(uint64_t)(f / m_fps)]++;
2032  }
2033 
2034  for(long long s = 0; s < (seconds + 1); s++)
2035  {
2036  if (sc_histogram[s] > 2)
2037  {
2038  if (section_start == -1)
2039  {
2040  auto f = (long long)(s * m_fps);
2041  for(int i = 0; i < m_fps; i++, f++)
2042  {
2043  if (m_sceneMap.contains(f))
2044  {
2046  i = (int)(m_fps) + 1;
2047  }
2048  }
2049  }
2050 
2051  section_start = s;
2052  }
2053 
2054  if ((section_start >= 0) &&
2055  (s > (section_start + 32)))
2056  {
2057  auto f = (long long)(section_start * m_fps);
2058  bool found_end = false;
2059 
2060  for(int i = 0; i < m_fps; i++, f++)
2061  {
2062  if (m_sceneMap.contains(f))
2063  {
2064  frm_dir_map_t::iterator dit = m_sceneCommBreakMap.find(f);
2065  if (dit != m_sceneCommBreakMap.end())
2066  m_sceneCommBreakMap.erase(dit);
2067  else
2069  i = (int)(m_fps) + 1;
2070  found_end = true;
2071  }
2072  }
2073  section_start = -1;
2074 
2075  if (!found_end)
2076  {
2077  f = (long long)(section_start * m_fps);
2079  }
2080  }
2081  }
2082  delete[] sc_histogram;
2083 
2084  if (section_start >= 0)
2086 
2087  frm_dir_map_t deleteMap;
2088  frm_dir_map_t::iterator it = m_sceneCommBreakMap.begin();
2089  frm_dir_map_t::iterator prev = it;
2090  if (it != m_sceneCommBreakMap.end())
2091  {
2092  ++it;
2093  while (it != m_sceneCommBreakMap.end())
2094  {
2095  if ((*it == MARK_COMM_END) &&
2096  (it.key() - prev.key()) < (30 * m_fps))
2097  {
2098  deleteMap[it.key()] = MARK_CUT_START;
2099  deleteMap[prev.key()] = MARK_CUT_START;
2100  }
2101  ++prev;
2102  if (it != m_sceneCommBreakMap.end())
2103  ++it;
2104  }
2105 
2106  frm_dir_map_t::iterator dit;
2107  for (dit = deleteMap.begin(); dit != deleteMap.end(); ++dit)
2108  m_sceneCommBreakMap.remove(dit.key());
2109  }
2110 
2111  LOG(VB_COMMFLAG, LOG_INFO, "Scene-Change Commercial Break Map" );
2112  for (it = m_sceneCommBreakMap.begin(); it != m_sceneCommBreakMap.end(); ++it)
2113  {
2114  LOG(VB_COMMFLAG, LOG_INFO, QString(" %1:%2")
2115  .arg(it.key()).arg(*it));
2116  }
2117 }
2118 
2119 
2121 {
2122  show_map_t showmap;
2123  GetLogoCommBreakMap(showmap);
2124  CondenseMarkMap(showmap, (int)(25 * m_fps), (int)(30 * m_fps));
2126 
2127  frm_dir_map_t::iterator it;
2128  LOG(VB_COMMFLAG, LOG_INFO, "Logo Commercial Break Map" );
2129  for(it = m_logoCommBreakMap.begin(); it != m_logoCommBreakMap.end(); ++it)
2130  LOG(VB_COMMFLAG, LOG_INFO, QString(" %1:%2")
2131  .arg(it.key()).arg(*it));
2132 }
2133 
2135 {
2136  frm_dir_map_t::iterator it;
2137  frm_dir_map_t::iterator prev;
2138  QMap<long long, long long> tmpMap;
2139  QMap<long long, long long>::Iterator tmpMap_it;
2140  QMap<long long, long long>::Iterator tmpMap_prev;
2141 
2142  m_blankCommBreakMap.clear();
2143 
2144  if (m_blankCommMap.isEmpty())
2145  return;
2146 
2147  for (it = m_blankCommMap.begin(); it != m_blankCommMap.end(); ++it)
2148  m_blankCommBreakMap[it.key()] = *it;
2149 
2150  if (m_blankCommBreakMap.isEmpty())
2151  return;
2152 
2153  it = m_blankCommMap.begin();
2154  prev = it;
2155  ++it;
2156  for(; it != m_blankCommMap.end(); ++it, ++prev)
2157  {
2158  // if next commercial starts less than 15*fps frames away then merge
2159  if ((((prev.key() + 1) == it.key()) ||
2160  ((prev.key() + (15 * m_fps)) > it.key())) &&
2161  (*prev == MARK_COMM_END) &&
2162  (*it == MARK_COMM_START))
2163  {
2164  m_blankCommBreakMap.remove(prev.key());
2165  m_blankCommBreakMap.remove(it.key());
2166  }
2167  }
2168 
2169 
2170  // make temp copy of commercial break list
2171  it = m_blankCommBreakMap.begin();
2172  prev = it;
2173  ++it;
2174  tmpMap[prev.key()] = it.key();
2175  for(; it != m_blankCommBreakMap.end(); ++it, ++prev)
2176  {
2177  if ((*prev == MARK_COMM_START) &&
2178  (*it == MARK_COMM_END))
2179  tmpMap[prev.key()] = it.key();
2180  }
2181 
2182  tmpMap_it = tmpMap.begin();
2183  tmpMap_prev = tmpMap_it;
2184  tmpMap_it++;
2185  for(; tmpMap_it != tmpMap.end(); ++tmpMap_it, ++tmpMap_prev)
2186  {
2187  // if we find any segments less than 35 seconds between commercial
2188  // breaks include those segments in the commercial break.
2189  if (((*tmpMap_prev + (35 * m_fps)) > tmpMap_it.key()) &&
2190  ((*tmpMap_prev - tmpMap_prev.key()) > (35 * m_fps)) &&
2191  ((*tmpMap_it - tmpMap_it.key()) > (35 * m_fps)))
2192  {
2193  m_blankCommBreakMap.remove(*tmpMap_prev);
2194  m_blankCommBreakMap.remove(tmpMap_it.key());
2195  }
2196  }
2197 }
2198 
2200  uint64_t f, const frm_dir_map_t &breakMap) const
2201 {
2202  for (uint64_t i = f; i < m_framesProcessed; i++)
2203  {
2204  if (breakMap.contains(i))
2205  {
2206  int type = breakMap[i];
2207  if ((type == MARK_COMM_END) || (i == f))
2208  return true;
2209  if (type == MARK_COMM_START)
2210  return false;
2211  }
2212  }
2213 
2214  // We want from f down to 0, but without wrapping the counter to negative
2215  // on an unsigned counter.
2216  for (uint64_t i = (f + 1); i-- > 0; )
2217  {
2218  if (breakMap.contains(i))
2219  {
2220  int type = breakMap[i];
2221  if ((type == MARK_COMM_START) || (i == f))
2222  return true;
2223  if (type == MARK_COMM_END)
2224  return false;
2225  }
2226  }
2227 
2228  return false;
2229 }
2230 
2232 {
2233  frm_dir_map_t::iterator it;
2234  QString msg;
2235 
2236  LOG(VB_COMMFLAG, LOG_INFO,
2237  "---------------------------------------------------");
2238  for (it = map.begin(); it != map.end(); ++it)
2239  {
2240  long long frame = it.key();
2241  int flag = *it;
2242  int my_fps = (int)ceil(m_fps);
2243  long long hour = (frame / my_fps) / 60 / 60;
2244  long long min = ((frame / my_fps) / 60) - (hour * 60);
2245  long long sec = (frame / my_fps) - (min * 60) - (hour * 60 * 60);
2246  long long frm = frame - ((sec * my_fps) + (min * 60 * my_fps) +
2247  (hour * 60 * 60 * my_fps));
2248  int my_sec = (int)(frame / my_fps);
2249  msg = QString("%1 : %2 (%3:%4:%5.%6) (%7)")
2250  .arg(frame, 7).arg(flag).arg(hour, 2, 10, QChar('0')).arg(min, 2, 10, QChar('0'))
2251  .arg(sec, 2, 10, QChar('0')).arg(frm, 2, 10, QChar('0')).arg(my_sec);
2252  LOG(VB_COMMFLAG, LOG_INFO, msg);
2253  }
2254  LOG(VB_COMMFLAG, LOG_INFO,
2255  "---------------------------------------------------");
2256 }
2257 
2259  int length)
2260 {
2261  show_map_t::iterator it;
2262  show_map_t::iterator prev;
2263  show_map_t tmpMap;
2264 
2265  if (map.size() <= 2)
2266  return;
2267 
2268  // merge any segments less than 'spacing' frames apart from each other
2269  LOG(VB_COMMFLAG, LOG_INFO, "Commercial Map Before condense:" );
2270  for (it = map.begin(); it != map.end(); ++it)
2271  {
2272  LOG(VB_COMMFLAG, LOG_INFO, QString(" %1:%2")
2273  .arg(it.key()).arg(*it));
2274  tmpMap[it.key()] = *it;
2275  }
2276 
2277  prev = tmpMap.begin();
2278  it = prev;
2279  ++it;
2280  while (it != tmpMap.end())
2281  {
2282  if ((*it == MARK_START) &&
2283  (*prev == MARK_END) &&
2284  ((it.key() - prev.key()) < (uint64_t)spacing))
2285  {
2286  map.remove(prev.key());
2287  map.remove(it.key());
2288  }
2289  ++prev;
2290  ++it;
2291  }
2292 
2293  if (map.empty())
2294  return;
2295 
2296  // delete any segments less than 'length' frames in length
2297  tmpMap.clear();
2298  for (it = map.begin(); it != map.end(); ++it)
2299  tmpMap[it.key()] = *it;
2300 
2301  prev = tmpMap.begin();
2302  it = prev;
2303  ++it;
2304  while (it != tmpMap.end())
2305  {
2306  if ((*prev == MARK_START) &&
2307  (*it == MARK_END) &&
2308  ((it.key() - prev.key()) < (uint64_t)length))
2309  {
2310  map.remove(prev.key());
2311  map.remove(it.key());
2312  }
2313  ++prev;
2314  ++it;
2315  }
2316 
2317  LOG(VB_COMMFLAG, LOG_INFO, "Commercial Map After condense:" );
2318  for (it = map.begin(); it != map.end(); ++it)
2319  LOG(VB_COMMFLAG, LOG_INFO, QString(" %1:%2")
2320  .arg(it.key()).arg(*it));
2321 }
2322 
2324  frm_dir_map_t &out, const show_map_t &in)
2325 {
2326  out.clear();
2327  if (in.empty())
2328  return;
2329 
2330  show_map_t::const_iterator sit;
2331  for (sit = in.begin(); sit != in.end(); ++sit)
2332  {
2333  if (*sit == MARK_START)
2334  out[sit.key()] = MARK_COMM_END;
2335  else
2336  out[sit.key()] = MARK_COMM_START;
2337  }
2338 
2339  frm_dir_map_t::iterator it = out.begin();
2340  if (it == out.end())
2341  return;
2342 
2343  switch (out[it.key()])
2344  {
2345  case MARK_COMM_END:
2346  if (it.key() == 0)
2347  out.remove(0);
2348  else
2349  out[0] = MARK_COMM_START;
2350  break;
2351  case MARK_COMM_START:
2352  break;
2353  default:
2354  out.remove(0);
2355  break;
2356  }
2357 }
2358 
2359 
2360 /* ideas for this method ported back from comskip.c mods by Jere Jones
2361  * which are partially mods based on Myth's original commercial skip
2362  * code written by Chris Pinkham. */
2363 
2365 {
2366  LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::CleanupFrameInfo()");
2367 
2368  // try to account for noisy signal causing blank frames to be undetected
2369  if ((m_framesProcessed > (m_fps * 60)) &&
2370  (m_blankFrameCount < (m_framesProcessed * 0.0004)))
2371  {
2372  std::array<int,256> avgHistogram {};
2373  int minAvg = -1;
2374  int newThreshold = -1;
2375 
2376  LOG(VB_COMMFLAG, LOG_INFO,
2377  QString("ClassicCommDetect: Only found %1 blank frames but "
2378  "wanted at least %2, rechecking data using higher "
2379  "threshold.")
2380  .arg(m_blankFrameCount)
2381  .arg((int)(m_framesProcessed * 0.0004)));
2382  m_blankFrameMap.clear();
2383  m_blankFrameCount = 0;
2384 
2385  avgHistogram.fill(0);
2386 
2387  for (uint64_t i = 1; i <= m_framesProcessed; i++)
2388  avgHistogram[std::clamp(m_frameInfo[i].avgBrightness, 0, 255)] += 1;
2389 
2390  for (int i = 1; i <= 255 && minAvg == -1; i++)
2391  if (avgHistogram[i] > (m_framesProcessed * 0.0004))
2392  minAvg = i;
2393 
2394  newThreshold = minAvg + 3;
2395  LOG(VB_COMMFLAG, LOG_INFO,
2396  QString("Minimum Average Brightness on a frame "
2397  "was %1, will use %2 as new threshold")
2398  .arg(minAvg).arg(newThreshold));
2399 
2400  for (uint64_t i = 1; i <= m_framesProcessed; i++)
2401  {
2402  int value = m_frameInfo[i].flagMask;
2403  m_frameInfo[i].flagMask = value & ~COMM_FRAME_BLANK;
2404 
2405  if (( (m_frameInfo[i].flagMask & COMM_FRAME_BLANK) == 0) &&
2406  (m_frameInfo[i].avgBrightness < newThreshold))
2407  {
2408  m_frameInfo[i].flagMask = value | COMM_FRAME_BLANK;
2411  }
2412  }
2413 
2414  LOG(VB_COMMFLAG, LOG_INFO,
2415  QString("Found %1 blank frames using new value")
2416  .arg(m_blankFrameCount));
2417  }
2418 
2419  // try to account for fuzzy logo detection
2420  for (uint64_t i = 1; i <= m_framesProcessed; i++)
2421  {
2422  if ((i < 10) || ((i+10) > m_framesProcessed))
2423  continue;
2424 
2425  int before = 0;
2426  for (int offset = 1; offset <= 10; offset++)
2427  if ((m_frameInfo[i - offset].flagMask & COMM_FRAME_LOGO_PRESENT) != 0)
2428  before++;
2429 
2430  int after = 0;
2431  for (int offset = 1; offset <= 10; offset++)
2432  if ((m_frameInfo[i + offset].flagMask & COMM_FRAME_LOGO_PRESENT) != 0)
2433  after++;
2434 
2435  int value = m_frameInfo[i].flagMask;
2436  if (value == -1)
2437  m_frameInfo[i].flagMask = 0;
2438 
2439  if (value & COMM_FRAME_LOGO_PRESENT)
2440  {
2441  if ((before < 4) && (after < 4))
2442  m_frameInfo[i].flagMask = value & ~COMM_FRAME_LOGO_PRESENT;
2443  }
2444  else
2445  {
2446  if ((before > 6) && (after > 6))
2447  m_frameInfo[i].flagMask = value | COMM_FRAME_LOGO_PRESENT;
2448  }
2449  }
2450 }
2451 
2453 {
2454  LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::GetLogoCommBreakMap()");
2455 
2456  map.clear();
2457 
2458  bool PrevFrameLogo = false;
2459 
2460  for (uint64_t curFrame = 1 ; curFrame <= m_framesProcessed; curFrame++)
2461  {
2462  bool CurrentFrameLogo =
2463  (m_frameInfo[curFrame].flagMask & COMM_FRAME_LOGO_PRESENT) != 0;
2464 
2465  if (!PrevFrameLogo && CurrentFrameLogo)
2466  map[curFrame] = MARK_START;
2467  else if (PrevFrameLogo && !CurrentFrameLogo)
2468  map[curFrame] = MARK_END;
2469 
2470  PrevFrameLogo = CurrentFrameLogo;
2471  }
2472 }
2473 
2475 {
2476  emit breathe();
2477 }
2478 
2480  std::ostream &out, const frm_dir_map_t *comm_breaks, bool verbose) const
2481 {
2482  if (verbose)
2483  {
2484  QByteArray tmp = FrameInfoEntry::GetHeader().toLatin1();
2485  out << tmp.constData() << " mark" << std::endl;
2486  }
2487 
2488  for (long long i = 1; i < m_curFrameNumber; i++)
2489  {
2490  QMap<long long, FrameInfoEntry>::const_iterator it = m_frameInfo.find(i);
2491  if (it == m_frameInfo.end())
2492  continue;
2493 
2494  QByteArray atmp = (*it).toString(i, verbose).toLatin1();
2495  out << atmp.constData() << " ";
2496  if (comm_breaks)
2497  {
2498  frm_dir_map_t::const_iterator mit = comm_breaks->find(i);
2499  if (mit != comm_breaks->end())
2500  {
2501  QString tmp = (verbose) ?
2502  toString((MarkTypes)*mit) : QString::number(*mit);
2503  atmp = tmp.toLatin1();
2504 
2505  out << atmp.constData();
2506  }
2507  }
2508  out << "\n";
2509  }
2510 
2511  out << std::flush;
2512 }
2513 
2514 /* vim: set expandtab tabstop=4 shiftwidth=4: */
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:93
COMM_FRAME_LOGO_PRESENT
@ COMM_FRAME_LOGO_PRESENT
Definition: ClassicCommDetector.h:28
FrameInfoEntry::sceneChangePercent
int sceneChangePercent
Definition: ClassicCommDetector.h:39
MARK_COMM_END
@ MARK_COMM_END
Definition: programtypes.h:59
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:142
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
COMM_DETECT_ALL
@ COMM_DETECT_ALL
Definition: programtypes.h:136
CommDetectorBase::breathe
void breathe()
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
MARK_START
@ MARK_START
Definition: CommDetectorBase.h:14
ClassicCommDetector::m_recordingStopsAt
QDateTime m_recordingStopsAt
Definition: ClassicCommDetector.h:192
mythcommflagplayer.h
MARK_BLANK_FRAME
@ MARK_BLANK_FRAME
Definition: programtypes.h:57
MythPlayer::OpenFile
virtual int OpenFile(int Retries=4)
Definition: mythplayer.cpp:417
ClassicCommDetector::m_commDetectBorder
int m_commDetectBorder
Definition: ClassicCommDetector.h:141
MarkTypes
MarkTypes
Definition: programtypes.h:46
ClassicCommDetector::BuildLogoCommList
void BuildLogoCommList()
Definition: ClassicCommDetector.cpp:2120
CommDetectorBase::gotNewCommercialBreakList
void gotNewCommercialBreakList()
COMM_FRAME_ASPECT_CHANGE
@ COMM_FRAME_ASPECT_CHANGE
Definition: ClassicCommDetector.h:29
ClassicCommDetector::m_stationLogoPresent
bool m_stationLogoPresent
Definition: ClassicCommDetector.h:181
FrameAspects
enum frameAspects FrameAspects
ClassicCommDetector::ProcessFrame
void ProcessFrame(MythVideoFrame *frame, long long frame_number)
Definition: ClassicCommDetector.cpp:746
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:117
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:2474
COMM_FRAME_RATING_SYMBOL
@ COMM_FRAME_RATING_SYMBOL
Definition: ClassicCommDetector.h:30
LogoDetectorBase::searchForLogo
virtual bool searchForLogo(MythCommFlagPlayer *player)=0
MythPlayer::GetFrameRate
float GetFrameRate(void) const
Definition: mythplayer.h:133
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
COMM_DETECT_LOGO
@ COMM_DETECT_LOGO
Definition: programtypes.h:134
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:702
MythPlayer::GetEof
EofState GetEof(void) const
Definition: mythplayer.cpp:1064
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:1038
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:15
COMM_ASPECT_WIDE
@ COMM_ASPECT_WIDE
Definition: ClassicCommDetector.cpp:25
FrameInfoEntry::flagMask
int flagMask
Definition: ClassicCommDetector.h:42
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:94
MARK_END
@ MARK_END
Definition: CommDetectorBase.h:15
ClassicCommDetector::PrintFullMap
void PrintFullMap(std::ostream &out, const frm_dir_map_t *comm_breaks, bool verbose) const override
Definition: ClassicCommDetector.cpp:2479
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:1023
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:2019
kEofStateNone
@ kEofStateNone
Definition: decoderbase.h:70
frameFormats
frameFormats
Definition: ClassicCommDetector.cpp:31
SceneChangeDetectorBase::haveNewInformation
void haveNewInformation(unsigned int framenum, bool scenechange, float debugValue=0.0)
programinfo.h
COMM_DETECT_OFF
@ COMM_DETECT_OFF
Definition: programtypes.h:130
COMM_DETECT_BLANK
@ COMM_DETECT_BLANK
Definition: programtypes.h:131
ClassicCommDetector::BuildBlankFrameCommList
void BuildBlankFrameCommList(void)
Definition: ClassicCommDetector.cpp:1860
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
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:2199
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:270
ClassicCommDetector::GetLogoCommBreakMap
void GetLogoCommBreakMap(show_map_t &map)
Definition: ClassicCommDetector.cpp:2452
MythVideoFrame::m_frameNumber
long long m_frameNumber
Definition: mythframe.h:128
toStringFrameMaskValues
static QString toStringFrameMaskValues(int mask, bool verbose)
Definition: ClassicCommDetector.cpp:38
ClassicCommDetector::m_preRoll
long long m_preRoll
Definition: ClassicCommDetector.h:199
MARK_CUT_START
@ MARK_CUT_START
Definition: programtypes.h:55
COMM_FRAME_SKIPPED
@ COMM_FRAME_SKIPPED
Definition: ClassicCommDetector.h:25
COMM_FORMAT_NORMAL
@ COMM_FORMAT_NORMAL
Definition: ClassicCommDetector.cpp:32
MythCommFlagPlayer
Definition: mythcommflagplayer.h:25
FMT_YV12
@ FMT_YV12
Definition: mythframe.h:23
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:990
floatusecs
std::chrono::duration< double, std::micro > floatusecs
Definition: mythchrono.h:41
MARK_COMM_START
@ MARK_COMM_START
Definition: programtypes.h:58
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:608
SceneChangeDetectorBase::processFrame
virtual void processFrame(MythVideoFrame *frame)=0
ClassicCommDetector::SetVideoParams
void SetVideoParams(float aspect)
Definition: ClassicCommDetector.cpp:708
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:55
clamp
static eu8 clamp(eu8 value, eu8 low, eu8 high)
Definition: pxsup2dast.c:204
COMM_ASPECT_NORMAL
@ COMM_ASPECT_NORMAL
Definition: ClassicCommDetector.cpp:24
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:916
ClassicCommDetector::m_framesProcessed
uint64_t m_framesProcessed
Definition: ClassicCommDetector.h:198
MythVideoFrame::m_pitches
FramePitches m_pitches
Definition: mythframe.h:141
CommDetectorBase::m_bStop
bool m_bStop
Definition: CommDetectorBase.h:53
SkipType
SkipType
This is used as a bitmask.
Definition: programtypes.h:127
MythCoreContext::GetBoolSetting
bool GetBoolSetting(const QString &key, bool defaultval=false)
Definition: mythcorecontext.cpp:910
ClassicCommDetector::m_vertSpacing
int m_vertSpacing
Definition: ClassicCommDetector.h:161
ClassicCommDetector::DumpMap
void DumpMap(frm_dir_map_t &map) const
Definition: ClassicCommDetector.cpp:2231
COMM_FORMAT_MAX
@ COMM_FORMAT_MAX
Definition: ClassicCommDetector.cpp:35
COMM_DETECT_BLANKS
@ COMM_DETECT_BLANKS
Definition: programtypes.h:132
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
frameAspects
frameAspects
Definition: ClassicCommDetector.cpp:23
ClassicCommDetector::m_commDetectDimAverage
int m_commDetectDimAverage
Definition: ClassicCommDetector.h:146
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
COMM_FORMAT_LETTERBOX
@ COMM_FORMAT_LETTERBOX
Definition: ClassicCommDetector.cpp:33
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:2258
mythmiscutil.h
ClassicCommDetector::GetCommercialBreakList
void GetCommercialBreakList(frm_dir_map_t &marks) override
Definition: ClassicCommDetector.cpp:625
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
MARK_SCENE_CHANGE
@ MARK_SCENE_CHANGE
Definition: programtypes.h:62
ClassicCommDetector::MergeBlankCommList
void MergeBlankCommList(void)
Definition: ClassicCommDetector.cpp:2134
MythVideoFrame::m_type
VideoFrameType m_type
Definition: mythframe.h:118
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:176
MythDate
Definition: mythdate.cpp:12
MythPlayer::GetVideoSize
QSize GetVideoSize(void) const
Definition: mythplayer.h:131
ClassicCommDetector::m_frameIsBlank
bool m_frameIsBlank
Definition: ClassicCommDetector.h:180
MythPlayer::GetVideoAspect
float GetVideoAspect(void) const
Definition: mythplayer.h:132
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:1961
ClassicCommDetector::m_aggressiveDetection
bool m_aggressiveDetection
Definition: ClassicCommDetector.h:193
ClassicCommDetector::m_commDetectBlankFrameMaxDiff
int m_commDetectBlankFrameMaxDiff
Definition: ClassicCommDetector.h:142
ClassicCommDetector::FrameBlock::length
double length
Definition: ClassicCommDetector.h:82
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:87
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
COMM_FRAME_BLANK
@ COMM_FRAME_BLANK
Definition: ClassicCommDetector.h:26
ClassicSceneChangeDetector
Definition: ClassicSceneChangeDetector.h:8
COMM_FORMAT_PILLARBOX
@ COMM_FORMAT_PILLARBOX
Definition: ClassicCommDetector.cpp:34
ClassicCommDetector::m_blankFrameMap
frm_dir_map_t m_blankFrameMap
Definition: ClassicCommDetector.h:172
ClassicCommDetector::CleanupFrameInfo
void CleanupFrameInfo(void)
Definition: ClassicCommDetector.cpp:2364
COMM_DETECT_SCENE
@ COMM_DETECT_SCENE
Definition: programtypes.h:133
toStringFrameAspects
static QString toStringFrameAspects(int aspect, bool verbose)
Definition: ClassicCommDetector.cpp:75
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:469
ClassicCommDetector::m_postRoll
long long m_postRoll
Definition: ClassicCommDetector.h:200
COMM_FRAME_SCENE_CHANGE
@ COMM_FRAME_SCENE_CHANGE
Definition: ClassicCommDetector.h:27
ClassicCommDetector::recordingFinished
void recordingFinished(long long totalFileSize) override
Definition: ClassicCommDetector.cpp:697
ClassicCommDetector::FrameBlock::bfCount
int bfCount
Definition: ClassicCommDetector.h:83
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:126
MythCommFlagPlayer::GetRawVideoFrame
MythVideoFrame * GetRawVideoFrame(long long FrameNumber=-1)
Returns a specific frame from the video.
Definition: mythcommflagplayer.cpp:226
FrameInfoEntry::aspect
int aspect
Definition: ClassicCommDetector.h:40
MythVideoFrame::m_buffer
uint8_t * m_buffer
Definition: mythframe.h:119
ClassicCommDetector::ConvertShowMapToCommMap
static void ConvertShowMapToCommMap(frm_dir_map_t &out, const show_map_t &in)
Definition: ClassicCommDetector.cpp:2323
ClassicCommDetector::m_startedAt
QDateTime m_startedAt
Definition: ClassicCommDetector.h:189
ClassicCommDetector::m_player
MythCommFlagPlayer * m_player
Definition: ClassicCommDetector.h:188
MythPlayer::DiscardVideoFrame
void DiscardVideoFrame(MythVideoFrame *buffer)
Places frame in the available frames queue.
Definition: mythplayer.cpp:626