diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp index 7da5eab280abb..b9178602cdb94 100644 --- a/xbmc/cores/VideoRenderers/RenderManager.cpp +++ b/xbmc/cores/VideoRenderers/RenderManager.cpp @@ -103,6 +103,7 @@ CXBMCRenderManager::CXBMCRenderManager() m_presentmethod = PRESENT_METHOD_SINGLE; m_bReconfigured = false; m_hasCaptures = false; + m_displayLatency = 0.0f; } CXBMCRenderManager::~CXBMCRenderManager() @@ -320,6 +321,8 @@ unsigned int CXBMCRenderManager::PreInit() #endif } + UpdateDisplayLatency(); + return m_pRenderer->PreInit(); } @@ -712,6 +715,17 @@ void CXBMCRenderManager::Recover() #if defined(HAS_GL) && !defined(TARGET_DARWIN) glFlush(); // attempt to have gpu done with pixmap and vdpau #endif + + UpdateDisplayLatency(); +} + +void CXBMCRenderManager::UpdateDisplayLatency() +{ + float refresh = g_graphicsContext.GetFPS(); + if (g_graphicsContext.GetVideoResolution() == RES_WINDOW) + refresh = 0; // No idea about refresh rate when windowed, just get the default latency + m_displayLatency = (double) g_advancedSettings.GetDisplayLatency(refresh); + CLog::Log(LOGDEBUG, "CRenderManager::UpdateDisplayLatency - Latency set to %1.0f msec", m_displayLatency * 1000.0f); } void CXBMCRenderManager::UpdateResolution() diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h index 961b19fbd5ecd..7f8dbce85e71f 100644 --- a/xbmc/cores/VideoRenderers/RenderManager.h +++ b/xbmc/cores/VideoRenderers/RenderManager.h @@ -108,6 +108,7 @@ class CXBMCRenderManager float GetMaximumFPS(); inline bool Paused() { return m_bPauseDrawing; }; inline bool IsStarted() { return m_bIsStarted;} + double GetDisplayLatency() { return m_displayLatency; } bool Supports(ERENDERFEATURE feature) { @@ -216,6 +217,8 @@ class CXBMCRenderManager PRESENT_METHOD_BOB, }; + double m_displayLatency; + void UpdateDisplayLatency(); double m_presenttime; double m_presentcorr; diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp index a5bf08af2115b..b9b271e6b8138 100644 --- a/xbmc/cores/dvdplayer/DVDPlayer.cpp +++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp @@ -2433,7 +2433,7 @@ void CDVDPlayer::GetGeneralInfo(CStdString& strGeneralInfo) { if (!m_bStop) { - double dDelay = (double)m_dvdPlayerVideo.GetDelay() / DVD_TIME_BASE; + double dDelay = m_dvdPlayerVideo.GetDelay() / DVD_TIME_BASE - g_renderManager.GetDisplayLatency(); double apts = m_dvdPlayerAudio.GetCurrentPts(); double vpts = m_dvdPlayerVideo.GetCurrentPts(); diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp index 15e11d2c8cf25..e28faaf3683cf 100644 --- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp @@ -1111,8 +1111,8 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) pts -= DVD_TIME_BASE * interval; } - //User set delay - pts += m_iVideoDelay; + // Correct pts by user set delay and rendering delay + pts += m_iVideoDelay - DVD_SEC_TO_TIME(g_renderManager.GetDisplayLatency()); // calculate the time we need to delay this picture before displaying double iSleepTime, iClockSleep, iFrameSleep, iPlayingClock, iCurrentClock, iFrameDuration; diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp index d6d65cc332dc3..d14b1396e9d9c 100644 --- a/xbmc/settings/AdvancedSettings.cpp +++ b/xbmc/settings/AdvancedSettings.cpp @@ -540,6 +540,44 @@ void CAdvancedSettings::ParseSettingsFile(const CStdString &file) XMLUtils::GetBoolean(pElement,"forcedxvarenderer", m_DXVAForceProcessorRenderer); //0 = disable fps detect, 1 = only detect on timestamps with uniform spacing, 2 detect on all timestamps XMLUtils::GetInt(pElement, "fpsdetect", m_videoFpsDetect, 0, 2); + + // Store global display latency settings + m_videoDefaultLatency = 0; + TiXmlElement* pVideoLatency = pElement->FirstChildElement("latency"); + if (pVideoLatency) + { + float refresh, refreshmin, refreshmax, delay; + TiXmlElement* pRefreshVideoLatency = pVideoLatency->FirstChildElement("refresh"); + + while (pRefreshVideoLatency) + { + RefreshVideoLatency videolatency = {0}; + + if (XMLUtils::GetFloat(pRefreshVideoLatency, "rate", refresh)) + { + videolatency.refreshmin = refresh - 0.01f; + videolatency.refreshmax = refresh + 0.01f; + } + else if (XMLUtils::GetFloat(pRefreshVideoLatency, "min", refreshmin) && + XMLUtils::GetFloat(pRefreshVideoLatency, "max", refreshmax)) + { + videolatency.refreshmin = refreshmin; + videolatency.refreshmax = refreshmax; + } + if (XMLUtils::GetFloat(pRefreshVideoLatency, "delay", delay, -600.0f, 600.0f)) + videolatency.delay = delay; + + if (videolatency.refreshmin > 0.0f && videolatency.refreshmax >= videolatency.refreshmin) + m_videoRefreshLatency.push_back(videolatency); + else + CLog::Log(LOGWARNING, "Ignoring malformed display latency entry, min:%f max:%f", videolatency.refreshmin, videolatency.refreshmax); + + pRefreshVideoLatency = pRefreshVideoLatency->NextSiblingElement("refresh"); + } + + // Get default global display latency + XMLUtils::GetFloat(pVideoLatency, "delay", m_videoDefaultLatency, -600.0f, 600.0f); + } } pElement = pRootElement->FirstChildElement("musiclibrary"); @@ -1049,3 +1087,16 @@ void CAdvancedSettings::AddSettingsFile(const CStdString &filename) { m_settingsFiles.push_back(filename); } + +float CAdvancedSettings::GetDisplayLatency(float refreshrate) +{ + float delay = m_videoDefaultLatency / 1000.0f; + for (int i = 0; i < (int) m_videoRefreshLatency.size(); i++) + { + RefreshVideoLatency& videolatency = m_videoRefreshLatency[i]; + if (refreshrate >= videolatency.refreshmin && refreshrate <= videolatency.refreshmax) + delay = videolatency.delay / 1000.0f; + } + + return delay; // in seconds +} diff --git a/xbmc/settings/AdvancedSettings.h b/xbmc/settings/AdvancedSettings.h index 3585e0ef6e136..0a8ad03054924 100644 --- a/xbmc/settings/AdvancedSettings.h +++ b/xbmc/settings/AdvancedSettings.h @@ -59,6 +59,15 @@ struct RefreshOverride bool fallback; }; + +struct RefreshVideoLatency +{ + float refreshmin; + float refreshmax; + + float delay; +}; + typedef std::vector SETTINGS_TVSHOWLIST; class CAdvancedSettings @@ -125,6 +134,8 @@ class CAdvancedSettings bool m_videoAllowMpeg4VDPAU; bool m_videoAllowMpeg4VAAPI; std::vector m_videoAdjustRefreshOverrides; + std::vector m_videoRefreshLatency; + float m_videoDefaultLatency; bool m_videoDisableBackgroundDeinterlace; int m_videoCaptureUseOcclusionQuery; bool m_DXVACheckCompatibility; @@ -303,6 +314,8 @@ class CAdvancedSettings bool m_enableMultimediaKeys; std::vector m_settingsFiles; void ParseSettingsFile(const CStdString &file); + + float GetDisplayLatency(float refreshrate); }; XBMC_GLOBAL(CAdvancedSettings,g_advancedSettings);