MythTV  0.26-pre
commbreakmap.cpp
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends