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