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 = direction;
46  else if (m_skipcommercials != 0 && direction == 0)
47  m_skipcommercials = direction;
48  m_commBreakMapLock.unlock();
49 }
50 
51 void CommBreakMap::LoadMap(PlayerContext *player_ctx, uint64_t framesPlayed)
52 {
53  if (!player_ctx)
54  return;
55 
56  QMutexLocker locker(&m_commBreakMapLock);
57  player_ctx->LockPlayingInfo(__FILE__, __LINE__);
58  if (player_ctx->m_playingInfo)
59  {
60  m_commBreakMap.clear();
63  SetTracker(framesPlayed);
64  }
65  player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
66 }
67 
68 void CommBreakMap::SetTracker(uint64_t framesPlayed)
69 {
70  QMutexLocker locker(&m_commBreakMapLock);
72  return;
73 
75  while (m_commBreakIter != m_commBreakMap.end())
76  {
77  if (framesPlayed <= m_commBreakIter.key())
78  break;
79 
81  }
82 
83  if (m_commBreakIter != m_commBreakMap.end())
84  {
85  LOG(VB_COMMFLAG, LOG_INFO, LOC +
86  QString("new commBreakIter = %1 @ frame %2, framesPlayed = %3")
87  .arg(*m_commBreakIter).arg(m_commBreakIter.key())
88  .arg(framesPlayed));
89  }
90 }
91 
93 {
94  QMutexLocker locker(&m_commBreakMapLock);
95  map.clear();
96  map = m_commBreakMap;
97 }
98 
99 bool CommBreakMap::IsInCommBreak(uint64_t frameNumber) const
100 {
101  QMutexLocker locker(&m_commBreakMapLock);
102  if (m_commBreakMap.isEmpty())
103  return false;
104 
105  frm_dir_map_t::const_iterator it = m_commBreakMap.find(frameNumber);
106  if (it != m_commBreakMap.end())
107  return true;
108 
109  int lastType = MARK_UNSET;
110  for (it = m_commBreakMap.begin(); it != m_commBreakMap.end(); ++it)
111  {
112  if (it.key() > frameNumber)
113  {
114  int type = *it;
115 
116  if (((type == MARK_COMM_END) ||
117  (type == MARK_CUT_END)) &&
118  ((lastType == MARK_COMM_START) ||
119  (lastType == MARK_CUT_START)))
120  return true;
121 
122  if ((type == MARK_COMM_START) ||
123  (type == MARK_CUT_START))
124  return false;
125  }
126 
127  lastType = *it;
128  }
129  return false;
130 }
131 
132 void CommBreakMap::SetMap(const frm_dir_map_t &newMap, uint64_t framesPlayed)
133 {
134  QMutexLocker locker(&m_commBreakMapLock);
135  LOG(VB_COMMFLAG, LOG_INFO, LOC +
136  QString("Setting New Commercial Break List, old size %1, new %2")
137  .arg(m_commBreakMap.size()).arg(newMap.size()));
138 
139  m_commBreakMap.clear();
140  m_commBreakMap = newMap;
141  m_hascommbreaktable = !m_commBreakMap.isEmpty();
142  SetTracker(framesPlayed);
143 }
144 
145 bool CommBreakMap::AutoCommercialSkip(uint64_t &jumpToFrame,
146  uint64_t framesPlayed,
147  double video_frame_rate,
148  uint64_t totalFrames,
149  QString &comm_msg)
150 {
151  QMutexLocker locker(&m_commBreakMapLock);
152  if (!m_hascommbreaktable)
153  return false;
154 
155  if (((time(nullptr) - m_lastSkipTime) <= 3) ||
156  ((time(nullptr) - m_lastCommSkipTime) <= 3))
157  {
158  SetTracker(framesPlayed);
159  return false;
160  }
161 
162  if (m_commBreakIter == m_commBreakMap.end())
163  return false;
164 
166  m_commBreakIter++;
167 
168  if (m_commBreakIter == m_commBreakMap.end())
169  return false;
170 
171  if (!((*m_commBreakIter == MARK_COMM_START) &&
173  (framesPlayed >= m_commBreakIter.key())) ||
175  (framesPlayed + m_commnotifyamount * video_frame_rate >=
176  m_commBreakIter.key())))))
177  {
178  return false;
179  }
180 
181  LOG(VB_COMMFLAG, LOG_INFO, LOC +
182  QString("AutoCommercialSkip(), current framesPlayed %1, commBreakIter "
183  "frame %2, incrementing commBreakIter")
184  .arg(framesPlayed).arg(m_commBreakIter.key()));
185 
186  ++m_commBreakIter;
187 
188  MergeShortCommercials(video_frame_rate);
189 
190  if (m_commBreakIter == m_commBreakMap.end())
191  {
192  LOG(VB_COMMFLAG, LOG_INFO, LOC + "AutoCommercialSkip(), at end of "
193  "commercial break list, will not skip.");
194  return false;
195  }
196 
198  {
199  LOG(VB_COMMFLAG, LOG_INFO, LOC + "AutoCommercialSkip(), new "
200  "commBreakIter mark is another start, "
201  "will not skip.");
202  return false;
203  }
204 
205  if (totalFrames &&
206  ((m_commBreakIter.key() + (10 * video_frame_rate)) > totalFrames))
207  {
208  LOG(VB_COMMFLAG, LOG_INFO, LOC + "AutoCommercialSkip(), skipping would "
209  "take us to the end of the file, will "
210  "not skip.");
211  return false;
212  }
213 
214  LOG(VB_COMMFLAG, LOG_INFO, LOC +
215  QString("AutoCommercialSkip(), new commBreakIter frame %1")
216  .arg(m_commBreakIter.key()));
217 
218  int skipped_seconds = (int)((m_commBreakIter.key() -
219  framesPlayed) / video_frame_rate);
220  QString skipTime = QString("%1:%2")
221  .arg(skipped_seconds / 60)
222  .arg(abs(skipped_seconds) % 60, 2, 10, QChar('0'));
224  {
225  //: %1 is the skip time
226  comm_msg = tr("Skip %1").arg(skipTime);
227  }
228  else
229  {
230  //: %1 is the skip time
231  comm_msg = tr("Commercial: %1").arg(skipTime);
232  }
233 
235  {
236  LOG(VB_COMMFLAG, LOG_INFO, LOC +
237  QString("AutoCommercialSkip(), auto-skipping to frame %1")
238  .arg(m_commBreakIter.key() -
239  (int)(m_commrewindamount * video_frame_rate)));
240 
242  m_lastCommSkipStart = framesPlayed;
243  m_lastCommSkipTime = time(nullptr);
244 
245  jumpToFrame = m_commBreakIter.key() -
246  (int)(m_commrewindamount * video_frame_rate);
247  return true;
248  }
249  ++m_commBreakIter;
250  return false;
251 }
252 
253 bool CommBreakMap::DoSkipCommercials(uint64_t &jumpToFrame,
254  uint64_t framesPlayed,
255  double video_frame_rate,
256  uint64_t totalFrames, QString &comm_msg)
257 {
258  QMutexLocker locker(&m_commBreakMapLock);
260  ((time(nullptr) - m_lastCommSkipTime) <= 5))
261  {
262  comm_msg = tr("Skipping Back.");
263 
264  if (m_lastCommSkipStart > (2.0 * video_frame_rate))
265  m_lastCommSkipStart -= (long long) (2.0 * video_frame_rate);
267  m_lastCommSkipTime = time(nullptr);
268  jumpToFrame = m_lastCommSkipStart;
269  return true;
270  }
272  m_lastCommSkipStart = framesPlayed;
273  m_lastCommSkipTime = time(nullptr);
274 
275  SetTracker(framesPlayed);
276 
277  if ((m_commBreakIter == m_commBreakMap.begin()) &&
278  (m_skipcommercials < 0))
279  {
280  comm_msg = tr("Start of program.");
281  jumpToFrame = 0;
282  return true;
283  }
284 
285  if ((m_skipcommercials > 0) &&
286  ((m_commBreakIter == m_commBreakMap.end()) ||
287  ((totalFrames) &&
288  ((m_commBreakIter.key() + (10 * video_frame_rate)) > totalFrames))))
289  {
290  comm_msg = tr("At End, cannot Skip.");
291  return false;
292  }
293 
294  if (m_skipcommercials < 0)
295  {
296  m_commBreakIter--;
297 
298  int skipped_seconds = (int)(((int64_t)(m_commBreakIter.key()) -
299  (int64_t)framesPlayed) / video_frame_rate);
300 
301  // special case when hitting 'skip backwards' <3 seconds after break
302  if (skipped_seconds > -3)
303  {
304  if (m_commBreakIter == m_commBreakMap.begin())
305  {
306  comm_msg = tr("Start of program.");
307  jumpToFrame = 0;
308  return true;
309  }
310  m_commBreakIter--;
311  }
312  }
313  else
314  {
315  int skipped_seconds = (int)(((int64_t)(m_commBreakIter.key()) -
316  (int64_t)framesPlayed) / video_frame_rate);
317 
318  // special case when hitting 'skip' within 20 seconds of the break
319  // start or within commrewindamount of the break end
320  // Even though commrewindamount has a max of 10 per the settings UI,
321  // check for MARK_COMM_END to make the code generic
323  if (((type == MARK_COMM_START) && (skipped_seconds < 20)) ||
324  ((type == MARK_COMM_END) && (skipped_seconds < m_commrewindamount)))
325  {
326  m_commBreakIter++;
327 
328  if ((m_commBreakIter == m_commBreakMap.end()) ||
329  ((totalFrames) &&
330  ((m_commBreakIter.key() + (10 * video_frame_rate)) >
331  totalFrames)))
332  {
333  comm_msg = tr("At End, cannot Skip.");
334  return false;
335  }
336  }
337  }
338 
339  if (m_skipcommercials > 0)
340  MergeShortCommercials(video_frame_rate);
341  int skipped_seconds = (int)(((int64_t)(m_commBreakIter.key()) -
342  (int64_t)framesPlayed) / video_frame_rate);
343  QString skipTime = QString("%1:%2")
344  .arg(skipped_seconds / 60)
345  .arg(abs(skipped_seconds) % 60, 2, 10, QChar('0'));
346 
347  if ((m_lastIgnoredManualSkip.secsTo(MythDate::current()) > 3) &&
348  (abs(skipped_seconds) >= m_maxskip))
349  {
350  //: %1 is the skip time
351  comm_msg = tr("Too Far %1").arg(skipTime);
353  return false;
354  }
355 
356  //: %1 is the skip time
357  comm_msg = tr("Skip %1").arg(skipTime);
358 
359  uint64_t jumpto = (m_skipcommercials > 0) ?
360  m_commBreakIter.key() - (long long)(m_commrewindamount * video_frame_rate):
361  m_commBreakIter.key();
362  m_commBreakIter++;
363  jumpToFrame = jumpto;
364  return true;
365 }
366 
367 void CommBreakMap::MergeShortCommercials(double video_frame_rate)
368 {
369  double maxMerge = m_maxShortMerge * video_frame_rate;
370  if (maxMerge <= 0.0 || (m_commBreakIter == m_commBreakMap.end()))
371  return;
372 
373  long long lastFrame = m_commBreakIter.key();
374  ++m_commBreakIter;
375  while ((m_commBreakIter != m_commBreakMap.end()) &&
376  (m_commBreakIter.key() - lastFrame < maxMerge))
377  {
378  ++m_commBreakIter;
379  }
380  --m_commBreakIter;
381 }
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)
QMap< uint64_t, MarkTypes > frm_dir_map_t
Frame # -> Mark map.
Definition: programtypes.h:81
unsigned int uint
Definition: compat.h:140
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)
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
#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