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"
30
31#include "DetectLetterbox.h"
32#include "audioplayer.h"
33#include "cardutil.h"
37#include "dummydecoder.h"
38#include "io/mythmediabuffer.h"
39#include "jitterometer.h"
40#include "livetvchain.h"
41#include "mythavutil.h"
42#include "mythplayer.h"
43#include "mythvideooutnull.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 return false;
1313}
1314
1316{
1317 uint64_t bookmark = 0;
1318
1321 bookmark = 0;
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 ret = 0;
1490 else if (behind - ff <= maxtime)
1491 {
1492 auto msec = millisecondsFromFloat(1000 * (secsWritten - maxtime));
1493 ret = TranslatePositionMsToFrame(msec, true) - m_framesPlayed;
1494 }
1495
1496 if (behind < maxtime * 3)
1497 m_limitKeyRepeat = true;
1498 }
1499 else if (IsPaused())
1500 {
1501 uint64_t lastFrame =
1503 if (m_framesPlayed + ffframes >= lastFrame)
1504 ret = lastFrame - 1 - m_framesPlayed;
1505 }
1506 else
1507 {
1508 float secsMax = secsWritten - (2.F * maxtime);
1509 if (secsMax <= 0.F)
1510 ret = 0;
1511 else if (secsMax < secsPlayed + ff)
1512 {
1513 auto msec = millisecondsFromFloat(1000 * secsMax);
1514 ret = TranslatePositionMsToFrame(msec, true) - m_framesPlayed;
1515 }
1516 }
1517
1518 return ret;
1519}
1520
1528{
1529 if (!m_videoOutput || !m_decoder)
1530 return false;
1531
1534}
1535
1539{
1540 if (!m_playerCtx)
1541 return false;
1542
1543 m_playerCtx->LockPlayingInfo(__FILE__, __LINE__);
1545 !m_decoder)
1546 {
1547 m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
1548 return false;
1549 }
1550 m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
1551
1552 auto margin = (long long)(m_videoFrameRate * 2);
1553 margin = (long long) (margin * m_audio.GetStretchFactor());
1554 bool watchingTV = IsWatchingInprogress();
1555
1556 uint64_t framesRead = m_framesPlayed;
1557 uint64_t framesLeft = 0;
1558
1560 {
1561 if (framesRead >= m_deleteMap.GetLastFrame())
1562 return true;
1563 uint64_t frameCount = GetCurrentFrameCount();
1564 framesLeft = (frameCount > framesRead) ? frameCount - framesRead : 0;
1565 return (framesLeft < (uint64_t)margin);
1566 }
1567
1568 if (!m_liveTV && !watchingTV)
1569 return false;
1570
1572 return false;
1573
1575 {
1576 framesLeft =
1578
1579 // if it looks like we are near end, get an updated GetFramesWritten()
1580 if (framesLeft < (uint64_t)margin)
1581 framesLeft = m_playerCtx->m_recorder->GetFramesWritten() - framesRead;
1582 }
1583
1584 return (framesLeft < (uint64_t)margin);
1585}
1586
1587bool MythPlayer::DoFastForward(uint64_t frames, double inaccuracy)
1588{
1590 return false;
1591
1592 uint64_t number = (frames ? frames - 1 : 0);
1593 uint64_t desiredFrame = m_framesPlayed + number;
1594
1595 if (!m_deleteMap.IsEditing() && IsInDelete(desiredFrame))
1596 {
1597 uint64_t endcheck = m_deleteMap.GetLastFrame();
1598 desiredFrame = std::min(desiredFrame, endcheck);
1599 }
1600
1601 uint64_t seeksnap_wanted = UINT64_MAX;
1602 if (inaccuracy != kInaccuracyFull)
1603 seeksnap_wanted = frames * inaccuracy;
1604 WaitForSeek(desiredFrame, seeksnap_wanted);
1605 m_ffTime = 0;
1606 ClearAfterSeek(false);
1607 return true;
1608}
1609
1610void MythPlayer::DoJumpToFrame(uint64_t frame, double inaccuracy)
1611{
1612 if (frame > m_framesPlayed)
1613 DoFastForward(frame - m_framesPlayed, inaccuracy);
1614 else
1615 DoRewind(m_framesPlayed - frame, inaccuracy);
1616}
1617
1618void MythPlayer::WaitForSeek(uint64_t frame, uint64_t seeksnap_wanted)
1619{
1620 if (!m_decoder)
1621 return;
1622
1624 m_decoder->SetSeekSnap(seeksnap_wanted);
1625
1626 bool islivetvcur = (m_liveTV && m_playerCtx->m_tvchain &&
1628
1629 uint64_t max = GetCurrentFrameCount();
1630 if (islivetvcur || IsWatchingInprogress())
1631 {
1632 max = (uint64_t)m_playerCtx->m_recorder->GetFramesWritten();
1633 }
1634 if (frame >= max)
1635 frame = max - 1;
1636
1637 m_decoderSeekLock.lock();
1638 m_decoderSeek = frame;
1639 m_decoderSeekLock.unlock();
1640
1641 int count = 0;
1642 bool needclear = false;
1643 while (m_decoderSeek >= 0)
1644 {
1645 // Waiting blocks the main UI thread but the decoder may
1646 // have initiated a callback into the UI thread to create
1647 // certain resources. Ensure the callback is processed.
1648 // Ideally MythPlayer should be fully event driven and these
1649 // calls wouldn't be necessary.
1650 emit CheckCallbacks();
1651
1652 // Wait a little
1653 std::this_thread::sleep_for(50ms);
1654
1655 // provide some on screen feedback if seeking is slow
1656 count++;
1657 if (!(count % 3) && !m_hasFullPositionMap)
1658 {
1659 emit SeekingSlow(count);
1660 needclear = true;
1661 }
1662 }
1663 if (needclear)
1664 emit SeekingComplete();
1665
1666 emit SeekingDone();
1667}
1668
1681void MythPlayer::ClearAfterSeek(bool clearvideobuffers)
1682{
1683 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("ClearAfterSeek(%1)")
1684 .arg(clearvideobuffers));
1685
1686 if (clearvideobuffers && m_videoOutput)
1688
1689 std::chrono::milliseconds savedTC = m_tcWrap[TC_AUDIO];
1690
1691 m_tcWrap.fill(0ms);
1692 m_tcWrap[TC_AUDIO] = savedTC;
1693 m_audio.Reset();
1694
1695 emit RequestResetCaptions();
1699 m_needNewPauseFrame = true;
1700
1702}
1703
1704bool MythPlayer::IsInDelete(uint64_t frame)
1705{
1706 return m_deleteMap.IsInDelete(frame);
1707}
1708
1710{
1712}
1713
1715{
1716 if (m_decoder)
1718 return {};
1719}
1720
1721QString MythPlayer::GetXDS(const QString &key) const
1722{
1723 if (!m_decoder)
1724 return {};
1725 return m_decoder->GetXDS(key);
1726}
1727
1729{
1732}
1733
1734// Returns the total frame count, as totalFrames for a completed
1735// recording, or the most recent frame count from the recorder for
1736// live TV or an in-progress recording.
1738{
1739 uint64_t result = m_totalFrames;
1742 return result;
1743}
1744
1745// Finds the frame number associated with the given time offset. A
1746// positive offset or +0.0F indicate offset from the beginning. A
1747// negative offset or -0.0F indicate offset from the end. Limit the
1748// result to within bounds of the video.
1749uint64_t MythPlayer::FindFrame(float offset, bool use_cutlist) const
1750{
1751 bool islivetvcur = (m_liveTV && m_playerCtx->m_tvchain &&
1753 std::chrono::milliseconds length_ms = TranslatePositionFrameToMs(m_totalFrames, use_cutlist);
1754 std::chrono::milliseconds position_ms = 0ms;
1755 auto offset_ms = std::chrono::milliseconds(llroundf(fabsf(offset) * 1000));
1756
1757 if (signbit(offset))
1758 {
1759 // Always get an updated totalFrame value for in progress recordings
1760 if (islivetvcur || IsWatchingInprogress())
1761 {
1762 uint64_t framesWritten = m_playerCtx->m_recorder->GetFramesWritten();
1763
1764 if (m_totalFrames < framesWritten)
1765 {
1766 // Known duration is less than what the backend reported, use new value
1767 length_ms =
1768 TranslatePositionFrameToMs(framesWritten, use_cutlist);
1769 }
1770 }
1771 position_ms = (offset_ms > length_ms) ? 0ms : length_ms - offset_ms;
1772 }
1773 else
1774 {
1775 position_ms = offset_ms;
1776 if (offset_ms > length_ms)
1777 {
1778 // Make sure we have an updated totalFrames
1779 if ((islivetvcur || IsWatchingInprogress()) &&
1780 (length_ms < offset_ms))
1781 {
1782 long long framesWritten =
1784
1785 length_ms =
1786 TranslatePositionFrameToMs(framesWritten, use_cutlist);
1787 }
1788 position_ms = std::min(position_ms, length_ms);
1789 }
1790 }
1791 return TranslatePositionMsToFrame(position_ms, use_cutlist);
1792}
1793
1794// If position == -1, it signifies that we are computing the current
1795// duration of an in-progress recording. In this case, we fetch the
1796// current frame rate and frame count from the recorder.
1797std::chrono::milliseconds MythPlayer::TranslatePositionFrameToMs(uint64_t position,
1798 bool use_cutlist) const
1799{
1800 float frameRate = GetFrameRate();
1801 if (position == UINT64_MAX &&
1803 {
1804 float recorderFrameRate = m_playerCtx->m_recorder->GetFrameRate();
1805 if (recorderFrameRate > 0)
1806 frameRate = recorderFrameRate;
1808 }
1809 return m_deleteMap.TranslatePositionFrameToMs(position, frameRate,
1810 use_cutlist);
1811}
1812
1814{
1815 if (m_decoder)
1816 return m_decoder->GetNumChapters();
1817 return 0;
1818}
1819
1821{
1822 if (m_decoder)
1824 return 0;
1825}
1826
1827void MythPlayer::GetChapterTimes(QList<std::chrono::seconds> &times)
1828{
1829 if (m_decoder)
1830 m_decoder->GetChapterTimes(times);
1831}
1832
1834{
1835 int64_t desiredFrame = -1;
1836 int total = GetNumChapters();
1837 int current = GetCurrentChapter();
1838
1839 if (chapter < 0 || chapter > total)
1840 {
1841
1842 if (chapter < 0)
1843 {
1844 chapter = current -1;
1845 chapter = std::max(chapter, 0);
1846 }
1847 else if (chapter > total)
1848 {
1849 chapter = current + 1;
1850 chapter = std::min(chapter, total);
1851 }
1852 }
1853
1854 desiredFrame = GetChapter(chapter);
1855 LOG(VB_PLAYBACK, LOG_INFO, LOC +
1856 QString("DoJumpChapter: current %1 want %2 (frame %3)")
1857 .arg(current).arg(chapter).arg(desiredFrame));
1858
1859 if (desiredFrame < 0)
1860 {
1861 LOG(VB_PLAYBACK, LOG_ERR, LOC + QString("DoJumpChapter failed."));
1862 m_jumpChapter = 0;
1863 return false;
1864 }
1865
1866 DoJumpToFrame(desiredFrame, kInaccuracyNone);
1867 m_jumpChapter = 0;
1868 return true;
1869}
1870
1871int64_t MythPlayer::GetChapter(int chapter)
1872{
1873 if (m_decoder)
1874 return m_decoder->GetChapter(chapter);
1875 return 0;
1876}
1877
1882{
1883 m_totalDecoderPause = true;
1884 PauseDecoder();
1885
1886 {
1887 while (!m_decoderChangeLock.tryLock(10))
1888 LOG(VB_GENERAL, LOG_INFO, LOC + "Waited 10ms for decoder lock");
1889 delete m_decoder;
1890 m_decoder = dec;
1891 if (m_decoder)
1893 m_decoderChangeLock.unlock();
1894 }
1895 // reset passthrough override
1896 m_disablePassthrough = false;
1898 m_totalDecoderPause = false;
1899}
1900
1901bool MythPlayer::PosMapFromEnc(uint64_t start,
1902 frm_pos_map_t &posMap,
1903 frm_pos_map_t &durMap)
1904{
1905 // Reads only new positionmap entries from encoder
1906 if (!(m_liveTV || (m_playerCtx->m_recorder &&
1908 return false;
1909
1910 // if livetv, and we're not the last entry, don't get it from the encoder
1911 if (HasTVChainNext())
1912 return false;
1913
1914 LOG(VB_PLAYBACK, LOG_INFO, LOC +
1915 QString("Filling position map from %1 to %2") .arg(start).arg("end"));
1916
1917 m_playerCtx->m_recorder->FillPositionMap(start, -1, posMap);
1918 m_playerCtx->m_recorder->FillDurationMap(start, -1, durMap);
1919
1920 return true;
1921}
1922
1923void MythPlayer::SetErrored(const QString &reason)
1924{
1925 QMutexLocker locker(&m_errorLock);
1926
1927 if (m_videoOutput)
1929
1930 if (m_errorMsg.isEmpty())
1931 {
1932 m_errorMsg = reason;
1933 }
1934 else
1935 {
1936 LOG(VB_GENERAL, LOG_ERR, LOC + QString("%1").arg(reason));
1937 }
1938}
1939
1941{
1942 QMutexLocker locker(&m_errorLock);
1943
1944 m_errorMsg = QString();
1945}
1946
1948{
1949 QMutexLocker locker(&m_errorLock);
1950 return !m_errorMsg.isEmpty();
1951}
1952
1953QString MythPlayer::GetError(void) const
1954{
1955 QMutexLocker locker(&m_errorLock);
1956 return m_errorMsg;
1957}
1958
1960{
1961 if (!m_decoder)
1962 return;
1963
1965}
1966
1968{
1969 if (!m_decoder)
1970 return;
1971
1973}
1974
1976{
1977 if (!m_decoder)
1978 return;
1979
1981}
1982
1984{
1985 if (m_decoder && m_audio.HasAudioOut())
1986 {
1987 float stretch = m_audio.GetStretchFactor();
1988 m_disablePassthrough |= (stretch < 0.99F) || (stretch > 1.01F);
1989 LOG(VB_PLAYBACK, LOG_INFO, LOC +
1990 QString("Stretch Factor %1, %2 passthru ")
1992 .arg((m_disablePassthrough) ? "disable" : "allow"));
1994 }
1995}
1996
1998{
1999 if (m_decoder && m_audio.HasAudioOut())
2001}
2002
2004{
2005 if (m_decoder && m_audio.HasAudioOut())
2007}
2008
2009static unsigned dbg_ident(const MythPlayer *player)
2010{
2011 static QMutex s_dbgLock;
2012 static unsigned s_dbgNextIdent = 0;
2013 using DbgMapType = QHash<const MythPlayer*, unsigned>;
2014 static DbgMapType s_dbgIdent;
2015
2016 QMutexLocker locker(&s_dbgLock);
2017 DbgMapType::iterator it = s_dbgIdent.find(player);
2018 if (it != s_dbgIdent.end())
2019 return *it;
2020 return s_dbgIdent[player] = s_dbgNextIdent++;
2021}
#define assert(x)
bool IsPaused(void)
float GetStretchFactor(void) const
Definition: audioplayer.h:64
bool HasAudioOut(void) const
Definition: audioplayer.h:52
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:1680
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:377
void SetDuration(std::chrono::seconds duration)
Definition: mythplayer.cpp:390
bool m_needNewPauseFrame
Definition: mythplayer.h:391
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:399
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:242
QMutex m_bufferPauseLock
Definition: mythplayer.h:379
bool m_normalSpeed
Definition: mythplayer.h:493
bool FlagIsSet(PlayerFlags arg)
Definition: mythplayer.h:318
std::chrono::microseconds m_frameInterval
always adjusted for play_speed
Definition: mythplayer.h:486
QMutex m_vidExitLock
Definition: mythplayer.h:398
void UnpauseVideo(void)
Definition: mythplayer.cpp:224
long long m_rewindTime
Definition: mythplayer.h:428
bool HasTVChainNext(void) const
bool m_inJumpToProgramPause
Definition: mythplayer.h:385
bool m_unpauseDecoder
Definition: mythplayer.h:387
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:257
bool m_decodeOneFrame
Definition: mythplayer.h:389
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:403
MythPlayer(PlayerContext *Context, PlayerFlags Flags=kNoFlags)
Definition: mythplayer.cpp:78
bool m_allPaused
Definition: mythplayer.h:394
void SetFramesPlayed(uint64_t played)
Definition: mythplayer.cpp:559
bool m_disableForcedSubtitles
Definition: mythplayer.h:464
MythDecoderThread * m_decoderThread
Definition: mythplayer.h:367
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:378
bool UpdateFFRewSkip(float ffrewScale=1.0F)
DecoderBase * m_decoder
Definition: mythplayer.h:362
int m_videobufRetries
How often we have tried to wait for a video output buffer and failed.
Definition: mythplayer.h:423
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:239
QRecursiveMutex m_decoderChangeLock
Definition: mythplayer.h:363
QTime m_bufferingStart
Definition: mythplayer.h:449
QWaitCondition m_decoderThreadPause
Definition: mythplayer.h:375
static const int kNightModeContrastAdjustment
Definition: mythplayer.h:238
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:241
const VideoFrameTypes * m_renderFormats
Definition: mythplayer.h:365
uint64_t m_framesPlayed
Definition: mythplayer.h:424
QString GetError(void) const
bool m_pauseDecoder
Definition: mythplayer.h:386
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:413
bool IsInDelete(uint64_t frame)
int m_jumpChapter
Definition: mythplayer.h:410
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:384
bool m_renderOneFrame
Definition: mythplayer.h:390
int m_ffrewSkip
Definition: mythplayer.h:488
virtual void ReinitVideo(bool ForceUpdate)
Definition: mythplayer.cpp:294
std::chrono::seconds m_totalDuration
Definition: mythplayer.h:427
void ResetTotalDuration(void)
bool m_limitKeyRepeat
Definition: mythplayer.h:407
bool IsPaused(void) const
Definition: mythplayer.h:151
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:397
uint64_t m_totalFrames
Definition: mythplayer.h:425
bool m_videoPaused
Definition: mythplayer.h:393
void RequestResetCaptions()
bool m_transcoding
Definition: mythplayer.h:405
static const double kSeekToEndOffset
Definition: mythplayer.h:243
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:372
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:229
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:402
int m_endExitPrompt
Definition: mythplayer.h:414
void EnableForcedSubtitles(bool enable)
Definition: mythplayer.cpp:676
bool volatile m_killDecoder
Definition: mythplayer.h:388
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:404
void CheckCallbacks()
void SaveTotalFrames(void)
QMutex m_errorLock
Definition: mythplayer.h:400
bool IsReallyNearEnd(void) const
Returns true iff really near end of recording.
bool m_playing
Definition: mythplayer.h:395
void FileChangedCallback()
Definition: mythplayer.cpp:941
QMutex m_pauseLock
Definition: mythplayer.h:381
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:368
int64_t m_decoderSeek
Definition: mythplayer.h:382
float ComputeSecs(uint64_t position, bool use_cutlist) const
Definition: mythplayer.h:272
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:376
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:315
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:419
virtual void DecoderPauseCheck(void)
std::chrono::milliseconds m_latestVideoTimecode
Definition: mythplayer.h:429
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:237
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:406
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:366
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:392
friend class MythDecoderThread
Definition: mythplayer.h:91
std::chrono::seconds m_totalLength
Definition: mythplayer.h:426
MythVideoOutput * m_videoOutput
Definition: mythplayer.h:364
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:380
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:133
std::chrono::milliseconds TranslatePositionFrameToMs(uint64_t position, bool use_cutlist) const
bool m_totalDecoderPause
Definition: mythplayer.h:383
void DiscardVideoFrame(MythVideoFrame *buffer)
Places frame in the available frames queue.
Definition: mythplayer.cpp:626
QString m_errorMsg
Reason why NVP exited with a error.
Definition: mythplayer.h:401
bool m_fileChanged
Definition: mythplayer.h:491
static const double kInaccuracyDefault
Definition: mythplayer.h:240
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:68
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
Definition: programinfo.h:373
AutoExpireType QueryAutoExpire(void) const
Returns "autoexpire" field from "recorded" table.
bool IsVideo(void) const
Definition: programinfo.h:490
QString GetChanNum(void) const
This is the channel "number", in the form 1, 1_2, 1-2, 1#1, etc.
Definition: programinfo.h:377
QString GetChannelSchedulingID(void) const
This is the unique programming identifier of a channel.
Definition: programinfo.h:384
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:129
#define PRIO_PROCESS
Definition: compat.h:128
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
unsigned int uint
Definition: freesurround.h:24
static guint32 * tmp
Definition: goom_core.cpp:26
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:65
@ kMusicChoice
Definition: mythplayer.h:76
@ kAudioMuted
Definition: mythplayer.h:74
@ kVideoIsNull
Definition: mythplayer.h:73
TCTypes
Timecode types.
Definition: mythplayer.h:55
@ TC_VIDEO
Definition: mythplayer.h:56
@ TC_AUDIO
Definition: mythplayer.h:57
@ 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)