00001 #include <cmath>
00002 #include <algorithm>
00003 #include <unistd.h>
00004
00005 #include "CommDetector.h"
00006 #include "ClassicCommDetector.h"
00007 #include "libmythtv/NuppelVideoPlayer.h"
00008 #include "ClassicLogoDetector.h"
00009 #include "ClassicSceneChangeDetector.h"
00010
00011 #include "qstring.h"
00012 #include "libmyth/mythcontext.h"
00013 #include "libmythtv/programinfo.h"
00014
00015
00016
00017 enum frameMaskValues {
00018 COMM_FRAME_SKIPPED = 0x0001,
00019 COMM_FRAME_BLANK = 0x0002,
00020 COMM_FRAME_SCENE_CHANGE = 0x0004,
00021 COMM_FRAME_LOGO_PRESENT = 0x0008,
00022 COMM_FRAME_ASPECT_CHANGE = 0x0010,
00023 COMM_FRAME_RATING_SYMBOL = 0x0020
00024 };
00025
00026 enum frameAspects {
00027 COMM_ASPECT_NORMAL = 0,
00028 COMM_ASPECT_WIDE
00029 };
00030
00031 enum frameFormats {
00032 COMM_FORMAT_NORMAL = 0,
00033 COMM_FORMAT_LETTERBOX,
00034 COMM_FORMAT_PILLARBOX,
00035 COMM_FORMAT_MAX
00036 };
00037
00038 ClassicCommDetector::ClassicCommDetector(enum SkipTypes commDetectMethod_in,
00039 bool showProgress_in,
00040 bool fullSpeed_in,
00041 NuppelVideoPlayer* nvp_in,
00042 const QDateTime& startedAt_in,
00043 const QDateTime& stopsAt_in,
00044 const QDateTime& recordingStartedAt_in,
00045 const QDateTime& recordingStopsAt_in) :
00046 commDetectMethod(commDetectMethod_in),
00047 showProgress(showProgress_in),
00048 fullSpeed(fullSpeed_in),
00049 nvp(nvp_in),
00050 startedAt(startedAt_in),
00051 stopsAt(stopsAt_in),
00052 recordingStartedAt(recordingStartedAt_in),
00053 recordingStopsAt(recordingStopsAt_in),
00054 framesProcessed(0),preRoll(0),postRoll(0),
00055 logoDetector(0),
00056 sceneChangeDetector(0)
00057 {
00058
00059 stillRecording = recordingStopsAt > QDateTime::currentDateTime();
00060
00061 commDetectBorder =
00062 gContext->GetNumSetting("CommDetectBorder", 20);
00063 commDetectBlankFrameMaxDiff =
00064 gContext->GetNumSetting("CommDetectBlankFrameMaxDiff", 25);
00065 commDetectDarkBrightness =
00066 gContext->GetNumSetting("CommDetectDarkBrightness", 80);
00067 commDetectDimBrightness =
00068 gContext->GetNumSetting("CommDetectDimBrightness", 120);
00069 commDetectBoxBrightness =
00070 gContext->GetNumSetting("CommDetectBoxBrightness", 30);
00071 commDetectDimAverage =
00072 gContext->GetNumSetting("CommDetectDimAverage", 35);
00073 commDetectMaxCommBreakLength =
00074 gContext->GetNumSetting("CommDetectMaxCommBreakLength", 395);
00075 commDetectMinCommBreakLength =
00076 gContext->GetNumSetting("CommDetectMinCommBreakLength", 60);
00077 commDetectMinShowLength =
00078 gContext->GetNumSetting("CommDetectMinShowLength", 65);
00079 commDetectMaxCommLength =
00080 gContext->GetNumSetting("CommDetectMaxCommLength", 125);
00081
00082 skipAllBlanks = !!gContext->GetNumSetting("CommSkipAllBlanks", 1);
00083 commDetectBlankCanHaveLogo =
00084 !!gContext->GetNumSetting("CommDetectBlankCanHaveLogo", 1);
00085
00086 }
00087
00088 void ClassicCommDetector::Init()
00089 {
00090 QSize video_disp_dim = nvp->GetVideoSize();
00091 width = video_disp_dim.width();
00092 height = video_disp_dim.height();
00093 fps = nvp->GetFrameRate();
00094
00095 preRoll = (long long)(max(0,recordingStartedAt.secsTo(startedAt)) * fps);
00096 postRoll = (long long)(max(0,stopsAt.secsTo(recordingStopsAt)) * fps);
00097
00098 #ifdef SHOW_DEBUG_WIN
00099 comm_debug_init(width, height);
00100 #endif
00101
00102 currentAspect = COMM_ASPECT_WIDE;
00103
00104 lastFrameNumber = -2;
00105 curFrameNumber = -1;
00106
00107 if (getenv("DEBUGCOMMFLAG"))
00108 verboseDebugging = true;
00109 else
00110 verboseDebugging = false;
00111
00112 VERBOSE(VB_COMMFLAG, "Commercial Detection initialized: width = " <<
00113 width << ", height = " << height << ", fps = " <<
00114 nvp->GetFrameRate() << ", method = " << commDetectMethod);
00115
00116 if ((width * height) > 1000000)
00117 {
00118 horizSpacing = 10;
00119 vertSpacing = 10;
00120 }
00121 else if ((width * height) > 800000)
00122 {
00123 horizSpacing = 8;
00124 vertSpacing = 8;
00125 }
00126 else if ((width * height) > 400000)
00127 {
00128 horizSpacing = 6;
00129 vertSpacing = 6;
00130 }
00131 else if ((width * height) > 300000)
00132 {
00133 horizSpacing = 6;
00134 vertSpacing = 4;
00135 }
00136 else
00137 {
00138 horizSpacing = 4;
00139 vertSpacing = 4;
00140 }
00141
00142 VERBOSE(VB_COMMFLAG,
00143 QString("Using Sample Spacing of %1 horizontal & %2 vertical "
00144 "pixels.").arg(horizSpacing).arg(vertSpacing));
00145
00146 framesProcessed = 0;
00147 totalMinBrightness = 0;
00148 blankFrameCount = 0;
00149
00150 aggressiveDetection = true;
00151 currentAspect = COMM_ASPECT_WIDE;
00152 decoderFoundAspectChanges = false;
00153
00154 lastSentCommBreakMap.clear();
00155 commBreakMapUpdateRequested = false;
00156 sendCommBreakMapUpdates = false;
00157
00158
00159 if (fabs(((width*1.0)/height) - 1.333333) < 0.1)
00160 currentAspect = COMM_ASPECT_NORMAL;
00161
00162 sceneChangeDetector = new ClassicSceneChangeDetector(width, height,
00163 commDetectBorder, horizSpacing, vertSpacing);
00164 connect(
00165 sceneChangeDetector,
00166 SIGNAL(haveNewInformation(unsigned int,bool,float)),
00167 this,
00168 SLOT(sceneChangeDetectorHasNewInformation(unsigned int,bool,float))
00169 );
00170
00171 frameIsBlank = false;
00172 stationLogoPresent = false;
00173
00174 framePtr = NULL;
00175
00176 logoInfoAvailable = false;
00177
00178 ClearAllMaps();
00179
00180 if (verboseDebugging)
00181 {
00182 VERBOSE(VB_COMMFLAG, " Fr # Min Max Avg Scn F A Mask");
00183 VERBOSE(VB_COMMFLAG, " ------ --- --- --- --- - - ----");
00184 }
00185 }
00186
00187 ClassicCommDetector::~ClassicCommDetector()
00188 {
00189 if (sceneChangeDetector)
00190 delete sceneChangeDetector;
00191
00192 if (logoDetector)
00193 delete logoDetector;
00194 }
00195
00196 bool ClassicCommDetector::go()
00197 {
00198 nvp->SetNullVideo();
00199
00200 int secsSince = 0;
00201 int requiredBuffer = 30;
00202 int requiredHeadStart = requiredBuffer;
00203 bool wereRecording = stillRecording;
00204
00205 emit statusUpdate("Building Head Start Buffer");
00206 secsSince = recordingStartedAt.secsTo(QDateTime::currentDateTime());
00207 while (stillRecording && (secsSince < requiredHeadStart))
00208 {
00209 emit breathe();
00210 if (m_bStop)
00211 return false;
00212
00213 sleep(2);
00214 secsSince = recordingStartedAt.secsTo(QDateTime::currentDateTime());
00215 }
00216
00217 if (nvp->OpenFile() < 0)
00218 return false;
00219
00220 Init();
00221
00222 if (commDetectMethod & COMM_DETECT_LOGO)
00223 {
00224 logoDetector = new ClassicLogoDetector(this, width, height,
00225 commDetectBorder, horizSpacing, vertSpacing);
00226
00227 requiredHeadStart += max(0,recordingStartedAt.secsTo(startedAt));
00228 requiredHeadStart += logoDetector->getRequiredAvailableBufferForSearch();
00229
00230 emit statusUpdate("Building Logo Detection Buffer");
00231 secsSince = recordingStartedAt.secsTo(QDateTime::currentDateTime());
00232 while (stillRecording && (secsSince < requiredHeadStart))
00233 {
00234 emit breathe();
00235 if (m_bStop)
00236 return false;
00237
00238 sleep(2);
00239 secsSince = recordingStartedAt.secsTo(QDateTime::currentDateTime());
00240 }
00241 }
00242
00243
00244 if ((wereRecording) && (!stillRecording) && (secsSince < requiredHeadStart))
00245 return false;
00246
00247 aggressiveDetection = gContext->GetNumSetting("AggressiveCommDetect", 1);
00248
00249 if (!nvp->InitVideo())
00250 {
00251 VERBOSE(VB_IMPORTANT,
00252 "NVP: Unable to initialize video for FlagCommercials.");
00253 return false;
00254 }
00255 nvp->SetCaptionsEnabled(false);
00256
00257 if (commDetectMethod & COMM_DETECT_LOGO)
00258 {
00259 emit statusUpdate("Searching for Logo");
00260
00261 if (showProgress)
00262 {
00263 cerr << "Finding Logo";
00264 cerr.flush();
00265 }
00266
00267 logoInfoAvailable = logoDetector->searchForLogo(nvp);
00268
00269 if (showProgress)
00270 {
00271 cerr << "\b\b\b\b\b\b\b\b\b\b\b\b "
00272 "\b\b\b\b\b\b\b\b\b\b\b\b";
00273 cerr.flush();
00274 }
00275 }
00276
00277 emit breathe();
00278 if (m_bStop)
00279 return false;
00280
00281 QTime flagTime;
00282 flagTime.start();
00283
00284 long long myTotalFrames;
00285 if (recordingStopsAt < QDateTime::currentDateTime() )
00286 myTotalFrames = nvp->GetTotalFrameCount();
00287 else
00288 myTotalFrames = (long long)(nvp->GetFrameRate() *
00289 (recordingStartedAt.secsTo(recordingStopsAt)));
00290
00291 if (showProgress)
00292 {
00293 if (myTotalFrames)
00294 cerr << " 0%/ ";
00295 else
00296 cerr << " 0/ ";
00297 cerr.flush();
00298 }
00299
00300
00301 float flagFPS;
00302 long long currentFrameNumber;
00303 float aspect = nvp->GetVideoAspect();
00304 float newAspect = aspect;
00305
00306 SetVideoParams(aspect);
00307
00308 emit breathe();
00309
00310 while (!nvp->GetEof())
00311 {
00312 struct timeval startTime;
00313 if (stillRecording)
00314 gettimeofday(&startTime, NULL);
00315
00316 VideoFrame* currentFrame = nvp->GetRawVideoFrame();
00317 currentFrameNumber = currentFrame->frameNumber;
00318
00319
00320
00321
00322
00323 newAspect = nvp->GetVideoAspect();
00324 if (newAspect != aspect)
00325 {
00326 SetVideoParams(aspect);
00327 aspect = newAspect;
00328 }
00329
00330 if (((currentFrameNumber % 500) == 0) ||
00331 (((currentFrameNumber % 100) == 0) &&
00332 (stillRecording)))
00333 {
00334 emit breathe();
00335 if (m_bStop)
00336 {
00337 nvp->DiscardVideoFrame(currentFrame);
00338 return false;
00339 }
00340 }
00341
00342 if ((sendCommBreakMapUpdates) &&
00343 ((commBreakMapUpdateRequested) ||
00344 ((currentFrameNumber % 500) == 0)))
00345 {
00346 QMap<long long,int> commBreakMap;
00347 QMap<long long, int>::Iterator it;
00348 QMap<long long, int>::Iterator lastIt;
00349 bool mapsAreIdentical = false;
00350
00351 getCommercialBreakList(commBreakMap);
00352
00353 if ((commBreakMap.size() == 0) &&
00354 (lastSentCommBreakMap.size() == 0))
00355 {
00356 mapsAreIdentical = true;
00357 }
00358 else if (commBreakMap.size() == lastSentCommBreakMap.size())
00359 {
00360
00361 mapsAreIdentical = true;
00362 for (it = commBreakMap.begin();
00363 it != commBreakMap.end() && mapsAreIdentical; ++it)
00364 {
00365 lastIt = lastSentCommBreakMap.find(it.key());
00366 if ((lastIt == lastSentCommBreakMap.end()) ||
00367 (lastIt.data() != it.data()))
00368 mapsAreIdentical = false;
00369 }
00370 }
00371
00372 if (commBreakMapUpdateRequested || !mapsAreIdentical)
00373 {
00374 emit gotNewCommercialBreakList();
00375 lastSentCommBreakMap = commBreakMap;
00376 }
00377
00378 if (commBreakMapUpdateRequested)
00379 commBreakMapUpdateRequested = false;
00380 }
00381
00382 while (m_bPaused)
00383 {
00384 emit breathe();
00385 sleep(1);
00386 }
00387
00388
00389 if (!fullSpeed && !stillRecording)
00390 usleep(10000);
00391
00392 if (((currentFrameNumber % 500) == 0) ||
00393 ((showProgress || stillRecording) &&
00394 ((currentFrameNumber % 100) == 0)))
00395 {
00396 float elapsed = flagTime.elapsed() / 1000.0;
00397
00398 if (elapsed)
00399 flagFPS = currentFrameNumber / elapsed;
00400 else
00401 flagFPS = 0.0;
00402
00403 int percentage;
00404 if (myTotalFrames)
00405 percentage = currentFrameNumber * 100 / myTotalFrames;
00406 else
00407 percentage = 0;
00408
00409 if (percentage > 100)
00410 percentage = 100;
00411
00412 if (showProgress)
00413 {
00414 if (myTotalFrames)
00415 {
00416 cerr << "\b\b\b\b\b\b\b\b\b\b\b"
00417 << QString::number(percentage).rightJustify(3, ' ')
00418 << "%/"
00419 << QString::number((int)flagFPS).rightJustify(3, ' ')
00420 << "fps";
00421 }
00422 else
00423 {
00424 cerr << "\b\b\b\b\b\b\b\b\b\b\b\b\b"
00425 << QString::number(currentFrameNumber)
00426 .rightJustify(6, ' ')
00427 << "/"
00428 << QString::number((int)flagFPS).rightJustify(3, ' ')
00429 << "fps";
00430 }
00431 cerr.flush();
00432 }
00433
00434 if (myTotalFrames)
00435 emit statusUpdate(QObject::tr("%1% Completed @ %2 fps.")
00436 .arg(percentage).arg(flagFPS));
00437 else
00438 emit statusUpdate(QObject::tr("%1 Frames Completed @ %2 fps.")
00439 .arg((long)currentFrameNumber).arg(flagFPS));
00440 }
00441
00442 ProcessFrame(currentFrame, currentFrameNumber);
00443
00444 if (stillRecording)
00445 {
00446 int secondsRecorded =
00447 recordingStartedAt.secsTo(QDateTime::currentDateTime());
00448 int secondsFlagged = (int)(framesProcessed / fps);
00449 int secondsBehind = secondsRecorded - secondsFlagged;
00450 long usecPerFrame = (long)(1.0 / nvp->GetFrameRate() * 1000000);
00451
00452 struct timeval endTime;
00453 gettimeofday(&endTime, NULL);
00454
00455 long long usecSleep =
00456 usecPerFrame -
00457 (((endTime.tv_sec - startTime.tv_sec) * 1000000) +
00458 (endTime.tv_usec - startTime.tv_usec));
00459
00460 if (secondsBehind > requiredBuffer)
00461 {
00462 if (fullSpeed)
00463 usecSleep = 0;
00464 else
00465 usecSleep = (long)(usecSleep * 0.25);
00466 }
00467 else if (secondsBehind < requiredBuffer)
00468 usecSleep = (long)(usecPerFrame * 1.5);
00469
00470 if (usecSleep > 0)
00471 usleep(usecSleep);
00472 }
00473
00474 nvp->DiscardVideoFrame(currentFrame);
00475 }
00476
00477 if (showProgress)
00478 {
00479 float elapsed = flagTime.elapsed() / 1000.0;
00480
00481 if (elapsed)
00482 flagFPS = currentFrameNumber / elapsed;
00483 else
00484 flagFPS = 0.0;
00485
00486 if (myTotalFrames)
00487 cerr << "\b\b\b\b\b\b \b\b\b\b\b\b";
00488 else
00489 cerr << "\b\b\b\b\b\b\b\b\b\b\b\b\b "
00490 "\b\b\b\b\b\b\b\b\b\b\b\b\b";
00491 cerr.flush();
00492 }
00493
00494 return true;
00495 }
00496
00497 void ClassicCommDetector::sceneChangeDetectorHasNewInformation(
00498 unsigned int framenum,bool isSceneChange,float debugValue)
00499 {
00500 if (isSceneChange)
00501 {
00502 frameInfo[framenum].flagMask |= COMM_FRAME_SCENE_CHANGE;
00503 sceneMap[framenum] = MARK_SCENE_CHANGE;
00504 }
00505 else
00506 {
00507 frameInfo[framenum].flagMask &= ~COMM_FRAME_SCENE_CHANGE;
00508 sceneMap.erase(framenum);
00509 }
00510
00511 frameInfo[framenum].sceneChangePercent = (int) (debugValue*100);
00512 }
00513
00514 void ClassicCommDetector::getCommercialBreakList(QMap<long long, int> &marks)
00515 {
00516
00517 VERBOSE(VB_COMMFLAG, "CommDetect::GetCommBreakMap()");
00518
00519 marks.clear();
00520
00521 CleanupFrameInfo();
00522
00523 switch (commDetectMethod)
00524 {
00525 case COMM_DETECT_OFF: return;
00526
00527 case COMM_DETECT_BLANKS: BuildBlankFrameCommList();
00528 marks = blankCommBreakMap;
00529 break;
00530
00531 case COMM_DETECT_SCENE: BuildSceneChangeCommList();
00532 marks = sceneCommBreakMap;
00533 break;
00534
00535 case COMM_DETECT_BLANK_SCENE: BuildBlankFrameCommList();
00536 BuildSceneChangeCommList();
00537 BuildMasterCommList();
00538 marks = commBreakMap;
00539 break;
00540
00541 case COMM_DETECT_LOGO: BuildLogoCommList();
00542 marks = logoCommBreakMap;
00543 break;
00544
00545 case COMM_DETECT_ALL: BuildAllMethodsCommList();
00546 marks = commBreakMap;
00547 break;
00548 default: VERBOSE(VB_COMMFLAG,
00549 QString("Unexpected commDetectMethod: %1")
00550 .arg(commDetectMethod));
00551 break;
00552 }
00553
00554 VERBOSE(VB_COMMFLAG, "Final Commercial Break Map" );
00555 }
00556
00557 void ClassicCommDetector::recordingFinished(long long totalFileSize)
00558 {
00559 (void)totalFileSize;
00560
00561 stillRecording = false;
00562 }
00563
00564 void ClassicCommDetector::requestCommBreakMapUpdate(void)
00565 {
00566 commBreakMapUpdateRequested = true;
00567 sendCommBreakMapUpdates = true;
00568 }
00569
00570 void ClassicCommDetector::SetVideoParams(float aspect)
00571 {
00572 int newAspect = COMM_ASPECT_WIDE;
00573
00574 VERBOSE(VB_COMMFLAG, QString("CommDetect::SetVideoParams called with "
00575 "aspect = %1").arg(aspect));
00576
00577
00578 if (fabs(aspect - 1.333333) < 0.1)
00579 newAspect = COMM_ASPECT_NORMAL;
00580
00581 if (newAspect != currentAspect)
00582 {
00583 VERBOSE(VB_COMMFLAG,
00584 QString("Aspect Ratio changed from %1 to %2 at frame %3")
00585 .arg(currentAspect).arg(newAspect)
00586 .arg((long)curFrameNumber));
00587
00588 if (frameInfo.contains(curFrameNumber))
00589 {
00590
00591
00592 frameInfo[curFrameNumber].flagMask |= COMM_FRAME_BLANK;
00593 frameInfo[curFrameNumber].flagMask |= COMM_FRAME_ASPECT_CHANGE;
00594 decoderFoundAspectChanges = true;
00595 }
00596 else if (curFrameNumber != -1)
00597 {
00598 VERBOSE(VB_COMMFLAG, QString("Unable to keep track of Aspect ratio "
00599 "change because frameInfo for frame "
00600 "number %1 does not exist.")
00601 .arg((long)curFrameNumber));
00602 }
00603 currentAspect = newAspect;
00604 }
00605 }
00606
00607 void ClassicCommDetector::ProcessFrame(VideoFrame *frame,
00608 long long frame_number)
00609 {
00610 int max = 0;
00611 int min = 255;
00612 int avg = 0;
00613 unsigned char pixel;
00614 int blankPixelsChecked = 0;
00615 long long totBrightness = 0;
00616 unsigned char rowMax[height];
00617 unsigned char colMax[width];
00618 int topDarkRow = commDetectBorder;
00619 int bottomDarkRow = height - commDetectBorder - 1;
00620 int leftDarkCol = commDetectBorder;
00621 int rightDarkCol = width - commDetectBorder - 1;
00622 FrameInfoEntry fInfo;
00623
00624 if (!frame || frame_number == -1 || frame->codec != FMT_YV12)
00625 {
00626 VERBOSE(VB_COMMFLAG, "CommDetect: Invalid video frame or codec, "
00627 "unable to process frame.");
00628 return;
00629 }
00630
00631 if (!width || !height)
00632 {
00633 VERBOSE(VB_COMMFLAG, "CommDetect: Width or Height is 0, "
00634 "unable to process frame.");
00635 return;
00636 }
00637
00638 curFrameNumber = frame_number;
00639 framePtr = frame->buf;
00640
00641 fInfo.minBrightness = -1;
00642 fInfo.maxBrightness = -1;
00643 fInfo.avgBrightness = -1;
00644 fInfo.sceneChangePercent = -1;
00645 fInfo.aspect = currentAspect;
00646 fInfo.format = COMM_FORMAT_NORMAL;
00647 fInfo.flagMask = 0;
00648
00649 int& flagMask = frameInfo[curFrameNumber].flagMask;
00650
00651
00652 if (lastFrameNumber != (curFrameNumber - 1))
00653 {
00654 if (lastFrameNumber > 0)
00655 {
00656 fInfo.aspect = frameInfo[lastFrameNumber].aspect;
00657 fInfo.format = frameInfo[lastFrameNumber].format;
00658 }
00659 fInfo.flagMask = COMM_FRAME_SKIPPED;
00660
00661 lastFrameNumber++;
00662 while(lastFrameNumber < curFrameNumber)
00663 frameInfo[lastFrameNumber++] = fInfo;
00664
00665 fInfo.flagMask = 0;
00666 }
00667 lastFrameNumber = curFrameNumber;
00668
00669 frameInfo[curFrameNumber] = fInfo;
00670
00671 if (commDetectMethod & COMM_DETECT_BLANKS)
00672 {
00673 memset(&rowMax, 0, sizeof(rowMax));
00674 memset(&colMax, 0, sizeof(colMax));
00675
00676 frameIsBlank = false;
00677 }
00678
00679 if (commDetectMethod & COMM_DETECT_SCENE)
00680 {
00681 sceneChangeDetector->processFrame(framePtr);
00682 }
00683
00684 stationLogoPresent = false;
00685
00686 for(int y = commDetectBorder; y < (height - commDetectBorder);
00687 y += vertSpacing)
00688 {
00689 for(int x = commDetectBorder; x < (width - commDetectBorder);
00690 x += horizSpacing)
00691 {
00692 pixel = framePtr[y * width + x];
00693
00694 if (commDetectMethod & COMM_DETECT_BLANKS)
00695 {
00696 bool checkPixel = false;
00697 if (!commDetectBlankCanHaveLogo)
00698 checkPixel = true;
00699
00700 if (!logoInfoAvailable)
00701 checkPixel = true;
00702 else if (!logoDetector->pixelInsideLogo(x,y))
00703 checkPixel=true;
00704
00705 if (checkPixel)
00706 {
00707 blankPixelsChecked++;
00708 totBrightness += pixel;
00709
00710 if (pixel < min)
00711 min = pixel;
00712
00713 if (pixel > max)
00714 max = pixel;
00715
00716 if (pixel > rowMax[y])
00717 rowMax[y] = pixel;
00718
00719 if (pixel > colMax[x])
00720 colMax[x] = pixel;
00721 }
00722 }
00723 }
00724 }
00725
00726 if (commDetectMethod & COMM_DETECT_BLANKS)
00727 {
00728 for(int y = commDetectBorder; y < (height - commDetectBorder);
00729 y += vertSpacing)
00730 {
00731 if (rowMax[y] > commDetectBoxBrightness)
00732 break;
00733 else
00734 topDarkRow = y;
00735 }
00736
00737 for(int y = commDetectBorder; y < (height - commDetectBorder);
00738 y += vertSpacing)
00739 if (rowMax[y] >= commDetectBoxBrightness)
00740 bottomDarkRow = y;
00741
00742 for(int x = commDetectBorder; x < (width - commDetectBorder);
00743 x += horizSpacing)
00744 {
00745 if (colMax[x] > commDetectBoxBrightness)
00746 break;
00747 else
00748 leftDarkCol = x;
00749 }
00750
00751 for(int x = commDetectBorder; x < (width - commDetectBorder);
00752 x += horizSpacing)
00753 if (colMax[x] >= commDetectBoxBrightness)
00754 rightDarkCol = x;
00755
00756 if ((topDarkRow > commDetectBorder) &&
00757 (topDarkRow < (height * .20)) &&
00758 (bottomDarkRow < (height - commDetectBorder)) &&
00759 (bottomDarkRow > (height * .80)))
00760 {
00761 frameInfo[curFrameNumber].format = COMM_FORMAT_LETTERBOX;
00762 }
00763 else if ((leftDarkCol > commDetectBorder) &&
00764 (leftDarkCol < (width * .20)) &&
00765 (rightDarkCol < (width - commDetectBorder)) &&
00766 (rightDarkCol > (width * .80)))
00767 {
00768 frameInfo[curFrameNumber].format = COMM_FORMAT_PILLARBOX;
00769 }
00770 else
00771 {
00772 frameInfo[curFrameNumber].format = COMM_FORMAT_NORMAL;
00773 }
00774
00775 avg = totBrightness / blankPixelsChecked;
00776
00777 frameInfo[curFrameNumber].minBrightness = min;
00778 frameInfo[curFrameNumber].maxBrightness = max;
00779 frameInfo[curFrameNumber].avgBrightness = avg;
00780
00781 totalMinBrightness += min;
00782 commDetectDimAverage = min + 10;
00783
00784
00785 if (((max - min) <= commDetectBlankFrameMaxDiff) &&
00786 (max < commDetectDimBrightness))
00787 frameIsBlank = true;
00788
00789
00790 if ((!aggressiveDetection) &&
00791 ((max - min) <= commDetectBlankFrameMaxDiff))
00792 frameIsBlank = true;
00793
00794
00795
00796 if ((!aggressiveDetection) &&
00797 ((max < commDetectDarkBrightness) ||
00798 ((max < commDetectDimBrightness) && (avg < commDetectDimAverage))))
00799 frameIsBlank = true;
00800 }
00801
00802 if ((logoInfoAvailable) && (commDetectMethod & COMM_DETECT_LOGO))
00803 {
00804 stationLogoPresent =
00805 logoDetector->doesThisFrameContainTheFoundLogo(framePtr);
00806 }
00807
00808 #if 0
00809 if ((commDetectMethod == COMM_DETECT_ALL) &&
00810 (CheckRatingSymbol()))
00811 {
00812 flagMask |= COMM_FRAME_RATING_SYMBOL;
00813 }
00814 #endif
00815
00816 if (frameIsBlank)
00817 {
00818 blankFrameMap[curFrameNumber] = MARK_BLANK_FRAME;
00819 flagMask |= COMM_FRAME_BLANK;
00820 blankFrameCount++;
00821 }
00822
00823 if (stationLogoPresent)
00824 flagMask |= COMM_FRAME_LOGO_PRESENT;
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834 if (verboseDebugging)
00835 VERBOSE(VB_COMMFLAG,
00836 QString().sprintf("Frame: %6ld -> %3d %3d %3d %3d %1d %1d %04x",
00837 (long)curFrameNumber,
00838 frameInfo[curFrameNumber].minBrightness,
00839 frameInfo[curFrameNumber].maxBrightness,
00840 frameInfo[curFrameNumber].avgBrightness,
00841 frameInfo[curFrameNumber].sceneChangePercent,
00842 frameInfo[curFrameNumber].format,
00843 frameInfo[curFrameNumber].aspect,
00844 frameInfo[curFrameNumber].flagMask ));
00845
00846 #ifdef SHOW_DEBUG_WIN
00847 comm_debug_show(frame->buf);
00848 getchar();
00849 #endif
00850
00851 framesProcessed++;
00852 }
00853
00854 void ClassicCommDetector::ClearAllMaps(void)
00855 {
00856 VERBOSE(VB_COMMFLAG, "CommDetect::ClearAllMaps()");
00857
00858 frameInfo.clear();
00859 blankFrameMap.clear();
00860 blankCommMap.clear();
00861 blankCommBreakMap.clear();
00862 sceneMap.clear();
00863 sceneCommBreakMap.clear();
00864 commBreakMap.clear();
00865 }
00866
00867 void ClassicCommDetector::GetBlankCommMap(QMap<long long, int> &comms)
00868 {
00869 VERBOSE(VB_COMMFLAG, "CommDetect::GetBlankCommMap()");
00870
00871 if (blankCommMap.isEmpty())
00872 BuildBlankFrameCommList();
00873
00874 comms = blankCommMap;
00875 }
00876
00877 void ClassicCommDetector::GetBlankCommBreakMap(QMap<long long, int> &comms)
00878 {
00879 VERBOSE(VB_COMMFLAG, "CommDetect::GetBlankCommBreakMap()");
00880
00881 if (blankCommBreakMap.isEmpty())
00882 BuildBlankFrameCommList();
00883
00884 comms = blankCommBreakMap;
00885 }
00886
00887 void ClassicCommDetector::GetSceneChangeMap(QMap<long long, int> &scenes,
00888 long long start_frame)
00889 {
00890 VERBOSE(VB_COMMFLAG, "CommDetect::GetSceneChangeMap()");
00891
00892 QMap<long long, int>::Iterator it;
00893
00894 if (start_frame == -1)
00895 scenes.clear();
00896
00897 for (it = sceneMap.begin(); it != sceneMap.end(); ++it)
00898 if ((start_frame == -1) || (it.key() >= start_frame))
00899 scenes[it.key()] = it.data();
00900 }
00901
00902 void ClassicCommDetector::BuildMasterCommList(void)
00903 {
00904 VERBOSE(VB_COMMFLAG, "CommDetect::BuildMasterCommList()");
00905
00906 if (blankCommBreakMap.size())
00907 {
00908 QMap<long long, int>::Iterator it;
00909
00910 for(it = blankCommBreakMap.begin(); it != blankCommBreakMap.end(); ++it)
00911 commBreakMap[it.key()] = it.data();
00912 }
00913
00914 if ((blankCommBreakMap.size() > 1) &&
00915 (sceneCommBreakMap.size() > 1))
00916 {
00917
00918 QMap<long long, int>::Iterator it_a;
00919 QMap<long long, int>::Iterator it_b;
00920
00921 it_a = blankCommBreakMap.begin();
00922 it_b = sceneCommBreakMap.begin();
00923
00924 if ((it_b.key() < 2) &&
00925 (it_a.key() > 2))
00926 {
00927 commBreakMap.erase(it_a.key());
00928 commBreakMap[0] = MARK_COMM_START;
00929 }
00930
00931
00932
00933 QMap<long long, int>::Iterator it;
00934 long long max_blank = 0;
00935 long long max_scene = 0;
00936
00937 it = blankCommBreakMap.begin();
00938 for(unsigned int i = 0; i < blankCommBreakMap.size(); i++)
00939 if ((it.data() == MARK_COMM_END) &&
00940 (it.key() > max_blank))
00941 max_blank = it.key();
00942
00943 it = sceneCommBreakMap.begin();
00944 for(unsigned int i = 0; i < sceneCommBreakMap.size(); i++)
00945 if ((it.data() == MARK_COMM_END) &&
00946 (it.key() > max_scene))
00947 max_scene = it.key();
00948
00949 if ((max_blank < (framesProcessed - 2)) &&
00950 (max_scene > (framesProcessed - 2)))
00951 {
00952 commBreakMap.erase(max_blank);
00953 commBreakMap[framesProcessed] = MARK_COMM_END;
00954 }
00955 }
00956
00957 if ((blankCommBreakMap.size() > 3) &&
00958 (sceneCommBreakMap.size() > 1))
00959 {
00960 QMap<long long, int>::Iterator it_a;
00961 QMap<long long, int>::Iterator it_b;
00962 long long b_start, b_end;
00963 long long s_start, s_end;
00964
00965 b_start = b_end = -1;
00966 s_start = s_end = -1;
00967
00968 it_a = blankCommBreakMap.begin();
00969 it_a++;
00970 it_b = it_a;
00971 it_b++;
00972 while(it_b != blankCommBreakMap.end())
00973 {
00974 long long fdiff = it_b.key() - it_a.key();
00975 bool allTrue = false;
00976
00977 if (fdiff < (62 * fps))
00978 {
00979 long long f = it_a.key() + 1;
00980
00981 allTrue = true;
00982
00983 while ((f <= framesProcessed) && (f < it_b.key()) && (allTrue))
00984 allTrue = FrameIsInBreakMap(f++, sceneCommBreakMap);
00985 }
00986
00987 if (allTrue)
00988 {
00989 commBreakMap.erase(it_a.key());
00990 commBreakMap.erase(it_b.key());
00991 }
00992
00993 it_a++; it_a++;
00994 it_b++;
00995 if (it_b != blankCommBreakMap.end())
00996 it_b++;
00997 }
00998 }
00999 }
01000
01001 void ClassicCommDetector::UpdateFrameBlock(FrameBlock *fbp,
01002 FrameInfoEntry finfo,
01003 int format, int aspect)
01004 {
01005 int value = 0;
01006
01007 value = finfo.flagMask;
01008
01009 if (value & COMM_FRAME_LOGO_PRESENT)
01010 fbp->logoCount++;
01011
01012 if (value & COMM_FRAME_RATING_SYMBOL)
01013 fbp->ratingCount++;
01014
01015 if (value & COMM_FRAME_SCENE_CHANGE)
01016 fbp->scCount++;
01017
01018 if (finfo.format == format)
01019 fbp->formatMatch++;
01020
01021 if (finfo.aspect == aspect)
01022 fbp->aspectMatch++;
01023 }
01024
01025
01026 void ClassicCommDetector::BuildAllMethodsCommList(void)
01027 {
01028 VERBOSE(VB_COMMFLAG, "CommDetect::BuildAllMethodsCommList()");
01029
01030 FrameBlock *fblock;
01031 FrameBlock *fbp;
01032 int value = 0;
01033 int curBlock = 0;
01034 int maxBlock = 0;
01035 int lastScore = 0;
01036 int thisScore = 0;
01037 int nextScore = 0;
01038 long curFrame = 0;
01039 long breakStart = 0;
01040 long lastStart = 0;
01041 long lastEnd = 0;
01042 long firstLogoFrame = -1;
01043 bool nextFrameIsBlank = false;
01044 bool lastFrameWasBlank = false;
01045 long formatFrames = 0;
01046 int format = COMM_FORMAT_NORMAL;
01047 long aspectFrames = 0;
01048 int aspect = COMM_ASPECT_NORMAL;
01049 QString msg;
01050 long long formatCounts[COMM_FORMAT_MAX];
01051 QMap<long long, int> tmpCommMap;
01052 QMap<long long, int>::Iterator it;
01053
01054 commBreakMap.clear();
01055
01056 fblock = new FrameBlock[blankFrameCount + 2];
01057
01058 curBlock = 0;
01059 curFrame = 1;
01060
01061 fbp = &fblock[curBlock];
01062 fbp->start = 0;
01063 fbp->bfCount = 0;
01064 fbp->logoCount = 0;
01065 fbp->ratingCount = 0;
01066 fbp->scCount = 0;
01067 fbp->scRate = 0.0;
01068 fbp->formatMatch = 0;
01069 fbp->aspectMatch = 0;
01070 fbp->score = 0;
01071
01072 lastFrameWasBlank = true;
01073
01074 if (decoderFoundAspectChanges)
01075 {
01076 for(long long i = preRoll; i < (framesProcessed - postRoll); i++ )
01077 {
01078 if ((frameInfo.contains(i)) &&
01079 (frameInfo[i].aspect == COMM_ASPECT_NORMAL))
01080 aspectFrames++;
01081 }
01082
01083 if (aspectFrames < ((framesProcessed - preRoll - postRoll) / 2))
01084 {
01085 aspect = COMM_ASPECT_WIDE;
01086 aspectFrames = framesProcessed - preRoll - postRoll - aspectFrames;
01087 }
01088 }
01089 else
01090 {
01091 memset(&formatCounts, 0, sizeof(formatCounts));
01092
01093 for(long long i = preRoll; i < (framesProcessed - postRoll); i++ )
01094 if ((frameInfo.contains(i)) &&
01095 (frameInfo[i].format >= 0) &&
01096 (frameInfo[i].format < COMM_FORMAT_MAX))
01097 formatCounts[frameInfo[i].format]++;
01098
01099 for(int i = 0; i < COMM_FORMAT_MAX; i++)
01100 {
01101 if (formatCounts[i] > formatFrames)
01102 {
01103 format = i;
01104 formatFrames = formatCounts[i];
01105 }
01106 }
01107 }
01108
01109 while (curFrame <= framesProcessed)
01110 {
01111 value = frameInfo[curFrame].flagMask;
01112
01113 if (((curFrame + 1) <= framesProcessed) &&
01114 (frameInfo[curFrame + 1].flagMask & COMM_FRAME_BLANK))
01115 nextFrameIsBlank = true;
01116 else
01117 nextFrameIsBlank = false;
01118
01119 if (value & COMM_FRAME_BLANK)
01120 {
01121 fbp->bfCount++;
01122
01123 if (!nextFrameIsBlank || !lastFrameWasBlank)
01124 {
01125 UpdateFrameBlock(fbp, frameInfo[curFrame], format, aspect);
01126
01127 fbp->end = curFrame;
01128 fbp->frames = fbp->end - fbp->start + 1;
01129 fbp->length = fbp->frames / fps;
01130
01131 if ((fbp->scCount) && (fbp->length > 1.05))
01132 fbp->scRate = fbp->scCount / fbp->length;
01133
01134 curBlock++;
01135
01136 fbp = &fblock[curBlock];
01137 fbp->bfCount = 1;
01138 fbp->logoCount = 0;
01139 fbp->ratingCount = 0;
01140 fbp->scCount = 0;
01141 fbp->scRate = 0.0;
01142 fbp->score = 0;
01143 fbp->formatMatch = 0;
01144 fbp->aspectMatch = 0;
01145 fbp->start = curFrame;
01146 }
01147
01148 lastFrameWasBlank = true;
01149 }
01150 else
01151 {
01152 lastFrameWasBlank = false;
01153 }
01154
01155 UpdateFrameBlock(fbp, frameInfo[curFrame], format, aspect);
01156
01157 if ((value & COMM_FRAME_LOGO_PRESENT) &&
01158 (firstLogoFrame == -1))
01159 firstLogoFrame = curFrame;
01160
01161 curFrame++;
01162 }
01163
01164 fbp->end = curFrame;
01165 fbp->frames = fbp->end - fbp->start + 1;
01166 fbp->length = fbp->frames / fps;
01167
01168 if ((fbp->scCount) && (fbp->length > 1.05))
01169 fbp->scRate = fbp->scCount / fbp->length;
01170
01171 maxBlock = curBlock;
01172 curBlock = 0;
01173 lastScore = 0;
01174
01175 VERBOSE(VB_COMMFLAG, "Initial Block pass");
01176 VERBOSE(VB_COMMFLAG, "Block StTime StFrm EndFrm Frames Secs "
01177 "Bf Lg Cnt RT Cnt SC Cnt SC Rt FmtMch AspMch Score");
01178 VERBOSE(VB_COMMFLAG, "----- ------ ------ ------ ------ ------- "
01179 "--- ------ ------ ------ ----- ------ ------ -----");
01180 while (curBlock <= maxBlock)
01181 {
01182 fbp = &fblock[curBlock];
01183
01184 msg.sprintf("%5d %3d:%02d %6ld %6ld %6ld %7.2f %3d %6d %6d %6d "
01185 "%5.2f %6d %6d %5d",
01186 curBlock, (int)(fbp->start / fps) / 60,
01187 (int)((fbp->start / fps )) % 60,
01188 fbp->start, fbp->end, fbp->frames, fbp->length,
01189 fbp->bfCount, fbp->logoCount, fbp->ratingCount,
01190 fbp->scCount, fbp->scRate, fbp->formatMatch,
01191 fbp->aspectMatch, fbp->score);
01192 VERBOSE(VB_COMMFLAG, msg);
01193
01194 if (fbp->frames > fps)
01195 {
01196 if (verboseDebugging)
01197 VERBOSE(VB_COMMFLAG, QString(" FRAMES > %1").arg(fps));
01198
01199 if (fbp->length > commDetectMaxCommLength)
01200 {
01201 if (verboseDebugging)
01202 VERBOSE(VB_COMMFLAG, " length > max comm length, +20");
01203 fbp->score += 20;
01204 }
01205
01206 if (fbp->length > commDetectMaxCommBreakLength)
01207 {
01208 if (verboseDebugging)
01209 VERBOSE(VB_COMMFLAG, " length > max comm break length,"
01210 " +20");
01211 fbp->score += 20;
01212 }
01213
01214 if ((fbp->length > 4) &&
01215 (fbp->logoCount > (fbp->frames * 0.60)) &&
01216 (fbp->bfCount < (fbp->frames * 0.10)))
01217 {
01218 if (verboseDebugging)
01219 VERBOSE(VB_COMMFLAG, " length > 4 && logoCount > "
01220 "frames * 0.60 && bfCount < frames "
01221 "* .10");
01222 if (fbp->length > commDetectMaxCommBreakLength)
01223 {
01224 if (verboseDebugging)
01225 VERBOSE(VB_COMMFLAG, " length > "
01226 "max comm break length, +20");
01227 fbp->score += 20;
01228 }
01229 else
01230 {
01231 if (verboseDebugging)
01232 VERBOSE(VB_COMMFLAG, " length <= "
01233 "max comm break length, +10");
01234 fbp->score += 10;
01235 }
01236 }
01237
01238 if ((logoInfoAvailable) &&
01239 (fbp->logoCount < (fbp->frames * 0.50)))
01240 {
01241 if (verboseDebugging)
01242 VERBOSE(VB_COMMFLAG, " logoInfoAvailable && logoCount"
01243 " < frames * .50, -10");
01244 fbp->score -= 10;
01245 }
01246
01247 if (fbp->ratingCount > (fbp->frames * 0.05))
01248 {
01249 if (verboseDebugging)
01250 VERBOSE(VB_COMMFLAG, " rating symbol present > 5% "
01251 "of time, +20");
01252 fbp->score += 20;
01253 }
01254
01255 if ((fbp->scRate > 1.0) &&
01256 (fbp->logoCount < (fbp->frames * .90)))
01257 {
01258 if (verboseDebugging)
01259 VERBOSE(VB_COMMFLAG, " scRate > 1.0, -10");
01260 fbp->score -= 10;
01261
01262 if (fbp->scRate > 2.0)
01263 {
01264 if (verboseDebugging)
01265 VERBOSE(VB_COMMFLAG, " scRate > 2.0, -10");
01266 fbp->score -= 10;
01267 }
01268 }
01269
01270 if ((!decoderFoundAspectChanges) &&
01271 (fbp->formatMatch < (fbp->frames * .10)))
01272 {
01273 if (verboseDebugging)
01274 VERBOSE(VB_COMMFLAG, " < 10% of frames match show "
01275 "letter/pillar-box format, -20");
01276 fbp->score -= 20;
01277 }
01278
01279 if ((abs((int)(fbp->frames - (15 * fps))) < 5 ) ||
01280 (abs((int)(fbp->frames - (30 * fps))) < 6 ) ||
01281 (abs((int)(fbp->frames - (60 * fps))) < 8 ))
01282 {
01283 if (verboseDebugging)
01284 VERBOSE(VB_COMMFLAG, " block appears to be standard "
01285 "comm length, -10");
01286 fbp->score -= 10;
01287 }
01288 }
01289 else
01290 {
01291 if (verboseDebugging)
01292 VERBOSE(VB_COMMFLAG, QString(" FRAMES <= %1").arg(fps));
01293
01294 if ((logoInfoAvailable) &&
01295 (fbp->start >= firstLogoFrame) &&
01296 (fbp->logoCount == 0))
01297 {
01298 if (verboseDebugging)
01299 VERBOSE(VB_COMMFLAG, " logoInfoAvailable && logoCount"
01300 " == 0, -10");
01301 fbp->score -= 10;
01302 }
01303
01304 if ((!decoderFoundAspectChanges) &&
01305 (fbp->formatMatch < (fbp->frames * .10)))
01306 {
01307 if (verboseDebugging)
01308 VERBOSE(VB_COMMFLAG, " < 10% of frames match show "
01309 "letter/pillar-box format, -10");
01310 fbp->score -= 10;
01311 }
01312
01313 if (fbp->ratingCount > (fbp->frames * 0.25))
01314 {
01315 if (verboseDebugging)
01316 VERBOSE(VB_COMMFLAG, " rating symbol present > 25% "
01317 "of time, +10");
01318 fbp->score += 10;
01319 }
01320 }
01321
01322 if ((decoderFoundAspectChanges) &&
01323 (fbp->aspectMatch < (fbp->frames * .10)))
01324 {
01325 if (verboseDebugging)
01326 VERBOSE(VB_COMMFLAG, " < 10% of frames match show "
01327 "aspect, -20");
01328 fbp->score -= 20;
01329 }
01330
01331 msg.sprintf(" NOW %3d:%02d %6ld %6ld %6ld %7.2f %3d %6d %6d %6d "
01332 "%5.2f %6d %6d %5d",
01333 (int)(fbp->start / fps) / 60,
01334 (int)((fbp->start / fps )) % 60,
01335 fbp->start, fbp->end, fbp->frames, fbp->length,
01336 fbp->bfCount, fbp->logoCount, fbp->ratingCount,
01337 fbp->scCount, fbp->scRate, fbp->formatMatch,
01338 fbp->aspectMatch, fbp->score);
01339 VERBOSE(VB_COMMFLAG, msg);
01340
01341 lastScore = fbp->score;
01342 curBlock++;
01343 }
01344
01345 curBlock = 0;
01346 lastScore = 0;
01347
01348 VERBOSE(VB_COMMFLAG, "============================================");
01349 VERBOSE(VB_COMMFLAG, "Second Block pass");
01350 VERBOSE(VB_COMMFLAG, "Block StTime StFrm EndFrm Frames Secs "
01351 "Bf Lg Cnt RT Cnt SC Cnt SC Rt FmtMch AspMch Score");
01352 VERBOSE(VB_COMMFLAG, "----- ------ ------ ------ ------ ------- "
01353 "--- ------ ------ ------ ----- ------ ------ -----");
01354 while (curBlock <= maxBlock)
01355 {
01356 fbp = &fblock[curBlock];
01357
01358 msg.sprintf("%5d %3d:%02d %6ld %6ld %6ld %7.2f %3d %6d %6d %6d "
01359 "%5.2f %6d %6d %5d",
01360 curBlock, (int)(fbp->start / fps) / 60,
01361 (int)((fbp->start / fps )) % 60,
01362 fbp->start, fbp->end, fbp->frames, fbp->length,
01363 fbp->bfCount, fbp->logoCount, fbp->ratingCount,
01364 fbp->scCount, fbp->scRate, fbp->formatMatch,
01365 fbp->aspectMatch, fbp->score);
01366 VERBOSE(VB_COMMFLAG, msg);
01367
01368 if ((curBlock > 0) && (curBlock < maxBlock))
01369 {
01370 nextScore = fblock[curBlock + 1].score;
01371
01372 if ((lastScore < 0) && (nextScore < 0) && (fbp->length < 35))
01373 {
01374 if (verboseDebugging)
01375 VERBOSE(VB_COMMFLAG, " lastScore < 0 && nextScore < 0 "
01376 "&& length < 35, setting -10");
01377 fbp->score -= 10;
01378 }
01379
01380 if ((fbp->bfCount > (fbp->frames * 0.95)) &&
01381 (fbp->frames < (2*fps)) &&
01382 (lastScore < 0 && nextScore < 0))
01383 {
01384 if (verboseDebugging)
01385 VERBOSE(VB_COMMFLAG, " blanks > frames * 0.95 && "
01386 "frames < 2*fps && lastScore < 0 && "
01387 "nextScore < 0, setting -10");
01388 fbp->score -= 10;
01389 }
01390
01391 if ((fbp->frames < (120*fps)) &&
01392 (lastScore < 0) &&
01393 (fbp->score > 0) &&
01394 (fbp->score < 20) &&
01395 (nextScore < 0))
01396 {
01397 if (verboseDebugging)
01398 VERBOSE(VB_COMMFLAG, " frames < 120 * fps && (-20 < "
01399 "lastScore < 0) && thisScore > 0 && "
01400 "nextScore < 0, setting score = -10");
01401 fbp->score = -10;
01402 }
01403
01404 if ((fbp->frames < (30*fps)) &&
01405 (lastScore > 0) &&
01406 (fbp->score < 0) &&
01407 (fbp->score > -20) &&
01408 (nextScore > 0))
01409 {
01410 if (verboseDebugging)
01411 VERBOSE(VB_COMMFLAG, " frames < 30 * fps && (0 < "
01412 "lastScore < 20) && thisScore < 0 && "
01413 "nextScore > 0, setting score = 10");
01414 fbp->score = 10;
01415 }
01416 }
01417
01418 if ((fbp->score == 0) && (lastScore > 30))
01419 {
01420 int offset = 1;
01421 while(((curBlock + offset) <= maxBlock) &&
01422 (fblock[curBlock + offset].frames < (2 * fps)) &&
01423 (fblock[curBlock + offset].score == 0))
01424 offset++;
01425
01426 if ((curBlock + offset) <= maxBlock)
01427 {
01428 offset--;
01429 if (fblock[curBlock + offset + 1].score > 0)
01430 {
01431 for (; offset >= 0; offset--)
01432 {
01433 fblock[curBlock + offset].score += 10;
01434 if (verboseDebugging)
01435 VERBOSE(VB_COMMFLAG, QString(" Setting block "
01436 "%1 score +10")
01437 .arg(curBlock+offset));
01438 }
01439 }
01440 else if (fblock[curBlock + offset + 1].score < 0)
01441 {
01442 for (; offset >= 0; offset--)
01443 {
01444 fblock[curBlock + offset].score -= 10;
01445 if (verboseDebugging)
01446 VERBOSE(VB_COMMFLAG, QString(" Setting block "
01447 "%1 score -10")
01448 .arg(curBlock+offset));
01449 }
01450 }
01451 }
01452 }
01453
01454 msg.sprintf(" NOW %3d:%02d %6ld %6ld %6ld %7.2f %3d %6d %6d %6d "
01455 "%5.2f %6d %6d %5d",
01456 (int)(fbp->start / fps) / 60,
01457 (int)((fbp->start / fps )) % 60,
01458 fbp->start, fbp->end, fbp->frames, fbp->length,
01459 fbp->bfCount, fbp->logoCount, fbp->ratingCount,
01460 fbp->scCount, fbp->scRate, fbp->formatMatch,
01461 fbp->aspectMatch, fbp->score);
01462 VERBOSE(VB_COMMFLAG, msg);
01463
01464 lastScore = fbp->score;
01465 curBlock++;
01466 }
01467
01468 VERBOSE(VB_COMMFLAG, "============================================");
01469 VERBOSE(VB_COMMFLAG, "FINAL Block stats");
01470 VERBOSE(VB_COMMFLAG, "Block StTime StFrm EndFrm Frames Secs "
01471 "Bf Lg Cnt RT Cnt SC Cnt SC Rt FmtMch AspMch Score");
01472 VERBOSE(VB_COMMFLAG, "----- ------ ------ ------ ------ ------- "
01473 "--- ------ ------ ------ ----- ------ ------ -----");
01474 curBlock = 0;
01475 lastScore = 0;
01476 breakStart = -1;
01477 while (curBlock <= maxBlock)
01478 {
01479 fbp = &fblock[curBlock];
01480 thisScore = fbp->score;
01481
01482 if ((breakStart >= 0) &&
01483 ((fbp->end - breakStart) > (commDetectMaxCommBreakLength * fps)))
01484 {
01485 if (((fbp->start - breakStart) >
01486 (commDetectMinCommBreakLength * fps)) ||
01487 (breakStart == 0))
01488 {
01489 if (verboseDebugging)
01490 VERBOSE(VB_COMMFLAG,
01491 QString("Closing commercial block at start of "
01492 "frame block %1 with length %2, frame "
01493 "block length of %3 frames would put comm "
01494 "block length over max of %4 seconds.")
01495 .arg(curBlock).arg(fbp->start - breakStart)
01496 .arg(fbp->frames)
01497 .arg(commDetectMaxCommBreakLength));
01498
01499 commBreakMap[breakStart] = MARK_COMM_START;
01500 commBreakMap[fbp->start] = MARK_COMM_END;
01501 lastStart = breakStart;
01502 lastEnd = fbp->start;
01503 breakStart = -1;
01504 }
01505 else
01506 {
01507 if (verboseDebugging)
01508 VERBOSE(VB_COMMFLAG,
01509 QString("Ignoring what appears to be commercial"
01510 " block at frame %1 with length %2, "
01511 "length of %3 frames would put comm "
01512 "block length under min of %4 seconds.")
01513 .arg((long)breakStart)
01514 .arg(fbp->start - breakStart)
01515 .arg(fbp->frames)
01516 .arg(commDetectMinCommBreakLength));
01517 breakStart = -1;
01518 }
01519 }
01520 if (thisScore == 0)
01521 {
01522 thisScore = lastScore;
01523 }
01524 else if (thisScore < 0)
01525 {
01526 if ((lastScore > 0) || (curBlock == 0))
01527 {
01528 if ((fbp->start - lastEnd) < (commDetectMinShowLength * fps))
01529 {
01530 commBreakMap.erase(lastStart);
01531 commBreakMap.erase(lastEnd);
01532 breakStart = lastStart;
01533
01534 if (verboseDebugging)
01535 {
01536 if (breakStart)
01537 VERBOSE(VB_COMMFLAG,
01538 QString("ReOpening commercial block at "
01539 "frame %1 because show less than "
01540 "%2 seconds")
01541 .arg(breakStart)
01542 .arg(commDetectMinShowLength));
01543 else
01544 VERBOSE(VB_COMMFLAG,
01545 QString("Opening initial commercial block "
01546 "at start of recording, block 0."));
01547 }
01548 }
01549 else
01550 {
01551 breakStart = fbp->start;
01552
01553 if (verboseDebugging)
01554 VERBOSE(VB_COMMFLAG,
01555 QString("Starting new commercial block at "
01556 "frame %1 from start of frame block %2")
01557 .arg(fbp->start).arg(curBlock));
01558 }
01559 }
01560 else if (curBlock == maxBlock)
01561 {
01562 if ((fbp->end - breakStart) >
01563 (commDetectMinCommBreakLength * fps))
01564 {
01565 if (fbp->end <= (framesProcessed - (int)(2 * fps) - 2))
01566 {
01567 if (verboseDebugging)
01568 VERBOSE(VB_COMMFLAG,
01569 QString("Closing final commercial block at "
01570 "frame %1").arg(fbp->end));
01571
01572 commBreakMap[breakStart] = MARK_COMM_START;
01573 commBreakMap[fbp->end] = MARK_COMM_END;
01574 lastStart = breakStart;
01575 lastEnd = fbp->end;
01576 breakStart = -1;
01577 }
01578 }
01579 else
01580 {
01581 if (verboseDebugging)
01582 VERBOSE(VB_COMMFLAG,
01583 QString("Ignoring what appears to be commercial"
01584 " block at frame %1 with length %2, "
01585 "length of %3 frames would put comm "
01586 "block length under min of %4 seconds.")
01587 .arg((long)breakStart)
01588 .arg(fbp->start - breakStart)
01589 .arg(fbp->frames)
01590 .arg(commDetectMinCommBreakLength));
01591 breakStart = -1;
01592 }
01593 }
01594 }
01595 else if ((thisScore > 0) &&
01596 (lastScore < 0) &&
01597 (breakStart != -1))
01598 {
01599 if (((fbp->start - breakStart) >
01600 (commDetectMinCommBreakLength * fps)) ||
01601 (breakStart == 0))
01602 {
01603 commBreakMap[breakStart] = MARK_COMM_START;
01604 commBreakMap[fbp->start] = MARK_COMM_END;
01605 lastStart = breakStart;
01606 lastEnd = fbp->start;
01607
01608 if (verboseDebugging)
01609 VERBOSE(VB_COMMFLAG,
01610 QString("Closing commercial block at frame %1")
01611 .arg(fbp->start));
01612 }
01613 else
01614 {
01615 if (verboseDebugging)
01616 VERBOSE(VB_COMMFLAG,
01617 QString("Ignoring what appears to be commercial "
01618 "block at frame %1 with length %2, "
01619 "length of %3 frames would put comm block "
01620 "length under min of %4 seconds.")
01621 .arg((long)breakStart)
01622 .arg(fbp->start - breakStart)
01623 .arg(fbp->frames)
01624 .arg(commDetectMinCommBreakLength));
01625 }
01626 breakStart = -1;
01627 }
01628
01629 msg.sprintf("%5d %3d:%02d %6ld %6ld %6ld %7.2f %3d %6d %6d %6d "
01630 "%5.2f %6d %6d %5d",
01631 curBlock, (int)(fbp->start / fps) / 60,
01632 (int)((fbp->start / fps )) % 60,
01633 fbp->start, fbp->end, fbp->frames, fbp->length,
01634 fbp->bfCount, fbp->logoCount, fbp->ratingCount,
01635 fbp->scCount, fbp->scRate, fbp->formatMatch,
01636 fbp->aspectMatch, thisScore);
01637 VERBOSE(VB_COMMFLAG, msg);
01638
01639 lastScore = thisScore;
01640 curBlock++;
01641 }
01642
01643 if ((breakStart != -1) &&
01644 (breakStart <= (framesProcessed - (int)(2 * fps) - 2)))
01645 {
01646 if (verboseDebugging)
01647 VERBOSE(VB_COMMFLAG,
01648 QString("Closing final commercial block started at "
01649 "block %1 and going to end of program. length "
01650 "is %2 frames")
01651 .arg(curBlock)
01652 .arg((long)(framesProcessed - breakStart - 1)));
01653
01654 commBreakMap[breakStart] = MARK_COMM_START;
01655 commBreakMap[framesProcessed - (int)(2 * fps) - 2] = MARK_COMM_END;
01656 }
01657
01658
01659 tmpCommMap = commBreakMap;
01660 commBreakMap.clear();
01661
01662 if (verboseDebugging)
01663 VERBOSE(VB_COMMFLAG, "Adjusting start/end marks according to blanks.");
01664 for (it = tmpCommMap.begin(); it != tmpCommMap.end(); ++it)
01665 {
01666 if (it.data() == MARK_COMM_START)
01667 {
01668 lastStart = it.key();
01669 if (skipAllBlanks)
01670 {
01671 while ((lastStart > 0) &&
01672 (frameInfo[lastStart - 1].flagMask & COMM_FRAME_BLANK))
01673 lastStart--;
01674 }
01675 else
01676 {
01677 while ((lastStart < (framesProcessed - (2 * fps))) &&
01678 (frameInfo[lastStart + 1].flagMask & COMM_FRAME_BLANK))
01679 lastStart++;
01680 }
01681
01682 if (verboseDebugging)
01683 VERBOSE(VB_COMMFLAG, QString("Start Mark: %1 -> %2")
01684 .arg((long)it.key())
01685 .arg((long)lastStart));
01686
01687 commBreakMap[lastStart] = MARK_COMM_START;
01688 }
01689 else
01690 {
01691 lastEnd = it.key();
01692 if (skipAllBlanks)
01693 {
01694 while ((lastEnd < (framesProcessed - (2 * fps))) &&
01695 (frameInfo[lastEnd + 1].flagMask & COMM_FRAME_BLANK))
01696 lastEnd++;
01697 }
01698 else
01699 {
01700 while ((lastEnd > 0) &&
01701 (frameInfo[lastEnd - 1].flagMask & COMM_FRAME_BLANK))
01702 lastEnd--;
01703 }
01704
01705 if (verboseDebugging)
01706 VERBOSE(VB_COMMFLAG, QString("End Mark : %1 -> %2")
01707 .arg((long)it.key())
01708 .arg((long)lastEnd));
01709
01710 commBreakMap[lastEnd] = MARK_COMM_END;
01711 }
01712 }
01713
01714 delete [] fblock;
01715 }
01716
01717
01718 void ClassicCommDetector::BuildBlankFrameCommList(void)
01719 {
01720 VERBOSE(VB_COMMFLAG, "CommDetect::BuildBlankFrameCommList()");
01721
01722 long long bframes[blankFrameMap.count()*2];
01723 long long c_start[blankFrameMap.count()];
01724 long long c_end[blankFrameMap.count()];
01725 int frames = 0;
01726 int commercials = 0;
01727 int i, x;
01728 QMap<long long, int>::Iterator it;
01729
01730 blankCommMap.clear();
01731
01732 for (it = blankFrameMap.begin(); it != blankFrameMap.end(); ++it)
01733 bframes[frames++] = it.key();
01734
01735 if (frames == 0)
01736 return;
01737
01738
01739
01740
01741 for(i = 0; i < frames; i++ )
01742 {
01743 for(x=i+1; x < frames; x++ )
01744 {
01745
01746
01747
01748 int gap_length = bframes[x] - bframes[i];
01749 if (((aggressiveDetection) &&
01750 ((abs((int)(gap_length - (5 * fps))) < 5 ) ||
01751 (abs((int)(gap_length - (10 * fps))) < 7 ) ||
01752 (abs((int)(gap_length - (15 * fps))) < 10 ) ||
01753 (abs((int)(gap_length - (20 * fps))) < 11 ) ||
01754 (abs((int)(gap_length - (30 * fps))) < 12 ) ||
01755 (abs((int)(gap_length - (40 * fps))) < 1 ) ||
01756 (abs((int)(gap_length - (45 * fps))) < 1 ) ||
01757 (abs((int)(gap_length - (60 * fps))) < 15 ) ||
01758 (abs((int)(gap_length - (90 * fps))) < 10 ) ||
01759 (abs((int)(gap_length - (120 * fps))) < 10 ))) ||
01760 ((!aggressiveDetection) &&
01761 ((abs((int)(gap_length - (5 * fps))) < 11 ) ||
01762 (abs((int)(gap_length - (10 * fps))) < 13 ) ||
01763 (abs((int)(gap_length - (15 * fps))) < 16 ) ||
01764 (abs((int)(gap_length - (20 * fps))) < 17 ) ||
01765 (abs((int)(gap_length - (30 * fps))) < 18 ) ||
01766 (abs((int)(gap_length - (40 * fps))) < 3 ) ||
01767 (abs((int)(gap_length - (45 * fps))) < 3 ) ||
01768 (abs((int)(gap_length - (60 * fps))) < 20 ) ||
01769 (abs((int)(gap_length - (90 * fps))) < 20 ) ||
01770 (abs((int)(gap_length - (120 * fps))) < 20 ))))
01771 {
01772 c_start[commercials] = bframes[i];
01773 c_end[commercials] = bframes[x] - 1;
01774 commercials++;
01775 i = x-1;
01776 x = frames;
01777 }
01778
01779 if ((!aggressiveDetection) &&
01780 ((abs((int)(gap_length - (30 * fps))) < (int)(fps * 0.85)) ||
01781 (abs((int)(gap_length - (60 * fps))) < (int)(fps * 0.95)) ||
01782 (abs((int)(gap_length - (90 * fps))) < (int)(fps * 1.05)) ||
01783 (abs((int)(gap_length - (120 * fps))) < (int)(fps * 1.15))) &&
01784 ((x + 2) < frames) &&
01785 ((i + 2) < frames) &&
01786 ((bframes[i] + 1) == bframes[i+1]) &&
01787 ((bframes[x] + 1) == bframes[x+1]))
01788 {
01789 c_start[commercials] = bframes[i];
01790 c_end[commercials] = bframes[x];
01791 commercials++;
01792 i = x;
01793 x = frames;
01794 }
01795 }
01796 }
01797
01798 i = 0;
01799
01800
01801
01802 if ((commercials > 1) &&
01803 (c_end[0] < (33 * fps)) &&
01804 (c_start[1] > (c_end[0] + 40 * fps)))
01805 i = 1;
01806
01807
01808 bool first_comm = true;
01809 for(; i < (commercials-1); i++)
01810 {
01811 long long r = c_start[i];
01812
01813 if ((r < (30 * fps)) &&
01814 (first_comm))
01815 r = 1;
01816
01817 blankCommMap[r] = MARK_COMM_START;
01818
01819 r = c_end[i];
01820 if ( i < (commercials-1))
01821 {
01822 for(x = 0; x < (frames-1); x++)
01823 if (bframes[x] == r)
01824 break;
01825 while((x < (frames-1)) &&
01826 ((bframes[x] + 1 ) == bframes[x+1]) &&
01827 (bframes[x+1] < c_start[i+1]))
01828 {
01829 r++;
01830 x++;
01831 }
01832
01833 if (skipAllBlanks)
01834 while((blankFrameMap.contains(r+1)) &&
01835 (c_start[i+1] != (r+1)))
01836 r++;
01837 }
01838 else
01839 {
01840 if (skipAllBlanks)
01841 while(blankFrameMap.contains(r+1))
01842 r++;
01843 }
01844
01845 blankCommMap[r] = MARK_COMM_END;
01846 first_comm = false;
01847 }
01848
01849 blankCommMap[c_start[i]] = MARK_COMM_START;
01850 blankCommMap[c_end[i]] = MARK_COMM_END;
01851
01852 VERBOSE(VB_COMMFLAG, "Blank-Frame Commercial Map" );
01853 for(it = blankCommMap.begin(); it != blankCommMap.end(); ++it)
01854 VERBOSE(VB_COMMFLAG, QString(" %1:%2")
01855 .arg((long int)it.key()).arg(it.data()));
01856
01857 MergeBlankCommList();
01858
01859 VERBOSE(VB_COMMFLAG, "Merged Blank-Frame Commercial Break Map" );
01860 for(it = blankCommBreakMap.begin(); it != blankCommBreakMap.end(); ++it)
01861 VERBOSE(VB_COMMFLAG, QString(" %1:%2")
01862 .arg((long int)it.key()).arg(it.data()));
01863 }
01864
01865
01866 void ClassicCommDetector::BuildSceneChangeCommList(void)
01867 {
01868 int section_start = -1;
01869 int seconds = (int)(framesProcessed / fps);
01870 int sc_histogram[seconds+1];
01871
01872 sceneCommBreakMap.clear();
01873
01874 memset(sc_histogram, 0, sizeof(sc_histogram));
01875 for(long long f = 1; f <= framesProcessed; f++)
01876 {
01877 if (sceneMap.contains(f))
01878 sc_histogram[(int)(f / fps)]++;
01879 }
01880
01881 for(long long s = 0; s < (seconds + 1); s++)
01882 {
01883 if (sc_histogram[s] > 2)
01884 {
01885 if (section_start == -1)
01886 {
01887 long long f = (long long)(s * fps);
01888 for(int i = 0; i < fps; i++, f++)
01889 {
01890 if (sceneMap.contains(f))
01891 {
01892 sceneCommBreakMap[f] = MARK_COMM_START;
01893 i = (int)(fps) + 1;
01894 }
01895 }
01896 }
01897
01898 section_start = s;
01899 }
01900
01901 if ((section_start >= 0) &&
01902 (s > (section_start + 32)))
01903 {
01904 long long f = (long long)(section_start * fps);
01905 bool found_end = false;
01906
01907 for(int i = 0; i < fps; i++, f++)
01908 {
01909 if (sceneMap.contains(f))
01910 {
01911 if (sceneCommBreakMap.contains(f))
01912 sceneCommBreakMap.erase(f);
01913 else
01914 sceneCommBreakMap[f] = MARK_COMM_END;
01915 i = (int)(fps) + 1;
01916 found_end = true;
01917 }
01918 }
01919 section_start = -1;
01920
01921 if (!found_end)
01922 {
01923 f = (long long)(section_start * fps);
01924 sceneCommBreakMap[f] = MARK_COMM_END;
01925 }
01926 }
01927 }
01928
01929 if (section_start >= 0)
01930 sceneCommBreakMap[framesProcessed] = MARK_COMM_END;
01931
01932 QMap<long long, int>::Iterator it;
01933 QMap<long long, int>::Iterator prev;
01934 QMap<long long, int> deleteMap;
01935
01936 it = sceneCommBreakMap.begin();
01937 prev = it;
01938 if (it != sceneCommBreakMap.end())
01939 {
01940 it++;
01941 while (it != sceneCommBreakMap.end())
01942 {
01943 if ((it.data() == MARK_COMM_END) &&
01944 (it.key() - prev.key()) < (30 * fps))
01945 {
01946 deleteMap[it.key()] = 1;
01947 deleteMap[prev.key()] = 1;
01948 }
01949 prev++;
01950 if (it != sceneCommBreakMap.end())
01951 it++;
01952 }
01953
01954 for (it = deleteMap.begin(); it != deleteMap.end(); ++it)
01955 sceneCommBreakMap.erase(it.key());
01956 }
01957
01958 VERBOSE(VB_COMMFLAG, "Scene-Change Commercial Break Map" );
01959 for(it = sceneCommBreakMap.begin(); it != sceneCommBreakMap.end(); ++it)
01960 VERBOSE(VB_COMMFLAG, QString(" %1:%2")
01961 .arg((long int)it.key()).arg(it.data()));
01962 }
01963
01964
01965 void ClassicCommDetector::BuildLogoCommList()
01966 {
01967 GetLogoCommBreakMap(logoCommBreakMap);
01968 CondenseMarkMap(logoCommBreakMap, (int)(25 * fps), (int)(30 * fps));
01969 ConvertShowMapToCommMap(logoCommBreakMap);
01970
01971 QMap<long long, int>::Iterator it;
01972 VERBOSE(VB_COMMFLAG, "Logo Commercial Break Map" );
01973 for(it = logoCommBreakMap.begin(); it != logoCommBreakMap.end(); ++it)
01974 VERBOSE(VB_COMMFLAG, QString(" %1:%2")
01975 .arg((long int)it.key()).arg(it.data()));
01976 }
01977
01978 void ClassicCommDetector::MergeBlankCommList(void)
01979 {
01980 QMap<long long, int>::Iterator it;
01981 QMap<long long, int>::Iterator prev;
01982 QMap<long long, long long> tmpMap;
01983 QMap<long long, long long>::Iterator tmpMap_it;
01984 QMap<long long, long long>::Iterator tmpMap_prev;
01985
01986 blankCommBreakMap.clear();
01987
01988 if (blankCommMap.isEmpty())
01989 return;
01990
01991 for (it = blankCommMap.begin(); it != blankCommMap.end(); ++it)
01992 blankCommBreakMap[it.key()] = it.data();
01993
01994 if (blankCommBreakMap.isEmpty())
01995 return;
01996
01997 it = blankCommMap.begin();
01998 prev = it;
01999 it++;
02000 for(; it != blankCommMap.end(); ++it, ++prev)
02001 {
02002
02003 if ((((prev.key() + 1) == it.key()) ||
02004 ((prev.key() + (15 * fps)) > it.key())) &&
02005 (prev.data() == MARK_COMM_END) &&
02006 (it.data() == MARK_COMM_START))
02007 {
02008 blankCommBreakMap.erase(prev.key());
02009 blankCommBreakMap.erase(it.key());
02010 }
02011 }
02012
02013
02014
02015 it = blankCommBreakMap.begin();
02016 prev = it;
02017 it++;
02018 tmpMap[prev.key()] = it.key();
02019 for(; it != blankCommBreakMap.end(); ++it, ++prev)
02020 {
02021 if ((prev.data() == MARK_COMM_START) &&
02022 (it.data() == MARK_COMM_END))
02023 tmpMap[prev.key()] = it.key();
02024 }
02025
02026 tmpMap_it = tmpMap.begin();
02027 tmpMap_prev = tmpMap_it;
02028 tmpMap_it++;
02029 for(; tmpMap_it != tmpMap.end(); ++tmpMap_it, ++tmpMap_prev)
02030 {
02031
02032
02033 if (((tmpMap_prev.data() + (35 * fps)) > tmpMap_it.key()) &&
02034 ((tmpMap_prev.data() - tmpMap_prev.key()) > (35 * fps)) &&
02035 ((tmpMap_it.data() - tmpMap_it.key()) > (35 * fps)))
02036 {
02037 blankCommBreakMap.erase(tmpMap_prev.data());
02038 blankCommBreakMap.erase(tmpMap_it.key());
02039 }
02040 }
02041 }
02042
02043 bool ClassicCommDetector::FrameIsInBreakMap(long long f,
02044 QMap<long long, int> &breakMap)
02045 {
02046 for(long long i = f; i < framesProcessed; i++)
02047 if (breakMap.contains(i))
02048 {
02049 int type = breakMap[i];
02050 if ((type == MARK_COMM_END) || (i == f))
02051 return true;
02052 if (type == MARK_COMM_START)
02053 return false;
02054 }
02055
02056 for(long long i = f; i >= 0; i--)
02057 if (breakMap.contains(i))
02058 {
02059 int type = breakMap[i];
02060 if ((type == MARK_COMM_START) || (i == f))
02061 return true;
02062 if (type == MARK_COMM_END)
02063 return false;
02064 }
02065
02066 return false;
02067 }
02068
02069 void ClassicCommDetector::DumpMap(QMap<long long, int> &map)
02070 {
02071 QMap<long long, int>::Iterator it;
02072 QString msg;
02073
02074 VERBOSE(VB_COMMFLAG, "---------------------------------------------------");
02075 for (it = map.begin(); it != map.end(); ++it)
02076 {
02077 long long frame = it.key();
02078 int flag = it.data();
02079 int my_fps = (int)ceil(fps);
02080 int hour = (frame / my_fps) / 60 / 60;
02081 int min = (frame / my_fps) / 60 - (hour * 60);
02082 int sec = (frame / my_fps) - (min * 60) - (hour * 60 * 60);
02083 int frm = frame - ((sec * my_fps) + (min * 60 * my_fps) +
02084 (hour * 60 * 60 * my_fps));
02085 int my_sec = (int)(frame / my_fps);
02086 msg.sprintf("%7ld : %d (%02d:%02d:%02d.%02d) (%d)",
02087 (long)frame, flag, hour, min, sec, frm, my_sec);
02088 VERBOSE(VB_COMMFLAG, msg);
02089 }
02090 VERBOSE(VB_COMMFLAG, "---------------------------------------------------");
02091 }
02092
02093 void ClassicCommDetector::CondenseMarkMap(QMap<long long, int>&map, int spacing,
02094 int length)
02095 {
02096 QMap<long long, int>::Iterator it;
02097 QMap<long long, int>::Iterator prev;
02098 QMap<long long, int>tmpMap;
02099
02100 if (map.size() <= 2)
02101 return;
02102
02103
02104 VERBOSE(VB_COMMFLAG, "Commercial Map Before condense:" );
02105 for (it = map.begin(); it != map.end(); it++)
02106 {
02107 VERBOSE(VB_COMMFLAG, QString(" %1:%2")
02108 .arg((long int)it.key()).arg(it.data()));
02109 tmpMap[it.key()] = it.data();
02110 }
02111
02112 prev = tmpMap.begin();
02113 it = prev;
02114 it++;
02115 while(it != tmpMap.end())
02116 {
02117 if ((it.data() == MARK_START) &&
02118 (prev.data() == MARK_END) &&
02119 ((it.key() - prev.key()) < spacing))
02120 {
02121 map.erase(prev.key());
02122 map.erase(it.key());
02123 }
02124 prev++;
02125 it++;
02126 }
02127
02128 if (map.size() == 0)
02129 return;
02130
02131
02132 tmpMap.clear();
02133 for (it = map.begin(); it != map.end(); it++)
02134 tmpMap[it.key()] = it.data();
02135
02136 prev = tmpMap.begin();
02137 it = prev;
02138 it++;
02139 while(it != tmpMap.end())
02140 {
02141 if ((prev.data() == MARK_START) &&
02142 (it.data() == MARK_END) &&
02143 ((it.key() - prev.key()) < length))
02144 {
02145 map.erase(prev.key());
02146 map.erase(it.key());
02147 }
02148 prev++;
02149 it++;
02150 }
02151
02152 VERBOSE(VB_COMMFLAG, "Commercial Map After condense:" );
02153 for (it = map.begin(); it != map.end(); it++)
02154 VERBOSE(VB_COMMFLAG, QString(" %1:%2")
02155 .arg((long int)it.key()).arg(it.data()));
02156 }
02157
02158 void ClassicCommDetector::ConvertShowMapToCommMap(QMap<long long, int>&map)
02159 {
02160 QMap<long long, int>::Iterator it;
02161
02162 if (map.size() == 0)
02163 return;
02164
02165 for (it = map.begin(); it != map.end(); it++)
02166 {
02167 if (it.data() == MARK_START)
02168 map[it.key()] = MARK_COMM_END;
02169 else
02170 map[it.key()] = MARK_COMM_START;
02171 }
02172
02173 it = map.begin();
02174 if (it != map.end())
02175 {
02176 switch (map[it.key()])
02177 {
02178 case MARK_COMM_END:
02179 if (it.key() == 0)
02180 map.erase(0);
02181 else
02182 map[0] = MARK_COMM_START;
02183 break;
02184 case MARK_COMM_START:
02185 break;
02186 default:
02187 map.erase(0);
02188 break;
02189 }
02190 }
02191 }
02192
02193
02194
02195
02196
02197
02198 void ClassicCommDetector::CleanupFrameInfo(void)
02199 {
02200 VERBOSE(VB_COMMFLAG, "CommDetect::CleanupFrameInfo()");
02201
02202 int value;
02203 int before, after;
02204
02205
02206 if ((framesProcessed > (fps * 60)) &&
02207 (blankFrameCount < (framesProcessed * 0.0004)))
02208 {
02209 int avgHistogram[256];
02210 int minAvg = -1;
02211 int newThreshold = -1;
02212
02213 VERBOSE(VB_COMMFLAG,
02214 QString("ClassicCommDetect: Only found %1 blank frames but "
02215 "wanted at least %2, rechecking data using higher "
02216 "threshold.")
02217 .arg(blankFrameCount)
02218 .arg((int)(framesProcessed * 0.0004)));
02219 blankFrameMap.clear();
02220 blankFrameCount = 0;
02221
02222 memset(avgHistogram, 0, sizeof(avgHistogram));
02223
02224 for (long i = 1; i <= framesProcessed; i++)
02225 avgHistogram[frameInfo[i].avgBrightness] += 1;
02226
02227 for (int i = 1; i <= 255 && minAvg == -1; i++)
02228 if (avgHistogram[i] > (framesProcessed * 0.0004))
02229 minAvg = i;
02230
02231 newThreshold = minAvg + 3;
02232 VERBOSE(VB_COMMFLAG, QString("Minimum Average Brightness on a frame "
02233 "was %1, will use %2 as new threshold")
02234 .arg(minAvg).arg(newThreshold));
02235
02236 for (long i = 1; i <= framesProcessed; i++)
02237 {
02238 value = frameInfo[i].flagMask;
02239 frameInfo[i].flagMask = value & ~COMM_FRAME_BLANK;
02240
02241 if (( !(frameInfo[i].flagMask & COMM_FRAME_BLANK)) &&
02242 (frameInfo[i].avgBrightness < newThreshold))
02243 {
02244 frameInfo[i].flagMask = value | COMM_FRAME_BLANK;
02245 blankFrameMap[i] = MARK_BLANK_FRAME;
02246 blankFrameCount++;
02247 }
02248 }
02249
02250 VERBOSE(VB_COMMFLAG, QString("Found %1 blank frames using new value")
02251 .arg(blankFrameCount));
02252 }
02253
02254
02255 for (long i = 1; i <= framesProcessed; i++)
02256 {
02257 if ((i < 10) || (i > (framesProcessed - 10)))
02258 continue;
02259
02260 before = 0;
02261 for (int offset = 1; offset <= 10; offset++)
02262 if (frameInfo[i - offset].flagMask & COMM_FRAME_LOGO_PRESENT)
02263 before++;
02264
02265 after = 0;
02266 for (int offset = 1; offset <= 10; offset++)
02267 if (frameInfo[i + offset].flagMask & COMM_FRAME_LOGO_PRESENT)
02268 after++;
02269
02270 value = frameInfo[i].flagMask;
02271 if (value == -1)
02272 frameInfo[i].flagMask = 0;
02273
02274 if (value & COMM_FRAME_LOGO_PRESENT)
02275 {
02276 if ((before < 4) && (after < 4))
02277 frameInfo[i].flagMask = value & ~COMM_FRAME_LOGO_PRESENT;
02278 }
02279 else
02280 {
02281 if ((before > 6) && (after > 6))
02282 frameInfo[i].flagMask = value | COMM_FRAME_LOGO_PRESENT;
02283 }
02284 }
02285 }
02286
02287 void ClassicCommDetector::GetLogoCommBreakMap(QMap<long long, int> &map)
02288 {
02289 VERBOSE(VB_COMMFLAG, "CommDetect::GetLogoCommBreakMap()");
02290
02291 map.clear();
02292
02293 int curFrame;
02294 bool PrevFrameLogo;
02295 bool CurrentFrameLogo;
02296
02297 curFrame = 1;
02298 PrevFrameLogo = false;
02299
02300 while (curFrame <= framesProcessed)
02301 {
02302 if (frameInfo[curFrame].flagMask & COMM_FRAME_LOGO_PRESENT)
02303 CurrentFrameLogo = true;
02304 else
02305 CurrentFrameLogo = false;
02306
02307 if (!PrevFrameLogo && CurrentFrameLogo)
02308 map[curFrame] = MARK_START;
02309 else if (PrevFrameLogo && !CurrentFrameLogo)
02310 map[curFrame] = MARK_END;
02311
02312 curFrame++;
02313 PrevFrameLogo = CurrentFrameLogo;
02314 }
02315
02316 }
02317
02318 void ClassicCommDetector::logoDetectorBreathe()
02319 {
02320 emit breathe();
02321 }
02322
02323