MythTV  0.26-pre
PrePostRollFlagger.cpp
Go to the documentation of this file.
00001 #include <unistd.h>
00002 
00003 #include "PrePostRollFlagger.h"
00004 
00005 // MythTV headers
00006 #include "mythcorecontext.h"
00007 #include "programinfo.h"
00008 #include "mythplayer.h"
00009 
00010 PrePostRollFlagger::PrePostRollFlagger(SkipType commDetectMethod,
00011                             bool showProgress,bool fullSpeed,
00012                             MythPlayer* player,
00013                             const QDateTime& startedAt_in,
00014                             const QDateTime& stopsAt_in,
00015                             const QDateTime& recordingStartedAt_in,
00016                             const QDateTime& recordingStopsAt_in):
00017     ClassicCommDetector( commDetectMethod,  showProgress,  fullSpeed,
00018         player,          startedAt_in,      stopsAt_in,
00019         recordingStartedAt_in,              recordingStopsAt_in),
00020         myTotalFrames(0),                   closestAfterPre(0),
00021         closestBeforePre(0),                closestAfterPost(0),
00022         closestBeforePost(0)
00023 {
00024 }
00025 
00026 void PrePostRollFlagger::Init()
00027 {
00028     ClassicCommDetector::Init();
00029     player->SetExactSeeks(true);
00030 }
00031 
00032 bool PrePostRollFlagger::go()
00033 {
00034     int secsSince = 0;
00035     int requiredBuffer = 120;
00036     int requiredHeadStart = requiredBuffer;
00037     bool wereRecording = stillRecording;
00038 
00039     secsSince = startedAt.secsTo(QDateTime::currentDateTime());
00040     while (stillRecording && (secsSince < requiredHeadStart))
00041     {
00042         emit statusUpdate(QObject::tr("Waiting to pass preroll + head start"));
00043 
00044         emit breathe();
00045         if (m_bStop)
00046             return false;
00047 
00048         sleep(5);
00049         secsSince = startedAt.secsTo(QDateTime::currentDateTime());
00050     }
00051 
00052     if (player->OpenFile() < 0)
00053         return false;
00054 
00055     Init();
00056 
00057 
00058     // Don't bother flagging short ~realtime recordings
00059     if ((wereRecording) && (!stillRecording) && (secsSince < requiredHeadStart))
00060         return false;
00061 
00062     aggressiveDetection =
00063         gCoreContext->GetNumSetting("AggressiveCommDetect", 1);
00064 
00065     if (!player->InitVideo())
00066     {
00067         LOG(VB_GENERAL, LOG_ERR,
00068             "NVP: Unable to initialize video for FlagCommercials.");
00069         return false;
00070     }
00071     player->EnableSubtitles(false);
00072 
00073     emit breathe();
00074     if (m_bStop)
00075         return false;
00076 
00077     QTime flagTime;
00078     flagTime.start();
00079 
00080     if (recordingStopsAt < QDateTime::currentDateTime() )
00081         myTotalFrames = player->GetTotalFrameCount();
00082     else
00083         myTotalFrames = (long long)(player->GetFrameRate() *
00084                         (recordingStartedAt.secsTo(recordingStopsAt)));
00085 
00086 
00087 
00088     if (showProgress)
00089     {
00090         if (myTotalFrames)
00091             cerr << "  0%/      ";
00092         else
00093             cerr << "     0/      ";
00094         cerr.flush();
00095     }
00096 
00097     float aspect = player->GetVideoAspect();
00098 
00099     SetVideoParams(aspect);
00100 
00101     emit breathe();
00102 
00103     long long stopFrame = preRoll + fps * 120; //look up to 2 minutes past
00104     long long framesToProcess = 0;
00105     if(preRoll)
00106         framesToProcess += stopFrame;
00107     if(postRoll)
00108         //guess two minutes before
00109         framesToProcess += myTotalFrames - postRoll + fps * 120;
00110 
00111 
00112     long long framesProcessed = 0;
00113     if(preRoll > 0)
00114     {
00115         //check from preroll after
00116         LOG(VB_COMMFLAG, LOG_INFO,
00117             QString("Finding closest after preroll(%1-%2)")
00118                 .arg(preRoll).arg(stopFrame));
00119 
00120         closestAfterPre = findBreakInrange(preRoll, stopFrame, framesToProcess,
00121                                            framesProcessed, flagTime, false);
00122 
00123         LOG(VB_COMMFLAG, LOG_INFO, QString("Closest after preroll: %1")
00124                 .arg(closestAfterPre));
00125 
00126 
00127         //check before preroll
00128         long long startFrame = 0;
00129         if(closestAfterPre)
00130             startFrame = preRoll - (closestAfterPre - preRoll) - 1;
00131 
00132         LOG(VB_COMMFLAG, LOG_INFO, QString("Finding before preroll (%1-%2)")
00133                 .arg(startFrame).arg(preRoll));
00134         closestBeforePre = findBreakInrange(startFrame, preRoll,
00135                                             framesToProcess, framesProcessed,
00136                                             flagTime, true);
00137         LOG(VB_COMMFLAG, LOG_INFO, QString("Closest before preroll: %1")
00138                 .arg(closestBeforePre));
00139 
00140         if(closestBeforePre || closestAfterPre)
00141             emit gotNewCommercialBreakList();
00142 
00143         // for better processing percent
00144         framesToProcess -= (stopFrame - framesProcessed);
00145 
00146     }
00147 
00148     if(stillRecording)
00149     {
00150         while (QDateTime::currentDateTime() <= recordingStopsAt)
00151         {
00152             emit breathe();
00153             if (m_bStop)
00154                 return false;
00155             emit statusUpdate(QObject::tr("Waiting for recording to finish"));
00156             sleep(5);
00157         }
00158         stillRecording = false;
00159          myTotalFrames = player->GetTotalFrameCount();
00160     }
00161 
00162     if(postRoll > 0)
00163     {
00164         //check from preroll after
00165         long long postRollStartLoc = myTotalFrames - postRoll;
00166         LOG(VB_COMMFLAG, LOG_INFO,
00167             QString("Finding closest after postroll(%1-%2)")
00168                 .arg(postRollStartLoc).arg(myTotalFrames));
00169         closestAfterPost = findBreakInrange(postRollStartLoc, myTotalFrames,
00170                                             framesToProcess, framesProcessed,
00171                                             flagTime, false);
00172         LOG(VB_COMMFLAG, LOG_INFO, QString("Closest after postRoll: %1")
00173                 .arg(closestAfterPost));
00174 
00175         //check before preroll
00176         long long startFrame = 0;
00177         if(closestAfterPost)
00178             startFrame = postRollStartLoc
00179                          - (closestAfterPost - postRollStartLoc) - 1;
00180 
00181         LOG(VB_COMMFLAG, LOG_INFO,
00182             QString("finding closest before preroll(%1-%2)")
00183                 .arg(startFrame).arg(postRollStartLoc));
00184         closestBeforePost = findBreakInrange(startFrame, postRollStartLoc,
00185                                              framesToProcess, framesProcessed,
00186                                              flagTime, true);
00187         LOG(VB_COMMFLAG, LOG_INFO, QString("Closest before postroll: %1")
00188                 .arg(closestBeforePost));
00189 
00190         framesToProcess = framesProcessed;
00191     }
00192 
00193     if (showProgress)
00194     {
00195         //float elapsed = flagTime.elapsed() / 1000.0;
00196 
00197         //float flagFPS = (elapsed > 0.0f) ? (framesProcessed / elapsed) : 0.0f;
00198 
00199         if (myTotalFrames)
00200             cerr << "\b\b\b\b\b\b      \b\b\b\b\b\b";
00201         else
00202             cerr << "\b\b\b\b\b\b\b\b\b\b\b\b\b             "
00203                     "\b\b\b\b\b\b\b\b\b\b\b\b\b";
00204         cerr.flush();
00205     }
00206 
00207     return true;
00208 }
00209 
00210 
00211 long long PrePostRollFlagger::findBreakInrange(long long startFrame,
00212                                                long long stopFrame,
00213                                                long long totalFrames,
00214                                                long long &framesProcessed,
00215                                              QTime &flagTime, bool findLast)
00216 {
00217     float flagFPS;
00218     int requiredBuffer = 30;
00219     long long currentFrameNumber;
00220     int prevpercent = -1;
00221 
00222     if(startFrame > 0)
00223         startFrame--;
00224     else
00225         startFrame = 0;
00226 
00227     player->DiscardVideoFrame(player->GetRawVideoFrame(0));
00228 
00229     long long tmpStartFrame = startFrame;
00230     player->SetExactSeeks(true);
00231     VideoFrame* f = player->GetRawVideoFrame(tmpStartFrame);
00232     float aspect = player->GetVideoAspect();
00233     currentFrameNumber = f->frameNumber;
00234     LOG(VB_COMMFLAG, LOG_INFO, QString("Starting with frame %1")
00235             .arg(currentFrameNumber));
00236     player->DiscardVideoFrame(f);
00237 
00238     long long foundFrame = 0;
00239 
00240     while (!player->GetEof())
00241     {
00242         struct timeval startTime;
00243         if (stillRecording)
00244             gettimeofday(&startTime, NULL);
00245 
00246         VideoFrame* currentFrame = player->GetRawVideoFrame();
00247         currentFrameNumber = currentFrame->frameNumber;
00248 
00249         if(currentFrameNumber % 1000 == 0)
00250         {
00251             LOG(VB_COMMFLAG, LOG_INFO, QString("Processing frame %1")
00252                     .arg(currentFrameNumber));
00253         }
00254 
00255         if(currentFrameNumber > stopFrame || (!findLast && foundFrame))
00256         {
00257             player->DiscardVideoFrame(currentFrame);
00258             break;
00259         }
00260 
00261         double newAspect = currentFrame->aspect;
00262         if (newAspect != aspect)
00263         {
00264             SetVideoParams(aspect);
00265             aspect = newAspect;
00266         }
00267 
00268         if (((currentFrameNumber % 500) == 0) ||
00269             (((currentFrameNumber % 100) == 0) &&
00270              (stillRecording)))
00271         {
00272             emit breathe();
00273             if (m_bStop)
00274             {
00275                 player->DiscardVideoFrame(currentFrame);
00276                 return false;
00277             }
00278         }
00279 
00280         while (m_bPaused)
00281         {
00282             emit breathe();
00283             sleep(1);
00284         }
00285 
00286         // sleep a little so we don't use all cpu even if we're niced
00287         if (!fullSpeed && !stillRecording)
00288             usleep(10000);
00289 
00290         if (((currentFrameNumber % 500) == 0) ||
00291             ((showProgress || stillRecording) &&
00292              ((currentFrameNumber % 100) == 0)))
00293         {
00294             float elapsed = flagTime.elapsed() / 1000.0;
00295 
00296             if (elapsed)
00297                 flagFPS = framesProcessed / elapsed;
00298             else
00299                 flagFPS = 0.0;
00300 
00301             int percentage;
00302             if (stopFrame)
00303                 percentage = framesProcessed * 100 / totalFrames;
00304             else
00305                 percentage = 0;
00306 
00307             if (percentage > 100)
00308                 percentage = 100;
00309 
00310             if (showProgress)
00311             {
00312                 if (stopFrame)
00313                 {
00314                     QString tmp = QString("\b\b\b\b\b\b\b\b\b\b\b%1%/%2fps")
00315                         .arg(percentage, 3).arg((int)flagFPS, 3);
00316                     QByteArray ba = tmp.toAscii();
00317                     cerr << ba.constData() << flush;
00318                 }
00319                 else
00320                 {
00321                     QString tmp = QString("\b\b\b\b\b\b\b\b\b\b\b\b\b%1/%2fps")
00322                         .arg(currentFrameNumber, 6).arg((int)flagFPS, 3);
00323                     QByteArray ba = tmp.toAscii();
00324                     cerr << ba.constData() << flush;
00325                 }
00326                 cerr.flush();
00327             }
00328 
00329             if (stopFrame)
00330                 emit statusUpdate(QObject::tr("%1% Completed @ %2 fps.")
00331                                   .arg(percentage).arg(flagFPS));
00332             else
00333                 emit statusUpdate(QObject::tr("%1 Frames Completed @ %2 fps.")
00334                                   .arg((long)currentFrameNumber).arg(flagFPS));
00335 
00336             if (percentage % 10 == 0 && prevpercent != percentage)
00337             {
00338                 prevpercent = percentage;
00339                 LOG(VB_GENERAL, LOG_INFO, QString("%1%% Completed @ %2 fps.")
00340                     .arg(percentage) .arg(flagFPS));
00341             }
00342         }
00343 
00344         ProcessFrame(currentFrame, currentFrameNumber);
00345 
00346         if(frameInfo[currentFrameNumber].flagMask &
00347            (COMM_FRAME_SCENE_CHANGE | COMM_FRAME_BLANK))
00348         {
00349             foundFrame = currentFrameNumber;
00350         }
00351 
00352         if (stillRecording)
00353         {
00354             int secondsRecorded =
00355                 recordingStartedAt.secsTo(QDateTime::currentDateTime());
00356             int secondsFlagged = (int)(framesProcessed / fps);
00357             int secondsBehind = secondsRecorded - secondsFlagged;
00358             long usecPerFrame = (long)(1.0 / player->GetFrameRate() * 1000000);
00359 
00360             struct timeval endTime;
00361             gettimeofday(&endTime, NULL);
00362 
00363             long long usecSleep =
00364                       usecPerFrame -
00365                       (((endTime.tv_sec - startTime.tv_sec) * 1000000) +
00366                        (endTime.tv_usec - startTime.tv_usec));
00367 
00368             if (secondsBehind > requiredBuffer)
00369             {
00370                 if (fullSpeed)
00371                     usecSleep = 0;
00372                 else
00373                     usecSleep = (long)(usecSleep * 0.25);
00374             }
00375             else if (secondsBehind < requiredBuffer)
00376                 usecSleep = (long)(usecPerFrame * 1.5);
00377 
00378             if (usecSleep > 0)
00379                 usleep(usecSleep);
00380         }
00381 
00382         player->DiscardVideoFrame(currentFrame);
00383         framesProcessed++;
00384     }
00385     return foundFrame;
00386 }
00387 
00388 
00389 void PrePostRollFlagger::GetCommercialBreakList(frm_dir_map_t &marks)
00390 {
00391     LOG(VB_COMMFLAG, LOG_INFO, "PrePostRollFlagger::GetCommBreakMap()");
00392     marks.clear();
00393 
00394     long long end = 0;
00395     if(closestAfterPre && closestBeforePre)
00396     {
00397         //choose closest
00398         if(closestAfterPre - preRoll < preRoll - closestBeforePre)
00399             end = closestAfterPre;
00400         else
00401             end = closestBeforePre;
00402     }
00403     else if(closestBeforePre)
00404         end = closestBeforePre;
00405     else if(closestAfterPre)
00406         end = closestAfterPre;
00407     else
00408         end = preRoll;
00409 
00410     if(end)
00411     {
00412         marks[0] = MARK_COMM_START;
00413         marks[end] = MARK_COMM_END;
00414     }
00415 
00416     long long start = 0;
00417     if(closestAfterPost && closestBeforePost)
00418     {
00419         //choose closest
00420         if(closestAfterPost - postRoll < postRoll - closestBeforePost)
00421             start = closestAfterPost;
00422         else
00423             start = closestBeforePost;
00424     }
00425     else if(closestBeforePost)
00426         start = closestBeforePost;
00427     else if(closestAfterPost)
00428         start = closestAfterPost;
00429     else if(postRoll)
00430         start = myTotalFrames - postRoll;
00431 
00432     if(start)
00433     {
00434         marks[start] = MARK_COMM_START;
00435         marks[myTotalFrames] = MARK_COMM_END;
00436     }
00437 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends