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