MythTV master
mythplayer.cpp
Go to the documentation of this file.
1// -*- Mode: c++ -*-
2// C++ headers
3#include <algorithm>
4#include <cassert>
5#include <cmath>
6#include <cstdint>
7#include <cstdio>
8#include <cstdlib>
9#include <unistd.h>
10
11// Qt headers
12#include <QCoreApplication>
13#include <QDir>
14#include <QHash>
15#include <QMap>
16#include <QThread>
17#include <utility>
18
19// MythTV headers
21#include "libmythbase/mthread.h"
28
29#include "DetectLetterbox.h"
30#include "audioplayer.h"
31#include "cardutil.h"
35#include "dummydecoder.h"
36#include "io/mythmediabuffer.h"
37#include "jitterometer.h"
38#include "livetvchain.h"
39#include "mythavutil.h"
40#include "mythplayer.h"
41#include "mythvideooutnull.h"
42#include "programinfo.h"
43#include "remoteencoder.h"
44#include "tv_actions.h"
45#include "tv_play.h"
46
47extern "C" {
48#include "libavcodec/avcodec.h"
49}
50
51static unsigned dbg_ident(const MythPlayer* /*player*/);
52
53#define LOC QString("Player(%1): ").arg(dbg_ident(this),0,36)
54
57
58// Exact frame seeking, no inaccuracy allowed.
59const double MythPlayer::kInaccuracyNone = 0;
60
61// By default, when seeking, snap to a keyframe if the keyframe's
62// distance from the target frame is less than 10% of the total seek
63// distance.
64const double MythPlayer::kInaccuracyDefault = 0.1;
65
66// Allow greater inaccuracy (50%) in the cutlist editor (unless the
67// editor seek distance is set to 1 frame or 1 keyframe).
68const double MythPlayer::kInaccuracyEditor = 0.5;
69
70// Any negative value means completely inexact, i.e. seek to the
71// keyframe that is closest to the target.
72const double MythPlayer::kInaccuracyFull = -1.0;
73
74// How close we can seek to the end of a recording.
75const double MythPlayer::kSeekToEndOffset = 1.0;
76
78 : m_playerCtx(Context),
79 m_playerThread(QThread::currentThread()),
80 m_playerFlags(Flags),
81 m_liveTV(Context->m_tvchain),
82 // CC608/708
83 m_cc608(this),
84 // Audio
85 m_audio(this, (Flags & kAudioMuted) != 0)
86{
87#ifdef Q_OS_ANDROID
88 m_playerThreadId = gettid();
89#endif
91
94 m_endExitPrompt = gCoreContext->GetNumSetting("EndOfRecordingExitPrompt");
95
96 // Get VBI page number
97 QString mypage = gCoreContext->GetSetting("VBIpageNr", "888");
98 bool valid = false;
99 uint tmp = mypage.toInt(&valid, 16);
100 m_ttPageNum = (valid) ? tmp : m_ttPageNum;
102}
103
105{
106 QMutexLocker lock2(&m_vidExitLock);
107
108 SetDecoder(nullptr);
109
110 delete m_decoderThread;
111 m_decoderThread = nullptr;
112
113 delete m_videoOutput;
114 m_videoOutput = nullptr;
115}
116
118{
119 m_watchingRecording = mode;
120 if (m_decoder)
122}
123
125{
127}
128
130{
131 m_bufferPauseLock.lock();
133 {
136 }
137 m_bufferPaused = true;
138 m_bufferPauseLock.unlock();
139}
140
142{
143 m_bufferPauseLock.lock();
146 m_bufferPaused = false;
147 m_bufferPauseLock.unlock();
148}
149
151{
152 while (!m_pauseLock.tryLock(100))
153 {
154 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Waited 100ms to get pause lock.");
156 }
157 bool already_paused = m_allPaused;
158 if (already_paused)
159 {
160 m_pauseLock.unlock();
161 return already_paused;
162 }
163 m_nextPlaySpeed = 0.0;
164 m_nextNormalSpeed = false;
165 PauseVideo();
166 m_audio.Pause(true);
167 PauseDecoder();
168 PauseBuffer();
169 if (!m_decoderPaused)
170 PauseDecoder(); // Retry in case audio only stream
172 {
177 }
178 m_pauseLock.unlock();
180 return already_paused;
181}
182
183bool MythPlayer::Play(float speed, bool normal, bool unpauseaudio)
184{
185 m_pauseLock.lock();
186 LOG(VB_PLAYBACK, LOG_INFO, LOC +
187 QString("Play(%1, normal %2, unpause audio %3)")
188 .arg(speed,5,'f',1).arg(normal).arg(unpauseaudio));
189
191 {
192 LOG(VB_GENERAL, LOG_ERR, LOC + "Ignoring Play(), in edit mode.");
193 m_pauseLock.unlock();
194 return false;
195 }
196
198
202 if (unpauseaudio)
203 m_audio.Pause(false);
204 UnpauseVideo();
205 m_allPaused = false;
206 m_nextPlaySpeed = speed;
207 m_nextNormalSpeed = normal;
208 m_pauseLock.unlock();
210 return true;
211}
212
214{
215 m_videoPauseLock.lock();
216 m_needNewPauseFrame = true;
217 m_videoPaused = true;
218 m_videoPauseLock.unlock();
219}
220
222{
223 m_videoPauseLock.lock();
224 m_videoPaused = false;
225 m_videoPauseLock.unlock();
226}
227
229{
231 if (!m_playerCtx)
232 return;
233
234 m_playerCtx->LockPlayingInfo(__FILE__, __LINE__);
235 m_playerCtx->SetPlayingInfo(&pginfo);
236 m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
237}
238
239void MythPlayer::SetPlaying(bool is_playing)
240{
241 QMutexLocker locker(&m_playingLock);
242
243 m_playing = is_playing;
244
245 m_playingWaitCond.wakeAll();
246}
247
248bool MythPlayer::IsPlaying(std::chrono::milliseconds wait_in_msec, bool wait_for) const
249{
250 QMutexLocker locker(&m_playingLock);
251
252 if (wait_in_msec == 0ms)
253 return m_playing;
254
255 MythTimer t;
256 t.start();
257
258 while ((wait_for != m_playing) && (t.elapsed() < wait_in_msec))
259 {
261 &m_playingLock, std::max(0ms,wait_in_msec - t.elapsed()).count());
262 }
263
264 return m_playing;
265}
266
268{
269 if (!m_playerCtx)
270 return false;
271
272 if (!m_decoder)
273 {
274 LOG(VB_GENERAL, LOG_ERR, LOC + "Cannot create a video renderer without a decoder.");
275 return false;
276 }
277
280
281 if (!m_videoOutput)
282 {
283 LOG(VB_GENERAL, LOG_ERR, LOC + "Couldn't create VideoOutput instance. Exiting..");
284 SetErrored(tr("Failed to initialize video output"));
285 return false;
286 }
287
288 return true;
289}
290
291void MythPlayer::ReinitVideo(bool ForceUpdate)
292{
293
294 bool aspect_only = false;
295 {
296 QMutexLocker locker(&m_vidExitLock);
298 float video_aspect = (m_forcedVideoAspect > 0) ? m_forcedVideoAspect : m_videoAspect;
300 m_decoder->GetVideoCodecID(), aspect_only,
301 m_maxReferenceFrames, ForceUpdate))
302 {
303 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to Reinitialize Video. Exiting..");
304 SetErrored(tr("Failed to reinitialize video output"));
305 return;
306 }
307 }
308
309 if (!aspect_only)
311}
312
313void MythPlayer::SetKeyframeDistance(int keyframedistance)
314{
315 m_keyframeDist = (keyframedistance > 0) ? static_cast<uint>(keyframedistance) : m_keyframeDist;
316}
317
318void MythPlayer::SetVideoParams(int width, int height, double fps,
319 float aspect, bool ForceUpdate,
320 int ReferenceFrames, FrameScanType /*scan*/, const QString& codecName)
321{
322 bool paramsChanged = ForceUpdate;
323
324 if (width >= 0 && height >= 0)
325 {
326 paramsChanged = true;
327 m_videoDim = m_videoDispDim = QSize(width, height);
328 m_videoAspect = aspect > 0.0F ? aspect : static_cast<float>(width) / height;
329 }
330
331 if (!qIsNaN(fps) && fps > 0.0 && fps < 121.0)
332 {
333 paramsChanged = true;
334 m_videoFrameRate = fps;
335 if (m_ffrewSkip != 0 && m_ffrewSkip != 1)
336 {
338 }
339 else
340 {
341 float temp_speed = (m_playSpeed == 0.0F) ?
344 1.0 / (m_videoFrameRate * static_cast<double>(temp_speed)));
345 }
346 }
347
348 if (!codecName.isEmpty())
349 {
350 m_codecName = codecName;
351 paramsChanged = true;
352 }
353
354 if (ReferenceFrames > 0)
355 {
356 m_maxReferenceFrames = ReferenceFrames;
357 paramsChanged = true;
358 }
359
360 if (!paramsChanged)
361 return;
362
363 if (m_videoOutput)
364 ReinitVideo(ForceUpdate);
365
366 if (IsErrored())
367 return;
368}
369
370
372{
373 m_videoFrameRate = fps;
374 float temp_speed = (m_playSpeed == 0.0F) ? m_audio.GetStretchFactor() : m_playSpeed;
375 if (abs(m_ffrewSkip) > 1)
377 else
378 SetFrameInterval(kScan_Progressive, 1.0 / (m_videoFrameRate * static_cast<double>(temp_speed)));
379}
380
381void MythPlayer::SetFileLength(std::chrono::seconds total, int frames)
382{
383 m_totalLength = total;
384 m_totalFrames = frames;
385}
386
387void MythPlayer::SetDuration(std::chrono::seconds duration)
388{
389 m_totalDuration = duration;
390}
391
393{
394 m_isDummy = true;
395
396 if (!m_videoOutput)
397 {
399 SetVideoParams(720, 576, 25.00, 1.25F, false, 2);
400 }
401
402 m_playerCtx->LockPlayingInfo(__FILE__, __LINE__);
403 auto *dec = new DummyDecoder(this, *(m_playerCtx->m_playingInfo));
404 m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
405 SetDecoder(dec);
406}
407
409{
412}
413
414int MythPlayer::OpenFile(int Retries)
415{
416 // Sanity check
418 return -1;
419
420 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Opening '%1'").arg(m_playerCtx->m_buffer->GetSafeFilename()));
421
422 m_isDummy = false;
424
425 // Dummy setup for livetv transtions. Can we get rid of this?
427 {
428 int currentposition = m_playerCtx->m_tvchain->GetCurPos();
429 if (m_playerCtx->m_tvchain->GetInputType(currentposition) == "DUMMY")
430 {
431 OpenDummy();
432 return 0;
433 }
434 }
435
436 // Start the RingBuffer read ahead thread
438
440 TestBufferVec testbuf {};
441 testbuf.reserve(kDecoderProbeBufferSize);
442
444
445 // delete any pre-existing recorder
446 SetDecoder(nullptr);
447 int testreadsize = 2048;
448
449 // Test the incoming buffer and create a suitable decoder
450 MythTimer bigTimer;
451 bigTimer.start();
452 std::chrono::milliseconds timeout =
453 std::max(500ms * (Retries + 1), 30000ms);
454 while (testreadsize <= kDecoderProbeBufferSize)
455 {
456 testbuf.resize(testreadsize);
457 MythTimer peekTimer;
458 peekTimer.start();
459 while (m_playerCtx->m_buffer->Peek(testbuf) != testreadsize)
460 {
461 // NB need to allow for streams encountering network congestion
462 if (peekTimer.elapsed() > 30s || bigTimer.elapsed() > timeout
464 {
465 LOG(VB_GENERAL, LOG_ERR, LOC +
466 QString("OpenFile(): Could not read first %1 bytes of '%2'")
467 .arg(testreadsize)
469 SetErrored(tr("Could not read first %1 bytes").arg(testreadsize));
470 return -1;
471 }
472 LOG(VB_GENERAL, LOG_WARNING, LOC + "OpenFile() waiting on data");
473 std::this_thread::sleep_for(50ms);
474 }
475
476 m_playerCtx->LockPlayingInfo(__FILE__, __LINE__);
477 CreateDecoder(testbuf);
478 m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
479 if (m_decoder || (bigTimer.elapsed() > timeout))
480 break;
481 testreadsize <<= 1;
482 }
483
484 // Fail
485 if (!m_decoder)
486 {
487 LOG(VB_GENERAL, LOG_ERR, LOC +
488 QString("Couldn't find an A/V decoder for: '%1'")
490 SetErrored(tr("Could not find an A/V decoder"));
491
492 return -1;
493 }
494
495 if (m_decoder->IsErrored())
496 {
497 LOG(VB_GENERAL, LOG_ERR, LOC + "Could not initialize A/V decoder.");
498 SetDecoder(nullptr);
499 SetErrored(tr("Could not initialize A/V decoder"));
500
501 return -1;
502 }
503
504 // Pre-init the decoder
508 // TODO (re)move this into MythTranscode player
510
511 // Open the decoder
512 int result = m_decoder->OpenFile(m_playerCtx->m_buffer, false, testbuf);
513
514 if (result < 0)
515 {
516 LOG(VB_GENERAL, LOG_ERR, QString("Couldn't open decoder for: %1")
518 SetErrored(tr("Could not open decoder"));
519 return -1;
520 }
521
522 // Disable audio if necessary
524
525 // Livetv, recording or in-progress
526 if (result > 0)
527 {
531 }
532
533 // Determine the initial bookmark and update it for the cutlist
537
540 {
541 gCoreContext->SaveSetting("DefaultChanid",
542 static_cast<int>(m_playerCtx->m_playingInfo->GetChanID()));
543 QString callsign = m_playerCtx->m_playingInfo->GetChannelSchedulingID();
544 QString channum = m_playerCtx->m_playingInfo->GetChanNum();
545 gCoreContext->SaveSetting("DefaultChanKeys", callsign + "[]:[]" + channum);
547 {
548 uint cardid = static_cast<uint>(m_playerCtx->m_recorder->GetRecorderNumber());
549 CardUtil::SetStartChannel(cardid, channum);
550 }
551 }
552
553 return IsErrored() ? -1 : 0;
554}
555
556void MythPlayer::SetFramesPlayed(uint64_t played)
557{
558 m_framesPlayed = played;
559 if (m_videoOutput)
561}
562
567{
568 if (m_videoOutput)
570 return 0;
571}
572
583{
584 if (m_videoOutput)
586 return nullptr;
587}
588
593 std::chrono::milliseconds timecode,
594 bool wrap)
595{
596 if (wrap)
597 WrapTimecode(timecode, TC_VIDEO);
598 buffer->m_timecode = timecode;
599 m_latestVideoTimecode = timecode;
600
602 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + "Clearing decode one");
603 m_decodeOneFrame = false;
604
605 if (m_videoOutput)
606 {
607 if (abs(m_ffrewSkip) > 1)
608 {
609 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + "Setting render one");
610 m_renderOneFrame = true;
611 }
613 }
614
615 // FIXME need to handle this in the correct place in the main thread (DVD stills?)
616 //if (m_allPaused)
617 // CheckAspectRatio(buffer);
618}
619
624{
625 if (m_videoOutput)
627}
628
642void MythPlayer::DiscardVideoFrames(bool KeyFrame, bool Flushed)
643{
644 if (m_videoOutput)
645 {
646 m_videoOutput->DiscardFrames(KeyFrame, Flushed);
648 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + "Clearing render one");
649 m_renderOneFrame = false;
650 }
651}
652
654{
655 EofState eof = GetEof();
656 if (eof != kEofStateNone && !m_allPaused)
657 return true;
658 if (GetEditMode())
659 return false;
660 if (m_liveTV)
661 return false;
663 return true;
664 return false;
665}
666
668{
669 if (m_videoOutput)
671}
672
674{
675 if (enable)
677 else
679}
680
682{
683 if (m_decoder)
685 m_frameInterval = microsecondsFromFloat(1000000.0 * frame_period / m_fpsMultiplier);
686
687 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("SetFrameInterval Interval:%1 Speed:%2 Scan:%3 (Multiplier: %4)")
688 .arg(m_frameInterval.count()).arg(static_cast<double>(m_playSpeed)).arg(ScanTypeToString(scan)).arg(m_fpsMultiplier));
689}
690
692{
693 // try to get preferential scheduling, but ignore if we fail to.
694 myth_nice(-19);
695}
696
697void MythPlayer::SetBuffering(bool new_buffering)
698{
699 if (!m_buffering && new_buffering)
700 {
701 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Waiting for video buffers...");
702 m_buffering = true;
703 m_bufferingStart = QTime::currentTime();
704 m_bufferingLastMsg = QTime::currentTime();
705 }
706 else if (m_buffering && !new_buffering)
707 {
708 m_buffering = false;
709 }
710}
711
712// For debugging playback set this to increase the timeout so that
713// playback does not fail if stepping through code.
714// Set PREBUFFERDEBUG to any value and you will get 30 minutes.
715static bool preBufferDebug = qEnvironmentVariableIsSet("PREBUFFERDEBUG");
716
718{
719 if (!m_videoOutput)
720 return false;
721
722 if (!min_buffers
724 || abs(m_ffrewSkip) > 1
725 || GetEof() != kEofStateNone))
726 min_buffers = 1;
727
728 auto wait = false;
729 if (min_buffers)
730 wait = m_videoOutput->ValidVideoFrames() < min_buffers;
731 else
733
734 if (!wait)
735 {
737 m_audio.Pause(false);
738 SetBuffering(false);
740 }
741
742 SetBuffering(true);
743
744 // This piece of code is to address the problem, when starting
745 // Live TV, of jerking and stuttering. Without this code
746 // that could go on forever, but is cured by a pause and play.
747 // This code inserts a brief pause and play when the potential
748 // for the jerking is detected.
751 && m_ffrewSkip == 1
753 {
754 auto behind = (GetCurrentFrameCount() - m_framesPlayed) /
756 if (behind < 3.0)
757 {
758 LOG(VB_PLAYBACK, LOG_NOTICE, LOC +
759 "Pause to allow live tv catch up");
761 }
762 }
763
764 std::this_thread::sleep_for(m_frameInterval / 8);
765 auto waited_for = std::chrono::milliseconds(m_bufferingStart.msecsTo(QTime::currentTime()));
766 auto last_msg = std::chrono::milliseconds(m_bufferingLastMsg.msecsTo(QTime::currentTime()));
767 if (last_msg > 100ms && !FlagIsSet(kMusicChoice))
768 {
769 if (++m_bufferingCounter == 10)
770 LOG(VB_GENERAL, LOG_NOTICE, LOC +
771 "To see more buffering messages use -v playback");
772 LOG(m_bufferingCounter >= 10 ? VB_PLAYBACK : VB_GENERAL,
773 LOG_NOTICE, LOC +
774 QString("Waited %1ms for video buffers %2")
775 .arg(waited_for.count()).arg(m_videoOutput->GetFrameStatus()));
776 m_bufferingLastMsg = QTime::currentTime();
777 if (waited_for > 7s && m_audio.IsBufferAlmostFull()
778 && m_framesPlayed < 5
779 && gCoreContext->GetBoolSetting("MusicChoiceEnabled", false))
780 {
782 LOG(VB_GENERAL, LOG_NOTICE, LOC + "Music Choice program detected - disabling AV Sync.");
784 }
785 if (waited_for > 7s && m_audio.IsBufferAlmostFull()
787 {
788 // We are likely to enter this condition
789 // if the audio buffer was too full during GetFrame in AVFD
790 LOG(VB_GENERAL, LOG_NOTICE, LOC + "Resetting audio buffer");
791 m_audio.Reset();
792 }
793
795 {
796 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + "Forcibly clearing render one");
797 m_renderOneFrame = false;
798 }
799 }
800
801 std::chrono::milliseconds msecs { 500ms };
802 if (preBufferDebug)
803 msecs = 30min;
804 if ((waited_for > msecs) && !m_videoOutput->EnoughFreeFrames())
805 {
806 LOG(VB_GENERAL, LOG_NOTICE, LOC +
807 "Timed out waiting for frames, and"
808 "\n\t\t\tthere are not enough free frames. "
809 "Discarding buffered frames.");
810 // This call will result in some ugly frames, but allows us
811 // to recover from serious problems if frames get leaked.
812 DiscardVideoFrames(true, true);
813 }
814
815 msecs = 30s;
816 if (preBufferDebug)
817 msecs = 30min;
818 if (waited_for > msecs) // 30 seconds for internet streamed media
819 {
820 LOG(VB_GENERAL, LOG_ERR, LOC +
821 "Waited too long for decoder to fill video buffers. Exiting..");
822 SetErrored(tr("Video frame buffering failed too many times."));
823 }
824
825 return false;
826}
827
829{
830 m_vidExitLock.lock();
831 delete m_videoOutput;
832 m_videoOutput = nullptr;
833 m_vidExitLock.unlock();
834}
835
836bool MythPlayer::FastForward(float seconds)
837{
838 if (!m_videoOutput)
839 return false;
840
841 // Update m_totalFrames so we know how far we can skip
842 if (m_decoder)
844
845 if (m_ffTime <= 0)
846 {
847 float current = ComputeSecs(m_framesPlayed, true);
848 float dest = current + seconds;
849 float length = ComputeSecs(m_totalFrames, true);
850
851 if (dest > length)
852 {
853 auto msec = millisecondsFromFloat(seconds * 1000);
854 int64_t pos = TranslatePositionMsToFrame(msec, false);
855 if (CalcMaxFFTime(pos) < 0)
856 return true;
857 // Reach end of recording, go to offset before the end
859 }
860 uint64_t target = FindFrame(dest, true);
861 m_ffTime = target - m_framesPlayed;
862 }
863 return m_ffTime > CalcMaxFFTime(m_ffTime, false);
864}
865
866bool MythPlayer::Rewind(float seconds)
867{
868 if (!m_videoOutput)
869 return false;
870
871 if (m_rewindTime <= 0)
872 {
873 float current = ComputeSecs(m_framesPlayed, true);
874 float dest = current - seconds;
875 if (dest < 0)
876 {
877 auto msec = millisecondsFromFloat(seconds * 1000);
878 int64_t pos = TranslatePositionMsToFrame(msec, false);
879 if (CalcRWTime(pos) < 0)
880 return true;
881 dest = 0;
882 }
883 uint64_t target = FindFrame(dest, true);
884 m_rewindTime = m_framesPlayed - target;
885 }
886 return (uint64_t)m_rewindTime >= m_framesPlayed;
887}
888
889bool MythPlayer::JumpToFrame(uint64_t frame)
890{
891 if (!m_videoOutput)
892 return false;
893
894 bool ret = false;
896 if (frame > m_framesPlayed)
897 {
898 m_ffTime = frame - m_framesPlayed;
899 ret = m_ffTime > CalcMaxFFTime(m_ffTime, false);
900 }
901 else if (frame < m_framesPlayed)
902 {
904 ret = m_ffTime > CalcMaxFFTime(m_ffTime, false);
905 }
906 return ret;
907}
908
909
910void MythPlayer::JumpChapter(int chapter)
911{
912 if (m_jumpChapter == 0)
913 m_jumpChapter = chapter;
914}
915
916void MythPlayer::ResetPlaying(bool resetframes)
917{
919 m_ffrewSkip = 1;
920 if (resetframes)
921 m_framesPlayed = 0;
922 if (m_decoder)
923 {
924 m_decoder->Reset(true, true, true);
925 if (m_decoder->IsErrored())
926 SetErrored("Unable to reset video decoder");
927 }
928}
929
931{
932 bool last = !(m_playerCtx->m_tvchain->HasNext());
934}
935
936// This is called from decoder thread. Set an indicator that will
937// be checked and actioned in the player thread.
939{
940 LOG(VB_PLAYBACK, LOG_INFO, LOC + "FileChangedCallback");
941 m_fileChanged = true;
942}
943
945{
946 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("StopPlaying - begin"));
947 m_playerThread->setPriority(QThread::NormalPriority);
948#ifdef Q_OS_ANDROID
949 setpriority(PRIO_PROCESS, m_playerThreadId, 0);
950#endif
951
952 emit CheckCallbacks();
953 DecoderEnd();
954 VideoEnd();
955 AudioEnd();
956
957 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("StopPlaying - end"));
958}
959
961{
963}
964
966{
967 m_decoderPauseLock.lock();
969 {
970 m_decoderPaused = true;
971 m_decoderThreadPause.wakeAll();
972 m_decoderPauseLock.unlock();
973 return m_decoderPaused;
974 }
975
976 int tries = 0;
977 m_pauseDecoder = true;
978 while (m_decoderThread && !m_killDecoder && (tries++ < 100) &&
980 {
981 emit CheckCallbacks();
982 LOG(VB_GENERAL, LOG_WARNING, LOC + "Waited 100ms for decoder to pause");
983 }
984 m_pauseDecoder = false;
985 m_decoderPauseLock.unlock();
986 return m_decoderPaused;
987}
988
990{
991 m_decoderPauseLock.lock();
992
994 {
995 m_decoderPaused = false;
996 m_decoderThreadUnpause.wakeAll();
997 m_decoderPauseLock.unlock();
998 return;
999 }
1000
1001 if (!IsInStillFrame())
1002 {
1003 int tries = 0;
1004 m_unpauseDecoder = true;
1005 while (m_decoderThread && !m_killDecoder && (tries++ < 100) &&
1007 {
1008 emit CheckCallbacks();
1009 LOG(VB_GENERAL, LOG_WARNING, LOC + "Waited 100ms for decoder to unpause");
1010 }
1011 m_unpauseDecoder = false;
1012 }
1013 m_decoderPauseLock.unlock();
1014}
1015
1016void MythPlayer::DecoderStart(bool start_paused)
1017{
1018 if (m_decoderThread)
1019 {
1021 {
1022 LOG(VB_GENERAL, LOG_ERR, LOC + "Decoder thread already running");
1023 }
1024 delete m_decoderThread;
1025 }
1026
1027 m_killDecoder = false;
1028 m_decoderPaused = start_paused;
1029 m_decoderThread = new MythDecoderThread(this, start_paused);
1030 if (m_decoderThread)
1032}
1033
1035{
1036 PauseDecoder();
1037 SetPlaying(false);
1038 // Ensure any hardware frames are released (after pausing the decoder) to
1039 // allow the decoder to exit cleanly
1040 DiscardVideoFrames(true, true);
1041
1042 m_killDecoder = true;
1043 int tries = 0;
1044 while (m_decoderThread && !m_decoderThread->wait(100ms) && (tries++ < 50))
1045 LOG(VB_PLAYBACK, LOG_INFO, LOC +
1046 "Waited 100ms for decoder loop to stop");
1047
1049 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to stop decoder loop.");
1050 else
1051 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Exited decoder loop.");
1052 SetDecoder(nullptr);
1053}
1054
1056{
1058 {
1059 if (m_pauseDecoder)
1060 PauseDecoder();
1061 if (m_unpauseDecoder)
1063 }
1064}
1065
1068{
1071
1072 if (!m_decoderChangeLock.tryLock(50))
1073 return kEofStateNone;
1074
1076 m_decoderChangeLock.unlock();
1077 return eof;
1078}
1079
1081{
1083 {
1084 if (m_decoder)
1085 m_decoder->SetEofState(eof);
1086 return;
1087 }
1088
1089 if (!m_decoderChangeLock.tryLock(50))
1090 return;
1091
1092 if (m_decoder)
1093 m_decoder->SetEofState(eof);
1094 m_decoderChangeLock.unlock();
1095}
1097
1099{
1100 if (pause)
1101 PauseDecoder();
1102
1103 while (!m_killDecoder && !IsErrored())
1104 {
1106
1108 {
1109 std::this_thread::sleep_for(1ms);
1110 continue;
1111 }
1112
1114 {
1115 if (!m_decoderChangeLock.tryLock(1))
1116 continue;
1117 if (m_decoder)
1118 {
1119 m_forcePositionMapSync = false;
1121 }
1122 m_decoderChangeLock.unlock();
1123 }
1124
1125 if (m_decoderSeek >= 0)
1126 {
1127 if (!m_decoderChangeLock.tryLock(1))
1128 continue;
1129 if (m_decoder)
1130 {
1131 m_decoderSeekLock.lock();
1132 if (((uint64_t)m_decoderSeek < m_framesPlayed) && m_decoder)
1134 else if (m_decoder)
1136 m_decoderSeek = -1;
1137 m_decoderSeekLock.unlock();
1138 }
1139 m_decoderChangeLock.unlock();
1140 }
1141
1142 bool obey_eof = (GetEof() != kEofStateNone) &&
1144 if (m_isDummy || ((m_decoderPaused || m_ffrewSkip == 0 || obey_eof) &&
1146 {
1147 std::this_thread::sleep_for(1ms);
1148 continue;
1149 }
1150
1153
1154 DecoderGetFrame(dt);
1155 }
1156
1157 // Clear any wait conditions
1159 m_decoderSeek = -1;
1160}
1161
1162static float ffrewScaleAdjust = 0.10F;
1163static float ffrewSkipThresh = 0.60F;
1164static float ffrewScaleLowest = 1.00F;
1165static float ffrewScaleHighest = 2.50F;
1166
1168{
1169 if (!m_decoder)
1170 return;
1171
1172 if (m_ffrewSkip > 0)
1173 {
1174 long long delta = m_decoder->GetFramesRead() - m_framesPlayed;
1175 long long real_skip = CalcMaxFFTime(m_ffrewSkip - m_ffrewAdjust + delta) - delta;
1176 long long target_frame = m_decoder->GetFramesRead() + real_skip;
1177 if (real_skip >= 0)
1178 m_decoder->DoFastForward(target_frame, true);
1179
1180 long long seek_frame = m_decoder->GetFramesRead();
1181 m_ffrewAdjust = seek_frame - target_frame;
1182 float adjustRatio = float(m_ffrewAdjust) / m_ffrewSkip;
1183 LOG(VB_PLAYBACK, LOG_INFO, LOC +
1184 QString("skip %1, adjust %2, ratio %3")
1185 .arg(m_ffrewSkip).arg(m_ffrewAdjust).arg(adjustRatio));
1186
1187 // If the needed adjustment is too large either way, adjust
1188 // the scale factor up or down accordingly.
1189 if (adjustRatio > ffrewSkipThresh
1190 && m_ffrewScale < (ffrewScaleHighest - 0.01F))
1192 else if (adjustRatio < -ffrewSkipThresh
1193 && m_ffrewScale > (ffrewScaleLowest + 0.01F))
1195 }
1196 else if (CalcRWTime(-m_ffrewSkip) >= 0)
1197 {
1198 long long cur_frame = m_decoder->GetFramesPlayed();
1199 bool toBegin = -cur_frame > m_ffrewSkip + m_ffrewAdjust;
1200 long long real_skip = (toBegin) ? -cur_frame : m_ffrewSkip + m_ffrewAdjust;
1201 long long target_frame = cur_frame + real_skip;
1202 m_decoder->DoRewind(target_frame, true);
1203
1204 long long seek_frame = m_decoder->GetFramesPlayed();
1205 m_ffrewAdjust = target_frame - seek_frame;
1206 float adjustRatio = float(m_ffrewAdjust) / m_ffrewSkip;
1207 LOG(VB_PLAYBACK, LOG_INFO, LOC +
1208 QString("skip %1, adjust, %2, ratio %3")
1209 .arg(m_ffrewSkip).arg(m_ffrewAdjust).arg(adjustRatio));
1210
1211 // If the needed adjustment is too large either way, adjust the
1212 // scale factor up or down accordingly.
1213 if (adjustRatio < -ffrewSkipThresh
1214 && m_ffrewScale < (ffrewScaleHighest - 0.01F))
1216 else if (adjustRatio > ffrewSkipThresh
1217 && m_ffrewScale > (ffrewScaleLowest + 0.01F))
1219 }
1220
1221 LOG(VB_PLAYBACK, LOG_DEBUG, "Setting decode one");
1222 m_decodeOneFrame = true;
1223}
1224
1225bool MythPlayer::DecoderGetFrame(DecodeType decodetype, bool unsafe)
1226{
1227 bool ret = false;
1228 if (!m_videoOutput)
1229 return false;
1230
1231 // Wait for frames to be available for decoding onto
1232 int tries = 0;
1233 while (!unsafe && (!m_videoOutput->EnoughFreeFrames() || m_audio.IsBufferAlmostFull()))
1234 {
1236 return false;
1237
1238 if (++tries > 10)
1239 {
1240 if (++m_videobufRetries >= 2000)
1241 {
1242 LOG(VB_GENERAL, LOG_ERR, LOC +
1243 "Decoder timed out waiting for free video buffers.");
1244 // We've tried for 20 seconds now, give up so that we don't
1245 // get stuck permanently in this state
1246 SetErrored("Decoder timed out waiting for free video buffers.");
1247 }
1248 return false;
1249 }
1250 std::this_thread::sleep_for(1ms);
1251 }
1253
1254 if (!m_decoderChangeLock.tryLock(5))
1255 return false;
1257 {
1258 m_decoderChangeLock.unlock();
1259 return false;
1260 }
1261
1262 if (abs(m_ffrewSkip) > 1 && !m_decodeOneFrame && !m_renderOneFrame)
1263 DoFFRewSkip();
1264
1265 if ((abs(m_ffrewSkip) > 0 || m_decodeOneFrame) && !m_renderOneFrame)
1266 ret = DoGetFrame(decodetype);
1267
1268 m_decoderChangeLock.unlock();
1269 return ret;
1270}
1271
1287{
1288 bool retry = false;
1289 bool ret = m_decoder->GetFrame(Type, retry);
1290 if (retry)
1291 {
1292 // Delay here so we don't spin too fast.
1293 m_decoderChangeLock.unlock();
1294 std::this_thread::sleep_for(1ms);
1295 m_decoderChangeLock.lock();
1296 return false;
1297 }
1298 return ret;
1299}
1300
1301void MythPlayer::WrapTimecode(std::chrono::milliseconds &timecode, TCTypes tc_type)
1302{
1303 timecode += m_tcWrap[tc_type];
1304}
1305
1306bool MythPlayer::PrepareAudioSample(std::chrono::milliseconds &timecode)
1307{
1308 WrapTimecode(timecode, TC_AUDIO);
1309 m_latestAudioTimecode = timecode;
1310 return false;
1311}
1312
1314{
1315 uint64_t bookmark = 0;
1316
1319 bookmark = 0;
1320 else
1321 {
1322 m_playerCtx->LockPlayingInfo(__FILE__, __LINE__);
1323 if (const ProgramInfo *pi = m_playerCtx->m_playingInfo)
1324 bookmark = pi->QueryStartMark();
1325 m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
1326 }
1327
1328 return bookmark;
1329}
1330
1331bool MythPlayer::UpdateFFRewSkip(float ffrewScale)
1332{
1333 bool skip_changed = false;
1334
1335 float temp_speed = (m_playSpeed == 0.0F) ?
1337 if (m_playSpeed >= 0.0F && m_playSpeed <= 3.0F)
1338 {
1339 skip_changed = (m_ffrewSkip != 1);
1340 if (m_decoder)
1342 m_frameInterval = microsecondsFromFloat((1000000.0 / m_videoFrameRate / static_cast<double>(temp_speed))
1343 / m_fpsMultiplier);
1344 m_ffrewSkip = static_cast<int>(m_playSpeed != 0.0F);
1345 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + "Clearing render one");
1346 }
1347 else
1348 {
1349 skip_changed = true;
1350 m_ffrewScale = ffrewScale;
1351 if (fabs(m_playSpeed) <= 10.0F)
1352 m_frameInterval = 200000us; // 5.00 fps
1353 else if (fabs(m_playSpeed) <= 20.0F)
1354 m_frameInterval = 166667us; // 6.00 fps
1355 else
1356 m_frameInterval = 150000us; // 6.67 fps
1358 float ffw_fps = fabs(static_cast<double>(m_playSpeed)) * m_videoFrameRate;
1359 float dis_fps = 1000000.0F / m_frameInterval.count();
1360 m_ffrewSkip = (int)ceil(ffw_fps / dis_fps);
1362 LOG(VB_PLAYBACK, LOG_INFO, LOC +
1363 QString("new skip %1, interval %2, scale %3")
1364 .arg(m_ffrewSkip).arg(m_frameInterval.count()).arg(m_ffrewScale));
1365 m_ffrewAdjust = 0;
1366 }
1367
1368 return skip_changed;
1369}
1370
1372{
1373 float last_speed = m_playSpeed;
1377
1378 bool skip_changed = UpdateFFRewSkip();
1379
1380 if (skip_changed && m_videoOutput)
1381 {
1383 if (m_playSpeed != 0.0F && (last_speed != 0.0F || m_ffrewSkip != 1))
1385 }
1386
1387 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Play speed: " +
1388 QString("rate: %1 speed: %2 skip: %3 => new interval %4")
1389 .arg(m_videoFrameRate).arg(static_cast<double>(m_playSpeed))
1390 .arg(m_ffrewSkip).arg(m_frameInterval.count()));
1391
1392 if (m_videoOutput)
1393 m_videoOutput->SetVideoFrameRate(static_cast<float>(m_videoFrameRate));
1394
1396 {
1399 }
1400}
1401
1402bool MythPlayer::DoRewind(uint64_t frames, double inaccuracy)
1403{
1405 return false;
1406
1407 uint64_t number = frames + 1;
1408 uint64_t desiredFrame = (m_framesPlayed > number) ? m_framesPlayed - number : 0;
1409
1410 m_limitKeyRepeat = false;
1411 if (desiredFrame < m_videoFrameRate)
1412 m_limitKeyRepeat = true;
1413
1414 uint64_t seeksnap_wanted = UINT64_MAX;
1415 if (inaccuracy != kInaccuracyFull)
1416 seeksnap_wanted = frames * inaccuracy;
1417 WaitForSeek(desiredFrame, seeksnap_wanted);
1418 m_rewindTime = 0;
1420 return true;
1421}
1422
1428long long MythPlayer::CalcRWTime(long long rw) const
1429{
1430 bool hasliveprev = (m_liveTV && m_playerCtx->m_tvchain &&
1432
1433 if (!hasliveprev || ((int64_t)m_framesPlayed >= rw))
1434 {
1435 return rw;
1436 }
1437
1438 auto seconds = secondsFromFloat(((int64_t)m_framesPlayed - rw) / m_videoFrameRate);
1439 m_playerCtx->m_tvchain->JumpToNext(false, seconds);
1440
1441 return -1;
1442}
1443
1448long long MythPlayer::CalcMaxFFTime(long long ffframes, bool setjump) const
1449{
1450 float maxtime = kSeekToEndOffset;
1451 bool islivetvcur = (m_liveTV && m_playerCtx->m_tvchain &&
1453
1454 long long ret = ffframes;
1455 float ff = ComputeSecs(ffframes, true);
1456 float secsPlayed = ComputeSecs(m_framesPlayed, true);
1457 float secsWritten = ComputeSecs(m_totalFrames, true);
1458
1459 m_limitKeyRepeat = false;
1460
1461 if (m_liveTV && !islivetvcur && m_playerCtx->m_tvchain)
1462 {
1463 // recording has completed, totalFrames will always be up to date
1464 if ((ffframes + m_framesPlayed > m_totalFrames) && setjump)
1465 {
1466 ret = -1;
1467 // Number of frames to be skipped is from the end of the current segment
1468 int64_t frames = (int64_t)m_totalFrames - (int64_t)m_framesPlayed - ffframes;
1469 auto seconds = secondsFromFloat(frames / m_videoFrameRate);
1470 m_playerCtx->m_tvchain->JumpToNext(true, seconds);
1471 }
1472 }
1473 else if (islivetvcur || IsWatchingInprogress())
1474 {
1475 if ((ff + secsPlayed) > secsWritten)
1476 {
1477 // If we attempt to seek past the last known duration,
1478 // check for up to date data
1479 long long framesWritten = m_playerCtx->m_recorder->GetFramesWritten();
1480
1481 secsWritten = ComputeSecs(framesWritten, true);
1482 }
1483
1484 float behind = secsWritten - secsPlayed;
1485
1486 if (behind < maxtime) // if we're close, do nothing
1487 ret = 0;
1488 else if (behind - ff <= maxtime)
1489 {
1490 auto msec = millisecondsFromFloat(1000 * (secsWritten - maxtime));
1491 ret = TranslatePositionMsToFrame(msec, true) - m_framesPlayed;
1492 }
1493
1494 if (behind < maxtime * 3)
1495 m_limitKeyRepeat = true;
1496 }
1497 else if (IsPaused())
1498 {
1499 uint64_t lastFrame =
1501 if (m_framesPlayed + ffframes >= lastFrame)
1502 ret = lastFrame - 1 - m_framesPlayed;
1503 }
1504 else
1505 {
1506 float secsMax = secsWritten - (2.F * maxtime);
1507 if (secsMax <= 0.F)
1508 ret = 0;
1509 else if (secsMax < secsPlayed + ff)
1510 {
1511 auto msec = millisecondsFromFloat(1000 * secsMax);
1512 ret = TranslatePositionMsToFrame(msec, true) - m_framesPlayed;
1513 }
1514 }
1515
1516 return ret;
1517}
1518
1526{
1527 if (!m_videoOutput || !m_decoder)
1528 return false;
1529
1532}
1533
1537{
1538 if (!m_playerCtx)
1539 return false;
1540
1541 m_playerCtx->LockPlayingInfo(__FILE__, __LINE__);
1543 !m_decoder)
1544 {
1545 m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
1546 return false;
1547 }
1548 m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
1549
1550 auto margin = (long long)(m_videoFrameRate * 2);
1551 margin = (long long) (margin * m_audio.GetStretchFactor());
1552 bool watchingTV = IsWatchingInprogress();
1553
1554 uint64_t framesRead = m_framesPlayed;
1555 uint64_t framesLeft = 0;
1556
1558 {
1559 if (framesRead >= m_deleteMap.GetLastFrame())
1560 return true;
1561 uint64_t frameCount = GetCurrentFrameCount();
1562 framesLeft = (frameCount > framesRead) ? frameCount - framesRead : 0;
1563 return (framesLeft < (uint64_t)margin);
1564 }
1565
1566 if (!m_liveTV && !watchingTV)
1567 return false;
1568
1570 return false;
1571
1573 {
1574 framesLeft =
1576
1577 // if it looks like we are near end, get an updated GetFramesWritten()
1578 if (framesLeft < (uint64_t)margin)
1579 framesLeft = m_playerCtx->m_recorder->GetFramesWritten() - framesRead;
1580 }
1581
1582 return (framesLeft < (uint64_t)margin);
1583}
1584
1585bool MythPlayer::DoFastForward(uint64_t frames, double inaccuracy)
1586{
1588 return false;
1589
1590 uint64_t number = (frames ? frames - 1 : 0);
1591 uint64_t desiredFrame = m_framesPlayed + number;
1592
1593 if (!m_deleteMap.IsEditing() && IsInDelete(desiredFrame))
1594 {
1595 uint64_t endcheck = m_deleteMap.GetLastFrame();
1596 desiredFrame = std::min(desiredFrame, endcheck);
1597 }
1598
1599 uint64_t seeksnap_wanted = UINT64_MAX;
1600 if (inaccuracy != kInaccuracyFull)
1601 seeksnap_wanted = frames * inaccuracy;
1602 WaitForSeek(desiredFrame, seeksnap_wanted);
1603 m_ffTime = 0;
1604 ClearAfterSeek(false);
1605 return true;
1606}
1607
1608void MythPlayer::DoJumpToFrame(uint64_t frame, double inaccuracy)
1609{
1610 if (frame > m_framesPlayed)
1611 DoFastForward(frame - m_framesPlayed, inaccuracy);
1612 else
1613 DoRewind(m_framesPlayed - frame, inaccuracy);
1614}
1615
1616void MythPlayer::WaitForSeek(uint64_t frame, uint64_t seeksnap_wanted)
1617{
1618 if (!m_decoder)
1619 return;
1620
1622 m_decoder->SetSeekSnap(seeksnap_wanted);
1623
1624 bool islivetvcur = (m_liveTV && m_playerCtx->m_tvchain &&
1626
1627 uint64_t max = GetCurrentFrameCount();
1628 if (islivetvcur || IsWatchingInprogress())
1629 {
1630 max = (uint64_t)m_playerCtx->m_recorder->GetFramesWritten();
1631 }
1632 if (frame >= max)
1633 frame = max - 1;
1634
1635 m_decoderSeekLock.lock();
1636 m_decoderSeek = frame;
1637 m_decoderSeekLock.unlock();
1638
1639 int count = 0;
1640 bool needclear = false;
1641 while (m_decoderSeek >= 0)
1642 {
1643 // Waiting blocks the main UI thread but the decoder may
1644 // have initiated a callback into the UI thread to create
1645 // certain resources. Ensure the callback is processed.
1646 // Ideally MythPlayer should be fully event driven and these
1647 // calls wouldn't be necessary.
1648 emit CheckCallbacks();
1649
1650 // Wait a little
1651 std::this_thread::sleep_for(50ms);
1652
1653 // provide some on screen feedback if seeking is slow
1654 count++;
1655 if (!(count % 3) && !m_hasFullPositionMap)
1656 {
1657 emit SeekingSlow(count);
1658 needclear = true;
1659 }
1660 }
1661 if (needclear)
1662 emit SeekingComplete();
1663
1664 emit SeekingDone();
1665}
1666
1679void MythPlayer::ClearAfterSeek(bool clearvideobuffers)
1680{
1681 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("ClearAfterSeek(%1)")
1682 .arg(clearvideobuffers));
1683
1684 if (clearvideobuffers && m_videoOutput)
1686
1687 std::chrono::milliseconds savedTC = m_tcWrap[TC_AUDIO];
1688
1689 m_tcWrap.fill(0ms);
1690 m_tcWrap[TC_AUDIO] = savedTC;
1691 m_audio.Reset();
1692
1693 emit RequestResetCaptions();
1697 m_needNewPauseFrame = true;
1698
1700}
1701
1702bool MythPlayer::IsInDelete(uint64_t frame)
1703{
1704 return m_deleteMap.IsInDelete(frame);
1705}
1706
1708{
1710}
1711
1713{
1714 if (m_decoder)
1716 return {};
1717}
1718
1719QString MythPlayer::GetXDS(const QString &key) const
1720{
1721 if (!m_decoder)
1722 return {};
1723 return m_decoder->GetXDS(key);
1724}
1725
1727{
1730}
1731
1732// Returns the total frame count, as totalFrames for a completed
1733// recording, or the most recent frame count from the recorder for
1734// live TV or an in-progress recording.
1736{
1737 uint64_t result = m_totalFrames;
1740 return result;
1741}
1742
1743// Finds the frame number associated with the given time offset. A
1744// positive offset or +0.0F indicate offset from the beginning. A
1745// negative offset or -0.0F indicate offset from the end. Limit the
1746// result to within bounds of the video.
1747uint64_t MythPlayer::FindFrame(float offset, bool use_cutlist) const
1748{
1749 bool islivetvcur = (m_liveTV && m_playerCtx->m_tvchain &&
1751 std::chrono::milliseconds length_ms = TranslatePositionFrameToMs(m_totalFrames, use_cutlist);
1752 std::chrono::milliseconds position_ms = 0ms;
1753 auto offset_ms = std::chrono::milliseconds(llroundf(fabsf(offset) * 1000));
1754
1755 if (std::signbit(offset))
1756 {
1757 // Always get an updated totalFrame value for in progress recordings
1758 if (islivetvcur || IsWatchingInprogress())
1759 {
1760 uint64_t framesWritten = m_playerCtx->m_recorder->GetFramesWritten();
1761
1762 if (m_totalFrames < framesWritten)
1763 {
1764 // Known duration is less than what the backend reported, use new value
1765 length_ms =
1766 TranslatePositionFrameToMs(framesWritten, use_cutlist);
1767 }
1768 }
1769 position_ms = (offset_ms > length_ms) ? 0ms : length_ms - offset_ms;
1770 }
1771 else
1772 {
1773 position_ms = offset_ms;
1774 if (offset_ms > length_ms)
1775 {
1776 // Make sure we have an updated totalFrames
1777 if ((islivetvcur || IsWatchingInprogress()) &&
1778 (length_ms < offset_ms))
1779 {
1780 long long framesWritten =
1782
1783 length_ms =
1784 TranslatePositionFrameToMs(framesWritten, use_cutlist);
1785 }
1786 position_ms = std::min(position_ms, length_ms);
1787 }
1788 }
1789 return TranslatePositionMsToFrame(position_ms, use_cutlist);
1790}
1791
1792// If position == -1, it signifies that we are computing the current
1793// duration of an in-progress recording. In this case, we fetch the
1794// current frame rate and frame count from the recorder.
1795std::chrono::milliseconds MythPlayer::TranslatePositionFrameToMs(uint64_t position,
1796 bool use_cutlist) const
1797{
1798 float frameRate = GetFrameRate();
1799 if (position == UINT64_MAX &&
1801 {
1802 float recorderFrameRate = m_playerCtx->m_recorder->GetFrameRate();
1803 if (recorderFrameRate > 0)
1804 frameRate = recorderFrameRate;
1806 }
1807 return m_deleteMap.TranslatePositionFrameToMs(position, frameRate,
1808 use_cutlist);
1809}
1810
1812{
1813 if (m_decoder)
1814 return m_decoder->GetNumChapters();
1815 return 0;
1816}
1817
1819{
1820 if (m_decoder)
1822 return 0;
1823}
1824
1825void MythPlayer::GetChapterTimes(QList<std::chrono::seconds> &times)
1826{
1827 if (m_decoder)
1828 m_decoder->GetChapterTimes(times);
1829}
1830
1832{
1833 int64_t desiredFrame = -1;
1834 int total = GetNumChapters();
1835 int current = GetCurrentChapter();
1836
1837 if (chapter < 0 || chapter > total)
1838 {
1839
1840 if (chapter < 0)
1841 {
1842 chapter = current -1;
1843 chapter = std::max(chapter, 0);
1844 }
1845 else if (chapter > total)
1846 {
1847 chapter = current + 1;
1848 chapter = std::min(chapter, total);
1849 }
1850 }
1851
1852 desiredFrame = GetChapter(chapter);
1853 LOG(VB_PLAYBACK, LOG_INFO, LOC +
1854 QString("DoJumpChapter: current %1 want %2 (frame %3)")
1855 .arg(current).arg(chapter).arg(desiredFrame));
1856
1857 if (desiredFrame < 0)
1858 {
1859 LOG(VB_PLAYBACK, LOG_ERR, LOC + QString("DoJumpChapter failed."));
1860 m_jumpChapter = 0;
1861 return false;
1862 }
1863
1864 DoJumpToFrame(desiredFrame, kInaccuracyNone);
1865 m_jumpChapter = 0;
1866 return true;
1867}
1868
1869int64_t MythPlayer::GetChapter(int chapter)
1870{
1871 if (m_decoder)
1872 return m_decoder->GetChapter(chapter);
1873 return 0;
1874}
1875
1880{
1881 m_totalDecoderPause = true;
1882 PauseDecoder();
1883
1884 {
1885 while (!m_decoderChangeLock.tryLock(10))
1886 LOG(VB_GENERAL, LOG_INFO, LOC + "Waited 10ms for decoder lock");
1887 delete m_decoder;
1888 m_decoder = dec;
1889 if (m_decoder)
1891 m_decoderChangeLock.unlock();
1892 }
1893 // reset passthrough override
1894 m_disablePassthrough = false;
1896 m_totalDecoderPause = false;
1897}
1898
1899bool MythPlayer::PosMapFromEnc(uint64_t start,
1900 frm_pos_map_t &posMap,
1901 frm_pos_map_t &durMap)
1902{
1903 // Reads only new positionmap entries from encoder
1904 if (!(m_liveTV || (m_playerCtx->m_recorder &&
1906 return false;
1907
1908 // if livetv, and we're not the last entry, don't get it from the encoder
1909 if (HasTVChainNext())
1910 return false;
1911
1912 LOG(VB_PLAYBACK, LOG_INFO, LOC +
1913 QString("Filling position map from %1 to %2") .arg(start).arg("end"));
1914
1915 m_playerCtx->m_recorder->FillPositionMap(start, -1, posMap);
1916 m_playerCtx->m_recorder->FillDurationMap(start, -1, durMap);
1917
1918 return true;
1919}
1920
1921void MythPlayer::SetErrored(const QString &reason)
1922{
1923 QMutexLocker locker(&m_errorLock);
1924
1925 if (m_videoOutput)
1927
1928 if (m_errorMsg.isEmpty())
1929 {
1930 m_errorMsg = reason;
1931 }
1932 else
1933 {
1934 LOG(VB_GENERAL, LOG_ERR, LOC + QString("%1").arg(reason));
1935 }
1936}
1937
1939{
1940 QMutexLocker locker(&m_errorLock);
1941
1942 m_errorMsg = QString();
1943}
1944
1946{
1947 QMutexLocker locker(&m_errorLock);
1948 return !m_errorMsg.isEmpty();
1949}
1950
1951QString MythPlayer::GetError(void) const
1952{
1953 QMutexLocker locker(&m_errorLock);
1954 return m_errorMsg;
1955}
1956
1958{
1959 if (!m_decoder)
1960 return;
1961
1963}
1964
1966{
1967 if (!m_decoder)
1968 return;
1969
1971}
1972
1974{
1975 if (!m_decoder)
1976 return;
1977
1979}
1980
1982{
1983 if (m_decoder && m_audio.HasAudioOut())
1984 {
1985 float stretch = m_audio.GetStretchFactor();
1986 m_disablePassthrough |= (stretch < 0.99F) || (stretch > 1.01F);
1987 LOG(VB_PLAYBACK, LOG_INFO, LOC +
1988 QString("Stretch Factor %1, %2 passthru ")
1990 .arg((m_disablePassthrough) ? "disable" : "allow"));
1992 }
1993}
1994
1996{
1997 if (m_decoder && m_audio.HasAudioOut())
1999}
2000
2002{
2003 if (m_decoder && m_audio.HasAudioOut())
2005}
2006
2007static unsigned dbg_ident(const MythPlayer *player)
2008{
2009 static QMutex s_dbgLock;
2010 static unsigned s_dbgNextIdent = 0;
2011 using DbgMapType = QHash<const MythPlayer*, unsigned>;
2012 static DbgMapType s_dbgIdent;
2013
2014 QMutexLocker locker(&s_dbgLock);
2015 DbgMapType::iterator it = s_dbgIdent.find(player);
2016 if (it != s_dbgIdent.end())
2017 return *it;
2018 return s_dbgIdent[player] = s_dbgNextIdent++;
2019}
#define assert(x)
bool IsPaused(void)
float GetStretchFactor(void) const
Definition: audioplayer.h:62
bool HasAudioOut(void) const
Definition: audioplayer.h:50
bool Pause(bool pause)
void CheckFormat(void)
void DeleteOutput(void)
Definition: audioplayer.cpp:95
void Reset(void)
Definition: audioplayer.cpp:86
bool IsBufferAlmostFull(void)
void SetStretchFactor(float factor)
A decoder for media files.
static bool CanHandle(TestBufferVec &testbuf, const QString &filename)
Perform an av_probe_input_format on the passed data to see if we can decode it with this class.
void SetTTPageNum(int page)
Definition: cc608reader.h:84
static bool SetStartChannel(uint inputid, const QString &channum)
Definition: cardutil.cpp:1686
void ResetLastSkip(void)
void SetMap(const frm_dir_map_t &newMap, uint64_t framesPlayed)
void SetTracker(uint64_t framesPlayed)
virtual void SetWatchingRecording(bool mode)
Definition: decoderbase.cpp:80
long long GetFramesPlayed(void) const
Definition: decoderbase.h:195
virtual bool GetFrame(DecodeType Type, bool &Retry)=0
Demux, preprocess and possibly decode a frame of video/audio.
virtual void SetDisablePassThrough(bool disable)
Disables AC3/DTS pass through.
Definition: decoderbase.h:145
virtual QString GetXDS(const QString &) const
Definition: decoderbase.h:239
virtual long long GetChapter(int)
Definition: decoderbase.h:157
virtual void UpdateFramesPlayed(void)
void SetTranscoding(bool value)
Definition: decoderbase.h:214
void SetRenderFormats(const VideoFrameTypes *RenderFormats)
Definition: decoderbase.cpp:34
virtual void GetChapterTimes(QList< std::chrono::seconds > &)
Definition: decoderbase.h:156
void SaveTotalDuration(void)
virtual void Reset(bool reset_video_data, bool seek_reset, bool reset_file)
Definition: decoderbase.cpp:46
virtual void SetEofState(EofState eof)
Definition: decoderbase.h:131
void SetLiveTVMode(bool live)
Definition: decoderbase.h:139
long long GetFramesRead(void) const
Definition: decoderbase.h:194
virtual void ForceSetupAudioStream(void)
Definition: decoderbase.h:147
virtual int GetCurrentChapter(long long)
Definition: decoderbase.h:155
int GetfpsMultiplier(void) const
Definition: decoderbase.h:252
virtual bool DoFastForward(long long desiredFrame, bool discardFrames=true)
Skips ahead or rewinds to desiredFrame.
void SaveTotalFrames(void)
virtual MythCodecID GetVideoCodecID(void) const =0
void ResetTotalDuration(void)
Definition: decoderbase.h:249
virtual int GetNumChapters(void)
Definition: decoderbase.h:154
virtual bool SyncPositionMap(void)
Updates the position map used for skipping frames.
EofState GetEof(void)
Definition: decoderbase.h:135
void SetSeekSnap(uint64_t snap)
Definition: decoderbase.h:137
virtual bool DoRewind(long long desiredFrame, bool discardFrames=true)
virtual int OpenFile(MythMediaBuffer *Buffer, bool novideo, TestBufferVec &testbuf)=0
virtual double GetFPS(void) const
Definition: decoderbase.h:189
bool IsErrored() const
Definition: decoderbase.h:216
void SetPlayerContext(PlayerContext *ctx)
Definition: deletemap.h:32
void TrackerReset(uint64_t frame)
Resets the internal state tracker.
Definition: deletemap.cpp:810
uint64_t GetLastFrame(void) const
Returns the number of the last frame in the video that is not in a cut sequence.
Definition: deletemap.cpp:861
bool TrackerWantsToJump(uint64_t frame, uint64_t &to) const
Returns true if the given frame has passed the last cut point start and provides the frame number of ...
Definition: deletemap.cpp:846
bool IsEditing(void) const
Definition: deletemap.h:41
bool IsInDelete(uint64_t frame) const
Returns true if the given frame is deemed to be within a region that should be cut.
Definition: deletemap.cpp:572
std::chrono::milliseconds TranslatePositionFrameToMs(uint64_t position, float fallback_framerate, bool use_cutlist) const
Definition: deletemap.cpp:901
bool IsEmpty(void) const
Definition: deletemap.cpp:259
void LoadMap(const QString &undoMessage="")
Loads the delete map from the database.
Definition: deletemap.cpp:739
bool HasNext(void) const
int GetCurPos(void) const
Definition: livetvchain.h:55
bool HasPrev(void) const
Definition: livetvchain.h:62
void JumpToNext(bool up, std::chrono::seconds pos)
jump to the next (up == true) or previous (up == false) liveTV program If pos > 0: indicate the absol...
QString GetInputType(int pos=-1) const
bool isRunning(void) const
Definition: mthread.cpp:261
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:281
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:298
bool IsDatabaseIgnored(void) const
/brief Returns true if database is being ignored.
void SaveSetting(const QString &key, int newValue)
QString GetSetting(const QString &key, const QString &defaultval="")
int GetNumSetting(const QString &key, int defaultval=0)
bool GetBoolSetting(const QString &key, bool defaultval=false)
int Peek(void *Buffer, int Count)
QString GetSafeFilename(void)
virtual bool IsBookmarkAllowed(void)
void Pause(void)
Pauses the read-ahead thread.
void Start(void)
Starts the read-ahead thread.
void WaitForPause(void)
Waits for Pause(void) to take effect.
virtual bool IsSeekingAllowed(void)
bool GetStopReads(void) const
void Unpause(void)
Unpauses the read-ahead thread.
bool IsNearEnd(double Framerate, uint Frames) const
bool LiveMode(void) const
Returns true if this RingBuffer has been assigned a LiveTVChain.
QString GetFilename(void) const
void SetAVSyncMusicChoice(AudioPlayer *Audio)
AVSyncAudioPausedType GetAVSyncAudioPause() const
void ResetAVSyncForLiveTV(AudioPlayer *Audio)
void SaveTotalDuration(void)
virtual bool Rewind(float seconds)
Definition: mythplayer.cpp:866
QMutex m_decoderPauseLock
Definition: mythplayer.h:376
void SetDuration(std::chrono::seconds duration)
Definition: mythplayer.cpp:387
bool m_needNewPauseFrame
Definition: mythplayer.h:390
virtual void ReleaseNextVideoFrame(MythVideoFrame *buffer, std::chrono::milliseconds timecode, bool wrap=true)
Places frame on the queue of frames ready for display.
Definition: mythplayer.cpp:592
void syncWithAudioStretch()
QMutex m_playingLock
Definition: mythplayer.h:398
void SetEof(EofState eof)
void OpenDummy(void)
Definition: mythplayer.cpp:392
uint64_t FindFrame(float offset, bool use_cutlist) const
static const double kInaccuracyFull
Definition: mythplayer.h:241
QMutex m_bufferPauseLock
Definition: mythplayer.h:378
bool m_normalSpeed
Definition: mythplayer.h:493
bool FlagIsSet(PlayerFlags arg)
Definition: mythplayer.h:317
std::chrono::microseconds m_frameInterval
always adjusted for play_speed
Definition: mythplayer.h:486
QMutex m_vidExitLock
Definition: mythplayer.h:397
void UnpauseVideo(void)
Definition: mythplayer.cpp:221
long long m_rewindTime
Definition: mythplayer.h:427
bool HasTVChainNext(void) const
bool m_inJumpToProgramPause
Definition: mythplayer.h:384
bool m_unpauseDecoder
Definition: mythplayer.h:386
bool PauseDecoder(void)
Definition: mythplayer.cpp:965
virtual void SetVideoParams(int w, int h, double fps, float aspect, bool ForceUpdate, int ReferenceFrames, FrameScanType=kScan_Ignore, const QString &codecName=QString())
Definition: mythplayer.cpp:318
virtual bool HasReachedEof(void) const
Definition: mythplayer.cpp:653
uint64_t TranslatePositionMsToFrame(std::chrono::milliseconds position, bool use_cutlist) const
Definition: mythplayer.h:256
bool m_decodeOneFrame
Definition: mythplayer.h:388
bool m_captionsEnabledbyDefault
This allows us to enable captions/subtitles later if the streams are not immediately available when t...
Definition: mythplayer.h:462
bool m_liveTV
Definition: mythplayer.h:402
MythPlayer(PlayerContext *Context, PlayerFlags Flags=kNoFlags)
Definition: mythplayer.cpp:77
bool m_allPaused
Definition: mythplayer.h:393
void SetFramesPlayed(uint64_t played)
Definition: mythplayer.cpp:556
bool m_disableForcedSubtitles
Definition: mythplayer.h:464
MythDecoderThread * m_decoderThread
Definition: mythplayer.h:366
virtual void DecoderStart(bool start_paused)
void SetDecoder(DecoderBase *dec)
Sets the stream decoder, deleting any existing recorder.
void WaitForSeek(uint64_t frame, uint64_t seeksnap_wanted)
void SetWatchingRecording(bool mode)
Definition: mythplayer.cpp:117
QMutex m_decoderSeekLock
Definition: mythplayer.h:377
bool UpdateFFRewSkip(float ffrewScale=1.0F)
DecoderBase * m_decoder
Definition: mythplayer.h:361
int m_videobufRetries
How often we have tried to wait for a video output buffer and failed.
Definition: mythplayer.h:422
DeleteMap m_deleteMap
Definition: mythplayer.h:478
int m_ffrewAdjust
offset after last skip
Definition: mythplayer.h:489
virtual bool JumpToFrame(uint64_t frame)
Definition: mythplayer.cpp:889
virtual bool FastForward(float seconds)
Definition: mythplayer.cpp:836
static const double kInaccuracyNone
Definition: mythplayer.h:238
QRecursiveMutex m_decoderChangeLock
Definition: mythplayer.h:362
QTime m_bufferingStart
Definition: mythplayer.h:449
QWaitCondition m_decoderThreadPause
Definition: mythplayer.h:374
static const int kNightModeContrastAdjustment
Definition: mythplayer.h:237
void DoJumpToFrame(uint64_t frame, double inaccuracy)
AudioPlayer m_audio
Definition: mythplayer.h:472
virtual int GetNumChapters(void)
uint64_t GetCurrentFrameCount(void) const
static const double kInaccuracyEditor
Definition: mythplayer.h:240
const VideoFrameTypes * m_renderFormats
Definition: mythplayer.h:364
uint64_t m_framesPlayed
Definition: mythplayer.h:423
QString GetError(void) const
bool m_pauseDecoder
Definition: mythplayer.h:385
CommBreakMap m_commBreakMap
Definition: mythplayer.h:475
int m_fpsMultiplier
used to detect changes
Definition: mythplayer.h:487
bool m_buffering
Definition: mythplayer.h:448
virtual void AudioEnd(void)
Definition: mythplayer.cpp:960
void SeekingSlow(int Count)
long long CalcRWTime(long long rw) const
CalcRWTime(rw): rewind rw frames back.
void DiscardVideoFrames(bool KeyFrame, bool Flushed)
Places frames in the available frames queue.
Definition: mythplayer.cpp:642
virtual void ResetPlaying(bool resetframes=true)
Definition: mythplayer.cpp:916
virtual int OpenFile(int Retries=4)
Definition: mythplayer.cpp:414
virtual void InitFrameInterval()
Definition: mythplayer.cpp:691
bool m_isDummy
Definition: mythplayer.h:500
uint64_t m_bookmarkSeek
Definition: mythplayer.h:412
bool IsInDelete(uint64_t frame)
int m_jumpChapter
Definition: mythplayer.h:409
virtual long long CalcMaxFFTime(long long ff, bool setjump=true) const
CalcMaxFFTime(ffframes): forward ffframes forward.
bool m_forcePositionMapSync
Definition: mythplayer.h:476
bool m_decoderPaused
Definition: mythplayer.h:383
bool m_renderOneFrame
Definition: mythplayer.h:389
int m_ffrewSkip
Definition: mythplayer.h:488
virtual void ReinitVideo(bool ForceUpdate)
Definition: mythplayer.cpp:291
std::chrono::seconds m_totalDuration
Definition: mythplayer.h:426
void ResetTotalDuration(void)
bool m_limitKeyRepeat
Definition: mythplayer.h:406
bool IsPaused(void) const
Definition: mythplayer.h:150
void PauseChanged(bool Paused)
float m_nextPlaySpeed
Definition: mythplayer.h:483
bool m_disablePassthrough
Definition: mythplayer.h:508
bool IsPlaying(std::chrono::milliseconds wait_in_msec=0ms, bool wait_for=true) const
Definition: mythplayer.cpp:248
void SetErrored(const QString &reason)
virtual void DecoderLoop(bool pause)
QWaitCondition m_playingWaitCond
Definition: mythplayer.h:396
uint64_t m_totalFrames
Definition: mythplayer.h:424
bool m_videoPaused
Definition: mythplayer.h:392
void RequestResetCaptions()
bool m_transcoding
Definition: mythplayer.h:404
static const double kSeekToEndOffset
Definition: mythplayer.h:242
virtual void VideoEnd(void)
Definition: mythplayer.cpp:828
void SetFrameRate(double fps)
Definition: mythplayer.cpp:371
virtual int GetCurrentChapter(void)
void ForceSetupAudioStream(void)
bool IsNearEnd(void)
Returns true iff near end of recording.
bool IsWatchingInprogress(void) const
Definition: mythplayer.cpp:124
PlayerFlags m_playerFlags
Definition: mythplayer.h:371
float m_playSpeed
Definition: mythplayer.h:484
tctype_arr m_tcWrap
Definition: mythplayer.h:496
void DeLimboFrame(MythVideoFrame *frame)
Definition: mythplayer.cpp:667
bool m_enableForcedSubtitles
Definition: mythplayer.h:463
bool DoGetFrame(DecodeType DecodeType)
Get one frame from the decoder.
virtual bool IsInStillFrame() const
Definition: mythplayer.h:228
int m_maxReferenceFrames
Number of reference frames used in the video stream.
Definition: mythplayer.h:440
bool IsErrored(void) const
QSize m_videoDispDim
Video (input) width & height.
Definition: mythplayer.h:438
bool DecoderGetFrame(DecodeType decodetype, bool unsafe=false)
virtual uint64_t GetBookmark(void)
int m_errorType
Definition: mythplayer.h:401
int m_endExitPrompt
Definition: mythplayer.h:413
void EnableForcedSubtitles(bool enable)
Definition: mythplayer.cpp:673
bool volatile m_killDecoder
Definition: mythplayer.h:387
int m_ttPageNum
VBI page to display when in PAL vbimode.
Definition: mythplayer.h:455
QSize m_videoDim
Video (input) buffer width & height.
Definition: mythplayer.h:439
void SetKeyframeDistance(int keyframedistance)
Definition: mythplayer.cpp:313
void UnpauseBuffer(void)
Definition: mythplayer.cpp:141
virtual bool PrebufferEnoughFrames(int min_buffers=0)
Definition: mythplayer.cpp:717
void WrapTimecode(std::chrono::milliseconds &timecode, TCTypes tc_type)
float m_ffrewScale
scale skip for large gops
Definition: mythplayer.h:490
void SeekingComplete()
MythPlayerAVSync m_avSync
Definition: mythplayer.h:430
void SetDisablePassThrough(bool disabled)
void SetBuffering(bool new_buffering)
Definition: mythplayer.cpp:697
bool m_watchingRecording
Definition: mythplayer.h:403
void CheckCallbacks()
void SaveTotalFrames(void)
QMutex m_errorLock
Definition: mythplayer.h:399
bool IsReallyNearEnd(void) const
Returns true iff really near end of recording.
bool m_playing
Definition: mythplayer.h:394
void FileChangedCallback()
Definition: mythplayer.cpp:938
QMutex m_pauseLock
Definition: mythplayer.h:380
void SetFileLength(std::chrono::seconds total, int frames)
Definition: mythplayer.cpp:381
virtual void DecoderEnd(void)
float m_videoAspect
Video (input) Apect Ratio.
Definition: mythplayer.h:441
bool Pause(void)
Definition: mythplayer.cpp:150
float m_forcedVideoAspect
Definition: mythplayer.h:442
QThread * m_playerThread
Definition: mythplayer.h:367
int64_t m_decoderSeek
Definition: mythplayer.h:381
float ComputeSecs(uint64_t position, bool use_cutlist) const
Definition: mythplayer.h:271
virtual bool DoJumpChapter(int chapter)
virtual void StopPlaying(void)
Definition: mythplayer.cpp:944
int m_bufferingCounter
Definition: mythplayer.h:503
void PauseVideo(void)
Definition: mythplayer.cpp:213
QWaitCondition m_decoderThreadUnpause
Definition: mythplayer.h:375
double m_videoFrameRate
Video (input) Frame Rate (often inaccurate)
Definition: mythplayer.h:435
void ClearAfterSeek(bool clearvideobuffers=true)
This is to support seeking...
virtual void ChangeSpeed(void)
bool GetEditMode(void) const
Definition: mythplayer.h:314
QString GetXDS(const QString &key) const
virtual void GetChapterTimes(QList< std::chrono::seconds > &times)
long long m_ffTime
If m_ffTime>0, number of frames to seek forward.
Definition: mythplayer.h:418
virtual void DecoderPauseCheck(void)
std::chrono::milliseconds m_latestVideoTimecode
Definition: mythplayer.h:428
void PauseBuffer(void)
Definition: mythplayer.cpp:129
virtual int64_t GetChapter(int chapter)
void SetPlayingInfo(const ProgramInfo &pginfo)
Definition: mythplayer.cpp:228
void UnpauseDecoder(void)
Definition: mythplayer.cpp:989
static const int kNightModeBrightenssAdjustment
Definition: mythplayer.h:236
void ResetErrored(void)
bool Play(float speed=1.0, bool normal=true, bool unpauseaudio=true)
Definition: mythplayer.cpp:183
CC608Reader m_cc608
Definition: mythplayer.h:468
bool m_hasFullPositionMap
Definition: mythplayer.h:405
void CheckTVChain()
Definition: mythplayer.cpp:930
uint m_vbiMode
VBI decoder to use.
Definition: mythplayer.h:454
void SetPlaying(bool is_playing)
Definition: mythplayer.cpp:239
virtual void CreateDecoder(TestBufferVec &TestBuffer)
Definition: mythplayer.cpp:408
PlayerContext * m_playerCtx
Definition: mythplayer.h:365
bool PosMapFromEnc(uint64_t start, frm_pos_map_t &posMap, frm_pos_map_t &durMap)
MythVideoFrame * GetNextVideoFrame(void)
Removes a frame from the available queue for decoding onto.
Definition: mythplayer.cpp:582
bool m_bufferPaused
Definition: mythplayer.h:391
friend class MythDecoderThread
Definition: mythplayer.h:90
std::chrono::seconds m_totalLength
Definition: mythplayer.h:425
MythVideoOutput * m_videoOutput
Definition: mythplayer.h:363
void SeekingDone()
void JumpChapter(int chapter)
Definition: mythplayer.cpp:910
bool DoRewind(uint64_t frames, double inaccuracy)
bool m_nextNormalSpeed
Definition: mythplayer.h:492
int GetFreeVideoFrames(void) const
Returns the number of frames available for decoding onto.
Definition: mythplayer.cpp:566
void SetFrameInterval(FrameScanType scan, double frame_period)
Definition: mythplayer.cpp:681
virtual bool PrepareAudioSample(std::chrono::milliseconds &timecode)
QString GetEncodingType(void) const
~MythPlayer() override
Definition: mythplayer.cpp:104
QTime m_bufferingLastMsg
Definition: mythplayer.h:450
void SetCommBreakMap(const frm_dir_map_t &NewMap)
QMutex m_videoPauseLock
Definition: mythplayer.h:379
QString m_codecName
Codec Name - used by playback profile.
Definition: mythplayer.h:437
virtual void DoFFRewSkip(void)
EofState GetEof(void) const
float GetFrameRate(void) const
Definition: mythplayer.h:132
std::chrono::milliseconds TranslatePositionFrameToMs(uint64_t position, bool use_cutlist) const
bool m_totalDecoderPause
Definition: mythplayer.h:382
void DiscardVideoFrame(MythVideoFrame *buffer)
Places frame in the available frames queue.
Definition: mythplayer.cpp:623
std::chrono::milliseconds m_latestAudioTimecode
Definition: mythplayer.h:429
QString m_errorMsg
Reason why NVP exited with a error.
Definition: mythplayer.h:400
bool m_fileChanged
Definition: mythplayer.h:491
static const double kInaccuracyDefault
Definition: mythplayer.h:239
virtual bool InitVideo(void)
Definition: mythplayer.cpp:267
bool DoFastForward(uint64_t frames, double inaccuracy)
uint m_keyframeDist
Video (input) Number of frames between key frames (often inaccurate)
Definition: mythplayer.h:445
A QElapsedTimer based timer to replace use of QTime as a timer.
Definition: mythtimer.h:14
std::chrono::milliseconds elapsed(void)
Returns milliseconds elapsed since last start() or restart()
Definition: mythtimer.cpp:91
void start(void)
starts measuring elapsed time.
Definition: mythtimer.cpp:47
std::chrono::milliseconds m_timecode
Definition: mythframe.h:130
static MythVideoOutputNull * Create(QSize VideoDim, QSize VideoDispDim, float VideoAspect, MythCodecID CodecID)
bool EnoughFreeFrames()
Returns true iff enough frames are available to decode onto.
bool EnoughDecodedFrames()
Returns true iff there are plenty of decoded frames ready for display.
virtual void ReleaseFrame(MythVideoFrame *Frame)
Releases a frame from the ready for decoding queue onto the queue of frames ready for display.
virtual int ValidVideoFrames() const
Returns number of frames that are fully decoded.
virtual void ClearAfterSeek()
Tells video output to toss decoded buffers due to a seek.
void SetPrebuffering(bool Normal)
Sets whether to use a normal number of buffers or fewer buffers.
virtual void SetVideoFrameRate(float VideoFrameRate)
virtual long long GetFramesPlayed()
QString GetFrameStatus() const
Returns string with status of each frame for debugging.
VideoErrorState GetError() const
virtual void DeLimboFrame(MythVideoFrame *Frame)
Releases a frame for reuse if it is in limbo.
virtual MythVideoFrame * GetNextFreeFrame()
Blocks until it is possible to return a frame for decoding onto.
int FreeVideoFrames()
Returns number of frames available for decoding onto.
virtual void DiscardFrame(MythVideoFrame *Frame)
Releases frame from any queue onto the queue of frames ready for decoding onto.
virtual void SetFramesPlayed(long long FramesPlayed)
virtual void DiscardFrames(bool KeyFrame, bool Flushed)
Releases all frames not being actively displayed from any queue onto the queue of frames ready for de...
virtual bool InputChanged(QSize VideoDim, QSize VideoDispDim, float VideoAspect, MythCodecID CodecID, bool &AspectChanged, int ReferenceFrames, bool ForceChange)
Tells video output to discard decoded frames and wait for new ones.
void SetPlayingInfo(const ProgramInfo *info)
assign programinfo to the context
void LockPlayingInfo(const char *file, int line) const
TVState GetState(void) const
RemoteEncoder * m_recorder
MythMediaBuffer * m_buffer
LiveTVChain * m_tvchain
void UnlockPlayingInfo(const char *file, int line) const
ProgramInfo * m_playingInfo
Currently playing info.
Holds information on recordings and videos.
Definition: programinfo.h:74
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
Definition: programinfo.h:380
AutoExpireType QueryAutoExpire(void) const
Returns "autoexpire" field from "recorded" table.
bool IsVideo(void) const
Definition: programinfo.h:497
QString GetChanNum(void) const
This is the channel "number", in the form 1, 1_2, 1-2, 1#1, etc.
Definition: programinfo.h:384
QString GetChannelSchedulingID(void) const
This is the unique programming identifier of a channel.
Definition: programinfo.h:391
void FillPositionMap(int64_t start, int64_t end, frm_pos_map_t &positionMap)
bool IsValidRecorder(void) const
float GetFrameRate(void)
Returns recordering frame rate set by nvr.
long long GetFramesWritten(void)
Returns number of frames written to disk by TVRec's RecorderBase instance.
long long GetCachedFramesWritten(void) const
Return value last returned by GetFramesWritten().
Definition: remoteencoder.h:40
void FillDurationMap(int64_t start, int64_t end, frm_pos_map_t &durationMap)
int GetRecorderNumber(void) const
static uint Parse(const QString &vbiformat)
Definition: tv.h:17
#define setpriority(x, y, z)
Definition: compat.h:74
#define PRIO_PROCESS
Definition: compat.h:73
unsigned int uint
Definition: compat.h:60
EofState
Definition: decoderbase.h:68
@ kEofStateNone
Definition: decoderbase.h:69
@ kEofStateImmediate
Definition: decoderbase.h:71
std::vector< char > TestBufferVec
Definition: decoderbase.h:23
const int kDecoderProbeBufferSize
Definition: decoderbase.h:22
DecodeType
Definition: decoderbase.h:48
@ kDecodeVideo
Definition: decoderbase.h:50
@ kDecodeAV
Definition: decoderbase.h:52
static uint32_t * tmp
Definition: goom_core.cpp:28
bool is_current_thread(MThread *thread)
Use this to determine if you are in the named thread.
Definition: mthread.cpp:40
std::enable_if_t< std::is_floating_point_v< T >, std::chrono::milliseconds > millisecondsFromFloat(T value)
Helper function for convert a floating point number to a duration.
Definition: mythchrono.h:91
static constexpr T chronomult(T duration, double f)
Multiply a duration by a float, returning a duration.
Definition: mythchrono.h:199
std::enable_if_t< std::is_floating_point_v< T >, std::chrono::seconds > secondsFromFloat(T value)
Helper function for convert a floating point number to a duration.
Definition: mythchrono.h:80
std::enable_if_t< std::is_floating_point_v< T >, std::chrono::microseconds > microsecondsFromFloat(T value)
Helper function for convert a floating point number to a duration.
Definition: mythchrono.h:102
QString get_encoding_type(MythCodecID codecid)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
bool myth_nice(int val)
#define LOC
Definition: mythplayer.cpp:53
static float ffrewScaleLowest
static float ffrewScaleHighest
static float ffrewSkipThresh
static unsigned dbg_ident(const MythPlayer *)
static bool preBufferDebug
Definition: mythplayer.cpp:715
static float ffrewScaleAdjust
PlayerFlags
Definition: mythplayer.h:64
@ kMusicChoice
Definition: mythplayer.h:75
@ kAudioMuted
Definition: mythplayer.h:73
@ kVideoIsNull
Definition: mythplayer.h:72
TCTypes
Timecode types.
Definition: mythplayer.h:54
@ TC_VIDEO
Definition: mythplayer.h:55
@ TC_AUDIO
Definition: mythplayer.h:56
@ kAVSyncAudioPausedLiveTV
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:15
def scan(profile, smoonURL, gate)
Definition: scan.py:54
QMap< uint64_t, MarkTypes > frm_dir_map_t
Frame # -> Mark map.
Definition: programtypes.h:117
@ kLiveTVAutoExpire
Definition: programtypes.h:196
QMap< long long, long long > frm_pos_map_t
Frame # -> File offset map.
Definition: programtypes.h:44
@ kState_WatchingPreRecorded
Watching Pre-recorded is a TV only state for when we are watching a pre-existing recording.
Definition: tv.h:70
FrameScanType
Definition: videoouttypes.h:95
@ kScan_Progressive
QString ScanTypeToString(FrameScanType Scan)