|
MythTV
0.26-pre
|
00001 #include "mythcontext.h" 00002 #include "programinfo.h" 00003 #include "playercontext.h" 00004 #include "commbreakmap.h" 00005 00006 #define LOC QString("CommBreakMap: ") 00007 00008 CommBreakMap::CommBreakMap(void) 00009 : commBreakMapLock(QMutex::Recursive), 00010 skipcommercials(0), autocommercialskip(kCommSkipOff), 00011 commrewindamount(0), commnotifyamount(0), 00012 lastCommSkipDirection(0), lastCommSkipTime(0/*1970*/), 00013 lastCommSkipStart(0), lastSkipTime(0 /*1970*/), 00014 hascommbreaktable(false), maxskip(3600), 00015 maxShortMerge(0), commBreakIter(commBreakMap.end()) 00016 { 00017 commrewindamount = gCoreContext->GetNumSetting("CommRewindAmount",0); 00018 commnotifyamount = gCoreContext->GetNumSetting("CommNotifyAmount",0); 00019 lastIgnoredManualSkip = QDateTime::currentDateTime().addSecs(-10); 00020 autocommercialskip = (CommSkipMode) 00021 gCoreContext->GetNumSetting("AutoCommercialSkip", kCommSkipOff); 00022 maxskip = gCoreContext->GetNumSetting("MaximumCommercialSkip", 3600); 00023 maxShortMerge = gCoreContext->GetNumSetting("MergeShortCommBreaks", 0); 00024 } 00025 00026 CommSkipMode CommBreakMap::GetAutoCommercialSkip(void) const 00027 { 00028 QMutexLocker locker(&commBreakMapLock); 00029 return autocommercialskip; 00030 } 00031 00032 void CommBreakMap::ResetLastSkip(void) 00033 { 00034 lastSkipTime = time(NULL); 00035 } 00036 00037 void CommBreakMap::SetAutoCommercialSkip(CommSkipMode autoskip, uint64_t framesplayed) 00038 { 00039 QMutexLocker locker(&commBreakMapLock); 00040 SetTracker(framesplayed); 00041 uint next = (kCommSkipIncr == autoskip) ? 00042 (uint) autocommercialskip + 1 : (uint) autoskip; 00043 autocommercialskip = (CommSkipMode) (next % kCommSkipCount); 00044 } 00045 00046 void CommBreakMap::SkipCommercials(int direction) 00047 { 00048 commBreakMapLock.lock(); 00049 if (skipcommercials == 0 && direction != 0) 00050 skipcommercials = direction; 00051 else if (skipcommercials != 0 && direction == 0) 00052 skipcommercials = direction; 00053 commBreakMapLock.unlock(); 00054 } 00055 00056 void CommBreakMap::LoadMap(PlayerContext *player_ctx, uint64_t framesPlayed) 00057 { 00058 if (!player_ctx) 00059 return; 00060 00061 QMutexLocker locker(&commBreakMapLock); 00062 player_ctx->LockPlayingInfo(__FILE__, __LINE__); 00063 if (player_ctx->playingInfo) 00064 { 00065 commBreakMap.clear(); 00066 player_ctx->playingInfo->QueryCommBreakList(commBreakMap); 00067 hascommbreaktable = !commBreakMap.isEmpty(); 00068 SetTracker(framesPlayed); 00069 } 00070 player_ctx->UnlockPlayingInfo(__FILE__, __LINE__); 00071 } 00072 00073 void CommBreakMap::SetTracker(uint64_t framesPlayed) 00074 { 00075 QMutexLocker locker(&commBreakMapLock); 00076 if (!hascommbreaktable) 00077 return; 00078 00079 commBreakIter = commBreakMap.begin(); 00080 while (commBreakIter != commBreakMap.end()) 00081 { 00082 if (framesPlayed <= commBreakIter.key()) 00083 break; 00084 00085 commBreakIter++; 00086 } 00087 00088 if (commBreakIter != commBreakMap.end()) 00089 { 00090 LOG(VB_COMMFLAG, LOG_INFO, LOC + 00091 QString("new commBreakIter = %1 @ frame %2, framesPlayed = %3") 00092 .arg(*commBreakIter).arg(commBreakIter.key()) 00093 .arg(framesPlayed)); 00094 } 00095 } 00096 00097 void CommBreakMap::GetMap(frm_dir_map_t &map) const 00098 { 00099 QMutexLocker locker(&commBreakMapLock); 00100 map.clear(); 00101 map = commBreakMap; 00102 map.detach(); 00103 } 00104 00105 bool CommBreakMap::IsInCommBreak(uint64_t frameNumber) const 00106 { 00107 QMutexLocker locker(&commBreakMapLock); 00108 if (commBreakMap.isEmpty()) 00109 return false; 00110 00111 frm_dir_map_t::const_iterator it = commBreakMap.find(frameNumber); 00112 if (it != commBreakMap.end()) 00113 return true; 00114 00115 int lastType = MARK_UNSET; 00116 for (it = commBreakMap.begin(); it != commBreakMap.end(); ++it) 00117 { 00118 if (it.key() > frameNumber) 00119 { 00120 int type = *it; 00121 00122 if (((type == MARK_COMM_END) || 00123 (type == MARK_CUT_END)) && 00124 ((lastType == MARK_COMM_START) || 00125 (lastType == MARK_CUT_START))) 00126 return true; 00127 00128 if ((type == MARK_COMM_START) || 00129 (type == MARK_CUT_START)) 00130 return false; 00131 } 00132 00133 lastType = *it; 00134 } 00135 return false; 00136 } 00137 00138 void CommBreakMap::SetMap(const frm_dir_map_t &newMap, uint64_t framesPlayed) 00139 { 00140 QMutexLocker locker(&commBreakMapLock); 00141 LOG(VB_COMMFLAG, LOG_INFO, LOC + 00142 QString("Setting New Commercial Break List, old size %1, new %2") 00143 .arg(commBreakMap.size()).arg(newMap.size())); 00144 00145 commBreakMap.clear(); 00146 commBreakMap = newMap; 00147 commBreakMap.detach(); 00148 hascommbreaktable = !commBreakMap.isEmpty(); 00149 SetTracker(framesPlayed); 00150 } 00151 00152 bool CommBreakMap::AutoCommercialSkip(uint64_t &jumpToFrame, 00153 uint64_t framesPlayed, 00154 double video_frame_rate, 00155 uint64_t totalFrames, 00156 QString &comm_msg) 00157 { 00158 QMutexLocker locker(&commBreakMapLock); 00159 if (!hascommbreaktable) 00160 return false; 00161 00162 if (((time(NULL) - lastSkipTime) <= 3) || 00163 ((time(NULL) - lastCommSkipTime) <= 3)) 00164 { 00165 SetTracker(framesPlayed); 00166 return false; 00167 } 00168 00169 if (commBreakIter == commBreakMap.end()) 00170 return false; 00171 00172 if (*commBreakIter == MARK_COMM_END) 00173 commBreakIter++; 00174 00175 if (commBreakIter == commBreakMap.end()) 00176 return false; 00177 00178 if (!((*commBreakIter == MARK_COMM_START) && 00179 (((kCommSkipOn == autocommercialskip) && 00180 (framesPlayed >= commBreakIter.key())) || 00181 ((kCommSkipNotify == autocommercialskip) && 00182 (framesPlayed + commnotifyamount * video_frame_rate >= 00183 commBreakIter.key()))))) 00184 { 00185 return false; 00186 } 00187 00188 LOG(VB_COMMFLAG, LOG_INFO, LOC + 00189 QString("AutoCommercialSkip(), current framesPlayed %1, commBreakIter " 00190 "frame %2, incrementing commBreakIter") 00191 .arg(framesPlayed).arg(commBreakIter.key())); 00192 00193 ++commBreakIter; 00194 00195 MergeShortCommercials(video_frame_rate); 00196 00197 if (commBreakIter == commBreakMap.end()) 00198 { 00199 LOG(VB_COMMFLAG, LOG_INFO, LOC + "AutoCommercialSkip(), at end of " 00200 "commercial break list, will not skip."); 00201 return false; 00202 } 00203 00204 if (*commBreakIter == MARK_COMM_START) 00205 { 00206 LOG(VB_COMMFLAG, LOG_INFO, LOC + "AutoCommercialSkip(), new " 00207 "commBreakIter mark is another start, " 00208 "will not skip."); 00209 return false; 00210 } 00211 00212 if (totalFrames && 00213 ((commBreakIter.key() + (10 * video_frame_rate)) > totalFrames)) 00214 { 00215 LOG(VB_COMMFLAG, LOG_INFO, LOC + "AutoCommercialSkip(), skipping would " 00216 "take us to the end of the file, will " 00217 "not skip."); 00218 return false; 00219 } 00220 00221 LOG(VB_COMMFLAG, LOG_INFO, LOC + 00222 QString("AutoCommercialSkip(), new commBreakIter frame %1") 00223 .arg(commBreakIter.key())); 00224 00225 int skipped_seconds = (int)((commBreakIter.key() - 00226 framesPlayed) / video_frame_rate); 00227 QString skipTime; 00228 skipTime.sprintf("%d:%02d", skipped_seconds / 60, 00229 abs(skipped_seconds) % 60); 00230 if (kCommSkipOn == autocommercialskip) 00231 comm_msg = QString(QObject::tr("Skip %1")).arg(skipTime); 00232 else 00233 comm_msg = QString(QObject::tr("Commercial: %1")).arg(skipTime); 00234 00235 if (kCommSkipOn == autocommercialskip) 00236 { 00237 LOG(VB_COMMFLAG, LOG_INFO, LOC + 00238 QString("AutoCommercialSkip(), auto-skipping to frame %1") 00239 .arg(commBreakIter.key() - 00240 (int)(commrewindamount * video_frame_rate))); 00241 00242 lastCommSkipDirection = 1; 00243 lastCommSkipStart = framesPlayed; 00244 lastCommSkipTime = time(NULL); 00245 00246 jumpToFrame = commBreakIter.key() - 00247 (int)(commrewindamount * video_frame_rate); 00248 return true; 00249 } 00250 ++commBreakIter; 00251 return false; 00252 } 00253 00254 bool CommBreakMap::DoSkipCommercials(uint64_t &jumpToFrame, 00255 uint64_t framesPlayed, 00256 double video_frame_rate, 00257 uint64_t totalFrames, QString &comm_msg) 00258 { 00259 QMutexLocker locker(&commBreakMapLock); 00260 if ((skipcommercials == (0 - lastCommSkipDirection)) && 00261 ((time(NULL) - lastCommSkipTime) <= 5)) 00262 { 00263 comm_msg = QObject::tr("Skipping Back."); 00264 00265 if (lastCommSkipStart > (2.0 * video_frame_rate)) 00266 lastCommSkipStart -= (long long) (2.0 * video_frame_rate); 00267 lastCommSkipDirection = 0; 00268 lastCommSkipTime = time(NULL); 00269 jumpToFrame = lastCommSkipStart; 00270 return true; 00271 } 00272 lastCommSkipDirection = skipcommercials; 00273 lastCommSkipStart = framesPlayed; 00274 lastCommSkipTime = time(NULL); 00275 00276 SetTracker(framesPlayed); 00277 00278 if ((commBreakIter == commBreakMap.begin()) && 00279 (skipcommercials < 0)) 00280 { 00281 comm_msg = QObject::tr("Start of program."); 00282 jumpToFrame = 0; 00283 return true; 00284 } 00285 00286 if ((skipcommercials > 0) && 00287 ((commBreakIter == commBreakMap.end()) || 00288 ((totalFrames) && 00289 ((commBreakIter.key() + (10 * video_frame_rate)) > totalFrames)))) 00290 { 00291 comm_msg = QObject::tr("At End, cannot Skip."); 00292 return false; 00293 } 00294 00295 if (skipcommercials < 0) 00296 { 00297 commBreakIter--; 00298 00299 int skipped_seconds = (int)(((int64_t)(commBreakIter.key()) - 00300 (int64_t)framesPlayed) / video_frame_rate); 00301 00302 // special case when hitting 'skip backwards' <3 seconds after break 00303 if (skipped_seconds > -3) 00304 { 00305 if (commBreakIter == commBreakMap.begin()) 00306 { 00307 comm_msg = QObject::tr("Start of program."); 00308 jumpToFrame = 0; 00309 return true; 00310 } 00311 else 00312 commBreakIter--; 00313 } 00314 } 00315 else 00316 { 00317 int skipped_seconds = (int)(((int64_t)(commBreakIter.key()) - 00318 (int64_t)framesPlayed) / video_frame_rate); 00319 00320 // special case when hitting 'skip' within 20 seconds of the break 00321 // start or within commrewindamount of the break end 00322 // Even though commrewindamount has a max of 10 per the settings UI, 00323 // check for MARK_COMM_END to make the code generic 00324 MarkTypes type = *commBreakIter; 00325 if (((type == MARK_COMM_START) && (skipped_seconds < 20)) || 00326 ((type == MARK_COMM_END) && (skipped_seconds < commrewindamount))) 00327 { 00328 commBreakIter++; 00329 00330 if ((commBreakIter == commBreakMap.end()) || 00331 ((totalFrames) && 00332 ((commBreakIter.key() + (10 * video_frame_rate)) > 00333 totalFrames))) 00334 { 00335 comm_msg = QObject::tr("At End, cannot Skip."); 00336 return false; 00337 } 00338 } 00339 } 00340 00341 if (skipcommercials > 0) 00342 MergeShortCommercials(video_frame_rate); 00343 int skipped_seconds = (int)(((int64_t)(commBreakIter.key()) - 00344 (int64_t)framesPlayed) / video_frame_rate); 00345 QString skipTime; 00346 skipTime.sprintf("%d:%02d", skipped_seconds / 60, 00347 abs(skipped_seconds) % 60); 00348 00349 if ((lastIgnoredManualSkip.secsTo(QDateTime::currentDateTime()) > 3) && 00350 (abs(skipped_seconds) >= maxskip)) 00351 { 00352 comm_msg = QObject::tr("Too Far %1").arg(skipTime); 00353 lastIgnoredManualSkip = QDateTime::currentDateTime(); 00354 return false; 00355 } 00356 comm_msg = QObject::tr("Skip %1").arg(skipTime); 00357 00358 uint64_t jumpto = (skipcommercials > 0) ? 00359 commBreakIter.key() - (long long)(commrewindamount * video_frame_rate): 00360 commBreakIter.key(); 00361 commBreakIter++; 00362 jumpToFrame = jumpto; 00363 return true; 00364 } 00365 00366 void CommBreakMap::MergeShortCommercials(double video_frame_rate) 00367 { 00368 double maxMerge = maxShortMerge * video_frame_rate; 00369 if (maxMerge <= 0.0 || (commBreakIter == commBreakMap.end())) 00370 return; 00371 00372 long long lastFrame = commBreakIter.key(); 00373 ++commBreakIter; 00374 while ((commBreakIter != commBreakMap.end()) && 00375 (commBreakIter.key() - lastFrame < maxMerge)) 00376 { 00377 ++commBreakIter; 00378 } 00379 --commBreakIter; 00380 }
1.7.6.1