From 6b3d4dbfc39058c9c30133c93fd2e6254a951ac3 Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Fri, 3 Apr 2015 14:03:44 +0200 Subject: dvdplayer/omxplayer: protect live streams (pvr) from stalling --- xbmc/cores/VideoRenderers/RenderManager.cpp | 9 +++++ xbmc/cores/dvdplayer/DVDClock.cpp | 53 +++++++++++++++-------------- xbmc/cores/dvdplayer/DVDClock.h | 10 ++++-- xbmc/cores/dvdplayer/DVDPlayer.cpp | 30 ++++++++++++++++ xbmc/cores/dvdplayer/DVDPlayer.h | 1 + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 5 +-- xbmc/linux/OMXClock.cpp | 20 ++++++++++- xbmc/linux/OMXClock.h | 2 ++ xbmc/video/VideoReferenceClock.cpp | 8 +++++ xbmc/video/VideoReferenceClock.h | 1 + 10 files changed, 106 insertions(+), 33 deletions(-) diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp index 25323ef43c..25d380981c 100644 --- a/xbmc/cores/VideoRenderers/RenderManager.cpp +++ b/xbmc/cores/VideoRenderers/RenderManager.cpp @@ -175,6 +175,15 @@ void CXBMCRenderManager::WaitPresentTime(double presenttime) return; } + CDVDClock *dvdclock = CDVDClock::GetMasterClock(); + if(dvdclock != NULL && dvdclock->GetSpeedAdjust() != 0.0) + { + CDVDClock::WaitAbsoluteClock(presenttime * DVD_TIME_BASE); + m_presenterr = 0; + m_presentcorr = 0; + return; + } + double clock = CDVDClock::WaitAbsoluteClock(presenttime * DVD_TIME_BASE) / DVD_TIME_BASE; double target = 0.5; double error = ( clock - presenttime ) / frametime - target; diff --git a/xbmc/cores/dvdplayer/DVDClock.cpp b/xbmc/cores/dvdplayer/DVDClock.cpp index a496ec0172..2629530d8d 100644 --- a/xbmc/cores/dvdplayer/DVDClock.cpp +++ b/xbmc/cores/dvdplayer/DVDClock.cpp @@ -29,7 +29,7 @@ int64_t CDVDClock::m_systemOffset; int64_t CDVDClock::m_systemFrequency; CCriticalSection CDVDClock::m_systemsection; -CDVDClock *CDVDClock::m_playerclock = NULL;; +CDVDClock *CDVDClock::m_playerclock = NULL; CDVDClock::CDVDClock() : m_master(MASTER_CLOCK_NONE) @@ -42,6 +42,9 @@ CDVDClock::CDVDClock() m_bReset = true; m_iDisc = 0; m_maxspeedadjust = 0.0; + m_lastSystemTime = g_VideoReferenceClock.GetTime(); + m_systemAdjust = 0; + m_speedAdjust = 0; m_startClock = 0; @@ -103,7 +106,12 @@ CDVDClock* CDVDClock::GetMasterClock() double CDVDClock::GetClock(bool interpolated /*= true*/) { CSharedLock lock(m_critSection); - return SystemToPlaying(g_VideoReferenceClock.GetTime(interpolated)); + + int64_t current = g_VideoReferenceClock.GetTime(interpolated); + m_systemAdjust += m_speedAdjust * (current - m_lastSystemTime); + m_lastSystemTime = current; + + return SystemToPlaying(current); } double CDVDClock::GetClock(double& absolute, bool interpolated /*= true*/) @@ -115,8 +123,7 @@ double CDVDClock::GetClock(double& absolute, bool interpolated /*= true*/) absolute = SystemToAbsolute(current); } - CSharedLock lock(m_critSection); - return SystemToPlaying(current); + return GetClock(interpolated); } void CDVDClock::SetSpeed(int iSpeed) @@ -145,6 +152,18 @@ void CDVDClock::SetSpeed(int iSpeed) m_systemUsed = newfreq; } +void CDVDClock::SetSpeedAdjust(double adjust) +{ + CExclusiveLock lock(m_critSection); + m_speedAdjust = adjust; +} + +double CDVDClock::GetSpeedAdjust() +{ + CExclusiveLock lock(m_critSection); + return m_speedAdjust; +} + bool CDVDClock::Update(double clock, double absolute, double limit, const char* log) { CExclusiveLock lock(m_critSection); @@ -174,26 +193,8 @@ void CDVDClock::Discontinuity(double clock, double absolute) m_pauseClock = m_startClock; m_iDisc = clock; m_bReset = false; -} - -void CDVDClock::Pause() -{ - CExclusiveLock lock(m_critSection); - if(!m_pauseClock) - m_pauseClock = g_VideoReferenceClock.GetTime(); -} - -void CDVDClock::Resume() -{ - CExclusiveLock lock(m_critSection); - if( m_pauseClock ) - { - int64_t current; - current = g_VideoReferenceClock.GetTime(); - - m_startClock += current - m_pauseClock; - m_pauseClock = 0; - } + m_systemAdjust = 0; + m_speedAdjust = 0; } void CDVDClock::SetMaxSpeedAdjust(double speed) @@ -265,6 +266,8 @@ double CDVDClock::SystemToPlaying(int64_t system) if(m_pauseClock) m_pauseClock = m_startClock; m_iDisc = 0; + m_systemAdjust = 0; + m_speedAdjust = 0; m_bReset = false; } @@ -273,7 +276,7 @@ double CDVDClock::SystemToPlaying(int64_t system) else current = system; - return DVD_TIME_BASE * (double)(current - m_startClock) / m_systemUsed + m_iDisc; + return DVD_TIME_BASE * (double)(current - m_startClock + m_systemAdjust) / m_systemUsed + m_iDisc; } EMasterClock CDVDClock::GetMaster() diff --git a/xbmc/cores/dvdplayer/DVDClock.h b/xbmc/cores/dvdplayer/DVDClock.h index d6b2d0a71a..cf03af5101 100644 --- a/xbmc/cores/dvdplayer/DVDClock.h +++ b/xbmc/cores/dvdplayer/DVDClock.h @@ -66,9 +66,9 @@ public: } void Reset() { m_bReset = true; } - void Pause(); - void Resume(); void SetSpeed(int iSpeed); + void SetSpeedAdjust(double adjust); + double GetSpeedAdjust(); double GetClockSpeed(); /**< get the current speed of the clock relative normal system time */ @@ -101,7 +101,11 @@ protected: static int64_t m_systemOffset; static CCriticalSection m_systemsection; - double m_maxspeedadjust; + int64_t m_systemAdjust; + int64_t m_lastSystemTime; + double m_speedAdjust; + + double m_maxspeedadjust; CCriticalSection m_speedsection; static CDVDClock *m_playerclock; }; diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp index c146331e2a..38252ed830 100644 --- a/xbmc/cores/dvdplayer/DVDPlayer.cpp +++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp @@ -1778,6 +1778,7 @@ void CDVDPlayer::HandlePlaySpeed() if(m_caching != caching) SetCaching(caching); + // check buffering levels and adjust clock if (m_playSpeed == DVD_PLAYSPEED_NORMAL && m_caching == CACHESTATE_DONE) { // due to i.e. discontinuities of pts the stream may have drifted away @@ -1788,6 +1789,31 @@ void CDVDPlayer::HandlePlaySpeed() CLog::Log(LOGDEBUG,"CDVDPlayer::HandlePlaySpeed - audio stream stalled, tiggering re-sync"); TriggerResync(); } + + if (CachePVRStream()) + { + if (m_CurrentAudio.id >= 0) + { + double adjust = -1.0; // a unique value + if (m_clock.GetSpeedAdjust() == 0.0 && m_dvdPlayerAudio->GetLevel() < 5) + adjust = -0.01; + else if (m_clock.GetSpeedAdjust() == 0.0 && m_dvdPlayerAudio->GetLevel() > 95) + adjust = 0.01; + + if (m_clock.GetSpeedAdjust() < 0 && m_dvdPlayerAudio->GetLevel() > 20) + adjust = 0.0; + else if (m_clock.GetSpeedAdjust() > 0 && m_dvdPlayerAudio->GetLevel() < 80) + adjust = 0.0; + + if (adjust != -1.0) + { + m_clock.SetSpeedAdjust(adjust); + if (m_omxplayer_mode) + m_OmxPlayerState.av_clock.OMXSetSpeedAdjust(adjust); + CLog::Log(LOGDEBUG, "CDVDPlayer::HandlePlaySpeed set clock adjust: %f", adjust); + } + } + } } if(GetPlaySpeed() != DVD_PLAYSPEED_NORMAL && GetPlaySpeed() != DVD_PLAYSPEED_PAUSE) @@ -2699,6 +2725,10 @@ void CDVDPlayer::SetCaching(ECacheState state) m_pInputStream->ResetScanTimeout(0); } m_caching = state; + + m_clock.SetSpeedAdjust(0); + if (m_omxplayer_mode) + m_OmxPlayerState.av_clock.OMXSetSpeedAdjust(0); } void CDVDPlayer::SetPlaySpeed(int speed) diff --git a/xbmc/cores/dvdplayer/DVDPlayer.h b/xbmc/cores/dvdplayer/DVDPlayer.h index 468239c3c6..e12a800ba1 100644 --- a/xbmc/cores/dvdplayer/DVDPlayer.h +++ b/xbmc/cores/dvdplayer/DVDPlayer.h @@ -68,6 +68,7 @@ public: bool OMXStateExecute(bool lock = true) { return false; } void OMXStateIdle(bool lock = true) {} bool HDMIClockSync(bool lock = true) { return false; } + void OMXSetSpeedAdjust(double adjust, bool lock = true) {} }; #endif diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp index 69dc501c18..8d739ea904 100644 --- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp @@ -201,10 +201,7 @@ bool CDVDPlayerVideo::OpenStream( CDVDStreamInfo &hint ) return false; } - if(CSettings::Get().GetBool("videoplayer.usedisplayasclock") && !g_VideoReferenceClock.IsRunning()) - { - g_VideoReferenceClock.Create(); - } + g_VideoReferenceClock.Start(); if(m_messageQueue.IsInited()) m_messageQueue.Put(new CDVDMsgVideoCodecChange(hint, codec), 0); diff --git a/xbmc/linux/OMXClock.cpp b/xbmc/linux/OMXClock.cpp index 46df52e879..4f094df927 100644 --- a/xbmc/linux/OMXClock.cpp +++ b/xbmc/linux/OMXClock.cpp @@ -45,6 +45,7 @@ OMXClock::OMXClock() m_clock = NULL; m_last_media_time = 0.0f; m_last_media_time_read = 0.0f; + m_speedAdjust = 0; pthread_mutex_init(&m_lock, NULL); } @@ -477,7 +478,7 @@ bool OMXClock::OMXSetSpeed(int speed, bool lock /* = true */, bool pause_resume if(lock) Lock(); - CLog::Log(LOGDEBUG, "OMXClock::OMXSetSpeed(%.2f) pause_resume:%d", (float)speed / (float)DVD_PLAYSPEED_NORMAL, pause_resume); + CLog::Log(LOGDEBUG, "OMXClock::OMXSetSpeed(%.3f) pause_resume:%d", (float)speed / (float)DVD_PLAYSPEED_NORMAL * (1.0 + m_speedAdjust), pause_resume); if (pause_resume) { @@ -485,6 +486,8 @@ bool OMXClock::OMXSetSpeed(int speed, bool lock /* = true */, bool pause_resume OMX_INIT_STRUCTURE(scaleType); scaleType.xScale = (speed << 16) / DVD_PLAYSPEED_NORMAL; + scaleType.xScale += scaleType.xScale * m_speedAdjust; + OMX_ERRORTYPE omx_err = m_omx_clock.SetConfig(OMX_IndexConfigTimeScale, &scaleType); if(omx_err != OMX_ErrorNone) { @@ -504,6 +507,21 @@ bool OMXClock::OMXSetSpeed(int speed, bool lock /* = true */, bool pause_resume return true; } +void OMXClock::OMXSetSpeedAdjust(double adjust, bool lock /* = true */) +{ + if(lock) + Lock(); + // we only support resampling (and hence clock adjustment) in this mode + if (CSettings::Get().GetBool("videoplayer.usedisplayasclock")) + { + m_speedAdjust = adjust; + OMXSetSpeed(m_omx_speed, false, true); + m_last_media_time = 0.0f; + } + if(lock) + UnLock(); +} + bool OMXClock::OMXFlush(bool lock) { if(m_omx_clock.GetComponent() == NULL) diff --git a/xbmc/linux/OMXClock.h b/xbmc/linux/OMXClock.h index 8f0613487d..df0d4cfb9c 100644 --- a/xbmc/linux/OMXClock.h +++ b/xbmc/linux/OMXClock.h @@ -59,6 +59,7 @@ private: COMXCoreComponent m_omx_clock; double m_last_media_time; double m_last_media_time_read; + double m_speedAdjust; public: OMXClock(); ~OMXClock(); @@ -82,6 +83,7 @@ public: bool OMXPause(bool lock = true); bool OMXResume(bool lock = true); bool OMXSetSpeed(int speed, bool lock = true, bool pause_resume = false); + void OMXSetSpeedAdjust(double adjust, bool lock = true); int OMXPlaySpeed() { return m_omx_speed; }; bool OMXFlush(bool lock = true); COMXCoreComponent *GetOMXClock(); diff --git a/xbmc/video/VideoReferenceClock.cpp b/xbmc/video/VideoReferenceClock.cpp index f97e0bf401..a363c3612d 100644 --- a/xbmc/video/VideoReferenceClock.cpp +++ b/xbmc/video/VideoReferenceClock.cpp @@ -28,6 +28,7 @@ #include "guilib/GraphicContext.h" #include "video/videosync/VideoSync.h" #include "windowing/WindowingFactory.h" +#include "settings/Settings.h" #if defined(HAS_GLX) #include "video/videosync/VideoSyncGLX.h" @@ -72,6 +73,13 @@ CVideoReferenceClock::~CVideoReferenceClock() { } +void CVideoReferenceClock::Start() +{ + CSingleExit lock(g_graphicsContext); + if(CSettings::Get().GetBool("videoplayer.usedisplayasclock") && !IsRunning()) + Create(); +} + void CVideoReferenceClock::Stop() { CSingleExit lock(g_graphicsContext); diff --git a/xbmc/video/VideoReferenceClock.h b/xbmc/video/VideoReferenceClock.h index 937b53e323..d0a9c3f9f1 100644 --- a/xbmc/video/VideoReferenceClock.h +++ b/xbmc/video/VideoReferenceClock.h @@ -39,6 +39,7 @@ class CVideoReferenceClock : public CThread bool GetClockInfo(int& MissedVblanks, double& ClockSpeed, double& RefreshRate); void SetFineAdjust(double fineadjust); void RefreshChanged(); + void Start(); void Stop(); private: -- cgit v1.2.3