MythTV  master
commbreakmap.cpp
Go to the documentation of this file.
1 // MythTV
2 #include "libmyth/mythcontext.h"
3 #include "libmythbase/mythdate.h"
5 
6 #include "commbreakmap.h"
7 
8 #define LOC QString("CommBreakMap: ")
9 
11  : m_autocommercialskip(static_cast<CommSkipMode>(gCoreContext->GetNumSetting("AutoCommercialSkip", kCommSkipOff))),
12  m_commrewindamount(gCoreContext->GetDurSetting<std::chrono::seconds>("CommRewindAmount",0s)),
13  m_commnotifyamount(gCoreContext->GetDurSetting<std::chrono::seconds>("CommNotifyAmount",0s)),
14  m_lastIgnoredManualSkip(MythDate::current().addSecs(-10)),
15  m_maxskip(gCoreContext->GetDurSetting<std::chrono::seconds>("MaximumCommercialSkip", 1h)),
16  m_maxShortMerge(gCoreContext->GetDurSetting<std::chrono::seconds>("MergeShortCommBreaks", 0s)),
17  m_commBreakIter(m_commBreakMap.end())
18 {
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.count() * 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  auto skipped_seconds = std::chrono::seconds((int)((m_commBreakIter.key() -
218  framesPlayed) / video_frame_rate));
219  QString skipTime = MythDate::formatTime(skipped_seconds, "m:ss");
221  {
222  //: %1 is the skip time
223  comm_msg = tr("Skip %1").arg(skipTime);
224  }
225  else
226  {
227  //: %1 is the skip time
228  comm_msg = tr("Commercial: %1").arg(skipTime);
229  }
230 
232  {
233  int framediff = (int)(m_commrewindamount.count() * video_frame_rate);
234  LOG(VB_COMMFLAG, LOG_INFO, LOC +
235  QString("AutoCommercialSkip(), auto-skipping to frame %1")
236  .arg(m_commBreakIter.key() - framediff));
237 
239  m_lastCommSkipStart = framesPlayed;
240  m_lastCommSkipTime = time(nullptr);
241 
242  jumpToFrame = m_commBreakIter.key() - framediff;
243  return true;
244  }
245  ++m_commBreakIter;
246  return false;
247 }
248 
249 bool CommBreakMap::DoSkipCommercials(uint64_t &jumpToFrame,
250  uint64_t framesPlayed,
251  double video_frame_rate,
252  uint64_t totalFrames, QString &comm_msg)
253 {
254  QMutexLocker locker(&m_commBreakMapLock);
256  ((time(nullptr) - m_lastCommSkipTime) <= 5))
257  {
258  comm_msg = tr("Skipping Back.");
259 
260  if (m_lastCommSkipStart > (2.0 * video_frame_rate))
261  m_lastCommSkipStart -= (long long) (2.0 * video_frame_rate);
263  m_lastCommSkipTime = time(nullptr);
264  jumpToFrame = m_lastCommSkipStart;
265  return true;
266  }
268  m_lastCommSkipStart = framesPlayed;
269  m_lastCommSkipTime = time(nullptr);
270 
271  SetTracker(framesPlayed);
272 
273  if ((m_commBreakIter == m_commBreakMap.begin()) &&
274  (m_skipcommercials < 0))
275  {
276  comm_msg = tr("Start of program.");
277  jumpToFrame = 0;
278  return true;
279  }
280 
281  if ((m_skipcommercials > 0) &&
282  ((m_commBreakIter == m_commBreakMap.end()) ||
283  (((totalFrames) != 0U) &&
284  ((m_commBreakIter.key() + (10 * video_frame_rate)) > totalFrames))))
285  {
286  comm_msg = tr("At End, cannot Skip.");
287  return false;
288  }
289 
290  if (m_skipcommercials < 0)
291  {
292  m_commBreakIter--;
293 
294  int skipped_seconds = (int)(((int64_t)(m_commBreakIter.key()) -
295  (int64_t)framesPlayed) / video_frame_rate);
296 
297  // special case when hitting 'skip backwards' <3 seconds after break
298  if (skipped_seconds > -3)
299  {
300  if (m_commBreakIter == m_commBreakMap.begin())
301  {
302  comm_msg = tr("Start of program.");
303  jumpToFrame = 0;
304  return true;
305  }
306  m_commBreakIter--;
307  }
308  }
309  else
310  {
311  int64_t framediff = m_commBreakIter.key() - framesPlayed;
312  auto skipped_seconds = std::chrono::seconds((int)(framediff / video_frame_rate));
313 
314  // special case when hitting 'skip' within 20 seconds of the break
315  // start or within commrewindamount of the break end
316  // Even though commrewindamount has a max of 10 per the settings UI,
317  // check for MARK_COMM_END to make the code generic
319  if (((type == MARK_COMM_START) && (skipped_seconds < 20s)) ||
320  ((type == MARK_COMM_END) && (skipped_seconds < m_commrewindamount)))
321  {
322  m_commBreakIter++;
323 
324  if ((m_commBreakIter == m_commBreakMap.end()) ||
325  (((totalFrames) != 0U) &&
326  ((m_commBreakIter.key() + (10 * video_frame_rate)) >
327  totalFrames)))
328  {
329  comm_msg = tr("At End, cannot Skip.");
330  return false;
331  }
332  }
333  }
334 
335  if (m_skipcommercials > 0)
336  MergeShortCommercials(video_frame_rate);
337  int64_t framediff = m_commBreakIter.key() - framesPlayed;
338  auto skipped_seconds = std::chrono::seconds((int)(framediff / video_frame_rate));
339  QString skipTime = MythDate::formatTime(skipped_seconds, "m:ss");
340 
342  (abs(skipped_seconds) >= m_maxskip))
343  {
344  //: %1 is the skip time
345  comm_msg = tr("Too Far %1").arg(skipTime);
347  return false;
348  }
349 
350  //: %1 is the skip time
351  comm_msg = tr("Skip %1").arg(skipTime);
352 
353  uint64_t jumpto = (m_skipcommercials > 0) ?
354  m_commBreakIter.key() - (long long)(m_commrewindamount.count() * video_frame_rate):
355  m_commBreakIter.key();
356  m_commBreakIter++;
357  jumpToFrame = jumpto;
358  return true;
359 }
360 
361 void CommBreakMap::MergeShortCommercials(double video_frame_rate)
362 {
363  double maxMerge = m_maxShortMerge.count() * video_frame_rate;
364  if (maxMerge <= 0.0 || (m_commBreakIter == m_commBreakMap.end()))
365  return;
366 
367  long long lastFrame = m_commBreakIter.key();
368  ++m_commBreakIter;
369  while ((m_commBreakIter != m_commBreakMap.end()) &&
370  (m_commBreakIter.key() - lastFrame < maxMerge))
371  {
372  ++m_commBreakIter;
373  }
374  --m_commBreakIter;
375 }
CommBreakMap::m_skipcommercials
int m_skipcommercials
Definition: commbreakmap.h:51
CommBreakMap::m_lastSkipTime
time_t m_lastSkipTime
Definition: commbreakmap.h:58
MARK_COMM_END
@ MARK_COMM_END
Definition: programtypes.h:60
commbreakmap.h
PlayerContext::UnlockPlayingInfo
void UnlockPlayingInfo(const char *file, int line) const
Definition: playercontext.cpp:249
CommBreakMap::DoSkipCommercials
bool DoSkipCommercials(uint64_t &jumpToFrame, uint64_t framesPlayed, double video_frame_rate, uint64_t totalFrames, QString &comm_msg)
Definition: commbreakmap.cpp:249
MarkTypes
MarkTypes
Definition: programtypes.h:47
CommBreakMap::SetTracker
void SetTracker(uint64_t framesPlayed)
Definition: commbreakmap.cpp:67
CommBreakMap::MergeShortCommercials
void MergeShortCommercials(double video_frame_rate)
Definition: commbreakmap.cpp:361
frm_dir_map_t
QMap< uint64_t, MarkTypes > frm_dir_map_t
Frame # -> Mark map.
Definition: programtypes.h:118
MythDate::formatTime
QString formatTime(std::chrono::milliseconds msecs, QString fmt)
Format a milliseconds time value.
Definition: mythdate.cpp:233
CommBreakMap::m_autocommercialskip
CommSkipMode m_autocommercialskip
Definition: commbreakmap.h:52
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
CommBreakMap::GetMap
void GetMap(frm_dir_map_t &map) const
Definition: commbreakmap.cpp:91
kCommSkipCount
@ kCommSkipCount
Definition: tv.h:138
CommSkipMode
CommSkipMode
Definition: tv.h:133
CommBreakMap::m_commnotifyamount
std::chrono::seconds m_commnotifyamount
Definition: commbreakmap.h:54
CommBreakMap::SetMap
void SetMap(const frm_dir_map_t &newMap, uint64_t framesPlayed)
Definition: commbreakmap.cpp:131
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:14
CommBreakMap::m_commBreakMapLock
QRecursiveMutex m_commBreakMapLock
Definition: commbreakmap.h:50
kCommSkipOff
@ kCommSkipOff
Definition: tv.h:135
mythdate.h
CommBreakMap::m_lastCommSkipStart
uint64_t m_lastCommSkipStart
Definition: commbreakmap.h:57
programinfo.h
kCommSkipIncr
@ kCommSkipIncr
Definition: tv.h:139
CommBreakMap::ResetLastSkip
void ResetLastSkip(void)
Definition: commbreakmap.cpp:27
CommBreakMap::m_commBreakIter
frm_dir_map_t::Iterator m_commBreakIter
Definition: commbreakmap.h:64
PlayerContext::m_playingInfo
ProgramInfo * m_playingInfo
Currently playing info.
Definition: playercontext.h:117
CommBreakMap::SetAutoCommercialSkip
void SetAutoCommercialSkip(CommSkipMode autoskip, uint64_t framesPlayed)
Definition: commbreakmap.cpp:32
PlayerContext::LockPlayingInfo
void LockPlayingInfo(const char *file, int line) const
Definition: playercontext.cpp:239
CommBreakMap::LoadMap
void LoadMap(PlayerContext *player_ctx, uint64_t framesPlayed)
Definition: commbreakmap.cpp:50
CommBreakMap::m_lastIgnoredManualSkip
QDateTime m_lastIgnoredManualSkip
Definition: commbreakmap.h:60
MARK_CUT_START
@ MARK_CUT_START
Definition: programtypes.h:56
hardwareprofile.smolt.long
long
Definition: smolt.py:75
CommBreakMap::IsInCommBreak
bool IsInCommBreak(uint64_t frameNumber) const
Definition: commbreakmap.cpp:98
MARK_COMM_START
@ MARK_COMM_START
Definition: programtypes.h:59
uint
unsigned int uint
Definition: compat.h:81
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:55
CommBreakMap::m_lastCommSkipDirection
int m_lastCommSkipDirection
Definition: commbreakmap.h:55
MARK_UNSET
@ MARK_UNSET
Definition: programtypes.h:50
LOC
#define LOC
Definition: commbreakmap.cpp:8
CommBreakMap::m_lastCommSkipTime
time_t m_lastCommSkipTime
Definition: commbreakmap.h:56
CommBreakMap::m_maxShortMerge
std::chrono::seconds m_maxShortMerge
Definition: commbreakmap.h:62
CommBreakMap::GetAutoCommercialSkip
CommSkipMode GetAutoCommercialSkip(void) const
Definition: commbreakmap.cpp:21
CommBreakMap::m_maxskip
std::chrono::seconds m_maxskip
Definition: commbreakmap.h:61
MythDate::secsInPast
std::chrono::seconds secsInPast(const QDateTime &past)
Definition: mythdate.cpp:203
MARK_CUT_END
@ MARK_CUT_END
Definition: programtypes.h:55
CommBreakMap::AutoCommercialSkip
bool AutoCommercialSkip(uint64_t &jumpToFrame, uint64_t framesPlayed, double video_frame_rate, uint64_t totalFrames, QString &comm_msg)
Definition: commbreakmap.cpp:144
MythDate
Definition: mythdate.cpp:11
CommBreakMap::m_commBreakMap
frm_dir_map_t m_commBreakMap
Definition: commbreakmap.h:63
mythcontext.h
CommBreakMap::CommBreakMap
CommBreakMap(void)
Definition: commbreakmap.cpp:10
PlayerContext
Definition: playercontext.h:49
CommBreakMap::m_hascommbreaktable
bool m_hascommbreaktable
Definition: commbreakmap.h:59
ProgramInfo::QueryCommBreakList
void QueryCommBreakList(frm_dir_map_t &frames) const
Definition: programinfo.cpp:3555
kCommSkipNotify
@ kCommSkipNotify
Definition: tv.h:137
kCommSkipOn
@ kCommSkipOn
Definition: tv.h:136
CommBreakMap::m_commrewindamount
std::chrono::seconds m_commrewindamount
Definition: commbreakmap.h:53
CommBreakMap::SkipCommercials
void SkipCommercials(int direction)
Definition: commbreakmap.cpp:41