8#include <QCoreApplication>
59 msg = msg.left(msg.length() - 1);
88 return (
verbose) ?
"normal" :
" N ";
90 return (
verbose) ?
"letter" :
" L ";
92 return (
verbose) ?
"pillar" :
" P ";
94 return (
verbose) ?
"letter,pillar" :
"L,P";
96 return (
verbose) ?
" max " :
" M ";
99 return (
verbose) ?
"unknown" :
" U ";
104 return {
" frame min/max/avg scene aspect format flags"};
110 "%1: %2/%3/%4 %5% %6 %7 %8")
122 bool showProgress_in,
125 QDateTime startedAt_in,
126 QDateTime stopsAt_in,
127 QDateTime recordingStartedAt_in,
128 QDateTime recordingStopsAt_in) :
131 m_commDetectMethod(commDetectMethod_in),
133 m_startedAt(
std::move(startedAt_in)),
134 m_stopsAt(
std::move(stopsAt_in)),
135 m_recordingStartedAt(
std::move(recordingStartedAt_in)),
136 m_recordingStopsAt(
std::move(recordingStopsAt_in)),
138 m_fullSpeed(fullSpeed_in),
139 m_showProgress(showProgress_in)
167 m_width = video_disp_dim.width();
192 LOG(VB_COMMFLAG, LOG_INFO,
193 QString(
"Commercial Detection initialized: "
194 "width = %1, height = %2, fps = %3, method = %4")
224 LOG(VB_COMMFLAG, LOG_INFO,
225 QString(
"Using Sample Spacing of %1 horizontal & %2 vertical pixels.")
260 LOG(VB_COMMFLAG, LOG_DEBUG,
261 " Fr # Min Max Avg Scn F A Mask");
262 LOG(VB_COMMFLAG, LOG_DEBUG,
263 " ------ --- --- --- --- - - ----");
275 CommDetectorBase::deleteLater();
281 int requiredBuffer = 30;
282 int requiredHeadStart = requiredBuffer;
285 emit
statusUpdate(QCoreApplication::translate(
"(mythcommflag)",
286 "Building Head Start Buffer"));
294 std::this_thread::sleep_for(2s);
314 int logoDetectBorder =
319 requiredHeadStart += std::max(
323 emit
statusUpdate(QCoreApplication::translate(
"(mythcommflag)",
324 "Building Logo Detection Buffer"));
332 std::this_thread::sleep_for(2s);
338 if ((wereRecording) && (!
m_stillRecording) && (secsSince < requiredHeadStart))
346 LOG(VB_GENERAL, LOG_ERR,
347 "NVP: Unable to initialize video for FlagCommercials.");
353 emit
statusUpdate(QCoreApplication::translate(
"(mythcommflag)",
354 "Searching for Logo"));
358 std::cerr <<
"Finding Logo";
361 LOG(VB_GENERAL, LOG_INFO,
"Finding Logo");
368 LOG(VB_COMMFLAG, LOG_WARNING,
"No logo found, abort flagging.");
375 std::cerr <<
"\b\b\b\b\b\b\b\b\b\b\b\b "
376 "\b\b\b\b\b\b\b\b\b\b\b\b";
385 QElapsedTimer flagTime;
388 long long myTotalFrames = 0;
398 std::cerr <<
"\r 0%/ \r" << std::flush;
400 std::cerr <<
"\r 0/ \r" << std::flush;
405 int prevpercent = -1;
415 std::chrono::microseconds startTime {0us};
417 startTime = nowAsDuration<std::chrono::microseconds>();
426 float newAspect = currentFrame->
m_aspect;
427 if (newAspect != aspect)
433 if (((currentFrameNumber % 500) == 0) ||
434 (((currentFrameNumber % 100) == 0) &&
447 ((currentFrameNumber % 500) == 0)))
450 frm_dir_map_t::iterator it;
451 frm_dir_map_t::iterator lastIt;
452 bool mapsAreIdentical =
false;
456 if ((commBreakMap.empty()) &&
459 mapsAreIdentical =
true;
464 mapsAreIdentical =
true;
465 for (it = commBreakMap.begin();
466 it != commBreakMap.end() && mapsAreIdentical; ++it)
471 mapsAreIdentical =
false;
488 std::this_thread::sleep_for(1s);
493 std::this_thread::sleep_for(10ms);
495 if (((currentFrameNumber % 500) == 0) ||
497 ((currentFrameNumber % 100) == 0)))
499 float flagFPS { 0.0 };
500 float elapsed = flagTime.elapsed() / 1000.0F;
503 flagFPS = currentFrameNumber / elapsed;
509 percentage = currentFrameNumber * 100 / myTotalFrames;
511 percentage = std::min(percentage, 100);
517 QString
tmp = QString(
"\r%1%/%2fps \r")
518 .arg(percentage, 3).arg((
int)flagFPS, 4);
519 std::cerr << qPrintable(
tmp) << std::flush;
523 QString
tmp = QString(
"\r%1/%2fps \r")
524 .arg(currentFrameNumber, 6).arg((
int)flagFPS, 4);
525 std::cerr << qPrintable(
tmp) << std::flush;
531 emit
statusUpdate(QCoreApplication::translate(
"(mythcommflag)",
532 "%1% Completed @ %2 fps.")
533 .arg(percentage).arg(flagFPS));
537 emit
statusUpdate(QCoreApplication::translate(
"(mythcommflag)",
538 "%1 Frames Completed @ %2 fps.")
539 .arg(currentFrameNumber).arg(flagFPS));
542 if (percentage % 10 == 0 && prevpercent != percentage)
544 prevpercent = percentage;
545 LOG(VB_GENERAL, LOG_INFO, QString(
"%1%% Completed @ %2 fps.")
546 .arg(percentage) .arg(flagFPS));
554 int secondsRecorded =
557 int secondsBehind = secondsRecorded - secondsFlagged;
560 auto endTime = nowAsDuration<std::chrono::microseconds>();
562 floatusecs usecSleep = usecPerFrame - (endTime - startTime);
564 if (secondsBehind > requiredBuffer)
569 usecSleep = usecSleep * 0.25;
571 else if (secondsBehind < requiredBuffer)
573 usecSleep = usecPerFrame * 1.5;
577 std::this_thread::sleep_for(usecSleep);
586 float elapsed = flagTime.elapsed() / 1000.0;
589 flagFPS = currentFrameNumber / elapsed;
595 std::cerr <<
"\b\b\b\b\b\b \b\b\b\b\b\b";
597 std::cerr <<
"\b\b\b\b\b\b\b\b\b\b\b\b\b "
598 "\b\b\b\b\b\b\b\b\b\b\b\b\b";
606 unsigned int framenum,
bool isSceneChange,
float debugValue)
615 m_frameInfo[framenum].flagMask &= ~COMM_FRAME_SCENE_CHANGE;
619 m_frameInfo[framenum].sceneChangePercent = (int) (debugValue*100);
625 LOG(VB_COMMFLAG, LOG_INFO,
"CommDetect::GetCommBreakMap()");
638 if (!blank && !scene && !logo)
640 LOG(VB_COMMFLAG, LOG_ERR, QString(
"Unexpected commDetectMethod: 0x%1")
645 if (blank && scene && logo)
649 LOG(VB_COMMFLAG, LOG_INFO,
"Final Commercial Break Map");
671 int cnt = ((blank) ? 1 : 0) + ((scene) ? 1 : 0) + ((logo) ? 1 : 0);
679 else if (blank && logo)
684 else if (scene && logo)
691 LOG(VB_COMMFLAG, LOG_INFO,
"Final Commercial Break Map");
709 LOG(VB_COMMFLAG, LOG_INFO,
710 QString(
"CommDetect::SetVideoParams called with aspect = %1")
714 if (fabs(aspect - 1.333333F) < 0.1F)
719 LOG(VB_COMMFLAG, LOG_INFO,
720 QString(
"Aspect Ratio changed from %1 to %2 at frame %3")
734 LOG(VB_COMMFLAG, LOG_ERR,
735 QString(
"Unable to keep track of Aspect ratio change because "
736 "frameInfo for frame number %1 does not exist.")
744 long long frame_number)
748 int blankPixelsChecked = 0;
749 long long totBrightness = 0;
750 auto *rowMax =
new unsigned char[
m_height];
751 auto *colMax =
new unsigned char[
m_width];
752 memset(rowMax, 0,
sizeof(*rowMax)*
m_height);
753 memset(colMax, 0,
sizeof(*colMax)*
m_width);
760 if (!frame || !(frame->
m_buffer) || frame_number == -1 ||
763 LOG(VB_COMMFLAG, LOG_ERR,
"CommDetect: Invalid video frame or codec, "
764 "unable to process frame.");
772 LOG(VB_COMMFLAG, LOG_ERR,
"CommDetect: Width or Height is 0, "
773 "unable to process frame.");
780 unsigned char* framePtr = frame->
m_buffer;
783 fInfo.minBrightness = -1;
784 fInfo.maxBrightness = -1;
785 fInfo.avgBrightness = -1;
786 fInfo.sceneChangePercent = -1;
829 uchar
pixel = framePtr[(y * bytesPerLine) + x];
833 bool checkPixel =
false;
843 blankPixelsChecked++;
844 totBrightness +=
pixel;
846 min = std::min<int>(
pixel, min);
847 max = std::max<int>(
pixel, max);
848 rowMax[y] = std::max(
pixel, rowMax[y]);
849 colMax[x] = std::max(
pixel, colMax[x]);
898 (leftDarkCol < (
m_width * .20)) &&
900 (rightDarkCol > (
m_width * .80)))
905 int avg = totBrightness / blankPixelsChecked;
940 (CheckRatingSymbol()))
966 LOG(VB_COMMFLAG, LOG_DEBUG, QString(
"Frame: %1 -> %2 %3 %4 %5 %6 %7 %8")
984 LOG(VB_COMMFLAG, LOG_INFO,
"CommDetect::ClearAllMaps()");
997 LOG(VB_COMMFLAG, LOG_INFO,
"CommDetect::GetBlankCommMap()");
1007 LOG(VB_COMMFLAG, LOG_INFO,
"CommDetect::GetBlankCommBreakMap()");
1016 int64_t start_frame)
1018 LOG(VB_COMMFLAG, LOG_INFO,
"CommDetect::GetSceneChangeMap()");
1020 frm_dir_map_t::iterator it;
1022 if (start_frame == -1)
1026 if ((start_frame == -1) || ((int64_t)it.key() >= start_frame))
1027 scenes[it.key()] = *it;
1033 LOG(VB_COMMFLAG, LOG_INFO,
"CommDetect::BuildMasterCommList()");
1039 frm_dir_map_t::const_iterator it = a.begin();
1040 for (; it != a.end(); ++it)
1041 newMap[it.key()] = *it;
1044 if ((a.size() > 1) &&
1048 frm_dir_map_t::const_iterator it_a;
1049 frm_dir_map_t::const_iterator it_b;
1054 if ((it_b.key() < 2) && (it_a.key() > 2))
1056 newMap.remove(it_a.key());
1062 frm_dir_map_t::const_iterator it;
1067 for (; it != a.end(); ++it)
1074 for (; it != b.end(); ++it)
1083 newMap.remove(max_a);
1088 if ((a.size() > 3) &&
1091 frm_dir_map_t::const_iterator it_a;
1092 frm_dir_map_t::const_iterator it_b;
1098 while (it_b != a.end())
1100 uint64_t fdiff = it_b.key() - it_a.key();
1101 bool allTrue =
false;
1103 if (fdiff < (62 *
m_fps))
1105 uint64_t f = it_a.key() + 1;
1115 newMap.remove(it_a.key());
1116 newMap.remove(it_b.key());
1121 if (it_b != a.end())
1131 int format,
int aspect)
1146 if (finfo.
format == format)
1149 if (finfo.
aspect == aspect)
1155 LOG(VB_COMMFLAG, LOG_INFO,
"CommDetect::BuildAllMethodsCommList()");
1158 uint64_t lastStart = 0;
1159 uint64_t lastEnd = 0;
1160 int64_t firstLogoFrame = -1;
1164 std::array<uint64_t,COMM_FORMAT_MAX> formatCounts {};
1166 frm_dir_map_t::iterator it;
1173 uint64_t curFrame = 1;
1186 bool lastFrameWasBlank =
true;
1190 uint64_t aspectFrames = 0;
1207 formatCounts.fill(0);
1218 uint64_t formatFrames = 0;
1221 if (formatCounts[i] > formatFrames)
1224 formatFrames = formatCounts[i];
1240 if (!nextFrameIsBlank || !lastFrameWasBlank)
1244 fbp->
end = curFrame;
1253 fbp = &fblock[curBlock];
1262 fbp->
start = curFrame;
1265 lastFrameWasBlank =
true;
1269 lastFrameWasBlank =
false;
1275 (firstLogoFrame == -1))
1276 firstLogoFrame = curFrame;
1281 fbp->
end = curFrame;
1288 int maxBlock = curBlock;
1292 LOG(VB_COMMFLAG, LOG_INFO,
"Initial Block pass");
1293 LOG(VB_COMMFLAG, LOG_DEBUG,
1294 "Block StTime StFrm EndFrm Frames Secs "
1295 "Bf Lg Cnt RT Cnt SC Cnt SC Rt FmtMch AspMch Score");
1296 LOG(VB_COMMFLAG, LOG_INFO,
1297 "----- ------ ------ ------ ------ ------- "
1298 "--- ------ ------ ------ ----- ------ ------ -----");
1299 while (curBlock <= maxBlock)
1301 fbp = &fblock[curBlock];
1304 LOG(VB_COMMFLAG, LOG_DEBUG, msg);
1309 LOG(VB_COMMFLAG, LOG_DEBUG,
1310 QString(
" FRAMES > %1").arg(
m_fps));
1315 LOG(VB_COMMFLAG, LOG_DEBUG,
1316 " length > max comm length, +20");
1323 LOG(VB_COMMFLAG, LOG_DEBUG,
1324 " length > max comm break length, +20");
1334 LOG(VB_COMMFLAG, LOG_DEBUG,
1335 " length > 4 && logoCount > frames * 0.60 && "
1336 "bfCount < frames * .10");
1341 LOG(VB_COMMFLAG, LOG_DEBUG,
1342 " length > max comm break length, +20");
1348 LOG(VB_COMMFLAG, LOG_DEBUG,
1349 " length <= max comm break length, +10");
1359 LOG(VB_COMMFLAG, LOG_DEBUG,
1360 " logoInfoAvailable && logoCount < frames * .50, "
1369 LOG(VB_COMMFLAG, LOG_DEBUG,
1370 " rating symbol present > 5% of time, +20");
1374 if ((fbp->
scRate > 1.0) &&
1378 LOG(VB_COMMFLAG, LOG_DEBUG,
" scRate > 1.0, -10");
1384 LOG(VB_COMMFLAG, LOG_DEBUG,
" scRate > 2.0, -10");
1394 LOG(VB_COMMFLAG, LOG_DEBUG,
1395 " < 10% of frames match show letter/pillar-box "
1401 if ((abs((
int)(fbp->
frames - (15 *
m_fps))) < 5 ) ||
1406 LOG(VB_COMMFLAG, LOG_DEBUG,
1407 " block appears to be standard comm length, -10");
1414 LOG(VB_COMMFLAG, LOG_DEBUG,
1415 QString(
" FRAMES <= %1").arg(
m_fps));
1418 (fbp->
start >= firstLogoFrame) &&
1422 LOG(VB_COMMFLAG, LOG_DEBUG,
1423 " logoInfoAvailable && logoCount == 0, -10");
1432 LOG(VB_COMMFLAG, LOG_DEBUG,
1433 " < 10% of frames match show letter/pillar-box "
1442 LOG(VB_COMMFLAG, LOG_DEBUG,
1443 " rating symbol present > 25% of time, +10");
1452 LOG(VB_COMMFLAG, LOG_DEBUG,
1453 " < 10% of frames match show aspect, -20");
1458 LOG(VB_COMMFLAG, LOG_DEBUG, msg);
1467 LOG(VB_COMMFLAG, LOG_DEBUG,
"============================================");
1468 LOG(VB_COMMFLAG, LOG_INFO,
"Second Block pass");
1469 LOG(VB_COMMFLAG, LOG_DEBUG,
1470 "Block StTime StFrm EndFrm Frames Secs "
1471 "Bf Lg Cnt RT Cnt SC Cnt SC Rt FmtMch AspMch Score");
1472 LOG(VB_COMMFLAG, LOG_DEBUG,
1473 "----- ------ ------ ------ ------ ------- "
1474 "--- ------ ------ ------ ----- ------ ------ -----");
1475 while (curBlock <= maxBlock)
1477 fbp = &fblock[curBlock];
1480 LOG(VB_COMMFLAG, LOG_DEBUG, msg);
1482 if ((curBlock > 0) && (curBlock < maxBlock))
1484 int nextScore = fblock[curBlock + 1].score;
1486 if ((lastScore < 0) && (nextScore < 0) && (fbp->
length < 35))
1490 LOG(VB_COMMFLAG, LOG_DEBUG,
1491 " lastScore < 0 && nextScore < 0 "
1492 "&& length < 35, setting -10");
1499 (lastScore < 0 && nextScore < 0))
1503 LOG(VB_COMMFLAG, LOG_DEBUG,
1504 " blanks > frames * 0.95 && frames < 2*m_fps && "
1505 "lastScore < 0 && nextScore < 0, setting -10");
1513 (fbp->
score < 20) &&
1518 LOG(VB_COMMFLAG, LOG_DEBUG,
1519 " frames < 120 * m_fps && (-20 < lastScore < 0) && "
1520 "thisScore > 0 && nextScore < 0, setting score = -10");
1528 (fbp->
score > -20) &&
1533 LOG(VB_COMMFLAG, LOG_DEBUG,
1534 " frames < 30 * m_fps && (0 < lastScore < 20) && "
1535 "thisScore < 0 && nextScore > 0, setting score = 10");
1541 if ((fbp->
score == 0) && (lastScore > 30))
1544 while(((curBlock + offset) <= maxBlock) &&
1545 (fblock[curBlock + offset].frames < (2 *
m_fps)) &&
1546 (fblock[curBlock + offset].score == 0))
1549 if ((curBlock + offset) <= maxBlock)
1552 if (fblock[curBlock + offset + 1].score > 0)
1554 for (; offset >= 0; offset--)
1556 fblock[curBlock + offset].score += 10;
1559 LOG(VB_COMMFLAG, LOG_DEBUG,
1560 QString(
" Setting block %1 score +10")
1561 .arg(curBlock+offset));
1565 else if (fblock[curBlock + offset + 1].score < 0)
1567 for (; offset >= 0; offset--)
1569 fblock[curBlock + offset].score -= 10;
1572 LOG(VB_COMMFLAG, LOG_DEBUG,
1573 QString(
" Setting block %1 score -10")
1574 .arg(curBlock+offset));
1582 LOG(VB_COMMFLAG, LOG_DEBUG, msg);
1584 lastScore = fbp->
score;
1588 LOG(VB_COMMFLAG, LOG_DEBUG,
"============================================");
1589 LOG(VB_COMMFLAG, LOG_INFO,
"FINAL Block stats");
1590 LOG(VB_COMMFLAG, LOG_DEBUG,
1591 "Block StTime StFrm EndFrm Frames Secs "
1592 "Bf Lg Cnt RT Cnt SC Cnt SC Rt FmtMch AspMch Score");
1593 LOG(VB_COMMFLAG, LOG_DEBUG,
1594 "----- ------ ------ ------ ------ ------- "
1595 "--- ------ ------ ------ ----- ------ ------ -----");
1598 int64_t breakStart = -1;
1599 while (curBlock <= maxBlock)
1601 fbp = &fblock[curBlock];
1602 int thisScore = fbp->
score;
1604 if ((breakStart >= 0) &&
1607 if (((fbp->
start - breakStart) >
1613 LOG(VB_COMMFLAG, LOG_DEBUG,
1614 QString(
"Closing commercial block at start of "
1615 "frame block %1 with length %2, frame "
1616 "block length of %3 frames would put comm "
1617 "block length over max of %4 seconds.")
1618 .arg(curBlock).arg(fbp->
start - breakStart)
1625 lastStart = breakStart;
1626 lastEnd = fbp->
start;
1633 LOG(VB_COMMFLAG, LOG_DEBUG,
1634 QString(
"Ignoring what appears to be commercial"
1635 " block at frame %1 with length %2, "
1636 "length of %3 frames would put comm "
1637 "block length under min of %4 seconds.")
1639 .arg(fbp->
start - breakStart)
1648 thisScore = lastScore;
1650 else if (thisScore < 0)
1652 if ((lastScore > 0) || (curBlock == 0))
1658 breakStart = lastStart;
1664 LOG(VB_COMMFLAG, LOG_DEBUG,
1665 QString(
"ReOpening commercial block at "
1666 "frame %1 because show less than "
1673 LOG(VB_COMMFLAG, LOG_DEBUG,
1674 "Opening initial commercial block "
1675 "at start of recording, block 0.");
1681 breakStart = fbp->
start;
1685 LOG(VB_COMMFLAG, LOG_DEBUG,
1686 QString(
"Starting new commercial block at "
1687 "frame %1 from start of frame block %2")
1688 .arg(fbp->
start).arg(curBlock));
1692 else if (curBlock == maxBlock)
1694 if ((fbp->
end - breakStart) >
1702 LOG(VB_COMMFLAG, LOG_DEBUG,
1703 QString(
"Closing final commercial block at "
1704 "frame %1").arg(fbp->
end));
1709 lastStart = breakStart;
1718 LOG(VB_COMMFLAG, LOG_DEBUG,
1719 QString(
"Ignoring what appears to be commercial"
1720 " block at frame %1 with length %2, "
1721 "length of %3 frames would put comm "
1722 "block length under min of %4 seconds.")
1724 .arg(fbp->
start - breakStart)
1733 else if ((lastScore < 0) &&
1736 if (((fbp->
start - breakStart) >
1742 lastStart = breakStart;
1743 lastEnd = fbp->
start;
1747 LOG(VB_COMMFLAG, LOG_DEBUG,
1748 QString(
"Closing commercial block at frame %1")
1756 LOG(VB_COMMFLAG, LOG_DEBUG,
1757 QString(
"Ignoring what appears to be commercial "
1758 "block at frame %1 with length %2, "
1759 "length of %3 frames would put comm block "
1760 "length under min of %4 seconds.")
1762 .arg(fbp->
start - breakStart)
1771 LOG(VB_COMMFLAG, LOG_DEBUG, msg);
1773 lastScore = thisScore;
1777 if ((breakStart != -1) &&
1782 LOG(VB_COMMFLAG, LOG_DEBUG,
1783 QString(
"Closing final commercial block started at "
1784 "block %1 and going to end of program. length "
1802 LOG(VB_COMMFLAG, LOG_DEBUG,
1803 "Adjusting start/end marks according to blanks.");
1804 for (it = tmpCommMap.begin(); it != tmpCommMap.end(); ++it)
1808 uint64_t lastStartLower = it.key();
1809 uint64_t lastStartUpper = it.key();
1810 while ((lastStartLower > 0) &&
1816 uint64_t adj = (lastStartUpper - lastStartLower) / 2;
1818 lastStart = lastStartLower + adj;
1821 LOG(VB_COMMFLAG, LOG_DEBUG, QString(
"Start Mark: %1 -> %2")
1822 .arg(it.key()).arg(lastStart));
1828 uint64_t lastEndLower = it.key();
1829 uint64_t lastEndUpper = it.key();
1833 while ((lastEndLower > 0) &&
1836 uint64_t adj = (lastEndUpper - lastEndLower) / 2;
1838 lastEnd = lastEndUpper - adj;
1841 LOG(VB_COMMFLAG, LOG_DEBUG, QString(
"End Mark : %1 -> %2")
1842 .arg(it.key()).arg(lastEnd));
1854 LOG(VB_COMMFLAG, LOG_INFO,
"CommDetect::BuildBlankFrameCommList()");
1863 int commercials = 0;
1868 bframes[frames++] = it.key();
1873 for(
int i = 0; i < frames; i++ )
1875 for(
int x=i+1; x < frames; x++ )
1880 int gap_length = bframes[x] - bframes[i];
1882 ((abs((
int)(gap_length - (5 *
m_fps))) < 5 ) ||
1883 (abs((
int)(gap_length - (10 *
m_fps))) < 7 ) ||
1884 (abs((
int)(gap_length - (15 *
m_fps))) < 10 ) ||
1885 (abs((
int)(gap_length - (20 *
m_fps))) < 11 ) ||
1886 (abs((
int)(gap_length - (30 *
m_fps))) < 12 ) ||
1887 (abs((
int)(gap_length - (40 *
m_fps))) < 1 ) ||
1888 (abs((
int)(gap_length - (45 *
m_fps))) < 1 ) ||
1889 (abs((
int)(gap_length - (60 *
m_fps))) < 15 ) ||
1890 (abs((
int)(gap_length - (90 *
m_fps))) < 10 ) ||
1891 (abs((
int)(gap_length - (120 *
m_fps))) < 10 ))) ||
1893 ((abs((
int)(gap_length - (5 *
m_fps))) < 11 ) ||
1894 (abs((
int)(gap_length - (10 *
m_fps))) < 13 ) ||
1895 (abs((
int)(gap_length - (15 *
m_fps))) < 16 ) ||
1896 (abs((
int)(gap_length - (20 *
m_fps))) < 17 ) ||
1897 (abs((
int)(gap_length - (30 *
m_fps))) < 18 ) ||
1898 (abs((
int)(gap_length - (40 *
m_fps))) < 3 ) ||
1899 (abs((
int)(gap_length - (45 *
m_fps))) < 3 ) ||
1900 (abs((
int)(gap_length - (60 *
m_fps))) < 20 ) ||
1901 (abs((
int)(gap_length - (90 *
m_fps))) < 20 ) ||
1902 (abs((
int)(gap_length - (120 *
m_fps))) < 20 ))))
1904 c_start[commercials] = bframes[i];
1905 c_end[commercials] = bframes[x] - 1;
1912 ((abs((
int)(gap_length - (30 *
m_fps))) < (
int)(
m_fps * 0.85)) ||
1913 (abs((
int)(gap_length - (60 *
m_fps))) < (
int)(
m_fps * 0.95)) ||
1914 (abs((
int)(gap_length - (90 *
m_fps))) < (
int)(
m_fps * 1.05)) ||
1915 (abs((
int)(gap_length - (120 *
m_fps))) < (
int)(
m_fps * 1.15))) &&
1916 ((x + 2) < frames) &&
1917 ((i + 2) < frames) &&
1918 ((bframes[i] + 1) == bframes[i+1]) &&
1919 ((bframes[x] + 1) == bframes[x+1]))
1921 c_start[commercials] = bframes[i];
1922 c_end[commercials] = bframes[x];
1934 if ((commercials > 1) &&
1935 (c_end[0] < (33 *
m_fps)) &&
1936 (c_start[1] > (c_end[0] + (40 *
m_fps))))
1940 bool first_comm =
true;
1941 for(; i < (commercials-1); i++)
1943 long long r = c_start[i];
1944 long long adjustment = 0;
1946 if ((r < (30 *
m_fps)) &&
1953 if ( i < (commercials-1))
1956 for(x = 0; x < (frames-1); x++)
1957 if (bframes[x] == r)
1959 while((x < (frames-1)) &&
1960 ((bframes[x] + 1 ) == bframes[x+1]) &&
1961 (bframes[x+1] < c_start[i+1]))
1968 (c_start[i+1] != (r+1)))
1997 LOG(VB_COMMFLAG, LOG_INFO,
"Blank-Frame Commercial Map" );
1999 LOG(VB_COMMFLAG, LOG_INFO, QString(
" %1:%2")
2000 .arg(it.key()).arg(*it));
2004 LOG(VB_COMMFLAG, LOG_INFO,
"Merged Blank-Frame Commercial Break Map" );
2006 LOG(VB_COMMFLAG, LOG_INFO, QString(
" %1:%2")
2007 .arg(it.key()).arg(*it));
2013 int section_start = -1;
2015 int *sc_histogram =
new int[seconds+1];
2019 memset(sc_histogram, 0, (seconds+1)*
sizeof(
int));
2023 sc_histogram[(uint64_t)(f /
m_fps)]++;
2026 for(
long long s = 0; s < (seconds + 1); s++)
2028 if (sc_histogram[s] > 2)
2030 if (section_start == -1)
2033 for(
int i = 0; i <
m_fps; i++, f++)
2038 i = (int)(
m_fps) + 1;
2046 if ((section_start >= 0) &&
2047 (s > (section_start + 32)))
2049 auto f = (
long long)(section_start *
m_fps);
2050 bool found_end =
false;
2052 for(
int i = 0; i <
m_fps; i++, f++)
2061 i = (int)(
m_fps) + 1;
2074 delete[] sc_histogram;
2076 if (section_start >= 0)
2081 frm_dir_map_t::iterator prev = it;
2088 (it.key() - prev.key()) < (30 *
m_fps))
2098 frm_dir_map_t::iterator dit;
2099 for (dit = deleteMap.begin(); dit != deleteMap.end(); ++dit)
2103 LOG(VB_COMMFLAG, LOG_INFO,
"Scene-Change Commercial Break Map" );
2106 LOG(VB_COMMFLAG, LOG_INFO, QString(
" %1:%2")
2107 .arg(it.key()).arg(*it));
2119 frm_dir_map_t::iterator it;
2120 LOG(VB_COMMFLAG, LOG_INFO,
"Logo Commercial Break Map" );
2122 LOG(VB_COMMFLAG, LOG_INFO, QString(
" %1:%2")
2123 .arg(it.key()).arg(*it));
2128 frm_dir_map_t::iterator it;
2129 frm_dir_map_t::iterator prev;
2130 QMap<long long, long long> tmpMap;
2131 QMap<long long, long long>::Iterator tmpMap_it;
2132 QMap<long long, long long>::Iterator tmpMap_prev;
2151 if ((((prev.key() + 1) == it.key()) ||
2152 ((prev.key() + (15 *
m_fps)) > it.key())) &&
2166 tmpMap[prev.key()] = it.key();
2171 tmpMap[prev.key()] = it.key();
2174 tmpMap_it = tmpMap.begin();
2175 tmpMap_prev = tmpMap_it;
2177 for(; tmpMap_it != tmpMap.end(); ++tmpMap_it, ++tmpMap_prev)
2181 if (((*tmpMap_prev + (35 *
m_fps)) > tmpMap_it.key()) &&
2182 ((*tmpMap_prev - tmpMap_prev.key()) > (35 *
m_fps)) &&
2183 ((*tmpMap_it - tmpMap_it.key()) > (35 *
m_fps)))
2196 if (breakMap.contains(i))
2198 int type = breakMap[i];
2208 for (uint64_t i = (f + 1); i-- > 0; )
2210 if (breakMap.contains(i))
2212 int type = breakMap[i];
2225 frm_dir_map_t::iterator it;
2228 LOG(VB_COMMFLAG, LOG_INFO,
2229 "---------------------------------------------------");
2230 for (it = map.begin(); it != map.end(); ++it)
2232 long long frame = it.key();
2234 int my_fps = (int)ceil(
m_fps);
2235 long long hour = (frame / my_fps) / 60 / 60;
2236 long long min = ((frame / my_fps) / 60) - (hour * 60);
2237 long long sec = (frame / my_fps) - (min * 60) - (hour * 60 * 60);
2238 long long frm = frame - ((sec * my_fps) + (min * 60 * my_fps) +
2239 (hour * 60 * 60 * my_fps));
2240 int my_sec = (int)(frame / my_fps);
2241 msg = QString(
"%1 : %2 (%3:%4:%5.%6) (%7)")
2242 .arg(frame, 7).arg(flag).arg(hour, 2, 10, QChar(
'0')).arg(min, 2, 10, QChar(
'0'))
2243 .arg(sec, 2, 10, QChar(
'0')).arg(frm, 2, 10, QChar(
'0')).arg(my_sec);
2244 LOG(VB_COMMFLAG, LOG_INFO, msg);
2246 LOG(VB_COMMFLAG, LOG_INFO,
2247 "---------------------------------------------------");
2253 show_map_t::iterator it;
2254 show_map_t::iterator prev;
2257 if (map.size() <= 2)
2261 LOG(VB_COMMFLAG, LOG_INFO,
"Commercial Map Before condense:" );
2262 for (it = map.begin(); it != map.end(); ++it)
2264 LOG(VB_COMMFLAG, LOG_INFO, QString(
" %1:%2")
2265 .arg(it.key()).arg(*it));
2266 tmpMap[it.key()] = *it;
2269 prev = tmpMap.begin();
2272 while (it != tmpMap.end())
2276 ((it.key() - prev.key()) < (uint64_t)spacing))
2278 map.remove(prev.key());
2279 map.remove(it.key());
2290 for (it = map.begin(); it != map.end(); ++it)
2291 tmpMap[it.key()] = *it;
2293 prev = tmpMap.begin();
2296 while (it != tmpMap.end())
2300 ((it.key() - prev.key()) < (uint64_t)length))
2302 map.remove(prev.key());
2303 map.remove(it.key());
2309 LOG(VB_COMMFLAG, LOG_INFO,
"Commercial Map After condense:" );
2310 for (it = map.begin(); it != map.end(); ++it)
2311 LOG(VB_COMMFLAG, LOG_INFO, QString(
" %1:%2")
2312 .arg(it.key()).arg(*it));
2322 show_map_t::const_iterator sit;
2323 for (sit = in.begin(); sit != in.end(); ++sit)
2331 frm_dir_map_t::iterator it = out.begin();
2332 if (it == out.end())
2335 switch (out[it.key()])
2358 LOG(VB_COMMFLAG, LOG_INFO,
"CommDetect::CleanupFrameInfo()");
2364 std::array<int,256> avgHistogram {};
2366 int newThreshold = -1;
2368 LOG(VB_COMMFLAG, LOG_INFO,
2369 QString(
"ClassicCommDetect: Only found %1 blank frames but "
2370 "wanted at least %2, rechecking data using higher "
2377 avgHistogram.fill(0);
2382 for (
int i = 1; i <= 255 && minAvg == -1; i++)
2386 newThreshold = minAvg + 3;
2387 LOG(VB_COMMFLAG, LOG_INFO,
2388 QString(
"Minimum Average Brightness on a frame "
2389 "was %1, will use %2 as new threshold")
2390 .arg(minAvg).arg(newThreshold));
2395 m_frameInfo[i].flagMask = value & ~COMM_FRAME_BLANK;
2406 LOG(VB_COMMFLAG, LOG_INFO,
2407 QString(
"Found %1 blank frames using new value")
2418 for (
int offset = 1; offset <= 10; offset++)
2423 for (
int offset = 1; offset <= 10; offset++)
2433 if ((before < 4) && (after < 4))
2434 m_frameInfo[i].flagMask = value & ~COMM_FRAME_LOGO_PRESENT;
2438 if ((before > 6) && (after > 6))
2446 LOG(VB_COMMFLAG, LOG_INFO,
"CommDetect::GetLogoCommBreakMap()");
2450 bool PrevFrameLogo =
false;
2454 bool CurrentFrameLogo =
2457 if (!PrevFrameLogo && CurrentFrameLogo)
2459 else if (PrevFrameLogo && !CurrentFrameLogo)
2462 PrevFrameLogo = CurrentFrameLogo;
2477 out <<
tmp.constData() <<
" mark" << std::endl;
2482 QMap<long long, FrameInfoEntry>::const_iterator it =
m_frameInfo.find(i);
2486 QByteArray atmp = (*it).toString(i,
verbose).toLatin1();
2487 out << atmp.constData() <<
" ";
2490 frm_dir_map_t::const_iterator mit = comm_breaks->find(i);
2491 if (mit != comm_breaks->end())
2495 atmp =
tmp.toLatin1();
2497 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 guint32 * 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)