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