8#include <QCoreApplication>
15#ifndef __cpp_size_t_suffix
61 msg = msg.left(msg.length() - 1);
90 return (
verbose) ?
"normal" :
" N ";
92 return (
verbose) ?
"letter" :
" L ";
94 return (
verbose) ?
"pillar" :
" P ";
96 return (
verbose) ?
"letter,pillar" :
"L,P";
98 return (
verbose) ?
" max " :
" M ";
101 return (
verbose) ?
"unknown" :
" U ";
106 return {
" frame min/max/avg scene aspect format flags"};
112 "%1: %2/%3/%4 %5% %6 %7 %8")
124 bool showProgress_in,
127 QDateTime startedAt_in,
128 QDateTime stopsAt_in,
129 QDateTime recordingStartedAt_in,
130 QDateTime recordingStopsAt_in) :
133 m_commDetectMethod(commDetectMethod_in),
135 m_startedAt(std::move(startedAt_in)),
136 m_stopsAt(std::move(stopsAt_in)),
137 m_recordingStartedAt(std::move(recordingStartedAt_in)),
138 m_recordingStopsAt(std::move(recordingStopsAt_in)),
140 m_fullSpeed(fullSpeed_in),
141 m_showProgress(showProgress_in)
169 m_width = video_disp_dim.width();
194 LOG(VB_COMMFLAG, LOG_INFO,
195 QString(
"Commercial Detection initialized: "
196 "width = %1, height = %2, fps = %3, method = %4")
226 LOG(VB_COMMFLAG, LOG_INFO,
227 QString(
"Using Sample Spacing of %1 horizontal & %2 vertical pixels.")
262 LOG(VB_COMMFLAG, LOG_DEBUG,
263 " Fr # Min Max Avg Scn F A Mask");
264 LOG(VB_COMMFLAG, LOG_DEBUG,
265 " ------ --- --- --- --- - - ----");
277 CommDetectorBase::deleteLater();
283 int requiredBuffer = 30;
284 int requiredHeadStart = requiredBuffer;
287 emit
statusUpdate(QCoreApplication::translate(
"(mythcommflag)",
288 "Building Head Start Buffer"));
296 std::this_thread::sleep_for(2s);
316 int logoDetectBorder =
321 requiredHeadStart += std::max(
325 emit
statusUpdate(QCoreApplication::translate(
"(mythcommflag)",
326 "Building Logo Detection Buffer"));
334 std::this_thread::sleep_for(2s);
340 if ((wereRecording) && (!
m_stillRecording) && (secsSince < requiredHeadStart))
348 LOG(VB_GENERAL, LOG_ERR,
349 "NVP: Unable to initialize video for FlagCommercials.");
355 emit
statusUpdate(QCoreApplication::translate(
"(mythcommflag)",
356 "Searching for Logo"));
360 std::cerr <<
"Finding Logo";
363 LOG(VB_GENERAL, LOG_INFO,
"Finding Logo");
370 LOG(VB_COMMFLAG, LOG_WARNING,
"No logo found, abort flagging.");
377 std::cerr <<
"\b\b\b\b\b\b\b\b\b\b\b\b "
378 "\b\b\b\b\b\b\b\b\b\b\b\b";
387 QElapsedTimer flagTime;
390 long long myTotalFrames = 0;
400 std::cerr <<
"\r 0%/ \r" << std::flush;
402 std::cerr <<
"\r 0/ \r" << std::flush;
407 int prevpercent = -1;
417 std::chrono::microseconds startTime {0us};
419 startTime = nowAsDuration<std::chrono::microseconds>();
428 float newAspect = currentFrame->
m_aspect;
429 if (newAspect != aspect)
435 if (((currentFrameNumber % 500) == 0) ||
436 (((currentFrameNumber % 100) == 0) &&
449 ((currentFrameNumber % 500) == 0)))
452 frm_dir_map_t::iterator it;
453 frm_dir_map_t::iterator lastIt;
454 bool mapsAreIdentical =
false;
458 if ((commBreakMap.empty()) &&
461 mapsAreIdentical =
true;
466 mapsAreIdentical =
true;
467 for (it = commBreakMap.begin();
468 it != commBreakMap.end() && mapsAreIdentical; ++it)
473 mapsAreIdentical =
false;
490 std::this_thread::sleep_for(1s);
495 std::this_thread::sleep_for(10ms);
497 if (((currentFrameNumber % 500) == 0) ||
499 ((currentFrameNumber % 100) == 0)))
501 float flagFPS { 0.0 };
502 float elapsed = flagTime.elapsed() / 1000.0F;
505 flagFPS = currentFrameNumber / elapsed;
511 percentage = currentFrameNumber * 100 / myTotalFrames;
513 percentage = std::min(percentage, 100);
519 QString tmp = QString(
"\r%1%/%2fps \r")
520 .arg(percentage, 3).arg((
int)flagFPS, 4);
521 std::cerr << qPrintable(tmp) << std::flush;
525 QString tmp = QString(
"\r%1/%2fps \r")
526 .arg(currentFrameNumber, 6).arg((
int)flagFPS, 4);
527 std::cerr << qPrintable(tmp) << std::flush;
533 emit
statusUpdate(QCoreApplication::translate(
"(mythcommflag)",
534 "%1% Completed @ %2 fps.")
535 .arg(percentage).arg(flagFPS));
539 emit
statusUpdate(QCoreApplication::translate(
"(mythcommflag)",
540 "%1 Frames Completed @ %2 fps.")
541 .arg(currentFrameNumber).arg(flagFPS));
544 if (percentage % 10 == 0 && prevpercent != percentage)
546 prevpercent = percentage;
547 LOG(VB_GENERAL, LOG_INFO, QString(
"%1% Completed @ %2 fps.")
548 .arg(percentage) .arg(flagFPS));
556 int secondsRecorded =
559 int secondsBehind = secondsRecorded - secondsFlagged;
562 auto endTime = nowAsDuration<std::chrono::microseconds>();
564 floatusecs usecSleep = usecPerFrame - (endTime - startTime);
566 if (secondsBehind > requiredBuffer)
571 usecSleep = usecSleep * 0.25;
573 else if (secondsBehind < requiredBuffer)
575 usecSleep = usecPerFrame * 1.5;
579 std::this_thread::sleep_for(usecSleep);
588 float elapsed = flagTime.elapsed() / 1000.0;
591 flagFPS = currentFrameNumber / elapsed;
597 std::cerr <<
"\b\b\b\b\b\b \b\b\b\b\b\b";
599 std::cerr <<
"\b\b\b\b\b\b\b\b\b\b\b\b\b "
600 "\b\b\b\b\b\b\b\b\b\b\b\b\b";
608 unsigned int framenum,
bool isSceneChange,
float debugValue)
617 m_frameInfo[framenum].flagMask &= ~COMM_FRAME_SCENE_CHANGE;
621 m_frameInfo[framenum].sceneChangePercent = (int) (debugValue*100);
627 LOG(VB_COMMFLAG, LOG_INFO,
"CommDetect::GetCommBreakMap()");
640 if (!blank && !scene && !logo)
642 LOG(VB_COMMFLAG, LOG_ERR, QString(
"Unexpected commDetectMethod: 0x%1")
647 if (blank && scene && logo)
651 LOG(VB_COMMFLAG, LOG_INFO,
"Final Commercial Break Map");
673 int cnt = ((blank) ? 1 : 0) + ((scene) ? 1 : 0) + ((logo) ? 1 : 0);
681 else if (blank && logo)
686 else if (scene && logo)
693 LOG(VB_COMMFLAG, LOG_INFO,
"Final Commercial Break Map");
711 LOG(VB_COMMFLAG, LOG_INFO,
712 QString(
"CommDetect::SetVideoParams called with aspect = %1")
716 if (fabs(aspect - 1.333333F) < 0.1F)
721 LOG(VB_COMMFLAG, LOG_INFO,
722 QString(
"Aspect Ratio changed from %1 to %2 at frame %3")
736 LOG(VB_COMMFLAG, LOG_ERR,
737 QString(
"Unable to keep track of Aspect ratio change because "
738 "frameInfo for frame number %1 does not exist.")
746 long long frame_number)
750 int blankPixelsChecked = 0;
751 long long totBrightness = 0;
752 auto *rowMax =
new unsigned char[
m_height];
753 auto *colMax =
new unsigned char[
m_width];
754 memset(rowMax, 0,
sizeof(*rowMax)*
m_height);
755 memset(colMax, 0,
sizeof(*colMax)*
m_width);
762 if (!frame || !(frame->
m_buffer) || frame_number == -1 ||
765 LOG(VB_COMMFLAG, LOG_ERR,
"CommDetect: Invalid video frame or codec, "
766 "unable to process frame.");
774 LOG(VB_COMMFLAG, LOG_ERR,
"CommDetect: Width or Height is 0, "
775 "unable to process frame.");
782 unsigned char* framePtr = frame->
m_buffer;
785 fInfo.minBrightness = -1;
786 fInfo.maxBrightness = -1;
787 fInfo.avgBrightness = -1;
788 fInfo.sceneChangePercent = -1;
831 uchar
pixel = framePtr[(y * bytesPerLine) + x];
835 bool checkPixel =
false;
845 blankPixelsChecked++;
846 totBrightness +=
pixel;
848 min = std::min<int>(
pixel, min);
849 max = std::max<int>(
pixel, max);
850 rowMax[y] = std::max(
pixel, rowMax[y]);
851 colMax[x] = std::max(
pixel, colMax[x]);
900 (leftDarkCol < (
m_width * .20)) &&
902 (rightDarkCol > (
m_width * .80)))
907 int avg = totBrightness / blankPixelsChecked;
942 (CheckRatingSymbol()))
968 LOG(VB_COMMFLAG, LOG_DEBUG, QString(
"Frame: %1 -> %2 %3 %4 %5 %6 %7 %8")
986 LOG(VB_COMMFLAG, LOG_INFO,
"CommDetect::ClearAllMaps()");
999 LOG(VB_COMMFLAG, LOG_INFO,
"CommDetect::GetBlankCommMap()");
1009 LOG(VB_COMMFLAG, LOG_INFO,
"CommDetect::GetBlankCommBreakMap()");
1018 int64_t start_frame)
1020 LOG(VB_COMMFLAG, LOG_INFO,
"CommDetect::GetSceneChangeMap()");
1022 frm_dir_map_t::iterator it;
1024 if (start_frame == -1)
1028 if ((start_frame == -1) || ((int64_t)it.key() >= start_frame))
1029 scenes[it.key()] = *it;
1035 LOG(VB_COMMFLAG, LOG_INFO,
"CommDetect::BuildMasterCommList()");
1041 frm_dir_map_t::const_iterator it = a.begin();
1042 for (; it != a.end(); ++it)
1043 newMap[it.key()] = *it;
1046 if ((a.size() > 1) &&
1050 frm_dir_map_t::const_iterator it_a;
1051 frm_dir_map_t::const_iterator it_b;
1056 if ((it_b.key() < 2) && (it_a.key() > 2))
1058 newMap.remove(it_a.key());
1064 frm_dir_map_t::const_iterator it;
1069 for (; it != a.end(); ++it)
1076 for (; it != b.end(); ++it)
1085 newMap.remove(max_a);
1090 if ((a.size() > 3) &&
1093 frm_dir_map_t::const_iterator it_a;
1094 frm_dir_map_t::const_iterator it_b;
1100 while (it_b != a.end())
1102 uint64_t fdiff = it_b.key() - it_a.key();
1103 bool allTrue =
false;
1105 if (fdiff < (62 *
m_fps))
1107 uint64_t f = it_a.key() + 1;
1117 newMap.remove(it_a.key());
1118 newMap.remove(it_b.key());
1123 if (it_b != a.end())
1133 int format,
int aspect)
1148 if (finfo.
format == format)
1151 if (finfo.
aspect == aspect)
1157 LOG(VB_COMMFLAG, LOG_INFO,
"CommDetect::BuildAllMethodsCommList()");
1160 uint64_t lastStart = 0;
1161 uint64_t lastEnd = 0;
1162 int64_t firstLogoFrame = -1;
1166 std::array<uint64_t,COMM_FORMAT_MAX> formatCounts {};
1168 frm_dir_map_t::iterator it;
1175 uint64_t curFrame = 1;
1188 bool lastFrameWasBlank =
true;
1192 uint64_t aspectFrames = 0;
1209 formatCounts.fill(0);
1220 uint64_t formatFrames = 0;
1223 if (formatCounts[i] > formatFrames)
1226 formatFrames = formatCounts[i];
1242 if (!nextFrameIsBlank || !lastFrameWasBlank)
1246 fbp->
end = curFrame;
1255 fbp = &fblock[curBlock];
1264 fbp->
start = curFrame;
1267 lastFrameWasBlank =
true;
1271 lastFrameWasBlank =
false;
1277 (firstLogoFrame == -1))
1278 firstLogoFrame = curFrame;
1283 fbp->
end = curFrame;
1290 int maxBlock = curBlock;
1294 LOG(VB_COMMFLAG, LOG_INFO,
"Initial Block pass");
1295 LOG(VB_COMMFLAG, LOG_DEBUG,
1296 "Block StTime StFrm EndFrm Frames Secs "
1297 "Bf Lg Cnt RT Cnt SC Cnt SC Rt FmtMch AspMch Score");
1298 LOG(VB_COMMFLAG, LOG_INFO,
1299 "----- ------ ------ ------ ------ ------- "
1300 "--- ------ ------ ------ ----- ------ ------ -----");
1301 while (curBlock <= maxBlock)
1303 fbp = &fblock[curBlock];
1306 LOG(VB_COMMFLAG, LOG_DEBUG, msg);
1311 LOG(VB_COMMFLAG, LOG_DEBUG,
1312 QString(
" FRAMES > %1").arg(
m_fps));
1317 LOG(VB_COMMFLAG, LOG_DEBUG,
1318 " length > max comm length, +20");
1325 LOG(VB_COMMFLAG, LOG_DEBUG,
1326 " length > max comm break length, +20");
1336 LOG(VB_COMMFLAG, LOG_DEBUG,
1337 " length > 4 && logoCount > frames * 0.60 && "
1338 "bfCount < frames * .10");
1343 LOG(VB_COMMFLAG, LOG_DEBUG,
1344 " length > max comm break length, +20");
1350 LOG(VB_COMMFLAG, LOG_DEBUG,
1351 " length <= max comm break length, +10");
1361 LOG(VB_COMMFLAG, LOG_DEBUG,
1362 " logoInfoAvailable && logoCount < frames * .50, "
1371 LOG(VB_COMMFLAG, LOG_DEBUG,
1372 " rating symbol present > 5% of time, +20");
1376 if ((fbp->
scRate > 1.0) &&
1380 LOG(VB_COMMFLAG, LOG_DEBUG,
" scRate > 1.0, -10");
1386 LOG(VB_COMMFLAG, LOG_DEBUG,
" scRate > 2.0, -10");
1396 LOG(VB_COMMFLAG, LOG_DEBUG,
1397 " < 10% of frames match show letter/pillar-box "
1403 if ((abs((
int)(fbp->
frames - (15 *
m_fps))) < 5 ) ||
1408 LOG(VB_COMMFLAG, LOG_DEBUG,
1409 " block appears to be standard comm length, -10");
1416 LOG(VB_COMMFLAG, LOG_DEBUG,
1417 QString(
" FRAMES <= %1").arg(
m_fps));
1420 (fbp->
start >= firstLogoFrame) &&
1424 LOG(VB_COMMFLAG, LOG_DEBUG,
1425 " logoInfoAvailable && logoCount == 0, -10");
1434 LOG(VB_COMMFLAG, LOG_DEBUG,
1435 " < 10% of frames match show letter/pillar-box "
1444 LOG(VB_COMMFLAG, LOG_DEBUG,
1445 " rating symbol present > 25% of time, +10");
1454 LOG(VB_COMMFLAG, LOG_DEBUG,
1455 " < 10% of frames match show aspect, -20");
1460 LOG(VB_COMMFLAG, LOG_DEBUG, msg);
1469 LOG(VB_COMMFLAG, LOG_DEBUG,
"============================================");
1470 LOG(VB_COMMFLAG, LOG_INFO,
"Second Block pass");
1471 LOG(VB_COMMFLAG, LOG_DEBUG,
1472 "Block StTime StFrm EndFrm Frames Secs "
1473 "Bf Lg Cnt RT Cnt SC Cnt SC Rt FmtMch AspMch Score");
1474 LOG(VB_COMMFLAG, LOG_DEBUG,
1475 "----- ------ ------ ------ ------ ------- "
1476 "--- ------ ------ ------ ----- ------ ------ -----");
1477 while (curBlock <= maxBlock)
1479 fbp = &fblock[curBlock];
1482 LOG(VB_COMMFLAG, LOG_DEBUG, msg);
1484 if ((curBlock > 0) && (curBlock < maxBlock))
1486 int nextScore = fblock[curBlock + 1].score;
1488 if ((lastScore < 0) && (nextScore < 0) && (fbp->
length < 35))
1492 LOG(VB_COMMFLAG, LOG_DEBUG,
1493 " lastScore < 0 && nextScore < 0 "
1494 "&& length < 35, setting -10");
1501 (lastScore < 0 && nextScore < 0))
1505 LOG(VB_COMMFLAG, LOG_DEBUG,
1506 " blanks > frames * 0.95 && frames < 2*m_fps && "
1507 "lastScore < 0 && nextScore < 0, setting -10");
1515 (fbp->
score < 20) &&
1520 LOG(VB_COMMFLAG, LOG_DEBUG,
1521 " frames < 120 * m_fps && (-20 < lastScore < 0) && "
1522 "thisScore > 0 && nextScore < 0, setting score = -10");
1530 (fbp->
score > -20) &&
1535 LOG(VB_COMMFLAG, LOG_DEBUG,
1536 " frames < 30 * m_fps && (0 < lastScore < 20) && "
1537 "thisScore < 0 && nextScore > 0, setting score = 10");
1543 if ((fbp->
score == 0) && (lastScore > 30))
1546 while(((curBlock + offset) <= maxBlock) &&
1547 (fblock[curBlock + offset].frames < (2 *
m_fps)) &&
1548 (fblock[curBlock + offset].score == 0))
1551 if ((curBlock + offset) <= maxBlock)
1554 if (fblock[curBlock + offset + 1].score > 0)
1556 for (; offset >= 0; offset--)
1558 fblock[curBlock + offset].score += 10;
1561 LOG(VB_COMMFLAG, LOG_DEBUG,
1562 QString(
" Setting block %1 score +10")
1563 .arg(curBlock+offset));
1567 else if (fblock[curBlock + offset + 1].score < 0)
1569 for (; offset >= 0; offset--)
1571 fblock[curBlock + offset].score -= 10;
1574 LOG(VB_COMMFLAG, LOG_DEBUG,
1575 QString(
" Setting block %1 score -10")
1576 .arg(curBlock+offset));
1584 LOG(VB_COMMFLAG, LOG_DEBUG, msg);
1586 lastScore = fbp->
score;
1590 LOG(VB_COMMFLAG, LOG_DEBUG,
"============================================");
1591 LOG(VB_COMMFLAG, LOG_INFO,
"FINAL Block stats");
1592 LOG(VB_COMMFLAG, LOG_DEBUG,
1593 "Block StTime StFrm EndFrm Frames Secs "
1594 "Bf Lg Cnt RT Cnt SC Cnt SC Rt FmtMch AspMch Score");
1595 LOG(VB_COMMFLAG, LOG_DEBUG,
1596 "----- ------ ------ ------ ------ ------- "
1597 "--- ------ ------ ------ ----- ------ ------ -----");
1600 int64_t breakStart = -1;
1601 while (curBlock <= maxBlock)
1603 fbp = &fblock[curBlock];
1604 int thisScore = fbp->
score;
1606 if ((breakStart >= 0) &&
1609 if (((fbp->
start - breakStart) >
1615 LOG(VB_COMMFLAG, LOG_DEBUG,
1616 QString(
"Closing commercial block at start of "
1617 "frame block %1 with length %2, frame "
1618 "block length of %3 frames would put comm "
1619 "block length over max of %4 seconds.")
1620 .arg(curBlock).arg(fbp->
start - breakStart)
1627 lastStart = breakStart;
1628 lastEnd = fbp->
start;
1635 LOG(VB_COMMFLAG, LOG_DEBUG,
1636 QString(
"Ignoring what appears to be commercial"
1637 " block at frame %1 with length %2, "
1638 "length of %3 frames would put comm "
1639 "block length under min of %4 seconds.")
1641 .arg(fbp->
start - breakStart)
1650 thisScore = lastScore;
1652 else if (thisScore < 0)
1654 if ((lastScore > 0) || (curBlock == 0))
1660 breakStart = lastStart;
1666 LOG(VB_COMMFLAG, LOG_DEBUG,
1667 QString(
"ReOpening commercial block at "
1668 "frame %1 because show less than "
1675 LOG(VB_COMMFLAG, LOG_DEBUG,
1676 "Opening initial commercial block "
1677 "at start of recording, block 0.");
1683 breakStart = fbp->
start;
1687 LOG(VB_COMMFLAG, LOG_DEBUG,
1688 QString(
"Starting new commercial block at "
1689 "frame %1 from start of frame block %2")
1690 .arg(fbp->
start).arg(curBlock));
1694 else if (curBlock == maxBlock)
1696 if ((fbp->
end - breakStart) >
1704 LOG(VB_COMMFLAG, LOG_DEBUG,
1705 QString(
"Closing final commercial block at "
1706 "frame %1").arg(fbp->
end));
1711 lastStart = breakStart;
1720 LOG(VB_COMMFLAG, LOG_DEBUG,
1721 QString(
"Ignoring what appears to be commercial"
1722 " block at frame %1 with length %2, "
1723 "length of %3 frames would put comm "
1724 "block length under min of %4 seconds.")
1726 .arg(fbp->
start - breakStart)
1735 else if ((lastScore < 0) &&
1738 if (((fbp->
start - breakStart) >
1744 lastStart = breakStart;
1745 lastEnd = fbp->
start;
1749 LOG(VB_COMMFLAG, LOG_DEBUG,
1750 QString(
"Closing commercial block at frame %1")
1758 LOG(VB_COMMFLAG, LOG_DEBUG,
1759 QString(
"Ignoring what appears to be commercial "
1760 "block at frame %1 with length %2, "
1761 "length of %3 frames would put comm block "
1762 "length under min of %4 seconds.")
1764 .arg(fbp->
start - breakStart)
1773 LOG(VB_COMMFLAG, LOG_DEBUG, msg);
1775 lastScore = thisScore;
1779 if ((breakStart != -1) &&
1784 LOG(VB_COMMFLAG, LOG_DEBUG,
1785 QString(
"Closing final commercial block started at "
1786 "block %1 and going to end of program. length "
1804 LOG(VB_COMMFLAG, LOG_DEBUG,
1805 "Adjusting start/end marks according to blanks.");
1806 for (it = tmpCommMap.begin(); it != tmpCommMap.end(); ++it)
1810 uint64_t lastStartLower = it.key();
1811 uint64_t lastStartUpper = it.key();
1812 while ((lastStartLower > 0) &&
1818 uint64_t adj = (lastStartUpper - lastStartLower) / 2;
1820 lastStart = lastStartLower + adj;
1823 LOG(VB_COMMFLAG, LOG_DEBUG, QString(
"Start Mark: %1 -> %2")
1824 .arg(it.key()).arg(lastStart));
1830 uint64_t lastEndLower = it.key();
1831 uint64_t lastEndUpper = it.key();
1835 while ((lastEndLower > 0) &&
1838 uint64_t adj = (lastEndUpper - lastEndLower) / 2;
1840 lastEnd = lastEndUpper - adj;
1843 LOG(VB_COMMFLAG, LOG_DEBUG, QString(
"End Mark : %1 -> %2")
1844 .arg(it.key()).arg(lastEnd));
1856 LOG(VB_COMMFLAG, LOG_INFO,
"CommDetect::BuildBlankFrameCommList()");
1861#ifdef __cpp_size_t_suffix
1871 int commercials = 0;
1876 bframes[frames++] = it.key();
1881 for(
int i = 0; i < frames; i++ )
1883 for(
int x=i+1; x < frames; x++ )
1888 int gap_length = bframes[x] - bframes[i];
1890 ((abs((
int)(gap_length - (5 *
m_fps))) < 5 ) ||
1891 (abs((
int)(gap_length - (10 *
m_fps))) < 7 ) ||
1892 (abs((
int)(gap_length - (15 *
m_fps))) < 10 ) ||
1893 (abs((
int)(gap_length - (20 *
m_fps))) < 11 ) ||
1894 (abs((
int)(gap_length - (30 *
m_fps))) < 12 ) ||
1895 (abs((
int)(gap_length - (40 *
m_fps))) < 1 ) ||
1896 (abs((
int)(gap_length - (45 *
m_fps))) < 1 ) ||
1897 (abs((
int)(gap_length - (60 *
m_fps))) < 15 ) ||
1898 (abs((
int)(gap_length - (90 *
m_fps))) < 10 ) ||
1899 (abs((
int)(gap_length - (120 *
m_fps))) < 10 ))) ||
1901 ((abs((
int)(gap_length - (5 *
m_fps))) < 11 ) ||
1902 (abs((
int)(gap_length - (10 *
m_fps))) < 13 ) ||
1903 (abs((
int)(gap_length - (15 *
m_fps))) < 16 ) ||
1904 (abs((
int)(gap_length - (20 *
m_fps))) < 17 ) ||
1905 (abs((
int)(gap_length - (30 *
m_fps))) < 18 ) ||
1906 (abs((
int)(gap_length - (40 *
m_fps))) < 3 ) ||
1907 (abs((
int)(gap_length - (45 *
m_fps))) < 3 ) ||
1908 (abs((
int)(gap_length - (60 *
m_fps))) < 20 ) ||
1909 (abs((
int)(gap_length - (90 *
m_fps))) < 20 ) ||
1910 (abs((
int)(gap_length - (120 *
m_fps))) < 20 ))))
1912 c_start[commercials] = bframes[i];
1913 c_end[commercials] = bframes[x] - 1;
1920 ((abs((
int)(gap_length - (30 *
m_fps))) < (
int)(
m_fps * 0.85)) ||
1921 (abs((
int)(gap_length - (60 *
m_fps))) < (
int)(
m_fps * 0.95)) ||
1922 (abs((
int)(gap_length - (90 *
m_fps))) < (
int)(
m_fps * 1.05)) ||
1923 (abs((
int)(gap_length - (120 *
m_fps))) < (
int)(
m_fps * 1.15))) &&
1924 ((x + 2) < frames) &&
1925 ((i + 2) < frames) &&
1926 ((bframes[i] + 1) == bframes[i+1]) &&
1927 ((bframes[x] + 1) == bframes[x+1]))
1929 c_start[commercials] = bframes[i];
1930 c_end[commercials] = bframes[x];
1942 if ((commercials > 1) &&
1943 (c_end[0] < (33 *
m_fps)) &&
1944 (c_start[1] > (c_end[0] + (40 *
m_fps))))
1948 bool first_comm =
true;
1949 for(; i < (commercials-1); i++)
1951 long long r = c_start[i];
1952 long long adjustment = 0;
1954 if ((r < (30 *
m_fps)) &&
1961 if ( i < (commercials-1))
1964 for(x = 0; x < (frames-1); x++)
1965 if (bframes[x] == r)
1967 while((x < (frames-1)) &&
1968 ((bframes[x] + 1 ) == bframes[x+1]) &&
1969 (bframes[x+1] < c_start[i+1]))
1976 (c_start[i+1] != (r+1)))
2005 LOG(VB_COMMFLAG, LOG_INFO,
"Blank-Frame Commercial Map" );
2007 LOG(VB_COMMFLAG, LOG_INFO, QString(
" %1:%2")
2008 .arg(it.key()).arg(*it));
2012 LOG(VB_COMMFLAG, LOG_INFO,
"Merged Blank-Frame Commercial Break Map" );
2014 LOG(VB_COMMFLAG, LOG_INFO, QString(
" %1:%2")
2015 .arg(it.key()).arg(*it));
2021 int section_start = -1;
2023 int *sc_histogram =
new int[seconds+1];
2027 memset(sc_histogram, 0, (seconds+1)*
sizeof(
int));
2031 sc_histogram[(uint64_t)(f /
m_fps)]++;
2034 for(
long long s = 0; s < (seconds + 1); s++)
2036 if (sc_histogram[s] > 2)
2038 if (section_start == -1)
2041 for(
int i = 0; i <
m_fps; i++, f++)
2046 i = (int)(
m_fps) + 1;
2054 if ((section_start >= 0) &&
2055 (s > (section_start + 32)))
2057 auto f = (
long long)(section_start *
m_fps);
2058 bool found_end =
false;
2060 for(
int i = 0; i <
m_fps; i++, f++)
2069 i = (int)(
m_fps) + 1;
2082 delete[] sc_histogram;
2084 if (section_start >= 0)
2089 frm_dir_map_t::iterator prev = it;
2096 (it.key() - prev.key()) < (30 *
m_fps))
2106 frm_dir_map_t::iterator dit;
2107 for (dit = deleteMap.begin(); dit != deleteMap.end(); ++dit)
2111 LOG(VB_COMMFLAG, LOG_INFO,
"Scene-Change Commercial Break Map" );
2114 LOG(VB_COMMFLAG, LOG_INFO, QString(
" %1:%2")
2115 .arg(it.key()).arg(*it));
2127 frm_dir_map_t::iterator it;
2128 LOG(VB_COMMFLAG, LOG_INFO,
"Logo Commercial Break Map" );
2130 LOG(VB_COMMFLAG, LOG_INFO, QString(
" %1:%2")
2131 .arg(it.key()).arg(*it));
2136 frm_dir_map_t::iterator it;
2137 frm_dir_map_t::iterator prev;
2138 QMap<long long, long long> tmpMap;
2139 QMap<long long, long long>::Iterator tmpMap_it;
2140 QMap<long long, long long>::Iterator tmpMap_prev;
2159 if ((((prev.key() + 1) == it.key()) ||
2160 ((prev.key() + (15 *
m_fps)) > it.key())) &&
2174 tmpMap[prev.key()] = it.key();
2179 tmpMap[prev.key()] = it.key();
2182 tmpMap_it = tmpMap.begin();
2183 tmpMap_prev = tmpMap_it;
2185 for(; tmpMap_it != tmpMap.end(); ++tmpMap_it, ++tmpMap_prev)
2189 if (((*tmpMap_prev + (35 *
m_fps)) > tmpMap_it.key()) &&
2190 ((*tmpMap_prev - tmpMap_prev.key()) > (35 *
m_fps)) &&
2191 ((*tmpMap_it - tmpMap_it.key()) > (35 *
m_fps)))
2204 if (breakMap.contains(i))
2206 int type = breakMap[i];
2216 for (uint64_t i = (f + 1); i-- > 0; )
2218 if (breakMap.contains(i))
2220 int type = breakMap[i];
2233 frm_dir_map_t::iterator it;
2236 LOG(VB_COMMFLAG, LOG_INFO,
2237 "---------------------------------------------------");
2238 for (it = map.begin(); it != map.end(); ++it)
2240 long long frame = it.key();
2242 int my_fps = (int)ceil(
m_fps);
2243 long long hour = (frame / my_fps) / 60 / 60;
2244 long long min = ((frame / my_fps) / 60) - (hour * 60);
2245 long long sec = (frame / my_fps) - (min * 60) - (hour * 60 * 60);
2246 long long frm = frame - ((sec * my_fps) + (min * 60 * my_fps) +
2247 (hour * 60 * 60 * my_fps));
2248 int my_sec = (int)(frame / my_fps);
2249 msg = QString(
"%1 : %2 (%3:%4:%5.%6) (%7)")
2250 .arg(frame, 7).arg(flag).arg(hour, 2, 10, QChar(
'0')).arg(min, 2, 10, QChar(
'0'))
2251 .arg(sec, 2, 10, QChar(
'0')).arg(frm, 2, 10, QChar(
'0')).arg(my_sec);
2252 LOG(VB_COMMFLAG, LOG_INFO, msg);
2254 LOG(VB_COMMFLAG, LOG_INFO,
2255 "---------------------------------------------------");
2261 show_map_t::iterator it;
2262 show_map_t::iterator prev;
2265 if (map.size() <= 2)
2269 LOG(VB_COMMFLAG, LOG_INFO,
"Commercial Map Before condense:" );
2270 for (it = map.begin(); it != map.end(); ++it)
2272 LOG(VB_COMMFLAG, LOG_INFO, QString(
" %1:%2")
2273 .arg(it.key()).arg(*it));
2274 tmpMap[it.key()] = *it;
2277 prev = tmpMap.begin();
2280 while (it != tmpMap.end())
2284 ((it.key() - prev.key()) < (uint64_t)spacing))
2286 map.remove(prev.key());
2287 map.remove(it.key());
2298 for (it = map.begin(); it != map.end(); ++it)
2299 tmpMap[it.key()] = *it;
2301 prev = tmpMap.begin();
2304 while (it != tmpMap.end())
2308 ((it.key() - prev.key()) < (uint64_t)length))
2310 map.remove(prev.key());
2311 map.remove(it.key());
2317 LOG(VB_COMMFLAG, LOG_INFO,
"Commercial Map After condense:" );
2318 for (it = map.begin(); it != map.end(); ++it)
2319 LOG(VB_COMMFLAG, LOG_INFO, QString(
" %1:%2")
2320 .arg(it.key()).arg(*it));
2330 show_map_t::const_iterator sit;
2331 for (sit = in.begin(); sit != in.end(); ++sit)
2339 frm_dir_map_t::iterator it = out.begin();
2340 if (it == out.end())
2343 switch (out[it.key()])
2366 LOG(VB_COMMFLAG, LOG_INFO,
"CommDetect::CleanupFrameInfo()");
2372 std::array<int,256> avgHistogram {};
2374 int newThreshold = -1;
2376 LOG(VB_COMMFLAG, LOG_INFO,
2377 QString(
"ClassicCommDetect: Only found %1 blank frames but "
2378 "wanted at least %2, rechecking data using higher "
2385 avgHistogram.fill(0);
2390 for (
int i = 1; i <= 255 && minAvg == -1; i++)
2394 newThreshold = minAvg + 3;
2395 LOG(VB_COMMFLAG, LOG_INFO,
2396 QString(
"Minimum Average Brightness on a frame "
2397 "was %1, will use %2 as new threshold")
2398 .arg(minAvg).arg(newThreshold));
2403 m_frameInfo[i].flagMask = value & ~COMM_FRAME_BLANK;
2414 LOG(VB_COMMFLAG, LOG_INFO,
2415 QString(
"Found %1 blank frames using new value")
2426 for (
int offset = 1; offset <= 10; offset++)
2431 for (
int offset = 1; offset <= 10; offset++)
2441 if ((before < 4) && (after < 4))
2442 m_frameInfo[i].flagMask = value & ~COMM_FRAME_LOGO_PRESENT;
2446 if ((before > 6) && (after > 6))
2454 LOG(VB_COMMFLAG, LOG_INFO,
"CommDetect::GetLogoCommBreakMap()");
2458 bool PrevFrameLogo =
false;
2462 bool CurrentFrameLogo =
2465 if (!PrevFrameLogo && CurrentFrameLogo)
2467 else if (PrevFrameLogo && !CurrentFrameLogo)
2470 PrevFrameLogo = CurrentFrameLogo;
2485 out << tmp.constData() <<
" mark\n";
2490 QMap<long long, FrameInfoEntry>::const_iterator it =
m_frameInfo.find(i);
2494 QByteArray atmp = (*it).toString(i,
verbose).toLatin1();
2495 out << atmp.constData() <<
" ";
2498 frm_dir_map_t::const_iterator mit = comm_breaks->find(i);
2499 if (mit != comm_breaks->end())
2503 atmp = tmp.toLatin1();
2505 out << atmp.constData();
enum frameFormats FrameFormats
enum frameAspects FrameAspects
static QString toStringFrameFormats(int format, bool verbose)
static QString toStringFrameMaskValues(int mask, bool verbose)
static QString toStringFrameAspects(int aspect, bool verbose)
@ COMM_FRAME_RATING_SYMBOL
@ COMM_FRAME_LOGO_PRESENT
@ COMM_FRAME_ASPECT_CHANGE
@ COMM_FRAME_SCENE_CHANGE
static constexpr int64_t MAX_BLANK_FRAMES
QMap< uint64_t, CommMapValue > show_map_t
frm_dir_map_t m_blankFrameMap
static void ConvertShowMapToCommMap(frm_dir_map_t &out, const show_map_t &in)
uint64_t m_framesProcessed
ClassicCommDetector(SkipType commDetectMethod, bool showProgress, bool fullSpeed, MythCommFlagPlayer *player, QDateTime startedAt_in, QDateTime stopsAt_in, QDateTime recordingStartedAt_in, QDateTime recordingStopsAt_in)
QMap< long long, FrameInfoEntry > m_frameInfo
void GetCommercialBreakList(frm_dir_map_t &marks) override
frm_dir_map_t m_commBreakMap
void MergeBlankCommList(void)
static void CondenseMarkMap(show_map_t &map, int spacing, int length)
frm_dir_map_t m_sceneCommBreakMap
QDateTime m_recordingStopsAt
bool m_commBreakMapUpdateRequested
void GetLogoCommBreakMap(show_map_t &map)
void GetBlankCommMap(frm_dir_map_t &comms)
void sceneChangeDetectorHasNewInformation(unsigned int framenum, bool isSceneChange, float debugValue)
void ProcessFrame(MythVideoFrame *frame, long long frame_number)
void PrintFullMap(std::ostream &out, const frm_dir_map_t *comm_breaks, bool verbose) const override
virtual void deleteLater(void)
bool m_sendCommBreakMapUpdates
int m_commDetectMinShowLength
void BuildAllMethodsCommList(void)
int m_commDetectDarkBrightness
frm_dir_map_t m_blankCommMap
frm_dir_map_t m_blankCommBreakMap
int m_commDetectBoxBrightness
long long m_curFrameNumber
SkipType m_commDetectMethod
bool m_stationLogoPresent
long long m_lastFrameNumber
void requestCommBreakMapUpdate(void) override
void BuildBlankFrameCommList(void)
frm_dir_map_t m_logoCommBreakMap
void logoDetectorBreathe()
bool m_decoderFoundAspectChanges
void SetVideoParams(float aspect)
void GetBlankCommBreakMap(frm_dir_map_t &comms)
int m_commDetectMaxCommBreakLength
int m_commDetectMinCommBreakLength
bool m_aggressiveDetection
LogoDetectorBase * m_logoDetector
frm_dir_map_t m_lastSentCommBreakMap
void CleanupFrameInfo(void)
void DumpMap(frm_dir_map_t &map) const
int m_commDetectBlankFrameMaxDiff
int m_commDetectDimAverage
int m_commDetectMaxCommLength
QDateTime m_recordingStartedAt
bool m_commDetectBlankCanHaveLogo
QString FormatMsg(T first, const FrameBlock *fbp)
friend class ClassicLogoDetector
void recordingFinished(long long totalFileSize) override
void GetSceneChangeMap(frm_dir_map_t &scenes, int64_t start_frame)
void BuildSceneChangeCommList(void)
int m_commDetectDimBrightness
static void UpdateFrameBlock(FrameBlock *fbp, const FrameInfoEntry &finfo, int format, int aspect)
MythCommFlagPlayer * m_player
SceneChangeDetectorBase * m_sceneChangeDetector
frm_dir_map_t Combine2Maps(const frm_dir_map_t &a, const frm_dir_map_t &b) const
bool FrameIsInBreakMap(uint64_t f, const frm_dir_map_t &breakMap) const
void statusUpdate(const QString &a)
void gotNewCommercialBreakList()
static QString GetHeader(void)
QString toString(uint64_t frame, bool verbose) const
virtual bool searchForLogo(MythCommFlagPlayer *player)=0
virtual bool pixelInsideLogo(unsigned int x, unsigned int y)=0
virtual bool doesThisFrameContainTheFoundLogo(MythVideoFrame *frame)=0
virtual unsigned int getRequiredAvailableBufferForSearch()=0
MythVideoFrame * GetRawVideoFrame(long long FrameNumber=-1)
Returns a specific frame from the video.
int GetNumSetting(const QString &key, int defaultval=0)
bool GetBoolSetting(const QString &key, bool defaultval=false)
uint64_t GetTotalFrameCount(void) const
QSize GetVideoSize(void) const
virtual int OpenFile(int Retries=4)
void ResetTotalDuration(void)
float GetVideoAspect(void) const
EofState GetEof(void) const
float GetFrameRate(void) const
void DiscardVideoFrame(MythVideoFrame *buffer)
Places frame in the available frames queue.
virtual bool InitVideo(void)
void haveNewInformation(unsigned int framenum, bool scenechange, float debugValue=0.0)
virtual void processFrame(MythVideoFrame *frame)=0
static std::vector< uint32_t > pixel
--------------------------------------------------—**
std::chrono::duration< double, std::micro > floatusecs
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
static uint32_t avg(uint32_t A, uint32_t B)
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
SkipType
This is used as a bitmask.
QMap< uint64_t, MarkTypes > frm_dir_map_t
Frame # -> Mark map.
static eu8 clamp(eu8 value, eu8 low, eu8 high)