MythTV master
playercontext.cpp
Go to the documentation of this file.
1#include <cmath>
2#include <utility>
3
4#include <QPainter>
5
6#include "libmythbase/mythconfig.h"
10
11#include "Bluray/mythbdplayer.h"
12#include "DVD/mythdvdplayer.h"
13#include "channelutil.h"
14#include "io/mythmediabuffer.h"
15#include "livetvchain.h"
16#include "metadataimagehelper.h"
17#include "mythplayer.h"
18#include "playercontext.h"
19#include "playgroup.h"
20#include "remoteencoder.h"
21#include "tv_play.h"
22#include "videometadatautil.h"
23#include "videoouttypes.h"
24
25#define LOC QString("playCtx: ")
26
28 m_recUsage(std::move(inUseID))
29{
32}
33
35{
37 m_nextState.clear();
38}
39
41{
42 m_ffRewState = 0;
43 m_ffRewIndex = 0;
44 m_ffRewSpeed = 0;
45 m_tsNormal = 1.0F;
46
47 SetPlayer(nullptr);
48 SetRecorder(nullptr);
49 SetRingBuffer(nullptr);
50 SetTVChain(nullptr);
51 SetPlayingInfo(nullptr);
52}
53
59{
60 TVState newState = kState_None;
61 QString newPlaygroup("Default");
62
63 LockPlayingInfo(__FILE__, __LINE__);
64 if (islivetv)
65 {
67 newState = kState_WatchingLiveTV;
68 }
69 else if (m_playingInfo)
70 {
71 int overrecordseconds = gCoreContext->GetNumSetting("RecordOverTime");
72 QDateTime curtime = MythDate::current();
73 QDateTime recendts = m_playingInfo->GetRecordingEndTime()
74 .addSecs(overrecordseconds);
75
77 {
78 newState = (curtime < recendts) ?
80 }
81 else if (m_playingInfo->IsVideoDVD())
82 {
83 newState = kState_WatchingDVD;
84 }
85 else if (m_playingInfo->IsVideoBD())
86 {
87 newState = kState_WatchingBD;
88 }
89 else
90 {
91 newState = kState_WatchingVideo;
92 }
93
94 newPlaygroup = m_playingInfo->GetPlaybackGroup();
95 }
96 UnlockPlayingInfo(__FILE__, __LINE__);
97
98 ChangeState(newState);
99 SetPlayGroup(newPlaygroup);
100}
101
103{
104 QMutexLocker locker(&m_deletePlayerLock);
105 return m_player;
106}
107
109{
110 QMutexLocker locker(&m_deletePlayerLock);
111 return m_player && m_player->IsErrored();
112}
113
115{
116 QMutexLocker locker(&m_deletePlayerLock);
117 return m_player && m_player->IsPlaying();
118}
119
121{
122 QMutexLocker locker(&m_deletePlayerLock);
124 {
125 m_ffRewSpeed = 0;
126 m_ffRewState = 0;
128 return true;
129 }
130 return false;
131}
132
134{
135 QMutexLocker locker(&m_deletePlayerLock);
138 {
139 // Speed got changed in player since we are close to the end of file
140 m_tsNormal = 1.0F;
141 return true;
142 }
143 return false;
144}
145
147{
149}
150
152{
153 if (m_player)
155}
156
157void PlayerContext::UpdateTVChain(const QStringList &data)
158{
159 QMutexLocker locker(&m_deletePlayerLock);
160 if (m_tvchain && m_player)
161 {
162 m_tvchain->ReloadAll(data);
164 }
165}
166
168{
169 if (!m_tvchain)
170 return false;
171
173 ProgramInfo *pinfo = m_tvchain->GetProgramAt(-1);
174 if (pinfo)
175 {
176 SetPlayingInfo(pinfo);
177 delete pinfo;
178 return true;
179 }
180 return false;
181}
182
187{
188 if (!m_tvchain)
189 return;
190
191 // Don't store more than kMaxChannelHistory channels. Remove the first item
192 if (m_prevChan.size() >= kMaxChannelHistory)
193 m_prevChan.pop_front();
194
195 // This method builds the stack of previous channels
196 QString curChan = m_tvchain->GetChannelName(-1);
197 if (m_prevChan.empty() ||
198 curChan != m_prevChan[m_prevChan.size() - 1])
199 {
200 const QString& chan = curChan;
201 m_prevChan.push_back(chan);
202 }
203}
204
206{
207 if (m_prevChan.empty())
208 return {};
209
210 QString curChan = m_tvchain->GetChannelName(-1);
211 if ((curChan == m_prevChan.back()) && !m_prevChan.empty())
212 m_prevChan.pop_back();
213
214 if (m_prevChan.empty())
215 return {};
216
217 QString chan = m_prevChan.back();
218 m_prevChan.pop_back();
219 // add the current channel back to the list, to allow easy flipping between
220 // two channels using PREVCHAN
222 return chan;
223}
224
226{
227 if (m_prevChan.empty())
228 return {};
229
230 QString curChan = m_tvchain->GetChannelName(-1);
231 QString preChan;
232 if (curChan != m_prevChan.back() || m_prevChan.size() < 2)
233 preChan = m_prevChan.back();
234 else
235 preChan = m_prevChan[m_prevChan.size()-2];
236 return preChan;
237}
238
239void PlayerContext::LockPlayingInfo([[maybe_unused]] const char *file,
240 [[maybe_unused]] int line) const
241{
242#if 0
243 LOG(VB_GENERAL, LOG_DEBUG, QString("LockPlayingInfo(%1,%2)")
244 .arg(file).arg(line));
245#endif
246 m_playingInfoLock.lock();
247}
248
249void PlayerContext::UnlockPlayingInfo([[maybe_unused]] const char *file,
250 [[maybe_unused]] int line) const
251{
252#if 0
253 LOG(VB_GENERAL, LOG_DEBUG, QString("UnlockPlayingInfo(%1,%2)")
254 .arg(file).arg(line));
255#endif
256 m_playingInfoLock.unlock();
257}
258
264void PlayerContext::LockDeletePlayer([[maybe_unused]] const char *file,
265 [[maybe_unused]] int line) const
266{
267#if 0
268 LOG(VB_GENERAL, LOG_DEBUG, QString("LockDeletePlayer(%1,%2)")
269 .arg(file).arg(line));
270#endif
271 m_deletePlayerLock.lock();
272}
273
277void PlayerContext::UnlockDeletePlayer([[maybe_unused]] const char *file,
278 [[maybe_unused]] int line) const
279{
280#if 0
281 LOG(VB_GENERAL, LOG_DEBUG, QString("UnlockDeletePlayer(%1,%2)")
282 .arg(file).arg(line));
283#endif
284 m_deletePlayerLock.unlock();
285}
286
288{
289 m_stateLock.lock();
290}
291
293{
294 m_stateLock.unlock();
295}
296
298{
299 if (!m_stateLock.tryLock())
300 return true;
301 bool inStateChange = !m_nextState.empty();
302 m_stateLock.unlock();
303 return inStateChange;
304}
305
310{
311 QMutexLocker locker(&m_stateLock);
312 m_nextState.enqueue(newState);
313}
314
316{
317 QMutexLocker locker(&m_stateLock);
318 return m_nextState.dequeue();
319}
320
325{
326 QMutexLocker locker(&m_stateLock);
327 m_nextState.clear();
328 m_nextState.push_back(kState_None);
329}
330
332{
333 QMutexLocker locker(&m_stateLock);
334 return m_playingState;
335}
336
338{
339 bool loaded = false;
340 LockPlayingInfo(__FILE__, __LINE__);
341 if (m_playingInfo)
342 {
343 m_playingInfo->ToMap(infoMap);
344 infoMap["tvstate"] = StateToString(m_playingState);
345 infoMap["iconpath"] = ChannelUtil::GetIcon(m_playingInfo->GetChanID());
349 {
350 infoMap["coverartpath"] = VideoMetaDataUtil::GetArtPath(
351 m_playingInfo->GetPathname(), "Coverart");
352 infoMap["fanartpath"] = VideoMetaDataUtil::GetArtPath(
353 m_playingInfo->GetPathname(), "Fanart");
354 infoMap["bannerpath"] = VideoMetaDataUtil::GetArtPath(
355 m_playingInfo->GetPathname(), "Banners");
356 infoMap["screenshotpath"] = VideoMetaDataUtil::GetArtPath(
357 m_playingInfo->GetPathname(), "Screenshots");
358 }
359 else
360 {
363 infoMap["coverartpath"] =
364 artmap.value(kArtworkCoverart).url;
365 infoMap["fanartpath"] =
366 artmap.value(kArtworkFanart).url;
367 infoMap["bannerpath"] =
368 artmap.value(kArtworkBanner).url;
369 infoMap["screenshotpath"] =
370 artmap.value(kArtworkScreenshot).url;
371 }
372 loaded = true;
373 }
374 UnlockPlayingInfo(__FILE__, __LINE__);
375 return loaded;
376}
377
379{
380 bool ret = false;
381 LockPlayingInfo(__FILE__, __LINE__);
382 if (m_playingInfo)
384 UnlockPlayingInfo(__FILE__, __LINE__);
385 return ret;
386}
387
388QString PlayerContext::GetFilters(const QString &baseFilters) const
389{
390 QString filters = baseFilters;
391 QString chanFilters;
392
394 return baseFilters;
395
396 LockPlayingInfo(__FILE__, __LINE__);
397 if (m_playingInfo) // Recordings have this info already.
399 UnlockPlayingInfo(__FILE__, __LINE__);
400
401 if (!chanFilters.isEmpty())
402 {
403 if ((chanFilters[0] != '+'))
404 {
405 filters = chanFilters;
406 }
407 else
408 {
409 if (!filters.isEmpty() && (!filters.endsWith(",")))
410 filters += ",";
411
412 filters += chanFilters.mid(1);
413 }
414 }
415
416 LOG(VB_CHANNEL, LOG_INFO, LOC +
417 QString("Output filters for this channel are: '%1'")
418 .arg(filters));
419
420 return filters;
421}
422
424{
425 QString mesg = QObject::tr("Play");
426 if (m_ffRewState < 0)
427 {
428 mesg = QObject::tr("Rewind");
429 mesg += QString(" %1X").arg(-m_ffRewSpeed);
430 }
431 else if (m_ffRewState > 0)
432 {
433 mesg = QObject::tr("Forward");
434 mesg += QString(" %1X").arg(m_ffRewSpeed);
435 }
436 // Make sure these values for m_ffRewSpeed in TV::ChangeSpeed()
437 // and PlayerContext::GetPlayMessage() stay in sync.
438 else if (m_ffRewSpeed == 0)
439 {
440 mesg += QString(" %1X").arg(m_tsNormal);
441 }
442 else if (m_ffRewSpeed == -1)
443 {
444 mesg += QString(" 1/3X");
445 }
446 else if (m_ffRewSpeed == -2)
447 {
448 mesg += QString(" 1/8X");
449 }
450 else if (m_ffRewSpeed == -3)
451 {
452 mesg += QString(" 1/16X");
453 }
454
455 return mesg;
456}
457
459{
460 QMutexLocker locker(&m_deletePlayerLock);
461 if (m_player)
462 {
463 StopPlaying();
464 delete m_player;
465 }
466 m_player = newplayer;
467}
468
470{
471 if (m_recorder)
472 {
473 delete m_recorder;
474 m_recorder = nullptr;
475 }
476
477 if (rec)
478 {
479 m_recorder = rec;
481 }
482}
483
485{
486 if (m_tvchain)
487 {
490 m_tvchain = nullptr;
491 }
492
493 m_tvchain = chain;
494
495 if (m_tvchain)
497}
498
500{
501 if (m_buffer)
502 {
503 delete m_buffer;
504 m_buffer = nullptr;
505 }
506
508}
509
514{
515 bool ignoreDB = gCoreContext->IsDatabaseIgnored();
516
517 QMutexLocker locker(&m_playingInfoLock);
518
519 if (m_playingInfo)
520 {
521 if (!ignoreDB)
523 delete m_playingInfo;
524 m_playingInfo = nullptr;
525 }
526
527 if (info)
528 {
530 if (!ignoreDB)
534 }
535}
536
537void PlayerContext::SetPlayGroup(const QString &group)
538{
539 m_fftime = PlayGroup::GetDurSetting<std::chrono::seconds>(group, "skipahead", 30s);
540 m_rewtime = PlayGroup::GetDurSetting<std::chrono::seconds>(group, "skipback", 5s);
541 m_jumptime = PlayGroup::GetDurSetting<std::chrono::minutes>(group, "jump", 10min);
542 m_tsNormal = PlayGroup::GetSetting(group, "timestretch", 100) * 0.01F;
543 m_tsAlt = (m_tsNormal == 1.0F) ? 1.5F : 1.0F;
544}
545
547 const ProgramInfo *pi, PseudoState new_state)
548{
550 ProgramInfo *new_rec = nullptr;
551
552 if (pi)
553 {
554 new_rec = new ProgramInfo(*pi);
555 QString msg = QString("Wants to record: %1 %2 %3 %4")
556 .arg(new_rec->GetTitle(), new_rec->GetChanNum(),
559 LOG(VB_PLAYBACK, LOG_INFO, LOC + msg);
560 }
561
562 m_pseudoLiveTVRec = new_rec;
563 m_pseudoLiveTVState = new_state;
564
565 if (old_rec)
566 {
567 QString msg = QString("Done recording: %1 %2 %3 %4")
568 .arg(old_rec->GetTitle(), old_rec->GetChanNum(),
571 LOG(VB_PLAYBACK, LOG_INFO, LOC + msg);
572 delete old_rec;
573 }
574}
static QString GetIcon(uint chanid)
Keeps track of recordings in a current LiveTV instance.
Definition: livetvchain.h:33
void DestroyChain(void)
QString GetChannelName(int pos=-1) const
void ReloadAll(const QStringList &data=QStringList())
ProgramInfo * GetProgramAt(int at) const
Returns program at the desired location.
QString InitializeNewChain(const QString &seed)
Definition: livetvchain.cpp:40
bool IsDatabaseIgnored(void) const
/brief Returns true if database is being ignored.
QString GetHostName(void)
int GetNumSetting(const QString &key, int defaultval=0)
T dequeue()
Removes item from front of list and returns a copy. O(1).
Definition: mythdeque.h:31
void enqueue(const T &d)
Adds item to the back of the list. O(1).
Definition: mythdeque.h:41
float GetNextPlaySpeed(void) const
Definition: mythplayer.h:140
bool AtNormalSpeed(void) const
Definition: mythplayer.h:157
bool IsPlaying(std::chrono::milliseconds wait_in_msec=0ms, bool wait_for=true) const
Definition: mythplayer.cpp:251
bool IsErrored(void) const
virtual void StopPlaying(void)
Definition: mythplayer.cpp:947
void CheckTVChain()
Definition: mythplayer.cpp:933
void addMSecs(std::chrono::milliseconds ms)
Adds an offset to the last call to start() or restart().
Definition: mythtimer.cpp:146
void start(void)
starts measuring elapsed time.
Definition: mythtimer.cpp:47
static int GetSetting(const QString &name, const QString &field, int defval)
Definition: playgroup.cpp:277
QString m_recUsage
void SetRingBuffer(MythMediaBuffer *Buffer)
void SetPlayingInfo(const ProgramInfo *info)
assign programinfo to the context
QRecursiveMutex m_playingInfoLock
StringDeque m_prevChan
Previous channels.
QString GetPlayMessage(void) const
PlayerContext(QString inUseID=QString("Unknown"))
MythPlayer * m_player
void SetPseudoLiveTV(const ProgramInfo *pi, PseudoState new_state)
PseudoState m_pseudoLiveTVState
bool ReloadTVChain(void)
MythTimer m_lastSignalMsgTime
static constexpr uint kMaxChannelHistory
void LockState(void) const
void LockPlayingInfo(const char *file, int line) const
void SetPlayGroup(const QString &group)
TVState GetState(void) const
QRecursiveMutex m_deletePlayerLock
static constexpr std::chrono::milliseconds kSMExitTimeout
Timeout after last Signal Monitor message for ignoring OSD when exiting.
bool HasPlayer(void) const
bool IsPlayerErrored(void) const
void PushPreviousChannel(void)
most recently selected channel to the previous channel list
bool IsPlayerPlaying(void) const
QDateTime m_playingRecStart
std::chrono::seconds m_rewtime
int m_ffRewState
0 == normal, +1 == fast forward, -1 == rewind
TVState DequeueNextState(void)
void ForceNextStateNone(void)
Removes any pending state changes, and puts kState_None on the queue.
QString GetFilters(const QString &baseFilters) const
int m_lastCardid
CardID of current/last recorder.
void UnlockDeletePlayer(const char *file, int line) const
allow player to be deleted.
void UnlockState(void) const
int m_ffRewIndex
Index into m_ffRewSpeeds for FF and Rewind speeds.
RemoteEncoder * m_recorder
void UpdateTVChain(const QStringList &data=QStringList())
bool HandlePlayerSpeedChangeFFRew(void)
bool InStateChange(void) const
TVState m_playingState
void SetPlayer(MythPlayer *newplayer)
int m_ffRewSpeed
Caches value of m_ffRewSpeeds[m_ffRewIndex].
void SetTVChain(LiveTVChain *chain)
void LockDeletePlayer(const char *file, int line) const
prevent MythPlayer from being deleted used to ensure player can only be deleted after osd in TV() is ...
void SetRecorder(RemoteEncoder *rec)
bool IsRecorderErrored(void) const
bool HandlePlayerSpeedChangeEOF(void)
float m_tsNormal
Time stretch speed, 1.0F for normal playback.
std::chrono::seconds m_fftime
QString GetPreviousChannel(void) const
QRecursiveMutex m_stateLock
MythMediaBuffer * m_buffer
bool GetPlayingInfoMap(InfoMap &infoMap) const
void SetInitialTVState(bool islivetv)
determine initial tv state and playgroup for the recording
void ChangeState(TVState newState)
Puts a state change on the nextState queue.
LiveTVChain * m_tvchain
std::chrono::minutes m_jumptime
QString PopPreviousChannel(void)
MythDeque< TVState > m_nextState
bool IsSameProgram(const ProgramInfo &p) const
std::chrono::seconds m_playingLen
Initial CalculateLength()
void TeardownPlayer(void)
void UnlockPlayingInfo(const char *file, int line) const
ProgramInfo * m_pseudoLiveTVRec
void StopPlaying(void) const
ProgramInfo * m_playingInfo
Currently playing info.
Holds information on recordings and videos.
Definition: programinfo.h:68
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
Definition: programinfo.h:373
QString GetBasename(void) const
Definition: programinfo.h:345
bool IsVideoFile(void) const
Definition: programinfo.h:346
bool IsVideoDVD(void) const
Definition: programinfo.h:348
QString GetChannelPlaybackFilters(void) const
Definition: programinfo.h:388
QString GetInetRef(void) const
Definition: programinfo.h:441
bool IsSameProgram(const ProgramInfo &other) const
Checks whether this is the same program as "other", which may or may not be a repeat or on another ch...
bool IsRecording(void) const
Definition: programinfo.h:491
QString GetPlaybackGroup(void) const
Definition: programinfo.h:421
QString GetTitle(void) const
Definition: programinfo.h:362
void MarkAsInUse(bool inuse, const QString &usedFor="")
Tracks a recording's in use status, to prevent deletion and to allow the storage scheduler to perform...
QDateTime GetRecordingStartTime(void) const
Approximate time the recording started.
Definition: programinfo.h:405
QString GetChanNum(void) const
This is the channel "number", in the form 1, 1_2, 1-2, 1#1, etc.
Definition: programinfo.h:377
bool IsVideoBD(void) const
Definition: programinfo.h:350
std::chrono::seconds GetSecondsInRecording(void) const
Returns length of program/recording in seconds.
virtual void ToMap(InfoMap &progMap, bool showrerecord=false, uint star_range=10, uint date_format=0) const
Converts ProgramInfo into QString QHash containing each field in ProgramInfo converted into localized...
QString GetPathname(void) const
Definition: programinfo.h:344
QDateTime GetRecordingEndTime(void) const
Approximate time the recording should have ended, did end, or is intended to end.
Definition: programinfo.h:413
uint GetSeason(void) const
Definition: programinfo.h:367
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
int GetRecorderNumber(void) const
bool GetErrorStatus(void)
Definition: remoteencoder.h:81
static const int kInitFFRWSpeed
Definition: tv_play.h:750
static QString GetArtPath(const QString &pathname, const QString &type)
ArtworkMap GetArtwork(const QString &inetref, uint season, bool strict)
QMultiMap< VideoArtworkType, ArtworkInfo > ArtworkMap
@ kArtworkScreenshot
@ kArtworkFanart
@ kArtworkBanner
@ kArtworkCoverart
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
@ ISODate
Default UTC.
Definition: mythdate.h:17
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:15
dictionary info
Definition: azlyrics.py:7
STL namespace.
#define LOC
PseudoState
Definition: playercontext.h:41
QString StateToString(TVState state)
Returns a human readable QString representing a TVState.
Definition: tv.cpp:11
TVState
TVState is an enumeration of the states used by TV and TVRec.
Definition: tv.h:54
@ kState_WatchingDVD
Watching DVD is the state when we are watching a DVD.
Definition: tv.h:76
@ kState_None
None State, this is the initial state in both TV and TVRec, it indicates that we are ready to change ...
Definition: tv.h:61
@ kState_WatchingLiveTV
Watching LiveTV is the state for when we are watching a recording and the user has control over the c...
Definition: tv.h:66
@ kState_WatchingPreRecorded
Watching Pre-recorded is a TV only state for when we are watching a pre-existing recording.
Definition: tv.h:70
@ kState_WatchingRecording
Watching Recording is the state for when we are watching an in progress recording,...
Definition: tv.h:83
@ kState_WatchingBD
Watching BD is the state when we are watching a BD.
Definition: tv.h:78
@ kState_WatchingVideo
Watching Video is the state when we are watching a video and is not a dvd or BD.
Definition: tv.h:74