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"
22#include "libmythbase/mythconfig.h"
29
30#include "DetectLetterbox.h"
31#include "audioplayer.h"
32#include "cardutil.h"
36#include "dummydecoder.h"
37#include "io/mythmediabuffer.h"
38#include "jitterometer.h"
39#include "livetvchain.h"
40#include "mythavutil.h"
41#include "mythplayer.h"
42#include "mythvideooutnull.h"
43#include "programinfo.h"
44#include "remoteencoder.h"
45#include "tv_actions.h"
46#include "tv_play.h"
47
48extern "C" {
49#include "libavcodec/avcodec.h"
50}
51
52static unsigned dbg_ident(const MythPlayer* /*player*/);
53
54#define LOC QString("Player(%1): ").arg(dbg_ident(this),0,36)
55
58
59// Exact frame seeking, no inaccuracy allowed.
60const double MythPlayer::kInaccuracyNone = 0;
61
62// By default, when seeking, snap to a keyframe if the keyframe's
63// distance from the target frame is less than 10% of the total seek
64// distance.
65const double MythPlayer::kInaccuracyDefault = 0.1;
66
67// Allow greater inaccuracy (50%) in the cutlist editor (unless the
68// editor seek distance is set to 1 frame or 1 keyframe).
69const double MythPlayer::kInaccuracyEditor = 0.5;
70
71// Any negative value means completely inexact, i.e. seek to the
72// keyframe that is closest to the target.
73const double MythPlayer::kInaccuracyFull = -1.0;
74
75// How close we can seek to the end of a recording.
76const double MythPlayer::kSeekToEndOffset = 1.0;
77
79 : m_playerCtx(Context),
80 m_playerThread(QThread::currentThread()),
81 m_playerFlags(Flags),
82 m_liveTV(Context->m_tvchain),
83 //AV subtitles
84 m_subReader(this),
85 // CC608/708
86 m_cc608(this), m_cc708(this),
87 // Audio
88 m_audio(this, (Flags & kAudioMuted) != 0)
89{
90#ifdef Q_OS_ANDROID
91 m_playerThreadId = gettid();
92#endif
94
97 m_endExitPrompt = gCoreContext->GetNumSetting("EndOfRecordingExitPrompt");
98
99 // Get VBI page number
100 QString mypage = gCoreContext->GetSetting("VBIpageNr", "888");
101 bool valid = false;
102 uint tmp = mypage.toInt(&valid, 16);
103 m_ttPageNum = (valid) ? tmp : m_ttPageNum;
105}
106
108{
109 QMutexLocker lock2(&m_vidExitLock);
110
111 SetDecoder(nullptr);
112
113 delete m_decoderThread;
114 m_decoderThread = nullptr;
115
116 delete m_videoOutput;
117 m_videoOutput = nullptr;
118}
119
121{
122 m_watchingRecording = mode;
123 if (m_decoder)
125}
126
128{
130}
131
133{
134 m_bufferPauseLock.lock();
136 {
139 }
140 m_bufferPaused = true;
141 m_bufferPauseLock.unlock();
142}
143
145{
146 m_bufferPauseLock.lock();
149 m_bufferPaused = false;
150 m_bufferPauseLock.unlock();
151}
152
154{
155 while (!m_pauseLock.tryLock(100))
156 {
157 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Waited 100ms to get pause lock.");
159 }
160 bool already_paused = m_allPaused;
161 if (already_paused)
162 {
163 m_pauseLock.unlock();
164 return already_paused;
165 }
166 m_nextPlaySpeed = 0.0;
167 m_nextNormalSpeed = false;
168 PauseVideo();
169 m_audio.Pause(true);
170 PauseDecoder();
171 PauseBuffer();
172 if (!m_decoderPaused)
173 PauseDecoder(); // Retry in case audio only stream
175 {
180 }
181 m_pauseLock.unlock();
183 return already_paused;
184}
185
186bool MythPlayer::Play(float speed, bool normal, bool unpauseaudio)
187{
188 m_pauseLock.lock();
189 LOG(VB_PLAYBACK, LOG_INFO, LOC +
190 QString("Play(%1, normal %2, unpause audio %3)")
191 .arg(speed,5,'f',1).arg(normal).arg(unpauseaudio));
192
194 {
195 LOG(VB_GENERAL, LOG_ERR, LOC + "Ignoring Play(), in edit mode.");
196 m_pauseLock.unlock();
197 return false;
198 }
199
201
205 if (unpauseaudio)
206 m_audio.Pause(false);
207 UnpauseVideo();
208 m_allPaused = false;
209 m_nextPlaySpeed = speed;
210 m_nextNormalSpeed = normal;
211 m_pauseLock.unlock();
213 return true;
214}
215
217{
218 m_videoPauseLock.lock();
219 m_needNewPauseFrame = true;
220 m_videoPaused = true;
221 m_videoPauseLock.unlock();
222}
223
225{
226 m_videoPauseLock.lock();
227 m_videoPaused = false;
228 m_videoPauseLock.unlock();
229}
230
232{
234 if (!m_playerCtx)
235 return;
236
237 m_playerCtx->LockPlayingInfo(__FILE__, __LINE__);
238 m_playerCtx->SetPlayingInfo(&pginfo);
239 m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
240}
241
242void MythPlayer::SetPlaying(bool is_playing)
243{
244 QMutexLocker locker(&m_playingLock);
245
246 m_playing = is_playing;
247
248 m_playingWaitCond.wakeAll();
249}
250
251bool MythPlayer::IsPlaying(std::chrono::milliseconds wait_in_msec, bool wait_for) const
252{
253 QMutexLocker locker(&m_playingLock);
254
255 if (wait_in_msec == 0ms)
256 return m_playing;
257
258 MythTimer t;
259 t.start();
260
261 while ((wait_for != m_playing) && (t.elapsed() < wait_in_msec))
262 {
264 &m_playingLock, std::max(0ms,wait_in_msec - t.elapsed()).count());
265 }
266
267 return m_playing;
268}
269
271{
272 if (!m_playerCtx)
273 return false;
274
275 if (!m_decoder)
276 {
277 LOG(VB_GENERAL, LOG_ERR, LOC + "Cannot create a video renderer without a decoder.");
278 return false;
279 }
280
283
284 if (!m_videoOutput)
285 {
286 LOG(VB_GENERAL, LOG_ERR, LOC + "Couldn't create VideoOutput instance. Exiting..");
287 SetErrored(tr("Failed to initialize video output"));
288 return false;
289 }
290
291 return true;
292}
293
294void MythPlayer::ReinitVideo(bool ForceUpdate)
295{
296
297 bool aspect_only = false;
298 {
299 QMutexLocker locker(&m_vidExitLock);
301 float video_aspect = (m_forcedVideoAspect > 0) ? m_forcedVideoAspect : m_videoAspect;
303 m_decoder->GetVideoCodecID(), aspect_only,
304 m_maxReferenceFrames, ForceUpdate))
305 {
306 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to Reinitialize Video. Exiting..");
307 SetErrored(tr("Failed to reinitialize video output"));
308 return;
309 }
310 }
311
312 if (!aspect_only)
314}
315
316void MythPlayer::SetKeyframeDistance(int keyframedistance)
317{
318 m_keyframeDist = (keyframedistance > 0) ? static_cast<uint>(keyframedistance) : m_keyframeDist;
319}
320
321void MythPlayer::SetVideoParams(int width, int height, double fps,
322 float aspect, bool ForceUpdate,
323 int ReferenceFrames, FrameScanType /*scan*/, const QString& codecName)
324{
325 bool paramsChanged = ForceUpdate;
326
327 if (width >= 0 && height >= 0)
328 {
329 paramsChanged = true;
330 m_videoDim = m_videoDispDim = QSize(width, height);
331 m_videoAspect = aspect > 0.0F ? aspect : static_cast<float>(width) / height;
332 }
333
334 if (!qIsNaN(fps) && fps > 0.0 && fps < 121.0)
335 {
336 paramsChanged = true;
337 m_videoFrameRate = fps;
338 if (m_ffrewSkip != 0 && m_ffrewSkip != 1)
339 {
341 }
342 else
343 {
344 float temp_speed = (m_playSpeed == 0.0F) ?
347 1.0 / (m_videoFrameRate * static_cast<double>(temp_speed)));
348 }
349 }
350
351 if (!codecName.isEmpty())
352 {
353 m_codecName = codecName;
354 paramsChanged = true;
355 }
356
357 if (ReferenceFrames > 0)
358 {
359 m_maxReferenceFrames = ReferenceFrames;
360 paramsChanged = true;
361 }
362
363 if (!paramsChanged)
364 return;
365
366 if (m_videoOutput)
367 ReinitVideo(ForceUpdate);
368
369 if (IsErrored())
370 return;
371}
372
373
375{
376 m_videoFrameRate = fps;
377 float temp_speed = (m_playSpeed == 0.0F) ? m_audio.GetStretchFactor() : m_playSpeed;
378 if (abs(m_ffrewSkip) > 1)
380 else
381 SetFrameInterval(kScan_Progressive, 1.0 / (m_videoFrameRate * static_cast<double>(temp_speed)));
382}
383
384void MythPlayer::SetFileLength(std::chrono::seconds total, int frames)
385{
386 m_totalLength = total;
387 m_totalFrames = frames;
388}
389
390void MythPlayer::SetDuration(std::chrono::seconds duration)
391{
392 m_totalDuration = duration;
393}
394
396{
397 m_isDummy = true;
398
399 if (!m_videoOutput)
400 {
402 SetVideoParams(720, 576, 25.00, 1.25F, false, 2);
403 }
404
405 m_playerCtx->LockPlayingInfo(__FILE__, __LINE__);
406 auto *dec = new DummyDecoder(this, *(m_playerCtx->m_playingInfo));
407 m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
408 SetDecoder(dec);
409}
410
412{
415}
416
417int MythPlayer::OpenFile(int Retries)
418{
419 // Sanity check
421 return -1;
422
423 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Opening '%1'").arg(m_playerCtx->m_buffer->GetSafeFilename()));
424
425 m_isDummy = false;
427
428 // Dummy setup for livetv transtions. Can we get rid of this?
430 {
431 int currentposition = m_playerCtx->m_tvchain->GetCurPos();
432 if (m_playerCtx->m_tvchain->GetInputType(currentposition) == "DUMMY")
433 {
434 OpenDummy();
435 return 0;
436 }
437 }
438
439 // Start the RingBuffer read ahead thread
441
443 TestBufferVec testbuf {};
444 testbuf.reserve(kDecoderProbeBufferSize);
445
447
448 // delete any pre-existing recorder
449 SetDecoder(nullptr);
450 int testreadsize = 2048;
451
452 // Test the incoming buffer and create a suitable decoder
453 MythTimer bigTimer;
454 bigTimer.start();
455 std::chrono::milliseconds timeout =
456 std::max(500ms * (Retries + 1), 30000ms);
457 while (testreadsize <= kDecoderProbeBufferSize)
458 {
459 testbuf.resize(testreadsize);
460 MythTimer peekTimer;
461 peekTimer.start();
462 while (m_playerCtx->m_buffer->Peek(testbuf) != testreadsize)
463 {
464 // NB need to allow for streams encountering network congestion
465 if (peekTimer.elapsed() > 30s || bigTimer.elapsed() > timeout
467 {
468 LOG(VB_GENERAL, LOG_ERR, LOC +
469 QString("OpenFile(): Could not read first %1 bytes of '%2'")
470 .arg(testreadsize)
472 SetErrored(tr("Could not read first %1 bytes").arg(testreadsize));
473 return -1;
474 }
475 LOG(VB_GENERAL, LOG_WARNING, LOC + "OpenFile() waiting on data");
476 std::this_thread::sleep_for(50ms);
477 }
478
479 m_playerCtx->LockPlayingInfo(__FILE__, __LINE__);
480 CreateDecoder(testbuf);
481 m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
482 if (m_decoder || (bigTimer.elapsed() > timeout))
483 break;
484 testreadsize <<= 1;
485 }
486
487 // Fail
488 if (!m_decoder)
489 {
490 LOG(VB_GENERAL, LOG_ERR, LOC +
491 QString("Couldn't find an A/V decoder for: '%1'")
493 SetErrored(tr("Could not find an A/V decoder"));
494
495 return -1;
496 }
497
498 if (m_decoder->IsErrored())
499 {
500 LOG(VB_GENERAL, LOG_ERR, LOC + "Could not initialize A/V decoder.");
501 SetDecoder(nullptr);
502 SetErrored(tr("Could not initialize A/V decoder"));
503
504 return -1;
505 }
506
507 // Pre-init the decoder
511 // TODO (re)move this into MythTranscode player
513
514 // Open the decoder
515 int result = m_decoder->OpenFile(m_playerCtx->m_buffer, false, testbuf);
516
517 if (result < 0)
518 {
519 LOG(VB_GENERAL, LOG_ERR, QString("Couldn't open decoder for: %1")
521 SetErrored(tr("Could not open decoder"));
522 return -1;
523 }
524
525 // Disable audio if necessary
527
528 // Livetv, recording or in-progress
529 if (result > 0)
530 {
534 }
535
536 // Determine the initial bookmark and update it for the cutlist
540
543 {
544 gCoreContext->SaveSetting("DefaultChanid",
545 static_cast<int>(m_playerCtx->m_playingInfo->GetChanID()));
546 QString callsign = m_playerCtx->m_playingInfo->GetChannelSchedulingID();
547 QString channum = m_playerCtx->m_playingInfo->GetChanNum();
548 gCoreContext->SaveSetting("DefaultChanKeys", callsign + "[]:[]" + channum);
550 {
551 uint cardid = static_cast<uint>(m_playerCtx->m_recorder->GetRecorderNumber());
552 CardUtil::SetStartChannel(cardid, channum);
553 }
554 }
555
556 return IsErrored() ? -1 : 0;
557}
558
559void MythPlayer::SetFramesPlayed(uint64_t played)
560{
561 m_framesPlayed = played;
562 if (m_videoOutput)
564}
565
570{
571 if (m_videoOutput)
573 return 0;
574}
575
586{
587 if (m_videoOutput)
589 return nullptr;
590}
591
596 std::chrono::milliseconds timecode,
597 bool wrap)
598{
599 if (wrap)
600 WrapTimecode(timecode, TC_VIDEO);
601 buffer->m_timecode = timecode;
602 m_latestVideoTimecode = timecode;
603
605 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + "Clearing decode one");
606 m_decodeOneFrame = false;
607
608 if (m_videoOutput)
609 {
610 if (abs(m_ffrewSkip) > 1)
611 {
612 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + "Setting render one");
613 m_renderOneFrame = true;
614 }
616 }
617
618 // FIXME need to handle this in the correct place in the main thread (DVD stills?)
619 //if (m_allPaused)
620 // CheckAspectRatio(buffer);
621}
622
627{
628 if (m_videoOutput)
630}
631
645void MythPlayer::DiscardVideoFrames(bool KeyFrame, bool Flushed)
646{
647 if (m_videoOutput)
648 {
649 m_videoOutput->DiscardFrames(KeyFrame, Flushed);
651 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + "Clearing render one");
652 m_renderOneFrame = false;
653 }
654}
655
657{
658 EofState eof = GetEof();
659 if (eof != kEofStateNone && !m_allPaused)
660 return true;
661 if (GetEditMode())
662 return false;
663 if (m_liveTV)
664 return false;
666 return true;
667 return false;
668}
669
671{
672 if (m_videoOutput)
674}
675
677{
678 if (enable)
680 else
682}
683
685{
686 if (m_decoder)
688 m_frameInterval = microsecondsFromFloat(1000000.0 * frame_period / m_fpsMultiplier);
689
690 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("SetFrameInterval Interval:%1 Speed:%2 Scan:%3 (Multiplier: %4)")
691 .arg(m_frameInterval.count()).arg(static_cast<double>(m_playSpeed)).arg(ScanTypeToString(scan)).arg(m_fpsMultiplier));
692}
693
695{
696 // try to get preferential scheduling, but ignore if we fail to.
697 myth_nice(-19);
698}
699
700void MythPlayer::SetBuffering(bool new_buffering)
701{
702 if (!m_buffering && new_buffering)
703 {
704 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Waiting for video buffers...");
705 m_buffering = true;
706 m_bufferingStart = QTime::currentTime();
707 m_bufferingLastMsg = QTime::currentTime();
708 }
709 else if (m_buffering && !new_buffering)
710 {
711 m_buffering = false;
712 }
713}
714
715// For debugging playback set this to increase the timeout so that
716// playback does not fail if stepping through code.
717// Set PREBUFFERDEBUG to any value and you will get 30 minutes.
718static bool preBufferDebug = qEnvironmentVariableIsSet("PREBUFFERDEBUG");
719
721{
722 if (!m_videoOutput)
723 return false;
724
725 if (!min_buffers
727 || abs(m_ffrewSkip) > 1
728 || GetEof() != kEofStateNone))
729 min_buffers = 1;
730
731 auto wait = false;
732 if (min_buffers)
733 wait = m_videoOutput->ValidVideoFrames() < min_buffers;
734 else
736
737 if (!wait)
738 {
740 m_audio.Pause(false);
741 SetBuffering(false);
743 }
744
745 SetBuffering(true);
746
747 // This piece of code is to address the problem, when starting
748 // Live TV, of jerking and stuttering. Without this code
749 // that could go on forever, but is cured by a pause and play.
750 // This code inserts a brief pause and play when the potential
751 // for the jerking is detected.
754 && m_ffrewSkip == 1
756 {
757 auto behind = (GetCurrentFrameCount() - m_framesPlayed) /
759 if (behind < 3.0)
760 {
761 LOG(VB_PLAYBACK, LOG_NOTICE, LOC +
762 "Pause to allow live tv catch up");
764 }
765 }
766
767 std::this_thread::sleep_for(m_frameInterval / 8);
768 auto waited_for = std::chrono::milliseconds(m_bufferingStart.msecsTo(QTime::currentTime()));
769 auto last_msg = std::chrono::milliseconds(m_bufferingLastMsg.msecsTo(QTime::currentTime()));
770 if (last_msg > 100ms && !FlagIsSet(kMusicChoice))
771 {
772 if (++m_bufferingCounter == 10)
773 LOG(VB_GENERAL, LOG_NOTICE, LOC +
774 "To see more buffering messages use -v playback");
775 LOG(m_bufferingCounter >= 10 ? VB_PLAYBACK : VB_GENERAL,
776 LOG_NOTICE, LOC +
777 QString("Waited %1ms for video buffers %2")
778 .arg(waited_for.count()).arg(m_videoOutput->GetFrameStatus()));
779 m_bufferingLastMsg = QTime::currentTime();
780 if (waited_for > 7s && m_audio.IsBufferAlmostFull()
781 && m_framesPlayed < 5
782 && gCoreContext->GetBoolSetting("MusicChoiceEnabled", false))
783 {
785 LOG(VB_GENERAL, LOG_NOTICE, LOC + "Music Choice program detected - disabling AV Sync.");
787 }
788 if (waited_for > 7s && m_audio.IsBufferAlmostFull()
790 {
791 // We are likely to enter this condition
792 // if the audio buffer was too full during GetFrame in AVFD
793 LOG(VB_GENERAL, LOG_NOTICE, LOC + "Resetting audio buffer");
794 m_audio.Reset();
795 }
796
798 {
799 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + "Forcibly clearing render one");
800 m_renderOneFrame = false;
801 }
802 }
803
804 std::chrono::milliseconds msecs { 500ms };
805 if (preBufferDebug)
806 msecs = 30min;
807 if ((waited_for > msecs) && !m_videoOutput->EnoughFreeFrames())
808 {
809 LOG(VB_GENERAL, LOG_NOTICE, LOC +
810 "Timed out waiting for frames, and"
811 "\n\t\t\tthere are not enough free frames. "
812 "Discarding buffered frames.");
813 // This call will result in some ugly frames, but allows us
814 // to recover from serious problems if frames get leaked.
815 DiscardVideoFrames(true, true);
816 }
817
818 msecs = 30s;
819 if (preBufferDebug)
820 msecs = 30min;
821 if (waited_for > msecs) // 30 seconds for internet streamed media
822 {
823 LOG(VB_GENERAL, LOG_ERR, LOC +
824 "Waited too long for decoder to fill video buffers. Exiting..");
825 SetErrored(tr("Video frame buffering failed too many times."));
826 }
827
828 return false;
829}
830
832{
833 m_vidExitLock.lock();
834 delete m_videoOutput;
835 m_videoOutput = nullptr;
836 m_vidExitLock.unlock();
837}
838
839bool MythPlayer::FastForward(float seconds)
840{
841 if (!m_videoOutput)
842 return false;
843
844 // Update m_totalFrames so we know how far we can skip
845 if (m_decoder)
847
848 if (m_ffTime <= 0)
849 {
850 float current = ComputeSecs(m_framesPlayed, true);
851 float dest = current + seconds;
852 float length = ComputeSecs(m_totalFrames, true);
853
854 if (dest > length)
855 {
856 auto msec = millisecondsFromFloat(seconds * 1000);
857 int64_t pos = TranslatePositionMsToFrame(msec, false);
858 if (CalcMaxFFTime(pos) < 0)
859 return true;
860 // Reach end of recording, go to offset before the end
862 }
863 uint64_t target = FindFrame(dest, true);
864 m_ffTime = target - m_framesPlayed;
865 }
866 return m_ffTime > CalcMaxFFTime(m_ffTime, false);
867}
868
869bool MythPlayer::Rewind(float seconds)
870{
871 if (!m_videoOutput)
872 return false;
873
874 if (m_rewindTime <= 0)
875 {
876 float current = ComputeSecs(m_framesPlayed, true);
877 float dest = current - seconds;
878 if (dest < 0)
879 {
880 auto msec = millisecondsFromFloat(seconds * 1000);
881 int64_t pos = TranslatePositionMsToFrame(msec, false);
882 if (CalcRWTime(pos) < 0)
883 return true;
884 dest = 0;
885 }
886 uint64_t target = FindFrame(dest, true);
887 m_rewindTime = m_framesPlayed - target;
888 }
889 return (uint64_t)m_rewindTime >= m_framesPlayed;
890}
891
892bool MythPlayer::JumpToFrame(uint64_t frame)
893{
894 if (!m_videoOutput)
895 return false;
896
897 bool ret = false;
899 if (frame > m_framesPlayed)
900 {
901 m_ffTime = frame - m_framesPlayed;
902 ret = m_ffTime > CalcMaxFFTime(m_ffTime, false);
903 }
904 else if (frame < m_framesPlayed)
905 {
907 ret = m_ffTime > CalcMaxFFTime(m_ffTime, false);
908 }
909 return ret;
910}
911
912
913void MythPlayer::JumpChapter(int chapter)
914{
915 if (m_jumpChapter == 0)
916 m_jumpChapter = chapter;
917}
918
919void MythPlayer::ResetPlaying(bool resetframes)
920{
922 m_ffrewSkip = 1;
923 if (resetframes)
924 m_framesPlayed = 0;
925 if (m_decoder)
926 {
927 m_decoder->Reset(true, true, true);
928 if (m_decoder->IsErrored())
929 SetErrored("Unable to reset video decoder");
930 }
931}
932
934{
935 bool last = !(m_playerCtx->m_tvchain->HasNext());
937}
938
939// This is called from decoder thread. Set an indicator that will
940// be checked and actioned in the player thread.
942{
943 LOG(VB_PLAYBACK, LOG_INFO, LOC + "FileChangedCallback");
944 m_fileChanged = true;
945}
946
948{
949 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("StopPlaying - begin"));
950 m_playerThread->setPriority(QThread::NormalPriority);
951#ifdef Q_OS_ANDROID
952 setpriority(PRIO_PROCESS, m_playerThreadId, 0);
953#endif
954
955 emit CheckCallbacks();
956 DecoderEnd();
957 VideoEnd();
958 AudioEnd();
959
960 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("StopPlaying - end"));
961}
962
964{
966}
967
969{
970 m_decoderPauseLock.lock();
972 {
973 m_decoderPaused = true;
974 m_decoderThreadPause.wakeAll();
975 m_decoderPauseLock.unlock();
976 return m_decoderPaused;
977 }
978
979 int tries = 0;
980 m_pauseDecoder = true;
981 while (m_decoderThread && !m_killDecoder && (tries++ < 100) &&
983 {
984 emit CheckCallbacks();
985 LOG(VB_GENERAL, LOG_WARNING, LOC + "Waited 100ms for decoder to pause");
986 }
987 m_pauseDecoder = false;
988 m_decoderPauseLock.unlock();
989 return m_decoderPaused;
990}
991
993{
994 m_decoderPauseLock.lock();
995
997 {
998 m_decoderPaused = false;
999 m_decoderThreadUnpause.wakeAll();
1000 m_decoderPauseLock.unlock();
1001 return;
1002 }
1003
1004 if (!IsInStillFrame())
1005 {
1006 int tries = 0;
1007 m_unpauseDecoder = true;
1008 while (m_decoderThread && !m_killDecoder && (tries++ < 100) &&
1010 {
1011 emit CheckCallbacks();
1012 LOG(VB_GENERAL, LOG_WARNING, LOC + "Waited 100ms for decoder to unpause");
1013 }
1014 m_unpauseDecoder = false;
1015 }
1016 m_decoderPauseLock.unlock();
1017}
1018
1019void MythPlayer::DecoderStart(bool start_paused)
1020{
1021 if (m_decoderThread)
1022 {
1024 {
1025 LOG(VB_GENERAL, LOG_ERR, LOC + "Decoder thread already running");
1026 }
1027 delete m_decoderThread;
1028 }
1029
1030 m_killDecoder = false;
1031 m_decoderPaused = start_paused;
1032 m_decoderThread = new MythDecoderThread(this, start_paused);
1033 if (m_decoderThread)
1035}
1036
1038{
1039 PauseDecoder();
1040 SetPlaying(false);
1041 // Ensure any hardware frames are released (after pausing the decoder) to
1042 // allow the decoder to exit cleanly
1043 DiscardVideoFrames(true, true);
1044
1045 m_killDecoder = true;
1046 int tries = 0;
1047 while (m_decoderThread && !m_decoderThread->wait(100ms) && (tries++ < 50))
1048 LOG(VB_PLAYBACK, LOG_INFO, LOC +
1049 "Waited 100ms for decoder loop to stop");
1050
1052 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to stop decoder loop.");
1053 else
1054 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Exited decoder loop.");
1055 SetDecoder(nullptr);
1056}
1057
1059{
1061 {
1062 if (m_pauseDecoder)
1063 PauseDecoder();
1064 if (m_unpauseDecoder)
1066 }
1067}
1068
1071{
1074
1075 if (!m_decoderChangeLock.tryLock(50))
1076 return kEofStateNone;
1077
1079 m_decoderChangeLock.unlock();
1080 return eof;
1081}
1082
1084{
1086 {
1087 if (m_decoder)
1088 m_decoder->SetEofState(eof);
1089 return;
1090 }
1091
1092 if (!m_decoderChangeLock.tryLock(50))
1093 return;
1094
1095 if (m_decoder)
1096 m_decoder->SetEofState(eof);
1097 m_decoderChangeLock.unlock();
1098}
1100
1102{
1103 if (pause)
1104 PauseDecoder();
1105
1106 while (!m_killDecoder && !IsErrored())
1107 {
1109
1111 {
1112 std::this_thread::sleep_for(1ms);
1113 continue;
1114 }
1115
1117 {
1118 if (!m_decoderChangeLock.tryLock(1))
1119 continue;
1120 if (m_decoder)
1121 {
1122 m_forcePositionMapSync = false;
1124 }
1125 m_decoderChangeLock.unlock();
1126 }
1127
1128 if (m_decoderSeek >= 0)
1129 {
1130 if (!m_decoderChangeLock.tryLock(1))
1131 continue;
1132 if (m_decoder)
1133 {
1134 m_decoderSeekLock.lock();
1135 if (((uint64_t)m_decoderSeek < m_framesPlayed) && m_decoder)
1137 else if (m_decoder)
1139 m_decoderSeek = -1;
1140 m_decoderSeekLock.unlock();
1141 }
1142 m_decoderChangeLock.unlock();
1143 }
1144
1145 bool obey_eof = (GetEof() != kEofStateNone) &&
1147 if (m_isDummy || ((m_decoderPaused || m_ffrewSkip == 0 || obey_eof) &&
1149 {
1150 std::this_thread::sleep_for(1ms);
1151 continue;
1152 }
1153
1156
1157 DecoderGetFrame(dt);
1158 }
1159
1160 // Clear any wait conditions
1162 m_decoderSeek = -1;
1163}
1164
1165static float ffrewScaleAdjust = 0.10F;
1166static float ffrewSkipThresh = 0.60F;
1167static float ffrewScaleLowest = 1.00F;
1168static float ffrewScaleHighest = 2.50F;
1169
1171{
1172 if (!m_decoder)
1173 return;
1174
1175 if (m_ffrewSkip > 0)
1176 {
1177 long long delta = m_decoder->GetFramesRead() - m_framesPlayed;
1178 long long real_skip = CalcMaxFFTime(m_ffrewSkip - m_ffrewAdjust + delta) - delta;
1179 long long target_frame = m_decoder->GetFramesRead() + real_skip;
1180 if (real_skip >= 0)
1181 m_decoder->DoFastForward(target_frame, true);
1182
1183 long long seek_frame = m_decoder->GetFramesRead();
1184 m_ffrewAdjust = seek_frame - target_frame;
1185 float adjustRatio = float(m_ffrewAdjust) / m_ffrewSkip;
1186 LOG(VB_PLAYBACK, LOG_INFO, LOC +
1187 QString("skip %1, adjust %2, ratio %3")
1188 .arg(m_ffrewSkip).arg(m_ffrewAdjust).arg(adjustRatio));
1189
1190 // If the needed adjustment is too large either way, adjust
1191 // the scale factor up or down accordingly.
1192 if (adjustRatio > ffrewSkipThresh
1193 && m_ffrewScale < (ffrewScaleHighest - 0.01F))
1195 else if (adjustRatio < -ffrewSkipThresh
1196 && m_ffrewScale > (ffrewScaleLowest + 0.01F))
1198 }
1199 else if (CalcRWTime(-m_ffrewSkip) >= 0)
1200 {
1201 long long cur_frame = m_decoder->GetFramesPlayed();
1202 bool toBegin = -cur_frame > m_ffrewSkip + m_ffrewAdjust;
1203 long long real_skip = (toBegin) ? -cur_frame : m_ffrewSkip + m_ffrewAdjust;
1204 long long target_frame = cur_frame + real_skip;
1205 m_decoder->DoRewind(target_frame, true);
1206
1207 long long seek_frame = m_decoder->GetFramesPlayed();
1208 m_ffrewAdjust = target_frame - seek_frame;
1209 float adjustRatio = float(m_ffrewAdjust) / m_ffrewSkip;
1210 LOG(VB_PLAYBACK, LOG_INFO, LOC +
1211 QString("skip %1, adjust, %2, ratio %3")
1212 .arg(m_ffrewSkip).arg(m_ffrewAdjust).arg(adjustRatio));
1213
1214 // If the needed adjustment is too large either way, adjust the
1215 // scale factor up or down accordingly.
1216 if (adjustRatio < -ffrewSkipThresh
1217 && m_ffrewScale < (ffrewScaleHighest - 0.01F))
1219 else if (adjustRatio > ffrewSkipThresh
1220 && m_ffrewScale > (ffrewScaleLowest + 0.01F))
1222 }
1223
1224 LOG(VB_PLAYBACK, LOG_DEBUG, "Setting decode one");
1225 m_decodeOneFrame = true;
1226}
1227
1228bool MythPlayer::DecoderGetFrame(DecodeType decodetype, bool unsafe)
1229{
1230 bool ret = false;
1231 if (!m_videoOutput)
1232 return false;
1233
1234 // Wait for frames to be available for decoding onto
1235 int tries = 0;
1236 while (!unsafe && (!m_videoOutput->EnoughFreeFrames() || m_audio.IsBufferAlmostFull()))
1237 {
1239 return false;
1240
1241 if (++tries > 10)
1242 {
1243 if (++m_videobufRetries >= 2000)
1244 {
1245 LOG(VB_GENERAL, LOG_ERR, LOC +
1246 "Decoder timed out waiting for free video buffers.");
1247 // We've tried for 20 seconds now, give up so that we don't
1248 // get stuck permanently in this state
1249 SetErrored("Decoder timed out waiting for free video buffers.");
1250 }
1251 return false;
1252 }
1253 std::this_thread::sleep_for(1ms);
1254 }
1256
1257 if (!m_decoderChangeLock.tryLock(5))
1258 return false;
1260 {
1261 m_decoderChangeLock.unlock();
1262 return false;
1263 }
1264
1265 if (abs(m_ffrewSkip) > 1 && !m_decodeOneFrame && !m_renderOneFrame)
1266 DoFFRewSkip();
1267
1268 if ((abs(m_ffrewSkip) > 0 || m_decodeOneFrame) && !m_renderOneFrame)
1269 ret = DoGetFrame(decodetype);
1270
1271 m_decoderChangeLock.unlock();
1272 return ret;
1273}
1274
1290{
1291 bool retry = false;
1292 bool ret = m_decoder->GetFrame(Type, retry);
1293 if (retry)
1294 {
1295 // Delay here so we don't spin too fast.
1296 m_decoderChangeLock.unlock();
1297 std::this_thread::sleep_for(1ms);
1298 m_decoderChangeLock.lock();
1299 return false;
1300 }
1301 return ret;
1302}
1303
1304void MythPlayer::WrapTimecode(std::chrono::milliseconds &timecode, TCTypes tc_type)
1305{
1306 timecode += m_tcWrap[tc_type];
1307}
1308
1309bool MythPlayer::PrepareAudioSample(std::chrono::milliseconds &timecode)
1310{
1311 WrapTimecode(timecode, TC_AUDIO);
1312 m_latestAudioTimecode = timecode;
1313 return false;
1314}
1315
1317{
1318 uint64_t bookmark = 0;
1319
1322 bookmark = 0;
1323 else
1324 {
1325 m_playerCtx->LockPlayingInfo(__FILE__, __LINE__);
1326 if (const ProgramInfo *pi = m_playerCtx->m_playingInfo)
1327 bookmark = pi->QueryStartMark();
1328 m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
1329 }
1330
1331 return bookmark;
1332}
1333
1334bool MythPlayer::UpdateFFRewSkip(float ffrewScale)
1335{
1336 bool skip_changed = false;
1337
1338 float temp_speed = (m_playSpeed == 0.0F) ?
1340 if (m_playSpeed >= 0.0F && m_playSpeed <= 3.0F)
1341 {
1342 skip_changed = (m_ffrewSkip != 1);
1343 if (m_decoder)
1345 m_frameInterval = microsecondsFromFloat((1000000.0 / m_videoFrameRate / static_cast<double>(temp_speed))
1346 / m_fpsMultiplier);
1347 m_ffrewSkip = static_cast<int>(m_playSpeed != 0.0F);
1348 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + "Clearing render one");
1349 }
1350 else
1351 {
1352 skip_changed = true;
1353 m_ffrewScale = ffrewScale;
1354 if (fabs(m_playSpeed) <= 10.0F)
1355 m_frameInterval = 200000us; // 5.00 fps
1356 else if (fabs(m_playSpeed) <= 20.0F)
1357 m_frameInterval = 166667us; // 6.00 fps
1358 else
1359 m_frameInterval = 150000us; // 6.67 fps
1361 float ffw_fps = fabs(static_cast<double>(m_playSpeed)) * m_videoFrameRate;
1362 float dis_fps = 1000000.0F / m_frameInterval.count();
1363 m_ffrewSkip = (int)ceil(ffw_fps / dis_fps);
1365 LOG(VB_PLAYBACK, LOG_INFO, LOC +
1366 QString("new skip %1, interval %2, scale %3")
1367 .arg(m_ffrewSkip).arg(m_frameInterval.count()).arg(m_ffrewScale));
1368 m_ffrewAdjust = 0;
1369 }
1370
1371 return skip_changed;
1372}
1373
1375{
1376 float last_speed = m_playSpeed;
1380
1381 bool skip_changed = UpdateFFRewSkip();
1382
1383 if (skip_changed && m_videoOutput)
1384 {
1386 if (m_playSpeed != 0.0F && (last_speed != 0.0F || m_ffrewSkip != 1))
1388 }
1389
1390 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Play speed: " +
1391 QString("rate: %1 speed: %2 skip: %3 => new interval %4")
1392 .arg(m_videoFrameRate).arg(static_cast<double>(m_playSpeed))
1393 .arg(m_ffrewSkip).arg(m_frameInterval.count()));
1394
1395 if (m_videoOutput)
1396 m_videoOutput->SetVideoFrameRate(static_cast<float>(m_videoFrameRate));
1397
1399 {
1402 }
1403}
1404
1405bool MythPlayer::DoRewind(uint64_t frames, double inaccuracy)
1406{
1408 return false;
1409
1410 uint64_t number = frames + 1;
1411 uint64_t desiredFrame = (m_framesPlayed > number) ? m_framesPlayed - number : 0;
1412
1413 m_limitKeyRepeat = false;
1414 if (desiredFrame < m_videoFrameRate)
1415 m_limitKeyRepeat = true;
1416
1417 uint64_t seeksnap_wanted = UINT64_MAX;
1418 if (inaccuracy != kInaccuracyFull)
1419 seeksnap_wanted = frames * inaccuracy;
1420 WaitForSeek(desiredFrame, seeksnap_wanted);
1421 m_rewindTime = 0;
1423 return true;
1424}
1425
1431long long MythPlayer::CalcRWTime(long long rw) const
1432{
1433 bool hasliveprev = (m_liveTV && m_playerCtx->m_tvchain &&
1435
1436 if (!hasliveprev || ((int64_t)m_framesPlayed >= rw))
1437 {
1438 return rw;
1439 }
1440
1441 auto seconds = secondsFromFloat(((int64_t)m_framesPlayed - rw) / m_videoFrameRate);
1442 m_playerCtx->m_tvchain->JumpToNext(false, seconds);
1443
1444 return -1;
1445}
1446
1451long long MythPlayer::CalcMaxFFTime(long long ffframes, bool setjump) const
1452{
1453 float maxtime = kSeekToEndOffset;
1454 bool islivetvcur = (m_liveTV && m_playerCtx->m_tvchain &&
1456
1457 long long ret = ffframes;
1458 float ff = ComputeSecs(ffframes, true);
1459 float secsPlayed = ComputeSecs(m_framesPlayed, true);
1460 float secsWritten = ComputeSecs(m_totalFrames, true);
1461
1462 m_limitKeyRepeat = false;
1463
1464 if (m_liveTV && !islivetvcur && m_playerCtx->m_tvchain)
1465 {
1466 // recording has completed, totalFrames will always be up to date
1467 if ((ffframes + m_framesPlayed > m_totalFrames) && setjump)
1468 {
1469 ret = -1;
1470 // Number of frames to be skipped is from the end of the current segment
1471 int64_t frames = (int64_t)m_totalFrames - (int64_t)m_framesPlayed - ffframes;
1472 auto seconds = secondsFromFloat(frames / m_videoFrameRate);
1473 m_playerCtx->m_tvchain->JumpToNext(true, seconds);
1474 }
1475 }
1476 else if (islivetvcur || IsWatchingInprogress())
1477 {
1478 if ((ff + secsPlayed) > secsWritten)
1479 {
1480 // If we attempt to seek past the last known duration,
1481 // check for up to date data
1482 long long framesWritten = m_playerCtx->m_recorder->GetFramesWritten();
1483
1484 secsWritten = ComputeSecs(framesWritten, true);
1485 }
1486
1487 float behind = secsWritten - secsPlayed;
1488
1489 if (behind < maxtime) // if we're close, do nothing
1490 ret = 0;
1491 else if (behind - ff <= maxtime)
1492 {
1493 auto msec = millisecondsFromFloat(1000 * (secsWritten - maxtime));
1494 ret = TranslatePositionMsToFrame(msec, true) - m_framesPlayed;
1495 }
1496
1497 if (behind < maxtime * 3)
1498 m_limitKeyRepeat = true;
1499 }
1500 else if (IsPaused())
1501 {
1502 uint64_t lastFrame =
1504 if (m_framesPlayed + ffframes >= lastFrame)
1505 ret = lastFrame - 1 - m_framesPlayed;
1506 }
1507 else
1508 {
1509 float secsMax = secsWritten - (2.F * maxtime);
1510 if (secsMax <= 0.F)
1511 ret = 0;
1512 else if (secsMax < secsPlayed + ff)
1513 {
1514 auto msec = millisecondsFromFloat(1000 * secsMax);
1515 ret = TranslatePositionMsToFrame(msec, true) - m_framesPlayed;
1516 }
1517 }
1518
1519 return ret;
1520}
1521
1529{
1530 if (!m_videoOutput || !m_decoder)
1531 return false;
1532
1535}
1536
1540{
1541 if (!m_playerCtx)
1542 return false;
1543
1544 m_playerCtx->LockPlayingInfo(__FILE__, __LINE__);
1546 !m_decoder)
1547 {
1548 m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
1549 return false;
1550 }
1551 m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
1552
1553 auto margin = (long long)(m_videoFrameRate * 2);
1554 margin = (long long) (margin * m_audio.GetStretchFactor());
1555 bool watchingTV = IsWatchingInprogress();
1556
1557 uint64_t framesRead = m_framesPlayed;
1558 uint64_t framesLeft = 0;
1559
1561 {
1562 if (framesRead >= m_deleteMap.GetLastFrame())
1563 return true;
1564 uint64_t frameCount = GetCurrentFrameCount();
1565 framesLeft = (frameCount > framesRead) ? frameCount - framesRead : 0;
1566 return (framesLeft < (uint64_t)margin);
1567 }
1568
1569 if (!m_liveTV && !watchingTV)
1570 return false;
1571
1573 return false;
1574
1576 {
1577 framesLeft =
1579
1580 // if it looks like we are near end, get an updated GetFramesWritten()
1581 if (framesLeft < (uint64_t)margin)
1582 framesLeft = m_playerCtx->m_recorder->GetFramesWritten() - framesRead;
1583 }
1584
1585 return (framesLeft < (uint64_t)margin);
1586}
1587
1588bool MythPlayer::DoFastForward(uint64_t frames, double inaccuracy)
1589{
1591 return false;
1592
1593 uint64_t number = (frames ? frames - 1 : 0);
1594 uint64_t desiredFrame = m_framesPlayed + number;
1595
1596 if (!m_deleteMap.IsEditing() && IsInDelete(desiredFrame))
1597 {
1598 uint64_t endcheck = m_deleteMap.GetLastFrame();
1599 desiredFrame = std::min(desiredFrame, endcheck);
1600 }
1601
1602 uint64_t seeksnap_wanted = UINT64_MAX;
1603 if (inaccuracy != kInaccuracyFull)
1604 seeksnap_wanted = frames * inaccuracy;
1605 WaitForSeek(desiredFrame, seeksnap_wanted);
1606 m_ffTime = 0;
1607 ClearAfterSeek(false);
1608 return true;
1609}
1610
1611void MythPlayer::DoJumpToFrame(uint64_t frame, double inaccuracy)
1612{
1613 if (frame > m_framesPlayed)
1614 DoFastForward(frame - m_framesPlayed, inaccuracy);
1615 else
1616 DoRewind(m_framesPlayed - frame, inaccuracy);
1617}
1618
1619void MythPlayer::WaitForSeek(uint64_t frame, uint64_t seeksnap_wanted)
1620{
1621 if (!m_decoder)
1622 return;
1623
1625 m_decoder->SetSeekSnap(seeksnap_wanted);
1626
1627 bool islivetvcur = (m_liveTV && m_playerCtx->m_tvchain &&
1629
1630 uint64_t max = GetCurrentFrameCount();
1631 if (islivetvcur || IsWatchingInprogress())
1632 {
1633 max = (uint64_t)m_playerCtx->m_recorder->GetFramesWritten();
1634 }
1635 if (frame >= max)
1636 frame = max - 1;
1637
1638 m_decoderSeekLock.lock();
1639 m_decoderSeek = frame;
1640 m_decoderSeekLock.unlock();
1641
1642 int count = 0;
1643 bool needclear = false;
1644 while (m_decoderSeek >= 0)
1645 {
1646 // Waiting blocks the main UI thread but the decoder may
1647 // have initiated a callback into the UI thread to create
1648 // certain resources. Ensure the callback is processed.
1649 // Ideally MythPlayer should be fully event driven and these
1650 // calls wouldn't be necessary.
1651 emit CheckCallbacks();
1652
1653 // Wait a little
1654 std::this_thread::sleep_for(50ms);
1655
1656 // provide some on screen feedback if seeking is slow
1657 count++;
1658 if (!(count % 3) && !m_hasFullPositionMap)
1659 {
1660 emit SeekingSlow(count);
1661 needclear = true;
1662 }
1663 }
1664 if (needclear)
1665 emit SeekingComplete();
1666
1667 emit SeekingDone();
1668}
1669
1682void MythPlayer::ClearAfterSeek(bool clearvideobuffers)
1683{
1684 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("ClearAfterSeek(%1)")
1685 .arg(clearvideobuffers));
1686
1687 if (clearvideobuffers && m_videoOutput)
1689
1690 std::chrono::milliseconds savedTC = m_tcWrap[TC_AUDIO];
1691
1692 m_tcWrap.fill(0ms);
1693 m_tcWrap[TC_AUDIO] = savedTC;
1694 m_audio.Reset();
1695
1696 emit RequestResetCaptions();
1700 m_needNewPauseFrame = true;
1701
1703}
1704
1705bool MythPlayer::IsInDelete(uint64_t frame)
1706{
1707 return m_deleteMap.IsInDelete(frame);
1708}
1709
1711{
1713}
1714
1716{
1717 if (m_decoder)
1719 return {};
1720}
1721
1722QString MythPlayer::GetXDS(const QString &key) const
1723{
1724 if (!m_decoder)
1725 return {};
1726 return m_decoder->GetXDS(key);
1727}
1728
1730{
1733}
1734
1735// Returns the total frame count, as totalFrames for a completed
1736// recording, or the most recent frame count from the recorder for
1737// live TV or an in-progress recording.
1739{
1740 uint64_t result = m_totalFrames;
1743 return result;
1744}
1745
1746// Finds the frame number associated with the given time offset. A
1747// positive offset or +0.0F indicate offset from the beginning. A
1748// negative offset or -0.0F indicate offset from the end. Limit the
1749// result to within bounds of the video.
1750uint64_t MythPlayer::FindFrame(float offset, bool use_cutlist) const
1751{
1752 bool islivetvcur = (m_liveTV && m_playerCtx->m_tvchain &&
1754 std::chrono::milliseconds length_ms = TranslatePositionFrameToMs(m_totalFrames, use_cutlist);
1755 std::chrono::milliseconds position_ms = 0ms;
1756 auto offset_ms = std::chrono::milliseconds(llroundf(fabsf(offset) * 1000));
1757
1758 if (std::signbit(offset))
1759 {
1760 // Always get an updated totalFrame value for in progress recordings
1761 if (islivetvcur || IsWatchingInprogress())
1762 {
1763 uint64_t framesWritten = m_playerCtx->m_recorder->GetFramesWritten();
1764
1765 if (m_totalFrames < framesWritten)
1766 {
1767 // Known duration is less than what the backend reported, use new value
1768 length_ms =
1769 TranslatePositionFrameToMs(framesWritten, use_cutlist);
1770 }
1771 }
1772 position_ms = (offset_ms > length_ms) ? 0ms : length_ms - offset_ms;
1773 }
1774 else
1775 {
1776 position_ms = offset_ms;
1777 if (offset_ms > length_ms)
1778 {
1779 // Make sure we have an updated totalFrames
1780 if ((islivetvcur || IsWatchingInprogress()) &&
1781 (length_ms < offset_ms))
1782 {
1783 long long framesWritten =
1785
1786 length_ms =
1787 TranslatePositionFrameToMs(framesWritten, use_cutlist);
1788 }
1789 position_ms = std::min(position_ms, length_ms);
1790 }
1791 }
1792 return TranslatePositionMsToFrame(position_ms, use_cutlist);
1793}
1794
1795// If position == -1, it signifies that we are computing the current
1796// duration of an in-progress recording. In this case, we fetch the
1797// current frame rate and frame count from the recorder.
1798std::chrono::milliseconds MythPlayer::TranslatePositionFrameToMs(uint64_t position,
1799 bool use_cutlist) const
1800{
1801 float frameRate = GetFrameRate();
1802 if (position == UINT64_MAX &&
1804 {
1805 float recorderFrameRate = m_playerCtx->m_recorder->GetFrameRate();
1806 if (recorderFrameRate > 0)
1807 frameRate = recorderFrameRate;
1809 }
1810 return m_deleteMap.TranslatePositionFrameToMs(position, frameRate,
1811 use_cutlist);
1812}
1813
1815{
1816 if (m_decoder)
1817 return m_decoder->GetNumChapters();
1818 return 0;
1819}
1820
1822{
1823 if (m_decoder)
1825 return 0;
1826}
1827
1828void MythPlayer::GetChapterTimes(QList<std::chrono::seconds> &times)
1829{
1830 if (m_decoder)
1831 m_decoder->GetChapterTimes(times);
1832}
1833
1835{
1836 int64_t desiredFrame = -1;
1837 int total = GetNumChapters();
1838 int current = GetCurrentChapter();
1839
1840 if (chapter < 0 || chapter > total)
1841 {
1842
1843 if (chapter < 0)
1844 {
1845 chapter = current -1;
1846 chapter = std::max(chapter, 0);
1847 }
1848 else if (chapter > total)
1849 {
1850 chapter = current + 1;
1851 chapter = std::min(chapter, total);
1852 }
1853 }
1854
1855 desiredFrame = GetChapter(chapter);
1856 LOG(VB_PLAYBACK, LOG_INFO, LOC +
1857 QString("DoJumpChapter: current %1 want %2 (frame %3)")
1858 .arg(current).arg(chapter).arg(desiredFrame));
1859
1860 if (desiredFrame < 0)
1861 {
1862 LOG(VB_PLAYBACK, LOG_ERR, LOC + QString("DoJumpChapter failed."));
1863 m_jumpChapter = 0;
1864 return false;
1865 }
1866
1867 DoJumpToFrame(desiredFrame, kInaccuracyNone);
1868 m_jumpChapter = 0;
1869 return true;
1870}
1871
1872int64_t MythPlayer::GetChapter(int chapter)
1873{
1874 if (m_decoder)
1875 return m_decoder->GetChapter(chapter);
1876 return 0;
1877}
1878
1883{
1884 m_totalDecoderPause = true;
1885 PauseDecoder();
1886
1887 {
1888 while (!m_decoderChangeLock.tryLock(10))
1889 LOG(VB_GENERAL, LOG_INFO, LOC + "Waited 10ms for decoder lock");
1890 delete m_decoder;
1891 m_decoder = dec;
1892 if (m_decoder)
1894 m_decoderChangeLock.unlock();
1895 }
1896 // reset passthrough override
1897 m_disablePassthrough = false;
1899 m_totalDecoderPause = false;
1900}
1901
1902bool MythPlayer::PosMapFromEnc(uint64_t start,
1903 frm_pos_map_t &posMap,
1904 frm_pos_map_t &durMap)
1905{
1906 // Reads only new positionmap entries from encoder
1907 if (!(m_liveTV || (m_playerCtx->m_recorder &&
1909 return false;
1910
1911 // if livetv, and we're not the last entry, don't get it from the encoder
1912 if (HasTVChainNext())
1913 return false;
1914
1915 LOG(VB_PLAYBACK, LOG_INFO, LOC +
1916 QString("Filling position map from %1 to %2") .arg(start).arg("end"));
1917
1918 m_playerCtx->m_recorder->FillPositionMap(start, -1, posMap);
1919 m_playerCtx->m_recorder->FillDurationMap(start, -1, durMap);
1920
1921 return true;
1922}
1923
1924void MythPlayer::SetErrored(const QString &reason)
1925{
1926 QMutexLocker locker(&m_errorLock);
1927
1928 if (m_videoOutput)
1930
1931 if (m_errorMsg.isEmpty())
1932 {
1933 m_errorMsg = reason;
1934 }
1935 else
1936 {
1937 LOG(VB_GENERAL, LOG_ERR, LOC + QString("%1").arg(reason));
1938 }
1939}
1940
1942{
1943 QMutexLocker locker(&m_errorLock);
1944
1945 m_errorMsg = QString();
1946}
1947
1949{
1950 QMutexLocker locker(&m_errorLock);
1951 return !m_errorMsg.isEmpty();
1952}
1953
1954QString MythPlayer::GetError(void) const
1955{
1956 QMutexLocker locker(&m_errorLock);
1957 return m_errorMsg;
1958}
1959
1961{
1962 if (!m_decoder)
1963 return;
1964
1966}
1967
1969{
1970 if (!m_decoder)
1971 return;
1972
1974}
1975
1977{
1978 if (!m_decoder)
1979 return;
1980
1982}
1983
1985{
1986 if (m_decoder && m_audio.HasAudioOut())
1987 {
1988 float stretch = m_audio.GetStretchFactor();
1989 m_disablePassthrough |= (stretch < 0.99F) || (stretch > 1.01F);
1990 LOG(VB_PLAYBACK, LOG_INFO, LOC +
1991 QString("Stretch Factor %1, %2 passthru ")
1993 .arg((m_disablePassthrough) ? "disable" : "allow"));
1995 }
1996}
1997
1999{
2000 if (m_decoder && m_audio.HasAudioOut())
2002}
2003
2005{
2006 if (m_decoder && m_audio.HasAudioOut())
2008}
2009
2010static unsigned dbg_ident(const MythPlayer *player)
2011{
2012 static QMutex s_dbgLock;
2013 static unsigned s_dbgNextIdent = 0;
2014 using DbgMapType = QHash<const MythPlayer*, unsigned>;
2015 static DbgMapType s_dbgIdent;
2016
2017 QMutexLocker locker(&s_dbgLock);
2018 DbgMapType::iterator it = s_dbgIdent.find(player);
2019 if (it != s_dbgIdent.end())
2020 return *it;
2021 return s_dbgIdent[player] = s_dbgNextIdent++;
2022}
#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:1682
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:81
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:35
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:47
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:811
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:862
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:847
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:575
std::chrono::milliseconds TranslatePositionFrameToMs(uint64_t position, float fallback_framerate, bool use_cutlist) const
Definition: deletemap.cpp:902
bool IsEmpty(void) const
Definition: deletemap.cpp:259
void LoadMap(const QString &undoMessage="")
Loads the delete map from the database.
Definition: deletemap.cpp:742
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:263
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:283
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:300
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:869
QMutex m_decoderPauseLock
Definition: mythplayer.h:376
void SetDuration(std::chrono::seconds duration)
Definition: mythplayer.cpp:390
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:595
void syncWithAudioStretch()
QMutex m_playingLock
Definition: mythplayer.h:398
void SetEof(EofState eof)
void OpenDummy(void)
Definition: mythplayer.cpp:395
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:224
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:968
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:321
virtual bool HasReachedEof(void) const
Definition: mythplayer.cpp:656
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:78
bool m_allPaused
Definition: mythplayer.h:393
void SetFramesPlayed(uint64_t played)
Definition: mythplayer.cpp:559
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:120
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:892
virtual bool FastForward(float seconds)
Definition: mythplayer.cpp:839
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:963
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:645
virtual void ResetPlaying(bool resetframes=true)
Definition: mythplayer.cpp:919
virtual int OpenFile(int Retries=4)
Definition: mythplayer.cpp:417
virtual void InitFrameInterval()
Definition: mythplayer.cpp:694
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:294
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:251
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:831
void SetFrameRate(double fps)
Definition: mythplayer.cpp:374
virtual int GetCurrentChapter(void)
void ForceSetupAudioStream(void)
bool IsNearEnd(void)
Returns true iff near end of recording.
bool IsWatchingInprogress(void) const
Definition: mythplayer.cpp:127
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:670
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:676
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:316
void UnpauseBuffer(void)
Definition: mythplayer.cpp:144
virtual bool PrebufferEnoughFrames(int min_buffers=0)
Definition: mythplayer.cpp:720
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:700
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:941
QMutex m_pauseLock
Definition: mythplayer.h:380
void SetFileLength(std::chrono::seconds total, int frames)
Definition: mythplayer.cpp:384
virtual void DecoderEnd(void)
float m_videoAspect
Video (input) Apect Ratio.
Definition: mythplayer.h:441
bool Pause(void)
Definition: mythplayer.cpp:153
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:947
int m_bufferingCounter
Definition: mythplayer.h:503
void PauseVideo(void)
Definition: mythplayer.cpp:216
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:132
virtual int64_t GetChapter(int chapter)
void SetPlayingInfo(const ProgramInfo &pginfo)
Definition: mythplayer.cpp:231
void UnpauseDecoder(void)
Definition: mythplayer.cpp:992
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:186
CC608Reader m_cc608
Definition: mythplayer.h:468
bool m_hasFullPositionMap
Definition: mythplayer.h:405
void CheckTVChain()
Definition: mythplayer.cpp:933
uint m_vbiMode
VBI decoder to use.
Definition: mythplayer.h:454
void SetPlaying(bool is_playing)
Definition: mythplayer.cpp:242
virtual void CreateDecoder(TestBufferVec &TestBuffer)
Definition: mythplayer.cpp:411
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:585
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:913
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:569
void SetFrameInterval(FrameScanType scan, double frame_period)
Definition: mythplayer.cpp:684
virtual bool PrepareAudioSample(std::chrono::milliseconds &timecode)
QString GetEncodingType(void) const
~MythPlayer() override
Definition: mythplayer.cpp:107
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:626
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:270
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:70
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
Definition: programinfo.h:375
AutoExpireType QueryAutoExpire(void) const
Returns "autoexpire" field from "recorded" table.
bool IsVideo(void) const
Definition: programinfo.h:492
QString GetChanNum(void) const
This is the channel "number", in the form 1, 1_2, 1-2, 1#1, etc.
Definition: programinfo.h:379
QString GetChannelSchedulingID(void) const
This is the unique programming identifier of a channel.
Definition: programinfo.h:386
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:90
#define PRIO_PROCESS
Definition: compat.h:89
unsigned int uint
Definition: compat.h:68
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:54
static float ffrewScaleLowest
static float ffrewScaleHighest
static float ffrewSkipThresh
static unsigned dbg_ident(const MythPlayer *)
static bool preBufferDebug
Definition: mythplayer.cpp:718
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)