MythTV  master
commbreakmap.cpp
Go to the documentation of this file.
1 
2 #include "commbreakmap.h"
3 
4 #include "mythcontext.h"
5 #include "programinfo.h"
6 
7 #define LOC QString("CommBreakMap: ")
8 
10  : m_commBreakIter(m_commBreakMap.end())
11 {
12  m_commrewindamount = gCoreContext->GetNumSetting("CommRewindAmount",0);
13  m_commnotifyamount = gCoreContext->GetNumSetting("CommNotifyAmount",0);
16  gCoreContext->GetNumSetting("AutoCommercialSkip", kCommSkipOff);
17  m_maxskip = gCoreContext->GetNumSetting("MaximumCommercialSkip", 3600);
18  m_maxShortMerge = gCoreContext->GetNumSetting("MergeShortCommBreaks", 0);
19 }
20 
22 {
23  QMutexLocker locker(&m_commBreakMapLock);
24  return m_autocommercialskip;
25 }
26 
28 {
29  m_lastSkipTime = time(nullptr);
30 }
31 
32 void CommBreakMap::SetAutoCommercialSkip(CommSkipMode autoskip, uint64_t framesplayed)
33 {
34  QMutexLocker locker(&m_commBreakMapLock);
35  SetTracker(framesplayed);
36  uint next = (kCommSkipIncr == autoskip) ?
37  (uint) m_autocommercialskip + 1 : (uint) autoskip;
39 }
40 
41 void CommBreakMap::SkipCommercials(int direction)
42 {
43  m_commBreakMapLock.lock();
44  if ((m_skipcommercials == 0 && direction != 0) ||
45  (m_skipcommercials != 0 && direction == 0))
46  m_skipcommercials = direction;
47  m_commBreakMapLock.unlock();
48 }
49 
50 void CommBreakMap::LoadMap(PlayerContext *player_ctx, uint64_t framesPlayed)
51 {
52  if (!player_ctx)
53  return;
54 
55  QMutexLocker locker(&m_commBreakMapLock);
56  player_ctx->LockPlayingInfo(__FILE__, __LINE__);
57  if (player_ctx->m_playingInfo)
58  {
59  m_commBreakMap.clear();
62  SetTracker(framesPlayed);
63  }
64  player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
65 }
66 
67 void CommBreakMap::SetTracker(uint64_t framesPlayed)
68 {
69  QMutexLocker locker(&m_commBreakMapLock);
71  return;
72 
74  while (m_commBreakIter != m_commBreakMap.end())
75  {
76  if (framesPlayed <= m_commBreakIter.key())
77  break;
78 
80  }
81 
82  if (m_commBreakIter != m_commBreakMap.end())
83  {
84  LOG(VB_COMMFLAG, LOG_INFO, LOC +
85  QString("new commBreakIter = %1 @ frame %2, framesPlayed = %3")
86  .arg(*m_commBreakIter).arg(m_commBreakIter.key())
87  .arg(framesPlayed));
88  }
89 }
90 
92 {
93  QMutexLocker locker(&m_commBreakMapLock);
94  map.clear();
95  map = m_commBreakMap;
96 }
97 
98 bool CommBreakMap::IsInCommBreak(uint64_t frameNumber) const
99 {
100  QMutexLocker locker(&m_commBreakMapLock);
101  if (m_commBreakMap.isEmpty())
102  return false;
103 
104  frm_dir_map_t::const_iterator it = m_commBreakMap.find(frameNumber);
105  if (it != m_commBreakMap.end())
106  return true;
107 
108  int lastType = MARK_UNSET;
109  for (it = m_commBreakMap.begin(); it != m_commBreakMap.end(); ++it)
110  {
111  if (it.key() > frameNumber)
112  {
113  int type = *it;
114 
115  if (((type == MARK_COMM_END) ||
116  (type == MARK_CUT_END)) &&
117  ((lastType == MARK_COMM_START) ||
118  (lastType == MARK_CUT_START)))
119  return true;
120 
121  if ((type == MARK_COMM_START) ||
122  (type == MARK_CUT_START))
123  return false;
124  }
125 
126  lastType = *it;
127  }
128  return false;
129 }
130 
131 void CommBreakMap::SetMap(const frm_dir_map_t &newMap, uint64_t framesPlayed)
132 {
133  QMutexLocker locker(&m_commBreakMapLock);
134  LOG(VB_COMMFLAG, LOG_INFO, LOC +
135  QString("Setting New Commercial Break List, old size %1, new %2")
136  .arg(m_commBreakMap.size()).arg(newMap.size()));
137 
138  m_commBreakMap.clear();
139  m_commBreakMap = newMap;
140  m_hascommbreaktable = !m_commBreakMap.isEmpty();
141  SetTracker(framesPlayed);
142 }
143 
144 bool CommBreakMap::AutoCommercialSkip(uint64_t &jumpToFrame,
145  uint64_t framesPlayed,
146  double video_frame_rate,
147  uint64_t totalFrames,
148  QString &comm_msg)
149 {
150  QMutexLocker locker(&m_commBreakMapLock);
151  if (!m_hascommbreaktable)
152  return false;
153 
154  if (((time(nullptr) - m_lastSkipTime) <= 3) ||
155  ((time(nullptr) - m_lastCommSkipTime) <= 3))
156  {
157  SetTracker(framesPlayed);
158  return false;
159  }
160 
161  if (m_commBreakIter == m_commBreakMap.end())
162  return false;
163 
165  m_commBreakIter++;
166 
167  if (m_commBreakIter == m_commBreakMap.end())
168  return false;
169 
170  if (!((*m_commBreakIter == MARK_COMM_START) &&
172  (framesPlayed >= m_commBreakIter.key())) ||
174  (framesPlayed + m_commnotifyamount * video_frame_rate >=
175  m_commBreakIter.key())))))
176  {
177  return false;
178  }
179 
180  LOG(VB_COMMFLAG, LOG_INFO, LOC +
181  QString("AutoCommercialSkip(), current framesPlayed %1, commBreakIter "
182  "frame %2, incrementing commBreakIter")
183  .arg(framesPlayed).arg(m_commBreakIter.key()));
184 
185  ++m_commBreakIter;
186 
187  MergeShortCommercials(video_frame_rate);
188 
189  if (m_commBreakIter == m_commBreakMap.end())
190  {
191  LOG(VB_COMMFLAG, LOG_INFO, LOC + "AutoCommercialSkip(), at end of "
192  "commercial break list, will not skip.");
193  return false;
194  }
195 
197  {
198  LOG(VB_COMMFLAG, LOG_INFO, LOC + "AutoCommercialSkip(), new "
199  "commBreakIter mark is another start, "
200  "will not skip.");
201  return false;
202  }
203 
204  if (totalFrames &&
205  ((m_commBreakIter.key() + (10 * video_frame_rate)) > totalFrames))
206  {
207  LOG(VB_COMMFLAG, LOG_INFO, LOC + "AutoCommercialSkip(), skipping would "
208  "take us to the end of the file, will "
209  "not skip.");
210  return false;
211  }
212 
213  LOG(VB_COMMFLAG, LOG_INFO, LOC +
214  QString("AutoCommercialSkip(), new commBreakIter frame %1")
215  .arg(m_commBreakIter.key()));
216 
217  int skipped_seconds = (int)((m_commBreakIter.key() -
218  framesPlayed) / video_frame_rate);
219  QString skipTime = QString("%1:%2")
220  .arg(skipped_seconds / 60)
221  .arg(abs(skipped_seconds) % 60, 2, 10, QChar('0'));
223  {
224  //: %1 is the skip time
225  comm_msg = tr("Skip %1").arg(skipTime);
226  }
227  else
228  {
229  //: %1 is the skip time
230  comm_msg = tr("Commercial: %1").arg(skipTime);
231  }
232 
234  {
235  LOG(VB_COMMFLAG, LOG_INFO, LOC +
236  QString("AutoCommercialSkip(), auto-skipping to frame %1")
237  .arg(m_commBreakIter.key() -
238  (int)(m_commrewindamount * video_frame_rate)));
239 
241  m_lastCommSkipStart = framesPlayed;
242  m_lastCommSkipTime = time(nullptr);
243 
244  jumpToFrame = m_commBreakIter.key() -
245  (int)(m_commrewindamount * video_frame_rate);
246  return true;
247  }
248  ++m_commBreakIter;
249  return false;
250 }
251 
252 bool CommBreakMap::DoSkipCommercials(uint64_t &jumpToFrame,
253  uint64_t framesPlayed,
254  double video_frame_rate,
255  uint64_t totalFrames, QString &comm_msg)
256 {
257  QMutexLocker locker(&m_commBreakMapLock);
259  ((time(nullptr) - m_lastCommSkipTime) <= 5))
260  {
261  comm_msg = tr("Skipping Back.");
262 
263  if (m_lastCommSkipStart > (2.0 * video_frame_rate))
264  m_lastCommSkipStart -= (long long) (2.0 * video_frame_rate);
266  m_lastCommSkipTime = time(nullptr);
267  jumpToFrame = m_lastCommSkipStart;
268  return true;
269  }
271  m_lastCommSkipStart = framesPlayed;
272  m_lastCommSkipTime = time(nullptr);
273 
274  SetTracker(framesPlayed);
275 
276  if ((m_commBreakIter == m_commBreakMap.begin()) &&
277  (m_skipcommercials < 0))
278  {
279  comm_msg = tr("Start of program.");
280  jumpToFrame = 0;
281  return true;
282  }
283 
284  if ((m_skipcommercials > 0) &&
285  ((m_commBreakIter == m_commBreakMap.end()) ||
286  ((totalFrames) &&
287  ((m_commBreakIter.key() + (10 * video_frame_rate)) > totalFrames))))
288  {
289  comm_msg = tr("At End, cannot Skip.");
290  return false;
291  }
292 
293  if (m_skipcommercials < 0)
294  {
295  m_commBreakIter--;
296 
297  int skipped_seconds = (int)(((int64_t)(m_commBreakIter.key()) -
298  (int64_t)framesPlayed) / video_frame_rate);
299 
300  // special case when hitting 'skip backwards' <3 seconds after break
301  if (skipped_seconds > -3)
302  {
303  if (m_commBreakIter == m_commBreakMap.begin())
304  {
305  comm_msg = tr("Start of program.");
306  jumpToFrame = 0;
307  return true;
308  }
309  m_commBreakIter--;
310  }
311  }
312  else
313  {
314  int skipped_seconds = (int)(((int64_t)(m_commBreakIter.key()) -
315  (int64_t)framesPlayed) / video_frame_rate);
316 
317  // special case when hitting 'skip' within 20 seconds of the break
318  // start or within commrewindamount of the break end
319  // Even though commrewindamount has a max of 10 per the settings UI,
320  // check for MARK_COMM_END to make the code generic
322  if (((type == MARK_COMM_START) && (skipped_seconds < 20)) ||
323  ((type == MARK_COMM_END) && (skipped_seconds < m_commrewindamount)))
324  {
325  m_commBreakIter++;
326 
327  if ((m_commBreakIter == m_commBreakMap.end()) ||
328  ((totalFrames) &&
329  ((m_commBreakIter.key() + (10 * video_frame_rate)) >
330  totalFrames)))
331  {
332  comm_msg = tr("At End, cannot Skip.");
333  return false;
334  }
335  }
336  }
337 
338  if (m_skipcommercials > 0)
339  MergeShortCommercials(video_frame_rate);
340  int skipped_seconds = (int)(((int64_t)(m_commBreakIter.key()) -
341  (int64_t)framesPlayed) / video_frame_rate);
342  QString skipTime = QString("%1:%2")
343  .arg(skipped_seconds / 60)
344  .arg(abs(skipped_seconds) % 60, 2, 10, QChar('0'));
345 
346  if ((m_lastIgnoredManualSkip.secsTo(MythDate::current()) > 3) &&
347  (abs(skipped_seconds) >= m_maxskip))
348  {
349  //: %1 is the skip time
350  comm_msg = tr("Too Far %1").arg(skipTime);
352  return false;
353  }
354 
355  //: %1 is the skip time
356  comm_msg = tr("Skip %1").arg(skipTime);
357 
358  uint64_t jumpto = (m_skipcommercials > 0) ?
359  m_commBreakIter.key() - (long long)(m_commrewindamount * video_frame_rate):
360  m_commBreakIter.key();
361  m_commBreakIter++;
362  jumpToFrame = jumpto;
363  return true;
364 }
365 
366 void CommBreakMap::MergeShortCommercials(double video_frame_rate)
367 {
368  double maxMerge = m_maxShortMerge * video_frame_rate;
369  if (maxMerge <= 0.0 || (m_commBreakIter == m_commBreakMap.end()))
370  return;
371 
372  long long lastFrame = m_commBreakIter.key();
373  ++m_commBreakIter;
374  while ((m_commBreakIter != m_commBreakMap.end()) &&
375  (m_commBreakIter.key() - lastFrame < maxMerge))
376  {
377  ++m_commBreakIter;
378  }
379  --m_commBreakIter;
380 }
int m_commrewindamount
Definition: commbreakmap.h:54
CommSkipMode m_autocommercialskip
Definition: commbreakmap.h:53
time_t m_lastCommSkipTime
Definition: commbreakmap.h:57
void UnlockPlayingInfo(const char *file, int line) const
void SkipCommercials(int direction)
uint64_t m_lastCommSkipStart
Definition: commbreakmap.h:58
void SetMap(const frm_dir_map_t &newMap, uint64_t framesPlayed)
int m_skipcommercials
Definition: commbreakmap.h:52
void QueryCommBreakList(frm_dir_map_t &) const
void SetAutoCommercialSkip(CommSkipMode autoskip, uint64_t framesPlayed)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
QMutex m_commBreakMapLock
Definition: commbreakmap.h:51
void GetMap(frm_dir_map_t &map) const
void ResetLastSkip(void)
MarkTypes
Definition: programtypes.h:48
ProgramInfo * m_playingInfo
Currently playing info.
void SetTracker(uint64_t framesPlayed)
CommSkipMode
Definition: tv.h:130
int m_commnotifyamount
Definition: commbreakmap.h:55
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
bool AutoCommercialSkip(uint64_t &jumpToFrame, uint64_t framesPlayed, double video_frame_rate, uint64_t totalFrames, QString &comm_msg)
void LockPlayingInfo(const char *file, int line) const
CommBreakMap(void)
Definition: commbreakmap.cpp:9
bool DoSkipCommercials(uint64_t &jumpToFrame, uint64_t framesPlayed, double video_frame_rate, uint64_t totalFrames, QString &comm_msg)
unsigned int uint
Definition: compat.h:140
frm_dir_map_t::Iterator m_commBreakIter
Definition: commbreakmap.h:65
frm_dir_map_t m_commBreakMap
Definition: commbreakmap.h:64
int m_maxShortMerge
Definition: commbreakmap.h:63
PictureAttribute next(PictureAttributeSupported supported, PictureAttribute attribute)
int GetNumSetting(const QString &key, int defaultval=0)
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
bool m_hascommbreaktable
Definition: commbreakmap.h:60
QDateTime m_lastIgnoredManualSkip
Definition: commbreakmap.h:61
void MergeShortCommercials(double video_frame_rate)
CommSkipMode GetAutoCommercialSkip(void) const
int m_lastCommSkipDirection
Definition: commbreakmap.h:56
QMap< uint64_t, MarkTypes > frm_dir_map_t
Frame # -> Mark map.
Definition: programtypes.h:81
#define LOC
Definition: commbreakmap.cpp:7
void LoadMap(PlayerContext *player_ctx, uint64_t framesPlayed)
time_t m_lastSkipTime
Definition: commbreakmap.h:59
bool IsInCommBreak(uint64_t frameNumber) const