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