|
MythTV
0.26-pre
|
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 }
1.7.6.1