00001
00002 #include <unistd.h>
00003
00004
00005 #include <cmath>
00006 #include <cerrno>
00007
00008
00009 #include <algorithm>
00010 using namespace std;
00011
00012
00013 #include <QDir>
00014 #include <QFileInfo>
00015
00016
00017 #include "compat.h"
00018 #include "mythdb.h"
00019 #include "mythlogging.h"
00020 #include "mythplayer.h"
00021 #include "programinfo.h"
00022 #include "channelutil.h"
00023
00024
00025 #include "CommDetector2.h"
00026 #include "CannyEdgeDetector.h"
00027 #include "FrameAnalyzer.h"
00028 #include "PGMConverter.h"
00029 #include "BorderDetector.h"
00030 #include "HistogramAnalyzer.h"
00031 #include "BlankFrameDetector.h"
00032 #include "SceneChangeDetector.h"
00033 #include "TemplateFinder.h"
00034 #include "TemplateMatcher.h"
00035
00036 namespace {
00037
00038 bool stopForBreath(bool isrecording, long long frameno)
00039 {
00040 return (isrecording && (frameno % 100) == 0) || (frameno % 500) == 0;
00041 }
00042
00043 bool needToReportState(bool showprogress, bool isrecording, long long frameno)
00044 {
00045 return ((showprogress || isrecording) && (frameno % 100) == 0) ||
00046 (frameno % 500) == 0;
00047 }
00048
00049 void waitForBuffer(const struct timeval *framestart, int minlag, int flaglag,
00050 float fps, bool fullspeed)
00051 {
00052 long usperframe = (long)(1000000.0 / fps);
00053 struct timeval now, elapsed;
00054 long sleepus;
00055
00056 (void)gettimeofday(&now, NULL);
00057 timersub(&now, framestart, &elapsed);
00058
00059
00060 sleepus = usperframe - elapsed.tv_sec * 1000000 - elapsed.tv_usec;
00061 if (sleepus <= 0)
00062 return;
00063
00064 if (flaglag > minlag)
00065 {
00066
00067 if (fullspeed)
00068 return;
00069 sleepus /= 4;
00070 }
00071 else if (flaglag < minlag)
00072 {
00073
00074 sleepus = sleepus * 3 / 2;
00075 }
00076 usleep(sleepus);
00077 }
00078
00079 bool MythPlayerInited(FrameAnalyzerItem &pass,
00080 FrameAnalyzerItem &finishedAnalyzers,
00081 FrameAnalyzerItem &deadAnalyzers,
00082 MythPlayer *player,
00083 long long nframes)
00084 {
00085 FrameAnalyzerItem::iterator it = pass.begin();
00086 while (it != pass.end())
00087 {
00088 FrameAnalyzer::analyzeFrameResult ares =
00089 (*it)->MythPlayerInited(player, nframes);
00090
00091 if ((FrameAnalyzer::ANALYZE_OK == ares) ||
00092 (FrameAnalyzer::ANALYZE_ERROR == ares))
00093 {
00094 ++it;
00095 }
00096 else if (FrameAnalyzer::ANALYZE_FINISHED == ares)
00097 {
00098 finishedAnalyzers.push_back(*it);
00099 it = pass.erase(it);
00100 }
00101 else if (FrameAnalyzer::ANALYZE_FATAL == ares)
00102 {
00103 deadAnalyzers.push_back(*it);
00104 it = pass.erase(it);
00105 }
00106 else
00107 {
00108 LOG(VB_GENERAL, LOG_ERR,
00109 QString("Unexpected return value from %1::MythPlayerInited: %2")
00110 .arg((*it)->name()).arg(ares));
00111 return false;
00112 }
00113 }
00114
00115 return true;
00116 }
00117
00118 long long processFrame(FrameAnalyzerItem &pass,
00119 FrameAnalyzerItem &finishedAnalyzers,
00120 FrameAnalyzerItem &deadAnalyzers,
00121 const VideoFrame *frame,
00122 long long frameno)
00123 {
00124 long long nextFrame;
00125 long long minNextFrame = FrameAnalyzer::ANYFRAME;
00126
00127 FrameAnalyzerItem::iterator it = pass.begin();
00128 while (it != pass.end())
00129 {
00130 FrameAnalyzer::analyzeFrameResult ares =
00131 (*it)->analyzeFrame(frame, frameno, &nextFrame);
00132
00133 if ((FrameAnalyzer::ANALYZE_OK == ares) ||
00134 (FrameAnalyzer::ANALYZE_ERROR == ares))
00135 {
00136 minNextFrame = std::min(minNextFrame, nextFrame);
00137 ++it;
00138 }
00139 else if (ares == FrameAnalyzer::ANALYZE_FINISHED)
00140 {
00141 finishedAnalyzers.push_back(*it);
00142 it = pass.erase(it);
00143 }
00144 else
00145 {
00146 if (ares != FrameAnalyzer::ANALYZE_FATAL)
00147 {
00148 LOG(VB_GENERAL, LOG_ERR,
00149 QString("Unexpected return value from %1::analyzeFrame: %2")
00150 .arg((*it)->name()).arg(ares));
00151 }
00152
00153 deadAnalyzers.push_back(*it);
00154 it = pass.erase(it);
00155 }
00156 }
00157
00158 if (minNextFrame == FrameAnalyzer::ANYFRAME)
00159 minNextFrame = FrameAnalyzer::NEXTFRAME;
00160
00161 if (minNextFrame == FrameAnalyzer::NEXTFRAME)
00162 minNextFrame = frameno + 1;
00163
00164 return minNextFrame;
00165 }
00166
00167 int passFinished(FrameAnalyzerItem &pass, long long nframes, bool final)
00168 {
00169 FrameAnalyzerItem::iterator it = pass.begin();
00170 for (; it != pass.end(); ++it)
00171 (void)(*it)->finished(nframes, final);
00172
00173 return 0;
00174 }
00175
00176 int passReportTime(const FrameAnalyzerItem &pass)
00177 {
00178 FrameAnalyzerItem::const_iterator it = pass.begin();
00179 for (; it != pass.end(); ++it)
00180 (void)(*it)->reportTime();
00181
00182 return 0;
00183 }
00184
00185 bool searchingForLogo(TemplateFinder *tf, const FrameAnalyzerItem &pass)
00186 {
00187 if (!tf)
00188 return false;
00189
00190 FrameAnalyzerItem::const_iterator it =
00191 std::find(pass.begin(), pass.end(), tf);
00192
00193 return it != pass.end();
00194 }
00195
00196 };
00197
00198 namespace commDetector2 {
00199
00200 QString debugDirectory(int chanid, const QDateTime& recstartts)
00201 {
00202
00203
00204
00205 MSqlQuery query(MSqlQuery::InitCon());
00206 query.prepare("SELECT basename"
00207 " FROM recorded"
00208 " WHERE chanid = :CHANID"
00209 " AND starttime = :STARTTIME"
00210 ";");
00211 query.bindValue(":CHANID", chanid);
00212 query.bindValue(":STARTTIME", recstartts);
00213 if (!query.exec() || !query.next())
00214 {
00215 MythDB::DBError("Error in CommDetector2::CommDetector2", query);
00216 return "";
00217 }
00218
00219 const ProgramInfo pginfo(chanid, recstartts);
00220
00221 if (!pginfo.GetChanID())
00222 return "";
00223
00224 QString pburl = pginfo.GetPlaybackURL(true);
00225 if (pburl.left(1) != "/")
00226 return "";
00227
00228 QString basename(query.value(0).toString());
00229 QString debugdir = pburl.section('/',0,-2) + "/" + basename + "-debug";
00230
00231 return debugdir;
00232 }
00233
00234 void createDebugDirectory(QString dirname, QString comment)
00235 {
00236 QDir qdir(dirname);
00237 if (qdir.exists())
00238 {
00239 LOG(VB_COMMFLAG, LOG_INFO, QString("%1 using debug directory \"%2\"")
00240 .arg(comment).arg(dirname));
00241 }
00242 else
00243 {
00244 if (qdir.mkdir(dirname))
00245 {
00246 LOG(VB_COMMFLAG, LOG_INFO,
00247 QString("%1 created debug directory \"%1\"")
00248 .arg(comment).arg(dirname));
00249 }
00250 else
00251 {
00252 LOG(VB_COMMFLAG, LOG_INFO, QString("%1 failed to create \"%2\": %3")
00253 .arg(comment).arg(dirname).arg(strerror(errno)));
00254 }
00255 }
00256 }
00257
00258 QString frameToTimestamp(long long frameno, float fps)
00259 {
00260 int ms, ss, mm, hh;
00261 QString ts;
00262
00263 ms = (int)roundf(frameno / fps * 1000);
00264
00265 ss = ms / 1000;
00266 ms %= 1000;
00267 if (ms >= 500)
00268 ss++;
00269
00270 mm = ss / 60;
00271 ss %= 60;
00272
00273 hh = mm / 60;
00274 mm %= 60;
00275
00276 return ts.sprintf("%d:%02d:%02d", hh, mm, ss);
00277 }
00278
00279 QString frameToTimestampms(long long frameno, float fps)
00280 {
00281 int ms, ss, mm;
00282 QString ts;
00283
00284 ms = (int)roundf(frameno / fps * 1000);
00285
00286 ss = ms / 1000;
00287 ms %= 1000;
00288
00289 mm = ss / 60;
00290 ss %= 60;
00291
00292 return ts.sprintf("%d:%02d.%03d", mm, ss, ms);
00293 }
00294
00295 QString strftimeval(const struct timeval *tv)
00296 {
00297 QString str;
00298 return str.sprintf("%ld.%06ld", tv->tv_sec, tv->tv_usec);
00299 }
00300
00301 };
00302
00303 using namespace commDetector2;
00304
00305 CommDetector2::CommDetector2(
00306 enum SkipTypes commDetectMethod_in,
00307 bool showProgress_in,
00308 bool fullSpeed_in,
00309 MythPlayer *player_in,
00310 int chanid,
00311 const QDateTime &startts_in,
00312 const QDateTime &endts_in,
00313 const QDateTime &recstartts_in,
00314 const QDateTime &recendts_in,
00315 bool useDB) :
00316 commDetectMethod((enum SkipTypes)(commDetectMethod_in & ~COMM_DETECT_2)),
00317 showProgress(showProgress_in), fullSpeed(fullSpeed_in),
00318 player(player_in),
00319 startts(startts_in), endts(endts_in),
00320 recstartts(recstartts_in), recendts(recendts_in),
00321 isRecording(QDateTime::currentDateTime() < recendts),
00322 sendBreakMapUpdates(false), breakMapUpdateRequested(false),
00323 finished(false), currentFrameNumber(0),
00324 logoFinder(NULL), logoMatcher(NULL),
00325 blankFrameDetector(NULL), sceneChangeDetector(NULL),
00326 debugdir("")
00327 {
00328 FrameAnalyzerItem pass0, pass1;
00329 PGMConverter *pgmConverter = NULL;
00330 BorderDetector *borderDetector = NULL;
00331 HistogramAnalyzer *histogramAnalyzer = NULL;
00332
00333 if (useDB)
00334 debugdir = debugDirectory(chanid, recstartts);
00335
00336
00337
00338
00339
00340 if ((commDetectMethod & COMM_DETECT_2_BLANK))
00341 {
00342 if (!pgmConverter)
00343 pgmConverter = new PGMConverter();
00344
00345 if (!borderDetector)
00346 borderDetector = new BorderDetector();
00347
00348 if (!histogramAnalyzer)
00349 {
00350 histogramAnalyzer = new HistogramAnalyzer(pgmConverter,
00351 borderDetector, debugdir);
00352 }
00353
00354 if (!blankFrameDetector)
00355 {
00356 blankFrameDetector = new BlankFrameDetector(histogramAnalyzer,
00357 debugdir);
00358 pass1.push_back(blankFrameDetector);
00359 }
00360 }
00361
00362
00363
00364
00365
00366 if ((commDetectMethod & COMM_DETECT_2_SCENE))
00367 {
00368 if (!pgmConverter)
00369 pgmConverter = new PGMConverter();
00370
00371 if (!borderDetector)
00372 borderDetector = new BorderDetector();
00373
00374 if (!histogramAnalyzer)
00375 {
00376 histogramAnalyzer = new HistogramAnalyzer(pgmConverter,
00377 borderDetector, debugdir);
00378 }
00379
00380 if (!sceneChangeDetector)
00381 {
00382 sceneChangeDetector = new SceneChangeDetector(histogramAnalyzer,
00383 debugdir);
00384 pass1.push_back(sceneChangeDetector);
00385 }
00386 }
00387
00388
00389
00390
00391
00392
00393
00394 if ((commDetectMethod & COMM_DETECT_2_LOGO))
00395 {
00396 CannyEdgeDetector *cannyEdgeDetector = NULL;
00397
00398 if (!pgmConverter)
00399 pgmConverter = new PGMConverter();
00400
00401 if (!borderDetector)
00402 borderDetector = new BorderDetector();
00403
00404 if (!cannyEdgeDetector)
00405 cannyEdgeDetector = new CannyEdgeDetector();
00406
00407 if (!logoFinder)
00408 {
00409 logoFinder = new TemplateFinder(pgmConverter, borderDetector,
00410 cannyEdgeDetector, player, recstartts.secsTo(recendts),
00411 debugdir);
00412 pass0.push_back(logoFinder);
00413 }
00414
00415 if (!logoMatcher)
00416 {
00417 logoMatcher = new TemplateMatcher(pgmConverter, cannyEdgeDetector,
00418 logoFinder, debugdir);
00419 pass1.push_back(logoMatcher);
00420 }
00421 }
00422
00423 if (histogramAnalyzer && logoFinder)
00424 histogramAnalyzer->setLogoState(logoFinder);
00425
00426
00427 frameAnalyzers.push_back(pass0);
00428 frameAnalyzers.push_back(pass1);
00429 }
00430
00431 void CommDetector2::reportState(int elapsedms, long long frameno,
00432 long long nframes, unsigned int passno, unsigned int npasses)
00433 {
00434 float fps = elapsedms ? (float)frameno * 1000 / elapsedms : 0;
00435 int prevpercent = -1;
00436
00437
00438 int percentage = passno == 0 ? 0 :
00439 (passno - 1) * 100 / (npasses - 1) +
00440 min((long long)100, (frameno * 100 / nframes) / (npasses - 1));
00441
00442 if (showProgress)
00443 {
00444 QString tmp = "";
00445
00446 if (nframes)
00447 tmp = QString("\r%1%/ %2fps").arg(percentage,3).arg(fps,6,'f',2);
00448 else
00449 tmp = QString("\r%1/ %2fps").arg(frameno,6).arg(fps,6,'f',2);
00450
00451 QByteArray tmp2 = tmp.toLocal8Bit();
00452 cerr << tmp2.constData() << " \r";
00453 cerr.flush();
00454 }
00455
00456 if (nframes)
00457 {
00458 emit statusUpdate(QObject::tr("%1% Completed @ %2 fps.")
00459 .arg(percentage).arg(fps));
00460 }
00461 else
00462 {
00463 emit statusUpdate(QObject::tr("%1 Frames Completed @ %2 fps.")
00464 .arg(frameno).arg(fps));
00465 }
00466
00467 if (percentage % 10 == 0 && prevpercent != percentage)
00468 {
00469 prevpercent = percentage;
00470 LOG(VB_GENERAL, LOG_INFO, QString("%1%% Completed @ %2 fps.")
00471 .arg(percentage) .arg(fps));
00472 }
00473 }
00474
00475 int CommDetector2::computeBreaks(long long nframes)
00476 {
00477 int trow, tcol, twidth, theight;
00478 TemplateMatcher *matcher;
00479
00480 breaks.clear();
00481
00482 matcher = logoFinder &&
00483 logoFinder->getTemplate(&trow, &tcol, &twidth, &theight) ? logoMatcher :
00484 NULL;
00485
00486 if (matcher && blankFrameDetector)
00487 {
00488 int cmp;
00489 if (!(cmp = matcher->templateCoverage(nframes, finished)))
00490 {
00491 if (matcher->adjustForBlanks(blankFrameDetector, nframes))
00492 return -1;
00493 if (matcher->computeBreaks(&breaks))
00494 return -1;
00495 }
00496 else
00497 {
00498 if (cmp > 0 &&
00499 blankFrameDetector->computeForLogoSurplus(matcher))
00500 return -1;
00501 else if (cmp < 0 &&
00502 blankFrameDetector->computeForLogoDeficit(matcher))
00503 return -1;
00504
00505 if (blankFrameDetector->computeBreaks(&breaks))
00506 return -1;
00507 }
00508 }
00509 else if (matcher)
00510 {
00511 if (matcher->computeBreaks(&breaks))
00512 return -1;
00513 }
00514 else if (blankFrameDetector)
00515 {
00516 if (blankFrameDetector->computeBreaks(&breaks))
00517 return -1;
00518 }
00519
00520 return 0;
00521 }
00522
00523 bool CommDetector2::go(void)
00524 {
00525 int minlag = 7;
00526
00527 if (player->OpenFile() < 0)
00528 return false;
00529
00530 if (!player->InitVideo())
00531 {
00532 LOG(VB_GENERAL, LOG_ERR,
00533 "NVP: Unable to initialize video for FlagCommercials.");
00534 return false;
00535 }
00536
00537 player->EnableSubtitles(false);
00538
00539 QTime totalFlagTime;
00540 totalFlagTime.start();
00541
00542
00543 long long nframes = isRecording ?
00544 (long long)roundf((recstartts.secsTo(recendts) + 5) *
00545 player->GetFrameRate()) :
00546 player->GetTotalFrameCount();
00547 bool postprocessing = !isRecording;
00548
00549 if (showProgress)
00550 {
00551 if (nframes)
00552 cerr << " 0%/ ";
00553 else
00554 cerr << " 0/ ";
00555 cerr.flush();
00556 }
00557
00558 frm_dir_map_t lastBreakMap;
00559 unsigned int passno = 0;
00560 unsigned int npasses = frameAnalyzers.size();
00561 for (currentPass = frameAnalyzers.begin();
00562 currentPass != frameAnalyzers.end();
00563 ++currentPass, passno++)
00564 {
00565 FrameAnalyzerItem deadAnalyzers;
00566
00567 LOG(VB_COMMFLAG, LOG_INFO,
00568 QString("CommDetector2::go pass %1 of %2 (%3 frames, %4 fps)")
00569 .arg(passno + 1).arg(npasses)
00570 .arg(player->GetTotalFrameCount())
00571 .arg(player->GetFrameRate(), 0, 'f', 2));
00572
00573 if (!MythPlayerInited(
00574 *currentPass, finishedAnalyzers, deadAnalyzers, player, nframes))
00575 {
00576 return false;
00577 }
00578
00579 player->DiscardVideoFrame(player->GetRawVideoFrame(0));
00580 long long nextFrame = -1;
00581 currentFrameNumber = 0;
00582 long long lastLoggedFrame = currentFrameNumber;
00583 QTime passTime, clock;
00584 struct timeval getframetime;
00585
00586 player->ResetTotalDuration();
00587
00588 if (searchingForLogo(logoFinder, *currentPass))
00589 emit statusUpdate(QObject::tr("Performing Logo Identification"));
00590
00591 clock.start();
00592 passTime.start();
00593 memset(&getframetime, 0, sizeof(getframetime));
00594 while (!(*currentPass).empty() && !player->GetEof())
00595 {
00596 struct timeval start, end, elapsedtv;
00597
00598 (void)gettimeofday(&start, NULL);
00599 VideoFrame *currentFrame = player->GetRawVideoFrame(nextFrame);
00600 long long lastFrameNumber = currentFrameNumber;
00601 currentFrameNumber = currentFrame->frameNumber;
00602 (void)gettimeofday(&end, NULL);
00603 timersub(&end, &start, &elapsedtv);
00604 timeradd(&getframetime, &elapsedtv, &getframetime);
00605
00606 if (nextFrame != -1 && nextFrame == lastFrameNumber + 1 &&
00607 currentFrameNumber != nextFrame)
00608 {
00609
00610
00611
00612
00613 LOG(VB_COMMFLAG, LOG_INFO,
00614 QString("Jumped from frame %1 to frame %2")
00615 .arg(lastFrameNumber).arg(currentFrameNumber));
00616 }
00617
00618 if (stopForBreath(isRecording, currentFrameNumber))
00619 {
00620 emit breathe();
00621 if (m_bStop)
00622 {
00623 player->DiscardVideoFrame(currentFrame);
00624 return false;
00625 }
00626 }
00627
00628 while (m_bPaused)
00629 {
00630 emit breathe();
00631 sleep(1);
00632 }
00633
00634 if (!searchingForLogo(logoFinder, *currentPass) &&
00635 needToReportState(showProgress, isRecording,
00636 currentFrameNumber))
00637 {
00638 reportState(passTime.elapsed(), currentFrameNumber,
00639 nframes, passno, npasses);
00640 }
00641
00642 nextFrame = processFrame(
00643 *currentPass, finishedAnalyzers,
00644 deadAnalyzers, currentFrame, currentFrameNumber);
00645
00646 if (((currentFrameNumber >= 1) &&
00647 (((nextFrame * 10) / nframes) !=
00648 ((currentFrameNumber * 10) / nframes))) ||
00649 (nextFrame >= nframes))
00650 {
00651
00652 int elapsed = clock.restart();
00653 LOG(VB_COMMFLAG, LOG_INFO,
00654 QString("processFrame %1 of %2 (%3%) - %4 fps")
00655 .arg(currentFrameNumber)
00656 .arg(nframes)
00657 .arg((int)roundf(currentFrameNumber * 100.0 / nframes))
00658 .arg((currentFrameNumber - lastLoggedFrame) * 1000 /
00659 elapsed));
00660 lastLoggedFrame = currentFrameNumber;
00661 }
00662
00663 if (isRecording)
00664 {
00665 waitForBuffer(&start, minlag,
00666 recstartts.secsTo(QDateTime::currentDateTime()) -
00667 totalFlagTime.elapsed() / 1000, player->GetFrameRate(),
00668 fullSpeed);
00669 }
00670
00671
00672 if (!fullSpeed && !isRecording)
00673 usleep(10000);
00674
00675 if (sendBreakMapUpdates && (breakMapUpdateRequested ||
00676 !(currentFrameNumber % 500)))
00677 {
00678 frm_dir_map_t breakMap;
00679
00680 GetCommercialBreakList(breakMap);
00681
00682 frm_dir_map_t::const_iterator ii, jj;
00683 ii = breakMap.begin();
00684 jj = lastBreakMap.begin();
00685 while (ii != breakMap.end() && jj != lastBreakMap.end())
00686 {
00687 if (ii.key() != jj.key())
00688 break;
00689 if (*ii != *jj)
00690 break;
00691 ++ii;
00692 ++jj;
00693 }
00694 bool same = ii == breakMap.end() && jj == lastBreakMap.end();
00695 lastBreakMap = breakMap;
00696
00697 if (breakMapUpdateRequested || !same)
00698 emit gotNewCommercialBreakList();
00699
00700 breakMapUpdateRequested = false;
00701 }
00702
00703 player->DiscardVideoFrame(currentFrame);
00704 }
00705
00706
00707
00708 if (passno + 1 == npasses)
00709 player->SaveTotalDuration();
00710
00711 currentPass->insert(currentPass->end(),
00712 finishedAnalyzers.begin(),
00713 finishedAnalyzers.end());
00714 finishedAnalyzers.clear();
00715
00716 if (postprocessing)
00717 currentFrameNumber = player->GetTotalFrameCount() - 1;
00718 if (passFinished(*currentPass, currentFrameNumber + 1, true))
00719 return false;
00720
00721 LOG(VB_COMMFLAG, LOG_INFO, QString("NVP Time: GetRawVideoFrame=%1s")
00722 .arg(strftimeval(&getframetime)));
00723 if (passReportTime(*currentPass))
00724 return false;
00725 }
00726
00727 if (showProgress)
00728 {
00729 if (nframes)
00730 cerr << "\b\b\b\b\b\b \b\b\b\b\b\b";
00731 else
00732 cerr << "\b\b\b\b\b\b\b\b\b\b\b\b\b "
00733 "\b\b\b\b\b\b\b\b\b\b\b\b\b";
00734 cerr.flush();
00735 }
00736
00737 finished = true;
00738 return true;
00739 }
00740
00741 void CommDetector2::GetCommercialBreakList(frm_dir_map_t &marks)
00742 {
00743 if (!finished)
00744 {
00745 for (FrameAnalyzerList::iterator pass = frameAnalyzers.begin();
00746 pass != frameAnalyzers.end(); ++pass)
00747 {
00748 if (*pass == *currentPass &&
00749 passFinished(finishedAnalyzers, currentFrameNumber + 1, false))
00750 {
00751 return;
00752 }
00753
00754 if (passFinished(*pass, currentFrameNumber + 1, false))
00755 return;
00756 }
00757 }
00758
00759 if (computeBreaks(currentFrameNumber + 1))
00760 return;
00761
00762 marks.clear();
00763
00764
00765 long long breakframes = 0;
00766 for (FrameAnalyzer::FrameMap::Iterator bb = breaks.begin();
00767 bb != breaks.end();
00768 ++bb)
00769 {
00770 long long segb = bb.key();
00771 long long seglen = *bb;
00772 long long sege = segb + seglen - 1;
00773
00774 if (segb < sege)
00775 {
00776 marks[segb] = MARK_COMM_START;
00777 marks[sege] = MARK_COMM_END;
00778
00779 breakframes += seglen;
00780 }
00781 }
00782
00783
00784 const float fps = player->GetFrameRate();
00785 for (frm_dir_map_t::const_iterator iimark = marks.begin();
00786 iimark != marks.end();
00787 ++iimark)
00788 {
00789 long long markstart, markend;
00790
00791
00792 markstart = iimark.key() + 1;
00793 ++iimark;
00794 if (iimark == marks.end())
00795 break;
00796 markend = iimark.key() + 1;
00797
00798 LOG(VB_COMMFLAG, LOG_INFO, QString("Break: frame %1-%2 (%3-%4, %5)")
00799 .arg(markstart, 6).arg(markend, 6)
00800 .arg(frameToTimestamp(markstart, fps))
00801 .arg(frameToTimestamp(markend, fps))
00802 .arg(frameToTimestamp(markend - markstart + 1, fps)));
00803 }
00804
00805 const long long nframes = player->GetTotalFrameCount();
00806 LOG(VB_COMMFLAG, LOG_INFO,
00807 QString("Flagged %1 of %2 frames (%3 of %4), %5% commercials (%6)")
00808 .arg(currentFrameNumber + 1).arg(nframes)
00809 .arg(frameToTimestamp(currentFrameNumber + 1, fps))
00810 .arg(frameToTimestamp(nframes, fps))
00811 .arg(breakframes * 100 / currentFrameNumber)
00812 .arg(frameToTimestamp(breakframes, fps)));
00813 }
00814
00815 void CommDetector2::recordingFinished(long long totalFileSize)
00816 {
00817 CommDetectorBase::recordingFinished(totalFileSize);
00818 isRecording = false;
00819 LOG(VB_COMMFLAG, LOG_INFO,
00820 QString("CommDetector2::recordingFinished: %1 bytes")
00821 .arg(totalFileSize));
00822 }
00823
00824 void CommDetector2::requestCommBreakMapUpdate(void)
00825 {
00826 if (searchingForLogo(logoFinder, *currentPass))
00827 {
00828 LOG(VB_COMMFLAG, LOG_INFO, "Ignoring request for commBreakMapUpdate; "
00829 "still doing logo detection");
00830 return;
00831 }
00832
00833 LOG(VB_COMMFLAG, LOG_INFO,
00834 QString("commBreakMapUpdate requested at frame %1")
00835 .arg(currentFrameNumber + 1));
00836 sendBreakMapUpdates = true;
00837 breakMapUpdateRequested = true;
00838 }
00839
00840 static void PrintReportMap(ostream &out,
00841 const FrameAnalyzer::FrameMap &frameMap)
00842 {
00843 FrameAnalyzer::FrameMap::const_iterator it = frameMap.begin();
00844 for (; it != frameMap.end(); ++it)
00845 {
00846
00847
00848
00849
00850
00851 long long bb = it.key() + 1;
00852 long long ee = (*it) ? (bb + *it) : 1;
00853 QString tmp = QString("%1: %2").arg(bb, 10).arg(ee - 1, 10);
00854
00855 out << qPrintable(tmp) << "\n";
00856 }
00857 out << flush;
00858 }
00859
00860 void CommDetector2::PrintFullMap(
00861 ostream &out, const frm_dir_map_t *comm_breaks, bool verbose) const
00862 {
00863 FrameAnalyzer::FrameMap logoMap, blankMap, blankBreakMap, sceneMap;
00864 if (logoFinder)
00865 logoMap = logoFinder->GetMap(0);
00866
00867 if (blankFrameDetector)
00868 {
00869 blankBreakMap = blankFrameDetector->GetMap(0);
00870 blankMap = blankFrameDetector->GetMap(1);
00871 }
00872
00873 if (sceneChangeDetector)
00874 sceneMap = sceneChangeDetector->GetMap(0);
00875
00876 out << "Logo Break Map" << endl;
00877 PrintReportMap(out, logoMap);
00878 out << "Blank Break Map" << endl;
00879 PrintReportMap(out, blankBreakMap);
00880 out << "Blank Map" << endl;
00881 PrintReportMap(out, blankMap);
00882 out << "Scene Break Map" << endl;
00883 PrintReportMap(out, sceneMap);
00884 }
00885
00886