MythTV master
commbreakmap.cpp
Go to the documentation of this file.
1// MythTV
6
7#include "commbreakmap.h"
8
9#define LOC QString("CommBreakMap: ")
10
12 : m_autocommercialskip(static_cast<CommSkipMode>(gCoreContext->GetNumSetting("AutoCommercialSkip", kCommSkipOff))),
13 m_commrewindamount(gCoreContext->GetDurSetting<std::chrono::seconds>("CommRewindAmount",0s)),
14 m_commnotifyamount(gCoreContext->GetDurSetting<std::chrono::seconds>("CommNotifyAmount",0s)),
15 m_lastIgnoredManualSkip(MythDate::current().addSecs(-10)),
16 m_maxskip(gCoreContext->GetDurSetting<std::chrono::seconds>("MaximumCommercialSkip", 1h)),
17 m_maxShortMerge(gCoreContext->GetDurSetting<std::chrono::seconds>("MergeShortCommBreaks", 0s)),
18 m_commBreakIter(m_commBreakMap.end())
19{
20}
21
23{
24 QMutexLocker locker(&m_commBreakMapLock);
26}
27
29{
30 m_lastSkipTime = SystemClock::now();
31}
32
33void CommBreakMap::SetAutoCommercialSkip(CommSkipMode autoskip, uint64_t framesplayed)
34{
35 QMutexLocker locker(&m_commBreakMapLock);
36 SetTracker(framesplayed);
37 uint next = (kCommSkipIncr == autoskip) ?
38 (uint) m_autocommercialskip + 1 : (uint) autoskip;
40}
41
43{
44 m_commBreakMapLock.lock();
45 if ((m_skipcommercials == 0 && direction != 0) ||
46 (m_skipcommercials != 0 && direction == 0))
47 m_skipcommercials = direction;
48 m_commBreakMapLock.unlock();
49}
50
51void 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
68void 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
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
99bool 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
132void 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;
142 SetTracker(framesPlayed);
143}
144
145bool 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);
153 return false;
154
155 if ((SystemClock::now() <= m_lastSkipTime + kAutoSkipDeadZone) ||
156 (SystemClock::now() <= m_lastCommSkipTime + kAutoSkipDeadZone))
157 {
158 SetTracker(framesPlayed);
159 return false;
160 }
161
162 if (m_commBreakIter == m_commBreakMap.end())
163 return false;
164
167
168 if (m_commBreakIter == m_commBreakMap.end())
169 return false;
170
173 (framesPlayed < m_commBreakIter.key())) &&
175 (framesPlayed + (m_commnotifyamount.count() * 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
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 auto skipped_seconds = std::chrono::seconds((int)((m_commBreakIter.key() -
219 framesPlayed) / video_frame_rate));
220 QString skipTime = MythDate::formatTime(skipped_seconds, "m:ss");
222 {
223 //: %1 is the skip time
224 comm_msg = tr("Skip %1").arg(skipTime);
225 }
226 else
227 {
228 //: %1 is the skip time
229 comm_msg = tr("Commercial: %1").arg(skipTime);
230 }
231
233 {
234 int framediff = (int)(m_commrewindamount.count() * video_frame_rate);
235 LOG(VB_COMMFLAG, LOG_INFO, LOC +
236 QString("AutoCommercialSkip(), auto-skipping to frame %1")
237 .arg(m_commBreakIter.key() - framediff));
238
240 m_lastCommSkipStart = framesPlayed;
241 m_lastCommSkipTime = SystemClock::now();
242
243 jumpToFrame = m_commBreakIter.key() - framediff;
244 return true;
245 }
247 return false;
248}
249
250bool CommBreakMap::DoSkipCommercials(uint64_t &jumpToFrame,
251 uint64_t framesPlayed,
252 double video_frame_rate,
253 uint64_t totalFrames, QString &comm_msg)
254{
255 QMutexLocker locker(&m_commBreakMapLock);
257 (SystemClock::now() <= m_lastCommSkipTime + kSkipBackWindow))
258 {
259 comm_msg = tr("Skipping Back.");
260
261 if (m_lastCommSkipStart > (2.0 * video_frame_rate))
262 m_lastCommSkipStart -= (long long) (2.0 * video_frame_rate);
264 m_lastCommSkipTime = SystemClock::now();
265 jumpToFrame = m_lastCommSkipStart;
266 return true;
267 }
269 m_lastCommSkipStart = framesPlayed;
270 m_lastCommSkipTime = SystemClock::now();
271
272 SetTracker(framesPlayed);
273
274 if ((m_commBreakIter == m_commBreakMap.begin()) &&
275 (m_skipcommercials < 0))
276 {
277 comm_msg = tr("Start of program.");
278 jumpToFrame = 0;
279 return true;
280 }
281
282 if ((m_skipcommercials > 0) &&
283 ((m_commBreakIter == m_commBreakMap.end()) ||
284 (((totalFrames) != 0U) &&
285 ((m_commBreakIter.key() + (10 * video_frame_rate)) > totalFrames))))
286 {
287 comm_msg = tr("At End, cannot Skip.");
288 return false;
289 }
290
291 if (m_skipcommercials < 0)
292 {
294
295 int skipped_seconds = (int)(((int64_t)(m_commBreakIter.key()) -
296 (int64_t)framesPlayed) / video_frame_rate);
297
298 // special case when hitting 'skip backwards' <3 seconds after break
299 if (skipped_seconds > -3)
300 {
301 if (m_commBreakIter == m_commBreakMap.begin())
302 {
303 comm_msg = tr("Start of program.");
304 jumpToFrame = 0;
305 return true;
306 }
308 }
309 }
310 else
311 {
312 int64_t framediff = m_commBreakIter.key() - framesPlayed;
313 auto skipped_seconds = std::chrono::seconds((int)(framediff / video_frame_rate));
314
315 // special case when hitting 'skip' within 20 seconds of the break
316 // start or within commrewindamount of the break end
317 // Even though commrewindamount has a max of 10 per the settings UI,
318 // check for MARK_COMM_END to make the code generic
320 if (((type == MARK_COMM_START) && (skipped_seconds < 20s)) ||
321 ((type == MARK_COMM_END) && (skipped_seconds < m_commrewindamount)))
322 {
324
325 if ((m_commBreakIter == m_commBreakMap.end()) ||
326 (((totalFrames) != 0U) &&
327 ((m_commBreakIter.key() + (10 * video_frame_rate)) >
328 totalFrames)))
329 {
330 comm_msg = tr("At End, cannot Skip.");
331 return false;
332 }
333 }
334 }
335
336 if (m_skipcommercials > 0)
337 MergeShortCommercials(video_frame_rate);
338 int64_t framediff = m_commBreakIter.key() - framesPlayed;
339 auto skipped_seconds = std::chrono::seconds((int)(framediff / video_frame_rate));
340 QString skipTime = MythDate::formatTime(skipped_seconds, "m:ss");
341
343 (abs(skipped_seconds) >= m_maxskip))
344 {
345 //: %1 is the skip time
346 comm_msg = tr("Too Far %1").arg(skipTime);
348 return false;
349 }
350
351 //: %1 is the skip time
352 comm_msg = tr("Skip %1").arg(skipTime);
353
354 uint64_t jumpto = (m_skipcommercials > 0) ?
355 m_commBreakIter.key() - (long long)(m_commrewindamount.count() * video_frame_rate):
356 m_commBreakIter.key();
358 jumpToFrame = jumpto;
359 return true;
360}
361
362void CommBreakMap::MergeShortCommercials(double video_frame_rate)
363{
364 double maxMerge = m_maxShortMerge.count() * video_frame_rate;
365 if (maxMerge <= 0.0 || (m_commBreakIter == m_commBreakMap.end()))
366 return;
367
368 long long lastFrame = m_commBreakIter.key();
370 while ((m_commBreakIter != m_commBreakMap.end()) &&
371 (m_commBreakIter.key() - lastFrame < maxMerge))
372 {
374 }
376}
frm_dir_map_t m_commBreakMap
Definition: commbreakmap.h:72
std::chrono::seconds m_maxShortMerge
Definition: commbreakmap.h:71
QRecursiveMutex m_commBreakMapLock
Definition: commbreakmap.h:50
CommSkipMode GetAutoCommercialSkip(void) const
bool IsInCommBreak(uint64_t frameNumber) const
SystemTime m_lastSkipTime
This is separate from m_lastCommSkipTime so a manual seek does not trigger the kSkipBackWindow code.
Definition: commbreakmap.h:65
SystemTime m_lastCommSkipTime
Definition: commbreakmap.h:56
int m_lastCommSkipDirection
Definition: commbreakmap.h:55
QDateTime m_lastIgnoredManualSkip
Definition: commbreakmap.h:69
void ResetLastSkip(void)
CommBreakMap(void)
bool DoSkipCommercials(uint64_t &jumpToFrame, uint64_t framesPlayed, double video_frame_rate, uint64_t totalFrames, QString &comm_msg)
void SetMap(const frm_dir_map_t &newMap, uint64_t framesPlayed)
void SetTracker(uint64_t framesPlayed)
void LoadMap(PlayerContext *player_ctx, uint64_t framesPlayed)
bool m_hascommbreaktable
Definition: commbreakmap.h:68
void MergeShortCommercials(double video_frame_rate)
std::chrono::seconds m_commnotifyamount
Definition: commbreakmap.h:54
std::chrono::seconds m_commrewindamount
Definition: commbreakmap.h:53
static constexpr std::chrono::seconds kSkipBackWindow
Time after a commercial skip that skipping back will skip to the start of the just skipped commercial...
Definition: commbreakmap.h:60
uint64_t m_lastCommSkipStart
Definition: commbreakmap.h:61
bool AutoCommercialSkip(uint64_t &jumpToFrame, uint64_t framesPlayed, double video_frame_rate, uint64_t totalFrames, QString &comm_msg)
void SetAutoCommercialSkip(CommSkipMode autoskip, uint64_t framesPlayed)
static constexpr std::chrono::seconds kAutoSkipDeadZone
Time after any seek that an automatic commercial skip will not occur.
Definition: commbreakmap.h:67
CommSkipMode m_autocommercialskip
Definition: commbreakmap.h:52
frm_dir_map_t::Iterator m_commBreakIter
Definition: commbreakmap.h:73
std::chrono::seconds m_maxskip
Definition: commbreakmap.h:70
void GetMap(frm_dir_map_t &map) const
int m_skipcommercials
Definition: commbreakmap.h:51
void SkipCommercials(int direction)
void LockPlayingInfo(const char *file, int line) const
void UnlockPlayingInfo(const char *file, int line) const
ProgramInfo * m_playingInfo
Currently playing info.
void QueryCommBreakList(frm_dir_map_t &frames) const
#define LOC
Definition: commbreakmap.cpp:9
unsigned int uint
Definition: freesurround.h:24
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
QString formatTime(std::chrono::milliseconds msecs, QString fmt)
Format a milliseconds time value.
Definition: mythdate.cpp:242
std::chrono::seconds secsInPast(const QDateTime &past)
Definition: mythdate.cpp:212
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:15
STL namespace.
MarkTypes
Definition: programtypes.h:46
@ MARK_CUT_START
Definition: programtypes.h:55
@ MARK_CUT_END
Definition: programtypes.h:54
@ MARK_UNSET
Definition: programtypes.h:49
@ MARK_COMM_END
Definition: programtypes.h:59
@ MARK_COMM_START
Definition: programtypes.h:58
QMap< uint64_t, MarkTypes > frm_dir_map_t
Frame # -> Mark map.
Definition: programtypes.h:117
CommSkipMode
Definition: tv.h:134
@ kCommSkipCount
Definition: tv.h:138
@ kCommSkipIncr
Definition: tv.h:139
@ kCommSkipOn
Definition: tv.h:136
@ kCommSkipNotify
Definition: tv.h:137
@ kCommSkipOff
Definition: tv.h:135