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#ifdef Q_OS_ANDROID
81 m_playerThreadId(gettid()),
82#endif
83 m_playerFlags(Flags),
84 m_liveTV(Context->m_tvchain),
85 // CC608/708
86 m_cc608(this),
87 // Audio
88 m_audio(this, (Flags & kAudioMuted) != 0)
89{
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 {
1320 bookmark = 0;
1321 }
1322 else
1323 {
1324 m_playerCtx->LockPlayingInfo(__FILE__, __LINE__);
1325 if (const ProgramInfo *pi = m_playerCtx->m_playingInfo)
1326 bookmark = pi->QueryStartMark();
1327 m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
1328 }
1329
1330 return bookmark;
1331}
1332
1333bool MythPlayer::UpdateFFRewSkip(float ffrewScale)
1334{
1335 bool skip_changed = false;
1336
1337 float temp_speed = (m_playSpeed == 0.0F) ?
1339 if (m_playSpeed >= 0.0F && m_playSpeed <= 3.0F)
1340 {
1341 skip_changed = (m_ffrewSkip != 1);
1342 if (m_decoder)
1344 m_frameInterval = microsecondsFromFloat((1000000.0 / m_videoFrameRate / static_cast<double>(temp_speed))
1345 / m_fpsMultiplier);
1346 m_ffrewSkip = static_cast<int>(m_playSpeed != 0.0F);
1347 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + "Clearing render one");
1348 }
1349 else
1350 {
1351 skip_changed = true;
1352 m_ffrewScale = ffrewScale;
1353 if (fabs(m_playSpeed) <= 10.0F)
1354 m_frameInterval = 200000us; // 5.00 fps
1355 else if (fabs(m_playSpeed) <= 20.0F)
1356 m_frameInterval = 166667us; // 6.00 fps
1357 else
1358 m_frameInterval = 150000us; // 6.67 fps
1360 float ffw_fps = fabs(static_cast<double>(m_playSpeed)) * m_videoFrameRate;
1361 float dis_fps = 1000000.0F / m_frameInterval.count();
1362 m_ffrewSkip = (int)ceil(ffw_fps / dis_fps);
1364 LOG(VB_PLAYBACK, LOG_INFO, LOC +
1365 QString("new skip %1, interval %2, scale %3")
1366 .arg(m_ffrewSkip).arg(m_frameInterval.count()).arg(m_ffrewScale));
1367 m_ffrewAdjust = 0;
1368 }
1369
1370 return skip_changed;
1371}
1372
1374{
1375 float last_speed = m_playSpeed;
1379
1380 bool skip_changed = UpdateFFRewSkip();
1381
1382 if (skip_changed && m_videoOutput)
1383 {
1385 if (m_playSpeed != 0.0F && (last_speed != 0.0F || m_ffrewSkip != 1))
1387 }
1388
1389 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Play speed: " +
1390 QString("rate: %1 speed: %2 skip: %3 => new interval %4")
1391 .arg(m_videoFrameRate).arg(static_cast<double>(m_playSpeed))
1392 .arg(m_ffrewSkip).arg(m_frameInterval.count()));
1393
1394 if (m_videoOutput)
1395 m_videoOutput->SetVideoFrameRate(static_cast<float>(m_videoFrameRate));
1396
1398 {
1401 }
1402}
1403
1404bool MythPlayer::DoRewind(uint64_t frames, double inaccuracy)
1405{
1407 return false;
1408
1409 uint64_t number = frames + 1;
1410 uint64_t desiredFrame = (m_framesPlayed > number) ? m_framesPlayed - number : 0;
1411
1412 m_limitKeyRepeat = false;
1413 if (desiredFrame < m_videoFrameRate)
1414 m_limitKeyRepeat = true;
1415
1416 uint64_t seeksnap_wanted = UINT64_MAX;
1417 if (inaccuracy != kInaccuracyFull)
1418 seeksnap_wanted = frames * inaccuracy;
1419 WaitForSeek(desiredFrame, seeksnap_wanted);
1420 m_rewindTime = 0;
1422 return true;
1423}
1424
1430long long MythPlayer::CalcRWTime(long long rw) const
1431{
1432 bool hasliveprev = (m_liveTV && m_playerCtx->m_tvchain &&
1434
1435 if (!hasliveprev || ((int64_t)m_framesPlayed >= rw))
1436 {
1437 return rw;
1438 }
1439
1440 auto seconds = secondsFromFloat(((int64_t)m_framesPlayed - rw) / m_videoFrameRate);
1441 m_playerCtx->m_tvchain->JumpToNext(false, seconds);
1442
1443 return -1;
1444}
1445
1450long long MythPlayer::CalcMaxFFTime(long long ffframes, bool setjump) const
1451{
1452 float maxtime = kSeekToEndOffset;
1453 bool islivetvcur = (m_liveTV && m_playerCtx->m_tvchain &&
1455
1456 long long ret = ffframes;
1457 float ff = ComputeSecs(ffframes, true);
1458 float secsPlayed = ComputeSecs(m_framesPlayed, true);
1459 float secsWritten = ComputeSecs(m_totalFrames, true);
1460
1461 m_limitKeyRepeat = false;
1462
1463 if (m_liveTV && !islivetvcur && m_playerCtx->m_tvchain)
1464 {
1465 // recording has completed, totalFrames will always be up to date
1466 if ((ffframes + m_framesPlayed > m_totalFrames) && setjump)
1467 {
1468 ret = -1;
1469 // Number of frames to be skipped is from the end of the current segment
1470 int64_t frames = (int64_t)m_totalFrames - (int64_t)m_framesPlayed - ffframes;
1471 auto seconds = secondsFromFloat(frames / m_videoFrameRate);
1472 m_playerCtx->m_tvchain->JumpToNext(true, seconds);
1473 }
1474 }
1475 else if (islivetvcur || IsWatchingInprogress())
1476 {
1477 if ((ff + secsPlayed) > secsWritten)
1478 {
1479 // If we attempt to seek past the last known duration,
1480 // check for up to date data
1481 long long framesWritten = m_playerCtx->m_recorder->GetFramesWritten();
1482
1483 secsWritten = ComputeSecs(framesWritten, true);
1484 }
1485
1486 float behind = secsWritten - secsPlayed;
1487
1488 if (behind < maxtime) // if we're close, do nothing
1489 {
1490 ret = 0;
1491 }
1492 else if (behind - ff <= maxtime)
1493 {
1494 auto msec = millisecondsFromFloat(1000 * (secsWritten - maxtime));
1495 ret = TranslatePositionMsToFrame(msec, true) - m_framesPlayed;
1496 }
1497
1498 if (behind < maxtime * 3)
1499 m_limitKeyRepeat = true;
1500 }
1501 else if (IsPaused())
1502 {
1503 uint64_t lastFrame =
1505 if (m_framesPlayed + ffframes >= lastFrame)
1506 ret = lastFrame - 1 - m_framesPlayed;
1507 }
1508 else
1509 {
1510 float secsMax = secsWritten - (2.F * maxtime);
1511 if (secsMax <= 0.F)
1512 {
1513 ret = 0;
1514 }
1515 else if (secsMax < secsPlayed + ff)
1516 {
1517 auto msec = millisecondsFromFloat(1000 * secsMax);
1518 ret = TranslatePositionMsToFrame(msec, true) - m_framesPlayed;
1519 }
1520 }
1521
1522 return ret;
1523}
1524
1532{
1533 if (!m_videoOutput || !m_decoder)
1534 return false;
1535
1538}
1539
1543{
1544 if (!m_playerCtx)
1545 return false;
1546
1547 m_playerCtx->LockPlayingInfo(__FILE__, __LINE__);
1549 !m_decoder)
1550 {
1551 m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
1552 return false;
1553 }
1554 m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
1555
1556 auto margin = (long long)(m_videoFrameRate * 2);
1557 margin = (long long) (margin * m_audio.GetStretchFactor());
1558 bool watchingTV = IsWatchingInprogress();
1559
1560 uint64_t framesRead = m_framesPlayed;
1561 uint64_t framesLeft = 0;
1562
1564 {
1565 if (framesRead >= m_deleteMap.GetLastFrame())
1566 return true;
1567 uint64_t frameCount = GetCurrentFrameCount();
1568 framesLeft = (frameCount > framesRead) ? frameCount - framesRead : 0;
1569 return (framesLeft < (uint64_t)margin);
1570 }
1571
1572 if (!m_liveTV && !watchingTV)
1573 return false;
1574
1576 return false;
1577
1579 {
1580 framesLeft =
1582
1583 // if it looks like we are near end, get an updated GetFramesWritten()
1584 if (framesLeft < (uint64_t)margin)
1585 framesLeft = m_playerCtx->m_recorder->GetFramesWritten() - framesRead;
1586 }
1587
1588 return (framesLeft < (uint64_t)margin);
1589}
1590
1591bool MythPlayer::DoFastForward(uint64_t frames, double inaccuracy)
1592{
1594 return false;
1595
1596 uint64_t number = (frames ? frames - 1 : 0);
1597 uint64_t desiredFrame = m_framesPlayed + number;
1598
1599 if (!m_deleteMap.IsEditing() && IsInDelete(desiredFrame))
1600 {
1601 uint64_t endcheck = m_deleteMap.GetLastFrame();
1602 desiredFrame = std::min(desiredFrame, endcheck);
1603 }
1604
1605 uint64_t seeksnap_wanted = UINT64_MAX;
1606 if (inaccuracy != kInaccuracyFull)
1607 seeksnap_wanted = frames * inaccuracy;
1608 WaitForSeek(desiredFrame, seeksnap_wanted);
1609 m_ffTime = 0;
1610 ClearAfterSeek(false);
1611 return true;
1612}
1613
1614void MythPlayer::DoJumpToFrame(uint64_t frame, double inaccuracy)
1615{
1616 if (frame > m_framesPlayed)
1617 DoFastForward(frame - m_framesPlayed, inaccuracy);
1618 else
1619 DoRewind(m_framesPlayed - frame, inaccuracy);
1620}
1621
1622void MythPlayer::WaitForSeek(uint64_t frame, uint64_t seeksnap_wanted)
1623{
1624 if (!m_decoder)
1625 return;
1626
1628 m_decoder->SetSeekSnap(seeksnap_wanted);
1629
1630 bool islivetvcur = (m_liveTV && m_playerCtx->m_tvchain &&
1632
1633 uint64_t max = GetCurrentFrameCount();
1634 if (islivetvcur || IsWatchingInprogress())
1635 {
1636 max = (uint64_t)m_playerCtx->m_recorder->GetFramesWritten();
1637 }
1638 if (frame >= max)
1639 frame = max - 1;
1640
1641 m_decoderSeekLock.lock();
1642 m_decoderSeek = frame;
1643 m_decoderSeekLock.unlock();
1644
1645 int count = 0;
1646 bool needclear = false;
1647 while (m_decoderSeek >= 0)
1648 {
1649 // Waiting blocks the main UI thread but the decoder may
1650 // have initiated a callback into the UI thread to create
1651 // certain resources. Ensure the callback is processed.
1652 // Ideally MythPlayer should be fully event driven and these
1653 // calls wouldn't be necessary.
1654 emit CheckCallbacks();
1655
1656 // Wait a little
1657 std::this_thread::sleep_for(50ms);
1658
1659 // provide some on screen feedback if seeking is slow
1660 count++;
1661 if (!(count % 3) && !m_hasFullPositionMap)
1662 {
1663 emit SeekingSlow(count);
1664 needclear = true;
1665 }
1666 }
1667 if (needclear)
1668 emit SeekingComplete();
1669
1670 emit SeekingDone();
1671}
1672
1685void MythPlayer::ClearAfterSeek(bool clearvideobuffers)
1686{
1687 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("ClearAfterSeek(%1)")
1688 .arg(clearvideobuffers));
1689
1690 if (clearvideobuffers && m_videoOutput)
1692
1693 std::chrono::milliseconds savedTC = m_tcWrap[TC_AUDIO];
1694
1695 m_tcWrap.fill(0ms);
1696 m_tcWrap[TC_AUDIO] = savedTC;
1697 m_audio.Reset();
1698
1699 emit RequestResetCaptions();
1703 m_needNewPauseFrame = true;
1704
1706}
1707
1708bool MythPlayer::IsInDelete(uint64_t frame)
1709{
1710 return m_deleteMap.IsInDelete(frame);
1711}
1712
1714{
1716}
1717
1719{
1720 if (m_decoder)
1722 return {};
1723}
1724
1725QString MythPlayer::GetXDS(const QString &key) const
1726{
1727 if (!m_decoder)
1728 return {};
1729 return m_decoder->GetXDS(key);
1730}
1731
1733{
1736}
1737
1738// Returns the total frame count, as totalFrames for a completed
1739// recording, or the most recent frame count from the recorder for
1740// live TV or an in-progress recording.
1742{
1743 uint64_t result = m_totalFrames;
1746 return result;
1747}
1748
1749// Finds the frame number associated with the given time offset. A
1750// positive offset or +0.0F indicate offset from the beginning. A
1751// negative offset or -0.0F indicate offset from the end. Limit the
1752// result to within bounds of the video.
1753uint64_t MythPlayer::FindFrame(float offset, bool use_cutlist) const
1754{
1755 bool islivetvcur = (m_liveTV && m_playerCtx->m_tvchain &&
1757 std::chrono::milliseconds length_ms = TranslatePositionFrameToMs(m_totalFrames, use_cutlist);
1758 std::chrono::milliseconds position_ms = 0ms;
1759 auto offset_ms = std::chrono::milliseconds(llroundf(fabsf(offset) * 1000));
1760
1761 if (std::signbit(offset))
1762 {
1763 // Always get an updated totalFrame value for in progress recordings
1764 if (islivetvcur || IsWatchingInprogress())
1765 {
1766 uint64_t framesWritten = m_playerCtx->m_recorder->GetFramesWritten();
1767
1768 if (m_totalFrames < framesWritten)
1769 {
1770 // Known duration is less than what the backend reported, use new value
1771 length_ms =
1772 TranslatePositionFrameToMs(framesWritten, use_cutlist);
1773 }
1774 }
1775 position_ms = (offset_ms > length_ms) ? 0ms : length_ms - offset_ms;
1776 }
1777 else
1778 {
1779 position_ms = offset_ms;
1780 if (offset_ms > length_ms)
1781 {
1782 // Make sure we have an updated totalFrames
1783 if ((islivetvcur || IsWatchingInprogress()) &&
1784 (length_ms < offset_ms))
1785 {
1786 long long framesWritten =
1788
1789 length_ms =
1790 TranslatePositionFrameToMs(framesWritten, use_cutlist);
1791 }
1792 position_ms = std::min(position_ms, length_ms);
1793 }
1794 }
1795 return TranslatePositionMsToFrame(position_ms, use_cutlist);
1796}
1797
1798// If position == -1, it signifies that we are computing the current
1799// duration of an in-progress recording. In this case, we fetch the
1800// current frame rate and frame count from the recorder.
1801std::chrono::milliseconds MythPlayer::TranslatePositionFrameToMs(uint64_t position,
1802 bool use_cutlist) const
1803{
1804 float frameRate = GetFrameRate();
1805 if (position == UINT64_MAX &&
1807 {
1808 float recorderFrameRate = m_playerCtx->m_recorder->GetFrameRate();
1809 if (recorderFrameRate > 0)
1810 frameRate = recorderFrameRate;
1812 }
1813 return m_deleteMap.TranslatePositionFrameToMs(position, frameRate,
1814 use_cutlist);
1815}
1816
1818{
1819 if (m_decoder)
1820 return m_decoder->GetNumChapters();
1821 return 0;
1822}
1823
1825{
1826 if (m_decoder)
1828 return 0;
1829}
1830
1831void MythPlayer::GetChapterTimes(QList<std::chrono::seconds> &times)
1832{
1833 if (m_decoder)
1834 m_decoder->GetChapterTimes(times);
1835}
1836
1838{
1839 int64_t desiredFrame = -1;
1840 int total = GetNumChapters();
1841 int current = GetCurrentChapter();
1842
1843 if (chapter < 0 || chapter > total)
1844 {
1845
1846 if (chapter < 0)
1847 {
1848 chapter = current -1;
1849 chapter = std::max(chapter, 0);
1850 }
1851 else if (chapter > total)
1852 {
1853 chapter = current + 1;
1854 chapter = std::min(chapter, total);
1855 }
1856 }
1857
1858 desiredFrame = GetChapter(chapter);
1859 LOG(VB_PLAYBACK, LOG_INFO, LOC +
1860 QString("DoJumpChapter: current %1 want %2 (frame %3)")
1861 .arg(current).arg(chapter).arg(desiredFrame));
1862
1863 if (desiredFrame < 0)
1864 {
1865 LOG(VB_PLAYBACK, LOG_ERR, LOC + QString("DoJumpChapter failed."));
1866 m_jumpChapter = 0;
1867 return false;
1868 }
1869
1870 DoJumpToFrame(desiredFrame, kInaccuracyNone);
1871 m_jumpChapter = 0;
1872 return true;
1873}
1874
1875int64_t MythPlayer::GetChapter(int chapter)
1876{
1877 if (m_decoder)
1878 return m_decoder->GetChapter(chapter);
1879 return 0;
1880}
1881
1886{
1887 m_totalDecoderPause = true;
1888 PauseDecoder();
1889
1890 {
1891 while (!m_decoderChangeLock.tryLock(10))
1892 LOG(VB_GENERAL, LOG_INFO, LOC + "Waited 10ms for decoder lock");
1893 delete m_decoder;
1894 m_decoder = dec;
1895 if (m_decoder)
1897 m_decoderChangeLock.unlock();
1898 }
1899 // reset passthrough override
1900 m_disablePassthrough = false;
1902 m_totalDecoderPause = false;
1903}
1904
1905bool MythPlayer::PosMapFromEnc(uint64_t start,
1906 frm_pos_map_t &posMap,
1907 frm_pos_map_t &durMap)
1908{
1909 // Reads only new positionmap entries from encoder
1910 if (!(m_liveTV || (m_playerCtx->m_recorder &&
1912 return false;
1913
1914 // if livetv, and we're not the last entry, don't get it from the encoder
1915 if (HasTVChainNext())
1916 return false;
1917
1918 LOG(VB_PLAYBACK, LOG_INFO, LOC +
1919 QString("Filling position map from %1 to %2") .arg(start).arg("end"));
1920
1921 m_playerCtx->m_recorder->FillPositionMap(start, -1, posMap);
1922 m_playerCtx->m_recorder->FillDurationMap(start, -1, durMap);
1923
1924 return true;
1925}
1926
1927void MythPlayer::SetErrored(const QString &reason)
1928{
1929 QMutexLocker locker(&m_errorLock);
1930
1931 if (m_videoOutput)
1933
1934 if (m_errorMsg.isEmpty())
1935 {
1936 m_errorMsg = reason;
1937 }
1938 else
1939 {
1940 LOG(VB_GENERAL, LOG_ERR, LOC + QString("%1").arg(reason));
1941 }
1942}
1943
1945{
1946 QMutexLocker locker(&m_errorLock);
1947
1948 m_errorMsg = QString();
1949}
1950
1952{
1953 QMutexLocker locker(&m_errorLock);
1954 return !m_errorMsg.isEmpty();
1955}
1956
1957QString MythPlayer::GetError(void) const
1958{
1959 QMutexLocker locker(&m_errorLock);
1960 return m_errorMsg;
1961}
1962
1964{
1965 if (!m_decoder)
1966 return;
1967
1969}
1970
1972{
1973 if (!m_decoder)
1974 return;
1975
1977}
1978
1980{
1981 if (!m_decoder)
1982 return;
1983
1985}
1986
1988{
1989 if (m_decoder && m_audio.HasAudioOut())
1990 {
1991 float stretch = m_audio.GetStretchFactor();
1992 m_disablePassthrough |= (stretch < 0.99F) || (stretch > 1.01F);
1993 LOG(VB_PLAYBACK, LOG_INFO, LOC +
1994 QString("Stretch Factor %1, %2 passthru ")
1996 .arg((m_disablePassthrough) ? "disable" : "allow"));
1998 }
1999}
2000
2002{
2003 if (m_decoder && m_audio.HasAudioOut())
2005}
2006
2008{
2009 if (m_decoder && m_audio.HasAudioOut())
2011}
2012
2013static unsigned dbg_ident(const MythPlayer *player)
2014{
2015 static QMutex s_dbgLock;
2016 static unsigned s_dbgNextIdent = 0;
2017 using DbgMapType = QHash<const MythPlayer*, unsigned>;
2018 static DbgMapType s_dbgIdent;
2019
2020 QMutexLocker locker(&s_dbgLock);
2021 DbgMapType::iterator it = s_dbgIdent.find(player);
2022 if (it != s_dbgIdent.end())
2023 return *it;
2024 return s_dbgIdent[player] = s_dbgNextIdent++;
2025}
#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)
void Reset(void)
Definition: audioplayer.cpp:92
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:1690
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:824
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:875
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:860
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:586
std::chrono::milliseconds TranslatePositionFrameToMs(uint64_t position, float fallback_framerate, bool use_cutlist) const
Definition: deletemap.cpp:915
bool IsEmpty(void) const
Definition: deletemap.cpp:271
void LoadMap(const QString &undoMessage="")
Loads the delete map from the database.
Definition: deletemap.cpp:753
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:247
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:267
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:284
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
bool is_current_thread(MThread *thread)
Use this to determine if you are in the named thread.
Definition: mthread.cpp:40
static constexpr T chronomult(T duration, double f)
Multiply a duration by a float, returning a duration.
Definition: mythchrono.h:189
std::chrono::microseconds microsecondsFromFloat(T value)
Helper function for convert a floating point number to a duration.
Definition: mythchrono.h:91
std::chrono::seconds secondsFromFloat(T value)
Helper function for convert a floating point number to a duration.
Definition: mythchrono.h:68
std::chrono::milliseconds millisecondsFromFloat(T value)
Helper function for convert a floating point number to a duration.
Definition: mythchrono.h:79
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)