diff --git a/packages/mediacenter/xbmc/patches/todo/xbmc-995.10-xvba_rpi_fixes-81496e1.patch b/packages/mediacenter/xbmc/patches/todo/xbmc-995.10-xvba_rpi_fixes-81496e1.patch deleted file mode 100644 index 029e8fa7a0..0000000000 --- a/packages/mediacenter/xbmc/patches/todo/xbmc-995.10-xvba_rpi_fixes-81496e1.patch +++ /dev/null @@ -1,549 +0,0 @@ -From d33a276284356e974dcf14e6c86b74064fb0715f Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Sun, 10 Feb 2013 18:38:56 +0100 -Subject: [PATCH 1/4] renderer: add buffering - get clock via IPlayer - ---- - xbmc/cores/IPlayer.h | 2 ++ - xbmc/cores/VideoRenderers/RenderManager.cpp | 9 ++++++--- - xbmc/cores/VideoRenderers/RenderManager.h | 3 +-- - xbmc/cores/dvdplayer/DVDPlayer.cpp | 7 ++++++- - xbmc/cores/dvdplayer/DVDPlayer.h | 2 ++ - 5 files changed, 17 insertions(+), 6 deletions(-) - -diff --git a/xbmc/cores/IPlayer.h b/xbmc/cores/IPlayer.h -index 5ed88d1..f136998 100644 ---- a/xbmc/cores/IPlayer.h -+++ b/xbmc/cores/IPlayer.h -@@ -229,6 +229,8 @@ class IPlayer - */ - virtual void GetSubtitleCapabilities(std::vector &subCaps) { subCaps.assign(1,IPC_SUBS_ALL); }; - -+ virtual double GetClock(double& absolute, bool interpolated = true) {return 0; }; -+ - protected: - IPlayerCallback& m_callback; - }; -diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp -index 9290f80..4664426 100644 ---- a/xbmc/cores/VideoRenderers/RenderManager.cpp -+++ b/xbmc/cores/VideoRenderers/RenderManager.cpp -@@ -325,7 +325,7 @@ void CXBMCRenderManager::RenderUpdate(bool clear, DWORD flags, DWORD alpha) - m_presentevent.Set(); - } - --unsigned int CXBMCRenderManager::PreInit(CDVDClock *pClock) -+unsigned int CXBMCRenderManager::PreInit() - { - CRetakeLock lock(m_sharedSection); - -@@ -333,7 +333,6 @@ unsigned int CXBMCRenderManager::PreInit(CDVDClock *pClock) - m_presenterr = 0.0; - m_errorindex = 0; - memset(m_errorbuff, 0, sizeof(m_errorbuff)); -- m_pClock = pClock; - - m_bIsStarted = false; - m_bPauseDrawing = false; -@@ -1045,7 +1044,11 @@ void CXBMCRenderManager::PrepareNextRender() - } - - double iClockSleep, iPlayingClock, iCurrentClock; -- iPlayingClock = m_pClock->GetClock(iCurrentClock, false); -+ if (g_application.m_pPlayer) -+ iPlayingClock = g_application.m_pPlayer->GetClock(iCurrentClock, false); -+ else -+ iPlayingClock = iCurrentClock = 0; -+ - iClockSleep = m_renderBuffers[idx].pts - iPlayingClock; - - if (m_speed) -diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h -index 6746957..b931f7d 100644 ---- a/xbmc/cores/VideoRenderers/RenderManager.h -+++ b/xbmc/cores/VideoRenderers/RenderManager.h -@@ -72,7 +72,7 @@ class CXBMCRenderManager - int AddVideoPicture(DVDVideoPicture& picture); - - void FlipPage(volatile bool& bStop, double timestamp = 0.0, int source = -1, EFIELDSYNC sync = FS_NONE, int speed = 0); -- unsigned int PreInit(CDVDClock *pClock); -+ unsigned int PreInit(); - void UnInit(); - bool Flush(); - -@@ -225,7 +225,6 @@ class CXBMCRenderManager - int m_presentsource; - CEvent m_presentevent; - CEvent m_flushEvent; -- CDVDClock *m_pClock; - - - OVERLAY::CRenderer m_overlays; -diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp -index 9e6e470..d0c7cd2 100644 ---- a/xbmc/cores/dvdplayer/DVDPlayer.cpp -+++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp -@@ -463,7 +463,7 @@ bool CDVDPlayer::OpenFile(const CFileItem& file, const CPlayerOptions &options) - m_ready.Reset(); - - #if defined(HAS_VIDEO_PLAYBACK) -- g_renderManager.PreInit(&m_clock); -+ g_renderManager.PreInit(); - #endif - - Create(); -@@ -4129,3 +4129,8 @@ bool CDVDPlayer::CachePVRStream(void) const - !g_PVRManager.IsPlayingRecording() && - g_advancedSettings.m_bPVRCacheInDvdPlayer; - } -+ -+double CDVDPlayer::GetClock(double& absolute, bool interpolated) -+{ -+ return m_clock.GetClock(absolute, interpolated); -+} -diff --git a/xbmc/cores/dvdplayer/DVDPlayer.h b/xbmc/cores/dvdplayer/DVDPlayer.h -index 35bf762..ab73950 100644 ---- a/xbmc/cores/dvdplayer/DVDPlayer.h -+++ b/xbmc/cores/dvdplayer/DVDPlayer.h -@@ -254,6 +254,8 @@ class CDVDPlayer : public IPlayer, public CThread, public IDVDPlayer - virtual bool SwitchChannel(const PVR::CPVRChannel &channel); - virtual bool CachePVRStream(void) const; - -+ virtual double GetClock(double& absolute, bool interpolated = true); -+ - enum ECacheState - { CACHESTATE_DONE = 0 - , CACHESTATE_FULL // player is filling up the demux queue --- -1.7.10 - - -From 113de500903cbe1933e1a50fc7809b8f6b7f2636 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Fri, 15 Feb 2013 17:00:47 +0100 -Subject: [PATCH 2/4] buffering: some rework - ---- - xbmc/cores/VideoRenderers/OverlayRenderer.cpp | 17 +++++++---------- - xbmc/cores/VideoRenderers/OverlayRenderer.h | 5 ++--- - xbmc/cores/VideoRenderers/RenderManager.cpp | 10 +++------- - xbmc/cores/VideoRenderers/RenderManager.h | 4 ++-- - xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 18 +++++++++++++++++- - 5 files changed, 31 insertions(+), 23 deletions(-) - -diff --git a/xbmc/cores/VideoRenderers/OverlayRenderer.cpp b/xbmc/cores/VideoRenderers/OverlayRenderer.cpp -index 94aaaf5..f7f74ce 100644 ---- a/xbmc/cores/VideoRenderers/OverlayRenderer.cpp -+++ b/xbmc/cores/VideoRenderers/OverlayRenderer.cpp -@@ -93,24 +93,28 @@ long COverlayMainThread::Release() - - CRenderer::~CRenderer() - { -- for(int i = 0; i < 2; i++) -+ for(int i = 0; i < 10; i++) - Release(m_buffers[i]); - } - --void CRenderer::AddOverlay(CDVDOverlay* o, double pts) -+void CRenderer::AddOverlay(CDVDOverlay* o, double pts, int index) - { - CSingleLock lock(m_section); - -+ m_decode = index; -+ - SElement e; - e.pts = pts; - e.overlay_dvd = o->Acquire(); - m_buffers[m_decode].push_back(e); - } - --void CRenderer::AddOverlay(COverlay* o, double pts) -+void CRenderer::AddOverlay(COverlay* o, double pts, int index) - { - CSingleLock lock(m_section); - -+ m_decode = index; -+ - SElement e; - e.pts = pts; - e.overlay = o->Acquire(); -@@ -163,13 +167,6 @@ void CRenderer::Flip() - m_render = (m_render + 1) % m_iNumBuffers; - } - --void CRenderer::SetBuffer(int idx) --{ -- CSingleLock lock(m_section); -- Release(m_buffers[idx]); -- m_decode = idx; --} -- - void CRenderer::ReleaseBuffer(int idx) - { - CSingleLock lock(m_section); -diff --git a/xbmc/cores/VideoRenderers/OverlayRenderer.h b/xbmc/cores/VideoRenderers/OverlayRenderer.h -index c6740a5..0921fc5 100644 ---- a/xbmc/cores/VideoRenderers/OverlayRenderer.h -+++ b/xbmc/cores/VideoRenderers/OverlayRenderer.h -@@ -92,14 +92,13 @@ - CRenderer(); - ~CRenderer(); - -- void AddOverlay(CDVDOverlay* o, double pts); -- void AddOverlay(COverlay* o, double pts); -+ void AddOverlay(CDVDOverlay* o, double pts, int index); -+ void AddOverlay(COverlay* o, double pts, int index); - void AddCleanup(COverlay* o); - void Flip(); - void Render(); - void Flush(); - void SetNumBuffers(int numBuffers) { m_iNumBuffers = numBuffers; } -- void SetBuffer(int idx); - void ReleaseBuffer(int idx); - - protected: -diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp -index 4664426..7094913 100644 ---- a/xbmc/cores/VideoRenderers/RenderManager.cpp -+++ b/xbmc/cores/VideoRenderers/RenderManager.cpp -@@ -228,7 +228,7 @@ CStdString CXBMCRenderManager::GetVSyncState() - return state; - } - --bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsigned int d_width, unsigned int d_height, float fps, unsigned flags, ERenderFormat format, unsigned extended_format, unsigned int orientation) -+bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsigned int d_width, unsigned int d_height, float fps, unsigned flags, ERenderFormat format, unsigned extended_format, unsigned int orientation, bool buffering) - { - /* make sure any queued frame was fully presented */ - double timeout = m_presenttime + 0.1; -@@ -248,8 +248,8 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi - return false; - } - -- // check if decoder supports buffering -- m_bCodecSupportsBuffering = false; -+ // set buffering -+ m_bCodecSupportsBuffering = buffering; - if (format == RENDER_FMT_VDPAU - || format == RENDER_FMT_VDPAU_420 - || format == RENDER_FMT_XVBA) -@@ -959,10 +959,6 @@ int CXBMCRenderManager::WaitForBuffer(volatile bool& bStop) - } - lock.Leave(); - -- { CRetakeLock lock(m_sharedSection); -- m_overlays.SetBuffer((m_iOutputRenderBuffer + 1) % m_iNumRenderBuffers); -- } -- - if (bStop) - return -1; - -diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h -index b931f7d..27bb8a2 100644 ---- a/xbmc/cores/VideoRenderers/RenderManager.h -+++ b/xbmc/cores/VideoRenderers/RenderManager.h -@@ -66,7 +66,7 @@ class CXBMCRenderManager - void SetViewMode(int iViewMode); - - // Functions called from mplayer -- bool Configure(unsigned int width, unsigned int height, unsigned int d_width, unsigned int d_height, float fps, unsigned flags, ERenderFormat format, unsigned extended_format, unsigned int orientation); -+ bool Configure(unsigned int width, unsigned int height, unsigned int d_width, unsigned int d_height, float fps, unsigned flags, ERenderFormat format, unsigned extended_format, unsigned int orientation, bool buffering); - bool IsConfigured(); - - int AddVideoPicture(DVDVideoPicture& picture); -@@ -79,7 +79,7 @@ class CXBMCRenderManager - void AddOverlay(CDVDOverlay* o, double pts) - { - CSharedLock lock(m_sharedSection); -- m_overlays.AddOverlay(o, pts); -+ m_overlays.AddOverlay(o, pts, (m_iOutputRenderBuffer + 1) % m_iNumRenderBuffers); - } - - void AddCleanup(OVERLAY::COverlay* o) -diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -index 109d75b..8a6599c 100644 ---- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -@@ -1132,53 +1132,69 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) - } - - CStdString formatstr; -+ bool buffering; - - switch(pPicture->format) - { - case RENDER_FMT_YUV420P: - formatstr = "YV12"; -+ buffering = true; - break; - case RENDER_FMT_YUV420P16: - formatstr = "YV12P16"; -+ buffering = true; - break; - case RENDER_FMT_YUV420P10: - formatstr = "YV12P10"; -+ buffering = true; - break; - case RENDER_FMT_NV12: - formatstr = "NV12"; -+ buffering = true; - break; - case RENDER_FMT_UYVY422: - formatstr = "UYVY"; -+ buffering = true; - break; - case RENDER_FMT_YUYV422: - formatstr = "YUY2"; -+ buffering = true; - break; - case RENDER_FMT_VDPAU: - formatstr = "VDPAU"; -+ buffering = true; - break; - case RENDER_FMT_VDPAU_420: - formatstr = "VDPAU_420"; -+ buffering = true; - break; - case RENDER_FMT_DXVA: - formatstr = "DXVA"; -+ buffering = false; - break; - case RENDER_FMT_VAAPI: - formatstr = "VAAPI"; -+ buffering = false; - break; - case RENDER_FMT_OMXEGL: - formatstr = "OMXEGL"; -+ buffering = false; - break; - case RENDER_FMT_CVBREF: - formatstr = "BGRA"; -+ buffering = false; - break; - case RENDER_FMT_BYPASS: - formatstr = "BYPASS"; -+ buffering = false; - break; - case RENDER_FMT_NONE: - formatstr = "NONE"; -+ buffering = false; - break; - case RENDER_FMT_XVBA: - formatstr = "XVBA"; -+ buffering = true; - break; - } - -@@ -1189,7 +1205,7 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) - } - - CLog::Log(LOGDEBUG,"%s - change configuration. %dx%d. framerate: %4.2f. format: %s",__FUNCTION__,pPicture->iWidth, pPicture->iHeight, config_framerate, formatstr.c_str()); -- if(!g_renderManager.Configure(pPicture->iWidth, pPicture->iHeight, pPicture->iDisplayWidth, pPicture->iDisplayHeight, config_framerate, flags, pPicture->format, pPicture->extended_format, m_hints.orientation)) -+ if(!g_renderManager.Configure(pPicture->iWidth, pPicture->iHeight, pPicture->iDisplayWidth, pPicture->iDisplayHeight, config_framerate, flags, pPicture->format, pPicture->extended_format, m_hints.orientation, buffering)) - { - CLog::Log(LOGERROR, "%s - failed to configure renderer", __FUNCTION__); - return EOS_ABORT; --- -1.7.10 - - -From 4d71be9fa0e34dccbb977199f1bde2f200f8b56e Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Sat, 16 Feb 2013 08:32:18 +0100 -Subject: [PATCH 3/4] add buffering for GLES - ---- - xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 10 ---------- - xbmc/cores/VideoRenderers/LinuxRendererGLES.h | 6 ++++-- - 2 files changed, 4 insertions(+), 12 deletions(-) - -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -index 2a59e2b..1bf2f3b 100644 ---- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -@@ -135,13 +135,6 @@ - delete m_dllSwScale; - } - --void CLinuxRendererGLES::ManageTextures() --{ -- m_NumYV12Buffers = 2; -- //m_iYV12RenderBuffer = 0; -- return; --} -- - bool CLinuxRendererGLES::ValidateRenderTarget() - { - if (!m_bValidated) -@@ -395,7 +388,6 @@ void CLinuxRendererGLES::Update(bool bPauseDrawing) - { - if (!m_bConfigured) return; - ManageDisplay(); -- ManageTextures(); - } - - void CLinuxRendererGLES::RenderUpdate(bool clear, DWORD flags, DWORD alpha) -@@ -409,7 +401,6 @@ void CLinuxRendererGLES::RenderUpdate(bool clear, DWORD flags, DWORD alpha) - if (m_renderMethod & RENDER_BYPASS) - { - ManageDisplay(); -- ManageTextures(); - // if running bypass, then the player might need the src/dst rects - // for sizing video playback on a layer other than the gles layer. - if (m_RenderUpdateCallBackFn) -@@ -449,7 +440,6 @@ void CLinuxRendererGLES::RenderUpdate(bool clear, DWORD flags, DWORD alpha) - return; - - ManageDisplay(); -- ManageTextures(); - - g_graphicsContext.BeginPaint(); - -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h -index c6b69db..7bdc3bc 100644 ---- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h -@@ -41,7 +41,7 @@ - class COpenMaxVideo; - typedef std::vector Features; - --#define NUM_BUFFERS 3 -+#define NUM_BUFFERS 10 - - - #undef ALIGN -@@ -138,6 +138,9 @@ class CLinuxRendererGLES : public CBaseRenderer - virtual void UnInit(); - virtual void Reset(); /* resets renderer after seek for example */ - virtual void ReorderDrawPoints(); -+ virtual void SetProcessorSize(int numBuffers) { m_NumYV12Buffers = numBuffers; } -+ virtual unsigned int GetMaxProcessorSize() { return NUM_BUFFERS; } -+ virtual unsigned int GetProcessorSize() { return m_NumYV12Buffers; } - - virtual void RenderUpdate(bool clear, DWORD flags = 0, DWORD alpha = 255); - -@@ -162,7 +165,6 @@ class CLinuxRendererGLES : public CBaseRenderer - protected: - virtual void Render(DWORD flags, int index); - -- virtual void ManageTextures(); - int NextYV12Texture(); - virtual bool ValidateRenderTarget(); - virtual void LoadShaders(int field=FIELD_FULL); --- -1.7.10 - - -From 81496e1f405980d3be6b05c883bdbfb65d617e3e Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Sun, 10 Feb 2013 18:40:30 +0100 -Subject: [PATCH 4/4] OMXPlayer: adopt to buffering in renderer - ---- - xbmc/cores/omxplayer/OMXPlayer.cpp | 5 +++++ - xbmc/cores/omxplayer/OMXPlayer.h | 2 ++ - xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 24 +++++++++++++++++++----- - 3 files changed, 26 insertions(+), 5 deletions(-) - -diff --git a/xbmc/cores/omxplayer/OMXPlayer.cpp b/xbmc/cores/omxplayer/OMXPlayer.cpp -index 60aa9ab..1acb9e2 100644 ---- a/xbmc/cores/omxplayer/OMXPlayer.cpp -+++ b/xbmc/cores/omxplayer/OMXPlayer.cpp -@@ -4210,4 +4210,9 @@ void COMXPlayer::GetSubtitleCapabilities(std::vector &subCaps) - subCaps.push_back(IPC_SUBS_ALL); - } - -+double COMXPlayer::GetClock(double& absolute, bool interpolated) -+{ -+ return m_av_clock.GetClock(absolute, interpolated); -+} -+ - #endif -diff --git a/xbmc/cores/omxplayer/OMXPlayer.h b/xbmc/cores/omxplayer/OMXPlayer.h -index ca824c2..57fc7a0 100644 ---- a/xbmc/cores/omxplayer/OMXPlayer.h -+++ b/xbmc/cores/omxplayer/OMXPlayer.h -@@ -332,6 +332,8 @@ class COMXPlayer : public IPlayer, public CThread, public IDVDPlayer - virtual void GetScalingMethods(std::vector &scalingMethods); - virtual void GetAudioCapabilities(std::vector &audioCaps); - virtual void GetSubtitleCapabilities(std::vector &subCaps); -+ -+ virtual double GetClock(double& absolute, bool interpolated = true); - protected: - friend class COMXSelectionStreams; - -diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -index 5f3f050..88c75db 100644 ---- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -+++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -@@ -158,6 +158,8 @@ bool OMXPlayerVideo::OpenStream(CDVDStreamInfo &hints) - m_open = true; - m_send_eos = false; - -+ g_renderManager.EnableBuffering(false); -+ - return true; - } - -@@ -358,7 +360,7 @@ void OMXPlayerVideo::Output(int iGroupId, double pts, bool bDropPacket) - - if(!g_renderManager.Configure(m_hints.width, m_hints.height, - iDisplayWidth, iDisplayHeight, m_fps, flags, format, 0, -- m_hints.orientation)) -+ m_hints.orientation, true)) - { - CLog::Log(LOGERROR, "%s - failed to configure renderer", __FUNCTION__); - return; -@@ -452,13 +454,22 @@ void OMXPlayerVideo::Output(int iGroupId, double pts, bool bDropPacket) - m_dropbase = 0.0f; - #endif - -- double pts_media = m_av_clock->OMXMediaTime(false, false); -- ProcessOverlays(iGroupId, pts_media); -- - if (!CThread::m_bStop && m_av_clock->GetAbsoluteClock(false) < (iCurrentClock + iSleepTime + DVD_MSEC_TO_TIME(500)) ) - return; - -- g_renderManager.FlipPage(CThread::m_bStop, (iCurrentClock + iSleepTime) / DVD_TIME_BASE, -1, FS_NONE); -+ int buffer = g_renderManager.WaitForBuffer(m_bStop); -+ while (buffer < 0 && !CThread::m_bStop) -+ { -+ Sleep(1); -+ buffer = g_renderManager.WaitForBuffer(m_bStop); -+ } -+ if (buffer < 0) -+ return; -+ -+ double pts_media = m_av_clock->OMXMediaTime(false, false); -+ ProcessOverlays(iGroupId, pts_media); -+ -+ g_renderManager.FlipPage(CThread::m_bStop, pts, -1, FS_NONE, m_speed); - - //m_av_clock->WaitAbsoluteClock((iCurrentClock + iSleepTime)); - } -@@ -569,6 +580,7 @@ void OMXPlayerVideo::Process() - m_av_clock->OMXReset(false); - m_av_clock->UnLock(); - m_started = false; -+ g_renderManager.EnableBuffering(false); - } - else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) // private message sent by (COMXPlayerVideo::Flush()) - { -@@ -580,6 +592,7 @@ void OMXPlayerVideo::Process() - m_omxVideo.Reset(); - m_av_clock->OMXReset(false); - m_av_clock->UnLock(); -+ g_renderManager.EnableBuffering(false); - } - else if (pMsg->IsType(CDVDMsg::PLAYER_SETSPEED)) - { -@@ -664,6 +677,7 @@ void OMXPlayerVideo::Process() - m_codecname = m_omxVideo.GetDecoderName(); - m_started = true; - m_messageParent.Put(new CDVDMsgInt(CDVDMsg::PLAYER_STARTED, DVDPLAYER_VIDEO)); -+ g_renderManager.EnableBuffering(true); - } - - // guess next frame pts. iDuration is always valid --- -1.7.10 - diff --git a/packages/mediacenter/xbmc/patches/todo/xbmc-995.11-multi-screen_fix_compilation_on_windows.patch b/packages/mediacenter/xbmc/patches/todo/xbmc-995.11-multi-screen_fix_compilation_on_windows.patch deleted file mode 100644 index 265c9ae628..0000000000 --- a/packages/mediacenter/xbmc/patches/todo/xbmc-995.11-multi-screen_fix_compilation_on_windows.patch +++ /dev/null @@ -1,75 +0,0 @@ -From bf4d77aeb9ff7c198914031ec0d8268dae0c5973 Mon Sep 17 00:00:00 2001 -From: unknown -Date: Fri, 18 Jan 2013 15:16:38 +0100 -Subject: [PATCH] multi-screen: fix compilation on windows - ---- - xbmc/settings/GUIWindowSettingsCategory.cpp | 11 ++++++++++- - 1 file changed, 10 insertions(+), 1 deletion(-) - -diff --git a/xbmc/settings/GUIWindowSettingsCategory.cpp b/xbmc/settings/GUIWindowSettingsCategory.cpp -index bb29daa..c468a73 100644 ---- a/xbmc/settings/GUIWindowSettingsCategory.cpp -+++ b/xbmc/settings/GUIWindowSettingsCategory.cpp -@@ -525,12 +525,14 @@ void CGUIWindowSettingsCategory::CreateSettings() - FillInRefreshRates(strSetting, g_guiSettings.GetResolution(), false); - continue; - } -+#if defined(HAS_GLX) - else if (strSetting.Equals("videoscreen.monitor")) - { - AddSetting(pSetting, group->GetWidth(), iControlID); - FillInMonitors(strSetting); - continue; - } -+#endif - else if (strSetting.Equals("lookandfeel.skintheme")) - { - AddSetting(pSetting, group->GetWidth(), iControlID); -@@ -1463,6 +1465,7 @@ void CGUIWindowSettingsCategory::OnSettingChanged(BaseSettingControlPtr pSetting - // Cascade - FillInResolutions("videoscreen.resolution", mode, RES_DESKTOP, true); - } -+#if defined(HAS_GLX) - else if (strSetting.Equals("videoscreen.monitor")) - { - CSettingString *pSettingString = (CSettingString *)pSettingControl->GetSetting(); -@@ -1477,6 +1480,7 @@ void CGUIWindowSettingsCategory::OnSettingChanged(BaseSettingControlPtr pSetting - FillInResolutions("videoscreen.resolution", mode, RES_DESKTOP, true); - } - } -+#endif - else if (strSetting.Equals("videoscreen.resolution")) - { - RESOLUTION nextRes = (RESOLUTION) g_guiSettings.GetInt("videoscreen.resolution"); -@@ -2431,6 +2435,7 @@ DisplayMode CGUIWindowSettingsCategory::FillInScreens(CStdString strSetting, RES - - void CGUIWindowSettingsCategory::FillInMonitors(CStdString strSetting) - { -+#if defined(HAS_GLX) - // we expect "videoscreen.monitor" but it might be hidden on some platforms, - // so check that we actually have a visable control. - BaseSettingControlPtr control = GetSetting(strSetting); -@@ -2456,6 +2461,7 @@ void CGUIWindowSettingsCategory::FillInMonitors(CStdString strSetting) - pControl->SetValue(currentMonitor); - g_guiSettings.SetString("videoscreen.monitor", g_settings.m_ResInfo[RES_DESKTOP].strOutput); - } -+#endif - } - - -@@ -2587,7 +2593,10 @@ void CGUIWindowSettingsCategory::OnRefreshRateChanged(RESOLUTION nextRes) - RESOLUTION lastRes = g_graphicsContext.GetVideoResolution(); - bool cancelled = false; - -- bool outputChanged = !g_Windowing.IsCurrentOutput(g_guiSettings.GetString("videoscreen.monitor")); -+ bool outputChanged = true; -+#if defined(HAS_GLX) -+ outputChanged = !g_Windowing.IsCurrentOutput(g_guiSettings.GetString("videoscreen.monitor")); -+#endif - - g_guiSettings.SetResolution(nextRes); - g_graphicsContext.SetVideoResolution(nextRes, outputChanged); --- -1.7.10 - diff --git a/packages/mediacenter/xbmc/patches/xbmc-995.01-xvba_support-1ea917e.patch b/packages/mediacenter/xbmc/patches/xbmc-995.01-xvba_support-1ea917e.patch new file mode 100644 index 0000000000..ac7780f5c2 --- /dev/null +++ b/packages/mediacenter/xbmc/patches/xbmc-995.01-xvba_support-1ea917e.patch @@ -0,0 +1,19295 @@ +From bfd49543c49747236d401df4351767d584f756ac Mon Sep 17 00:00:00 2001 +From: wsnipex +Date: Sun, 4 Nov 2012 14:05:52 +0100 +Subject: [PATCH 01/73] configure: add --enable-pvraddons-with-dependencies + switch for intree building of PVR Addons + +--- + configure.in | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/configure.in b/configure.in +index 4769315..350d960 100644 +--- a/configure.in ++++ b/configure.in +@@ -521,6 +521,14 @@ AC_ARG_ENABLE([external-ffmpeg], + [use_external_ffmpeg=$use_external_libraries]) + + ### End of external library options ++### PVR addons specific ++AC_ARG_ENABLE([pvraddons-with-dependencies], ++ [AS_HELP_STRING([--enable-pvraddons-with-dependencies], ++ [enable build of pvr addons with dependencies (default is no) 'Linux only'])], ++ [use_pvraddons_with_deps=$enableval], ++ [use_pvraddons_with_deps=no]) ++ ++### End PVR addons specific + + if test "x$host_vendor" != "xapple"; then + DEFAULT_COMPILE_FLAGS="-fPIC -DPIC -D_REENTRANT" +@@ -2770,12 +2778,16 @@ XB_CONFIG_MODULE([pvr-addons], [ + if test "$USE_EXTERNAL_FFMPEG" = 1; then + PVR_EXT_FFMPEG="--enable-external-ffmpeg" + fi ++ if test "$use_pvraddons_with_deps" = "yes"; then ++ ADDONS_WITH_DEPS="--enable-addons-with-dependencies" ++ fi + ./configure \ + --prefix="${prefix}" \ + --host=$host_alias \ + --build=$build_alias \ + --target=$target_alias \ + $PVR_EXT_FFMPEG \ ++ $ADDONS_WITH_DEPS \ + CC="$CC" \ + CXX="$CXX" \ + CFLAGS="$CFLAGS" \ +-- +1.7.10 + + +From dc83e2351e8bf8e904102782ea489d2c8caa2802 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 28 May 2012 10:03:31 +0200 +Subject: [PATCH 02/73] VideoRenerers: add buffering + +--- + xbmc/Application.cpp | 3 + + xbmc/cores/VideoRenderers/BaseRenderer.h | 5 +- + xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 41 ++-- + xbmc/cores/VideoRenderers/LinuxRendererGL.h | 13 +- + xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 8 +- + xbmc/cores/VideoRenderers/LinuxRendererGLES.h | 4 +- + xbmc/cores/VideoRenderers/OverlayRenderer.cpp | 19 +- + xbmc/cores/VideoRenderers/OverlayRenderer.h | 6 +- + xbmc/cores/VideoRenderers/RenderManager.cpp | 296 +++++++++++++++++++---- + xbmc/cores/VideoRenderers/RenderManager.h | 48 +++- + xbmc/cores/VideoRenderers/WinRenderer.cpp | 8 +- + xbmc/cores/VideoRenderers/WinRenderer.h | 2 +- + xbmc/cores/dvdplayer/DVDPlayer.cpp | 2 +- + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 18 +- + 14 files changed, 380 insertions(+), 93 deletions(-) + +diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp +index c6f0a14..18e6310 100644 +--- a/xbmc/Application.cpp ++++ b/xbmc/Application.cpp +@@ -2367,7 +2367,10 @@ void CApplication::Render() + m_lastFrameTime = XbmcThreads::SystemClockMillis(); + + if (flip) ++ { + g_graphicsContext.Flip(dirtyRegions); ++ g_renderManager.NotifyDisplayFlip(); ++ } + CTimeUtils::UpdateFrameTime(flip); + + g_TextureManager.FreeUnusedTextures(); +diff --git a/xbmc/cores/VideoRenderers/BaseRenderer.h b/xbmc/cores/VideoRenderers/BaseRenderer.h +index 81d21d8..b02d536 100644 +--- a/xbmc/cores/VideoRenderers/BaseRenderer.h ++++ b/xbmc/cores/VideoRenderers/BaseRenderer.h +@@ -80,10 +80,13 @@ class CBaseRenderer + void GetVideoRect(CRect &source, CRect &dest); + float GetAspectRatio() const; + +- virtual bool AddVideoPicture(DVDVideoPicture* picture) { return false; } ++ virtual bool AddVideoPicture(DVDVideoPicture* picture, int index) { return false; } + virtual void Flush() {}; + + virtual unsigned int GetProcessorSize() { return 0; } ++ virtual unsigned int GetMaxProcessorSize() { return 0; } ++ virtual void SetProcessorSize(int numBuffers) { } ++ virtual void ReleaseBuffer(int idx) { } + + virtual bool Supports(ERENDERFEATURE feature) { return false; } + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +index 1cf52d3..b32a7ea 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +@@ -235,14 +235,6 @@ bool CLinuxRendererGL::ValidateRenderer() + return true; + } + +- +-void CLinuxRendererGL::ManageTextures() +-{ +- m_NumYV12Buffers = 2; +- //m_iYV12RenderBuffer = 0; +- return; +-} +- + bool CLinuxRendererGL::ValidateRenderTarget() + { + if (!m_bValidated) +@@ -603,13 +595,28 @@ void CLinuxRendererGL::Flush() + glFinish(); + m_bValidated = false; + m_fbo.fbo.Cleanup(); ++ m_iYV12RenderBuffer = 0; ++} ++ ++void CLinuxRendererGL::ReleaseBuffer(int idx) ++{ ++ YUVBUFFER &buf = m_buffers[idx]; ++#ifdef HAVE_LIBVDPAU ++ SAFE_RELEASE(buf.vdpau); ++#endif ++#ifdef HAVE_LIBVA ++ buf.vaapi.surface.reset(); ++#endif ++#ifdef TARGET_DARWIN ++ if (buf.cvBufferRef) ++ CVBufferRelease(buf.cvBufferRef); ++#endif + } + + void CLinuxRendererGL::Update(bool bPauseDrawing) + { + if (!m_bConfigured) return; + ManageDisplay(); +- ManageTextures(); + } + + void CLinuxRendererGL::RenderUpdate(bool clear, DWORD flags, DWORD alpha) +@@ -625,7 +632,6 @@ void CLinuxRendererGL::RenderUpdate(bool clear, DWORD flags, DWORD alpha) + } + + ManageDisplay(); +- ManageTextures(); + + g_graphicsContext.BeginPaint(); + +@@ -782,7 +788,6 @@ unsigned int CLinuxRendererGL::PreInit() + m_resolution = RES_DESKTOP; + + m_iYV12RenderBuffer = 0; +- m_NumYV12Buffers = 2; + + m_formats.push_back(RENDER_FMT_YUV420P); + GLint size; +@@ -2465,7 +2470,7 @@ void CLinuxRendererGL::UploadVAAPITexture(int index) + || status == VA_STATUS_ERROR_INVALID_DISPLAY) + { + va.display->lost(true); +- for(int i = 0; i < NUM_BUFFERS; i++) ++ for(int i = 0; i < m_NumYV12Buffers; i++) + { + m_buffers[i].vaapi.display.reset(); + m_buffers[i].vaapi.surface.reset(); +@@ -3412,26 +3417,26 @@ void CLinuxRendererGL::UnBindPbo(YUVBUFFER& buff) + } + + #ifdef HAVE_LIBVDPAU +-void CLinuxRendererGL::AddProcessor(CVDPAU* vdpau) ++void CLinuxRendererGL::AddProcessor(CVDPAU* vdpau, int index) + { +- YUVBUFFER &buf = m_buffers[NextYV12Texture()]; ++ YUVBUFFER &buf = m_buffers[index]; + SAFE_RELEASE(buf.vdpau); + buf.vdpau = (CVDPAU*)vdpau->Acquire(); + } + #endif + + #ifdef HAVE_LIBVA +-void CLinuxRendererGL::AddProcessor(VAAPI::CHolder& holder) ++void CLinuxRendererGL::AddProcessor(VAAPI::CHolder& holder, int index) + { +- YUVBUFFER &buf = m_buffers[NextYV12Texture()]; ++ YUVBUFFER &buf = m_buffers[index]; + buf.vaapi.surface = holder.surface; + } + #endif + + #ifdef TARGET_DARWIN +-void CLinuxRendererGL::AddProcessor(struct __CVBuffer *cvBufferRef) ++void CLinuxRendererGL::AddProcessor(struct __CVBuffer *cvBufferRef, int index) + { +- YUVBUFFER &buf = m_buffers[NextYV12Texture()]; ++ YUVBUFFER &buf = m_buffers[index]; + if (buf.cvBufferRef) + CVBufferRelease(buf.cvBufferRef); + buf.cvBufferRef = cvBufferRef; +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.h b/xbmc/cores/VideoRenderers/LinuxRendererGL.h +index acebfe0..9f55fcb 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.h ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.h +@@ -44,7 +44,7 @@ + namespace Shaders { class BaseVideoFilterShader; } + namespace VAAPI { struct CHolder; } + +-#define NUM_BUFFERS 3 ++#define NUM_BUFFERS 10 + + + #undef ALIGN +@@ -138,15 +138,19 @@ class CLinuxRendererGL : public CBaseRenderer + virtual void UnInit(); + virtual void Reset(); /* resets renderer after seek for example */ + virtual void Flush(); ++ virtual void ReleaseBuffer(int idx); ++ virtual void SetProcessorSize(int numBuffers) { m_NumYV12Buffers = numBuffers; } ++ virtual unsigned int GetMaxProcessorSize() { return NUM_BUFFERS; } ++ virtual unsigned int GetProcessorSize() { return m_NumYV12Buffers; } + + #ifdef HAVE_LIBVDPAU +- virtual void AddProcessor(CVDPAU* vdpau); ++ virtual void AddProcessor(CVDPAU* vdpau, int index); + #endif + #ifdef HAVE_LIBVA +- virtual void AddProcessor(VAAPI::CHolder& holder); ++ virtual void AddProcessor(VAAPI::CHolder& holder, int index); + #endif + #ifdef TARGET_DARWIN +- virtual void AddProcessor(struct __CVBuffer *cvBufferRef); ++ virtual void AddProcessor(struct __CVBuffer *cvBufferRef, int index); + #endif + + virtual void RenderUpdate(bool clear, DWORD flags = 0, DWORD alpha = 255); +@@ -168,7 +172,6 @@ class CLinuxRendererGL : public CBaseRenderer + void DrawBlackBars(); + + bool ValidateRenderer(); +- virtual void ManageTextures(); + int NextYV12Texture(); + virtual bool ValidateRenderTarget(); + virtual void LoadShaders(int field=FIELD_FULL); +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +index cb0939f..2a59e2b 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +@@ -1982,16 +1982,16 @@ EINTERLACEMETHOD CLinuxRendererGLES::AutoInterlaceMethod() + } + + #ifdef HAVE_LIBOPENMAX +-void CLinuxRendererGLES::AddProcessor(COpenMax* openMax, DVDVideoPicture *picture) ++void CLinuxRendererGLES::AddProcessor(COpenMax* openMax, DVDVideoPicture *picture, int index) + { +- YUVBUFFER &buf = m_buffers[NextYV12Texture()]; ++ YUVBUFFER &buf = m_buffers[index]; + buf.openMaxBuffer = picture->openMaxBuffer; + } + #endif + #ifdef HAVE_VIDEOTOOLBOXDECODER +-void CLinuxRendererGLES::AddProcessor(struct __CVBuffer *cvBufferRef) ++void CLinuxRendererGLES::AddProcessor(struct __CVBuffer *cvBufferRef, int index) + { +- YUVBUFFER &buf = m_buffers[NextYV12Texture()]; ++ YUVBUFFER &buf = m_buffers[index]; + if (buf.cvBufferRef) + CVBufferRelease(buf.cvBufferRef); + buf.cvBufferRef = cvBufferRef; +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h +index 76b5437..c6b69db 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h +@@ -153,10 +153,10 @@ class CLinuxRendererGLES : public CBaseRenderer + virtual std::vector SupportedFormats() { return m_formats; } + + #ifdef HAVE_LIBOPENMAX +- virtual void AddProcessor(COpenMax* openMax, DVDVideoPicture *picture); ++ virtual void AddProcessor(COpenMax* openMax, DVDVideoPicture *picture, int index); + #endif + #ifdef HAVE_VIDEOTOOLBOXDECODER +- virtual void AddProcessor(struct __CVBuffer *cvBufferRef); ++ virtual void AddProcessor(struct __CVBuffer *cvBufferRef, int index); + #endif + + protected: +diff --git a/xbmc/cores/VideoRenderers/OverlayRenderer.cpp b/xbmc/cores/VideoRenderers/OverlayRenderer.cpp +index 19d2d7d..94aaaf5 100644 +--- a/xbmc/cores/VideoRenderers/OverlayRenderer.cpp ++++ b/xbmc/cores/VideoRenderers/OverlayRenderer.cpp +@@ -89,7 +89,6 @@ long COverlayMainThread::Release() + CRenderer::CRenderer() + { + m_render = 0; +- m_decode = (m_render + 1) % 2; + } + + CRenderer::~CRenderer() +@@ -151,20 +150,30 @@ void CRenderer::Flush() + { + CSingleLock lock(m_section); + +- for(int i = 0; i < 2; i++) ++ for(int i = 0; i < m_iNumBuffers; i++) + Release(m_buffers[i]); + ++ m_render = 0; + Release(m_cleanup); + } + + void CRenderer::Flip() + { + CSingleLock lock(m_section); ++ m_render = (m_render + 1) % m_iNumBuffers; ++} + +- m_render = m_decode; +- m_decode =(m_decode + 1) % 2; ++void CRenderer::SetBuffer(int idx) ++{ ++ CSingleLock lock(m_section); ++ Release(m_buffers[idx]); ++ m_decode = idx; ++} + +- Release(m_buffers[m_decode]); ++void CRenderer::ReleaseBuffer(int idx) ++{ ++ CSingleLock lock(m_section); ++ Release(m_buffers[idx]); + } + + void CRenderer::Render() +diff --git a/xbmc/cores/VideoRenderers/OverlayRenderer.h b/xbmc/cores/VideoRenderers/OverlayRenderer.h +index d2175d8..c6740a5 100644 +--- a/xbmc/cores/VideoRenderers/OverlayRenderer.h ++++ b/xbmc/cores/VideoRenderers/OverlayRenderer.h +@@ -98,6 +98,9 @@ + void Flip(); + void Render(); + void Flush(); ++ void SetNumBuffers(int numBuffers) { m_iNumBuffers = numBuffers; } ++ void SetBuffer(int idx); ++ void ReleaseBuffer(int idx); + + protected: + +@@ -124,7 +127,8 @@ + void Release(SElementV& list); + + CCriticalSection m_section; +- SElementV m_buffers[2]; ++ SElementV m_buffers[10]; ++ int m_iNumBuffers; + int m_decode; + int m_render; + +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index d22287d..eeb6c6f 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -28,6 +28,7 @@ + #include "utils/MathUtils.h" + #include "threads/SingleLock.h" + #include "utils/log.h" ++#include "utils/TimeUtils.h" + + #include "Application.h" + #include "ApplicationMessenger.h" +@@ -247,6 +248,11 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi + return false; + } + ++ // check if decoder supports buffering ++ m_bCodecSupportsBuffering = false; ++// if (format == RENDER_FMT_VDPAU) ++// m_bCodecSupportsBuffering = true; ++ + bool result = m_pRenderer->Configure(width, height, d_width, d_height, fps, flags, format, extended_format, orientation); + if(result) + { +@@ -261,6 +267,7 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi + m_bReconfigured = true; + m_presentstep = PRESENT_IDLE; + m_presentevent.Set(); ++ ResetRenderBuffer(); + } + + return result; +@@ -292,8 +299,12 @@ void CXBMCRenderManager::RenderUpdate(bool clear, DWORD flags, DWORD alpha) + if (!m_pRenderer) + return; + ++ if (m_presentstep == PRESENT_IDLE) ++ PrepareNextRender(); ++ + if(m_presentstep == PRESENT_FLIP) + { ++ FlipRenderBuffer(); + m_overlays.Flip(); + m_pRenderer->FlipPage(m_presentsource); + m_presentstep = PRESENT_FRAME; +@@ -312,7 +323,7 @@ void CXBMCRenderManager::RenderUpdate(bool clear, DWORD flags, DWORD alpha) + m_presentevent.Set(); + } + +-unsigned int CXBMCRenderManager::PreInit() ++unsigned int CXBMCRenderManager::PreInit(CDVDClock *pClock) + { + CRetakeLock lock(m_sharedSection); + +@@ -320,6 +331,7 @@ unsigned int CXBMCRenderManager::PreInit() + m_presenterr = 0.0; + m_errorindex = 0; + memset(m_errorbuff, 0, sizeof(m_errorbuff)); ++ m_pClock = pClock; + + m_bIsStarted = false; + m_bPauseDrawing = false; +@@ -338,6 +350,10 @@ unsigned int CXBMCRenderManager::PreInit() + + UpdateDisplayLatency(); + ++ m_bUseBuffering = false; ++ m_bCodecSupportsBuffering = true; ++ ResetRenderBuffer(); ++ + return m_pRenderer->PreInit(); + } + +@@ -366,7 +382,9 @@ bool CXBMCRenderManager::Flush() + + CRetakeLock lock(m_sharedSection); + m_pRenderer->Flush(); ++ m_overlays.Flush(); + m_flushEvent.Set(); ++ ResetRenderBuffer(); + } + else + { +@@ -534,25 +552,21 @@ void CXBMCRenderManager::SetViewMode(int iViewMode) + m_pRenderer->SetViewMode(iViewMode); + } + +-void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0LL*/, int source /*= -1*/, EFIELDSYNC sync /*= FS_NONE*/) ++void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0LL*/, int source /*= -1*/, EFIELDSYNC sync /*= FS_NONE*/, int speed /*= 0*/) + { +- if(timestamp - GetPresentTime() > MAXPRESENTDELAY) +- timestamp = GetPresentTime() + MAXPRESENTDELAY; +- +- /* can't flip, untill timestamp */ +- if(!g_graphicsContext.IsFullScreenVideo()) +- WaitPresentTime(timestamp); +- +- /* make sure any queued frame was fully presented */ +- double timeout = m_presenttime + 1.0; +- while(m_presentstep != PRESENT_IDLE && !bStop) ++ if (!m_bUseBuffering) + { +- if(!m_presentevent.WaitMSec(100) && GetPresentTime() > timeout && !bStop) ++ /* make sure any queued frame was fully presented */ ++ double timeout = m_presenttime + 1.0; ++ while(m_presentstep != PRESENT_IDLE && !bStop) + { +- CLog::Log(LOGWARNING, "CRenderManager::FlipPage - timeout waiting for previous frame"); +- return; ++ if(!m_presentevent.WaitMSec(100) && GetPresentTime() > timeout && !bStop) ++ { ++ CLog::Log(LOGWARNING, "CRenderManager::FlipPage - timeout waiting for previous frame"); ++ return; ++ } + } +- }; ++ } + + if(bStop) + return; +@@ -560,58 +574,67 @@ void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0L + { CRetakeLock lock(m_sharedSection); + if(!m_pRenderer) return; + +- m_presenttime = timestamp; +- m_presentfield = sync; +- m_presentstep = PRESENT_FLIP; +- m_presentsource = source; ++ double presenttime = timestamp; ++ EFIELDSYNC presentfield = sync; ++ EPRESENTMETHOD presentmethod; ++ + EDEINTERLACEMODE deinterlacemode = g_settings.m_currentVideoSettings.m_DeinterlaceMode; + EINTERLACEMETHOD interlacemethod = AutoInterlaceMethodInternal(g_settings.m_currentVideoSettings.m_InterlaceMethod); + + bool invert = false; + + if (deinterlacemode == VS_DEINTERLACEMODE_OFF) +- m_presentmethod = PRESENT_METHOD_SINGLE; ++ presentmethod = PRESENT_METHOD_SINGLE; + else + { +- if (deinterlacemode == VS_DEINTERLACEMODE_AUTO && m_presentfield == FS_NONE) +- m_presentmethod = PRESENT_METHOD_SINGLE; ++ if (deinterlacemode == VS_DEINTERLACEMODE_AUTO && presentfield == FS_NONE) ++ presentmethod = PRESENT_METHOD_SINGLE; + else + { +- if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BLEND) m_presentmethod = PRESENT_METHOD_BLEND; +- else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_WEAVE) m_presentmethod = PRESENT_METHOD_WEAVE; +- else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_WEAVE_INVERTED) { m_presentmethod = PRESENT_METHOD_WEAVE ; invert = true; } +- else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BOB) m_presentmethod = PRESENT_METHOD_BOB; +- else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BOB_INVERTED) { m_presentmethod = PRESENT_METHOD_BOB; invert = true; } +- else if (interlacemethod == VS_INTERLACEMETHOD_DXVA_BOB) m_presentmethod = PRESENT_METHOD_BOB; +- else if (interlacemethod == VS_INTERLACEMETHOD_DXVA_BEST) m_presentmethod = PRESENT_METHOD_BOB; +- else m_presentmethod = PRESENT_METHOD_SINGLE; ++ if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BLEND) presentmethod = PRESENT_METHOD_BLEND; ++ else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_WEAVE) presentmethod = PRESENT_METHOD_WEAVE; ++ else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_WEAVE_INVERTED) { presentmethod = PRESENT_METHOD_WEAVE ; invert = true; } ++ else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BOB) presentmethod = PRESENT_METHOD_BOB; ++ else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BOB_INVERTED) { presentmethod = PRESENT_METHOD_BOB; invert = true; } ++ else if (interlacemethod == VS_INTERLACEMETHOD_DXVA_BOB) presentmethod = PRESENT_METHOD_BOB; ++ else if (interlacemethod == VS_INTERLACEMETHOD_DXVA_BEST) presentmethod = PRESENT_METHOD_BOB; ++ else presentmethod = PRESENT_METHOD_SINGLE; + + /* default to odd field if we want to deinterlace and don't know better */ +- if (deinterlacemode == VS_DEINTERLACEMODE_FORCE && m_presentfield == FS_NONE) +- m_presentfield = FS_TOP; ++ if (deinterlacemode == VS_DEINTERLACEMODE_FORCE && presentfield == FS_NONE) ++ presentfield = FS_TOP; + + /* invert present field */ + if(invert) + { +- if( m_presentfield == FS_BOT ) +- m_presentfield = FS_TOP; ++ if( presentfield == FS_BOT ) ++ presentfield = FS_TOP; + else +- m_presentfield = FS_BOT; ++ presentfield = FS_BOT; + } + } + } + ++ FlipFreeBuffer(); ++ m_renderBuffers[m_iOutputRenderBuffer].pts = timestamp; ++ m_renderBuffers[m_iOutputRenderBuffer].presentfield = presentfield; ++ m_renderBuffers[m_iOutputRenderBuffer].presentmethod = presentmethod; ++ m_speed = speed; + } + + g_application.NewFrame(); +- /* wait untill render thread have flipped buffers */ +- timeout = m_presenttime + 1.0; +- while(m_presentstep == PRESENT_FLIP && !bStop) ++ ++ if (!m_bUseBuffering) + { +- if(!m_presentevent.WaitMSec(100) && GetPresentTime() > timeout && !bStop) ++ /* wait untill render thread have flipped buffers */ ++ double timeout = m_presenttime + 1.0; ++ while(m_presentstep == PRESENT_FLIP && !bStop) + { +- CLog::Log(LOGWARNING, "CRenderManager::FlipPage - timeout waiting for flip to complete"); +- return; ++ if(!m_presentevent.WaitMSec(100) && GetPresentTime() > timeout && !bStop) ++ { ++ CLog::Log(LOGWARNING, "CRenderManager::FlipPage - timeout waiting for flip to complete"); ++ return; ++ } + } + } + } +@@ -675,8 +698,12 @@ void CXBMCRenderManager::Present() + if (!m_pRenderer) + return; + ++ if (m_presentstep == PRESENT_IDLE) ++ PrepareNextRender(); ++ + if(m_presentstep == PRESENT_FLIP) + { ++ FlipRenderBuffer(); + m_overlays.Flip(); + m_pRenderer->FlipPage(m_presentsource); + m_presentstep = PRESENT_FRAME; +@@ -800,11 +827,11 @@ int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic) + if (!m_pRenderer) + return -1; + +- if(m_pRenderer->AddVideoPicture(&pic)) ++ if(m_pRenderer->AddVideoPicture(&pic, (m_iOutputRenderBuffer + 1) % m_iNumRenderBuffers)) + return 1; + + YV12Image image; +- int index = m_pRenderer->GetImage(&image); ++ int index = m_pRenderer->GetImage(&image, (m_iOutputRenderBuffer + 1) % m_iNumRenderBuffers); + + if(index < 0) + return index; +@@ -830,19 +857,19 @@ int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic) + } + #ifdef HAVE_LIBVDPAU + else if(pic.format == RENDER_FMT_VDPAU) +- m_pRenderer->AddProcessor(pic.vdpau); ++ m_pRenderer->AddProcessor(pic.vdpau, index); + #endif + #ifdef HAVE_LIBOPENMAX + else if(pic.format == RENDER_FMT_OMXEGL) +- m_pRenderer->AddProcessor(pic.openMax, &pic); ++ m_pRenderer->AddProcessor(pic.openMax, &pic, index); + #endif + #ifdef TARGET_DARWIN + else if(pic.format == RENDER_FMT_CVBREF) +- m_pRenderer->AddProcessor(pic.cvBufferRef); ++ m_pRenderer->AddProcessor(pic.cvBufferRef, index); + #endif + #ifdef HAVE_LIBVA + else if(pic.format == RENDER_FMT_VAAPI) +- m_pRenderer->AddProcessor(*pic.vaapi); ++ m_pRenderer->AddProcessor(*pic.vaapi, index); + #endif + m_pRenderer->ReleaseImage(index, false); + +@@ -904,3 +931,176 @@ EINTERLACEMETHOD CXBMCRenderManager::AutoInterlaceMethodInternal(EINTERLACEMETHO + + return mInt; + } ++ ++int CXBMCRenderManager::WaitForBuffer(volatile bool& bStop) ++{ ++ CSharedLock lock(m_sharedSection); ++ if (!m_pRenderer) ++ return -1; ++ ++ //wait up to a second as this is our slowest allowed output rate ++ double timeout = GetPresentTime() + 0.1; ++ while(!HasFreeBuffer() && !bStop) ++ { ++ lock.Leave(); ++ m_flipEvent.WaitMSec(50); ++ if(GetPresentTime() > timeout && !bStop) ++ { ++ CLog::Log(LOGWARNING, "CRenderManager::WaitForBuffer - timeout waiting for buffer"); ++ return -1; ++ } ++ lock.Enter(); ++ } ++ lock.Leave(); ++ ++ { CRetakeLock lock(m_sharedSection); ++ m_overlays.SetBuffer((m_iOutputRenderBuffer + 1) % m_iNumRenderBuffers); ++ } ++ ++ if (bStop) ++ return -1; ++ ++ return 1; ++} ++ ++int CXBMCRenderManager::GetNextRenderBufferIndex() ++{ ++ if (m_iOutputRenderBuffer == m_iCurrentRenderBuffer) ++ return -1; ++ return (m_iCurrentRenderBuffer + 1) % m_iNumRenderBuffers; ++} ++ ++void CXBMCRenderManager::FlipRenderBuffer() ++{ ++ m_iCurrentRenderBuffer = GetNextRenderBufferIndex(); ++} ++ ++int CXBMCRenderManager::FlipFreeBuffer() ++{ ++ // See "Render Buffer State Description" in header for information. ++ if (HasFreeBuffer()) ++ { ++ m_bAllRenderBuffersDisplayed = false; ++ m_iOutputRenderBuffer = (m_iOutputRenderBuffer + 1) % m_iNumRenderBuffers; ++ return m_iOutputRenderBuffer; ++ } ++} ++ ++bool CXBMCRenderManager::HasFreeBuffer() ++{ ++ if (!m_bUseBuffering) ++ { ++ if (m_iOutputRenderBuffer != m_iCurrentRenderBuffer) ++ return false; ++ else ++ return true; ++ } ++ ++ int outputPlus1 = (m_iOutputRenderBuffer + 1) % m_iNumRenderBuffers; ++ if ((m_iOutputRenderBuffer == m_iDisplayedRenderBuffer && !m_bAllRenderBuffersDisplayed) ++ || outputPlus1 == m_iCurrentRenderBuffer) ++ return false; ++ else ++ return true; ++} ++ ++void CXBMCRenderManager::ResetRenderBuffer() ++{ ++ m_iNumRenderBuffers = m_pRenderer->GetMaxProcessorSize(); ++ m_iNumRenderBuffers = std::min(5, m_iNumRenderBuffers); ++ m_iNumRenderBuffers = std::max(2, m_iNumRenderBuffers); ++ ++ if (!m_bCodecSupportsBuffering) ++ m_iNumRenderBuffers = 2; ++ ++ CLog::Log(LOGNOTICE,"CXBMCRenderManager::ResetRenderBuffer - using %d render buffers", m_iNumRenderBuffers); ++ m_overlays.SetNumBuffers(m_iNumRenderBuffers); ++ m_pRenderer->SetProcessorSize(m_iNumRenderBuffers); ++ ++ m_iCurrentRenderBuffer = 0; ++ m_iOutputRenderBuffer = 0; ++ m_iDisplayedRenderBuffer = 0; ++ m_bAllRenderBuffersDisplayed = true; ++ m_sleeptime = 1.0; ++ m_presentPts = DVD_NOPTS_VALUE; ++ m_speed = 0; ++} ++ ++void CXBMCRenderManager::PrepareNextRender() ++{ ++ int idx = GetNextRenderBufferIndex(); ++ if (idx < 0) ++ { ++ if (m_speed >= DVD_PLAYSPEED_NORMAL && g_graphicsContext.IsFullScreenVideo()) ++ CLog::Log(LOGDEBUG,"%s no buffer, out: %d, current: %d, display: %d", ++ __FUNCTION__, m_iOutputRenderBuffer, m_iCurrentRenderBuffer, m_iDisplayedRenderBuffer); ++ return; ++ } ++ ++ double iClockSleep, iPlayingClock, iCurrentClock; ++ iPlayingClock = m_pClock->GetClock(iCurrentClock, false); ++ iClockSleep = m_renderBuffers[idx].pts - iPlayingClock; ++ ++ if (m_speed) ++ iClockSleep = iClockSleep * DVD_PLAYSPEED_NORMAL / m_speed; ++ ++ double presenttime = (iCurrentClock + iClockSleep) / DVD_TIME_BASE; ++ double clocktime = iCurrentClock / DVD_TIME_BASE; ++ if(presenttime - clocktime > MAXPRESENTDELAY) ++ presenttime = clocktime + MAXPRESENTDELAY; ++ ++ m_sleeptime = presenttime - clocktime; ++ ++ if (g_graphicsContext.IsFullScreenVideo() || presenttime <= clocktime+0.01) ++ { ++ m_presentPts = m_renderBuffers[idx].pts; ++ m_presenttime = presenttime; ++ m_presentmethod = m_renderBuffers[idx].presentmethod; ++ m_presentfield = m_renderBuffers[idx].presentfield; ++ m_presentstep = PRESENT_FLIP; ++ m_presentsource = idx; ++ } ++} ++ ++void CXBMCRenderManager::EnableBuffering(bool enable) ++{ ++ CRetakeLock lock(m_sharedSection); ++ ++ if (m_iNumRenderBuffers < 3) ++ return; ++ ++ m_bUseBuffering = enable; ++ if (!m_bUseBuffering) ++ m_iOutputRenderBuffer = m_iCurrentRenderBuffer; ++ ++ CLog::Log(LOGDEBUG, "CXBMCRenderManager::EnableBuffering - %d", m_bUseBuffering); ++} ++ ++void CXBMCRenderManager::DiscardBuffer() ++{ ++ CRetakeLock lock(m_sharedSection); ++ m_iOutputRenderBuffer = m_iCurrentRenderBuffer; ++} ++ ++void CXBMCRenderManager::NotifyDisplayFlip() ++{ ++ CRetakeLock lock(m_sharedSection); ++ if (!m_pRenderer) ++ return; ++ ++ if (m_iNumRenderBuffers < 3) ++ return; ++ ++ int last = m_iDisplayedRenderBuffer; ++ m_iDisplayedRenderBuffer = (m_iCurrentRenderBuffer + m_iNumRenderBuffers - 1) % m_iNumRenderBuffers; ++ ++ if (last != m_iDisplayedRenderBuffer ++ && m_iDisplayedRenderBuffer != m_iCurrentRenderBuffer) ++ { ++ m_pRenderer->ReleaseBuffer(m_iDisplayedRenderBuffer); ++ m_overlays.ReleaseBuffer(m_iDisplayedRenderBuffer); ++ } ++ ++ lock.Leave(); ++ m_flipEvent.Set(); ++} +diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h +index 7fe6bb2..34ff8d0 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.h ++++ b/xbmc/cores/VideoRenderers/RenderManager.h +@@ -31,6 +31,7 @@ + #include "OverlayRenderer.h" + + class CRenderCapture; ++class CDVDClock; + + namespace DXVA { class CProcessor; } + namespace VAAPI { class CSurfaceHolder; } +@@ -70,8 +71,8 @@ class CXBMCRenderManager + + int AddVideoPicture(DVDVideoPicture& picture); + +- void FlipPage(volatile bool& bStop, double timestamp = 0.0, int source = -1, EFIELDSYNC sync = FS_NONE); +- unsigned int PreInit(); ++ void FlipPage(volatile bool& bStop, double timestamp = 0.0, int source = -1, EFIELDSYNC sync = FS_NONE, int speed = 0); ++ unsigned int PreInit(CDVDClock *pClock); + void UnInit(); + bool Flush(); + +@@ -131,6 +132,10 @@ class CXBMCRenderManager + CSharedSection& GetSection() { return m_sharedSection; }; + + void RegisterRenderUpdateCallBack(const void *ctx, RenderUpdateCallBackFn fn); ++ int WaitForBuffer(volatile bool& bStop); ++ void NotifyDisplayFlip(); ++ void EnableBuffering(bool enable); ++ void DiscardBuffer(); + + protected: + void Render(bool clear, DWORD flags, DWORD alpha); +@@ -139,6 +144,13 @@ class CXBMCRenderManager + void PresentFields(bool clear, DWORD flags, DWORD alpha); + void PresentBlend(bool clear, DWORD flags, DWORD alpha); + ++ int GetNextRenderBufferIndex(); ++ void FlipRenderBuffer(); ++ int FlipFreeBuffer(); ++ bool HasFreeBuffer(); ++ void ResetRenderBuffer(); ++ void PrepareNextRender(); ++ + EINTERLACEMETHOD AutoInterlaceMethodInternal(EINTERLACEMETHOD mInt); + + bool m_bPauseDrawing; // true if we should pause rendering +@@ -169,6 +181,37 @@ class CXBMCRenderManager + double m_displayLatency; + void UpdateDisplayLatency(); + ++ // Render Buffer State Description: ++ // ++ // Output: is the buffer about to or having its texture prepared for render (ie from output thread). ++ // Cannot go past the "Displayed" buffer (otherwise we will probably overwrite buffers not yet ++ // displayed or even rendered). ++ // Current: is the current buffer being or having been submitted for render to back buffer. ++ // Cannot go past "Output" buffer (else it would be rendering old output). ++ // Displayed: is the buffer that is now considered to be safely copied from back buffer to front buffer ++ // (we assume that after two swap-buffer flips for the same "Current" render buffer that that ++ // buffer will be safe, but otherwise we consider that only the previous-to-"Current" is guaranteed). ++ ++ int m_iCurrentRenderBuffer; ++ int m_iNumRenderBuffers; ++ int m_iOutputRenderBuffer; ++ int m_iDisplayedRenderBuffer; ++ bool m_bAllRenderBuffersDisplayed; ++ bool m_bUseBuffering; ++ bool m_bCodecSupportsBuffering; ++ int m_speed; ++ CEvent m_flipEvent; ++ ++ struct ++ { ++ double pts; ++ EFIELDSYNC presentfield; ++ EPRESENTMETHOD presentmethod; ++ }m_renderBuffers[5]; ++ ++ double m_sleeptime; ++ double m_presentPts; ++ + double m_presenttime; + double m_presentcorr; + double m_presenterr; +@@ -180,6 +223,7 @@ class CXBMCRenderManager + int m_presentsource; + CEvent m_presentevent; + CEvent m_flushEvent; ++ CDVDClock *m_pClock; + + + OVERLAY::CRenderer m_overlays; +diff --git a/xbmc/cores/VideoRenderers/WinRenderer.cpp b/xbmc/cores/VideoRenderers/WinRenderer.cpp +index 7842089..6e4433c 100644 +--- a/xbmc/cores/VideoRenderers/WinRenderer.cpp ++++ b/xbmc/cores/VideoRenderers/WinRenderer.cpp +@@ -253,12 +253,12 @@ int CWinRenderer::NextYV12Texture() + return -1; + } + +-bool CWinRenderer::AddVideoPicture(DVDVideoPicture* picture) ++bool CWinRenderer::AddVideoPicture(DVDVideoPicture* picture, int index) + { + if (m_renderMethod == RENDER_DXVA) + { +- int source = NextYV12Texture(); +- if(source < 0) ++ int source = index; ++ if(source < 0 || NextYV12Texture() < 0) + return false; + + DXVABuffer *buf = (DXVABuffer*)m_VideoBuffers[source]; +@@ -274,7 +274,7 @@ int CWinRenderer::GetImage(YV12Image *image, int source, bool readonly) + if( source == AUTOSOURCE ) + source = NextYV12Texture(); + +- if( source < 0 ) ++ if( source < 0 || NextYV12Texture() < 0) + return -1; + + YUVBuffer *buf = (YUVBuffer*)m_VideoBuffers[source]; +diff --git a/xbmc/cores/VideoRenderers/WinRenderer.h b/xbmc/cores/VideoRenderers/WinRenderer.h +index 2ab5684..f493ba7 100644 +--- a/xbmc/cores/VideoRenderers/WinRenderer.h ++++ b/xbmc/cores/VideoRenderers/WinRenderer.h +@@ -157,7 +157,7 @@ class CWinRenderer : public CBaseRenderer + virtual bool Configure(unsigned int width, unsigned int height, unsigned int d_width, unsigned int d_height, float fps, unsigned flags, ERenderFormat format, unsigned extended_format, unsigned int orientation); + virtual int GetImage(YV12Image *image, int source = AUTOSOURCE, bool readonly = false); + virtual void ReleaseImage(int source, bool preserve = false); +- virtual bool AddVideoPicture(DVDVideoPicture* picture); ++ virtual bool AddVideoPicture(DVDVideoPicture* picture, int index); + virtual void FlipPage(int source); + virtual unsigned int PreInit(); + virtual void UnInit(); +diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp +index 0cd2510..315d64a 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp +@@ -463,7 +463,7 @@ bool CDVDPlayer::OpenFile(const CFileItem& file, const CPlayerOptions &options) + m_ready.Reset(); + + #if defined(HAS_VIDEO_PLAYBACK) +- g_renderManager.PreInit(); ++ g_renderManager.PreInit(&m_clock); + #endif + + Create(); +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +index 3008c25..a4bb1ba 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -261,6 +261,7 @@ void CDVDPlayerVideo::OpenStream(CDVDStreamInfo &hint, CDVDVideoCodec* codec) + m_stalled = m_messageQueue.GetPacketCount(CDVDMsg::DEMUXER_PACKET) == 0; + m_started = false; + m_codecname = m_pVideoCodec->GetName(); ++ g_renderManager.EnableBuffering(false); + } + + void CDVDPlayerVideo::CloseStream(bool bWaitForBuffers) +@@ -436,6 +437,7 @@ void CDVDPlayerVideo::Process() + picture.iFlags &= ~DVP_FLAG_ALLOCATED; + m_packets.clear(); + m_started = false; ++ g_renderManager.EnableBuffering(false); + } + else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) // private message sent by (CDVDPlayerVideo::Flush()) + { +@@ -448,6 +450,7 @@ void CDVDPlayerVideo::Process() + //we need to recalculate the framerate + //TODO: this needs to be set on a streamchange instead + ResetFrameRateCalc(); ++ g_renderManager.EnableBuffering(false); + + m_stalled = true; + m_started = false; +@@ -586,6 +589,8 @@ void CDVDPlayerVideo::Process() + + m_pVideoCodec->Reset(); + m_packets.clear(); ++ picture.iFlags &= ~DVP_FLAG_ALLOCATED; ++ g_renderManager.DiscardBuffer(); + break; + } + +@@ -700,6 +705,7 @@ void CDVDPlayerVideo::Process() + m_codecname = m_pVideoCodec->GetName(); + m_started = true; + m_messageParent.Put(new CDVDMsgInt(CDVDMsg::PLAYER_STARTED, DVDPLAYER_VIDEO)); ++ g_renderManager.EnableBuffering(true); + } + + // guess next frame pts. iDuration is always valid +@@ -1317,6 +1323,16 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) + mDisplayField = FS_BOT; + } + ++ int buffer = g_renderManager.WaitForBuffer(m_bStop); ++ while (buffer < 0 && !CThread::m_bStop && ++ CDVDClock::GetAbsoluteClock(false) < iCurrentClock + iSleepTime + DVD_MSEC_TO_TIME(500) ) ++ { ++ Sleep(1); ++ buffer = g_renderManager.WaitForBuffer(m_bStop); ++ } ++ if (buffer < 0) ++ return EOS_DROPPED; ++ + ProcessOverlays(pPicture, pts); + AutoCrop(pPicture); + +@@ -1333,7 +1349,7 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) + if (index < 0) + return EOS_DROPPED; + +- g_renderManager.FlipPage(CThread::m_bStop, (iCurrentClock + iSleepTime) / DVD_TIME_BASE, -1, mDisplayField); ++ g_renderManager.FlipPage(CThread::m_bStop, pts, -1, mDisplayField, m_speed); + + return result; + #else +-- +1.7.10 + + +From dacc0167c993efa6ac884fd3c439fc5f0c823934 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Tue, 2 Oct 2012 10:49:09 +0200 +Subject: [PATCH 03/73] linuxrenderer: delete all textures on reconfigure + +--- + xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +index b32a7ea..a2dc2be 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +@@ -251,7 +251,7 @@ bool CLinuxRendererGL::ValidateRenderTarget() + // function pointer for texture might change in + // call to LoadShaders + glFinish(); +- for (int i = 0 ; i < m_NumYV12Buffers ; i++) ++ for (int i = 0 ; i < NUM_BUFFERS ; i++) + (this->*m_textureDelete)(i); + + // trigger update of video filters +-- +1.7.10 + + +From 226539d21ba940ea8add89417df7102302c7ba79 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 28 May 2012 10:17:33 +0200 +Subject: [PATCH 04/73] drop frame counter in application, ask render manager + instead + +--- + xbmc/Application.cpp | 50 +++++---------------------- + xbmc/Application.h | 6 ++-- + xbmc/cores/VideoRenderers/RenderManager.cpp | 11 ++++++ + xbmc/cores/VideoRenderers/RenderManager.h | 1 + + 4 files changed, 23 insertions(+), 45 deletions(-) + +diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp +index 18e6310..9a7b900 100644 +--- a/xbmc/Application.cpp ++++ b/xbmc/Application.cpp +@@ -415,8 +415,6 @@ + #endif + m_currentStack = new CFileItemList; + +- m_frameCount = 0; +- + m_bPresentFrame = false; + m_bPlatformDirectories = true; + +@@ -2227,28 +2225,18 @@ float CApplication::GetDimScreenSaverLevel() const + + bool CApplication::WaitFrame(unsigned int timeout) + { +- bool done = false; +- + // Wait for all other frames to be presented +- CSingleLock lock(m_frameMutex); +- //wait until event is set, but modify remaining time ++ m_frameEvent.Reset(); + +- TightConditionVariable > cv(m_frameCond, InversePredicate(m_frameCount)); +- cv.wait(lock,timeout); +- done = m_frameCount == 0; ++ if (!g_renderManager.HasFrame() && !m_frameEvent.WaitMSec(timeout)) ++ return false; + +- return done; ++ return g_renderManager.HasFrame(); + } + + void CApplication::NewFrame() + { +- // We just posted another frame. Keep track and notify. +- { +- CSingleLock lock(m_frameMutex); +- m_frameCount++; +- } +- +- m_frameCond.notifyAll(); ++ m_frameEvent.Set(); + } + + void CApplication::Render() +@@ -2268,7 +2256,6 @@ void CApplication::Render() + + int vsync_mode = g_guiSettings.GetInt("videoscreen.vsync"); + +- bool decrement = false; + bool hasRendered = false; + bool limitFrames = false; + unsigned int singleFrameTime = 10; // default limit 100 fps +@@ -2282,13 +2269,10 @@ void CApplication::Render() + m_bPresentFrame = false; + if (!extPlayerActive && g_graphicsContext.IsFullScreenVideo() && !IsPaused()) + { +- CSingleLock lock(m_frameMutex); +- +- TightConditionVariable cv(m_frameCond,m_frameCount); +- cv.wait(lock,100); +- +- m_bPresentFrame = m_frameCount > 0; +- decrement = m_bPresentFrame; ++ m_frameEvent.Reset(); ++ m_bPresentFrame = g_renderManager.HasFrame(); ++ if (!m_bPresentFrame && m_frameEvent.WaitMSec(100)) ++ m_bPresentFrame = g_renderManager.HasFrame(); + hasRendered = true; + } + else +@@ -2312,8 +2296,6 @@ void CApplication::Render() + else if (lowfps) + singleFrameTime = 200; // 5 fps, <=200 ms latency to wake up + } +- +- decrement = true; + } + } + +@@ -2377,13 +2359,6 @@ void CApplication::Render() + + g_renderManager.UpdateResolution(); + g_renderManager.ManageCaptures(); +- +- { +- CSingleLock lock(m_frameMutex); +- if(m_frameCount > 0 && decrement) +- m_frameCount--; +- } +- m_frameCond.notifyAll(); + } + + void CApplication::SetStandAlone(bool value) +@@ -5638,12 +5613,6 @@ bool CApplication::SwitchToFullScreen() + // See if we're playing a video, and are in GUI mode + if ( IsPlayingVideo() && g_windowManager.GetActiveWindow() != WINDOW_FULLSCREEN_VIDEO) + { +- // Reset frame count so that timing is FPS will be correct. +- { +- CSingleLock lock(m_frameMutex); +- m_frameCount = 0; +- } +- + // then switch to fullscreen mode + g_windowManager.ActivateWindow(WINDOW_FULLSCREEN_VIDEO); + return true; +@@ -5876,7 +5845,6 @@ bool CApplication::IsCurrentThread() const + + bool CApplication::IsPresentFrame() + { +- CSingleLock lock(m_frameMutex); + bool ret = m_bPresentFrame; + + return ret; +diff --git a/xbmc/Application.h b/xbmc/Application.h +index 69609fa..6764a60 100644 +--- a/xbmc/Application.h ++++ b/xbmc/Application.h +@@ -422,10 +422,8 @@ class CApplication : public CXBApplicationEx, public IPlayerCallback, public IMs + bool m_bEnableLegacyRes; + bool m_bTestMode; + bool m_bSystemScreenSaverEnable; +- +- int m_frameCount; +- CCriticalSection m_frameMutex; +- XbmcThreads::ConditionVariable m_frameCond; ++ ++ CEvent m_frameEvent; + + VIDEO::CVideoInfoScanner *m_videoInfoScanner; + MUSIC_INFO::CMusicInfoScanner *m_musicInfoScanner; +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index eeb6c6f..4b897da 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -1104,3 +1104,14 @@ void CXBMCRenderManager::NotifyDisplayFlip() + lock.Leave(); + m_flipEvent.Set(); + } ++ ++bool CXBMCRenderManager::HasFrame() ++{ ++ CSharedLock lock(m_sharedSection); ++ if (m_presentstep == PRESENT_IDLE && ++ GetNextRenderBufferIndex() < 0 && ++ m_speed > 0) ++ return false; ++ else ++ return true; ++} +diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h +index 34ff8d0..288175e 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.h ++++ b/xbmc/cores/VideoRenderers/RenderManager.h +@@ -134,6 +134,7 @@ class CXBMCRenderManager + void RegisterRenderUpdateCallBack(const void *ctx, RenderUpdateCallBackFn fn); + int WaitForBuffer(volatile bool& bStop); + void NotifyDisplayFlip(); ++ bool HasFrame(); + void EnableBuffering(bool enable); + void DiscardBuffer(); + +-- +1.7.10 + + +From 0f81843cb7279f3b99607551967354ff30e15e4d Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 28 May 2012 10:34:39 +0200 +Subject: [PATCH 05/73] videoplayer: adopt lateness detection and dropping to + buffering + +--- + xbmc/cores/VideoRenderers/RenderManager.cpp | 12 ++ + xbmc/cores/VideoRenderers/RenderManager.h | 1 + + .../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h | 14 ++ + .../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 31 +++ + .../DVDCodecs/Video/DVDVideoCodecFFmpeg.h | 7 + + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 224 ++++++++++++++++---- + xbmc/cores/dvdplayer/DVDPlayerVideo.h | 24 +++ + 7 files changed, 268 insertions(+), 45 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index 4b897da..f19797c 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -1105,6 +1105,18 @@ void CXBMCRenderManager::NotifyDisplayFlip() + m_flipEvent.Set(); + } + ++bool CXBMCRenderManager::GetStats(double &sleeptime, double &pts, int &bufferLevel) ++{ ++ CSharedLock lock(m_sharedSection); ++ sleeptime = m_sleeptime; ++ pts = m_presentPts; ++ if (m_iNumRenderBuffers < 3) ++ bufferLevel = -1; ++ else ++ bufferLevel = (m_iOutputRenderBuffer - m_iCurrentRenderBuffer + m_iNumRenderBuffers) % m_iNumRenderBuffers; ++ return true; ++} ++ + bool CXBMCRenderManager::HasFrame() + { + CSharedLock lock(m_sharedSection); +diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h +index 288175e..9342586 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.h ++++ b/xbmc/cores/VideoRenderers/RenderManager.h +@@ -134,6 +134,7 @@ class CXBMCRenderManager + void RegisterRenderUpdateCallBack(const void *ctx, RenderUpdateCallBackFn fn); + int WaitForBuffer(volatile bool& bStop); + void NotifyDisplayFlip(); ++ bool GetStats(double &sleeptime, double &pts, int &bufferLevel); + bool HasFrame(); + void EnableBuffering(bool enable); + void DiscardBuffer(); +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h +index 1d8bad3..5001aac 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h +@@ -110,6 +110,10 @@ struct DVDVideoUserData + #define DVP_FLAG_NOSKIP 0x00000010 // indicate this picture should never be dropped + #define DVP_FLAG_DROPPED 0x00000020 // indicate that this picture has been dropped in decoder stage, will have no data + ++#define DVP_FLAG_DROPDEINT 0x00000040 // indicate that this picture was requested to have been dropped in deint stage ++#define DVP_FLAG_NO_POSTPROC 0x00000100 ++#define DVP_FLAG_DRAIN 0x00000200 ++ + // DVP_FLAG 0x00000100 - 0x00000f00 is in use by libmpeg2! + + #define DVP_QSCALE_UNKNOWN 0 +@@ -127,6 +131,9 @@ struct DVDVideoUserData + #define VC_PICTURE 0x00000004 // the decoder got a picture, call Decode(NULL, 0) again to parse the rest of the data + #define VC_USERDATA 0x00000008 // the decoder found some userdata, call Decode(NULL, 0) again to parse the rest of the data + #define VC_FLUSHED 0x00000010 // the decoder lost it's state, we need to restart decoding again ++#define VC_DROPPED 0x00000020 // needed to identify if a picture was dropped ++#define VC_HURRY 0x00000040 ++ + class CDVDVideoCodec + { + public: +@@ -237,4 +244,11 @@ class CDVDVideoCodec + { + return 0; + } ++ ++ virtual bool GetPts(double &pts, int &skippedDeint, int &interlaced) ++ { ++ return false; ++ } ++ ++ virtual void SetCodecControl(int flags) {} + }; +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +index 8f81637..af706bd 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +@@ -142,6 +142,7 @@ enum PixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx + m_iLastKeyframe = 0; + m_dts = DVD_NOPTS_VALUE; + m_started = false; ++ m_decoderPts = DVD_NOPTS_VALUE; + } + + CDVDVideoCodecFFmpeg::~CDVDVideoCodecFFmpeg() +@@ -340,6 +341,14 @@ void CDVDVideoCodecFFmpeg::SetDropState(bool bDrop) + { + if( m_pCodecContext ) + { ++ if (bDrop && m_pHardware && m_pHardware->CanSkipDeint()) ++ { ++ m_requestSkipDeint = true; ++ bDrop = false; ++ } ++ else ++ m_requestSkipDeint = false; ++ + // i don't know exactly how high this should be set + // couldn't find any good docs on it. think it varies + // from codec to codec on what it does +@@ -541,6 +550,7 @@ int CDVDVideoCodecFFmpeg::Decode(BYTE* pData, int iSize, double dts, double pts) + void CDVDVideoCodecFFmpeg::Reset() + { + m_started = false; ++ m_decoderPts = DVD_NOPTS_VALUE; + m_iLastKeyframe = m_pCodecContext->has_b_frames; + m_dllAvCodec.avcodec_flush_buffers(m_pCodecContext); + +@@ -639,6 +649,22 @@ bool CDVDVideoCodecFFmpeg::GetPictureCommon(DVDVideoPicture* pDvdVideoPicture) + else + pDvdVideoPicture->pts = DVD_NOPTS_VALUE; + ++ if (pDvdVideoPicture->pts != DVD_NOPTS_VALUE) ++ m_decoderPts = pDvdVideoPicture->pts; ++ else ++ m_decoderPts = m_dts; ++ ++ if (m_requestSkipDeint) ++ { ++ pDvdVideoPicture->iFlags |= DVP_FLAG_DROPDEINT; ++ m_skippedDeint = 1; ++ } ++ else ++ m_skippedDeint = 0; ++ ++ m_requestSkipDeint = false; ++ pDvdVideoPicture->iFlags |= m_codecControlFlags; ++ + if(!m_started) + pDvdVideoPicture->iFlags |= DVP_FLAG_DROPPED; + +@@ -861,3 +887,8 @@ unsigned CDVDVideoCodecFFmpeg::GetConvergeCount() + else + return 0; + } ++ ++void CDVDVideoCodecFFmpeg::SetCodecControl(int flags) ++{ ++ m_codecControlFlags = flags; ++} +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h +index 61d0305..52e1113 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h +@@ -44,6 +44,7 @@ class CDVDVideoCodecFFmpeg : public CDVDVideoCodec + virtual bool GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture) = 0; + virtual int Check (AVCodecContext* avctx) = 0; + virtual void Reset () {} ++ virtual bool CanSkipDeint() {return false; } + virtual const std::string Name() = 0; + virtual CCriticalSection* Section() { return NULL; } + }; +@@ -60,6 +61,8 @@ class CDVDVideoCodecFFmpeg : public CDVDVideoCodec + virtual unsigned int SetFilters(unsigned int filters); + virtual const char* GetName() { return m_name.c_str(); }; // m_name is never changed after open + virtual unsigned GetConvergeCount(); ++ virtual bool GetPts(double &pts, int &skippedDeint, int &interlaced) {pts=m_decoderPts; skippedDeint=m_skippedDeint; if (m_pFrame) interlaced = m_pFrame->interlaced_frame; return true;} ++ virtual void SetCodecControl(int flags); + + bool IsHardwareAllowed() { return !m_bSoftware; } + IHardwareDecoder * GetHardware() { return m_pHardware; }; +@@ -119,4 +122,8 @@ class CDVDVideoCodecFFmpeg : public CDVDVideoCodec + double m_dts; + bool m_started; + std::vector m_formats; ++ double m_decoderPts, m_decoderInterval; ++ int m_skippedDeint; ++ bool m_requestSkipDeint; ++ int m_codecControlFlags; + }; +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +index a4bb1ba..93908a7 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -326,8 +326,10 @@ void CDVDPlayerVideo::Process() + + int iDropped = 0; //frames dropped in a row + bool bRequestDrop = false; ++ int iDropDirective; + + m_videoStats.Start(); ++ m_droppingStats.Reset(); + + while (!m_bStop) + { +@@ -437,6 +439,7 @@ void CDVDPlayerVideo::Process() + picture.iFlags &= ~DVP_FLAG_ALLOCATED; + m_packets.clear(); + m_started = false; ++ m_droppingStats.Reset(); + g_renderManager.EnableBuffering(false); + } + else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) // private message sent by (CDVDPlayerVideo::Flush()) +@@ -450,6 +453,7 @@ void CDVDPlayerVideo::Process() + //we need to recalculate the framerate + //TODO: this needs to be set on a streamchange instead + ResetFrameRateCalc(); ++ m_droppingStats.Reset(); + g_renderManager.EnableBuffering(false); + + m_stalled = true; +@@ -468,6 +472,7 @@ void CDVDPlayerVideo::Process() + m_speed = static_cast(pMsg)->m_value; + if(m_speed == DVD_PLAYSPEED_PAUSE) + m_iNrOfPicturesNotToSkip = 0; ++ m_droppingStats.Reset(); + } + else if (pMsg->IsType(CDVDMsg::PLAYER_STARTED)) + { +@@ -502,6 +507,28 @@ void CDVDPlayerVideo::Process() + m_iNrOfPicturesNotToSkip = 1; + } + ++ bRequestDrop = false; ++ iDropDirective = CalcDropRequirement(pts); ++ if (iDropDirective & EOS_VERYLATE) ++ { ++ if (m_bAllowDrop) ++ { ++ m_pullupCorrection.Flush(); ++ bRequestDrop = true; ++ } ++ } ++ int codecControl = 0; ++ if (iDropDirective & EOS_BUFFER_LEVEL) ++ codecControl |= DVP_FLAG_DRAIN; ++ if (m_speed > DVD_PLAYSPEED_NORMAL) ++ codecControl |= DVP_FLAG_NO_POSTPROC; ++ m_pVideoCodec->SetCodecControl(codecControl); ++ if (iDropDirective & EOS_DROPPED) ++ { ++ m_iDroppedFrames++; ++ iDropped++; ++ } ++ + #ifdef PROFILE + bRequestDrop = false; + #else +@@ -511,6 +538,7 @@ void CDVDPlayerVideo::Process() + bRequestDrop = false; + m_iDroppedRequest = 0; + m_iLateFrames = 0; ++ m_droppingStats.m_requestOutputDrop = false; + } + #endif + +@@ -558,15 +586,8 @@ void CDVDPlayerVideo::Process() + } + + m_videoStats.AddSampleBytes(pPacket->iSize); +- // assume decoder dropped a picture if it didn't give us any +- // picture from a demux packet, this should be reasonable +- // for libavformat as a demuxer as it normally packetizes +- // pictures when they come from demuxer +- if(bRequestDrop && !bPacketDrop && (iDecoderState & VC_BUFFER) && !(iDecoderState & VC_PICTURE)) +- { +- m_iDroppedFrames++; +- iDropped++; +- } ++ ++ bRequestDrop = false; + + // loop while no error + while (!m_bStop) +@@ -1244,50 +1265,30 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) + m_FlipTimeStamp += max(0.0, iSleepTime); + m_FlipTimeStamp += iFrameDuration; + +- if (iSleepTime <= 0 && m_speed) +- m_iLateFrames++; +- else +- m_iLateFrames = 0; +- +- // ask decoder to drop frames next round, as we are very late +- if(m_iLateFrames > 10) +- { +- if (!(pPicture->iFlags & DVP_FLAG_NOSKIP)) +- { +- //if we're calculating the framerate, +- //don't drop frames until we've calculated a stable framerate +- if (m_bAllowDrop || m_speed != DVD_PLAYSPEED_NORMAL) +- { +- result |= EOS_VERYLATE; +- m_pullupCorrection.Flush(); //dropped frames mess up the pattern, so just flush it +- } +- +- //if we requested 5 drops in a row and we're still late, drop on output +- //this keeps a/v sync if the decoder can't drop, or we're still calculating the framerate +- if (m_iDroppedRequest > 5) +- { +- m_iDroppedRequest--; //decrease so we only drop half the frames +- return result | EOS_DROPPED; +- } +- m_iDroppedRequest++; +- } +- } +- else ++ if ((m_droppingStats.m_requestOutputDrop && !(pPicture->iFlags & DVP_FLAG_NOSKIP)) ++ || (pPicture->iFlags & DVP_FLAG_DROPPED)) + { +- m_iDroppedRequest = 0; ++ m_droppingStats.AddOutputDropGain(pts, 1/m_fFrameRate); ++ m_droppingStats.m_requestOutputDrop = false; ++ CLog::Log(LOGDEBUG,"%s - dropped in output", __FUNCTION__); ++ return result | EOS_DROPPED; + } + + if( m_speed < 0 ) + { +- if( iClockSleep < -DVD_MSEC_TO_TIME(200) +- && !(pPicture->iFlags & DVP_FLAG_NOSKIP) ) ++ double decoderPts = m_droppingStats.m_lastDecoderPts; ++ double renderPts = m_droppingStats.m_lastRenderPts; ++ if (pts > renderPts) ++ { ++ if (decoderPts >= renderPts) ++ { ++ Sleep(200); ++ } + return result | EOS_DROPPED; ++ } + } + +- if( (pPicture->iFlags & DVP_FLAG_DROPPED) ) +- return result | EOS_DROPPED; +- +- if( m_speed != DVD_PLAYSPEED_NORMAL && limited ) ++ if( m_speed != DVD_PLAYSPEED_NORMAL && m_speed >= 0 && limited ) + { + // calculate frame dropping pattern to render at this speed + // we do that by deciding if this or next frame is closest +@@ -1648,3 +1649,136 @@ void CDVDPlayerVideo::CalcFrameRate() + m_iFrameRateCount = 0; + } + } ++ ++int CDVDPlayerVideo::CalcDropRequirement(double pts) ++{ ++ int result = 0; ++ double iSleepTime; ++ double iDecoderPts, iRenderPts; ++ double iInterval; ++ int interlaced; ++ double iGain; ++ double iLateness; ++ bool bNewFrame; ++ int iSkippedDeint = 0; ++ int iBufferLevel; ++ ++ // get decoder stats ++ if (!m_pVideoCodec->GetPts(iDecoderPts, iSkippedDeint, interlaced)) ++ iDecoderPts = pts; ++ if (iDecoderPts == DVD_NOPTS_VALUE) ++ iDecoderPts = pts; ++ ++ // get render stats ++ g_renderManager.GetStats(iSleepTime, iRenderPts, iBufferLevel); ++ ++ if (iBufferLevel < 0) ++ result |= EOS_BUFFER_LEVEL; ++ else if (iBufferLevel < 2) ++ { ++ result |= EOS_BUFFER_LEVEL; ++ CLog::Log(LOGDEBUG,"CDVDPlayerVideo::CalcDropRequirement - hurry: %d", iBufferLevel); ++ } ++ ++ bNewFrame = iDecoderPts != m_droppingStats.m_lastDecoderPts; ++ ++ if (interlaced) ++ iInterval = 2/m_fFrameRate*(double)DVD_TIME_BASE; ++ else ++ iInterval = 1/m_fFrameRate*(double)DVD_TIME_BASE; ++ ++ if (m_droppingStats.m_lastDecoderPts > 0 ++ && bNewFrame ++ && m_bAllowDrop ++ && m_droppingStats.m_dropRequests > 0) ++ { ++ iGain = (iDecoderPts - m_droppingStats.m_lastDecoderPts - iInterval)/(double)DVD_TIME_BASE; ++ if (iSkippedDeint) ++ { ++ CDroppingStats::CGain gain; ++ gain.gain = 1/m_fFrameRate; ++ gain.pts = iDecoderPts; ++ m_droppingStats.m_gain.push_back(gain); ++ m_droppingStats.m_totalGain += gain.gain; ++ result |= EOS_DROPPED; ++ m_droppingStats.m_dropRequests = 0; ++ CLog::Log(LOGDEBUG,"CDVDPlayerVideo::CalcDropRequirement - dropped de-interlacing cycle, Sleeptime: %f, Bufferlevel: %d", iSleepTime, iBufferLevel); ++ } ++ else if (iGain > 1/m_fFrameRate) ++ { ++ CDroppingStats::CGain gain; ++ gain.gain = iGain; ++ gain.pts = iDecoderPts; ++ m_droppingStats.m_gain.push_back(gain); ++ m_droppingStats.m_totalGain += iGain; ++ result |= EOS_DROPPED; ++ m_droppingStats.m_dropRequests = 0; ++ CLog::Log(LOGDEBUG,"CDVDPlayerVideo::CalcDropRequirement - dropped in decoder, Sleeptime: %f, Bufferlevel: %d, Gain: %f", iSleepTime, iBufferLevel, iGain); ++ } ++ } ++ m_droppingStats.m_lastDecoderPts = iDecoderPts; ++ ++ // subtract gains ++ while (!m_droppingStats.m_gain.empty() && ++ iRenderPts >= m_droppingStats.m_gain.front().pts) ++ { ++ m_droppingStats.m_totalGain -= m_droppingStats.m_gain.front().gain; ++ m_droppingStats.m_gain.pop_front(); ++ } ++ ++ // calculate lateness ++ iLateness = iSleepTime + m_droppingStats.m_totalGain; ++ if (iLateness < 0 && m_speed) ++ { ++ if (bNewFrame) ++ m_droppingStats.m_lateFrames++; ++ ++ // if lateness is smaller than frametime, we observe this state ++ // for 10 cycles ++ if (m_droppingStats.m_lateFrames > 10 || iLateness < -2/m_fFrameRate) ++ { ++ // is frame allowed to skip ++ if (m_iNrOfPicturesNotToSkip <= 0) ++ { ++ result |= EOS_VERYLATE; ++ ++ // drop in output ++ if (m_droppingStats.m_dropRequests > 7 && g_graphicsContext.IsFullScreenVideo()) ++ { ++ m_droppingStats.m_dropRequests--; //decrease so we only drop half the frames ++ m_droppingStats.m_requestOutputDrop = true; ++ } ++ else if (bNewFrame) ++ m_droppingStats.m_dropRequests++; ++ } ++ } ++ } ++ else ++ { ++ m_droppingStats.m_dropRequests = 0; ++ m_droppingStats.m_lateFrames = 0; ++ m_droppingStats.m_requestOutputDrop = false; ++ } ++ m_droppingStats.m_lastRenderPts = iRenderPts; ++ return result; ++} ++ ++void CDroppingStats::Reset() ++{ ++ m_gain.clear(); ++ m_totalGain = 0; ++ m_lastDecoderPts = 0; ++ m_lastRenderPts = 0; ++ m_lateFrames = 0; ++ m_dropRequests = 0; ++ m_requestOutputDrop = false; ++} ++ ++void CDroppingStats::AddOutputDropGain(double pts, double frametime) ++{ ++ CDroppingStats::CGain gain; ++ gain.gain = frametime; ++ gain.pts = pts; ++ m_gain.push_back(gain); ++ m_totalGain += frametime; ++} +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.h b/xbmc/cores/dvdplayer/DVDPlayerVideo.h +index fe7e12c..4913712 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.h ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.h +@@ -37,6 +37,26 @@ + + #define VIDEO_PICTURE_QUEUE_SIZE 1 + ++class CDroppingStats ++{ ++public: ++ void Reset(); ++ void AddOutputDropGain(double pts, double frametime); ++ struct CGain ++ { ++ double gain; ++ double pts; ++ }; ++ std::deque m_gain; ++ double m_totalGain; ++ double m_lastDecoderPts; ++ double m_lastRenderPts; ++ unsigned int m_lateFrames; ++ unsigned int m_dropRequests; ++ bool m_requestOutputDrop; ++}; ++ ++ + class CDVDPlayerVideo : public CThread + { + public: +@@ -110,6 +130,7 @@ class CDVDPlayerVideo : public CThread + #define EOS_ABORT 1 + #define EOS_DROPPED 2 + #define EOS_VERYLATE 4 ++#define EOS_BUFFER_LEVEL 8 + + void AutoCrop(DVDVideoPicture* pPicture); + void AutoCrop(DVDVideoPicture *pPicture, RECT &crop); +@@ -135,6 +156,7 @@ class CDVDPlayerVideo : public CThread + + void ResetFrameRateCalc(); + void CalcFrameRate(); ++ int CalcDropRequirement(double pts); + + double m_fFrameRate; //framerate of the video currently playing + bool m_bCalcFrameRate; //if we should calculate the framerate from the timestamps +@@ -195,5 +217,7 @@ class CDVDPlayerVideo : public CThread + CPullupCorrection m_pullupCorrection; + + std::list m_packets; ++ ++ CDroppingStats m_droppingStats; + }; + +-- +1.7.10 + + +From 4bc6ff77b121468020578f9d393e8aaae1a419f6 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 28 May 2012 10:41:31 +0200 +Subject: [PATCH 06/73] videoplayer: update frametime, it might change due to + fps detection + +--- + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +index 93908a7..4675556 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -721,6 +721,8 @@ void CDVDPlayerVideo::Process() + CDVDCodecUtils::FreePicture(pTempYUVPackedPicture); + #endif + ++ frametime = (double)DVD_TIME_BASE/m_fFrameRate; ++ + if(m_started == false) + { + m_codecname = m_pVideoCodec->GetName(); +-- +1.7.10 + + +From 723a731d68b9360f9804e8711255afa62c4ce34d Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 28 May 2012 10:43:06 +0200 +Subject: [PATCH 07/73] videoplayer: give streams with invalid fps a chance + for fps detection + +--- + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +index 4675556..2ef6358 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -1595,7 +1595,7 @@ void CDVDPlayerVideo::CalcFrameRate() + double frameduration = m_pullupCorrection.GetFrameDuration(); + + if (frameduration == DVD_NOPTS_VALUE || +- (g_advancedSettings.m_videoFpsDetect == 1 && m_pullupCorrection.GetPatternLength() > 1)) ++ (g_advancedSettings.m_videoFpsDetect == 1 && (m_pullupCorrection.GetPatternLength() > 1 && !m_bFpsInvalid))) + { + //reset the stored framerates if no good framerate was detected + m_fStableFrameRate = 0.0; +-- +1.7.10 + + +From 60c955c30cdfcf361396e47fc92a1e1883b085fe Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 28 May 2012 10:49:05 +0200 +Subject: [PATCH 08/73] dvdplayer: allow rewinding at end of stream, do a seek + after rewind + +--- + xbmc/cores/dvdplayer/DVDPlayer.cpp | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp +index 315d64a..6fcb6b3 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp +@@ -1542,7 +1542,7 @@ void CDVDPlayer::HandlePlaySpeed() + + } + else if (m_CurrentVideo.id >= 0 +- && m_CurrentVideo.inited == true ++ && (m_CurrentVideo.inited == true || GetPlaySpeed() < 0) // allow rewind at end of file + && m_SpeedState.lastpts != m_dvdPlayerVideo.GetCurrentPts() + && m_SpeedState.lasttime != GetTime()) + { +@@ -2183,6 +2183,12 @@ void CDVDPlayer::HandleMessages() + pvrinputstream->Pause( speed == 0 ); + } + ++ // do a seek after rewind, clock is not in sync with current pts ++ if (m_playSpeed < 0 && speed >= 0) ++ { ++ m_messenger.Put(new CDVDMsgPlayerSeek(GetTime(), true, true, true)); ++ } ++ + // if playspeed is different then DVD_PLAYSPEED_NORMAL or DVD_PLAYSPEED_PAUSE + // audioplayer, stops outputing audio to audiorendere, but still tries to + // sleep an correct amount for each packet +-- +1.7.10 + + +From 8d237cf023501560fc394679819463034a209413 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sun, 2 Sep 2012 16:05:21 +0200 +Subject: [PATCH 09/73] video player: present correct pts to user for a/v sync + (after buffering in renderer) + +--- + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 41 +++++++++++++++++++------------ + xbmc/cores/dvdplayer/DVDPlayerVideo.h | 2 +- + 2 files changed, 26 insertions(+), 17 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +index 2ef6358..10e2225 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -1251,22 +1251,6 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) + else + iSleepTime = iFrameSleep + (iClockSleep - iFrameSleep) / m_autosync; + +-#ifdef PROFILE /* during profiling, try to play as fast as possible */ +- iSleepTime = 0; +-#endif +- +- // present the current pts of this frame to user, and include the actual +- // presentation delay, to allow him to adjust for it +- if( m_stalled ) +- m_iCurrentPts = DVD_NOPTS_VALUE; +- else +- m_iCurrentPts = pts - max(0.0, iSleepTime); +- +- // timestamp when we think next picture should be displayed based on current duration +- m_FlipTimeStamp = iCurrentClock; +- m_FlipTimeStamp += max(0.0, iSleepTime); +- m_FlipTimeStamp += iFrameDuration; +- + if ((m_droppingStats.m_requestOutputDrop && !(pPicture->iFlags & DVP_FLAG_NOSKIP)) + || (pPicture->iFlags & DVP_FLAG_DROPPED)) + { +@@ -1571,6 +1555,22 @@ void CDVDPlayerVideo::ResetFrameRateCalc() + g_advancedSettings.m_videoFpsDetect == 0; + } + ++double CDVDPlayerVideo::GetCurrentPts() ++{ ++ double iSleepTime, iRenderPts; ++ int iBufferLevel; ++ ++ // get render stats ++ g_renderManager.GetStats(iSleepTime, iRenderPts, iBufferLevel); ++ ++ if( m_stalled ) ++ iRenderPts = DVD_NOPTS_VALUE; ++ else ++ iRenderPts = iRenderPts - max(0.0, iSleepTime); ++ ++ return iRenderPts; ++} ++ + #define MAXFRAMERATEDIFF 0.01 + #define MAXFRAMESERR 1000 + +@@ -1689,6 +1689,15 @@ int CDVDPlayerVideo::CalcDropRequirement(double pts) + else + iInterval = 1/m_fFrameRate*(double)DVD_TIME_BASE; + ++ ++ m_FlipTimeStamp = m_pClock->GetAbsoluteClock() + max(0.0, iSleepTime) + iInterval; ++ ++ if( m_stalled ) ++ m_iCurrentPts = DVD_NOPTS_VALUE; ++ else ++ m_iCurrentPts = iRenderPts - max(0.0, iSleepTime); ++ ++ + if (m_droppingStats.m_lastDecoderPts > 0 + && bNewFrame + && m_bAllowDrop +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.h b/xbmc/cores/dvdplayer/DVDPlayerVideo.h +index 4913712..509d5f7 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.h ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.h +@@ -108,7 +108,7 @@ class CDVDPlayerVideo : public CThread + + bool InitializedOutputDevice(); + +- double GetCurrentPts() { return m_iCurrentPts; } ++ double GetCurrentPts(); + int GetPullupCorrection() { return m_pullupCorrection.GetPatternLength(); } + + double GetOutputDelay(); /* returns the expected delay, from that a packet is put in queue */ +-- +1.7.10 + + +From 04a6a8b4ca29c17da6bbb9591685922b2f6f1442 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 28 May 2012 11:02:29 +0200 +Subject: [PATCH 10/73] vaapi: adopt to buffering in renderer + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 2 +- + xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp | 3 ++- + xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h | 1 + + 3 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +index af706bd..dae3b8e 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +@@ -106,7 +106,7 @@ enum PixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx + && (avctx->codec_id != CODEC_ID_MPEG4 || g_advancedSettings.m_videoAllowMpeg4VAAPI)) + { + VAAPI::CDecoder* dec = new VAAPI::CDecoder(); +- if(dec->Open(avctx, *cur)) ++ if(dec->Open(avctx, *cur, ctx->m_uSurfacesCount)) + { + ctx->SetHardware(dec); + return *cur; +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp +index 9f5a960..a2b9195 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp +@@ -357,6 +357,7 @@ bool CDecoder::Open(AVCodecContext *avctx, enum PixelFormat fmt, unsigned int su + CHECK(vaCreateConfig(m_display->get(), profile, entrypoint, &attrib, 1, &m_hwaccel->config_id)) + m_config = m_hwaccel->config_id; + ++ m_renderbuffers_count = surfaces; + if (!EnsureContext(avctx)) + return false; + +@@ -388,7 +389,7 @@ bool CDecoder::EnsureContext(AVCodecContext *avctx) + else + m_refs = 2; + } +- return EnsureSurfaces(avctx, m_refs + 3); ++ return EnsureSurfaces(avctx, m_refs + m_renderbuffers_count + 1); + } + + bool CDecoder::EnsureSurfaces(AVCodecContext *avctx, unsigned n_surfaces_count) +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h +index 863edc4..417cbc0 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h +@@ -122,6 +122,7 @@ class CDecoder + static const unsigned m_surfaces_max = 32; + unsigned m_surfaces_count; + VASurfaceID m_surfaces[m_surfaces_max]; ++ unsigned m_renderbuffers_count; + + int m_refs; + std::list m_surfaces_used; +-- +1.7.10 + + +From 4d237410264bbff9c4ac373de498f80ecb15f7a3 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sat, 7 Apr 2012 09:19:00 +0200 +Subject: [PATCH 11/73] vdpau: redesign + +--- + language/English/strings.po | 12 +- + system/shaders/yuv2rgb_basic.glsl | 12 + + xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 203 +- + xbmc/cores/VideoRenderers/LinuxRendererGL.h | 13 +- + xbmc/cores/VideoRenderers/RenderFormats.h | 1 + + xbmc/cores/VideoRenderers/RenderManager.cpp | 8 +- + xbmc/cores/VideoRenderers/RenderManager.h | 2 +- + .../VideoRenderers/VideoShaders/YUV2RGBShader.cpp | 2 + + .../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h | 4 +- + .../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 23 +- + .../DVDCodecs/Video/DVDVideoCodecFFmpeg.h | 1 - + xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 3798 +++++++++++++++----- + xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h | 662 +++- + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 3 + + xbmc/settings/AdvancedSettings.cpp | 8 +- + xbmc/settings/AdvancedSettings.h | 4 +- + xbmc/settings/GUISettings.cpp | 2 + + xbmc/settings/GUIWindowSettingsCategory.cpp | 34 + + xbmc/utils/ActorProtocol.cpp | 253 ++ + xbmc/utils/ActorProtocol.h | 87 + + xbmc/utils/Makefile | 1 + + xbmc/video/dialogs/GUIDialogVideoSettings.cpp | 2 +- + xbmc/windowing/X11/WinSystemX11.h | 1 + + 23 files changed, 3942 insertions(+), 1194 deletions(-) + create mode 100644 xbmc/utils/ActorProtocol.cpp + create mode 100644 xbmc/utils/ActorProtocol.h + +diff --git a/language/English/strings.po b/language/English/strings.po +index dff2978..88292d3 100644 +--- a/language/English/strings.po ++++ b/language/English/strings.po +@@ -5114,7 +5114,15 @@ msgctxt "#13434" + msgid "Play only this" + msgstr "" + +-#empty strings from id 13435 to 13499 ++msgctxt "#13435" ++msgid "Allow Vdpau OpenGL interop" ++msgstr "" ++ ++msgctxt "#13436" ++msgid "Allow Vdpau OpenGL interop YUV" ++msgstr "" ++ ++#empty strings from id 13437 to 13499 + + msgctxt "#13500" + msgid "A/V sync method" +@@ -6333,7 +6341,7 @@ msgid "Software Blend" + msgstr "" + + msgctxt "#16325" +-msgid "Auto - ION Optimized" ++msgid "VDPAU - Bob" + msgstr "" + + #empty strings from id 16326 to 16399 +diff --git a/system/shaders/yuv2rgb_basic.glsl b/system/shaders/yuv2rgb_basic.glsl +index 88c33b2..aa26174 100644 +--- a/system/shaders/yuv2rgb_basic.glsl ++++ b/system/shaders/yuv2rgb_basic.glsl +@@ -70,6 +70,18 @@ void main() + rgb.a = gl_Color.a; + gl_FragColor = rgb; + ++#elif defined(XBMC_VDPAU_NV12) ++ ++ vec4 yuv, rgb; ++ yuv.rgba = vec4( texture2D(m_sampY, stretch(m_cordY)).r ++ , texture2D(m_sampU, stretch(m_cordU)).r ++ , texture2D(m_sampV, stretch(m_cordV)).g ++ , 1.0 ); ++ ++ rgb = m_yuvmat * yuv; ++ rgb.a = gl_Color.a; ++ gl_FragColor = rgb; ++ + #elif defined(XBMC_YUY2) || defined(XBMC_UYVY) + + #if(XBMC_texture_rectangle) +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +index a2dc2be..4ee50c1 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +@@ -689,6 +689,18 @@ void CLinuxRendererGL::RenderUpdate(bool clear, DWORD flags, DWORD alpha) + glDisable(GL_POLYGON_STIPPLE); + + } ++ else if(m_format == RENDER_FMT_VDPAU_420 ++ && !(flags & RENDER_FLAG_BOTH)) ++ { ++ glDisable(GL_BLEND); ++ glColor4f(1.0f, 1.0f, 1.0f, 1.0f); ++ Render(flags | RENDER_FLAG_TOP, index); ++ ++ glEnable(GL_BLEND); ++ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); ++ glColor4f(1.0f, 1.0f, 1.0f, 128 / 255.0f); ++ Render(flags | RENDER_FLAG_BOT , index); ++ } + else + Render(flags, index); + +@@ -769,11 +781,6 @@ void CLinuxRendererGL::FlipPage(int source) + + m_buffers[m_iYV12RenderBuffer].flipindex = ++m_flipindex; + +-#ifdef HAVE_LIBVDPAU +- if((m_renderMethod & RENDER_VDPAU) && m_buffers[m_iYV12RenderBuffer].vdpau) +- m_buffers[m_iYV12RenderBuffer].vdpau->Present(); +-#endif +- + return; + } + +@@ -1100,6 +1107,12 @@ void CLinuxRendererGL::LoadShaders(int field) + m_textureCreate = &CLinuxRendererGL::CreateVDPAUTexture; + m_textureDelete = &CLinuxRendererGL::DeleteVDPAUTexture; + } ++ else if (m_format == RENDER_FMT_VDPAU_420) ++ { ++ m_textureUpload = &CLinuxRendererGL::UploadVDPAUTexture420; ++ m_textureCreate = &CLinuxRendererGL::CreateVDPAUTexture420; ++ m_textureDelete = &CLinuxRendererGL::DeleteVDPAUTexture420; ++ } + else if (m_format == RENDER_FMT_VAAPI) + { + m_textureUpload = &CLinuxRendererGL::UploadVAAPITexture; +@@ -1175,7 +1188,10 @@ void CLinuxRendererGL::Render(DWORD flags, int renderBuffer) + m_currentField = FIELD_FULL; + + // call texture load function ++ m_skipRender = false; + (this->*m_textureUpload)(renderBuffer); ++ if (m_skipRender) ++ return; + + if (m_renderMethod & RENDER_GLSL) + { +@@ -1541,17 +1557,12 @@ void CLinuxRendererGL::RenderFromFBO() + void CLinuxRendererGL::RenderVDPAU(int index, int field) + { + #ifdef HAVE_LIBVDPAU +- YUVPLANE &plane = m_buffers[index].fields[field][0]; +- CVDPAU *vdpau = m_buffers[m_iYV12RenderBuffer].vdpau; +- +- if (!vdpau) +- return; ++ YUVPLANE &plane = m_buffers[index].fields[0][1]; + + glEnable(m_textureTarget); + glActiveTextureARB(GL_TEXTURE0); +- glBindTexture(m_textureTarget, plane.id); + +- vdpau->BindPixmap(); ++ glBindTexture(m_textureTarget, plane.id); + + // Try some clamping or wrapping + glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); +@@ -1609,8 +1620,6 @@ void CLinuxRendererGL::RenderVDPAU(int index, int field) + if (m_pVideoFilterShader) + m_pVideoFilterShader->Disable(); + +- vdpau->ReleasePixmap(); +- + glBindTexture (m_textureTarget, 0); + glDisable(m_textureTarget); + #endif +@@ -2295,12 +2304,14 @@ void CLinuxRendererGL::DeleteVDPAUTexture(int index) + { + #ifdef HAVE_LIBVDPAU + YUVPLANE &plane = m_buffers[index].fields[0][0]; ++ YUVFIELDS &fields = m_buffers[index].fields; + + SAFE_RELEASE(m_buffers[index].vdpau); + + if(plane.id && glIsTexture(plane.id)) + glDeleteTextures(1, &plane.id); + plane.id = 0; ++ fields[0][1].id = 0; + #endif + } + +@@ -2334,11 +2345,152 @@ bool CLinuxRendererGL::CreateVDPAUTexture(int index) + void CLinuxRendererGL::UploadVDPAUTexture(int index) + { + #ifdef HAVE_LIBVDPAU ++ VDPAU::CVdpauRenderPicture *vdpau = m_buffers[index].vdpau; ++ ++ unsigned int flipindex = m_buffers[index].flipindex; ++ YUVFIELDS &fields = m_buffers[index].fields; ++ YUVPLANE &plane = fields[0][0]; ++ ++ if (!vdpau || !vdpau->valid) ++ { ++ m_eventTexturesDone[index]->Set(); ++ m_skipRender = true; ++ return; ++ } ++ ++ fields[0][1].id = vdpau->texture[0]; ++ ++ m_eventTexturesDone[index]->Set(); ++#endif ++} ++ ++void CLinuxRendererGL::DeleteVDPAUTexture420(int index) ++{ ++#ifdef HAVE_LIBVDPAU ++ YUVPLANE &plane = m_buffers[index].fields[0][0]; ++ YUVFIELDS &fields = m_buffers[index].fields; ++ ++ SAFE_RELEASE(m_buffers[index].vdpau); ++ ++ if(plane.id && glIsTexture(plane.id)) ++ glDeleteTextures(1, &plane.id); ++ plane.id = 0; ++ fields[1][0].id = 0; ++ fields[1][1].id = 0; ++ fields[2][0].id = 0; ++ fields[2][1].id = 0; ++ ++#endif ++} ++ ++bool CLinuxRendererGL::CreateVDPAUTexture420(int index) ++{ ++#ifdef HAVE_LIBVDPAU ++ YV12Image &im = m_buffers[index].image; ++ YUVFIELDS &fields = m_buffers[index].fields; ++ YUVPLANE &plane = fields[0][0]; ++ GLuint *pbo = m_buffers[index].pbo; ++ ++ DeleteVDPAUTexture420(index); ++ ++ memset(&im , 0, sizeof(im)); ++ memset(&fields, 0, sizeof(fields)); ++ ++ im.cshift_x = 1; ++ im.cshift_y = 1; ++ ++ im.plane[0] = NULL; ++ im.plane[1] = NULL; ++ im.plane[2] = NULL; ++ ++ for(int p = 0;p<3;p++) ++ { ++ pbo[p] = None; ++ } ++ ++ glEnable(m_textureTarget); ++ glGenTextures(1, &plane.id); ++ glDisable(m_textureTarget); ++ + m_eventTexturesDone[index]->Set(); +- glPixelStorei(GL_UNPACK_ALIGNMENT,1); //what's this for? + #endif ++ return true; + } + ++void CLinuxRendererGL::UploadVDPAUTexture420(int index) ++{ ++#ifdef HAVE_LIBVDPAU ++ VDPAU::CVdpauRenderPicture *vdpau = m_buffers[index].vdpau; ++ YV12Image &im = m_buffers[index].image; ++ ++ unsigned int flipindex = m_buffers[index].flipindex; ++ YUVFIELDS &fields = m_buffers[index].fields; ++ YUVPLANE &plane = fields[0][0]; ++ ++ if (!vdpau || !vdpau->valid) ++ { ++ m_eventTexturesDone[index]->Set(); ++ m_skipRender = true; ++ return; ++ } ++ ++ im.height = vdpau->texHeight; ++ im.width = vdpau->texWidth; ++ ++ // YUV ++ for (int f = FIELD_FULL; f<=FIELD_BOT ; f++) ++ { ++ int fieldshift = (f==FIELD_FULL) ? 0 : 1; ++ YUVPLANES &planes = fields[f]; ++ ++ planes[0].texwidth = im.width; ++ planes[0].texheight = im.height >> fieldshift; ++ ++ planes[1].texwidth = planes[0].texwidth >> im.cshift_x; ++ planes[1].texheight = planes[0].texheight >> im.cshift_y; ++ planes[2].texwidth = planes[1].texwidth; ++ planes[2].texheight = planes[1].texheight; ++ ++ for (int p = 0; p < 3; p++) ++ { ++ planes[p].pixpertex_x = 1; ++ planes[p].pixpertex_y = 1; ++ } ++ } ++ // crop ++// m_sourceRect.x1 += vdpau->crop.x1; ++// m_sourceRect.x2 -= vdpau->crop.x2; ++// m_sourceRect.y1 += vdpau->crop.y1; ++// m_sourceRect.y2 -= vdpau->crop.y2; ++ ++ // set textures ++ fields[1][0].id = vdpau->texture[0]; ++ fields[1][1].id = vdpau->texture[2]; ++ fields[2][0].id = vdpau->texture[1]; ++ fields[2][1].id = vdpau->texture[3]; ++ ++ glEnable(m_textureTarget); ++ for (int f = 1; f < 3; f++) ++ { ++ for (int p=0;p<2;p++) ++ { ++ glBindTexture(m_textureTarget,fields[f][p].id); ++ glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); ++ glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); ++ glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); ++ glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); ++ ++ glBindTexture(m_textureTarget,0); ++ VerifyGLState(); ++ } ++ fields[f][2].id = fields[f][1].id; ++ } ++ CalculateTextureSourceRects(index, 3); ++ glDisable(m_textureTarget); ++ ++ m_eventTexturesDone[index]->Set(); ++#endif ++} + + void CLinuxRendererGL::DeleteVAAPITexture(int index) + { +@@ -3276,12 +3428,13 @@ bool CLinuxRendererGL::Supports(EINTERLACEMETHOD method) + if(method == VS_INTERLACEMETHOD_AUTO) + return true; + +- if(m_renderMethod & RENDER_VDPAU) ++ if(m_renderMethod & RENDER_VDPAU || ++ m_format == RENDER_FMT_VDPAU_420) + { + #ifdef HAVE_LIBVDPAU +- CVDPAU *vdpau = m_buffers[m_iYV12RenderBuffer].vdpau; +- if(vdpau) +- return vdpau->Supports(method); ++ VDPAU::CVdpauRenderPicture *vdpauPic = m_buffers[m_iYV12RenderBuffer].vdpau; ++ if(vdpauPic && vdpauPic->vdpau) ++ return vdpauPic->vdpau->Supports(method); + #endif + return false; + } +@@ -3367,14 +3520,7 @@ EINTERLACEMETHOD CLinuxRendererGL::AutoInterlaceMethod() + return VS_INTERLACEMETHOD_NONE; + + if(m_renderMethod & RENDER_VDPAU) +- { +-#ifdef HAVE_LIBVDPAU +- CVDPAU *vdpau = m_buffers[m_iYV12RenderBuffer].vdpau; +- if(vdpau) +- return vdpau->AutoInterlaceMethod(); +-#endif + return VS_INTERLACEMETHOD_NONE; +- } + + if(Supports(VS_INTERLACEMETHOD_RENDER_BOB)) + return VS_INTERLACEMETHOD_RENDER_BOB; +@@ -3417,11 +3563,12 @@ void CLinuxRendererGL::UnBindPbo(YUVBUFFER& buff) + } + + #ifdef HAVE_LIBVDPAU +-void CLinuxRendererGL::AddProcessor(CVDPAU* vdpau, int index) ++void CLinuxRendererGL::AddProcessor(VDPAU::CVdpauRenderPicture *vdpau, int index) + { + YUVBUFFER &buf = m_buffers[index]; ++ VDPAU::CVdpauRenderPicture *pic = vdpau->Acquire(); + SAFE_RELEASE(buf.vdpau); +- buf.vdpau = (CVDPAU*)vdpau->Acquire(); ++ buf.vdpau = pic; + } + #endif + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.h b/xbmc/cores/VideoRenderers/LinuxRendererGL.h +index 9f55fcb..3218cd5 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.h ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.h +@@ -38,15 +38,14 @@ + + class CRenderCapture; + +-class CVDPAU; + class CBaseTexture; + namespace Shaders { class BaseYUV2RGBShader; } + namespace Shaders { class BaseVideoFilterShader; } + namespace VAAPI { struct CHolder; } ++namespace VDPAU { class CVdpauRenderPicture; } + + #define NUM_BUFFERS 10 + +- + #undef ALIGN + #define ALIGN(value, alignment) (((value)+((alignment)-1))&~((alignment)-1)) + #define CLAMP(a, min, max) ((a) > (max) ? (max) : ( (a) < (min) ? (min) : a )) +@@ -144,7 +143,7 @@ class CLinuxRendererGL : public CBaseRenderer + virtual unsigned int GetProcessorSize() { return m_NumYV12Buffers; } + + #ifdef HAVE_LIBVDPAU +- virtual void AddProcessor(CVDPAU* vdpau, int index); ++ virtual void AddProcessor(VDPAU::CVdpauRenderPicture* vdpau, int index); + #endif + #ifdef HAVE_LIBVA + virtual void AddProcessor(VAAPI::CHolder& holder, int index); +@@ -195,6 +194,10 @@ class CLinuxRendererGL : public CBaseRenderer + void DeleteVDPAUTexture(int index); + bool CreateVDPAUTexture(int index); + ++ void UploadVDPAUTexture420(int index); ++ void DeleteVDPAUTexture420(int index); ++ bool CreateVDPAUTexture420(int index); ++ + void UploadVAAPITexture(int index); + void DeleteVAAPITexture(int index); + bool CreateVAAPITexture(int index); +@@ -221,6 +224,7 @@ class CLinuxRendererGL : public CBaseRenderer + void RenderSinglePass(int renderBuffer, int field); // single pass glsl renderer + void RenderSoftware(int renderBuffer, int field); // single pass s/w yuv2rgb renderer + void RenderVDPAU(int renderBuffer, int field); // render using vdpau hardware ++ void RenderVDPAUYV12(int renderBuffer, int field); // render using vdpau hardware + void RenderVAAPI(int renderBuffer, int field); // render using vdpau hardware + + struct +@@ -281,7 +285,7 @@ class CLinuxRendererGL : public CBaseRenderer + GLuint pbo[MAX_PLANES]; + + #ifdef HAVE_LIBVDPAU +- CVDPAU* vdpau; ++ VDPAU::CVdpauRenderPicture *vdpau; + #endif + #ifdef HAVE_LIBVA + VAAPI::CHolder& vaapi; +@@ -327,6 +331,7 @@ class CLinuxRendererGL : public CBaseRenderer + bool m_nonLinStretch; + bool m_nonLinStretchGui; + float m_pixelRatio; ++ bool m_skipRender; + }; + + +diff --git a/xbmc/cores/VideoRenderers/RenderFormats.h b/xbmc/cores/VideoRenderers/RenderFormats.h +index 09f8f5d..0262c60 100644 +--- a/xbmc/cores/VideoRenderers/RenderFormats.h ++++ b/xbmc/cores/VideoRenderers/RenderFormats.h +@@ -26,6 +26,7 @@ enum ERenderFormat { + RENDER_FMT_YUV420P10, + RENDER_FMT_YUV420P16, + RENDER_FMT_VDPAU, ++ RENDER_FMT_VDPAU_420, + RENDER_FMT_NV12, + RENDER_FMT_UYVY422, + RENDER_FMT_YUYV422, +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index f19797c..a521680 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -250,8 +250,9 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi + + // check if decoder supports buffering + m_bCodecSupportsBuffering = false; +-// if (format == RENDER_FMT_VDPAU) +-// m_bCodecSupportsBuffering = true; ++ if (format == RENDER_FMT_VDPAU || ++ format == RENDER_FMT_VDPAU_420) ++ m_bCodecSupportsBuffering = true; + + bool result = m_pRenderer->Configure(width, height, d_width, d_height, fps, flags, format, extended_format, orientation); + if(result) +@@ -856,7 +857,8 @@ int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic) + CDVDCodecUtils::CopyDXVA2Picture(&image, &pic); + } + #ifdef HAVE_LIBVDPAU +- else if(pic.format == RENDER_FMT_VDPAU) ++ else if(pic.format == RENDER_FMT_VDPAU ++ || pic.format == RENDER_FMT_VDPAU_420) + m_pRenderer->AddProcessor(pic.vdpau, index); + #endif + #ifdef HAVE_LIBOPENMAX +diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h +index 9342586..6746957 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.h ++++ b/xbmc/cores/VideoRenderers/RenderManager.h +@@ -35,7 +35,7 @@ + + namespace DXVA { class CProcessor; } + namespace VAAPI { class CSurfaceHolder; } +-class CVDPAU; ++namespace VDPAU { class CVdpauRenderPicture; } + struct DVDVideoPicture; + + #define ERRORBUFFSIZE 30 +diff --git a/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp b/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp +index 58f26b0..50606eb 100644 +--- a/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp ++++ b/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp +@@ -201,6 +201,8 @@ static void CalculateYUVMatrixGL(GLfloat res[4][4] + m_defines += "#define XBMC_YUY2\n"; + else if (m_format == RENDER_FMT_UYVY422) + m_defines += "#define XBMC_UYVY\n"; ++ else if (RENDER_FMT_VDPAU_420) ++ m_defines += "#define XBMC_VDPAU_NV12\n"; + else + CLog::Log(LOGERROR, "GL: BaseYUV2RGBGLSLShader - unsupported format %d", m_format); + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h +index 5001aac..98d8f89 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h +@@ -34,7 +34,7 @@ + + namespace DXVA { class CSurfaceContext; } + namespace VAAPI { struct CHolder; } +-class CVDPAU; ++namespace VDPAU { class CVdpauRenderPicture; } + class COpenMax; + class COpenMaxVideo; + struct OpenMaxVideoBuffer; +@@ -55,7 +55,7 @@ struct DVDVideoPicture + DXVA::CSurfaceContext* context; + }; + struct { +- CVDPAU* vdpau; ++ VDPAU::CVdpauRenderPicture* vdpau; + }; + struct { + VAAPI::CHolder* vaapi; +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +index dae3b8e..a6e42e5 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +@@ -71,14 +71,14 @@ enum PixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx + while(*cur != PIX_FMT_NONE) + { + #ifdef HAVE_LIBVDPAU +- if(CVDPAU::IsVDPAUFormat(*cur) && g_guiSettings.GetBool("videoplayer.usevdpau")) ++ if(VDPAU::CDecoder::IsVDPAUFormat(*cur) && g_guiSettings.GetBool("videoplayer.usevdpau")) + { + if(ctx->GetHardware()) + return *cur; + + CLog::Log(LOGNOTICE,"CDVDVideoCodecFFmpeg::GetFormat - Creating VDPAU(%ix%i)", avctx->width, avctx->height); +- CVDPAU* vdp = new CVDPAU(); +- if(vdp->Open(avctx, *cur)) ++ VDPAU::CDecoder* vdp = new VDPAU::CDecoder(); ++ if(vdp->Open(avctx, *cur, ctx->m_uSurfacesCount)) + { + ctx->SetHardware(vdp); + return *cur; +@@ -205,14 +205,27 @@ bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options + continue; + + CLog::Log(LOGNOTICE,"CDVDVideoCodecFFmpeg::Open() Creating VDPAU(%ix%i, %d)",hints.width, hints.height, hints.codec); +- CVDPAU* vdp = new CVDPAU(); ++ ++ VDPAU::CDecoder* vdp = new VDPAU::CDecoder(); + m_pCodecContext = m_dllAvCodec.avcodec_alloc_context3(pCodec); + m_pCodecContext->codec_id = hints.codec; + m_pCodecContext->width = hints.width; + m_pCodecContext->height = hints.height; + m_pCodecContext->coded_width = hints.width; + m_pCodecContext->coded_height = hints.height; +- if(vdp->Open(m_pCodecContext, pCodec->pix_fmts ? pCodec->pix_fmts[0] : PIX_FMT_NONE)) ++ ++ // check number of surfaces used in renderer ++ unsigned int surfaces = 0; ++ for(std::vector::iterator it = options.m_keys.begin(); it != options.m_keys.end(); it++) ++ { ++ if (it->m_name == "surfaces") ++ { ++ surfaces = std::atoi(it->m_value.c_str()); ++ break; ++ } ++ } ++ ++ if(vdp->Open(m_pCodecContext, pCodec->pix_fmts ? pCodec->pix_fmts[0] : PIX_FMT_NONE, surfaces)) + { + m_pHardware = vdp; + m_pCodecContext->codec_id = CODEC_ID_NONE; // ffmpeg will complain if this has been set +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h +index 52e1113..bf4367c 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h +@@ -28,7 +28,6 @@ + #include "DllSwScale.h" + #include "DllAvFilter.h" + +-class CVDPAU; + class CCriticalSection; + + class CDVDVideoCodecFFmpeg : public CDVDVideoCodec +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +index f70a4f9..235f565 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +@@ -32,11 +32,16 @@ + #include "settings/AdvancedSettings.h" + #include "Application.h" + #include "utils/MathUtils.h" ++#include "utils/TimeUtils.h" + #include "DVDCodecs/DVDCodecUtils.h" ++#include "cores/VideoRenderers/RenderFlags.h" ++ ++using namespace VDPAU; ++#define NUM_RENDER_PICS 9 + + #define ARSIZE(x) (sizeof(x) / sizeof((x)[0])) + +-CVDPAU::Desc decoder_profiles[] = { ++CDecoder::Desc decoder_profiles[] = { + {"MPEG1", VDP_DECODER_PROFILE_MPEG1}, + {"MPEG2_SIMPLE", VDP_DECODER_PROFILE_MPEG2_SIMPLE}, + {"MPEG2_MAIN", VDP_DECODER_PROFILE_MPEG2_MAIN}, +@@ -50,14 +55,16 @@ + {"MPEG4_PART2_ASP", VDP_DECODER_PROFILE_MPEG4_PART2_ASP}, + #endif + }; +-const size_t decoder_profile_count = sizeof(decoder_profiles)/sizeof(CVDPAU::Desc); ++const size_t decoder_profile_count = sizeof(decoder_profiles)/sizeof(CDecoder::Desc); + +-static float studioCSC[3][4] = +-{ +- { 1.0f, 0.0f, 1.57480000f,-0.78740000f}, +- { 1.0f,-0.18737736f,-0.46813736f, 0.32775736f}, +- { 1.0f, 1.85556000f, 0.0f,-0.92780000f} +-}; ++//static float studioCSC[3][4] = ++//{ ++// { 1.0f, 0.0f, 1.57480000f,-0.78740000f}, ++// { 1.0f,-0.18737736f,-0.46813736f, 0.32775736f}, ++// { 1.0f, 1.85556000f, 0.0f,-0.92780000f} ++//}; ++static float studioCSCKCoeffs601[3] = {0.299, 0.587, 0.114}; //BT601 {Kr, Kg, Kb} ++static float studioCSCKCoeffs709[3] = {0.2126, 0.7152, 0.0722}; //BT709 {Kr, Kg, Kb} + + static struct SInterlaceMapping + { +@@ -68,88 +75,30 @@ + , {VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF , VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL} + , {VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL , VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL} + , {VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF, VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL} +-, {VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE , VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE} ++, {VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE , VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE} + , {VS_INTERLACEMETHOD_NONE , (VdpVideoMixerFeature)-1} + }; + + //since libvdpau 0.4, vdp_device_create_x11() installs a callback on the Display*, + //if we unload libvdpau with dlclose(), we segfault on XCloseDisplay, + //so we just keep a static handle to libvdpau around +-void* CVDPAU::dl_handle; ++void* CDecoder::dl_handle; ++ ++//----------------------------------------------------------------------------- ++// CVDPAU ++//----------------------------------------------------------------------------- + +-CVDPAU::CVDPAU() ++CDecoder::CDecoder() : m_vdpauOutput(&m_inMsgEvent) + { +- glXBindTexImageEXT = NULL; +- glXReleaseTexImageEXT = NULL; +- vdp_device = VDP_INVALID_HANDLE; +- surfaceNum = presentSurfaceNum = 0; +- picAge.b_age = picAge.ip_age[0] = picAge.ip_age[1] = 256*256*256*64; +- vdpauConfigured = false; +- m_DisplayState = VDPAU_OPEN; +- m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME; +- m_mixerstep = 0; ++ m_vdpauConfig.vdpDevice = VDP_INVALID_HANDLE; ++ m_vdpauConfig.videoSurfaces = &m_videoSurfaces; ++ m_vdpauConfig.videoSurfaceSec = &m_videoSurfaceSec; + +- m_glPixmap = 0; +- m_Pixmap = 0; +- if (!glXBindTexImageEXT) +- glXBindTexImageEXT = (PFNGLXBINDTEXIMAGEEXTPROC)glXGetProcAddress((GLubyte *) "glXBindTexImageEXT"); +- if (!glXReleaseTexImageEXT) +- glXReleaseTexImageEXT = (PFNGLXRELEASETEXIMAGEEXTPROC)glXGetProcAddress((GLubyte *) "glXReleaseTexImageEXT"); ++ m_vdpauConfigured = false; ++ m_DisplayState = VDPAU_OPEN; ++} + +- totalAvailableOutputSurfaces = 0; +- outputSurface = presentSurface = VDP_INVALID_HANDLE; +- vdp_flip_target = VDP_INVALID_HANDLE; +- vdp_flip_queue = VDP_INVALID_HANDLE; +- vid_width = vid_height = OutWidth = OutHeight = 0; +- surface_width = surface_height = 0; +- +- memset(&decoder, 0, sizeof(decoder)); +- memset(&outRect, 0, sizeof(outRect)); +- memset(&outRectVid, 0, sizeof(outRectVid)); +- +- m_Display = NULL; +- +- tmpBrightness = 0; +- tmpContrast = 0; +- tmpDeintMode = 0; +- tmpDeintGUI = 0; +- tmpDeint = 0; +- max_references = 0; +- +- for (int i = 0; i < NUM_OUTPUT_SURFACES; i++) +- outputSurfaces[i] = VDP_INVALID_HANDLE; +- +- videoMixer = VDP_INVALID_HANDLE; +- m_BlackBar = NULL; +- +- memset(m_features, 0, sizeof(m_features)); +- m_feature_count = 0; +- m_vdpauOutputMethod = OUTPUT_NONE; +- +- upScale = g_advancedSettings.m_videoVDPAUScaling; +- +- vdp_video_mixer_set_attribute_values = NULL; +- vdp_generate_csc_matrix = NULL; +- vdp_presentation_queue_target_destroy = NULL; +- vdp_presentation_queue_create = NULL; +- vdp_presentation_queue_destroy = NULL; +- vdp_presentation_queue_display = NULL; +- vdp_presentation_queue_block_until_surface_idle = NULL; +- vdp_presentation_queue_target_create_x11 = NULL; +- vdp_presentation_queue_query_surface_status = NULL; +- vdp_presentation_queue_get_time = NULL; +- vdp_get_error_string = NULL; +- vdp_decoder_create = NULL; +- vdp_decoder_destroy = NULL; +- vdp_decoder_render = NULL; +- vdp_decoder_query_caps = NULL; +- vdp_preemption_callback_register = NULL; +- dl_vdp_device_create_x11 = NULL; +- dl_vdp_get_proc_address = NULL; +- dl_vdp_preemption_callback_register = NULL; +-} +- +-bool CVDPAU::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int surfaces) ++bool CDecoder::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int surfaces) + { + if(avctx->coded_width == 0 + || avctx->coded_height == 0) +@@ -157,6 +106,8 @@ bool CVDPAU::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int su + CLog::Log(LOGWARNING,"(VDPAU) no width/height available, can't init"); + return false; + } ++ m_vdpauConfig.numRenderBuffers = surfaces; ++ m_decoderThread = CThread::GetCurrentThreadId(); + + if (!dl_handle) + { +@@ -168,8 +119,6 @@ bool CVDPAU::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int su + error = "dlerror() returned NULL"; + + CLog::Log(LOGNOTICE,"(VDPAU) Unable to get handle to libvdpau: %s", error); +- //g_application.m_guiDialogKaiToast.QueueNotification(CGUIDialogKaiToast::Error, "VDPAU", error, 10000); +- + return false; + } + } +@@ -178,8 +127,9 @@ bool CVDPAU::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int su + return false; + + InitVDPAUProcs(); ++ m_presentPicture = 0; + +- if (vdp_device != VDP_INVALID_HANDLE) ++ if (m_vdpauConfig.vdpDevice != VDP_INVALID_HANDLE) + { + SpewHardwareAvailable(); + +@@ -197,25 +147,23 @@ bool CVDPAU::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int su + + /* attempt to create a decoder with this width/height, some sizes are not supported by hw */ + VdpStatus vdp_st; +- vdp_st = vdp_decoder_create(vdp_device, profile, avctx->coded_width, avctx->coded_height, 5, &decoder); ++ vdp_st = m_vdpauConfig.vdpProcs.vdp_decoder_create(m_vdpauConfig.vdpDevice, profile, avctx->coded_width, avctx->coded_height, 5, &m_vdpauConfig.vdpDecoder); + + if(vdp_st != VDP_STATUS_OK) + { +- CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) checking for decoder support\n", vdp_get_error_string(vdp_st), vdp_st); ++ CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) checking for decoder support\n", m_vdpauConfig.vdpProcs.vdp_get_error_string(vdp_st), vdp_st); + FiniVDPAUProcs(); + return false; + } + +- vdp_decoder_destroy(decoder); ++ m_vdpauConfig.vdpProcs.vdp_decoder_destroy(m_vdpauConfig.vdpDecoder); + CheckStatus(vdp_st, __LINE__); + } + +- InitCSCMatrix(avctx->coded_height); +- + /* finally setup ffmpeg */ +- avctx->get_buffer = CVDPAU::FFGetBuffer; +- avctx->release_buffer = CVDPAU::FFReleaseBuffer; +- avctx->draw_horiz_band = CVDPAU::FFDrawSlice; ++ avctx->get_buffer = CDecoder::FFGetBuffer; ++ avctx->release_buffer = CDecoder::FFReleaseBuffer; ++ avctx->draw_horiz_band = CDecoder::FFDrawSlice; + avctx->slice_flags=SLICE_FLAG_CODED_ORDER|SLICE_FLAG_ALLOW_FIELD; + + g_Windowing.Register(this); +@@ -224,17 +172,20 @@ bool CVDPAU::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int su + return false; + } + +-CVDPAU::~CVDPAU() ++CDecoder::~CDecoder() + { + Close(); + } + +-void CVDPAU::Close() ++void CDecoder::Close() + { + CLog::Log(LOGNOTICE, " (VDPAU) %s", __FUNCTION__); + ++ CSingleLock lock(m_DecoderSection); ++ + FiniVDPAUOutput(); + FiniVDPAUProcs(); ++ m_vdpauOutput.Dispose(); + + while (!m_videoSurfaces.empty()) + { +@@ -250,188 +201,111 @@ void CVDPAU::Close() + m_dllAvUtil.Unload(); + } + +-bool CVDPAU::MakePixmapGL() ++long CDecoder::Release() + { +- int num=0; +- int fbConfigIndex = 0; +- +- int doubleVisAttributes[] = { +- GLX_RENDER_TYPE, GLX_RGBA_BIT, +- GLX_RED_SIZE, 8, +- GLX_GREEN_SIZE, 8, +- GLX_BLUE_SIZE, 8, +- GLX_ALPHA_SIZE, 8, +- GLX_DEPTH_SIZE, 8, +- GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, +- GLX_BIND_TO_TEXTURE_RGBA_EXT, True, +- GLX_DOUBLEBUFFER, True, +- GLX_Y_INVERTED_EXT, True, +- GLX_X_RENDERABLE, True, +- None +- }; +- +- int pixmapAttribs[] = { +- GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, +- GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT, +- None +- }; +- +- GLXFBConfig *fbConfigs; +- fbConfigs = glXChooseFBConfig(m_Display, DefaultScreen(m_Display), doubleVisAttributes, &num); +- if (fbConfigs==NULL) ++ // check if we should do some pre-cleanup here ++ // a second decoder might need resources ++ if (m_vdpauConfigured == true) + { +- CLog::Log(LOGERROR, "GLX Error: MakePixmap: No compatible framebuffers found"); +- return false; +- } +- CLog::Log(LOGDEBUG, "Found %d fbconfigs.", num); +- fbConfigIndex = 0; +- CLog::Log(LOGDEBUG, "Using fbconfig index %d.", fbConfigIndex); ++ CSingleLock lock(m_DecoderSection); ++ CLog::Log(LOGNOTICE,"CVDPAU::Release pre-cleanup"); + +- m_glPixmap = glXCreatePixmap(m_Display, fbConfigs[fbConfigIndex], m_Pixmap, pixmapAttribs); ++ Message *reply; ++ if (m_vdpauOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::PRECLEANUP, ++ &reply, ++ 2000)) ++ { ++ bool success = reply->signal == COutputControlProtocol::ACC ? true : false; ++ reply->Release(); ++ if (!success) ++ { ++ CLog::Log(LOGERROR, "VDPAU::%s - pre-cleanup returned error", __FUNCTION__); ++ m_DisplayState = VDPAU_ERROR; ++ } ++ } ++ else ++ { ++ CLog::Log(LOGERROR, "VDPAU::%s - pre-cleanup timed out", __FUNCTION__); ++ m_DisplayState = VDPAU_ERROR; ++ } + +- if (!m_glPixmap) +- { +- CLog::Log(LOGINFO, "GLX Error: Could not create Pixmap"); +- XFree(fbConfigs); +- return false; ++ for(unsigned int i = 0; i < m_videoSurfaces.size(); ++i) ++ { ++ vdpau_render_state *render = m_videoSurfaces[i]; ++ if (render->surface != VDP_INVALID_HANDLE && !(render->state & FF_VDPAU_STATE_USED_FOR_RENDER)) ++ { ++ m_vdpauConfig.vdpProcs.vdp_video_surface_destroy(render->surface); ++ render->surface = VDP_INVALID_HANDLE; ++ } ++ } + } +- XFree(fbConfigs); ++ IHardwareDecoder::Release(); ++} + +- return true; ++long CDecoder::ReleasePicReference() ++{ ++ return IHardwareDecoder::Release(); + } + +-bool CVDPAU::MakePixmap(int width, int height) ++void CDecoder::SetWidthHeight(int width, int height) + { ++ m_vdpauConfig.upscale = g_advancedSettings.m_videoVDPAUScaling; ++ + //pick the smallest dimensions, so we downscale with vdpau and upscale with opengl when appropriate + //this requires the least amount of gpu memory bandwidth +- if (g_graphicsContext.GetWidth() < width || g_graphicsContext.GetHeight() < height || upScale) ++ if (g_graphicsContext.GetWidth() < width || g_graphicsContext.GetHeight() < height || m_vdpauConfig.upscale >= 0) + { + //scale width to desktop size if the aspect ratio is the same or bigger than the desktop + if ((double)height * g_graphicsContext.GetWidth() / width <= (double)g_graphicsContext.GetHeight()) + { +- OutWidth = g_graphicsContext.GetWidth(); +- OutHeight = MathUtils::round_int((double)height * g_graphicsContext.GetWidth() / width); ++ m_vdpauConfig.outWidth = g_graphicsContext.GetWidth(); ++ m_vdpauConfig.outHeight = MathUtils::round_int((double)height * g_graphicsContext.GetWidth() / width); + } + else //scale height to the desktop size if the aspect ratio is smaller than the desktop + { +- OutHeight = g_graphicsContext.GetHeight(); +- OutWidth = MathUtils::round_int((double)width * g_graphicsContext.GetHeight() / height); ++ m_vdpauConfig.outHeight = g_graphicsContext.GetHeight(); ++ m_vdpauConfig.outWidth = MathUtils::round_int((double)width * g_graphicsContext.GetHeight() / height); + } + } + else + { //let opengl scale +- OutWidth = width; +- OutHeight = height; +- } +- +- CLog::Log(LOGNOTICE,"Creating %ix%i pixmap", OutWidth, OutHeight); +- +- // Get our window attribs. +- XWindowAttributes wndattribs; +- XGetWindowAttributes(m_Display, DefaultRootWindow(m_Display), &wndattribs); // returns a status but I don't know what success is +- +- m_Pixmap = XCreatePixmap(m_Display, +- DefaultRootWindow(m_Display), +- OutWidth, +- OutHeight, +- wndattribs.depth); +- if (!m_Pixmap) +- { +- CLog::Log(LOGERROR, "GLX Error: MakePixmap: Unable to create XPixmap"); +- return false; +- } +- +- XGCValues values = {}; +- GC xgc; +- values.foreground = BlackPixel (m_Display, DefaultScreen (m_Display)); +- xgc = XCreateGC(m_Display, m_Pixmap, GCForeground, &values); +- XFillRectangle(m_Display, m_Pixmap, xgc, 0, 0, OutWidth, OutHeight); +- XFreeGC(m_Display, xgc); +- +- if(!MakePixmapGL()) +- return false; +- +- return true; +-} +- +-void CVDPAU::BindPixmap() +-{ +- CSharedLock lock(m_DecoderSection); +- +- { CSharedLock dLock(m_DisplaySection); +- if (m_DisplayState != VDPAU_OPEN) +- return; +- } +- +- if (m_glPixmap) +- { +- if(presentSurface != VDP_INVALID_HANDLE) +- { +- VdpPresentationQueueStatus status; +- VdpTime time; +- VdpStatus vdp_st; +- vdp_st = vdp_presentation_queue_query_surface_status( +- vdp_flip_queue, presentSurface, &status, &time); +- CheckStatus(vdp_st, __LINE__); +- while(status != VDP_PRESENTATION_QUEUE_STATUS_VISIBLE && vdp_st == VDP_STATUS_OK) +- { +- Sleep(1); +- vdp_st = vdp_presentation_queue_query_surface_status( +- vdp_flip_queue, presentSurface, &status, &time); +- CheckStatus(vdp_st, __LINE__); +- } +- } +- +- glXBindTexImageEXT(m_Display, m_glPixmap, GLX_FRONT_LEFT_EXT, NULL); +- } +- else CLog::Log(LOGERROR,"(VDPAU) BindPixmap called without valid pixmap"); +-} +- +-void CVDPAU::ReleasePixmap() +-{ +- CSharedLock lock(m_DecoderSection); +- +- { CSharedLock dLock(m_DisplaySection); +- if (m_DisplayState != VDPAU_OPEN) +- return; +- } +- +- if (m_glPixmap) +- { +- glXReleaseTexImageEXT(m_Display, m_glPixmap, GLX_FRONT_LEFT_EXT); ++ m_vdpauConfig.outWidth = width; ++ m_vdpauConfig.outHeight = height; + } +- else CLog::Log(LOGERROR,"(VDPAU) ReleasePixmap called without valid pixmap"); ++ CLog::Log(LOGDEBUG, "CVDPAU::SetWidthHeight Setting OutWidth: %i OutHeight: %i", m_vdpauConfig.outWidth, m_vdpauConfig.outHeight); + } + +-void CVDPAU::OnLostDevice() ++void CDecoder::OnLostDevice() + { + CLog::Log(LOGNOTICE,"CVDPAU::OnLostDevice event"); + +- CExclusiveLock lock(m_DecoderSection); ++ CSingleLock lock(m_DecoderSection); + FiniVDPAUOutput(); + FiniVDPAUProcs(); + + m_DisplayState = VDPAU_LOST; ++ lock.Leave(); + m_DisplayEvent.Reset(); + } + +-void CVDPAU::OnResetDevice() ++void CDecoder::OnResetDevice() + { + CLog::Log(LOGNOTICE,"CVDPAU::OnResetDevice event"); + +- CExclusiveLock lock(m_DisplaySection); ++ CSingleLock lock(m_DecoderSection); + if (m_DisplayState == VDPAU_LOST) + { + m_DisplayState = VDPAU_RESET; ++ lock.Leave(); + m_DisplayEvent.Set(); + } + } + +-int CVDPAU::Check(AVCodecContext* avctx) ++int CDecoder::Check(AVCodecContext* avctx) + { + EDisplayState state; + +- { CSharedLock lock(m_DisplaySection); ++ { CSingleLock lock(m_DecoderSection); + state = m_DisplayState; + } + +@@ -445,16 +319,13 @@ int CVDPAU::Check(AVCodecContext* avctx) + } + else + { +- CSharedLock lock(m_DisplaySection); ++ CSingleLock lock(m_DecoderSection); + state = m_DisplayState; + } + } + if (state == VDPAU_RESET || state == VDPAU_ERROR) + { +- CLog::Log(LOGNOTICE,"Attempting recovery"); +- +- CSingleLock gLock(g_graphicsContext); +- CExclusiveLock lock(m_DecoderSection); ++ CSingleLock lock(m_DecoderSection); + + FiniVDPAUOutput(); + FiniVDPAUProcs(); +@@ -469,7 +340,7 @@ int CVDPAU::Check(AVCodecContext* avctx) + return 0; + } + +-bool CVDPAU::IsVDPAUFormat(PixelFormat format) ++bool CDecoder::IsVDPAUFormat(PixelFormat format) + { + if ((format >= PIX_FMT_VDPAU_H264) && (format <= PIX_FMT_VDPAU_VC1)) return true; + #if (defined PIX_FMT_VDPAU_MPEG4_IN_AVUTIL) +@@ -478,91 +349,28 @@ bool CVDPAU::IsVDPAUFormat(PixelFormat format) + else return false; + } + +-void CVDPAU::CheckFeatures() +-{ +- if (videoMixer == VDP_INVALID_HANDLE) +- { +- CLog::Log(LOGNOTICE, " (VDPAU) Creating the video mixer"); +- // Creation of VideoMixer. +- VdpVideoMixerParameter parameters[] = { +- VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH, +- VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT, +- VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE +- }; +- +- void const * parameter_values[] = { +- &surface_width, +- &surface_height, +- &vdp_chroma_type +- }; +- +- tmpBrightness = 0; +- tmpContrast = 0; +- tmpNoiseReduction = 0; +- tmpSharpness = 0; +- +- VdpStatus vdp_st = VDP_STATUS_ERROR; +- vdp_st = vdp_video_mixer_create(vdp_device, +- m_feature_count, +- m_features, +- ARSIZE(parameters), +- parameters, +- parameter_values, +- &videoMixer); +- CheckStatus(vdp_st, __LINE__); +- +- SetHWUpscaling(); +- } +- +- if (tmpBrightness != g_settings.m_currentVideoSettings.m_Brightness || +- tmpContrast != g_settings.m_currentVideoSettings.m_Contrast) +- { +- SetColor(); +- tmpBrightness = g_settings.m_currentVideoSettings.m_Brightness; +- tmpContrast = g_settings.m_currentVideoSettings.m_Contrast; +- } +- if (tmpNoiseReduction != g_settings.m_currentVideoSettings.m_NoiseReduction) +- { +- tmpNoiseReduction = g_settings.m_currentVideoSettings.m_NoiseReduction; +- SetNoiseReduction(); +- } +- if (tmpSharpness != g_settings.m_currentVideoSettings.m_Sharpness) +- { +- tmpSharpness = g_settings.m_currentVideoSettings.m_Sharpness; +- SetSharpness(); +- } +- if ( tmpDeintMode != g_settings.m_currentVideoSettings.m_DeinterlaceMode || +- tmpDeintGUI != g_settings.m_currentVideoSettings.m_InterlaceMethod || +- (tmpDeintGUI == VS_INTERLACEMETHOD_AUTO && tmpDeint != AutoInterlaceMethod())) +- { +- tmpDeintMode = g_settings.m_currentVideoSettings.m_DeinterlaceMode; +- tmpDeintGUI = g_settings.m_currentVideoSettings.m_InterlaceMethod; +- if (tmpDeintGUI == VS_INTERLACEMETHOD_AUTO) +- tmpDeint = AutoInterlaceMethod(); +- else +- tmpDeint = tmpDeintGUI; +- +- SetDeinterlacing(); +- } +-} +- +-bool CVDPAU::Supports(VdpVideoMixerFeature feature) ++bool CDecoder::Supports(VdpVideoMixerFeature feature) + { +- for(int i = 0; i < m_feature_count; i++) ++ for(int i = 0; i < m_vdpauConfig.featureCount; i++) + { +- if(m_features[i] == feature) ++ if(m_vdpauConfig.vdpFeatures[i] == feature) + return true; + } + return false; + } + +-bool CVDPAU::Supports(EINTERLACEMETHOD method) ++bool CDecoder::Supports(EINTERLACEMETHOD method) + { + if(method == VS_INTERLACEMETHOD_VDPAU_BOB +- || method == VS_INTERLACEMETHOD_AUTO +- || method == VS_INTERLACEMETHOD_AUTO_ION) ++ || method == VS_INTERLACEMETHOD_AUTO) + return true; + ++ if (g_guiSettings.GetBool("videoplayer.usevdpauinteropyuv")) ++ { ++ if (method == VS_INTERLACEMETHOD_RENDER_BOB) ++ return true; ++ } ++ + for(SInterlaceMapping* p = g_interlace_mapping; p->method != VS_INTERLACEMETHOD_NONE; p++) + { + if(p->method == method) +@@ -571,162 +379,12 @@ bool CVDPAU::Supports(EINTERLACEMETHOD method) + return false; + } + +-EINTERLACEMETHOD CVDPAU::AutoInterlaceMethod() +-{ +- return VS_INTERLACEMETHOD_VDPAU_TEMPORAL; +-} +- +-void CVDPAU::SetColor() +-{ +- VdpStatus vdp_st; +- +- if (tmpBrightness != g_settings.m_currentVideoSettings.m_Brightness) +- m_Procamp.brightness = (float)((g_settings.m_currentVideoSettings.m_Brightness)-50) / 100; +- if (tmpContrast != g_settings.m_currentVideoSettings.m_Contrast) +- m_Procamp.contrast = (float)((g_settings.m_currentVideoSettings.m_Contrast)+50) / 100; +- +- if(vid_height >= 600 || vid_width > 1024) +- vdp_st = vdp_generate_csc_matrix(&m_Procamp, VDP_COLOR_STANDARD_ITUR_BT_709, &m_CSCMatrix); +- else +- vdp_st = vdp_generate_csc_matrix(&m_Procamp, VDP_COLOR_STANDARD_ITUR_BT_601, &m_CSCMatrix); +- +- VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX }; +- if (g_guiSettings.GetBool("videoplayer.vdpaustudiolevel")) +- { +- void const * pm_CSCMatix[] = { &studioCSC }; +- vdp_st = vdp_video_mixer_set_attribute_values(videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix); +- } +- else +- { +- void const * pm_CSCMatix[] = { &m_CSCMatrix }; +- vdp_st = vdp_video_mixer_set_attribute_values(videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix); +- } +- CheckStatus(vdp_st, __LINE__); +-} +- +-void CVDPAU::SetNoiseReduction() +-{ +- if(!Supports(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION)) +- return; +- +- VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION }; +- VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL }; +- VdpStatus vdp_st; +- +- if (!g_settings.m_currentVideoSettings.m_NoiseReduction) +- { +- VdpBool enabled[]= {0}; +- vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled); +- CheckStatus(vdp_st, __LINE__); +- return; +- } +- VdpBool enabled[]={1}; +- vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled); +- CheckStatus(vdp_st, __LINE__); +- void* nr[] = { &g_settings.m_currentVideoSettings.m_NoiseReduction }; +- CLog::Log(LOGNOTICE,"Setting Noise Reduction to %f",g_settings.m_currentVideoSettings.m_NoiseReduction); +- vdp_st = vdp_video_mixer_set_attribute_values(videoMixer, ARSIZE(attributes), attributes, nr); +- CheckStatus(vdp_st, __LINE__); +-} +- +-void CVDPAU::SetSharpness() +-{ +- if(!Supports(VDP_VIDEO_MIXER_FEATURE_SHARPNESS)) +- return; +- +- VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_SHARPNESS }; +- VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL }; +- VdpStatus vdp_st; +- +- if (!g_settings.m_currentVideoSettings.m_Sharpness) +- { +- VdpBool enabled[]={0}; +- vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled); +- CheckStatus(vdp_st, __LINE__); +- return; +- } +- VdpBool enabled[]={1}; +- vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled); +- CheckStatus(vdp_st, __LINE__); +- void* sh[] = { &g_settings.m_currentVideoSettings.m_Sharpness }; +- CLog::Log(LOGNOTICE,"Setting Sharpness to %f",g_settings.m_currentVideoSettings.m_Sharpness); +- vdp_st = vdp_video_mixer_set_attribute_values(videoMixer, ARSIZE(attributes), attributes, sh); +- CheckStatus(vdp_st, __LINE__); +-} +- +-void CVDPAU::SetHWUpscaling() +-{ +-#ifdef VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 +- if(!Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1) || !upScale) +- return; +- +- VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 }; +- VdpStatus vdp_st; +- VdpBool enabled[]={1}; +- vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled); +- CheckStatus(vdp_st, __LINE__); +-#endif +-} +- +-void CVDPAU::SetDeinterlacing() ++EINTERLACEMETHOD CDecoder::AutoInterlaceMethod() + { +- VdpStatus vdp_st; +- EDEINTERLACEMODE mode = g_settings.m_currentVideoSettings.m_DeinterlaceMode; +- EINTERLACEMETHOD method = g_settings.m_currentVideoSettings.m_InterlaceMethod; +- if (method == VS_INTERLACEMETHOD_AUTO) +- method = AutoInterlaceMethod(); +- +- VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL, +- VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL, +- VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE }; +- if (mode == VS_DEINTERLACEMODE_OFF) +- { +- VdpBool enabled[]={0,0,0}; +- vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled); +- } +- else +- { +- if (method == VS_INTERLACEMETHOD_AUTO_ION) +- { +- if (vid_height <= 576) +- { +- VdpBool enabled[]={1,1,0}; +- vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled); +- } +- else if (vid_height > 576) +- { +- VdpBool enabled[]={1,0,0}; +- vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled); +- } +- } +- else if (method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL +- || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF) +- { +- VdpBool enabled[]={1,0,0}; +- vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled); +- } +- else if (method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL +- || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF) +- { +- VdpBool enabled[]={1,1,0}; +- vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled); +- } +- else if (method == VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE) +- { +- VdpBool enabled[]={1,0,1}; +- vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled); +- } +- else +- { +- VdpBool enabled[]={0,0,0}; +- vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled); +- } +- } +- +- CheckStatus(vdp_st, __LINE__); ++ return VS_INTERLACEMETHOD_RENDER_BOB; + } + +-void CVDPAU::InitVDPAUProcs() ++void CDecoder::InitVDPAUProcs() + { + char* error; + +@@ -736,151 +394,115 @@ void CVDPAU::InitVDPAUProcs() + if (error) + { + CLog::Log(LOGERROR,"(VDPAU) - %s in %s",error,__FUNCTION__); +- vdp_device = VDP_INVALID_HANDLE; +- +- //g_application.m_guiDialogKaiToast.QueueNotification(CGUIDialogKaiToast::Error, "VDPAU", error, 10000); +- ++ m_vdpauConfig.vdpDevice = VDP_INVALID_HANDLE; + return; + } + + if (dl_vdp_device_create_x11) + { +- CSingleLock lock(g_graphicsContext); +- m_Display = g_Windowing.GetDisplay(); +- } +- else +- { +- CLog::Log(LOGERROR,"(VDPAU) - Unable to get dl_vdp_device_create_x11 in %s", __FUNCTION__); +- vdp_device = VDP_INVALID_HANDLE; +- return; ++ m_Display = XOpenDisplay(NULL); + } + +- int mScreen = DefaultScreen(m_Display); ++ int mScreen = g_Windowing.GetCurrentScreen(); + VdpStatus vdp_st; + + // Create Device +- // tested on 64bit Ubuntu 11.10 and it deadlocked without this +- XLockDisplay(m_Display); + vdp_st = dl_vdp_device_create_x11(m_Display, //x_display, + mScreen, //x_screen, +- &vdp_device, +- &vdp_get_proc_address); +- XUnlockDisplay(m_Display); ++ &m_vdpauConfig.vdpDevice, ++ &m_vdpauConfig.vdpProcs.vdp_get_proc_address); + +- CLog::Log(LOGNOTICE,"vdp_device = 0x%08x vdp_st = 0x%08x",vdp_device,vdp_st); ++ CLog::Log(LOGNOTICE,"vdp_device = 0x%08x vdp_st = 0x%08x",m_vdpauConfig.vdpDevice,vdp_st); + if (vdp_st != VDP_STATUS_OK) + { + CLog::Log(LOGERROR,"(VDPAU) unable to init VDPAU - vdp_st = 0x%x. Falling back.",vdp_st); +- vdp_device = VDP_INVALID_HANDLE; ++ m_vdpauConfig.vdpDevice = VDP_INVALID_HANDLE; + return; + } + + #define VDP_PROC(id, proc) \ + do { \ +- vdp_st = vdp_get_proc_address(vdp_device, id, (void**)&proc); \ ++ vdp_st = m_vdpauConfig.vdpProcs.vdp_get_proc_address(m_vdpauConfig.vdpDevice, id, (void**)&proc); \ + CheckStatus(vdp_st, __LINE__); \ + } while(0); + +- VDP_PROC(VDP_FUNC_ID_GET_ERROR_STRING , vdp_get_error_string); +- VDP_PROC(VDP_FUNC_ID_DEVICE_DESTROY , vdp_device_destroy); +- VDP_PROC(VDP_FUNC_ID_GENERATE_CSC_MATRIX , vdp_generate_csc_matrix); +- VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_CREATE , vdp_video_surface_create); +- VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_DESTROY , vdp_video_surface_destroy); +- VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_PUT_BITS_Y_CB_CR , vdp_video_surface_put_bits_y_cb_cr); +- VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR , vdp_video_surface_get_bits_y_cb_cr); +- VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_Y_CB_CR , vdp_output_surface_put_bits_y_cb_cr); +- VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_NATIVE , vdp_output_surface_put_bits_native); +- VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_CREATE , vdp_output_surface_create); +- VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_DESTROY , vdp_output_surface_destroy); +- VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_GET_BITS_NATIVE , vdp_output_surface_get_bits_native); +- VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_OUTPUT_SURFACE, vdp_output_surface_render_output_surface); +- VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_INDEXED , vdp_output_surface_put_bits_indexed); +- VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_CREATE , vdp_video_mixer_create); +- VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_SET_FEATURE_ENABLES , vdp_video_mixer_set_feature_enables); +- VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_DESTROY , vdp_video_mixer_destroy); +- VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_RENDER , vdp_video_mixer_render); +- VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_SET_ATTRIBUTE_VALUES , vdp_video_mixer_set_attribute_values); +- VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_QUERY_PARAMETER_SUPPORT , vdp_video_mixer_query_parameter_support); +- VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_QUERY_FEATURE_SUPPORT , vdp_video_mixer_query_feature_support); +- VDP_PROC(VDP_FUNC_ID_DECODER_CREATE , vdp_decoder_create); +- VDP_PROC(VDP_FUNC_ID_DECODER_DESTROY , vdp_decoder_destroy); +- VDP_PROC(VDP_FUNC_ID_DECODER_RENDER , vdp_decoder_render); +- VDP_PROC(VDP_FUNC_ID_DECODER_QUERY_CAPABILITIES , vdp_decoder_query_caps); +- VDP_PROC(VDP_FUNC_ID_PREEMPTION_CALLBACK_REGISTER , vdp_preemption_callback_register); +- VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_DESTROY , vdp_presentation_queue_target_destroy); +- VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_CREATE , vdp_presentation_queue_create); +- VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_DESTROY , vdp_presentation_queue_destroy); +- VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_DISPLAY , vdp_presentation_queue_display); +- VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_BLOCK_UNTIL_SURFACE_IDLE, vdp_presentation_queue_block_until_surface_idle); +- VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_CREATE_X11 , vdp_presentation_queue_target_create_x11); +- VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_QUERY_SURFACE_STATUS , vdp_presentation_queue_query_surface_status); +- VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_GET_TIME , vdp_presentation_queue_get_time); +- ++ VDP_PROC(VDP_FUNC_ID_GET_ERROR_STRING , m_vdpauConfig.vdpProcs.vdp_get_error_string); ++ VDP_PROC(VDP_FUNC_ID_DEVICE_DESTROY , m_vdpauConfig.vdpProcs.vdp_device_destroy); ++ VDP_PROC(VDP_FUNC_ID_GENERATE_CSC_MATRIX , m_vdpauConfig.vdpProcs.vdp_generate_csc_matrix); ++ VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_CREATE , m_vdpauConfig.vdpProcs.vdp_video_surface_create); ++ VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_DESTROY , m_vdpauConfig.vdpProcs.vdp_video_surface_destroy); ++ VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_PUT_BITS_Y_CB_CR , m_vdpauConfig.vdpProcs.vdp_video_surface_put_bits_y_cb_cr); ++ VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR , m_vdpauConfig.vdpProcs.vdp_video_surface_get_bits_y_cb_cr); ++ VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_Y_CB_CR , m_vdpauConfig.vdpProcs.vdp_output_surface_put_bits_y_cb_cr); ++ VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_NATIVE , m_vdpauConfig.vdpProcs.vdp_output_surface_put_bits_native); ++ VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_CREATE , m_vdpauConfig.vdpProcs.vdp_output_surface_create); ++ VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_DESTROY , m_vdpauConfig.vdpProcs.vdp_output_surface_destroy); ++ VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_GET_BITS_NATIVE , m_vdpauConfig.vdpProcs.vdp_output_surface_get_bits_native); ++ VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_OUTPUT_SURFACE, m_vdpauConfig.vdpProcs.vdp_output_surface_render_output_surface); ++ VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_INDEXED , m_vdpauConfig.vdpProcs.vdp_output_surface_put_bits_indexed); ++ VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_CREATE , m_vdpauConfig.vdpProcs.vdp_video_mixer_create); ++ VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_SET_FEATURE_ENABLES , m_vdpauConfig.vdpProcs.vdp_video_mixer_set_feature_enables); ++ VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_DESTROY , m_vdpauConfig.vdpProcs.vdp_video_mixer_destroy); ++ VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_RENDER , m_vdpauConfig.vdpProcs.vdp_video_mixer_render); ++ VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_SET_ATTRIBUTE_VALUES , m_vdpauConfig.vdpProcs.vdp_video_mixer_set_attribute_values); ++ VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_QUERY_PARAMETER_SUPPORT , m_vdpauConfig.vdpProcs.vdp_video_mixer_query_parameter_support); ++ VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_QUERY_FEATURE_SUPPORT , m_vdpauConfig.vdpProcs.vdp_video_mixer_query_feature_support); ++ VDP_PROC(VDP_FUNC_ID_DECODER_CREATE , m_vdpauConfig.vdpProcs.vdp_decoder_create); ++ VDP_PROC(VDP_FUNC_ID_DECODER_DESTROY , m_vdpauConfig.vdpProcs.vdp_decoder_destroy); ++ VDP_PROC(VDP_FUNC_ID_DECODER_RENDER , m_vdpauConfig.vdpProcs.vdp_decoder_render); ++ VDP_PROC(VDP_FUNC_ID_DECODER_QUERY_CAPABILITIES , m_vdpauConfig.vdpProcs.vdp_decoder_query_caps); ++ VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_DESTROY , m_vdpauConfig.vdpProcs.vdp_presentation_queue_target_destroy); ++ VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_CREATE , m_vdpauConfig.vdpProcs.vdp_presentation_queue_create); ++ VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_DESTROY , m_vdpauConfig.vdpProcs.vdp_presentation_queue_destroy); ++ VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_DISPLAY , m_vdpauConfig.vdpProcs.vdp_presentation_queue_display); ++ VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_BLOCK_UNTIL_SURFACE_IDLE, m_vdpauConfig.vdpProcs.vdp_presentation_queue_block_until_surface_idle); ++ VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_CREATE_X11 , m_vdpauConfig.vdpProcs.vdp_presentation_queue_target_create_x11); ++ VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_QUERY_SURFACE_STATUS , m_vdpauConfig.vdpProcs.vdp_presentation_queue_query_surface_status); ++ VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_GET_TIME , m_vdpauConfig.vdpProcs.vdp_presentation_queue_get_time); ++ + #undef VDP_PROC + + // set all vdpau resources to invalid +- vdp_flip_target = VDP_INVALID_HANDLE; +- vdp_flip_queue = VDP_INVALID_HANDLE; +- videoMixer = VDP_INVALID_HANDLE; +- totalAvailableOutputSurfaces = 0; +- presentSurface = VDP_INVALID_HANDLE; +- outputSurface = VDP_INVALID_HANDLE; +- for (int i = 0; i < NUM_OUTPUT_SURFACES; i++) +- outputSurfaces[i] = VDP_INVALID_HANDLE; +- +- m_vdpauOutputMethod = OUTPUT_NONE; +- +- CExclusiveLock lock(m_DisplaySection); + m_DisplayState = VDPAU_OPEN; +- vdpauConfigured = false; ++ m_vdpauConfigured = false; + } + +-void CVDPAU::FiniVDPAUProcs() ++void CDecoder::FiniVDPAUProcs() + { +- if (vdp_device == VDP_INVALID_HANDLE) return; ++ if (m_vdpauConfig.vdpDevice == VDP_INVALID_HANDLE) return; + + VdpStatus vdp_st; +- vdp_st = vdp_device_destroy(vdp_device); ++ vdp_st = m_vdpauConfig.vdpProcs.vdp_device_destroy(m_vdpauConfig.vdpDevice); + CheckStatus(vdp_st, __LINE__); +- vdp_device = VDP_INVALID_HANDLE; +- vdpauConfigured = false; ++ m_vdpauConfig.vdpDevice = VDP_INVALID_HANDLE; + } + +-void CVDPAU::InitCSCMatrix(int Height) ++void CDecoder::FiniVDPAUOutput() + { ++ if (m_vdpauConfig.vdpDevice == VDP_INVALID_HANDLE || !m_vdpauConfigured) return; ++ ++ CLog::Log(LOGNOTICE, " (VDPAU) %s", __FUNCTION__); ++ ++ // uninit output ++ m_vdpauOutput.Dispose(); ++ m_vdpauConfigured = false; ++ + VdpStatus vdp_st; +- m_Procamp.struct_version = VDP_PROCAMP_VERSION; +- m_Procamp.brightness = 0.0; +- m_Procamp.contrast = 1.0; +- m_Procamp.saturation = 1.0; +- m_Procamp.hue = 0; +- vdp_st = vdp_generate_csc_matrix(&m_Procamp, +- (Height < 720)? VDP_COLOR_STANDARD_ITUR_BT_601 : VDP_COLOR_STANDARD_ITUR_BT_709, +- &m_CSCMatrix); +- CheckStatus(vdp_st, __LINE__); +-} +- +-void CVDPAU::FiniVDPAUOutput() +-{ +- FiniOutputMethod(); + +- if (vdp_device == VDP_INVALID_HANDLE || !vdpauConfigured) return; +- +- CLog::Log(LOGNOTICE, " (VDPAU) %s", __FUNCTION__); +- +- VdpStatus vdp_st; +- +- vdp_st = vdp_decoder_destroy(decoder); ++ vdp_st = m_vdpauConfig.vdpProcs.vdp_decoder_destroy(m_vdpauConfig.vdpDecoder); + if (CheckStatus(vdp_st, __LINE__)) + return; +- decoder = VDP_INVALID_HANDLE; ++ m_vdpauConfig.vdpDecoder = VDP_INVALID_HANDLE; ++ ++ CSingleLock lock(m_videoSurfaceSec); ++ CLog::Log(LOGDEBUG, "CVDPAU::FiniVDPAUOutput destroying %d video surfaces", (int)m_videoSurfaces.size()); + +- for (unsigned int i = 0; i < m_videoSurfaces.size(); ++i) ++ for(unsigned int i = 0; i < m_videoSurfaces.size(); ++i) + { + vdpau_render_state *render = m_videoSurfaces[i]; + if (render->surface != VDP_INVALID_HANDLE) + { +- vdp_st = vdp_video_surface_destroy(render->surface); ++ vdp_st = m_vdpauConfig.vdpProcs.vdp_video_surface_destroy(render->surface); + render->surface = VDP_INVALID_HANDLE; + } + if (CheckStatus(vdp_st, __LINE__)) +@@ -888,8 +510,7 @@ void CVDPAU::FiniVDPAUOutput() + } + } + +- +-void CVDPAU::ReadFormatOf( PixelFormat fmt ++void CDecoder::ReadFormatOf( PixelFormat fmt + , VdpDecoderProfile &vdp_decoder_profile + , VdpChromaType &vdp_chroma_type) + { +@@ -916,9 +537,9 @@ void CVDPAU::ReadFormatOf( PixelFormat fmt + vdp_chroma_type = VDP_CHROMA_TYPE_420; + break; + #if (defined PIX_FMT_VDPAU_MPEG4_IN_AVUTIL) && \ +- (defined VDP_DECODER_PROFILE_MPEG4_PART2_ASP) ++ (defined VDP_DECODER_PROFILE_MP) + case PIX_FMT_VDPAU_MPEG4: +- vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG4_PART2_ASP; ++ vdp_decoder_profile = VDP_DECOPEG4_PART2_ASP; + vdp_chroma_type = VDP_CHROMA_TYPE_420; + break; + #endif +@@ -929,170 +550,78 @@ void CVDPAU::ReadFormatOf( PixelFormat fmt + } + } + +- +-bool CVDPAU::ConfigVDPAU(AVCodecContext* avctx, int ref_frames) ++bool CDecoder::ConfigVDPAU(AVCodecContext* avctx, int ref_frames) + { + FiniVDPAUOutput(); + + VdpStatus vdp_st; + VdpDecoderProfile vdp_decoder_profile; +- vid_width = avctx->width; +- vid_height = avctx->height; +- surface_width = avctx->coded_width; +- surface_height = avctx->coded_height; + +- past[1] = past[0] = current = future = NULL; +- CLog::Log(LOGNOTICE, " (VDPAU) screenWidth:%i vidWidth:%i surfaceWidth:%i",OutWidth,vid_width,surface_width); +- CLog::Log(LOGNOTICE, " (VDPAU) screenHeight:%i vidHeight:%i surfaceHeight:%i",OutHeight,vid_height,surface_height); +- ReadFormatOf(avctx->pix_fmt, vdp_decoder_profile, vdp_chroma_type); ++ m_vdpauConfig.vidWidth = avctx->width; ++ m_vdpauConfig.vidHeight = avctx->height; ++ m_vdpauConfig.surfaceWidth = avctx->coded_width; ++ m_vdpauConfig.surfaceHeight = avctx->coded_height; ++ ++ SetWidthHeight(avctx->width,avctx->height); ++ ++ CLog::Log(LOGNOTICE, " (VDPAU) screenWidth:%i vidWidth:%i surfaceWidth:%i",m_vdpauConfig.outWidth,m_vdpauConfig.vidWidth,m_vdpauConfig.surfaceWidth); ++ CLog::Log(LOGNOTICE, " (VDPAU) screenHeight:%i vidHeight:%i surfaceHeight:%i",m_vdpauConfig.outHeight,m_vdpauConfig.vidHeight,m_vdpauConfig.surfaceHeight); ++ ++ ReadFormatOf(avctx->pix_fmt, vdp_decoder_profile, m_vdpauConfig.vdpChromaType); + + if(avctx->pix_fmt == PIX_FMT_VDPAU_H264) + { +- max_references = ref_frames; +- if (max_references > 16) max_references = 16; +- if (max_references < 5) max_references = 5; ++ m_vdpauConfig.maxReferences = ref_frames; ++ if (m_vdpauConfig.maxReferences > 16) m_vdpauConfig.maxReferences = 16; ++ if (m_vdpauConfig.maxReferences < 5) m_vdpauConfig.maxReferences = 5; + } + else +- max_references = 2; ++ m_vdpauConfig.maxReferences = 2; + +- vdp_st = vdp_decoder_create(vdp_device, ++ vdp_st = m_vdpauConfig.vdpProcs.vdp_decoder_create(m_vdpauConfig.vdpDevice, + vdp_decoder_profile, +- surface_width, +- surface_height, +- max_references, +- &decoder); +- if (CheckStatus(vdp_st, __LINE__)) +- return false; +- +- m_vdpauOutputMethod = OUTPUT_NONE; +- +- vdpauConfigured = true; +- return true; +-} +- +-bool CVDPAU::ConfigOutputMethod(AVCodecContext *avctx, AVFrame *pFrame) +-{ +- VdpStatus vdp_st; +- +- if (m_vdpauOutputMethod == OUTPUT_PIXMAP) +- return true; +- +- FiniOutputMethod(); +- +- MakePixmap(avctx->width,avctx->height); +- +- vdp_st = vdp_presentation_queue_target_create_x11(vdp_device, +- m_Pixmap, //x_window, +- &vdp_flip_target); +- if (CheckStatus(vdp_st, __LINE__)) +- return false; +- +- vdp_st = vdp_presentation_queue_create(vdp_device, +- vdp_flip_target, +- &vdp_flip_queue); ++ m_vdpauConfig.surfaceWidth, ++ m_vdpauConfig.surfaceHeight, ++ m_vdpauConfig.maxReferences, ++ &m_vdpauConfig.vdpDecoder); + if (CheckStatus(vdp_st, __LINE__)) + return false; + +- totalAvailableOutputSurfaces = 0; +- +- int tmpMaxOutputSurfaces = NUM_OUTPUT_SURFACES; +- if (vid_width == FULLHD_WIDTH) +- tmpMaxOutputSurfaces = NUM_OUTPUT_SURFACES_FOR_FULLHD; +- +- // Creation of outputSurfaces +- for (int i = 0; i < NUM_OUTPUT_SURFACES && i < tmpMaxOutputSurfaces; i++) +- { +- vdp_st = vdp_output_surface_create(vdp_device, +- VDP_RGBA_FORMAT_B8G8R8A8, +- OutWidth, +- OutHeight, +- &outputSurfaces[i]); +- if (CheckStatus(vdp_st, __LINE__)) ++ // initialize output ++ CSingleLock lock(g_graphicsContext); ++ m_vdpauConfig.stats = &m_bufferStats; ++ m_vdpauConfig.vdpau = this; ++ m_bufferStats.Reset(); ++ m_vdpauOutput.Start(); ++ Message *reply; ++ if (m_vdpauOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::INIT, ++ &reply, ++ 2000, ++ &m_vdpauConfig, ++ sizeof(m_vdpauConfig))) ++ { ++ bool success = reply->signal == COutputControlProtocol::ACC ? true : false; ++ reply->Release(); ++ if (!success) ++ { ++ CLog::Log(LOGERROR, "VDPAU::%s - vdpau output returned error", __FUNCTION__); ++ m_vdpauOutput.Dispose(); + return false; +- totalAvailableOutputSurfaces++; +- } +- CLog::Log(LOGNOTICE, " (VDPAU) Total Output Surfaces Available: %i of a max (tmp: %i const: %i)", +- totalAvailableOutputSurfaces, +- tmpMaxOutputSurfaces, +- NUM_OUTPUT_SURFACES); +- +- // create 3 pitches of black lines needed for clipping top +- // and bottom lines when de-interlacing +- m_BlackBar = new uint32_t[3*OutWidth]; +- memset(m_BlackBar, 0, 3*OutWidth*sizeof(uint32_t)); +- +- surfaceNum = presentSurfaceNum = 0; +- outputSurface = presentSurface = VDP_INVALID_HANDLE; +- videoMixer = VDP_INVALID_HANDLE; +- +- m_vdpauOutputMethod = OUTPUT_PIXMAP; +- +- return true; +-} +- +-bool CVDPAU::FiniOutputMethod() +-{ +- VdpStatus vdp_st; +- +- if (vdp_flip_queue != VDP_INVALID_HANDLE) +- { +- vdp_st = vdp_presentation_queue_destroy(vdp_flip_queue); +- vdp_flip_queue = VDP_INVALID_HANDLE; +- CheckStatus(vdp_st, __LINE__); +- } +- +- if (vdp_flip_target != VDP_INVALID_HANDLE) +- { +- vdp_st = vdp_presentation_queue_target_destroy(vdp_flip_target); +- vdp_flip_target = VDP_INVALID_HANDLE; +- CheckStatus(vdp_st, __LINE__); +- } +- +- if (m_glPixmap) +- { +- CLog::Log(LOGDEBUG, "GLX: Destroying glPixmap"); +- glXDestroyPixmap(m_Display, m_glPixmap); +- m_glPixmap = None; +- } +- +- if (m_Pixmap) +- { +- CLog::Log(LOGDEBUG, "GLX: Destroying XPixmap"); +- XFreePixmap(m_Display, m_Pixmap); +- m_Pixmap = None; +- } +- +- outputSurface = presentSurface = VDP_INVALID_HANDLE; +- +- for (int i = 0; i < totalAvailableOutputSurfaces; i++) +- { +- if (outputSurfaces[i] == VDP_INVALID_HANDLE) +- continue; +- vdp_st = vdp_output_surface_destroy(outputSurfaces[i]); +- outputSurfaces[i] = VDP_INVALID_HANDLE; +- CheckStatus(vdp_st, __LINE__); +- } +- +- if (videoMixer != VDP_INVALID_HANDLE) +- { +- vdp_st = vdp_video_mixer_destroy(videoMixer); +- videoMixer = VDP_INVALID_HANDLE; +- CheckStatus(vdp_st, __LINE__); ++ } + } +- +- if (m_BlackBar) ++ else + { +- delete [] m_BlackBar; +- m_BlackBar = NULL; ++ CLog::Log(LOGERROR, "VDPAU::%s - failed to init output", __FUNCTION__); ++ m_vdpauOutput.Dispose(); ++ return false; + } + +- while (!m_DVDVideoPics.empty()) +- m_DVDVideoPics.pop(); +- ++ m_inMsgEvent.Reset(); ++ m_vdpauConfigured = true; + return true; + } + +-void CVDPAU::SpewHardwareAvailable() //Copyright (c) 2008 Wladimir J. van der Laan -- VDPInfo ++void CDecoder::SpewHardwareAvailable() //CopyrighVDPAUt (c) 2008 Wladimir J. van der Laan -- VDPInfo + { + VdpStatus rv; + CLog::Log(LOGNOTICE,"VDPAU Decoder capabilities:"); +@@ -1102,7 +631,7 @@ void CVDPAU::SpewHardwareAvailable() //Copyright (c) 2008 Wladimir J. van der L + { + VdpBool is_supported = false; + uint32_t max_level, max_macroblocks, max_width, max_height; +- rv = vdp_decoder_query_caps(vdp_device, decoder_profiles[x].id, ++ rv = m_vdpauConfig.vdpProcs.vdp_decoder_query_caps(m_vdpauConfig.vdpDevice, decoder_profiles[x].id, + &is_supported, &max_level, &max_macroblocks, &max_width, &max_height); + if(rv == VDP_STATUS_OK && is_supported) + { +@@ -1111,13 +640,13 @@ void CVDPAU::SpewHardwareAvailable() //Copyright (c) 2008 Wladimir J. van der L + } + } + CLog::Log(LOGNOTICE,"------------------------------------"); +- m_feature_count = 0; ++ m_vdpauConfig.featureCount = 0; + #define CHECK_SUPPORT(feature) \ + do { \ + VdpBool supported; \ +- if(vdp_video_mixer_query_feature_support(vdp_device, feature, &supported) == VDP_STATUS_OK && supported) { \ ++ if(m_vdpauConfig.vdpProcs.vdp_video_mixer_query_feature_support(m_vdpauConfig.vdpDevice, feature, &supported) == VDP_STATUS_OK && supported) { \ + CLog::Log(LOGNOTICE, "Mixer feature: "#feature); \ +- m_features[m_feature_count++] = feature; \ ++ m_vdpauConfig.vdpFeatures[m_vdpauConfig.featureCount++] = feature; \ + } \ + } while(false) + +@@ -1141,7 +670,7 @@ void CVDPAU::SpewHardwareAvailable() //Copyright (c) 2008 Wladimir J. van der L + + } + +-bool CVDPAU::IsSurfaceValid(vdpau_render_state *render) ++bool CDecoder::IsSurfaceValid(vdpau_render_state *render) + { + // find render state in queue + bool found(false); +@@ -1168,34 +697,33 @@ bool CVDPAU::IsSurfaceValid(vdpau_render_state *render) + return true; + } + +-int CVDPAU::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic) ++int CDecoder::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic) + { + //CLog::Log(LOGNOTICE,"%s",__FUNCTION__); + CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)avctx->opaque; +- CVDPAU* vdp = (CVDPAU*)ctx->GetHardware(); +- struct pictureAge* pA = &vdp->picAge; ++ CDecoder* vdp = (CDecoder*)ctx->GetHardware(); + + // while we are waiting to recover we can't do anything +- CSharedLock lock(vdp->m_DecoderSection); ++ CSingleLock lock(vdp->m_DecoderSection); + +- { CSharedLock dLock(vdp->m_DisplaySection); +- if(vdp->m_DisplayState != VDPAU_OPEN) +- { +- CLog::Log(LOGWARNING, "CVDPAU::FFGetBuffer - returning due to awaiting recovery"); +- return -1; +- } ++ if(vdp->m_DisplayState != VDPAU_OPEN) ++ { ++ CLog::Log(LOGWARNING, "CVDPAU::FFGetBuffer - returning due to awaiting recovery"); ++ return -1; + } + + vdpau_render_state * render = NULL; + + // find unused surface +- for(unsigned int i = 0; i < vdp->m_videoSurfaces.size(); i++) +- { +- if(!(vdp->m_videoSurfaces[i]->state & (FF_VDPAU_STATE_USED_FOR_REFERENCE | FF_VDPAU_STATE_USED_FOR_RENDER))) ++ { CSingleLock lock(vdp->m_videoSurfaceSec); ++ for(unsigned int i = 0; i < vdp->m_videoSurfaces.size(); i++) + { +- render = vdp->m_videoSurfaces[i]; +- render->state = 0; +- break; ++ if(!(vdp->m_videoSurfaces[i]->state & (FF_VDPAU_STATE_USED_FOR_REFERENCE | FF_VDPAU_STATE_USED_FOR_RENDER))) ++ { ++ render = vdp->m_videoSurfaces[i]; ++ render->state = 0; ++ break; ++ } + } + } + +@@ -1204,21 +732,22 @@ int CVDPAU::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic) + { + // create a new surface + VdpDecoderProfile profile; +- ReadFormatOf(avctx->pix_fmt, profile, vdp->vdp_chroma_type); ++ ReadFormatOf(avctx->pix_fmt, profile, vdp->m_vdpauConfig.vdpChromaType); + render = (vdpau_render_state*)calloc(sizeof(vdpau_render_state), 1); + if (render == NULL) + { + CLog::Log(LOGWARNING, "CVDPAU::FFGetBuffer - calloc failed"); + return -1; + } ++ CSingleLock lock(vdp->m_videoSurfaceSec); + render->surface = VDP_INVALID_HANDLE; + vdp->m_videoSurfaces.push_back(render); + } + + if (render->surface == VDP_INVALID_HANDLE) + { +- vdp_st = vdp->vdp_video_surface_create(vdp->vdp_device, +- vdp->vdp_chroma_type, ++ vdp_st = vdp->m_vdpauConfig.vdpProcs.vdp_video_surface_create(vdp->m_vdpauConfig.vdpDevice, ++ vdp->m_vdpauConfig.vdpChromaType, + avctx->coded_width, + avctx->coded_height, + &render->surface); +@@ -1239,18 +768,6 @@ int CVDPAU::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic) + + pic->linesize[0] = pic->linesize[1] = pic->linesize[2] = 0; + +- if(pic->reference) +- { +- pA->ip_age[0]= pA->ip_age[1]+1; +- pA->ip_age[1]= 1; +- pA->b_age++; +- } +- else +- { +- pA->ip_age[0]++; +- pA->ip_age[1]++; +- pA->b_age = 1; +- } + pic->type= FF_BUFFER_TYPE_USER; + + render->state |= FF_VDPAU_STATE_USED_FOR_REFERENCE; +@@ -1258,15 +775,16 @@ int CVDPAU::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic) + return 0; + } + +-void CVDPAU::FFReleaseBuffer(AVCodecContext *avctx, AVFrame *pic) ++void CDecoder::FFReleaseBuffer(AVCodecContext *avctx, AVFrame *pic) + { + //CLog::Log(LOGNOTICE,"%s",__FUNCTION__); + CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)avctx->opaque; +- CVDPAU* vdp = (CVDPAU*)ctx->GetHardware(); ++ CDecoder* vdp = (CDecoder*)ctx->GetHardware(); ++ + vdpau_render_state * render; + unsigned int i; + +- CSharedLock lock(vdp->m_DecoderSection); ++ CSingleLock lock(vdp->m_DecoderSection); + + render=(vdpau_render_state*)pic->data[0]; + if(!render) +@@ -1275,6 +793,8 @@ void CVDPAU::FFReleaseBuffer(AVCodecContext *avctx, AVFrame *pic) + return; + } + ++ CSingleLock vLock(vdp->m_videoSurfaceSec); ++ render->state &= ~FF_VDPAU_STATE_USED_FOR_REFERENCE; + for(i=0; i<4; i++) + pic->data[i]= NULL; + +@@ -1289,21 +809,18 @@ void CVDPAU::FFReleaseBuffer(AVCodecContext *avctx, AVFrame *pic) + } + + +-void CVDPAU::FFDrawSlice(struct AVCodecContext *s, ++void CDecoder::FFDrawSlice(struct AVCodecContext *s, + const AVFrame *src, int offset[4], + int y, int type, int height) + { + CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)s->opaque; +- CVDPAU* vdp = (CVDPAU*)ctx->GetHardware(); ++ CDecoder* vdp = (CDecoder*)ctx->GetHardware(); + + // while we are waiting to recover we can't do anything +- CSharedLock lock(vdp->m_DecoderSection); +- +- { CSharedLock dLock(vdp->m_DisplaySection); +- if(vdp->m_DisplayState != VDPAU_OPEN) +- return; +- } ++ CSingleLock lock(vdp->m_DecoderSection); + ++ if(vdp->m_DisplayState != VDPAU_OPEN) ++ return; + + if(src->linesize[0] || src->linesize[1] || src->linesize[2] + || offset[0] || offset[1] || offset[2]) +@@ -1333,59 +850,41 @@ void CVDPAU::FFDrawSlice(struct AVCodecContext *s, + if(s->pix_fmt == PIX_FMT_VDPAU_H264) + max_refs = render->info.h264.num_ref_frames; + +- if(vdp->decoder == VDP_INVALID_HANDLE +- || vdp->vdpauConfigured == false +- || vdp->max_references < max_refs) ++ if(vdp->m_vdpauConfig.vdpDecoder == VDP_INVALID_HANDLE ++ || vdp->m_vdpauConfigured == false ++ || vdp->m_vdpauConfig.maxReferences < max_refs) + { + if(!vdp->ConfigVDPAU(s, max_refs)) + return; + } + +- vdp_st = vdp->vdp_decoder_render(vdp->decoder, ++ uint64_t startTime = CurrentHostCounter(); ++ uint16_t decoded, processed, rend; ++ vdp->m_bufferStats.Get(decoded, processed, rend); ++ vdp_st = vdp->m_vdpauConfig.vdpProcs.vdp_decoder_render(vdp->m_vdpauConfig.vdpDecoder, + render->surface, + (VdpPictureInfo const *)&(render->info), + render->bitstream_buffers_used, + render->bitstream_buffers); + vdp->CheckStatus(vdp_st, __LINE__); ++ uint64_t diff = CurrentHostCounter() - startTime; ++ if (diff*1000/CurrentHostFrequency() > 30) ++ CLog::Log(LOGWARNING,"CVDPAU::DrawSlice - VdpDecoderRender long decoding: %d ms, dec: %d, proc: %d, rend: %d", (int)((diff*1000)/CurrentHostFrequency()), decoded, processed, rend); ++ + } + +-int CVDPAU::Decode(AVCodecContext *avctx, AVFrame *pFrame) +-{ +- //CLog::Log(LOGNOTICE,"%s",__FUNCTION__); +- VdpStatus vdp_st; +- VdpTime time; + ++int CDecoder::Decode(AVCodecContext *avctx, AVFrame *pFrame) ++{ + int result = Check(avctx); + if (result) + return result; + +- CSharedLock lock(m_DecoderSection); ++ CSingleLock lock(m_DecoderSection); + +- if (!vdpauConfigured) ++ if (!m_vdpauConfigured) + return VC_ERROR; + +- // configure vdpau output +- if (!ConfigOutputMethod(avctx, pFrame)) +- return VC_FLUSHED; +- +- outputSurface = outputSurfaces[surfaceNum]; +- +- CheckFeatures(); +- +- if (( (int)outRectVid.x1 != OutWidth ) || +- ( (int)outRectVid.y1 != OutHeight )) +- { +- outRectVid.x0 = 0; +- outRectVid.y0 = 0; +- outRectVid.x1 = OutWidth; +- outRectVid.y1 = OutHeight; +- } +- +- EDEINTERLACEMODE mode = g_settings.m_currentVideoSettings.m_DeinterlaceMode; +- EINTERLACEMETHOD method = g_settings.m_currentVideoSettings.m_InterlaceMethod; +- if (method == VS_INTERLACEMETHOD_AUTO) +- method = AutoInterlaceMethod(); +- + if(pFrame) + { // we have a new frame from decoder + +@@ -1393,7 +892,10 @@ int CVDPAU::Decode(AVCodecContext *avctx, AVFrame *pFrame) + if(!render) // old style ffmpeg gave data on plane 0 + render = (vdpau_render_state*)pFrame->data[0]; + if(!render) ++ { ++ CLog::Log(LOGERROR, "CVDPAU::Decode: no valid frame"); + return VC_ERROR; ++ } + + // ffmpeg vc-1 decoder does not flush, make sure the data buffer is still valid + if (!IsSurfaceValid(render)) +@@ -1402,258 +904,166 @@ int CVDPAU::Decode(AVCodecContext *avctx, AVFrame *pFrame) + return VC_BUFFER; + } + ++ CSingleLock lock(m_videoSurfaceSec); + render->state |= FF_VDPAU_STATE_USED_FOR_RENDER; ++ lock.Leave(); + +- ClearUsedForRender(&past[0]); +- past[0] = past[1]; +- past[1] = current; +- current = future; +- future = render; ++ // send frame to output for processing ++ CVdpauDecodedPicture pic; ++ memset(&pic.DVDPic, 0, sizeof(pic.DVDPic)); ++ ((CDVDVideoCodecFFmpeg*)avctx->opaque)->GetPictureCommon(&pic.DVDPic); ++ pic.render = render; ++ m_bufferStats.IncDecoded(); ++ m_vdpauOutput.m_dataPort.SendOutMessage(COutputDataProtocol::NEWFRAME, &pic, sizeof(pic)); + +- DVDVideoPicture DVDPic; +- memset(&DVDPic, 0, sizeof(DVDVideoPicture)); +- ((CDVDVideoCodecFFmpeg*)avctx->opaque)->GetPictureCommon(&DVDPic); +- m_DVDVideoPics.push(DVDPic); ++ m_codecControl = pic.DVDPic.iFlags & (DVP_FLAG_DRAIN | DVP_FLAG_NO_POSTPROC); ++ } + +- int pics = m_DVDVideoPics.size(); +- if (pics < 2) +- return VC_BUFFER; +- else if (pics > 2) ++ int retval = 0; ++ uint16_t decoded, processed, render; ++ Message *msg; ++ while (m_vdpauOutput.m_controlPort.ReceiveInMessage(&msg)) ++ { ++ if (msg->signal == COutputControlProtocol::ERROR) + { +- // this should not normally happen +- CLog::Log(LOGERROR, "CVDPAU::Decode - invalid number of pictures in queue"); +- while (pics-- != 2) +- m_DVDVideoPics.pop(); ++ m_DisplayState = VDPAU_ERROR; ++ retval |= VC_ERROR; + } ++ msg->Release(); ++ } + +- if (mode == VS_DEINTERLACEMODE_FORCE +- || (mode == VS_DEINTERLACEMODE_AUTO && m_DVDVideoPics.front().iFlags & DVP_FLAG_INTERLACED)) ++ m_bufferStats.Get(decoded, processed, render); ++ ++ uint64_t startTime = CurrentHostCounter(); ++ while (!retval) ++ { ++ if (m_vdpauOutput.m_dataPort.ReceiveInMessage(&msg)) + { +- if((method == VS_INTERLACEMETHOD_AUTO_ION +- || method == VS_INTERLACEMETHOD_VDPAU_BOB +- || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL +- || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF +- || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL +- || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF +- || method == VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE )) ++ if (msg->signal == COutputDataProtocol::PICTURE) + { +- if((method == VS_INTERLACEMETHOD_AUTO_ION && vid_height > 576) +- || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF +- || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF +- || avctx->skip_frame == AVDISCARD_NONREF) +- m_mixerstep = 0; +- else +- m_mixerstep = 1; +- +- if(m_DVDVideoPics.front().iFlags & DVP_FLAG_TOP_FIELD_FIRST) +- m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD; +- else +- m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD; ++ if (m_presentPicture) ++ { ++ m_presentPicture->ReturnUnused(); ++ m_presentPicture = 0; ++ } ++ ++ m_presentPicture = *(CVdpauRenderPicture**)msg->data; ++ m_presentPicture->vdpau = this; ++ m_bufferStats.DecRender(); ++ m_bufferStats.Get(decoded, processed, render); ++ retval |= VC_PICTURE; ++ msg->Release(); ++ break; ++ } ++ msg->Release(); ++ } ++ else if (m_vdpauOutput.m_controlPort.ReceiveInMessage(&msg)) ++ { ++ if (msg->signal == COutputControlProtocol::STATS) ++ { ++ m_bufferStats.Get(decoded, processed, render); + } + else + { +- m_mixerstep = 0; +- m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME; ++ m_DisplayState = VDPAU_ERROR; ++ retval |= VC_ERROR; + } ++ msg->Release(); + } +- else ++ ++ if ((m_codecControl & DVP_FLAG_DRAIN)) + { +- m_mixerstep = 0; +- m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME; ++ if (decoded + processed + render < 4) ++ { ++ retval |= VC_BUFFER; ++ } + } +- +- } +- else if(m_mixerstep == 1) +- { // no new frame given, output second field of old frame +- +- if(avctx->skip_frame == AVDISCARD_NONREF) ++ else + { +- ClearUsedForRender(&past[1]); +- m_DVDVideoPics.pop(); +- return VC_BUFFER; ++ if (decoded < 4 && (processed + render) < 3) ++ { ++ retval |= VC_BUFFER; ++ } + } + +- m_mixerstep = 2; +- if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD) +- m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD; +- else +- m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD; ++ if (!retval && !m_inMsgEvent.WaitMSec(2000)) ++ break; + } +- else ++ uint64_t diff = CurrentHostCounter() - startTime; ++ if (retval & VC_PICTURE) + { +- CLog::Log(LOGERROR, "CVDPAU::Decode - invalid mixer state reached"); +- return VC_BUFFER; ++ m_bufferStats.SetParams(diff, m_codecControl); + } ++ if (diff*1000/CurrentHostFrequency() > 50) ++ CLog::Log(LOGDEBUG,"CVDPAU::Decode long wait: %d", (int)((diff*1000)/CurrentHostFrequency())); + +- VdpVideoSurface past_surfaces[2] = { VDP_INVALID_HANDLE, VDP_INVALID_HANDLE }; +- VdpVideoSurface futu_surfaces[1] = { VDP_INVALID_HANDLE }; +- +- if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME) ++ if (!retval) + { +- if (past[0]) +- past_surfaces[1] = past[0]->surface; +- if (past[1]) +- past_surfaces[0] = past[1]->surface; +- futu_surfaces[0] = future->surface; ++ CLog::Log(LOGERROR, "VDPAU::%s - timed out waiting for output message", __FUNCTION__); ++ m_DisplayState = VDPAU_ERROR; ++ retval |= VC_ERROR; + } +- else +- { +- if(m_mixerstep == 1) +- { // first field +- if (past[1]) +- { +- past_surfaces[1] = past[1]->surface; +- past_surfaces[0] = past[1]->surface; +- } +- futu_surfaces[0] = current->surface; +- } +- else +- { // second field +- if (past[1]) +- past_surfaces[1] = past[1]->surface; +- past_surfaces[0] = current->surface; +- futu_surfaces[0] = future->surface; +- } +- } +- +- vdp_st = vdp_presentation_queue_block_until_surface_idle(vdp_flip_queue,outputSurface,&time); +- +- VdpRect sourceRect = {0,0,vid_width, vid_height}; +- +- vdp_st = vdp_video_mixer_render(videoMixer, +- VDP_INVALID_HANDLE, +- 0, +- m_mixerfield, +- 2, +- past_surfaces, +- current->surface, +- 1, +- futu_surfaces, +- &sourceRect, +- outputSurface, +- &(outRectVid), +- &(outRectVid), +- 0, +- NULL); +- CheckStatus(vdp_st, __LINE__); + +- surfaceNum++; +- if (surfaceNum >= totalAvailableOutputSurfaces) surfaceNum = 0; ++ return retval; ++} + +- if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME) +- { +- ClearUsedForRender(&past[0]); +- return VC_BUFFER | VC_PICTURE; +- } +- else +- { +- // in order to clip top and bottom lines when de-interlacing +- // we black those lines as a work around for not working +- // background colour using the mixer +- // pixel perfect is preferred over overscanning or zooming ++bool CDecoder::GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture) ++{ ++ CSingleLock lock(m_DecoderSection); + +- VdpRect clipRect = outRectVid; +- clipRect.y1 = clipRect.y0 + 2; +- uint32_t *data[] = {m_BlackBar}; +- uint32_t pitches[] = {outRectVid.x1}; +- vdp_st = vdp_output_surface_put_bits_native(outputSurface, +- (void**)data, +- pitches, +- &clipRect); +- CheckStatus(vdp_st, __LINE__); ++ if (m_DisplayState != VDPAU_OPEN) ++ return false; + +- clipRect = outRectVid; +- clipRect.y0 = clipRect.y1 - 2; +- vdp_st = vdp_output_surface_put_bits_native(outputSurface, +- (void**)data, +- pitches, +- &clipRect); +- CheckStatus(vdp_st, __LINE__); ++ *picture = m_presentPicture->DVDPic; ++ picture->vdpau = m_presentPicture; + +- if(m_mixerstep == 1) +- return VC_PICTURE; +- else +- { +- ClearUsedForRender(&past[1]); +- return VC_BUFFER | VC_PICTURE; +- } +- } ++ return true; + } + +-bool CVDPAU::GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture) ++void CDecoder::Reset() + { +- CSharedLock lock(m_DecoderSection); +- +- { CSharedLock dLock(m_DisplaySection); +- if (m_DisplayState != VDPAU_OPEN) +- return false; +- } +- +- *picture = m_DVDVideoPics.front(); +- // if this is the first field of an interlaced frame, we'll need +- // this same picture for the second field later +- if (m_mixerstep != 1) +- m_DVDVideoPics.pop(); ++ CSingleLock lock(m_DecoderSection); + +- picture->format = RENDER_FMT_VDPAU; +- picture->iFlags &= DVP_FLAG_DROPPED; +- picture->iWidth = OutWidth; +- picture->iHeight = OutHeight; +- picture->vdpau = this; ++ if (!m_vdpauConfigured) ++ return; + +- if(m_mixerstep) ++ Message *reply; ++ if (m_vdpauOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::FLUSH, ++ &reply, ++ 2000)) + { +- picture->iRepeatPicture = -0.5; +- if(m_mixerstep > 1) ++ bool success = reply->signal == COutputControlProtocol::ACC ? true : false; ++ reply->Release(); ++ if (!success) + { +- picture->dts = DVD_NOPTS_VALUE; +- picture->pts = DVD_NOPTS_VALUE; ++ CLog::Log(LOGERROR, "VDPAU::%s - flush returned error", __FUNCTION__); ++ m_DisplayState = VDPAU_ERROR; + } ++ else ++ m_bufferStats.Reset(); ++ } ++ else ++ { ++ CLog::Log(LOGERROR, "VDPAU::%s - flush timed out", __FUNCTION__); ++ m_DisplayState = VDPAU_ERROR; + } +- return true; + } + +-void CVDPAU::Reset() ++bool CDecoder::CanSkipDeint() + { +- // invalidate surfaces and picture queue when seeking +- ClearUsedForRender(&past[0]); +- ClearUsedForRender(&past[1]); +- ClearUsedForRender(¤t); +- ClearUsedForRender(&future); +- +- while (!m_DVDVideoPics.empty()) +- m_DVDVideoPics.pop(); ++ return m_bufferStats.CanSkipDeint(); + } + +-void CVDPAU::Present() ++void CDecoder::ReturnRenderPicture(CVdpauRenderPicture *renderPic) + { +- //CLog::Log(LOGNOTICE,"%s",__FUNCTION__); +- VdpStatus vdp_st; +- +- CSharedLock lock(m_DecoderSection); +- +- { CSharedLock dLock(m_DisplaySection); +- if (m_DisplayState != VDPAU_OPEN) +- return; +- } +- +- presentSurface = outputSurface; +- +- vdp_st = vdp_presentation_queue_display(vdp_flip_queue, +- presentSurface, +- 0, +- 0, +- 0); +- CheckStatus(vdp_st, __LINE__); ++ m_vdpauOutput.m_dataPort.SendOutMessage(COutputDataProtocol::RETURNPIC, &renderPic, sizeof(renderPic)); + } + +-bool CVDPAU::CheckStatus(VdpStatus vdp_st, int line) ++bool CDecoder::CheckStatus(VdpStatus vdp_st, int line) + { + if (vdp_st != VDP_STATUS_OK) + { +- CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) at %s:%d\n", vdp_get_error_string(vdp_st), vdp_st, __FILE__, line); +- +- CExclusiveLock lock(m_DisplaySection); ++ CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) at %s:%d\n", m_vdpauConfig.vdpProcs.vdp_get_error_string(vdp_st), vdp_st, __FILE__, line); + + if(m_DisplayState == VDPAU_OPEN) + { +@@ -1671,4 +1081,2422 @@ bool CVDPAU::CheckStatus(VdpStatus vdp_st, int line) + return false; + } + ++//----------------------------------------------------------------------------- ++// RenderPicture ++//----------------------------------------------------------------------------- ++ ++CVdpauRenderPicture* CVdpauRenderPicture::Acquire() ++{ ++ CSingleLock lock(*renderPicSection); ++ ++ if (refCount == 0) ++ vdpau->Acquire(); ++ ++ refCount++; ++ return this; ++} ++ ++long CVdpauRenderPicture::Release() ++{ ++ CSingleLock lock(*renderPicSection); ++ ++ refCount--; ++ if (refCount > 0) ++ return refCount; ++ ++ lock.Leave(); ++ vdpau->ReturnRenderPicture(this); ++ vdpau->ReleasePicReference(); ++ ++ return refCount; ++} ++ ++void CVdpauRenderPicture::ReturnUnused() ++{ ++ { CSingleLock lock(*renderPicSection); ++ if (refCount > 0) ++ return; ++ } ++ if (vdpau) ++ vdpau->ReturnRenderPicture(this); ++} ++//----------------------------------------------------------------------------- ++// Mixer ++//----------------------------------------------------------------------------- ++CMixer::CMixer(CEvent *inMsgEvent) : ++ CThread("Vdpau Mixer Thread"), ++ m_controlPort("ControlPort", inMsgEvent, &m_outMsgEvent), ++ m_dataPort("DataPort", inMsgEvent, &m_outMsgEvent) ++{ ++ m_inMsgEvent = inMsgEvent; ++} ++ ++CMixer::~CMixer() ++{ ++ Dispose(); ++} ++ ++void CMixer::Start() ++{ ++ Create(); ++} ++ ++void CMixer::Dispose() ++{ ++ m_bStop = true; ++ m_outMsgEvent.Set(); ++ StopThread(); ++ ++ m_controlPort.Purge(); ++ m_dataPort.Purge(); ++} ++ ++void CMixer::OnStartup() ++{ ++ CLog::Log(LOGNOTICE, "CMixer::OnStartup: Output Thread created"); ++} ++ ++void CMixer::OnExit() ++{ ++ CLog::Log(LOGNOTICE, "CMixer::OnExit: Output Thread terminated"); ++} ++ ++enum MIXER_STATES ++{ ++ M_TOP = 0, // 0 ++ M_TOP_ERROR, // 1 ++ M_TOP_UNCONFIGURED, // 2 ++ M_TOP_CONFIGURED, // 3 ++ M_TOP_CONFIGURED_WAIT1, // 4 ++ M_TOP_CONFIGURED_STEP1, // 5 ++ M_TOP_CONFIGURED_WAIT2, // 6 ++ M_TOP_CONFIGURED_STEP2, // 7 ++}; ++ ++int MIXER_parentStates[] = { ++ -1, ++ 0, //TOP_ERROR ++ 0, //TOP_UNCONFIGURED ++ 0, //TOP_CONFIGURED ++ 3, //TOP_CONFIGURED_WAIT1 ++ 3, //TOP_CONFIGURED_STEP1 ++ 3, //TOP_CONFIGURED_WAIT2 ++ 3, //TOP_CONFIGURED_STEP2 ++}; ++ ++void CMixer::StateMachine(int signal, Protocol *port, Message *msg) ++{ ++ for (int state = m_state; ; state = MIXER_parentStates[state]) ++ { ++ switch (state) ++ { ++ case M_TOP: // TOP ++ if (port == &m_controlPort) ++ { ++ switch (signal) ++ { ++ case CMixerControlProtocol::FLUSH: ++ Flush(); ++ msg->Reply(CMixerControlProtocol::ACC); ++ return; ++ default: ++ break; ++ } ++ } ++ { ++ std::string portName = port == NULL ? "timer" : port->portName; ++ CLog::Log(LOGWARNING, "CMixer::%s - signal: %d form port: %s not handled for state: %d", __FUNCTION__, signal, portName.c_str(), m_state); ++ } ++ return; ++ ++ case M_TOP_ERROR: // TOP ++ break; ++ ++ case M_TOP_UNCONFIGURED: ++ if (port == &m_controlPort) ++ { ++ switch (signal) ++ { ++ case CMixerControlProtocol::INIT: ++ CVdpauConfig *data; ++ data = (CVdpauConfig*)msg->data; ++ if (data) ++ { ++ m_config = *data; ++ } ++ Init(); ++ if (!m_vdpError) ++ { ++ m_state = M_TOP_CONFIGURED_WAIT1; ++ msg->Reply(CMixerControlProtocol::ACC); ++ } ++ else ++ { ++ msg->Reply(CMixerControlProtocol::ERROR); ++ } ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case M_TOP_CONFIGURED: ++ if (port == &m_dataPort) ++ { ++ switch (signal) ++ { ++ case CMixerDataProtocol::FRAME: ++ CVdpauDecodedPicture *frame; ++ frame = (CVdpauDecodedPicture*)msg->data; ++ if (frame) ++ { ++ m_decodedPics.push(*frame); ++ } ++ m_extTimeout = 0; ++ return; ++ case CMixerDataProtocol::BUFFER: ++ VdpOutputSurface *surf; ++ surf = (VdpOutputSurface*)msg->data; ++ if (surf) ++ { ++ m_outputSurfaces.push(*surf); ++ } ++ m_extTimeout = 0; ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case M_TOP_CONFIGURED_WAIT1: ++ if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case CMixerControlProtocol::TIMEOUT: ++ if (!m_decodedPics.empty() && !m_outputSurfaces.empty()) ++ { ++ m_state = M_TOP_CONFIGURED_STEP1; ++ m_bStateMachineSelfTrigger = true; ++ } ++ else ++ { ++// if (m_extTimeout != 0) ++// { ++// SetPostProcFeatures(false); ++// CLog::Log(LOGWARNING,"CVDPAU::Mixer timeout - decoded: %d, outputSurf: %d", (int)m_decodedPics.size(), (int)m_outputSurfaces.size()); ++// } ++ m_extTimeout = 100; ++ } ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case M_TOP_CONFIGURED_STEP1: ++ if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case CMixerControlProtocol::TIMEOUT: ++ m_mixerInput.push_front(m_decodedPics.front()); ++ m_decodedPics.pop(); ++ if (m_mixerInput.size() < 2) ++ { ++ m_state = M_TOP_CONFIGURED_WAIT1; ++ m_extTimeout = 0; ++ return; ++ } ++ InitCycle(); ++ ProcessPicture(); ++ if (m_vdpError) ++ { ++ m_state = M_TOP_CONFIGURED_WAIT1; ++ m_extTimeout = 1000; ++ return; ++ } ++ if (m_processPicture.DVDPic.format != RENDER_FMT_VDPAU_420) ++ m_outputSurfaces.pop(); ++ m_config.stats->IncProcessed(); ++ m_config.stats->DecDecoded(); ++ m_dataPort.SendInMessage(CMixerDataProtocol::PICTURE,&m_processPicture,sizeof(m_processPicture)); ++ if (m_mixersteps > 1) ++ { ++ m_state = M_TOP_CONFIGURED_WAIT2; ++ m_extTimeout = 0; ++ } ++ else ++ { ++ FiniCycle(); ++ m_state = M_TOP_CONFIGURED_WAIT1; ++ m_extTimeout = 0; ++ } ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case M_TOP_CONFIGURED_WAIT2: ++ if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case CMixerControlProtocol::TIMEOUT: ++ if (!m_outputSurfaces.empty()) ++ { ++ m_state = M_TOP_CONFIGURED_STEP2; ++ m_bStateMachineSelfTrigger = true; ++ } ++ else ++ { ++// if (m_extTimeout != 0) ++// { ++// SetPostProcFeatures(false); ++// CLog::Log(LOGNOTICE,"---mixer wait2 decoded: %d, outputSurf: %d", (int)m_decodedPics.size(), (int)m_outputSurfaces.size()); ++// } ++ m_extTimeout = 100; ++ } ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case M_TOP_CONFIGURED_STEP2: ++ if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case CMixerControlProtocol::TIMEOUT: ++ m_processPicture.outputSurface = m_outputSurfaces.front(); ++ m_mixerstep = 1; ++ ProcessPicture(); ++ if (m_vdpError) ++ { ++ m_state = M_TOP_CONFIGURED_WAIT1; ++ m_extTimeout = 1000; ++ return; ++ } ++ if (m_processPicture.DVDPic.format != RENDER_FMT_VDPAU_420) ++ m_outputSurfaces.pop(); ++ m_config.stats->IncProcessed(); ++ m_dataPort.SendInMessage(CMixerDataProtocol::PICTURE,&m_processPicture,sizeof(m_processPicture)); ++ FiniCycle(); ++ m_state = M_TOP_CONFIGURED_WAIT1; ++ m_extTimeout = 0; ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ default: // we are in no state, should not happen ++ CLog::Log(LOGERROR, "CMixer::%s - no valid state: %d", __FUNCTION__, m_state); ++ return; ++ } ++ } // for ++} ++ ++void CMixer::Process() ++{ ++ Message *msg; ++ Protocol *port; ++ bool gotMsg; ++ ++ m_state = M_TOP_UNCONFIGURED; ++ m_extTimeout = 1000; ++ m_bStateMachineSelfTrigger = false; ++ ++ while (!m_bStop) ++ { ++ gotMsg = false; ++ ++ if (m_bStateMachineSelfTrigger) ++ { ++ m_bStateMachineSelfTrigger = false; ++ // self trigger state machine ++ StateMachine(msg->signal, port, msg); ++ if (!m_bStateMachineSelfTrigger) ++ { ++ msg->Release(); ++ msg = NULL; ++ } ++ continue; ++ } ++ // check control port ++ else if (m_controlPort.ReceiveOutMessage(&msg)) ++ { ++ gotMsg = true; ++ port = &m_controlPort; ++ } ++ // check data port ++ else if (m_dataPort.ReceiveOutMessage(&msg)) ++ { ++ gotMsg = true; ++ port = &m_dataPort; ++ } ++ ++ if (gotMsg) ++ { ++ StateMachine(msg->signal, port, msg); ++ if (!m_bStateMachineSelfTrigger) ++ { ++ msg->Release(); ++ msg = NULL; ++ } ++ continue; ++ } ++ ++ // wait for message ++ else if (m_outMsgEvent.WaitMSec(m_extTimeout)) ++ { ++ continue; ++ } ++ // time out ++ else ++ { ++ msg = m_controlPort.GetMessage(); ++ msg->signal = CMixerControlProtocol::TIMEOUT; ++ port = 0; ++ // signal timeout to state machine ++ StateMachine(msg->signal, port, msg); ++ if (!m_bStateMachineSelfTrigger) ++ { ++ msg->Release(); ++ msg = NULL; ++ } ++ } ++ } ++ Uninit(); ++} ++ ++void CMixer::CreateVdpauMixer() ++{ ++ CLog::Log(LOGNOTICE, " (VDPAU) Creating the video mixer"); ++ ++ InitCSCMatrix(m_config.vidWidth); ++ ++ VdpVideoMixerParameter parameters[] = { ++ VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH, ++ VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT, ++ VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE}; ++ ++ void const * parameter_values[] = { ++ &m_config.surfaceWidth, ++ &m_config.surfaceHeight, ++ &m_config.vdpChromaType}; ++ ++ VdpStatus vdp_st = VDP_STATUS_ERROR; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_create(m_config.vdpDevice, ++ m_config.featureCount, ++ m_config.vdpFeatures, ++ ARSIZE(parameters), ++ parameters, ++ parameter_values, ++ &m_videoMixer); ++ CheckStatus(vdp_st, __LINE__); ++ ++ // create 3 pitches of black lines needed for clipping top ++ // and bottom lines when de-interlacing ++ m_BlackBar = new uint32_t[3*m_config.outWidth]; ++ memset(m_BlackBar, 0, 3*m_config.outWidth*sizeof(uint32_t)); ++ ++} ++ ++void CMixer::InitCSCMatrix(int Width) ++{ ++ VdpStatus vdp_st; ++ m_Procamp.struct_version = VDP_PROCAMP_VERSION; ++ m_Procamp.brightness = 0.0; ++ m_Procamp.contrast = 1.0; ++ m_Procamp.saturation = 1.0; ++ m_Procamp.hue = 0; ++ vdp_st = m_config.vdpProcs.vdp_generate_csc_matrix(&m_Procamp, ++ (Width < 1000)? VDP_COLOR_STANDARD_ITUR_BT_601 : VDP_COLOR_STANDARD_ITUR_BT_709, ++ &m_CSCMatrix); ++ CheckStatus(vdp_st, __LINE__); ++} ++ ++void CMixer::CheckFeatures() ++{ ++ if (m_Upscale != m_config.upscale) ++ { ++ SetHWUpscaling(); ++ m_Upscale = m_config.upscale; ++ } ++ if (m_Brightness != g_settings.m_currentVideoSettings.m_Brightness || ++ m_Contrast != g_settings.m_currentVideoSettings.m_Contrast) ++ { ++ SetColor(); ++ m_Brightness = g_settings.m_currentVideoSettings.m_Brightness; ++ m_Contrast = g_settings.m_currentVideoSettings.m_Contrast; ++ } ++ if (m_NoiseReduction != g_settings.m_currentVideoSettings.m_NoiseReduction) ++ { ++ m_NoiseReduction = g_settings.m_currentVideoSettings.m_NoiseReduction; ++ SetNoiseReduction(); ++ } ++ if (m_Sharpness != g_settings.m_currentVideoSettings.m_Sharpness) ++ { ++ m_Sharpness = g_settings.m_currentVideoSettings.m_Sharpness; ++ SetSharpness(); ++ } ++ if (m_DeintMode != g_settings.m_currentVideoSettings.m_DeinterlaceMode || ++ m_Deint != g_settings.m_currentVideoSettings.m_InterlaceMethod) ++ { ++ m_DeintMode = g_settings.m_currentVideoSettings.m_DeinterlaceMode; ++ m_Deint = g_settings.m_currentVideoSettings.m_InterlaceMethod; ++ SetDeinterlacing(); ++ } ++} ++ ++void CMixer::SetPostProcFeatures(bool postProcEnabled) ++{ ++ if (m_PostProc != postProcEnabled) ++ { ++ if (postProcEnabled) ++ { ++ SetNoiseReduction(); ++ SetSharpness(); ++ SetDeinterlacing(); ++ SetHWUpscaling(); ++ } ++ else ++ PostProcOff(); ++ m_PostProc = postProcEnabled; ++ } ++} ++ ++void CMixer::PostProcOff() ++{ ++ VdpStatus vdp_st; ++ ++ if (m_videoMixer == VDP_INVALID_HANDLE) ++ return; ++ ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL, ++ VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL, ++ VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE}; ++ ++ VdpBool enabled[]={0,0,0}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ CheckStatus(vdp_st, __LINE__); ++ ++ if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION}; ++ ++ VdpBool enabled[]={0}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ CheckStatus(vdp_st, __LINE__); ++ } ++ ++ if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_SHARPNESS)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_SHARPNESS}; ++ ++ VdpBool enabled[]={0}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ CheckStatus(vdp_st, __LINE__); ++ } ++ ++ DisableHQScaling(); ++} ++ ++ ++bool CMixer::GenerateStudioCSCMatrix(VdpColorStandard colorStandard, VdpCSCMatrix &studioCSCMatrix) ++{ ++ // instead use studioCSCKCoeffs601[3], studioCSCKCoeffs709[3] to generate float[3][4] matrix (float studioCSC[3][4]) ++ // m00 = mRY = red: luma factor (contrast factor) (1.0) ++ // m10 = mGY = green: luma factor (contrast factor) (1.0) ++ // m20 = mBY = blue: luma factor (contrast factor) (1.0) ++ // ++ // m01 = mRB = red: blue color diff coeff (0.0) ++ // m11 = mGB = green: blue color diff coeff (-2Kb(1-Kb)/(Kg)) ++ // m21 = mBB = blue: blue color diff coeff ((1-Kb)/0.5) ++ // ++ // m02 = mRR = red: red color diff coeff ((1-Kr)/0.5) ++ // m12 = mGR = green: red color diff coeff (-2Kr(1-Kr)/(Kg)) ++ // m22 = mBR = blue: red color diff coeff (0.0) ++ // ++ // m03 = mRC = red: colour zero offset (brightness factor) (-(1-Kr)/0.5 * (128/255)) ++ // m13 = mGC = green: colour zero offset (brightness factor) ((256/255) * (Kb(1-Kb) + Kr(1-Kr)) / Kg) ++ // m23 = mBC = blue: colour zero offset (brightness factor) (-(1-Kb)/0.5 * (128/255)) ++ ++ // columns ++ int Y = 0; ++ int Cb = 1; ++ int Cr = 2; ++ int C = 3; ++ // rows ++ int R = 0; ++ int G = 1; ++ int B = 2; ++ // colour standard coefficients for red, geen, blue ++ double Kr, Kg, Kb; ++ // colour diff zero position (use standard 8-bit coding precision) ++ double CDZ = 128; //256*0.5 ++ // range excursion (use standard 8-bit coding precision) ++ double EXC = 255; //256-1 ++ ++ if (colorStandard == VDP_COLOR_STANDARD_ITUR_BT_601) ++ { ++ Kr = studioCSCKCoeffs601[0]; ++ Kg = studioCSCKCoeffs601[1]; ++ Kb = studioCSCKCoeffs601[2]; ++ } ++ else // assume VDP_COLOR_STANDARD_ITUR_BT_709 ++ { ++ Kr = studioCSCKCoeffs709[0]; ++ Kg = studioCSCKCoeffs709[1]; ++ Kb = studioCSCKCoeffs709[2]; ++ } ++ // we keep luma unscaled to retain the levels present in source so that 16-235 luma is converted to RGB 16-235 ++ studioCSCMatrix[R][Y] = 1.0; ++ studioCSCMatrix[G][Y] = 1.0; ++ studioCSCMatrix[B][Y] = 1.0; ++ ++ studioCSCMatrix[R][Cb] = 0.0; ++ studioCSCMatrix[G][Cb] = (double)-2 * Kb * (1 - Kb) / Kg; ++ studioCSCMatrix[B][Cb] = (double)(1 - Kb) / 0.5; ++ ++ studioCSCMatrix[R][Cr] = (double)(1 - Kr) / 0.5; ++ studioCSCMatrix[G][Cr] = (double)-2 * Kr * (1 - Kr) / Kg; ++ studioCSCMatrix[B][Cr] = 0.0; ++ ++ studioCSCMatrix[R][C] = (double)-1 * studioCSCMatrix[R][Cr] * CDZ/EXC; ++ studioCSCMatrix[G][C] = (double)-1 * (studioCSCMatrix[G][Cb] + studioCSCMatrix[G][Cr]) * CDZ/EXC; ++ studioCSCMatrix[B][C] = (double)-1 * studioCSCMatrix[B][Cb] * CDZ/EXC; ++ ++ return true; ++} ++ ++void CMixer::SetColor() ++{ ++ VdpStatus vdp_st; ++ ++ if (m_Brightness != g_settings.m_currentVideoSettings.m_Brightness) ++ m_Procamp.brightness = (float)((g_settings.m_currentVideoSettings.m_Brightness)-50) / 100; ++ if (m_Contrast != g_settings.m_currentVideoSettings.m_Contrast) ++ m_Procamp.contrast = (float)((g_settings.m_currentVideoSettings.m_Contrast)+50) / 100; ++ ++ VdpColorStandard colorStandard; ++// if(vid_height >= 600 || vid_width > 1024) ++ if(m_config.surfaceWidth > 1000) ++ colorStandard = VDP_COLOR_STANDARD_ITUR_BT_709; ++ //vdp_st = vdp_generate_csc_matrix(&m_Procamp, VDP_COLOR_STANDARD_ITUR_BT_709, &m_CSCMatrix); ++ else ++ colorStandard = VDP_COLOR_STANDARD_ITUR_BT_601; ++ //vdp_st = vdp_generate_csc_matrix(&m_Procamp, VDP_COLOR_STANDARD_ITUR_BT_601, &m_CSCMatrix); ++ ++ VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX }; ++ if (g_guiSettings.GetBool("videoplayer.vdpaustudiolevel")) ++ { ++ float studioCSC[3][4]; ++ GenerateStudioCSCMatrix(colorStandard, studioCSC); ++ void const * pm_CSCMatix[] = { &studioCSC }; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix); ++ } ++ else ++ { ++ vdp_st = m_config.vdpProcs.vdp_generate_csc_matrix(&m_Procamp, colorStandard, &m_CSCMatrix); ++ void const * pm_CSCMatix[] = { &m_CSCMatrix }; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix); ++ } ++ CheckStatus(vdp_st, __LINE__); ++} ++ ++void CMixer::SetNoiseReduction() ++{ ++ if(!m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION)) ++ return; ++ ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION }; ++ VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL }; ++ VdpStatus vdp_st; ++ ++ if (!g_settings.m_currentVideoSettings.m_NoiseReduction) ++ { ++ VdpBool enabled[]= {0}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ CheckStatus(vdp_st, __LINE__); ++ return; ++ } ++ VdpBool enabled[]={1}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ CheckStatus(vdp_st, __LINE__); ++ void* nr[] = { &g_settings.m_currentVideoSettings.m_NoiseReduction }; ++ CLog::Log(LOGNOTICE,"Setting Noise Reduction to %f",g_settings.m_currentVideoSettings.m_NoiseReduction); ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, nr); ++ CheckStatus(vdp_st, __LINE__); ++} ++ ++void CMixer::SetSharpness() ++{ ++ if(!m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_SHARPNESS)) ++ return; ++ ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_SHARPNESS }; ++ VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL }; ++ VdpStatus vdp_st; ++ ++ if (!g_settings.m_currentVideoSettings.m_Sharpness) ++ { ++ VdpBool enabled[]={0}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ CheckStatus(vdp_st, __LINE__); ++ return; ++ } ++ VdpBool enabled[]={1}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ CheckStatus(vdp_st, __LINE__); ++ void* sh[] = { &g_settings.m_currentVideoSettings.m_Sharpness }; ++ CLog::Log(LOGNOTICE,"Setting Sharpness to %f",g_settings.m_currentVideoSettings.m_Sharpness); ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, sh); ++ CheckStatus(vdp_st, __LINE__); ++} ++ ++EINTERLACEMETHOD CMixer::GetDeinterlacingMethod(bool log /* = false */) ++{ ++ EINTERLACEMETHOD method = g_settings.m_currentVideoSettings.m_InterlaceMethod; ++ if (method == VS_INTERLACEMETHOD_AUTO) ++ { ++ int deint = -1; ++// if (m_config.outHeight >= 720) ++// deint = g_advancedSettings.m_videoVDPAUdeintHD; ++// else ++// deint = g_advancedSettings.m_videoVDPAUdeintSD; ++ ++ if (deint != -1) ++ { ++ if (m_config.vdpau->Supports(EINTERLACEMETHOD(deint))) ++ { ++ method = EINTERLACEMETHOD(deint); ++ if (log) ++ CLog::Log(LOGNOTICE, "CVDPAU::GetDeinterlacingMethod: set de-interlacing to %d", deint); ++ } ++ else ++ { ++ if (log) ++ CLog::Log(LOGWARNING, "CVDPAU::GetDeinterlacingMethod: method for de-interlacing (advanced settings) not supported"); ++ } ++ } ++ } ++ return method; ++} ++ ++void CMixer::SetDeinterlacing() ++{ ++ VdpStatus vdp_st; ++ ++ if (m_videoMixer == VDP_INVALID_HANDLE) ++ return; ++ ++ EDEINTERLACEMODE mode = g_settings.m_currentVideoSettings.m_DeinterlaceMode; ++ EINTERLACEMETHOD method = GetDeinterlacingMethod(true); ++ ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL, ++ VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL, ++ VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE }; ++ ++ if (mode == VS_DEINTERLACEMODE_OFF) ++ { ++ VdpBool enabled[] = {0,0,0}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ } ++ else ++ { ++ if (method == VS_INTERLACEMETHOD_AUTO) ++ { ++ VdpBool enabled[] = {1,0,0}; ++ if (g_advancedSettings.m_videoVDPAUtelecine) ++ enabled[2] = 1; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ } ++ else if (method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL ++ || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF) ++ { ++ VdpBool enabled[] = {1,0,0}; ++ if (g_advancedSettings.m_videoVDPAUtelecine) ++ enabled[2] = 1; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ } ++ else if (method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL ++ || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF) ++ { ++ VdpBool enabled[] = {1,1,0}; ++ if (g_advancedSettings.m_videoVDPAUtelecine) ++ enabled[2] = 1; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ } ++ else ++ { ++ VdpBool enabled[]={0,0,0}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ } ++ } ++ CheckStatus(vdp_st, __LINE__); ++ ++ SetDeintSkipChroma(); ++ ++ m_config.useInteropYuv = g_guiSettings.GetBool("videoplayer.usevdpauinteropyuv"); ++} ++ ++void CMixer::SetDeintSkipChroma() ++{ ++ VdpVideoMixerAttribute attribute[] = { VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE}; ++ VdpStatus vdp_st; ++ ++ uint8_t val; ++ if (g_advancedSettings.m_videoVDPAUdeintSkipChromaHD && m_config.outHeight >= 720) ++ val = 1; ++ else ++ val = 0; ++ ++ void const *values[]={&val}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attribute), attribute, values); ++ ++ CheckStatus(vdp_st, __LINE__); ++} ++ ++void CMixer::SetHWUpscaling() ++{ ++#ifdef VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 ++ ++ VdpStatus vdp_st; ++ VdpBool enabled[]={1}; ++ switch (m_config.upscale) ++ { ++ case 9: ++ if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9 }; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ break; ++ } ++ case 8: ++ if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8 }; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ break; ++ } ++ case 7: ++ if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7 }; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ break; ++ } ++ case 6: ++ if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6 }; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ break; ++ } ++ case 5: ++ if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5 }; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ break; ++ } ++ case 4: ++ if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4 }; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ break; ++ } ++ case 3: ++ if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3 }; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ break; ++ } ++ case 2: ++ if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2 }; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ break; ++ } ++ case 1: ++ if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 }; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ break; ++ } ++ default: ++ DisableHQScaling(); ++ return; ++ } ++ CheckStatus(vdp_st, __LINE__); ++#endif ++} ++ ++void CMixer::DisableHQScaling() ++{ ++ VdpStatus vdp_st; ++ ++ if (m_videoMixer == VDP_INVALID_HANDLE) ++ return; ++ ++ if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 }; ++ VdpBool enabled[]={0}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ CheckStatus(vdp_st, __LINE__); ++ } ++ ++ if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2 }; ++ VdpBool enabled[]={0}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ CheckStatus(vdp_st, __LINE__); ++ } ++ ++ if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3 }; ++ VdpBool enabled[]={0}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ CheckStatus(vdp_st, __LINE__); ++ } ++ ++ if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4 }; ++ VdpBool enabled[]={0}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ CheckStatus(vdp_st, __LINE__); ++ } ++ ++ if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5 }; ++ VdpBool enabled[]={0}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ CheckStatus(vdp_st, __LINE__); ++ } ++ ++ if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6 }; ++ VdpBool enabled[]={0}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ CheckStatus(vdp_st, __LINE__); ++ } ++ ++ if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7 }; ++ VdpBool enabled[]={0}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ CheckStatus(vdp_st, __LINE__); ++ } ++ ++ if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8 }; ++ VdpBool enabled[]={0}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ CheckStatus(vdp_st, __LINE__); ++ } ++ ++ if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9 }; ++ VdpBool enabled[]={0}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ CheckStatus(vdp_st, __LINE__); ++ } ++} ++ ++ ++void CMixer::Init() ++{ ++ m_Brightness = 0.0; ++ m_Contrast = 0.0; ++ m_NoiseReduction = 0.0; ++ m_Sharpness = 0.0; ++ m_DeintMode = 0; ++ m_Deint = 0; ++ m_PostProc = false; ++ m_vdpError = false; ++ ++ m_config.upscale = g_advancedSettings.m_videoVDPAUScaling; ++ m_config.useInteropYuv = g_guiSettings.GetBool("videoplayer.usevdpauinteropyuv"); ++ ++ CreateVdpauMixer(); ++} ++ ++void CMixer::Uninit() ++{ ++ Flush(); ++ while (!m_outputSurfaces.empty()) ++ { ++ m_outputSurfaces.pop(); ++ } ++ m_config.vdpProcs.vdp_video_mixer_destroy(m_videoMixer); ++} ++ ++void CMixer::Flush() ++{ ++ while (!m_mixerInput.empty()) ++ { ++ CVdpauDecodedPicture pic = m_mixerInput.back(); ++ m_mixerInput.pop_back(); ++ CSingleLock lock(*m_config.videoSurfaceSec); ++ if (pic.render) ++ pic.render->state &= ~FF_VDPAU_STATE_USED_FOR_RENDER; ++ } ++ while (!m_decodedPics.empty()) ++ { ++ CVdpauDecodedPicture pic = m_decodedPics.front(); ++ m_decodedPics.pop(); ++ CSingleLock lock(*m_config.videoSurfaceSec); ++ if (pic.render) ++ pic.render->state &= ~FF_VDPAU_STATE_USED_FOR_RENDER; ++ } ++ Message *msg; ++ while (m_dataPort.ReceiveOutMessage(&msg)) ++ { ++ if (msg->signal == CMixerDataProtocol::FRAME) ++ { ++ CVdpauDecodedPicture pic = *(CVdpauDecodedPicture*)msg->data; ++ CSingleLock lock(*m_config.videoSurfaceSec); ++ if (pic.render) ++ pic.render->state &= ~FF_VDPAU_STATE_USED_FOR_RENDER; ++ } ++ else if (msg->signal == CMixerDataProtocol::BUFFER) ++ { ++ VdpOutputSurface *surf; ++ surf = (VdpOutputSurface*)msg->data; ++ m_outputSurfaces.push(*surf); ++ } ++ msg->Release(); ++ } ++} ++ ++void CMixer::InitCycle() ++{ ++ CheckFeatures(); ++ uint64_t latency; ++ int flags; ++ m_config.stats->GetParams(latency, flags); ++ latency = (latency*1000)/CurrentHostFrequency(); ++ if (flags & DVP_FLAG_NO_POSTPROC) ++ SetPostProcFeatures(false); ++ else ++ SetPostProcFeatures(true); ++ ++ m_config.stats->SetCanSkipDeint(false); ++ ++ EDEINTERLACEMODE mode = g_settings.m_currentVideoSettings.m_DeinterlaceMode; ++ EINTERLACEMETHOD method = GetDeinterlacingMethod(); ++ bool interlaced = m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_INTERLACED; ++ ++ if (mode == VS_DEINTERLACEMODE_FORCE || ++ (mode == VS_DEINTERLACEMODE_AUTO && interlaced)) ++ { ++ if((method == VS_INTERLACEMETHOD_AUTO && interlaced) ++ || method == VS_INTERLACEMETHOD_VDPAU_BOB ++ || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL ++ || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF ++ || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL ++ || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF ++ || method == VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE ) ++ { ++ if(method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF ++ || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF ++ || !g_graphicsContext.IsFullScreenVideo()) ++ m_mixersteps = 1; ++ else ++ { ++ m_mixersteps = 2; ++ m_config.stats->SetCanSkipDeint(true); ++ } ++ ++ if (m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_DROPDEINT) ++ { ++ m_mixersteps = 1; ++ } ++ ++ if(m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_TOP_FIELD_FIRST) ++ m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD; ++ else ++ m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD; ++ ++ m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU; ++ m_mixerInput[1].DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST | ++ DVP_FLAG_REPEAT_TOP_FIELD | ++ DVP_FLAG_INTERLACED); ++ m_config.useInteropYuv = false; ++ } ++ else if (method == VS_INTERLACEMETHOD_RENDER_BOB && m_config.useInteropYuv) ++ { ++ m_mixersteps = 1; ++ m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME; ++ m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU_420; ++ } ++ else ++ { ++ CLog::Log(LOGERROR, "CMixer::%s - interlace method not supported", __FUNCTION__); ++ m_mixersteps = 1; ++ m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME; ++ m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU; ++ m_mixerInput[1].DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST | ++ DVP_FLAG_REPEAT_TOP_FIELD | ++ DVP_FLAG_INTERLACED); ++ } ++ } ++ else ++ { ++ m_mixersteps = 1; ++ m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME; ++ ++ if (m_config.useInteropYuv) ++ m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU_420; ++ else ++ { ++ m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU; ++ m_mixerInput[1].DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST | ++ DVP_FLAG_REPEAT_TOP_FIELD | ++ DVP_FLAG_INTERLACED); ++ } ++ } ++ m_mixerstep = 0; ++ ++ if (m_mixerInput[1].DVDPic.format == RENDER_FMT_VDPAU) ++ { ++ m_processPicture.outputSurface = m_outputSurfaces.front(); ++ m_mixerInput[1].DVDPic.iWidth = m_config.outWidth; ++ m_mixerInput[1].DVDPic.iHeight = m_config.outHeight; ++ } ++ else ++ { ++ m_mixerInput[1].DVDPic.iWidth = m_config.vidWidth; ++ m_mixerInput[1].DVDPic.iHeight = m_config.vidHeight; ++ } ++ ++ m_processPicture.DVDPic = m_mixerInput[1].DVDPic; ++ m_processPicture.render = m_mixerInput[1].render; ++} ++ ++void CMixer::FiniCycle() ++{ ++ while (m_mixerInput.size() > 3) ++ { ++ CVdpauDecodedPicture &tmp = m_mixerInput.back(); ++ if (tmp.render && m_processPicture.DVDPic.format != RENDER_FMT_VDPAU_420) ++ { ++ CSingleLock lock(*m_config.videoSurfaceSec); ++ tmp.render->state &= ~FF_VDPAU_STATE_USED_FOR_RENDER; ++ } ++ m_mixerInput.pop_back(); ++// m_config.stats->DecDecoded(); ++ } ++} ++ ++void CMixer::ProcessPicture() ++{ ++ if (m_processPicture.DVDPic.format == RENDER_FMT_VDPAU_420) ++ return; ++ ++ VdpStatus vdp_st; ++ ++ if (m_mixerstep == 1) ++ { ++ if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD) ++ m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD; ++ else ++ m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD; ++ } ++ ++ VdpVideoSurface past_surfaces[4] = { VDP_INVALID_HANDLE, VDP_INVALID_HANDLE, VDP_INVALID_HANDLE, VDP_INVALID_HANDLE }; ++ VdpVideoSurface futu_surfaces[2] = { VDP_INVALID_HANDLE, VDP_INVALID_HANDLE }; ++ uint32_t pastCount = 4; ++ uint32_t futuCount = 2; ++ ++ if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME) ++ { ++ // use only 2 past 1 future for progressive/weave ++ // (only used for postproc anyway eg noise reduction) ++ if (m_mixerInput.size() > 3) ++ past_surfaces[1] = m_mixerInput[3].render->surface; ++ if (m_mixerInput.size() > 2) ++ past_surfaces[0] = m_mixerInput[2].render->surface; ++ futu_surfaces[0] = m_mixerInput[0].render->surface; ++ pastCount = 2; ++ futuCount = 1; ++ } ++ else ++ { ++ if(m_mixerstep == 0) ++ { // first field ++ if (m_mixerInput.size() > 3) ++ { ++ past_surfaces[3] = m_mixerInput[3].render->surface; ++ past_surfaces[2] = m_mixerInput[3].render->surface; ++ } ++ if (m_mixerInput.size() > 2) ++ { ++ past_surfaces[1] = m_mixerInput[2].render->surface; ++ past_surfaces[0] = m_mixerInput[2].render->surface; ++ } ++ futu_surfaces[0] = m_mixerInput[1].render->surface; ++ futu_surfaces[1] = m_mixerInput[0].render->surface;; ++ } ++ else ++ { // second field ++ if (m_mixerInput.size() > 3) ++ { ++ past_surfaces[3] = m_mixerInput[3].render->surface; ++ } ++ if (m_mixerInput.size() > 2) ++ { ++ past_surfaces[2] = m_mixerInput[2].render->surface; ++ past_surfaces[1] = m_mixerInput[2].render->surface; ++ } ++ past_surfaces[0] = m_mixerInput[1].render->surface; ++ futu_surfaces[0] = m_mixerInput[1].render->surface; ++ futu_surfaces[1] = m_mixerInput[1].render->surface; ++ ++ m_processPicture.DVDPic.pts = DVD_NOPTS_VALUE; ++ m_processPicture.DVDPic.dts = DVD_NOPTS_VALUE; ++ } ++ m_processPicture.DVDPic.iRepeatPicture = 0.0; ++ } // interlaced ++ ++ VdpRect sourceRect; ++ sourceRect.x0 = 0; ++ sourceRect.y0 = 0; ++ sourceRect.x1 = m_config.vidWidth; ++ sourceRect.y1 = m_config.vidHeight; ++ ++ VdpRect destRect; ++ destRect.x0 = 0; ++ destRect.y0 = 0; ++ destRect.x1 = m_config.outWidth; ++ destRect.y1 = m_config.outHeight; ++ ++ // start vdpau video mixer ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_render(m_videoMixer, ++ VDP_INVALID_HANDLE, ++ 0, ++ m_mixerfield, ++ pastCount, ++ past_surfaces, ++ m_mixerInput[1].render->surface, ++ futuCount, ++ futu_surfaces, ++ &sourceRect, ++ m_processPicture.outputSurface, ++ &destRect, ++ &destRect, ++ 0, ++ NULL); ++ CheckStatus(vdp_st, __LINE__); ++ ++ if (m_mixerfield != VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME) ++ { ++ // in order to clip top and bottom lines when de-interlacing ++ // we black those lines as a work around for not working ++ // background colour using the mixer ++ // pixel perfect is preferred over overscanning or zooming ++ ++ VdpRect clipRect = destRect; ++ clipRect.y1 = clipRect.y0 + 2; ++ uint32_t *data[] = {m_BlackBar}; ++ uint32_t pitches[] = {destRect.x1}; ++ vdp_st = m_config.vdpProcs.vdp_output_surface_put_bits_native(m_processPicture.outputSurface, ++ (void**)data, ++ pitches, ++ &clipRect); ++ CheckStatus(vdp_st, __LINE__); ++ ++ clipRect = destRect; ++ clipRect.y0 = clipRect.y1 - 2; ++ vdp_st = m_config.vdpProcs.vdp_output_surface_put_bits_native(m_processPicture.outputSurface, ++ (void**)data, ++ pitches, ++ &clipRect); ++ CheckStatus(vdp_st, __LINE__); ++ } ++} ++ ++ ++bool CMixer::CheckStatus(VdpStatus vdp_st, int line) ++{ ++ if (vdp_st != VDP_STATUS_OK) ++ { ++ CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) at %s:%d\n", m_config.vdpProcs.vdp_get_error_string(vdp_st), vdp_st, __FILE__, line); ++ m_vdpError = true; ++ return true; ++ } ++ return false; ++} ++ ++//----------------------------------------------------------------------------- ++// Output ++//----------------------------------------------------------------------------- ++COutput::COutput(CEvent *inMsgEvent) : ++ CThread("Vdpau Output Thread"), ++ m_controlPort("OutputControlPort", inMsgEvent, &m_outMsgEvent), ++ m_dataPort("OutputDataPort", inMsgEvent, &m_outMsgEvent), ++ m_mixer(&m_outMsgEvent) ++{ ++ m_inMsgEvent = inMsgEvent; ++ ++ CVdpauRenderPicture pic; ++ pic.renderPicSection = &m_bufferPool.renderPicSec; ++ pic.refCount = 0; ++ for (unsigned int i = 0; i < NUM_RENDER_PICS; i++) ++ { ++ m_bufferPool.allRenderPics.push_back(pic); ++ } ++ for (unsigned int i = 0; i < m_bufferPool.allRenderPics.size(); ++i) ++ { ++ m_bufferPool.freeRenderPics.push_back(&m_bufferPool.allRenderPics[i]); ++ } ++} ++ ++void COutput::Start() ++{ ++ Create(); ++} ++ ++COutput::~COutput() ++{ ++ Dispose(); ++ ++ m_bufferPool.freeRenderPics.clear(); ++ m_bufferPool.usedRenderPics.clear(); ++ m_bufferPool.allRenderPics.clear(); ++} ++ ++void COutput::Dispose() ++{ ++ CSingleLock lock(g_graphicsContext); ++ m_bStop = true; ++ m_outMsgEvent.Set(); ++ StopThread(); ++ m_controlPort.Purge(); ++ m_dataPort.Purge(); ++} ++ ++void COutput::OnStartup() ++{ ++ CLog::Log(LOGNOTICE, "COutput::OnStartup: Output Thread created"); ++} ++ ++void COutput::OnExit() ++{ ++ CLog::Log(LOGNOTICE, "COutput::OnExit: Output Thread terminated"); ++} ++ ++enum OUTPUT_STATES ++{ ++ O_TOP = 0, // 0 ++ O_TOP_ERROR, // 1 ++ O_TOP_UNCONFIGURED, // 2 ++ O_TOP_CONFIGURED, // 3 ++ O_TOP_CONFIGURED_IDLE, // 4 ++ O_TOP_CONFIGURED_WORK, // 5 ++}; ++ ++int VDPAU_OUTPUT_parentStates[] = { ++ -1, ++ 0, //TOP_ERROR ++ 0, //TOP_UNCONFIGURED ++ 0, //TOP_CONFIGURED ++ 3, //TOP_CONFIGURED_IDLE ++ 3, //TOP_CONFIGURED_WORK ++}; ++ ++void COutput::StateMachine(int signal, Protocol *port, Message *msg) ++{ ++ for (int state = m_state; ; state = VDPAU_OUTPUT_parentStates[state]) ++ { ++ switch (state) ++ { ++ case O_TOP: // TOP ++ if (port == &m_controlPort) ++ { ++ switch (signal) ++ { ++ case COutputControlProtocol::FLUSH: ++ msg->Reply(COutputControlProtocol::ACC); ++ return; ++ case COutputControlProtocol::PRECLEANUP: ++ msg->Reply(COutputControlProtocol::ACC); ++ return; ++ default: ++ break; ++ } ++ } ++ else if (port == &m_dataPort) ++ { ++ switch (signal) ++ { ++ case COutputDataProtocol::RETURNPIC: ++ CVdpauRenderPicture *pic; ++ pic = *((CVdpauRenderPicture**)msg->data); ++ ProcessReturnPicture(pic); ++ return; ++ default: ++ break; ++ } ++ } ++ { ++ std::string portName = port == NULL ? "timer" : port->portName; ++ CLog::Log(LOGWARNING, "COutput::%s - signal: %d form port: %s not handled for state: %d", __FUNCTION__, signal, portName.c_str(), m_state); ++ } ++ return; ++ ++ case O_TOP_ERROR: ++ break; ++ ++ case O_TOP_UNCONFIGURED: ++ if (port == &m_controlPort) ++ { ++ switch (signal) ++ { ++ case COutputControlProtocol::INIT: ++ CVdpauConfig *data; ++ data = (CVdpauConfig*)msg->data; ++ if (data) ++ { ++ m_config = *data; ++ } ++ Init(); ++ Message *reply; ++ if (m_mixer.m_controlPort.SendOutMessageSync(CMixerControlProtocol::INIT, ++ &reply, 1000, &m_config, sizeof(m_config))) ++ { ++ if (reply->signal != CMixerControlProtocol::ACC) ++ m_vdpError = true; ++ reply->Release(); ++ } ++ ++ // set initial number of ++ m_bufferPool.numOutputSurfaces = 4; ++ EnsureBufferPool(); ++ if (!m_vdpError) ++ { ++ m_state = O_TOP_CONFIGURED_IDLE; ++ msg->Reply(COutputControlProtocol::ACC); ++ } ++ else ++ { ++ m_state = O_TOP_ERROR; ++ msg->Reply(COutputControlProtocol::ERROR); ++ } ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case O_TOP_CONFIGURED: ++ if (port == &m_controlPort) ++ { ++ switch (signal) ++ { ++ case COutputControlProtocol::FLUSH: ++ Flush(); ++ msg->Reply(COutputControlProtocol::ACC); ++ return; ++ case COutputControlProtocol::PRECLEANUP: ++ Flush(); ++ msg->Reply(COutputControlProtocol::ACC); ++ return; ++ default: ++ break; ++ } ++ } ++ else if (port == &m_dataPort) ++ { ++ switch (signal) ++ { ++ case COutputDataProtocol::NEWFRAME: ++ CVdpauDecodedPicture *frame; ++ frame = (CVdpauDecodedPicture*)msg->data; ++ if (frame) ++ { ++ m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::FRAME, ++ frame,sizeof(CVdpauDecodedPicture)); ++ } ++ return; ++ case COutputDataProtocol::RETURNPIC: ++ CVdpauRenderPicture *pic; ++ pic = *((CVdpauRenderPicture**)msg->data); ++ ProcessReturnPicture(pic); ++ m_controlPort.SendInMessage(COutputControlProtocol::STATS); ++ m_state = O_TOP_CONFIGURED_WORK; ++ m_extTimeout = 0; ++ return; ++ default: ++ break; ++ } ++ } ++ else if (port == &m_mixer.m_dataPort) ++ { ++ switch (signal) ++ { ++ case CMixerDataProtocol::PICTURE: ++ CVdpauProcessedPicture *pic; ++ pic = (CVdpauProcessedPicture*)msg->data; ++ m_bufferPool.processedPics.push(*pic); ++ m_state = O_TOP_CONFIGURED_WORK; ++ m_extTimeout = 0; ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case O_TOP_CONFIGURED_IDLE: ++ if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case COutputControlProtocol::TIMEOUT: ++// uint16_t decoded, processed, render; ++// m_config.stats->Get(decoded, processed, render); ++// CLog::Log(LOGDEBUG, "CVDPAU::COutput - timeout idle: decoded: %d, proc: %d, render: %d", decoded, processed, render); ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case O_TOP_CONFIGURED_WORK: ++ if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case COutputControlProtocol::TIMEOUT: ++ if (HasWork()) ++ { ++ CVdpauRenderPicture *pic; ++ pic = ProcessMixerPicture(); ++ if (pic) ++ { ++ m_config.stats->DecProcessed(); ++ m_config.stats->IncRender(); ++ m_dataPort.SendInMessage(COutputDataProtocol::PICTURE, &pic, sizeof(pic)); ++ } ++ m_extTimeout = 1; ++ } ++ else ++ { ++ m_state = O_TOP_CONFIGURED_IDLE; ++ m_extTimeout = 100; ++ } ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ default: // we are in no state, should not happen ++ CLog::Log(LOGERROR, "COutput::%s - no valid state: %d", __FUNCTION__, m_state); ++ return; ++ } ++ } // for ++} ++ ++void COutput::Process() ++{ ++ Message *msg; ++ Protocol *port; ++ bool gotMsg; ++ ++ m_state = O_TOP_UNCONFIGURED; ++ m_extTimeout = 1000; ++ m_bStateMachineSelfTrigger = false; ++ ++ while (!m_bStop) ++ { ++ gotMsg = false; ++ ++ if (m_bStateMachineSelfTrigger) ++ { ++ m_bStateMachineSelfTrigger = false; ++ // self trigger state machine ++ StateMachine(msg->signal, port, msg); ++ if (!m_bStateMachineSelfTrigger) ++ { ++ msg->Release(); ++ msg = NULL; ++ } ++ continue; ++ } ++ // check control port ++ else if (m_controlPort.ReceiveOutMessage(&msg)) ++ { ++ gotMsg = true; ++ port = &m_controlPort; ++ } ++ // check data port ++ else if (m_dataPort.ReceiveOutMessage(&msg)) ++ { ++ gotMsg = true; ++ port = &m_dataPort; ++ } ++ // check mixer data port ++ else if (m_mixer.m_dataPort.ReceiveInMessage(&msg)) ++ { ++ gotMsg = true; ++ port = &m_mixer.m_dataPort; ++ } ++ if (gotMsg) ++ { ++ StateMachine(msg->signal, port, msg); ++ if (!m_bStateMachineSelfTrigger) ++ { ++ msg->Release(); ++ msg = NULL; ++ } ++ continue; ++ } ++ ++ // wait for message ++ else if (m_outMsgEvent.WaitMSec(m_extTimeout)) ++ { ++ continue; ++ } ++ // time out ++ else ++ { ++ msg = m_controlPort.GetMessage(); ++ msg->signal = COutputControlProtocol::TIMEOUT; ++ port = 0; ++ // signal timeout to state machine ++ StateMachine(msg->signal, port, msg); ++ if (!m_bStateMachineSelfTrigger) ++ { ++ msg->Release(); ++ msg = NULL; ++ } ++ } ++ } ++ Flush(); ++ Uninit(); ++} ++ ++bool COutput::Init() ++{ ++ if (!CreateGlxContext()) ++ return false; ++ ++ if (!GLInit()) ++ return false; ++ ++ m_mixer.Start(); ++ m_vdpError = false; ++ ++ return true; ++} ++ ++bool COutput::Uninit() ++{ ++ m_mixer.Dispose(); ++ GLUnmapSurfaces(); ++ GLUnbindPixmaps(); ++ ReleaseBufferPool(); ++ DestroyGlxContext(); ++ return true; ++} ++ ++void COutput::Flush() ++{ ++ Message *reply; ++ if (m_mixer.m_controlPort.SendOutMessageSync(CMixerControlProtocol::FLUSH, ++ &reply, ++ 2000)) ++ { ++ reply->Release(); ++ } ++ else ++ CLog::Log(LOGERROR, "Coutput::%s - failed to flush mixer", __FUNCTION__); ++ ++ Message *msg; ++ while (m_mixer.m_dataPort.ReceiveInMessage(&msg)) ++ { ++ if (msg->signal == CMixerDataProtocol::PICTURE) ++ { ++ CVdpauProcessedPicture pic = *(CVdpauProcessedPicture*)msg->data; ++ if (pic.DVDPic.format == RENDER_FMT_VDPAU_420) ++ { ++ CSingleLock lock(*m_config.videoSurfaceSec); ++ if (pic.render) ++ pic.render->state &= ~FF_VDPAU_STATE_USED_FOR_RENDER; ++ } ++ } ++ msg->Release(); ++ } ++ ++ while (m_dataPort.ReceiveOutMessage(&msg)) ++ { ++ if (msg->signal == COutputDataProtocol::NEWFRAME) ++ { ++ CVdpauDecodedPicture pic = *(CVdpauDecodedPicture*)msg->data; ++ CSingleLock lock(*m_config.videoSurfaceSec); ++ if (pic.render) ++ pic.render->state &= ~FF_VDPAU_STATE_USED_FOR_RENDER; ++ } ++ else if (msg->signal == COutputDataProtocol::RETURNPIC) ++ { ++ CVdpauRenderPicture *pic; ++ pic = *((CVdpauRenderPicture**)msg->data); ++ ProcessReturnPicture(pic); ++ } ++ msg->Release(); ++ } ++ ++ while (m_dataPort.ReceiveInMessage(&msg)) ++ { ++ if (msg->signal == COutputDataProtocol::PICTURE) ++ { ++ CVdpauRenderPicture *pic; ++ pic = *((CVdpauRenderPicture**)msg->data); ++ ProcessReturnPicture(pic); ++ } ++ } ++ ++ // reset used render flag which was cleared on mixer flush ++ std::deque::iterator it; ++ for (it = m_bufferPool.usedRenderPics.begin(); it != m_bufferPool.usedRenderPics.end(); ++it) ++ { ++ if ((*it)->DVDPic.format == RENDER_FMT_VDPAU_420) ++ { ++ std::map::iterator it2; ++ it2 = m_bufferPool.glVideoSurfaceMap.find((*it)->sourceIdx); ++ if (it2 == m_bufferPool.glVideoSurfaceMap.end()) ++ { ++ CLog::Log(LOGDEBUG, "COutput::Flush - gl surface not found"); ++ continue; ++ } ++ vdpau_render_state *render = it2->second.sourceVuv; ++ if (render) ++ render->state |= FF_VDPAU_STATE_USED_FOR_RENDER; ++ } ++ } ++} ++ ++bool COutput::HasWork() ++{ ++ if (m_config.usePixmaps) ++ { ++ if (!m_bufferPool.processedPics.empty() && FindFreePixmap() >= 0) ++ return true; ++ if (!m_bufferPool.notVisiblePixmaps.empty() && !m_bufferPool.freeRenderPics.empty()) ++ return true; ++ return false; ++ } ++ else ++ { ++ if (!m_bufferPool.processedPics.empty() && !m_bufferPool.freeRenderPics.empty()) ++ return true; ++ return false; ++ } ++} ++ ++CVdpauRenderPicture* COutput::ProcessMixerPicture() ++{ ++ CVdpauRenderPicture *retPic = 0; ++ ++ if (m_config.usePixmaps) ++ { ++ if (!m_bufferPool.processedPics.empty() && FindFreePixmap() >= 0) ++ { ++ unsigned int i = FindFreePixmap(); ++ VdpauBufferPool::Pixmaps *pixmap = &m_bufferPool.pixmaps[i]; ++ pixmap->used = true; ++ CVdpauProcessedPicture pic = m_bufferPool.processedPics.front(); ++ m_bufferPool.processedPics.pop(); ++ pixmap->surface = pic.outputSurface; ++ pixmap->DVDPic = pic.DVDPic; ++ pixmap->id = i; ++ m_bufferPool.notVisiblePixmaps.push_back(pixmap); ++ VdpStatus vdp_st; ++ m_config.vdpProcs.vdp_presentation_queue_display(pixmap->vdp_flip_queue, ++ pixmap->surface,0,0,0); ++ } ++ if (!m_bufferPool.notVisiblePixmaps.empty() && !m_bufferPool.freeRenderPics.empty()) ++ { ++ VdpStatus vdp_st; ++ VdpTime time; ++ VdpPresentationQueueStatus status; ++ VdpauBufferPool::Pixmaps *pixmap = m_bufferPool.notVisiblePixmaps.front(); ++ vdp_st = m_config.vdpProcs.vdp_presentation_queue_query_surface_status( ++ pixmap->vdp_flip_queue, pixmap->surface, &status, &time); ++ ++ if (vdp_st == VDP_STATUS_OK && status == VDP_PRESENTATION_QUEUE_STATUS_VISIBLE) ++ { ++ retPic = m_bufferPool.freeRenderPics.front(); ++ m_bufferPool.freeRenderPics.pop_front(); ++ m_bufferPool.usedRenderPics.push_back(retPic); ++ retPic->sourceIdx = pixmap->id; ++ retPic->DVDPic = pixmap->DVDPic; ++ retPic->valid = true; ++ retPic->texture[0] = pixmap->texture; ++ retPic->crop = CRect(0,0,0,0); ++ m_bufferPool.notVisiblePixmaps.pop_front(); ++ m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER, &pixmap->surface, sizeof(pixmap->surface)); ++ } ++ } ++ } // pixmap ++ else if (!m_bufferPool.processedPics.empty() && !m_bufferPool.freeRenderPics.empty()) ++ { ++ retPic = m_bufferPool.freeRenderPics.front(); ++ m_bufferPool.freeRenderPics.pop_front(); ++ m_bufferPool.usedRenderPics.push_back(retPic); ++ CVdpauProcessedPicture procPic = m_bufferPool.processedPics.front(); ++ m_bufferPool.processedPics.pop(); ++ ++ retPic->DVDPic = procPic.DVDPic; ++ retPic->valid = true; ++ if (retPic->DVDPic.format == RENDER_FMT_VDPAU) ++ { ++ m_config.useInteropYuv = false; ++ m_bufferPool.numOutputSurfaces = NUM_RENDER_PICS; ++ EnsureBufferPool(); ++ GLMapSurfaces(); ++ retPic->sourceIdx = procPic.outputSurface; ++ retPic->texture[0] = m_bufferPool.glOutputSurfaceMap[procPic.outputSurface].texture[0]; ++ retPic->crop = CRect(0,0,0,0); ++ } ++ else ++ { ++ m_config.useInteropYuv = true; ++ GLMapSurfaces(); ++ retPic->sourceIdx = procPic.render->surface; ++ for (unsigned int i=0; i<4; ++i) ++ retPic->texture[i] = m_bufferPool.glVideoSurfaceMap[procPic.render->surface].texture[i]; ++ retPic->texWidth = m_config.surfaceWidth; ++ retPic->texHeight = m_config.surfaceHeight; ++ retPic->crop.x1 = 0; ++ retPic->crop.y1 = 0; ++ retPic->crop.x2 = m_config.surfaceWidth - m_config.vidWidth; ++ retPic->crop.y2 = m_config.surfaceHeight - m_config.vidHeight; ++ } ++ } ++ return retPic; ++} ++ ++void COutput::ProcessReturnPicture(CVdpauRenderPicture *pic) ++{ ++ std::deque::iterator it; ++ it = std::find(m_bufferPool.usedRenderPics.begin(), m_bufferPool.usedRenderPics.end(), pic); ++ if (it == m_bufferPool.usedRenderPics.end()) ++ { ++ CLog::Log(LOGWARNING, "COutput::ProcessReturnPicture - pic not found"); ++ return; ++ } ++ m_bufferPool.usedRenderPics.erase(it); ++ m_bufferPool.freeRenderPics.push_back(pic); ++ if (!pic->valid) ++ { ++ CLog::Log(LOGDEBUG, "COutput::%s - return of invalid render pic", __FUNCTION__); ++ return; ++ } ++ ++ if (m_config.usePixmaps) ++ { ++ m_bufferPool.pixmaps[pic->sourceIdx].used = false; ++ return; ++ } ++ else if (pic->DVDPic.format == RENDER_FMT_VDPAU_420) ++ { ++ std::map::iterator it; ++ it = m_bufferPool.glVideoSurfaceMap.find(pic->sourceIdx); ++ if (it == m_bufferPool.glVideoSurfaceMap.end()) ++ { ++ CLog::Log(LOGDEBUG, "COutput::ProcessReturnPicture - gl surface not found"); ++ return; ++ } ++ vdpau_render_state *render = it->second.sourceVuv; ++ CSingleLock lock(*m_config.videoSurfaceSec); ++ render->state &= ~FF_VDPAU_STATE_USED_FOR_RENDER; ++ } ++ else if (pic->DVDPic.format == RENDER_FMT_VDPAU) ++ { ++ std::map::iterator it; ++ it = m_bufferPool.glOutputSurfaceMap.find(pic->sourceIdx); ++ if (it == m_bufferPool.glOutputSurfaceMap.end()) ++ { ++ CLog::Log(LOGDEBUG, "COutput::ProcessReturnPicture - gl surface not found"); ++ return; ++ } ++ VdpOutputSurface outSurf = it->second.sourceRgb; ++ m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER, &outSurf, sizeof(outSurf)); ++ } ++} ++ ++int COutput::FindFreePixmap() ++{ ++ // find free pixmap ++ unsigned int i; ++ for (i = 0; i < m_bufferPool.pixmaps.size(); ++i) ++ { ++ if (!m_bufferPool.pixmaps[i].used) ++ break; ++ } ++ if (i == m_bufferPool.pixmaps.size()) ++ return -1; ++ else ++ return i; ++} ++ ++bool COutput::EnsureBufferPool() ++{ ++ VdpStatus vdp_st; ++ ++ // Creation of outputSurfaces ++ VdpOutputSurface outputSurface; ++ for (int i = m_bufferPool.outputSurfaces.size(); i < m_bufferPool.numOutputSurfaces; i++) ++ { ++ vdp_st = m_config.vdpProcs.vdp_output_surface_create(m_config.vdpDevice, ++ VDP_RGBA_FORMAT_B8G8R8A8, ++ m_config.outWidth, ++ m_config.outHeight, ++ &outputSurface); ++ if (CheckStatus(vdp_st, __LINE__)) ++ return false; ++ m_bufferPool.outputSurfaces.push_back(outputSurface); ++ ++ m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER, ++ &outputSurface, ++ sizeof(VdpOutputSurface)); ++ CLog::Log(LOGNOTICE, "VDPAU::COutput::InitBufferPool - Output Surface created"); ++ } ++ ++ ++ if (m_config.usePixmaps && m_bufferPool.pixmaps.empty()) ++ { ++ // create pixmpas ++ VdpauBufferPool::Pixmaps pixmap; ++ int numPixmaps = NUM_RENDER_PICS; ++ for (unsigned int i = 0; i < numPixmaps; i++) ++ { ++ pixmap.pixmap = None; ++ pixmap.glPixmap = None; ++ pixmap.vdp_flip_queue = VDP_INVALID_HANDLE; ++ pixmap.vdp_flip_target = VDP_INVALID_HANDLE; ++ MakePixmap(pixmap); ++ glXMakeCurrent(m_Display, None, NULL); ++ vdp_st = m_config.vdpProcs.vdp_presentation_queue_target_create_x11(m_config.vdpDevice, ++ pixmap.pixmap, //x_window, ++ &pixmap.vdp_flip_target); ++ ++ CheckStatus(vdp_st, __LINE__); ++ ++ vdp_st = m_config.vdpProcs.vdp_presentation_queue_create(m_config.vdpDevice, ++ pixmap.vdp_flip_target, ++ &pixmap.vdp_flip_queue); ++ CheckStatus(vdp_st, __LINE__); ++ glXMakeCurrent(m_Display, m_glPixmap, m_glContext); ++ ++ pixmap.id = i; ++ pixmap.used = false; ++ m_bufferPool.pixmaps.push_back(pixmap); ++ } ++ GLBindPixmaps(); ++ } ++ ++ return true; ++} ++ ++void COutput::ReleaseBufferPool() ++{ ++ VdpStatus vdp_st; ++ ++ CSingleLock lock(m_bufferPool.renderPicSec); ++ ++ if (m_config.usePixmaps) ++ { ++ for (unsigned int i = 0; i < m_bufferPool.pixmaps.size(); ++i) ++ { ++ if (m_bufferPool.pixmaps[i].vdp_flip_queue != VDP_INVALID_HANDLE) ++ { ++ vdp_st = m_config.vdpProcs.vdp_presentation_queue_destroy(m_bufferPool.pixmaps[i].vdp_flip_queue); ++ CheckStatus(vdp_st, __LINE__); ++ } ++ if (m_bufferPool.pixmaps[i].vdp_flip_target != VDP_INVALID_HANDLE) ++ { ++ vdp_st = m_config.vdpProcs.vdp_presentation_queue_target_destroy(m_bufferPool.pixmaps[i].vdp_flip_target); ++ CheckStatus(vdp_st, __LINE__); ++ } ++ if (m_bufferPool.pixmaps[i].glPixmap) ++ { ++ glXDestroyPixmap(m_Display, m_bufferPool.pixmaps[i].glPixmap); ++ } ++ if (m_bufferPool.pixmaps[i].pixmap) ++ { ++ XFreePixmap(m_Display, m_bufferPool.pixmaps[i].pixmap); ++ } ++ } ++ m_bufferPool.pixmaps.clear(); ++ } ++ ++ // release all output surfaces ++ for (unsigned int i = 0; i < m_bufferPool.outputSurfaces.size(); ++i) ++ { ++ if (m_bufferPool.outputSurfaces[i] == VDP_INVALID_HANDLE) ++ continue; ++ vdp_st = m_config.vdpProcs.vdp_output_surface_destroy(m_bufferPool.outputSurfaces[i]); ++ CheckStatus(vdp_st, __LINE__); ++ } ++ m_bufferPool.outputSurfaces.clear(); ++ ++ // invalidate all used render pictures ++ for (unsigned int i = 0; i < m_bufferPool.usedRenderPics.size(); ++i) ++ { ++ m_bufferPool.usedRenderPics[i]->valid = false; ++ } ++} ++ ++void COutput::InitMixer() ++{ ++ for (unsigned int i = 0; i < m_bufferPool.outputSurfaces.size(); ++i) ++ { ++ m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER, ++ &m_bufferPool.outputSurfaces[i], ++ sizeof(VdpOutputSurface)); ++ } ++} ++ ++bool COutput::MakePixmap(VdpauBufferPool::Pixmaps &pixmap) ++{ ++ CLog::Log(LOGNOTICE,"Creating %ix%i pixmap", m_config.outWidth, m_config.outHeight); ++ ++ // Get our window attribs. ++ XWindowAttributes wndattribs; ++ XGetWindowAttributes(m_Display, g_Windowing.GetWindow(), &wndattribs); ++ ++ pixmap.pixmap = XCreatePixmap(m_Display, ++ g_Windowing.GetWindow(), ++ m_config.outWidth, ++ m_config.outHeight, ++ wndattribs.depth); ++ if (!pixmap.pixmap) ++ { ++ CLog::Log(LOGERROR, "VDPAU::COUtput::MakePixmap - GLX Error: MakePixmap: Unable to create XPixmap"); ++ return false; ++ } ++ ++// XGCValues values = {}; ++// GC xgc; ++// values.foreground = BlackPixel (m_Display, DefaultScreen (m_Display)); ++// xgc = XCreateGC(m_Display, pixmap.pixmap, GCForeground, &values); ++// XFillRectangle(m_Display, pixmap.pixmap, xgc, 0, 0, m_config.outWidth, m_config.outHeight); ++// XFreeGC(m_Display, xgc); ++ ++ if(!MakePixmapGL(pixmap)) ++ return false; ++ ++ return true; ++} ++ ++bool COutput::MakePixmapGL(VdpauBufferPool::Pixmaps &pixmap) ++{ ++ int num=0; ++ int fbConfigIndex = 0; ++ ++ int doubleVisAttributes[] = { ++ GLX_RENDER_TYPE, GLX_RGBA_BIT, ++ GLX_RED_SIZE, 8, ++ GLX_GREEN_SIZE, 8, ++ GLX_BLUE_SIZE, 8, ++ GLX_ALPHA_SIZE, 8, ++ GLX_DEPTH_SIZE, 8, ++ GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, ++ GLX_BIND_TO_TEXTURE_RGBA_EXT, True, ++ GLX_DOUBLEBUFFER, False, ++ GLX_Y_INVERTED_EXT, True, ++ GLX_X_RENDERABLE, True, ++ None ++ }; ++ ++ int pixmapAttribs[] = { ++ GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, ++ GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT, ++ None ++ }; ++ ++ GLXFBConfig *fbConfigs; ++ fbConfigs = glXChooseFBConfig(m_Display, g_Windowing.GetCurrentScreen(), doubleVisAttributes, &num); ++ if (fbConfigs==NULL) ++ { ++ CLog::Log(LOGERROR, "VDPAU::COutput::MakPixmapGL - No compatible framebuffers found"); ++ return false; ++ } ++ fbConfigIndex = 0; ++ ++ pixmap.glPixmap = glXCreatePixmap(m_Display, fbConfigs[fbConfigIndex], pixmap.pixmap, pixmapAttribs); ++ ++ if (!pixmap.glPixmap) ++ { ++ CLog::Log(LOGERROR, "VDPAU::COutput::MakPixmapGL - Could not create Pixmap"); ++ XFree(fbConfigs); ++ return false; ++ } ++ XFree(fbConfigs); ++ return true; ++} ++ ++bool COutput::GLInit() ++{ ++ glXBindTexImageEXT = NULL; ++ glXReleaseTexImageEXT = NULL; ++#ifdef GL_NV_vdpau_interop ++ glVDPAUInitNV = NULL; ++ glVDPAUFiniNV = NULL; ++ glVDPAURegisterOutputSurfaceNV = NULL; ++ glVDPAURegisterVideoSurfaceNV = NULL; ++ glVDPAUIsSurfaceNV = NULL; ++ glVDPAUUnregisterSurfaceNV = NULL; ++ glVDPAUSurfaceAccessNV = NULL; ++ glVDPAUMapSurfacesNV = NULL; ++ glVDPAUUnmapSurfacesNV = NULL; ++ glVDPAUGetSurfaceivNV = NULL; ++#endif ++ ++ m_config.usePixmaps = !g_guiSettings.GetBool("videoplayer.usevdpauinterop"); ++ ++#ifdef GL_NV_vdpau_interop ++ if (glewIsSupported("GL_NV_vdpau_interop")) ++ { ++ if (!glVDPAUInitNV) ++ glVDPAUInitNV = (PFNGLVDPAUINITNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUInitNV"); ++ if (!glVDPAUFiniNV) ++ glVDPAUFiniNV = (PFNGLVDPAUFININVPROC)glXGetProcAddress((GLubyte *) "glVDPAUFiniNV"); ++ if (!glVDPAURegisterOutputSurfaceNV) ++ glVDPAURegisterOutputSurfaceNV = (PFNGLVDPAUREGISTEROUTPUTSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAURegisterOutputSurfaceNV"); ++ if (!glVDPAURegisterVideoSurfaceNV) ++ glVDPAURegisterVideoSurfaceNV = (PFNGLVDPAUREGISTERVIDEOSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAURegisterVideoSurfaceNV"); ++ if (!glVDPAUIsSurfaceNV) ++ glVDPAUIsSurfaceNV = (PFNGLVDPAUISSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAUIsSurfaceNV"); ++ if (!glVDPAUUnregisterSurfaceNV) ++ glVDPAUUnregisterSurfaceNV = (PFNGLVDPAUUNREGISTERSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAUUnregisterSurfaceNV"); ++ if (!glVDPAUSurfaceAccessNV) ++ glVDPAUSurfaceAccessNV = (PFNGLVDPAUSURFACEACCESSNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUSurfaceAccessNV"); ++ if (!glVDPAUMapSurfacesNV) ++ glVDPAUMapSurfacesNV = (PFNGLVDPAUMAPSURFACESNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUMapSurfacesNV"); ++ if (!glVDPAUUnmapSurfacesNV) ++ glVDPAUUnmapSurfacesNV = (PFNGLVDPAUUNMAPSURFACESNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUUnmapSurfacesNV"); ++ if (!glVDPAUGetSurfaceivNV) ++ glVDPAUGetSurfaceivNV = (PFNGLVDPAUGETSURFACEIVNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUGetSurfaceivNV"); ++ ++ CLog::Log(LOGNOTICE, "VDPAU::COutput GL interop supported"); ++ } ++ else ++#endif ++ { ++ m_config.usePixmaps = true; ++ g_guiSettings.SetBool("videoplayer.usevdpauinterop",false); ++ g_guiSettings.SetBool("videoplayer.usevdpauinteropyuv",false); ++ } ++ if (!glXBindTexImageEXT) ++ glXBindTexImageEXT = (PFNGLXBINDTEXIMAGEEXTPROC)glXGetProcAddress((GLubyte *) "glXBindTexImageEXT"); ++ if (!glXReleaseTexImageEXT) ++ glXReleaseTexImageEXT = (PFNGLXRELEASETEXIMAGEEXTPROC)glXGetProcAddress((GLubyte *) "glXReleaseTexImageEXT"); ++ ++#ifdef GL_NV_vdpau_interop ++ if (!m_config.usePixmaps) ++ { ++ while (glGetError() != GL_NO_ERROR); ++ glVDPAUInitNV(reinterpret_cast(m_config.vdpDevice), reinterpret_cast(m_config.vdpProcs.vdp_get_proc_address)); ++ if (glGetError() != GL_NO_ERROR) ++ { ++ CLog::Log(LOGERROR, "VDPAU::COutput - GLInitInterop glVDPAUInitNV failed"); ++ m_vdpError = true; ++ return false; ++ } ++ CLog::Log(LOGNOTICE, "VDPAU::COutput: vdpau gl interop initialized"); ++ } ++#endif ++ return true; ++} ++ ++void COutput::GLMapSurfaces() ++{ ++#ifdef GL_NV_vdpau_interop ++ if (m_config.usePixmaps) ++ return; ++ ++ if (m_config.useInteropYuv) ++ { ++ VdpauBufferPool::GLVideoSurface glSurface; ++ if (m_config.videoSurfaces->size() != m_bufferPool.glVideoSurfaceMap.size()) ++ { ++ CSingleLock lock(*m_config.videoSurfaceSec); ++ for (int i = 0; i < m_config.videoSurfaces->size(); i++) ++ { ++ if ((*m_config.videoSurfaces)[i]->surface == VDP_INVALID_HANDLE) ++ continue; ++ ++ if (m_bufferPool.glVideoSurfaceMap.find((*m_config.videoSurfaces)[i]->surface) == m_bufferPool.glVideoSurfaceMap.end()) ++ { ++ glSurface.sourceVuv = (*m_config.videoSurfaces)[i]; ++ while (glGetError() != GL_NO_ERROR) ; ++ glGenTextures(4, glSurface.texture); ++ if (glGetError() != GL_NO_ERROR) ++ { ++ CLog::Log(LOGERROR, "VDPAU::COutput error creating texture"); ++ m_vdpError = true; ++ } ++ glSurface.glVdpauSurface = glVDPAURegisterVideoSurfaceNV(reinterpret_cast((*m_config.videoSurfaces)[i]->surface), ++ GL_TEXTURE_2D, 4, glSurface.texture); ++ ++ if (glGetError() != GL_NO_ERROR) ++ { ++ CLog::Log(LOGERROR, "VDPAU::COutput error register video surface"); ++ m_vdpError = true; ++ } ++ glVDPAUSurfaceAccessNV(glSurface.glVdpauSurface, GL_READ_ONLY); ++ if (glGetError() != GL_NO_ERROR) ++ { ++ CLog::Log(LOGERROR, "VDPAU::COutput error setting access"); ++ m_vdpError = true; ++ } ++ glVDPAUMapSurfacesNV(1, &glSurface.glVdpauSurface); ++ if (glGetError() != GL_NO_ERROR) ++ { ++ CLog::Log(LOGERROR, "VDPAU::COutput error mapping surface"); ++ m_vdpError = true; ++ } ++ m_bufferPool.glVideoSurfaceMap[(*m_config.videoSurfaces)[i]->surface] = glSurface; ++ if (m_vdpError) ++ return; ++ CLog::Log(LOGNOTICE, "VDPAU::COutput registered surface"); ++ } ++ } ++ } ++ } ++ else ++ { ++ if (m_bufferPool.glOutputSurfaceMap.size() != m_bufferPool.numOutputSurfaces) ++ { ++ VdpauBufferPool::GLVideoSurface glSurface; ++ for (int i=m_bufferPool.glOutputSurfaceMap.size(); i(m_bufferPool.outputSurfaces[i]), ++ GL_TEXTURE_2D, 1, glSurface.texture); ++ if (glGetError() != GL_NO_ERROR) ++ { ++ CLog::Log(LOGERROR, "VDPAU::COutput error register output surface"); ++ m_vdpError = true; ++ } ++ glVDPAUSurfaceAccessNV(glSurface.glVdpauSurface, GL_READ_ONLY); ++ if (glGetError() != GL_NO_ERROR) ++ { ++ CLog::Log(LOGERROR, "VDPAU::COutput error setting access"); ++ m_vdpError = true; ++ } ++ glVDPAUMapSurfacesNV(1, &glSurface.glVdpauSurface); ++ if (glGetError() != GL_NO_ERROR) ++ { ++ CLog::Log(LOGERROR, "VDPAU::COutput error mapping surface"); ++ m_vdpError = true; ++ } ++ m_bufferPool.glOutputSurfaceMap[m_bufferPool.outputSurfaces[i]] = glSurface; ++ if (m_vdpError) ++ return; ++ } ++ CLog::Log(LOGNOTICE, "VDPAU::COutput registered output surfaces"); ++ } ++ } ++#endif ++} ++ ++void COutput::GLUnmapSurfaces() ++{ ++#ifdef GL_NV_vdpau_interop ++ if (m_config.usePixmaps) ++ return; ++ ++ { CSingleLock lock(*m_config.videoSurfaceSec); ++ std::map::iterator it; ++ for (it = m_bufferPool.glVideoSurfaceMap.begin(); it != m_bufferPool.glVideoSurfaceMap.end(); ++it) ++ { ++ glVDPAUUnregisterSurfaceNV(it->second.glVdpauSurface); ++ glDeleteTextures(4, it->second.texture); ++ } ++ m_bufferPool.glVideoSurfaceMap.clear(); ++ } ++ ++ std::map::iterator it; ++ for (it = m_bufferPool.glOutputSurfaceMap.begin(); it != m_bufferPool.glOutputSurfaceMap.end(); ++it) ++ { ++ glVDPAUUnregisterSurfaceNV(it->second.glVdpauSurface); ++ glDeleteTextures(1, it->second.texture); ++ } ++ m_bufferPool.glOutputSurfaceMap.clear(); ++ ++ glVDPAUFiniNV(); ++ ++ CLog::Log(LOGNOTICE, "VDPAU::COutput: vdpau gl interop finished"); ++ ++#endif ++} ++ ++void COutput::GLBindPixmaps() ++{ ++ if (!m_config.usePixmaps) ++ return; ++ ++ for (unsigned int i = 0; i < m_bufferPool.pixmaps.size(); i++) ++ { ++ // create texture ++ glGenTextures(1, &m_bufferPool.pixmaps[i].texture); ++ ++ //bind texture ++ glBindTexture(GL_TEXTURE_2D, m_bufferPool.pixmaps[i].texture); ++ ++ // bind pixmap ++ glXBindTexImageEXT(m_Display, m_bufferPool.pixmaps[i].glPixmap, GLX_FRONT_LEFT_EXT, NULL); ++ ++ glBindTexture(GL_TEXTURE_2D, 0); ++ } ++ ++ CLog::Log(LOGNOTICE, "VDPAU::COutput: bound pixmaps"); ++} ++ ++void COutput::GLUnbindPixmaps() ++{ ++ if (!m_config.usePixmaps) ++ return; ++ ++ for (unsigned int i = 0; i < m_bufferPool.pixmaps.size(); i++) ++ { ++ // create texture ++ if (!glIsTexture(m_bufferPool.pixmaps[i].texture)) ++ continue; ++ ++ //bind texture ++ glBindTexture(GL_TEXTURE_2D, m_bufferPool.pixmaps[i].texture); ++ ++ // release pixmap ++ glXReleaseTexImageEXT(m_Display, m_bufferPool.pixmaps[i].glPixmap, GLX_FRONT_LEFT_EXT); ++ ++ glBindTexture(GL_TEXTURE_2D, 0); ++ ++ glDeleteTextures(1, &m_bufferPool.pixmaps[i].texture); ++ } ++ CLog::Log(LOGNOTICE, "VDPAU::COutput: unbound pixmaps"); ++} ++ ++bool COutput::CheckStatus(VdpStatus vdp_st, int line) ++{ ++ if (vdp_st != VDP_STATUS_OK) ++ { ++ CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) at %s:%d\n", m_config.vdpProcs.vdp_get_error_string(vdp_st), vdp_st, __FILE__, line); ++ m_vdpError = true; ++ return true; ++ } ++ return false; ++} ++ ++bool COutput::CreateGlxContext() ++{ ++ GLXContext glContext; ++ Window window; ++ ++ m_Display = g_Windowing.GetDisplay(); ++ glContext = g_Windowing.GetGlxContext(); ++ m_Window = g_Windowing.GetWindow(); ++ ++ // Get our window attribs. ++ XWindowAttributes wndattribs; ++ XGetWindowAttributes(m_Display, m_Window, &wndattribs); ++ ++ // Get visual Info ++ XVisualInfo visInfo; ++ visInfo.visualid = wndattribs.visual->visualid; ++ int nvisuals = 0; ++ XVisualInfo* visuals = XGetVisualInfo(m_Display, VisualIDMask, &visInfo, &nvisuals); ++ if (nvisuals != 1) ++ { ++ CLog::Log(LOGERROR, "VDPAU::COutput::CreateGlxContext - could not find visual"); ++ return false; ++ } ++ visInfo = visuals[0]; ++ XFree(visuals); ++ ++ m_pixmap = XCreatePixmap(m_Display, ++ m_Window, ++ 192, ++ 108, ++ visInfo.depth); ++ if (!m_pixmap) ++ { ++ CLog::Log(LOGERROR, "VDPAU::COutput::CreateGlxContext - Unable to create XPixmap"); ++ return false; ++ } ++ ++ // create gl pixmap ++ m_glPixmap = glXCreateGLXPixmap(m_Display, &visInfo, m_pixmap); ++ ++ if (!m_glPixmap) ++ { ++ CLog::Log(LOGINFO, "VDPAU::COutput::CreateGlxContext - Could not create glPixmap"); ++ return false; ++ } ++ ++ m_glContext = glXCreateContext(m_Display, &visInfo, glContext, True); ++ ++ if (!glXMakeCurrent(m_Display, m_glPixmap, m_glContext)) ++ { ++ CLog::Log(LOGINFO, "VDPAU::COutput::CreateGlxContext - Could not make Pixmap current"); ++ return false; ++ } ++ ++ CLog::Log(LOGNOTICE, "VDPAU::COutput::CreateGlxContext - created context"); ++ return true; ++} ++ ++bool COutput::DestroyGlxContext() ++{ ++ if (m_glContext) ++ { ++ glXMakeCurrent(m_Display, None, NULL); ++ glXDestroyContext(m_Display, m_glContext); ++ } ++ m_glContext = 0; ++ ++ if (m_glPixmap) ++ glXDestroyPixmap(m_Display, m_glPixmap); ++ m_glPixmap = 0; ++ ++ if (m_pixmap) ++ XFreePixmap(m_Display, m_pixmap); ++ m_pixmap = 0; ++ ++ return true; ++} ++ + #endif +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h +index 2f53edf..4d1559c 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h +@@ -1,5 +1,3 @@ +- +-#pragma once + /* + * Copyright (C) 2005-2012 Team XBMC + * http://www.xbmc.org +@@ -20,9 +18,32 @@ + * + */ + ++/** ++ * design goals: ++ * - improve performance ++ * max out hw resources: e.g. make 1080p60 play on ION2 ++ * allow advanced de-interlacing on ION ++ * ++ * - add vdpau/opengl interop ++ * ++ * - remove tight dependency to render thread ++ * prior design needed to hijack render thread in order to do ++ * gl interop functions. In particular this was a problem for ++ * init and clear down. Introduction of GL_NV_vdpau_interop ++ * increased the need to be independent from render thread ++ * ++ * - move to an actor based design in order to reduce the number ++ * of locks needed. ++ */ ++ ++#pragma once ++ + #include "system_gl.h" + +-#include ++#include "DllAvUtil.h" ++#include "DVDVideoCodec.h" ++#include "DVDVideoCodecFFmpeg.h" ++#include "libavcodec/vdpau.h" + #include + #include + #define GLX_GLXEXT_PROTOTYPES +@@ -37,118 +58,31 @@ + #include "settings/VideoSettings.h" + #include "guilib/DispResource.h" + #include "threads/Event.h" +-namespace Surface { class CSurface; } +- +-#define NUM_OUTPUT_SURFACES 4 +-#define NUM_VIDEO_SURFACES_MPEG2 10 // (1 frame being decoded, 2 reference) +-#define NUM_VIDEO_SURFACES_H264 32 // (1 frame being decoded, up to 16 references) +-#define NUM_VIDEO_SURFACES_VC1 10 // (same as MPEG-2) +-#define NUM_OUTPUT_SURFACES_FOR_FULLHD 2 +-#define FULLHD_WIDTH 1920 +- +-class CVDPAU +- : public CDVDVideoCodecFFmpeg::IHardwareDecoder +- , public IDispResource +-{ +-public: +- +- struct pictureAge +- { +- int b_age; +- int ip_age[2]; +- }; +- +- struct Desc +- { +- const char *name; +- uint32_t id; +- uint32_t aux; /* optional extra parameter... */ +- }; +- +- CVDPAU(); +- virtual ~CVDPAU(); +- +- virtual bool Open (AVCodecContext* avctx, const enum PixelFormat, unsigned int surfaces = 0); +- virtual int Decode (AVCodecContext* avctx, AVFrame* frame); +- virtual bool GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture); +- virtual void Reset(); +- virtual void Close(); +- +- virtual int Check(AVCodecContext* avctx); +- +- virtual const std::string Name() { return "vdpau"; } +- +- bool MakePixmap(int width, int height); +- bool MakePixmapGL(); +- +- void ReleasePixmap(); +- void BindPixmap(); +- +- PFNGLXBINDTEXIMAGEEXTPROC glXBindTexImageEXT; +- PFNGLXRELEASETEXIMAGEEXTPROC glXReleaseTexImageEXT; +- GLXPixmap m_glPixmap; +- Pixmap m_Pixmap; +- +- static void FFReleaseBuffer(AVCodecContext *avctx, AVFrame *pic); +- static void FFDrawSlice(struct AVCodecContext *s, +- const AVFrame *src, int offset[4], +- int y, int type, int height); +- static int FFGetBuffer(AVCodecContext *avctx, AVFrame *pic); +- +- void Present(); +- bool ConfigVDPAU(AVCodecContext *avctx, int ref_frames); +- void SpewHardwareAvailable(); +- void InitCSCMatrix(int Height); +- bool CheckStatus(VdpStatus vdp_st, int line); +- bool IsSurfaceValid(vdpau_render_state *render); ++#include "threads/Thread.h" ++#include "utils/ActorProtocol.h" + +- void CheckFeatures(); +- void SetColor(); +- void SetNoiseReduction(); +- void SetSharpness(); +- void SetDeinterlacing(); +- void SetHWUpscaling(); ++using namespace Actor; + +- pictureAge picAge; +- vdpau_render_state *past[2], *current, *future; +- int tmpDeintMode, tmpDeintGUI, tmpDeint; +- float tmpNoiseReduction, tmpSharpness; +- float tmpBrightness, tmpContrast; +- int OutWidth, OutHeight; +- bool upScale; +- std::queue m_DVDVideoPics; + +- static inline void ClearUsedForRender(vdpau_render_state **st) +- { +- if (*st) { +- (*st)->state &= ~FF_VDPAU_STATE_USED_FOR_RENDER; +- *st = NULL; +- } +- } +- +- VdpProcamp m_Procamp; +- VdpCSCMatrix m_CSCMatrix; +- VdpDevice HasDevice() { return vdp_device != VDP_INVALID_HANDLE; }; +- VdpChromaType vdp_chroma_type; ++#define FULLHD_WIDTH 1920 ++#define MAX_PIC_Q_LENGTH 20 //for non-interop_yuv this controls the max length of the decoded pic to render completion Q + ++namespace VDPAU ++{ + +- // protected: +- void InitVDPAUProcs(); +- void FiniVDPAUProcs(); +- void FiniVDPAUOutput(); +- bool ConfigOutputMethod(AVCodecContext *avctx, AVFrame *pFrame); +- bool FiniOutputMethod(); ++/** ++ * VDPAU interface to driver ++ */ + +- VdpDevice vdp_device; +- VdpGetProcAddress * vdp_get_proc_address; +- VdpPresentationQueueTarget vdp_flip_target; +- VdpPresentationQueue vdp_flip_queue; +- VdpDeviceDestroy * vdp_device_destroy; ++struct VDPAU_procs ++{ ++ VdpGetProcAddress * vdp_get_proc_address; ++ VdpDeviceDestroy * vdp_device_destroy; + +- VdpVideoSurfaceCreate * vdp_video_surface_create; +- VdpVideoSurfaceDestroy * vdp_video_surface_destroy; +- VdpVideoSurfacePutBitsYCbCr * vdp_video_surface_put_bits_y_cb_cr; +- VdpVideoSurfaceGetBitsYCbCr * vdp_video_surface_get_bits_y_cb_cr; ++ VdpVideoSurfaceCreate * vdp_video_surface_create; ++ VdpVideoSurfaceDestroy * vdp_video_surface_destroy; ++ VdpVideoSurfacePutBitsYCbCr * vdp_video_surface_put_bits_y_cb_cr; ++ VdpVideoSurfaceGetBitsYCbCr * vdp_video_surface_get_bits_y_cb_cr; + + VdpOutputSurfacePutBitsYCbCr * vdp_output_surface_put_bits_y_cb_cr; + VdpOutputSurfacePutBitsNative * vdp_output_surface_put_bits_native; +@@ -158,15 +92,15 @@ class CVDPAU + VdpOutputSurfaceRenderOutputSurface * vdp_output_surface_render_output_surface; + VdpOutputSurfacePutBitsIndexed * vdp_output_surface_put_bits_indexed; + +- VdpVideoMixerCreate * vdp_video_mixer_create; +- VdpVideoMixerSetFeatureEnables * vdp_video_mixer_set_feature_enables; +- VdpVideoMixerQueryParameterSupport * vdp_video_mixer_query_parameter_support; +- VdpVideoMixerQueryFeatureSupport * vdp_video_mixer_query_feature_support; +- VdpVideoMixerDestroy * vdp_video_mixer_destroy; +- VdpVideoMixerRender * vdp_video_mixer_render; +- VdpVideoMixerSetAttributeValues * vdp_video_mixer_set_attribute_values; ++ VdpVideoMixerCreate * vdp_video_mixer_create; ++ VdpVideoMixerSetFeatureEnables * vdp_video_mixer_set_feature_enables; ++ VdpVideoMixerQueryParameterSupport * vdp_video_mixer_query_parameter_support; ++ VdpVideoMixerQueryFeatureSupport * vdp_video_mixer_query_feature_support; ++ VdpVideoMixerDestroy * vdp_video_mixer_destroy; ++ VdpVideoMixerRender * vdp_video_mixer_render; ++ VdpVideoMixerSetAttributeValues * vdp_video_mixer_set_attribute_values; + +- VdpGenerateCSCMatrix * vdp_generate_csc_matrix; ++ VdpGenerateCSCMatrix * vdp_generate_csc_matrix; + + VdpPresentationQueueTargetDestroy * vdp_presentation_queue_target_destroy; + VdpPresentationQueueCreate * vdp_presentation_queue_create; +@@ -179,64 +113,459 @@ class CVDPAU + + VdpGetErrorString * vdp_get_error_string; + +- VdpDecoderCreate * vdp_decoder_create; +- VdpDecoderDestroy * vdp_decoder_destroy; +- VdpDecoderRender * vdp_decoder_render; +- VdpDecoderQueryCapabilities * vdp_decoder_query_caps; ++ VdpDecoderCreate * vdp_decoder_create; ++ VdpDecoderDestroy * vdp_decoder_destroy; ++ VdpDecoderRender * vdp_decoder_render; ++ VdpDecoderQueryCapabilities * vdp_decoder_query_caps; + + VdpPreemptionCallbackRegister * vdp_preemption_callback_register; + +- VdpOutputSurface outputSurfaces[NUM_OUTPUT_SURFACES]; +- VdpOutputSurface outputSurface; +- VdpOutputSurface presentSurface; ++}; + +- VdpDecoder decoder; +- VdpVideoMixer videoMixer; +- VdpRect outRect; +- VdpRect outRectVid; ++//----------------------------------------------------------------------------- ++// VDPAU data structs ++//----------------------------------------------------------------------------- + +- static void* dl_handle; +- VdpStatus (*dl_vdp_device_create_x11)(Display* display, int screen, VdpDevice* device, VdpGetProcAddress **get_proc_address); +- VdpStatus (*dl_vdp_get_proc_address)(VdpDevice device, VdpFuncId function_id, void** function_pointer); +- VdpStatus (*dl_vdp_preemption_callback_register)(VdpDevice device, VdpPreemptionCallback callback, void* context); ++class CDecoder; + +- int surfaceNum; +- int presentSurfaceNum; +- int totalAvailableOutputSurfaces; +- uint32_t vid_width, vid_height; +- int surface_width, surface_height; +- uint32_t max_references; +- Display* m_Display; +- bool vdpauConfigured; +- uint32_t *m_BlackBar; ++/** ++ * Buffer statistics used to control number of frames in queue ++ */ + ++class CVdpauBufferStats ++{ ++public: ++ uint16_t decodedPics; ++ uint16_t processedPics; ++ uint16_t renderPics; ++ uint64_t latency; // time decoder has waited for a frame, ideally there is no latency ++ int playSpeed; ++ bool canSkipDeint; ++ int processCmd; ++ ++ void IncDecoded() { CSingleLock l(m_sec); decodedPics++;} ++ void DecDecoded() { CSingleLock l(m_sec); decodedPics--;} ++ void IncProcessed() { CSingleLock l(m_sec); processedPics++;} ++ void DecProcessed() { CSingleLock l(m_sec); processedPics--;} ++ void IncRender() { CSingleLock l(m_sec); renderPics++;} ++ void DecRender() { CSingleLock l(m_sec); renderPics--;} ++ void Reset() { CSingleLock l(m_sec); decodedPics=0; processedPics=0;renderPics=0;latency=0;} ++ void Get(uint16_t &decoded, uint16_t &processed, uint16_t &render) {CSingleLock l(m_sec); decoded = decodedPics, processed=processedPics, render=renderPics;} ++ void SetParams(uint64_t time, int speed) { CSingleLock l(m_sec); latency = time; playSpeed = speed; } ++ void GetParams(uint64_t &lat, int &speed) { CSingleLock l(m_sec); lat = latency; speed = playSpeed; } ++ void SetCmd(int cmd) { CSingleLock l(m_sec); processCmd = cmd; } ++ void GetCmd(int &cmd) { CSingleLock l(m_sec); cmd = processCmd; processCmd = 0; } ++ void SetCanSkipDeint(bool canSkip) { CSingleLock l(m_sec); canSkipDeint = canSkip; } ++ bool CanSkipDeint() { CSingleLock l(m_sec); if (canSkipDeint) return true; else return false;} ++private: ++ CCriticalSection m_sec; ++}; ++ ++/** ++ * CVdpauConfig holds all configuration parameters needed by vdpau ++ * The structure is sent to the internal classes CMixer and COutput ++ * for init. ++ */ + ++struct CVdpauConfig ++{ ++ int surfaceWidth; ++ int surfaceHeight; ++ int vidWidth; ++ int vidHeight; ++ int outWidth; ++ int outHeight; ++ VDPAU_procs vdpProcs; ++ VdpDevice vdpDevice; ++ VdpDecoder vdpDecoder; ++ VdpChromaType vdpChromaType; ++ CVdpauBufferStats *stats; ++ CDecoder *vdpau; ++ int featureCount; ++ int upscale; ++ VdpVideoMixerFeature vdpFeatures[14]; ++ std::vector *videoSurfaces; ++ CCriticalSection *videoSurfaceSec; ++ bool usePixmaps; ++ int numRenderBuffers; ++ uint32_t maxReferences; ++ bool useInteropYuv; ++}; ++ ++/** ++ * Holds a decoded frame ++ * Input to COutput for further processing ++ */ ++struct CVdpauDecodedPicture ++{ ++ DVDVideoPicture DVDPic; ++ vdpau_render_state *render; ++}; ++ ++/** ++ * Frame after having been processed by vdpau mixer ++ */ ++struct CVdpauProcessedPicture ++{ ++ DVDVideoPicture DVDPic; ++ vdpau_render_state *render; ++ VdpOutputSurface outputSurface; ++}; ++ ++/** ++ * Ready to render textures ++ * Sent from COutput back to CDecoder ++ * Objects are referenced by DVDVideoPicture and are sent ++ * to renderer ++ */ ++class CVdpauRenderPicture ++{ ++ friend class CDecoder; ++ friend class COutput; ++public: ++ DVDVideoPicture DVDPic; ++ int texWidth, texHeight; ++ CRect crop; ++ GLuint texture[4]; ++ uint32_t sourceIdx; ++ bool valid; ++ CDecoder *vdpau; ++ CVdpauRenderPicture* Acquire(); ++ long Release(); ++private: ++ void ReturnUnused(); ++ int refCount; ++ CCriticalSection *renderPicSection; ++}; ++ ++//----------------------------------------------------------------------------- ++// Mixer ++//----------------------------------------------------------------------------- ++ ++class CMixerControlProtocol : public Protocol ++{ ++public: ++ CMixerControlProtocol(std::string name, CEvent* inEvent, CEvent *outEvent) : Protocol(name, inEvent, outEvent) {}; ++ enum OutSignal ++ { ++ INIT = 0, ++ FLUSH, ++ TIMEOUT, ++ }; ++ enum InSignal ++ { ++ ACC, ++ ERROR, ++ }; ++}; ++ ++class CMixerDataProtocol : public Protocol ++{ ++public: ++ CMixerDataProtocol(std::string name, CEvent* inEvent, CEvent *outEvent) : Protocol(name, inEvent, outEvent) {}; ++ enum OutSignal ++ { ++ FRAME, ++ BUFFER, ++ }; ++ enum InSignal ++ { ++ PICTURE, ++ }; ++}; ++ ++/** ++ * Embeds the vdpau video mixer ++ * Embedded by COutput class, gets decoded frames from COutput, processes ++ * them in mixer ands sends processed frames back to COutput ++ */ ++class CMixer : private CThread ++{ ++public: ++ CMixer(CEvent *inMsgEvent); ++ virtual ~CMixer(); ++ void Start(); ++ void Dispose(); ++ CMixerControlProtocol m_controlPort; ++ CMixerDataProtocol m_dataPort; ++protected: ++ void OnStartup(); ++ void OnExit(); ++ void Process(); ++ void StateMachine(int signal, Protocol *port, Message *msg); ++ void Init(); ++ void Uninit(); ++ void Flush(); ++ void CreateVdpauMixer(); ++ void ProcessPicture(); ++ void InitCycle(); ++ void FiniCycle(); ++ void CheckFeatures(); ++ void SetPostProcFeatures(bool postProcEnabled); ++ void PostProcOff(); ++ void InitCSCMatrix(int Width); ++ bool GenerateStudioCSCMatrix(VdpColorStandard colorStandard, VdpCSCMatrix &studioCSCMatrix); ++ void SetColor(); ++ void SetNoiseReduction(); ++ void SetSharpness(); ++ void SetDeintSkipChroma(); ++ void SetDeinterlacing(); ++ void SetHWUpscaling(); ++ void DisableHQScaling(); ++ EINTERLACEMETHOD GetDeinterlacingMethod(bool log = false); ++ bool CheckStatus(VdpStatus vdp_st, int line); ++ CEvent m_outMsgEvent; ++ CEvent *m_inMsgEvent; ++ int m_state; ++ bool m_bStateMachineSelfTrigger; ++ ++ // extended state variables for state machine ++ int m_extTimeout; ++ bool m_vdpError; ++ CVdpauConfig m_config; ++ VdpVideoMixer m_videoMixer; ++ VdpProcamp m_Procamp; ++ VdpCSCMatrix m_CSCMatrix; ++ bool m_PostProc; ++ float m_Brightness; ++ float m_Contrast; ++ float m_NoiseReduction; ++ float m_Sharpness; ++ int m_DeintMode; ++ int m_Deint; ++ int m_Upscale; ++ uint32_t *m_BlackBar; + VdpVideoMixerPictureStructure m_mixerfield; +- int m_mixerstep; ++ int m_mixerstep; ++ int m_mixersteps; ++ CVdpauProcessedPicture m_processPicture; ++ std::queue m_outputSurfaces; ++ std::queue m_decodedPics; ++ std::deque m_mixerInput; ++}; ++ ++//----------------------------------------------------------------------------- ++// Output ++//----------------------------------------------------------------------------- ++ ++/** ++ * Buffer pool holds allocated vdpau and gl resources ++ * Embedded in COutput ++ */ ++struct VdpauBufferPool ++{ ++ struct Pixmaps ++ { ++ unsigned short id; ++ bool used; ++ DVDVideoPicture DVDPic; ++ GLuint texture; ++ Pixmap pixmap; ++ GLXPixmap glPixmap; ++ VdpPresentationQueueTarget vdp_flip_target; ++ VdpPresentationQueue vdp_flip_queue; ++ VdpOutputSurface surface; ++ }; ++ struct GLVideoSurface ++ { ++ GLuint texture[4]; ++#ifdef GL_NV_vdpau_interop ++ GLvdpauSurfaceNV glVdpauSurface; ++#endif ++ vdpau_render_state *sourceVuv; ++ VdpOutputSurface sourceRgb; ++ }; ++ unsigned short numOutputSurfaces; ++ std::vector pixmaps; ++ std::vector outputSurfaces; ++ std::deque notVisiblePixmaps; ++ std::vector allRenderPics; ++ std::map glVideoSurfaceMap; ++ std::map glOutputSurfaceMap; ++ std::queue processedPics; ++ std::deque usedRenderPics; ++ std::deque freeRenderPics; ++ CCriticalSection renderPicSec; ++}; ++ ++class COutputControlProtocol : public Protocol ++{ ++public: ++ COutputControlProtocol(std::string name, CEvent* inEvent, CEvent *outEvent) : Protocol(name, inEvent, outEvent) {}; ++ enum OutSignal ++ { ++ INIT, ++ FLUSH, ++ PRECLEANUP, ++ TIMEOUT, ++ }; ++ enum InSignal ++ { ++ ACC, ++ ERROR, ++ STATS, ++ }; ++}; ++ ++class COutputDataProtocol : public Protocol ++{ ++public: ++ COutputDataProtocol(std::string name, CEvent* inEvent, CEvent *outEvent) : Protocol(name, inEvent, outEvent) {}; ++ enum OutSignal ++ { ++ NEWFRAME = 0, ++ RETURNPIC, ++ }; ++ enum InSignal ++ { ++ PICTURE, ++ }; ++}; ++ ++/** ++ * COutput is embedded in CDecoder and embeds CMixer ++ * The class has its own OpenGl context which is shared with render thread ++ * COuput generated ready to render textures and passes them back to ++ * CDecoder ++ */ ++class COutput : private CThread ++{ ++public: ++ COutput(CEvent *inMsgEvent); ++ virtual ~COutput(); ++ void Start(); ++ void Dispose(); ++ COutputControlProtocol m_controlPort; ++ COutputDataProtocol m_dataPort; ++protected: ++ void OnStartup(); ++ void OnExit(); ++ void Process(); ++ void StateMachine(int signal, Protocol *port, Message *msg); ++ bool HasWork(); ++ CVdpauRenderPicture *ProcessMixerPicture(); ++ void ProcessReturnPicture(CVdpauRenderPicture *pic); ++ int FindFreePixmap(); ++ bool Init(); ++ bool Uninit(); ++ void Flush(); ++ bool CreateGlxContext(); ++ bool DestroyGlxContext(); ++ bool EnsureBufferPool(); ++ void ReleaseBufferPool(); ++ void InitMixer(); ++ bool GLInit(); ++ void GLMapSurfaces(); ++ void GLUnmapSurfaces(); ++ void GLBindPixmaps(); ++ void GLUnbindPixmaps(); ++ bool MakePixmap(VdpauBufferPool::Pixmaps &pixmap); ++ bool MakePixmapGL(VdpauBufferPool::Pixmaps &pixmap); ++ bool CheckStatus(VdpStatus vdp_st, int line); ++ CEvent m_outMsgEvent; ++ CEvent *m_inMsgEvent; ++ int m_state; ++ bool m_bStateMachineSelfTrigger; ++ ++ // extended state variables for state machine ++ int m_extTimeout; ++ bool m_vdpError; ++ CVdpauConfig m_config; ++ VdpauBufferPool m_bufferPool; ++ CMixer m_mixer; ++ Display *m_Display; ++ Window m_Window; ++ GLXContext m_glContext; ++ GLXWindow m_glWindow; ++ Pixmap m_pixmap; ++ GLXPixmap m_glPixmap; ++ ++ // gl functions ++ PFNGLXBINDTEXIMAGEEXTPROC glXBindTexImageEXT; ++ PFNGLXRELEASETEXIMAGEEXTPROC glXReleaseTexImageEXT; ++#ifdef GL_NV_vdpau_interop ++ PFNGLVDPAUINITNVPROC glVDPAUInitNV; ++ PFNGLVDPAUFININVPROC glVDPAUFiniNV; ++ PFNGLVDPAUREGISTEROUTPUTSURFACENVPROC glVDPAURegisterOutputSurfaceNV; ++ PFNGLVDPAUREGISTERVIDEOSURFACENVPROC glVDPAURegisterVideoSurfaceNV; ++ PFNGLVDPAUISSURFACENVPROC glVDPAUIsSurfaceNV; ++ PFNGLVDPAUUNREGISTERSURFACENVPROC glVDPAUUnregisterSurfaceNV; ++ PFNGLVDPAUSURFACEACCESSNVPROC glVDPAUSurfaceAccessNV; ++ PFNGLVDPAUMAPSURFACESNVPROC glVDPAUMapSurfacesNV; ++ PFNGLVDPAUUNMAPSURFACESNVPROC glVDPAUUnmapSurfacesNV; ++ PFNGLVDPAUGETSURFACEIVNVPROC glVDPAUGetSurfaceivNV; ++#endif ++}; ++ ++//----------------------------------------------------------------------------- ++// VDPAU decoder ++//----------------------------------------------------------------------------- ++ ++/** ++ * VDPAU main class ++ */ ++class CDecoder ++ : public CDVDVideoCodecFFmpeg::IHardwareDecoder ++ , public IDispResource ++{ ++ friend class CVdpauRenderPicture; ++ ++public: ++ ++ struct Desc ++ { ++ const char *name; ++ uint32_t id; ++ uint32_t aux; /* optional extra parameter... */ ++ }; ++ ++ CDecoder(); ++ virtual ~CDecoder(); ++ ++ virtual bool Open (AVCodecContext* avctx, const enum PixelFormat, unsigned int surfaces = 0); ++ virtual int Decode (AVCodecContext* avctx, AVFrame* frame); ++ virtual bool GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture); ++ virtual void Reset(); ++ virtual void Close(); ++ virtual long Release(); ++ virtual bool CanSkipDeint(); ++ ++ virtual int Check(AVCodecContext* avctx); ++ virtual const std::string Name() { return "vdpau"; } + + bool Supports(VdpVideoMixerFeature feature); + bool Supports(EINTERLACEMETHOD method); + EINTERLACEMETHOD AutoInterlaceMethod(); ++ static bool IsVDPAUFormat(PixelFormat fmt); + +- VdpVideoMixerFeature m_features[14]; +- int m_feature_count; ++ static void FFReleaseBuffer(AVCodecContext *avctx, AVFrame *pic); ++ static void FFDrawSlice(struct AVCodecContext *s, ++ const AVFrame *src, int offset[4], ++ int y, int type, int height); ++ static int FFGetBuffer(AVCodecContext *avctx, AVFrame *pic); ++ ++ virtual void OnLostDevice(); ++ virtual void OnResetDevice(); ++ ++protected: ++ void SetWidthHeight(int width, int height); ++ bool ConfigVDPAU(AVCodecContext *avctx, int ref_frames); ++ void SpewHardwareAvailable(); ++ bool CheckStatus(VdpStatus vdp_st, int line); ++ bool IsSurfaceValid(vdpau_render_state *render); ++ void InitVDPAUProcs(); ++ void FiniVDPAUProcs(); ++ void FiniVDPAUOutput(); ++ void ReturnRenderPicture(CVdpauRenderPicture *renderPic); ++ long ReleasePicReference(); + +- static bool IsVDPAUFormat(PixelFormat fmt); + static void ReadFormatOf( PixelFormat fmt + , VdpDecoderProfile &decoder_profile + , VdpChromaType &chroma_type); + +- std::vector m_videoSurfaces; +- DllAvUtil m_dllAvUtil; +- +- enum VDPAUOutputMethod +- { +- OUTPUT_NONE, +- OUTPUT_PIXMAP, +- OUTPUT_GL_INTEROP_RGB, +- OUTPUT_GL_INTEROP_YUV +- }; +- VDPAUOutputMethod m_vdpauOutputMethod; ++ VdpStatus (*dl_vdp_device_create_x11)(Display* display, int screen, VdpDevice* device, VdpGetProcAddress **get_proc_address); ++ VdpStatus (*dl_vdp_get_proc_address)(VdpDevice device, VdpFuncId function_id, void** function_pointer); ++ VdpStatus (*dl_vdp_preemption_callback_register)(VdpDevice device, VdpPreemptionCallback callback, void* context); + + // OnLostDevice triggers transition from all states to LOST + // internal errors trigger transition from OPEN to RESET +@@ -247,9 +576,24 @@ class CVDPAU + , VDPAU_LOST + , VDPAU_ERROR + } m_DisplayState; +- CSharedSection m_DecoderSection; +- CSharedSection m_DisplaySection; ++ CCriticalSection m_DecoderSection; + CEvent m_DisplayEvent; +- virtual void OnLostDevice(); +- virtual void OnResetDevice(); ++ ++ static void* dl_handle; ++ DllAvUtil m_dllAvUtil; ++ Display* m_Display; ++ ThreadIdentifier m_decoderThread; ++ bool m_vdpauConfigured; ++ CVdpauConfig m_vdpauConfig; ++ std::vector m_videoSurfaces; ++ CCriticalSection m_videoSurfaceSec; ++ ++ COutput m_vdpauOutput; ++ CVdpauBufferStats m_bufferStats; ++ CEvent m_inMsgEvent; ++ CVdpauRenderPicture *m_presentPicture; ++ ++ int m_codecControl; + }; ++ ++} +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +index 10e2225..15a39fa 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -1141,6 +1141,9 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) + case RENDER_FMT_VDPAU: + formatstr = "VDPAU"; + break; ++ case RENDER_FMT_VDPAU_420: ++ formatstr = "VDPAU_420"; ++ break; + case RENDER_FMT_DXVA: + formatstr = "DXVA"; + break; +diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp +index 16800b7..844f8e8 100644 +--- a/xbmc/settings/AdvancedSettings.cpp ++++ b/xbmc/settings/AdvancedSettings.cpp +@@ -98,7 +98,7 @@ void CAdvancedSettings::Initialize() + m_videoIgnoreSecondsAtStart = 3*60; + m_videoIgnorePercentAtEnd = 8.0f; + m_videoPlayCountMinimumPercent = 90.0f; +- m_videoVDPAUScaling = false; ++ m_videoVDPAUScaling = -1; + m_videoNonLinStretchRatio = 0.5f; + m_videoEnableHighQualityHwScalers = false; + m_videoAutoScaleMaxFps = 30.0f; +@@ -106,6 +106,8 @@ void CAdvancedSettings::Initialize() + m_videoAllowMpeg4VAAPI = false; + m_videoDisableBackgroundDeinterlace = false; + m_videoCaptureUseOcclusionQuery = -1; //-1 is auto detect ++ m_videoVDPAUtelecine = false; ++ m_videoVDPAUdeintSkipChromaHD = false; + m_DXVACheckCompatibility = false; + m_DXVACheckCompatibilityPresent = false; + m_DXVAForceProcessorRenderer = true; +@@ -493,7 +495,7 @@ void CAdvancedSettings::ParseSettingsFile(const CStdString &file) + XMLUtils::GetString(pElement,"cleandatetime", m_videoCleanDateTimeRegExp); + XMLUtils::GetString(pElement,"ppffmpegdeinterlacing",m_videoPPFFmpegDeint); + XMLUtils::GetString(pElement,"ppffmpegpostprocessing",m_videoPPFFmpegPostProc); +- XMLUtils::GetBoolean(pElement,"vdpauscaling",m_videoVDPAUScaling); ++ XMLUtils::GetInt(pElement,"vdpauscaling",m_videoVDPAUScaling); + XMLUtils::GetFloat(pElement, "nonlinearstretchratio", m_videoNonLinStretchRatio, 0.01f, 1.0f); + XMLUtils::GetBoolean(pElement,"enablehighqualityhwscalers", m_videoEnableHighQualityHwScalers); + XMLUtils::GetFloat(pElement,"autoscalemaxfps",m_videoAutoScaleMaxFps, 0.0f, 1000.0f); +@@ -501,6 +503,8 @@ void CAdvancedSettings::ParseSettingsFile(const CStdString &file) + XMLUtils::GetBoolean(pElement,"allowmpeg4vaapi",m_videoAllowMpeg4VAAPI); + XMLUtils::GetBoolean(pElement, "disablebackgrounddeinterlace", m_videoDisableBackgroundDeinterlace); + XMLUtils::GetInt(pElement, "useocclusionquery", m_videoCaptureUseOcclusionQuery, -1, 1); ++ XMLUtils::GetBoolean(pElement,"vdpauInvTelecine",m_videoVDPAUtelecine); ++ XMLUtils::GetBoolean(pElement,"vdpauHDdeintSkipChroma",m_videoVDPAUdeintSkipChromaHD); + + TiXmlElement* pAdjustRefreshrate = pElement->FirstChildElement("adjustrefreshrate"); + if (pAdjustRefreshrate) +diff --git a/xbmc/settings/AdvancedSettings.h b/xbmc/settings/AdvancedSettings.h +index 27887d4..72718e5 100644 +--- a/xbmc/settings/AdvancedSettings.h ++++ b/xbmc/settings/AdvancedSettings.h +@@ -133,6 +133,8 @@ class CAdvancedSettings + int m_videoPercentSeekBackwardBig; + CStdString m_videoPPFFmpegDeint; + CStdString m_videoPPFFmpegPostProc; ++ bool m_videoVDPAUtelecine; ++ bool m_videoVDPAUdeintSkipChromaHD; + bool m_musicUseTimeSeeking; + int m_musicTimeSeekForward; + int m_musicTimeSeekBackward; +@@ -148,7 +150,7 @@ class CAdvancedSettings + CStdString m_audioHost; + bool m_audioApplyDrc; + +- bool m_videoVDPAUScaling; ++ int m_videoVDPAUScaling; + float m_videoNonLinStretchRatio; + bool m_videoEnableHighQualityHwScalers; + float m_videoAutoScaleMaxFps; +diff --git a/xbmc/settings/GUISettings.cpp b/xbmc/settings/GUISettings.cpp +index 76ec0cc..4cdb093 100644 +--- a/xbmc/settings/GUISettings.cpp ++++ b/xbmc/settings/GUISettings.cpp +@@ -685,6 +685,8 @@ void CGUISettings::Initialize() + + #ifdef HAVE_LIBVDPAU + AddBool(vp, "videoplayer.usevdpau", 13425, true); ++ AddBool(vp, "videoplayer.usevdpauinterop", 13435, true); ++ AddBool(vp, "videoplayer.usevdpauinteropyuv", 13436, false); + #endif + #ifdef HAVE_LIBVA + AddBool(vp, "videoplayer.usevaapi", 13426, true); +diff --git a/xbmc/settings/GUIWindowSettingsCategory.cpp b/xbmc/settings/GUIWindowSettingsCategory.cpp +index 4ac2663..d988598 100644 +--- a/xbmc/settings/GUIWindowSettingsCategory.cpp ++++ b/xbmc/settings/GUIWindowSettingsCategory.cpp +@@ -596,6 +596,40 @@ void CGUIWindowSettingsCategory::UpdateSettings() + pControl->SetEnabled(true); + } + } ++ else if (strSetting.Equals("videoplayer.usevdpauinteropyuv")) ++ { ++ bool hasInterop = g_guiSettings.GetBool("videoplayer.usevdpauinterop"); ++#ifndef GL_NV_vdpau_interop ++ hasInterop = false; ++#endif ++ CGUIControl *pControl = (CGUIControl *)GetControl(pSettingControl->GetID()); ++ if (pControl && hasInterop && glewIsSupported("GL_NV_vdpau_interop")) ++ { ++ pControl->SetEnabled(true); ++ } ++ else ++ { ++ pControl->SetEnabled(false); ++ g_guiSettings.SetBool("videoplayer.usevdpauinteropyuv",false); ++ } ++ } ++ else if (strSetting.Equals("videoplayer.usevdpauinterop")) ++ { ++ bool hasInterop = g_guiSettings.GetBool("videoplayer.usevdpau"); ++#ifndef GL_NV_vdpau_interop ++ hasInterop = false; ++#endif ++ CGUIControl *pControl = (CGUIControl *)GetControl(pSettingControl->GetID()); ++ if (pControl && hasInterop && glewIsSupported("GL_NV_vdpau_interop")) ++ { ++ pControl->SetEnabled(true); ++ } ++ else ++ { ++ pControl->SetEnabled(false); ++ g_guiSettings.SetBool("videoplayer.usevdpauinterop",false); ++ } ++ } + else + #endif + if (strSetting.Equals("videoscreen.resolution")) +diff --git a/xbmc/utils/ActorProtocol.cpp b/xbmc/utils/ActorProtocol.cpp +new file mode 100644 +index 0000000..e0cfd0e +--- /dev/null ++++ b/xbmc/utils/ActorProtocol.cpp +@@ -0,0 +1,253 @@ ++/* ++ * Copyright (C) 2005-2012 Team XBMC ++ * http://www.xbmc.org ++ * ++ * This Program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2, or (at your option) ++ * any later version. ++ * ++ * This Program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with XBMC; see the file COPYING. If not, see ++ * . ++ * ++ */ ++ ++#include "ActorProtocol.h" ++ ++using namespace Actor; ++ ++void Message::Release() ++{ ++ bool skip; ++ origin->Lock(); ++ skip = isSync ? !isSyncFini : false; ++ isSyncFini = true; ++ origin->Unlock(); ++ ++ if (skip) ++ return; ++ ++ // free data buffer ++ if (data != buffer) ++ delete [] data; ++ ++ // delete event in case of sync message ++ if (event) ++ delete event; ++ ++ origin->ReturnMessage(this); ++} ++ ++bool Message::Reply(int sig, void *data /* = NULL*/, int size /* = 0 */) ++{ ++ if (!isSync) ++ { ++ if (isOut) ++ return origin->SendInMessage(sig, data, size); ++ else ++ return origin->SendOutMessage(sig, data, size); ++ } ++ ++ origin->Lock(); ++ ++ if (!isSyncTimeout) ++ { ++ Message *msg = origin->GetMessage(); ++ msg->signal = sig; ++ msg->isOut = !isOut; ++ replyMessage = msg; ++ if (data) ++ { ++ if (size > MSG_INTERNAL_BUFFER_SIZE) ++ msg->data = new uint8_t[size]; ++ else ++ msg->data = msg->buffer; ++ memcpy(msg->data, data, size); ++ } ++ } ++ ++ origin->Unlock(); ++ ++ if (event) ++ event->Set(); ++ ++ return true; ++} ++ ++Protocol::~Protocol() ++{ ++ Message *msg; ++ Purge(); ++ while (!freeMessageQueue.empty()) ++ { ++ msg = freeMessageQueue.front(); ++ freeMessageQueue.pop(); ++ delete msg; ++ } ++} ++ ++Message *Protocol::GetMessage() ++{ ++ Message *msg; ++ ++ CSingleLock lock(criticalSection); ++ ++ if (!freeMessageQueue.empty()) ++ { ++ msg = freeMessageQueue.front(); ++ freeMessageQueue.pop(); ++ } ++ else ++ msg = new Message(); ++ ++ msg->isSync = false; ++ msg->isSyncFini = false; ++ msg->isSyncTimeout = false; ++ msg->event = NULL; ++ msg->data = NULL; ++ msg->payloadSize = 0; ++ msg->replyMessage = NULL; ++ msg->origin = this; ++ ++ return msg; ++} ++ ++void Protocol::ReturnMessage(Message *msg) ++{ ++ CSingleLock lock(criticalSection); ++ ++ freeMessageQueue.push(msg); ++} ++ ++bool Protocol::SendOutMessage(int signal, void *data /* = NULL */, int size /* = 0 */, Message *outMsg /* = NULL */) ++{ ++ Message *msg; ++ if (outMsg) ++ msg = outMsg; ++ else ++ msg = GetMessage(); ++ ++ msg->signal = signal; ++ msg->isOut = true; ++ ++ if (data) ++ { ++ if (size > MSG_INTERNAL_BUFFER_SIZE) ++ msg->data = new uint8_t[size]; ++ else ++ msg->data = msg->buffer; ++ memcpy(msg->data, data, size); ++ } ++ ++ { CSingleLock lock(criticalSection); ++ outMessages.push(msg); ++ } ++ containerOutEvent->Set(); ++ ++ return true; ++} ++ ++bool Protocol::SendInMessage(int signal, void *data /* = NULL */, int size /* = 0 */, Message *outMsg /* = NULL */) ++{ ++ Message *msg; ++ if (outMsg) ++ msg = outMsg; ++ else ++ msg = GetMessage(); ++ ++ msg->signal = signal; ++ msg->isOut = false; ++ ++ if (data) ++ { ++ if (size > MSG_INTERNAL_BUFFER_SIZE) ++ msg->data = new uint8_t[size]; ++ else ++ msg->data = msg->buffer; ++ memcpy(msg->data, data, size); ++ } ++ ++ { CSingleLock lock(criticalSection); ++ inMessages.push(msg); ++ } ++ containerInEvent->Set(); ++ ++ return true; ++} ++ ++ ++bool Protocol::SendOutMessageSync(int signal, Message **retMsg, int timeout, void *data /* = NULL */, int size /* = 0 */) ++{ ++ Message *msg = GetMessage(); ++ msg->isOut = true; ++ msg->isSync = true; ++ msg->event = new CEvent; ++ msg->event->Reset(); ++ SendOutMessage(signal, data, size, msg); ++ ++ if (!msg->event->WaitMSec(timeout)) ++ { ++ msg->origin->Lock(); ++ if (msg->replyMessage) ++ *retMsg = msg->replyMessage; ++ else ++ { ++ *retMsg = NULL; ++ msg->isSyncTimeout = true; ++ } ++ msg->origin->Unlock(); ++ } ++ else ++ *retMsg = msg->replyMessage; ++ ++ msg->Release(); ++ ++ if (*retMsg) ++ return true; ++ else ++ return false; ++} ++ ++bool Protocol::ReceiveOutMessage(Message **msg) ++{ ++ CSingleLock lock(criticalSection); ++ ++ if (outMessages.empty() || outDefered) ++ return false; ++ ++ *msg = outMessages.front(); ++ outMessages.pop(); ++ ++ return true; ++} ++ ++bool Protocol::ReceiveInMessage(Message **msg) ++{ ++ CSingleLock lock(criticalSection); ++ ++ if (inMessages.empty() || inDefered) ++ return false; ++ ++ *msg = inMessages.front(); ++ inMessages.pop(); ++ ++ return true; ++} ++ ++ ++void Protocol::Purge() ++{ ++ Message *msg; ++ ++ while (ReceiveInMessage(&msg)) ++ msg->Release(); ++ ++ while (ReceiveOutMessage(&msg)) ++ msg->Release(); ++} +diff --git a/xbmc/utils/ActorProtocol.h b/xbmc/utils/ActorProtocol.h +new file mode 100644 +index 0000000..e7108ac +--- /dev/null ++++ b/xbmc/utils/ActorProtocol.h +@@ -0,0 +1,87 @@ ++/* ++ * Copyright (C) 2005-2012 Team XBMC ++ * http://www.xbmc.org ++ * ++ * This Program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2, or (at your option) ++ * any later version. ++ * ++ * This Program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with XBMC; see the file COPYING. If not, see ++ * . ++ * ++ */ ++ ++#pragma once ++ ++#include "threads/Thread.h" ++#include "utils/log.h" ++#include ++#include "memory.h" ++ ++#define MSG_INTERNAL_BUFFER_SIZE 32 ++ ++namespace Actor ++{ ++ ++class Protocol; ++ ++class Message ++{ ++ friend class Protocol; ++public: ++ int signal; ++ bool isSync; ++ bool isSyncFini; ++ bool isOut; ++ bool isSyncTimeout; ++ int payloadSize; ++ uint8_t buffer[MSG_INTERNAL_BUFFER_SIZE]; ++ uint8_t *data; ++ Message *replyMessage; ++ Protocol *origin; ++ CEvent *event; ++ ++ void Release(); ++ bool Reply(int sig, void *data = NULL, int size = 0); ++ ++private: ++ Message() {isSync = false; data = NULL; event = NULL; replyMessage = NULL;}; ++}; ++ ++class Protocol ++{ ++public: ++ Protocol(std::string name, CEvent* inEvent, CEvent *outEvent) ++ : portName(name), inDefered(false), outDefered(false) {containerInEvent = inEvent; containerOutEvent = outEvent;}; ++ virtual ~Protocol(); ++ Message *GetMessage(); ++ void ReturnMessage(Message *msg); ++ bool SendOutMessage(int signal, void *data = NULL, int size = 0, Message *outMsg = NULL); ++ bool SendInMessage(int signal, void *data = NULL, int size = 0, Message *outMsg = NULL); ++ bool SendOutMessageSync(int signal, Message **retMsg, int timeout, void *data = NULL, int size = 0); ++ bool ReceiveOutMessage(Message **msg); ++ bool ReceiveInMessage(Message **msg); ++ void Purge(); ++ void DeferIn(bool value) {inDefered = value;}; ++ void DeferOut(bool value) {outDefered = value;}; ++ void Lock() {criticalSection.lock();}; ++ void Unlock() {criticalSection.unlock();}; ++ std::string portName; ++ ++protected: ++ CEvent *containerInEvent, *containerOutEvent; ++ CCriticalSection criticalSection; ++ std::queue outMessages; ++ std::queue inMessages; ++ std::queue freeMessageQueue; ++ bool inDefered, outDefered; ++}; ++ ++} +diff --git a/xbmc/utils/Makefile b/xbmc/utils/Makefile +index d201884..7d1f9f0 100644 +--- a/xbmc/utils/Makefile ++++ b/xbmc/utils/Makefile +@@ -70,6 +70,7 @@ SRCS=AlarmClock.cpp \ + Weather.cpp \ + XBMCTinyXML.cpp \ + XMLUtils.cpp \ ++ ActorProtocol.cpp \ + + LIB=utils.a + +diff --git a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp +index ac5f007..f25d10d 100644 +--- a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp ++++ b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp +@@ -103,7 +103,7 @@ void CGUIDialogVideoSettings::CreateSettings() + entries.push_back(make_pair(VS_INTERLACEMETHOD_INVERSE_TELECINE , 16314)); + entries.push_back(make_pair(VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL , 16311)); + entries.push_back(make_pair(VS_INTERLACEMETHOD_VDPAU_TEMPORAL , 16310)); +- entries.push_back(make_pair(VS_INTERLACEMETHOD_VDPAU_BOB , 16021)); ++ entries.push_back(make_pair(VS_INTERLACEMETHOD_VDPAU_BOB , 16325)); + entries.push_back(make_pair(VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF, 16318)); + entries.push_back(make_pair(VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF , 16317)); + entries.push_back(make_pair(VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE , 16314)); +diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h +index e7af3cb..2dd8a9f 100644 +--- a/xbmc/windowing/X11/WinSystemX11.h ++++ b/xbmc/windowing/X11/WinSystemX11.h +@@ -63,6 +63,7 @@ class CWinSystemX11 : public CWinSystemBase + // Local to WinSystemX11 only + Display* GetDisplay() { return m_dpy; } + GLXWindow GetWindow() { return m_glWindow; } ++ GLXContext GetGlxContext() { return m_glContext; } + + protected: + bool RefreshGlxContext(); +-- +1.7.10 + + +From c088467d9d0955051a510dadbddb270ddc3e3c20 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Tue, 25 Sep 2012 12:14:15 +0200 +Subject: [PATCH 12/73] linuxrenderer: drop method RenderMultiPass + +--- + xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 9 ++------- + xbmc/cores/VideoRenderers/LinuxRendererGL.h | 1 - + 2 files changed, 2 insertions(+), 8 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +index 4ee50c1..ea58c85 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +@@ -1205,7 +1205,8 @@ void CLinuxRendererGL::Render(DWORD flags, int renderBuffer) + break; + + case RQ_MULTIPASS: +- RenderMultiPass(renderBuffer, m_currentField); ++ RenderToFBO(renderBuffer, m_currentField); ++ RenderFromFBO(); + VerifyGLState(); + break; + } +@@ -1328,12 +1329,6 @@ void CLinuxRendererGL::RenderSinglePass(int index, int field) + VerifyGLState(); + } + +-void CLinuxRendererGL::RenderMultiPass(int index, int field) +-{ +- RenderToFBO(index, field); +- RenderFromFBO(); +-} +- + void CLinuxRendererGL::RenderToFBO(int index, int field) + { + YUVPLANES &planes = m_buffers[index].fields[field]; +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.h b/xbmc/cores/VideoRenderers/LinuxRendererGL.h +index 3218cd5..afc78c2 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.h ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.h +@@ -218,7 +218,6 @@ class CLinuxRendererGL : public CBaseRenderer + void CalculateTextureSourceRects(int source, int num_planes); + + // renderers +- void RenderMultiPass(int renderBuffer, int field); // multi pass glsl renderer + void RenderToFBO(int renderBuffer, int field); + void RenderFromFBO(); + void RenderSinglePass(int renderBuffer, int field); // single pass glsl renderer +-- +1.7.10 + + +From 0de3939247a63509e6bfab2e77c298eaa28aa29c Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Tue, 25 Sep 2012 13:20:47 +0200 +Subject: [PATCH 13/73] linuxrenderer: implement progressive weave for vdpau + +--- + xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 55 ++++++++++++++++++------- + xbmc/cores/VideoRenderers/LinuxRendererGL.h | 4 +- + 2 files changed, 41 insertions(+), 18 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +index ea58c85..b281ca7 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +@@ -689,18 +689,6 @@ void CLinuxRendererGL::RenderUpdate(bool clear, DWORD flags, DWORD alpha) + glDisable(GL_POLYGON_STIPPLE); + + } +- else if(m_format == RENDER_FMT_VDPAU_420 +- && !(flags & RENDER_FLAG_BOTH)) +- { +- glDisable(GL_BLEND); +- glColor4f(1.0f, 1.0f, 1.0f, 1.0f); +- Render(flags | RENDER_FLAG_TOP, index); +- +- glEnable(GL_BLEND); +- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +- glColor4f(1.0f, 1.0f, 1.0f, 128 / 255.0f); +- Render(flags | RENDER_FLAG_BOT , index); +- } + else + Render(flags, index); + +@@ -1200,13 +1188,21 @@ void CLinuxRendererGL::Render(DWORD flags, int renderBuffer) + { + case RQ_LOW: + case RQ_SINGLEPASS: +- RenderSinglePass(renderBuffer, m_currentField); ++ if (m_format == RENDER_FMT_VDPAU_420 && m_currentField == FIELD_FULL) ++ RenderProgressiveWeave(renderBuffer, m_currentField); ++ else ++ RenderSinglePass(renderBuffer, m_currentField); + VerifyGLState(); + break; + + case RQ_MULTIPASS: +- RenderToFBO(renderBuffer, m_currentField); +- RenderFromFBO(); ++ if (m_format == RENDER_FMT_VDPAU_420 && m_currentField == FIELD_FULL) ++ RenderProgressiveWeave(renderBuffer, m_currentField); ++ else ++ { ++ RenderToFBO(renderBuffer, m_currentField); ++ RenderFromFBO(); ++ } + VerifyGLState(); + break; + } +@@ -1329,7 +1325,7 @@ void CLinuxRendererGL::RenderSinglePass(int index, int field) + VerifyGLState(); + } + +-void CLinuxRendererGL::RenderToFBO(int index, int field) ++void CLinuxRendererGL::RenderToFBO(int index, int field, bool weave /*= false*/) + { + YUVPLANES &planes = m_buffers[index].fields[field]; + +@@ -1431,6 +1427,8 @@ void CLinuxRendererGL::RenderToFBO(int index, int field) + } + m_fbo.width *= planes[0].pixpertex_x; + m_fbo.height *= planes[0].pixpertex_y; ++ if (weave) ++ m_fbo.height *= 2; + + // 1st Pass to video frame size + glBegin(GL_QUADS); +@@ -1549,6 +1547,31 @@ void CLinuxRendererGL::RenderFromFBO() + VerifyGLState(); + } + ++void CLinuxRendererGL::RenderProgressiveWeave(int index, int field) ++{ ++ bool scaleUp = (int)m_sourceHeight < g_graphicsContext.GetHeight() || (int)m_sourceWidth < g_graphicsContext.GetWidth(); ++ ++ if (m_fbo.fbo.IsSupported() && (scaleUp || m_renderQuality == RQ_MULTIPASS)) ++ { ++ glEnable(GL_POLYGON_STIPPLE); ++ glPolygonStipple(stipple_weave); ++ RenderToFBO(index, FIELD_TOP, true); ++ glPolygonStipple(stipple_weave+4); ++ RenderToFBO(index, FIELD_BOT, true); ++ glDisable(GL_POLYGON_STIPPLE); ++ RenderFromFBO(); ++ } ++ else ++ { ++ glEnable(GL_POLYGON_STIPPLE); ++ glPolygonStipple(stipple_weave); ++ RenderSinglePass(index, FIELD_TOP); ++ glPolygonStipple(stipple_weave+4); ++ RenderSinglePass(index, FIELD_BOT); ++ glDisable(GL_POLYGON_STIPPLE); ++ } ++} ++ + void CLinuxRendererGL::RenderVDPAU(int index, int field) + { + #ifdef HAVE_LIBVDPAU +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.h b/xbmc/cores/VideoRenderers/LinuxRendererGL.h +index afc78c2..2fc34ae 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.h ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.h +@@ -218,12 +218,12 @@ class CLinuxRendererGL : public CBaseRenderer + void CalculateTextureSourceRects(int source, int num_planes); + + // renderers +- void RenderToFBO(int renderBuffer, int field); ++ void RenderToFBO(int renderBuffer, int field, bool weave = false); + void RenderFromFBO(); + void RenderSinglePass(int renderBuffer, int field); // single pass glsl renderer + void RenderSoftware(int renderBuffer, int field); // single pass s/w yuv2rgb renderer + void RenderVDPAU(int renderBuffer, int field); // render using vdpau hardware +- void RenderVDPAUYV12(int renderBuffer, int field); // render using vdpau hardware ++ void RenderProgressiveWeave(int renderBuffer, int field); // render using vdpau hardware + void RenderVAAPI(int renderBuffer, int field); // render using vdpau hardware + + struct +-- +1.7.10 + + +From c12380f4b9c9c2671bfd1ebd3e29ba7cd83ac95e Mon Sep 17 00:00:00 2001 +From: FernetMenta +Date: Thu, 5 Jul 2012 15:22:05 +0200 +Subject: [PATCH 14/73] X11: ditch SDL for video and window events + +--- + xbmc/Application.cpp | 2 +- + xbmc/system.h | 5 + + xbmc/windowing/Makefile | 1 + + xbmc/windowing/WinEvents.h | 4 + + xbmc/windowing/WinEventsX11.cpp | 765 +++++++++++++++++++++++++++++++++++ + xbmc/windowing/WinEventsX11.h | 57 +++ + xbmc/windowing/X11/WinSystemX11.cpp | 370 ++++++++++++----- + xbmc/windowing/X11/WinSystemX11.h | 9 +- + 8 files changed, 1112 insertions(+), 101 deletions(-) + create mode 100644 xbmc/windowing/WinEventsX11.cpp + create mode 100644 xbmc/windowing/WinEventsX11.h + +diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp +index 9a7b900..fc8e721 100644 +--- a/xbmc/Application.cpp ++++ b/xbmc/Application.cpp +@@ -790,7 +790,7 @@ bool CApplication::CreateGUI() + + uint32_t sdlFlags = 0; + +-#if defined(HAS_SDL_OPENGL) || (HAS_GLES == 2) ++#if (defined(HAS_SDL_OPENGL) || (HAS_GLES == 2)) && !defined(HAS_GLX) + sdlFlags |= SDL_INIT_VIDEO; + #endif + +diff --git a/xbmc/system.h b/xbmc/system.h +index 4165c01..32584b1 100644 +--- a/xbmc/system.h ++++ b/xbmc/system.h +@@ -162,16 +162,21 @@ + #define HAS_GL + #ifdef HAVE_X11 + #define HAS_GLX ++#define HAS_X11_WIN_EVENTS + #endif + #ifdef HAVE_SDL + #define HAS_SDL + #ifndef HAS_SDL_OPENGL + #define HAS_SDL_OPENGL + #endif ++#ifndef HAVE_X11 + #define HAS_SDL_WIN_EVENTS ++#endif + #else ++#ifndef HAVE_X11 + #define HAS_LINUX_EVENTS + #endif ++#endif + #define HAS_LINUX_NETWORK + #define HAS_LIRC + #ifdef HAVE_LIBPULSE +diff --git a/xbmc/windowing/Makefile b/xbmc/windowing/Makefile +index f109bec..f981642 100644 +--- a/xbmc/windowing/Makefile ++++ b/xbmc/windowing/Makefile +@@ -1,6 +1,7 @@ + SRCS=WinEventsSDL.cpp \ + WinEventsLinux.cpp \ + WinSystem.cpp \ ++ WinEventsX11.cpp \ + + LIB=windowing.a + +diff --git a/xbmc/windowing/WinEvents.h b/xbmc/windowing/WinEvents.h +index 6d322a9..5a671cc 100644 +--- a/xbmc/windowing/WinEvents.h ++++ b/xbmc/windowing/WinEvents.h +@@ -58,6 +58,10 @@ class CWinEventsBase + #include "WinEventsSDL.h" + #define CWinEvents CWinEventsSDL + ++#elif defined(TARGET_LINUX) && defined(HAS_X11_WIN_EVENTS) ++#include "WinEventsX11.h" ++#define CWinEvents CWinEventsX11 ++ + #elif defined(TARGET_LINUX) && defined(HAS_LINUX_EVENTS) + #include "WinEventsLinux.h" + #define CWinEvents CWinEventsLinux +diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp +new file mode 100644 +index 0000000..24477ae +--- /dev/null ++++ b/xbmc/windowing/WinEventsX11.cpp +@@ -0,0 +1,765 @@ ++/* ++* Copyright (C) 2005-2012 Team XBMC ++* http://www.xbmc.org ++* ++* This Program is free software; you can redistribute it and/or modify ++* it under the terms of the GNU General Public License as published by ++* the Free Software Foundation; either version 2, or (at your option) ++* any later version. ++* ++* This Program is distributed in the hope that it will be useful, ++* but WITHOUT ANY WARRANTY; without even the implied warranty of ++* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++* GNU General Public License for more details. ++* ++* You should have received a copy of the GNU General Public License ++* along with XBMC; see the file COPYING. If not, write to ++* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ++* http://www.gnu.org/copyleft/gpl.html ++* ++*/ ++ ++#include "system.h" ++ ++#ifdef HAS_X11_WIN_EVENTS ++ ++#include "WinEvents.h" ++#include "WinEventsX11.h" ++#include "Application.h" ++#include "ApplicationMessenger.h" ++#include ++#include "X11/WinSystemX11GL.h" ++#include "X11/keysymdef.h" ++#include "X11/XF86keysym.h" ++#include "utils/log.h" ++#include "guilib/GUIWindowManager.h" ++#include "input/MouseStat.h" ++ ++CWinEventsX11* CWinEventsX11::WinEvents = 0; ++ ++static uint32_t SymMappingsX11[][2] = ++{ ++ {XK_BackSpace, XBMCK_BACKSPACE} ++, {XK_Tab, XBMCK_TAB} ++, {XK_Clear, XBMCK_CLEAR} ++, {XK_Return, XBMCK_RETURN} ++, {XK_Pause, XBMCK_PAUSE} ++, {XK_Escape, XBMCK_ESCAPE} ++, {XK_Delete, XBMCK_DELETE} ++// multi-media keys ++, {XF86XK_Back, XBMCK_BROWSER_BACK} ++, {XF86XK_Forward, XBMCK_BROWSER_FORWARD} ++, {XF86XK_Refresh, XBMCK_BROWSER_REFRESH} ++, {XF86XK_Stop, XBMCK_BROWSER_STOP} ++, {XF86XK_Search, XBMCK_BROWSER_SEARCH} ++, {XF86XK_Favorites, XBMCK_BROWSER_FAVORITES} ++, {XF86XK_HomePage, XBMCK_BROWSER_HOME} ++, {XF86XK_AudioMute, XBMCK_VOLUME_MUTE} ++, {XF86XK_AudioLowerVolume, XBMCK_VOLUME_DOWN} ++, {XF86XK_AudioRaiseVolume, XBMCK_VOLUME_UP} ++, {XF86XK_AudioNext, XBMCK_MEDIA_NEXT_TRACK} ++, {XF86XK_AudioPrev, XBMCK_MEDIA_PREV_TRACK} ++, {XF86XK_AudioStop, XBMCK_MEDIA_STOP} ++, {XF86XK_AudioPause, XBMCK_MEDIA_PLAY_PAUSE} ++, {XF86XK_Mail, XBMCK_LAUNCH_MAIL} ++, {XF86XK_Select, XBMCK_LAUNCH_MEDIA_SELECT} ++, {XF86XK_Launch0, XBMCK_LAUNCH_APP1} ++, {XF86XK_Launch1, XBMCK_LAUNCH_APP2} ++, {XF86XK_WWW, XBMCK_LAUNCH_FILE_BROWSER} ++, {XF86XK_AudioMedia, XBMCK_LAUNCH_MEDIA_CENTER } ++ // Numeric keypad ++, {XK_KP_0, XBMCK_KP0} ++, {XK_KP_1, XBMCK_KP1} ++, {XK_KP_2, XBMCK_KP2} ++, {XK_KP_3, XBMCK_KP3} ++, {XK_KP_4, XBMCK_KP4} ++, {XK_KP_5, XBMCK_KP5} ++, {XK_KP_6, XBMCK_KP6} ++, {XK_KP_7, XBMCK_KP7} ++, {XK_KP_8, XBMCK_KP8} ++, {XK_KP_9, XBMCK_KP9} ++, {XK_KP_Separator, XBMCK_KP_PERIOD} ++, {XK_KP_Divide, XBMCK_KP_DIVIDE} ++, {XK_KP_Multiply, XBMCK_KP_MULTIPLY} ++, {XK_KP_Subtract, XBMCK_KP_MINUS} ++, {XK_KP_Add, XBMCK_KP_PLUS} ++, {XK_KP_Enter, XBMCK_KP_ENTER} ++, {XK_KP_Equal, XBMCK_KP_EQUALS} ++ // Arrows + Home/End pad ++, {XK_Up, XBMCK_UP} ++, {XK_Down, XBMCK_DOWN} ++, {XK_Right, XBMCK_RIGHT} ++, {XK_Left, XBMCK_LEFT} ++, {XK_Insert, XBMCK_INSERT} ++, {XK_Home, XBMCK_HOME} ++, {XK_End, XBMCK_END} ++, {XK_Page_Up, XBMCK_PAGEUP} ++, {XK_Page_Down, XBMCK_PAGEDOWN} ++ // Function keys ++, {XK_F1, XBMCK_F1} ++, {XK_F2, XBMCK_F2} ++, {XK_F3, XBMCK_F3} ++, {XK_F4, XBMCK_F4} ++, {XK_F5, XBMCK_F5} ++, {XK_F6, XBMCK_F6} ++, {XK_F7, XBMCK_F7} ++, {XK_F8, XBMCK_F8} ++, {XK_F9, XBMCK_F9} ++, {XK_F10, XBMCK_F10} ++, {XK_F11, XBMCK_F11} ++, {XK_F12, XBMCK_F12} ++, {XK_F13, XBMCK_F13} ++, {XK_F14, XBMCK_F14} ++, {XK_F15, XBMCK_F15} ++ // Key state modifier keys ++, {XK_Num_Lock, XBMCK_NUMLOCK} ++, {XK_Caps_Lock, XBMCK_CAPSLOCK} ++, {XK_Scroll_Lock, XBMCK_SCROLLOCK} ++, {XK_Shift_R, XBMCK_RSHIFT} ++, {XK_Shift_L, XBMCK_LSHIFT} ++, {XK_Control_R, XBMCK_RCTRL} ++, {XK_Control_L, XBMCK_LCTRL} ++, {XK_Alt_R, XBMCK_RALT} ++, {XK_Alt_L, XBMCK_LALT} ++, {XK_Meta_R, XBMCK_RMETA} ++, {XK_Meta_L, XBMCK_LMETA} ++, {XK_Super_L, XBMCK_LSUPER} ++, {XK_Super_R, XBMCK_RSUPER} ++, {XK_Mode_switch, XBMCK_MODE} ++, {XK_Multi_key, XBMCK_COMPOSE} ++ // Miscellaneous function keys ++, {XK_Help, XBMCK_HELP} ++, {XK_Print, XBMCK_PRINT} ++//, {0, XBMCK_SYSREQ} ++, {XK_Break, XBMCK_BREAK} ++, {XK_Menu, XBMCK_MENU} ++, {XF86XK_PowerOff, XBMCK_POWER} ++, {XK_EcuSign, XBMCK_EURO} ++, {XK_Undo, XBMCK_UNDO} ++ /* Media keys */ ++, {XF86XK_Eject, XBMCK_EJECT} ++, {XF86XK_Stop, XBMCK_STOP} ++, {XF86XK_AudioRecord, XBMCK_RECORD} ++, {XF86XK_AudioRewind, XBMCK_REWIND} ++, {XF86XK_Phone, XBMCK_PHONE} ++, {XF86XK_AudioPlay, XBMCK_PLAY} ++, {XF86XK_AudioRandomPlay, XBMCK_SHUFFLE} ++, {XF86XK_AudioForward, XBMCK_FASTFORWARD} ++}; ++ ++ ++CWinEventsX11::CWinEventsX11() ++{ ++ m_display = 0; ++ m_window = 0; ++ m_keybuf = 0; ++ m_utf16buf = 0; ++} ++ ++CWinEventsX11::~CWinEventsX11() ++{ ++ if (m_keybuf); ++ { ++ free(m_keybuf); ++ m_keybuf = 0; ++ } ++ ++ if (m_utf16buf) ++ { ++ free(m_utf16buf); ++ m_utf16buf = 0; ++ } ++ ++ if (m_xic) ++ { ++ XUnsetICFocus(m_xic); ++ XDestroyIC(m_xic); ++ m_xic = 0; ++ } ++ ++ if (m_xim) ++ { ++ XCloseIM(m_xim); ++ m_xim = 0; ++ } ++ ++ m_symLookupTable.clear(); ++} ++ ++bool CWinEventsX11::Init(Display *dpy, Window win) ++{ ++ if (WinEvents) ++ return true; ++ ++ WinEvents = new CWinEventsX11(); ++ WinEvents->m_display = dpy; ++ WinEvents->m_window = win; ++ WinEvents->m_keybuf = (char*)malloc(32*sizeof(char)); ++ WinEvents->m_utf16buf = (uint16_t*)malloc(32*sizeof(uint16_t)); ++ WinEvents->m_keymodState = 0; ++ WinEvents->m_wmDeleteMessage = XInternAtom(dpy, "WM_DELETE_WINDOW", False); ++ WinEvents->m_structureChanged = false; ++ memset(&(WinEvents->m_lastKey), 0, sizeof(XBMC_Event)); ++ ++ // open input method ++ char *old_locale = NULL, *old_modifiers = NULL; ++ char res_name[8]; ++ const char *p; ++ size_t n; ++ ++ // set resource name to xbmc, not used ++ strcpy(res_name, "xbmc"); ++ ++ // save current locale, this should be "C" ++ p = setlocale(LC_ALL, NULL); ++ if (p) ++ { ++ old_locale = (char*)malloc(strlen(p) +1); ++ strcpy(old_locale, p); ++ } ++ p = XSetLocaleModifiers(NULL); ++ if (p) ++ { ++ old_modifiers = (char*)malloc(strlen(p) +1); ++ strcpy(old_modifiers, p); ++ } ++ ++ // set users preferences and open input method ++ p = setlocale(LC_ALL, ""); ++ XSetLocaleModifiers(""); ++ WinEvents->m_xim = XOpenIM(WinEvents->m_display, NULL, res_name, res_name); ++ ++ // restore old locale ++ if (old_locale) ++ { ++ setlocale(LC_ALL, old_locale); ++ free(old_locale); ++ } ++ if (old_modifiers) ++ { ++ XSetLocaleModifiers(old_modifiers); ++ free(old_modifiers); ++ } ++ ++ WinEvents->m_xic = NULL; ++ if (WinEvents->m_xim) ++ { ++ WinEvents->m_xic = XCreateIC(WinEvents->m_xim, ++ XNClientWindow, WinEvents->m_window, ++ XNFocusWindow, WinEvents->m_window, ++ XNInputStyle, XIMPreeditNothing | XIMStatusNothing, ++ XNResourceName, res_name, ++ XNResourceClass, res_name, ++ NULL); ++ } ++ ++ if (!WinEvents->m_xic) ++ CLog::Log(LOGWARNING,"CWinEventsX11::Init - no input method found"); ++ ++ // build Keysym lookup table ++ for (unsigned int i = 0; i < sizeof(SymMappingsX11)/(2*sizeof(uint32_t)); ++i) ++ { ++ WinEvents->m_symLookupTable[SymMappingsX11[i][0]] = SymMappingsX11[i][1]; ++ } ++ ++ return true; ++} ++ ++void CWinEventsX11::Quit() ++{ ++ if (!WinEvents) ++ return; ++ ++ delete WinEvents; ++ WinEvents = 0; ++} ++ ++bool CWinEventsX11::HasStructureChanged() ++{ ++ if (!WinEvents) ++ return false; ++ ++ bool ret = WinEvents->m_structureChanged; ++ WinEvents->m_structureChanged = false; ++ return ret; ++} ++ ++bool CWinEventsX11::MessagePump() ++{ ++ if (!WinEvents) ++ return false; ++ ++ bool ret = false; ++ XEvent xevent; ++ unsigned long serial = 0; ++ ++ while (WinEvents && XPending(WinEvents->m_display)) ++ { ++ memset(&xevent, 0, sizeof (XEvent)); ++ XNextEvent(WinEvents->m_display, &xevent); ++ ++ // ignore events generated by auto-repeat ++ if (xevent.type == KeyRelease && XPending(WinEvents->m_display)) ++ { ++ XEvent peekevent; ++ XPeekEvent(WinEvents->m_display, &peekevent); ++ if ((peekevent.type == KeyPress) && ++ (peekevent.xkey.keycode == xevent.xkey.keycode) && ++ ((peekevent.xkey.time - xevent.xkey.time) < 2)) ++ { ++ XNextEvent(WinEvents->m_display, &peekevent); ++ continue; ++ } ++ } ++ ++ if (XFilterEvent(&xevent, None)) ++ continue; ++ ++ switch (xevent.type) ++ { ++ case MapNotify: ++ { ++ g_application.m_AppActive = true; ++ break; ++ } ++ ++ case UnmapNotify: ++ { ++ g_application.m_AppActive = false; ++ break; ++ } ++ ++ case FocusIn: ++ { ++ if (WinEvents->m_xic) ++ XSetICFocus(WinEvents->m_xic); ++ g_application.m_AppFocused = true; ++ if (serial == xevent.xfocus.serial) ++ break; ++ g_Windowing.NotifyAppFocusChange(g_application.m_AppFocused); ++ break; ++ } ++ ++ case FocusOut: ++ { ++ if (WinEvents->m_xic) ++ XUnsetICFocus(WinEvents->m_xic); ++ g_application.m_AppFocused = false; ++ g_Windowing.NotifyAppFocusChange(g_application.m_AppFocused); ++ serial = xevent.xfocus.serial; ++ break; ++ } ++ ++ case Expose: ++ { ++ g_windowManager.MarkDirty(); ++ break; ++ } ++ ++ case ConfigureNotify: ++ { ++ if (xevent.xconfigure.window != WinEvents->m_window) ++ break; ++ ++ WinEvents->m_structureChanged = true; ++ XBMC_Event newEvent; ++ memset(&newEvent, 0, sizeof(newEvent)); ++ newEvent.type = XBMC_VIDEORESIZE; ++ newEvent.resize.w = xevent.xconfigure.width; ++ newEvent.resize.h = xevent.xconfigure.height; ++ ret |= g_application.OnEvent(newEvent); ++ g_windowManager.MarkDirty(); ++ break; ++ } ++ ++ case ClientMessage: ++ { ++ if (xevent.xclient.data.l[0] == WinEvents->m_wmDeleteMessage) ++ if (!g_application.m_bStop) CApplicationMessenger::Get().Quit(); ++ break; ++ } ++ ++ case KeyPress: ++ { ++ XBMC_Event newEvent; ++ memset(&newEvent, 0, sizeof(newEvent)); ++ newEvent.type = XBMC_KEYDOWN; ++ KeySym xkeysym; ++ ++ // fallback if we have no IM ++ if (!WinEvents->m_xic) ++ { ++ static XComposeStatus state; ++ char keybuf[32]; ++ xkeysym = XLookupKeysym(&xevent.xkey, 0); ++ newEvent.key.keysym.sym = LookupXbmcKeySym(xkeysym); ++ newEvent.key.keysym.scancode = xevent.xkey.keycode; ++ newEvent.key.state = xevent.xkey.state; ++ newEvent.key.type = xevent.xkey.type; ++ if (XLookupString(&xevent.xkey, keybuf, sizeof(keybuf), NULL, &state)) ++ { ++ newEvent.key.keysym.unicode = keybuf[0]; ++ } ++ ret |= ProcessKey(newEvent, 500); ++ break; ++ } ++ ++ Status status; ++ int utf16size; ++ int utf16length; ++ int len; ++ len = Xutf8LookupString(WinEvents->m_xic, &xevent.xkey, ++ WinEvents->m_keybuf, sizeof(WinEvents->m_keybuf), ++ &xkeysym, &status); ++ if (status == XBufferOverflow) ++ { ++ WinEvents->m_keybuf = (char*)realloc(WinEvents->m_keybuf, len*sizeof(char)); ++ len = Xutf8LookupString(WinEvents->m_xic, &xevent.xkey, ++ WinEvents->m_keybuf, sizeof(WinEvents->m_keybuf), ++ &xkeysym, &status); ++ } ++ switch (status) ++ { ++ case XLookupNone: ++ break; ++ case XLookupChars: ++ case XLookupBoth: ++ { ++ if (len == 0) ++ break; ++ utf16size = len * sizeof(uint16_t); ++ if (utf16size > sizeof(WinEvents->m_utf16buf)) ++ { ++ WinEvents->m_utf16buf = (uint16_t *)realloc(WinEvents->m_utf16buf,utf16size); ++ if (WinEvents->m_utf16buf == NULL) ++ { ++ break; ++ } ++ } ++ utf16length = Utf8ToUnicode(WinEvents->m_keybuf, len, WinEvents->m_utf16buf, utf16size); ++ if (utf16length < 0) ++ { ++ break; ++ } ++ for (unsigned int i = 0; i < utf16length - 1; i++) ++ { ++ newEvent.key.keysym.sym = XBMCK_UNKNOWN; ++ newEvent.key.keysym.unicode = WinEvents->m_utf16buf[i]; ++ newEvent.key.state = xevent.xkey.state; ++ newEvent.key.type = xevent.xkey.type; ++ ret |= ProcessKey(newEvent, 500); ++ } ++ if (utf16length > 0) ++ { ++ newEvent.key.keysym.scancode = xevent.xkey.keycode; ++ xkeysym = XLookupKeysym(&xevent.xkey, 0); ++ newEvent.key.keysym.sym = LookupXbmcKeySym(xkeysym); ++ newEvent.key.keysym.unicode = WinEvents->m_utf16buf[utf16length - 1]; ++ newEvent.key.state = xevent.xkey.state; ++ newEvent.key.type = xevent.xkey.type; ++ ++ ret |= ProcessKey(newEvent, 500); ++ } ++ break; ++ } ++ ++ case XLookupKeySym: ++ { ++ newEvent.key.keysym.scancode = xevent.xkey.keycode; ++ newEvent.key.keysym.sym = LookupXbmcKeySym(xkeysym); ++ newEvent.key.state = xevent.xkey.state; ++ newEvent.key.type = xevent.xkey.type; ++ ret |= ProcessKey(newEvent, 500); ++ break; ++ } ++ ++ }// switch status ++ break; ++ } //KeyPress ++ ++ case KeyRelease: ++ { ++ XBMC_Event newEvent; ++ KeySym xkeysym; ++ memset(&newEvent, 0, sizeof(newEvent)); ++ newEvent.type = XBMC_KEYUP; ++ xkeysym = XLookupKeysym(&xevent.xkey, 0); ++ newEvent.key.keysym.scancode = xevent.xkey.keycode; ++ newEvent.key.keysym.sym = LookupXbmcKeySym(xkeysym); ++ newEvent.key.state = xevent.xkey.state; ++ newEvent.key.type = xevent.xkey.type; ++ ret |= ProcessKey(newEvent, 0); ++ break; ++ } ++ ++ // lose mouse coverage ++ case LeaveNotify: ++ { ++ g_Mouse.SetActive(false); ++ break; ++ } ++ ++ case MotionNotify: ++ { ++ XBMC_Event newEvent; ++ memset(&newEvent, 0, sizeof(newEvent)); ++ newEvent.type = XBMC_MOUSEMOTION; ++ newEvent.motion.xrel = (int16_t)xevent.xmotion.x_root; ++ newEvent.motion.yrel = (int16_t)xevent.xmotion.y_root; ++ newEvent.motion.x = (int16_t)xevent.xmotion.x; ++ newEvent.motion.y = (int16_t)xevent.xmotion.y; ++ ret |= g_application.OnEvent(newEvent); ++ break; ++ } ++ ++ case ButtonPress: ++ { ++ XBMC_Event newEvent; ++ memset(&newEvent, 0, sizeof(newEvent)); ++ newEvent.type = XBMC_MOUSEBUTTONDOWN; ++ newEvent.button.button = (unsigned char)xevent.xbutton.button; ++ newEvent.button.state = XBMC_PRESSED; ++ newEvent.button.x = (int16_t)xevent.xbutton.x; ++ newEvent.button.y = (int16_t)xevent.xbutton.y; ++ ret |= g_application.OnEvent(newEvent); ++ break; ++ } ++ ++ case ButtonRelease: ++ { ++ XBMC_Event newEvent; ++ memset(&newEvent, 0, sizeof(newEvent)); ++ newEvent.type = XBMC_MOUSEBUTTONUP; ++ newEvent.button.button = (unsigned char)xevent.xbutton.button; ++ newEvent.button.state = XBMC_RELEASED; ++ newEvent.button.x = (int16_t)xevent.xbutton.x; ++ newEvent.button.y = (int16_t)xevent.xbutton.y; ++ ret |= g_application.OnEvent(newEvent); ++ break; ++ } ++ ++ default: ++ { ++ break; ++ } ++ }// switch event.type ++ }// while ++ ++ ret |= ProcessKeyRepeat(); ++ ++ return ret; ++} ++ ++bool CWinEventsX11::ProcessKey(XBMC_Event &event, int repeatDelay) ++{ ++ if (event.type == XBMC_KEYDOWN) ++ { ++ // check key modifiers ++ switch(event.key.keysym.sym) ++ { ++ case XBMCK_LSHIFT: ++ WinEvents->m_keymodState |= XBMCKMOD_LSHIFT; ++ break; ++ case XBMCK_RSHIFT: ++ WinEvents->m_keymodState |= XBMCKMOD_RSHIFT; ++ break; ++ case XBMCK_LCTRL: ++ WinEvents->m_keymodState |= XBMCKMOD_LCTRL; ++ break; ++ case XBMCK_RCTRL: ++ WinEvents->m_keymodState |= XBMCKMOD_RCTRL; ++ break; ++ case XBMCK_LALT: ++ WinEvents->m_keymodState |= XBMCKMOD_LALT; ++ break; ++ case XBMCK_RALT: ++ WinEvents->m_keymodState |= XBMCKMOD_RCTRL; ++ break; ++ case XBMCK_LMETA: ++ WinEvents->m_keymodState |= XBMCKMOD_LMETA; ++ break; ++ case XBMCK_RMETA: ++ WinEvents->m_keymodState |= XBMCKMOD_RMETA; ++ break; ++ case XBMCK_MODE: ++ WinEvents->m_keymodState |= XBMCKMOD_MODE; ++ break; ++ default: ++ break; ++ } ++ event.key.keysym.mod = (XBMCMod)WinEvents->m_keymodState; ++ memcpy(&(WinEvents->m_lastKey), &event, sizeof(event)); ++ WinEvents->m_repeatKeyTimeout.Set(repeatDelay); ++ ++ bool ret = ProcessShortcuts(event); ++ if (ret) ++ return ret; ++ } ++ else if (event.type == XBMC_KEYUP) ++ { ++ switch(event.key.keysym.sym) ++ { ++ case XBMCK_LSHIFT: ++ WinEvents->m_keymodState &= ~XBMCKMOD_LSHIFT; ++ break; ++ case XBMCK_RSHIFT: ++ WinEvents->m_keymodState &= ~XBMCKMOD_RSHIFT; ++ break; ++ case XBMCK_LCTRL: ++ WinEvents->m_keymodState &= ~XBMCKMOD_LCTRL; ++ break; ++ case XBMCK_RCTRL: ++ WinEvents->m_keymodState &= ~XBMCKMOD_RCTRL; ++ break; ++ case XBMCK_LALT: ++ WinEvents->m_keymodState &= ~XBMCKMOD_LALT; ++ break; ++ case XBMCK_RALT: ++ WinEvents->m_keymodState &= ~XBMCKMOD_RCTRL; ++ break; ++ case XBMCK_LMETA: ++ WinEvents->m_keymodState &= ~XBMCKMOD_LMETA; ++ break; ++ case XBMCK_RMETA: ++ WinEvents->m_keymodState &= ~XBMCKMOD_RMETA; ++ break; ++ case XBMCK_MODE: ++ WinEvents->m_keymodState &= ~XBMCKMOD_MODE; ++ break; ++ default: ++ break; ++ } ++ event.key.keysym.mod = (XBMCMod)WinEvents->m_keymodState; ++ memset(&(WinEvents->m_lastKey), 0, sizeof(event)); ++ } ++ ++ return g_application.OnEvent(event); ++} ++ ++bool CWinEventsX11::ProcessShortcuts(XBMC_Event& event) ++{ ++ if (event.key.keysym.mod & XBMCKMOD_ALT) ++ { ++ switch(event.key.keysym.sym) ++ { ++ case XBMCK_TAB: // ALT+TAB to minimize/hide ++ g_application.Minimize(); ++ return true; ++ ++ default: ++ return false; ++ } ++ } ++ return false; ++} ++ ++bool CWinEventsX11::ProcessKeyRepeat() ++{ ++ if (WinEvents && (WinEvents->m_lastKey.type == XBMC_KEYDOWN)) ++ { ++ if (WinEvents->m_repeatKeyTimeout.IsTimePast()) ++ { ++ return ProcessKey(WinEvents->m_lastKey, 10); ++ } ++ } ++ return false; ++} ++ ++int CWinEventsX11::Utf8ToUnicode(const char *utf8, const int utf8Length, uint16_t *utf16, const int utf16MaxLength) ++{ ++ // p moves over the output buffer. max_ptr points to the next to the last slot of the buffer. ++ uint16_t *p = utf16; ++ uint16_t const *const maxPtr = utf16 + utf16MaxLength; ++ ++ // end_of_input points to the last byte of input as opposed to the next to the last byte. ++ char const *const endOfInput = utf8 + utf8Length - 1; ++ ++ while (utf8 <= endOfInput) ++ { ++ unsigned char const c = *utf8; ++ if (p >= maxPtr) ++ { ++ //No more output space. ++ return -1; ++ } ++ if (c < 0x80) ++ { ++ //One byte ASCII. ++ *p++ = c; ++ utf8 += 1; ++ } ++ else if (c < 0xC0) ++ { ++ // Follower byte without preceding leader bytes. ++ return -1; ++ } ++ // 11 bits ++ else if (c < 0xE0) ++ { ++ // Two byte sequence. We need one follower byte. ++ if (endOfInput - utf8 < 1 || (((utf8[1] ^ 0x80)) & 0xC0)) ++ { ++ return -1; ++ } ++ *p++ = (uint16_t)(((c & 0x1F) << 6) + (utf8[1] & 0x3F)); ++ utf8 += 2; ++ } ++ // 16 bis ++ else if (c < 0xF0) ++ { ++ // Three byte sequence. We need two follower byte. ++ if (endOfInput - utf8 < 2 || ((utf8[1] ^ 0x80) & 0xC0) || ((utf8[2] ^ 0x80) & 0xC0)) ++ { ++ return -1; ++ } ++ *p++ = (uint16_t)(((c & 0xF) << 12) + ((utf8[1] & 0x3F) << 6) + (utf8[2] & 0x3F)); ++ utf8 += 3; ++ } ++ // 21 bits ++ else if (c < 0xF8) ++ { ++ int plane; ++ // Four byte sequence. We need three follower bytes. ++ if (endOfInput - utf8 < 3 || ((utf8[1] ^ 0x80) & 0xC0) || ++ ((utf8[2] ^ 0x80) & 0xC0) || ((utf8[3] ^ 0x80) & 0xC0)) ++ { ++ return -1; ++ } ++ uint32_t unicode = ((c & 0x7) << 18) + ((utf8[1] & 0x3F) << 12) + ++ ((utf8[2] & 0x3F) << 6) + (utf8[3] & 0x3F); ++ utf8 += 4; ++ CLog::Log(LOGERROR, "CWinEventsX11::Utf8ToUnicode: 4 byte unicode not supported"); ++ } ++ // 26 bits ++ else if (c < 0xFC) ++ { ++ CLog::Log(LOGERROR, "CWinEventsX11::Utf8ToUnicode: 4 byte unicode not supported"); ++ utf8 += 5; ++ } ++ // 31 bit ++ else ++ { ++ CLog::Log(LOGERROR, "CWinEventsX11::Utf8ToUnicode: 4 byte unicode not supported"); ++ utf8 += 6; ++ } ++ } ++ return p - utf16; ++} ++ ++XBMCKey CWinEventsX11::LookupXbmcKeySym(KeySym keysym) ++{ ++ // try direct mapping first ++ std::map::iterator it; ++ it = WinEvents->m_symLookupTable.find(keysym); ++ if (it != WinEvents->m_symLookupTable.end()) ++ { ++ return (XBMCKey)(it->second); ++ } ++ ++ // try ascii mappings ++ if (keysym>>8 == 0x00) ++ return (XBMCKey)(keysym & 0xFF); ++ ++ return (XBMCKey)keysym; ++} ++#endif +diff --git a/xbmc/windowing/WinEventsX11.h b/xbmc/windowing/WinEventsX11.h +new file mode 100644 +index 0000000..e9b7553 +--- /dev/null ++++ b/xbmc/windowing/WinEventsX11.h +@@ -0,0 +1,57 @@ ++/* ++* Copyright (C) 2005-2012 Team XBMC ++* http://www.xbmc.org ++* ++* This Program is free software; you can redistribute it and/or modify ++* it under the terms of the GNU General Public License as published by ++* the Free Software Foundation; either version 2, or (at your option) ++* any later version. ++* ++* This Program is distributed in the hope that it will be useful, ++* but WITHOUT ANY WARRANTY; without even the implied warranty of ++* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++* GNU General Public License for more details. ++* ++* You should have received a copy of the GNU General Public License ++* along with XBMC; see the file COPYING. If not, write to ++* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ++* http://www.gnu.org/copyleft/gpl.html ++* ++*/ ++#pragma once ++ ++#include "WinEvents.h" ++#include ++#include "threads/SystemClock.h" ++#include ++ ++class CWinEventsX11 : public CWinEventsBase ++{ ++public: ++ CWinEventsX11(); ++ virtual ~CWinEventsX11(); ++ static bool Init(Display *dpy, Window win); ++ static void Quit(); ++ static bool HasStructureChanged(); ++ static bool MessagePump(); ++ ++protected: ++ static int Utf8ToUnicode(const char *utf8, const int utf8Length, uint16_t *utf16, const int utf16MaxLength); ++ static XBMCKey LookupXbmcKeySym(KeySym keysym); ++ static bool ProcessKey(XBMC_Event &event, int repeatDelay); ++ static bool ProcessKeyRepeat(); ++ static bool ProcessShortcuts(XBMC_Event& event); ++ static CWinEventsX11 *WinEvents; ++ Display *m_display; ++ Window m_window; ++ Atom m_wmDeleteMessage; ++ char *m_keybuf; ++ uint16_t *m_utf16buf; ++ XIM m_xim; ++ XIC m_xic; ++ XBMC_Event m_lastKey; ++ XbmcThreads::EndTime m_repeatKeyTimeout; ++ std::map m_symLookupTable; ++ int m_keymodState; ++ bool m_structureChanged; ++}; +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index a839709..76ef462 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -22,7 +22,6 @@ + + #ifdef HAS_GLX + +-#include + #include "WinSystemX11.h" + #include "settings/Settings.h" + #include "guilib/Texture.h" +@@ -31,27 +30,30 @@ + #include "XRandR.h" + #include + #include "threads/SingleLock.h" +-#include + #include "cores/VideoRenderers/RenderManager.h" + #include "utils/TimeUtils.h" ++#include "settings/GUISettings.h" + + #if defined(HAS_XRANDR) + #include + #endif + ++#include "../WinEvents.h" ++#include "input/MouseStat.h" ++ + using namespace std; + + CWinSystemX11::CWinSystemX11() : CWinSystemBase() + { + m_eWindowSystem = WINDOW_SYSTEM_X11; + m_glContext = NULL; +- m_SDLSurface = NULL; + m_dpy = NULL; + m_glWindow = 0; +- m_wmWindow = 0; + m_bWasFullScreenBeforeMinimize = false; + m_minimized = false; ++ m_bIgnoreNextFocusMessage = false; + m_dpyLostTime = 0; ++ m_invisibleCursor = 0; + + XSetErrorHandler(XErrorHandler); + } +@@ -64,18 +66,6 @@ bool CWinSystemX11::InitWindowSystem() + { + if ((m_dpy = XOpenDisplay(NULL))) + { +- +- SDL_EnableUNICODE(1); +- // set repeat to 10ms to ensure repeat time < frame time +- // so that hold times can be reliably detected +- SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, 10); +- +- SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); +- SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); +- SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); +- SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); +- SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); +- + return CWinSystemBase::InitWindowSystem(); + } + else +@@ -113,45 +103,37 @@ bool CWinSystemX11::DestroyWindowSystem() + + bool CWinSystemX11::CreateNewWindow(const CStdString& name, bool fullScreen, RESOLUTION_INFO& res, PHANDLE_EVENT_FUNC userFunction) + { +- RESOLUTION_INFO& desktop = g_settings.m_ResInfo[RES_DESKTOP]; +- +- if (fullScreen && +- (res.iWidth != desktop.iWidth || res.iHeight != desktop.iHeight || +- res.fRefreshRate != desktop.fRefreshRate || res.iScreen != desktop.iScreen)) +- { +- //on the first call to SDL_SetVideoMode, SDL stores the current displaymode +- //SDL restores the displaymode on SDL_QUIT(), if we change the displaymode +- //before the first call to SDL_SetVideoMode, SDL changes the displaymode back +- //to the wrong mode on exit +- +- CLog::Log(LOGINFO, "CWinSystemX11::CreateNewWindow initializing to desktop resolution first"); +- if (!SetFullScreen(true, desktop, false)) +- return false; +- } +- + if(!SetFullScreen(fullScreen, res, false)) + return false; + +- CBaseTexture* iconTexture = CTexture::LoadFromFile("special://xbmc/media/icon.png"); +- +- if (iconTexture) +- SDL_WM_SetIcon(SDL_CreateRGBSurfaceFrom(iconTexture->GetPixels(), iconTexture->GetWidth(), iconTexture->GetHeight(), 32, iconTexture->GetPitch(), 0xff0000, 0x00ff00, 0x0000ff, 0xff000000L), NULL); +- SDL_WM_SetCaption("XBMC Media Center", NULL); +- delete iconTexture; +- +- // register XRandR Events +-#if defined(HAS_XRANDR) +- int iReturn; +- XRRQueryExtension(m_dpy, &m_RREventBase, &iReturn); +- XRRSelectInput(m_dpy, m_wmWindow, RRScreenChangeNotifyMask); +-#endif +- + m_bWindowCreated = true; + return true; + } + + bool CWinSystemX11::DestroyWindow() + { ++ if (!m_glWindow) ++ return true; ++ ++ if (m_glContext) ++ glXMakeCurrent(m_dpy, None, NULL); ++ ++ if (m_invisibleCursor) ++ { ++ XUndefineCursor(m_dpy, m_glWindow); ++ XFreeCursor(m_dpy, m_invisibleCursor); ++ m_invisibleCursor = 0; ++ } ++ ++ CWinEvents::Quit(); ++ ++ XUnmapWindow(m_dpy, m_glWindow); ++ XSync(m_dpy,TRUE); ++ XUngrabKeyboard(m_dpy, CurrentTime); ++ XUngrabPointer(m_dpy, CurrentTime); ++ XDestroyWindow(m_dpy, m_glWindow); ++ m_glWindow = 0; ++ + return true; + } + +@@ -161,65 +143,105 @@ bool CWinSystemX11::ResizeWindow(int newWidth, int newHeight, int newLeft, int n + && m_nHeight == newHeight) + return true; + ++ if (!SetWindow(newWidth, newHeight, false)) ++ { ++ return false; ++ } ++ ++ RefreshGlxContext(); + m_nWidth = newWidth; + m_nHeight = newHeight; ++ m_bFullScreen = false; + +- int options = SDL_OPENGL; +- if (m_bFullScreen) +- options |= SDL_FULLSCREEN; +- else +- options |= SDL_RESIZABLE; ++ return false; ++} ++ ++void CWinSystemX11::RefreshWindow() ++{ ++ g_xrandr.Query(true); ++ XOutput out = g_xrandr.GetCurrentOutput(); ++ XMode mode = g_xrandr.GetCurrentMode(out.name); + +- if ((m_SDLSurface = SDL_SetVideoMode(m_nWidth, m_nHeight, 0, options))) ++ // only overwrite desktop resolution, if we are not in fullscreen mode ++ if (!g_graphicsContext.IsFullScreenVideo()) + { +- RefreshGlxContext(); +- return true; ++ CLog::Log(LOGDEBUG, "CWinSystemX11::RefreshWindow - store desktop resolution, width: %d, height: %d, hz: %2.2f", mode.w, mode.h, mode.hz); ++ UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.w, mode.h, mode.hz); ++ g_settings.m_ResInfo[RES_DESKTOP].strId = mode.id; ++ g_settings.m_ResInfo[RES_DESKTOP].strOutput = out.name; + } + +- return false; ++ RESOLUTION_INFO res; ++ unsigned int i; ++ bool found(false); ++ for (i = RES_DESKTOP; i < g_settings.m_ResInfo.size(); ++i) ++ { ++ if (g_settings.m_ResInfo[i].strId == mode.id) ++ { ++ found = true; ++ break; ++ } ++ } ++ ++ if (!found) ++ { ++ CLog::Log(LOGERROR, "CWinSystemX11::RefreshWindow - could not find resolution"); ++ return; ++ } ++ ++ if (g_graphicsContext.IsFullScreenRoot()) ++ g_graphicsContext.SetVideoResolution((RESOLUTION)i, true); ++ else ++ g_graphicsContext.SetVideoResolution(RES_WINDOW, true); + } + + bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays) + { +- m_nWidth = res.iWidth; +- m_nHeight = res.iHeight; +- m_bFullScreen = fullScreen; + + #if defined(HAS_XRANDR) + XOutput out; + XMode mode; +- out.name = res.strOutput; +- mode.w = res.iWidth; +- mode.h = res.iHeight; +- mode.hz = res.fRefreshRate; +- mode.id = res.strId; ++ ++ if (fullScreen) ++ { ++ out.name = res.strOutput; ++ mode.w = res.iWidth; ++ mode.h = res.iHeight; ++ mode.hz = res.fRefreshRate; ++ mode.id = res.strId; ++ } ++ else ++ { ++ out.name = g_settings.m_ResInfo[RES_DESKTOP].strOutput; ++ mode.w = g_settings.m_ResInfo[RES_DESKTOP].iWidth; ++ mode.h = g_settings.m_ResInfo[RES_DESKTOP].iHeight; ++ mode.hz = g_settings.m_ResInfo[RES_DESKTOP].fRefreshRate; ++ mode.id = g_settings.m_ResInfo[RES_DESKTOP].strId; ++ } + +- if(m_bFullScreen) ++ XOutput currout = g_xrandr.GetCurrentOutput(); ++ XMode currmode = g_xrandr.GetCurrentMode(currout.name); ++ ++ // only call xrandr if mode changes ++ if (currout.name != out.name || currmode.w != mode.w || currmode.h != mode.h || ++ currmode.hz != mode.hz || currmode.id != mode.id) + { ++ CLog::Log(LOGNOTICE, "CWinSystemX11::SetFullScreen - calling xrandr"); + OnLostDevice(); + g_xrandr.SetMode(out, mode); + } +- else +- g_xrandr.RestoreState(); + #endif + +- int options = SDL_OPENGL; +- if (m_bFullScreen) +- options |= SDL_FULLSCREEN; +- else +- options |= SDL_RESIZABLE; +- +- if ((m_SDLSurface = SDL_SetVideoMode(m_nWidth, m_nHeight, 0, options))) +- { +- if ((m_SDLSurface->flags & SDL_OPENGL) != SDL_OPENGL) +- CLog::Log(LOGERROR, "CWinSystemX11::SetFullScreen SDL_OPENGL not set, SDL_GetError:%s", SDL_GetError()); ++ if (!SetWindow(res.iWidth, res.iHeight, fullScreen)) ++ return false; + +- RefreshGlxContext(); ++ RefreshGlxContext(); + +- return true; +- } ++ m_nWidth = res.iWidth; ++ m_nHeight = res.iHeight; ++ m_bFullScreen = fullScreen; + +- return false; ++ return true; + } + + void CWinSystemX11::UpdateResolutions() +@@ -321,17 +343,10 @@ bool CWinSystemX11::IsSuitableVisual(XVisualInfo *vInfo) + bool CWinSystemX11::RefreshGlxContext() + { + bool retVal = false; +- SDL_SysWMinfo info; +- SDL_VERSION(&info.version); +- if (SDL_GetWMInfo(&info) <= 0) +- { +- CLog::Log(LOGERROR, "Failed to get window manager info from SDL"); +- return false; +- } + +- if(m_glWindow == info.info.x11.window && m_glContext) ++ if (m_glContext) + { +- CLog::Log(LOGERROR, "GLX: Same window as before, refreshing context"); ++ CLog::Log(LOGDEBUG, "CWinSystemX11::RefreshGlxContext: refreshing context"); + glXMakeCurrent(m_dpy, None, NULL); + glXMakeCurrent(m_dpy, m_glWindow, m_glContext); + return true; +@@ -343,8 +358,6 @@ bool CWinSystemX11::RefreshGlxContext() + int availableVisuals = 0; + vMask.screen = DefaultScreen(m_dpy); + XWindowAttributes winAttr; +- m_glWindow = info.info.x11.window; +- m_wmWindow = info.info.x11.wmwindow; + + /* Assume a depth of 24 in case the below calls to XGetWindowAttributes() + or XGetVisualInfo() fail. That shouldn't happen unless something is +@@ -415,7 +428,10 @@ bool CWinSystemX11::RefreshGlxContext() + + void CWinSystemX11::ShowOSMouse(bool show) + { +- SDL_ShowCursor(show ? 1 : 0); ++ if (show) ++ XUndefineCursor(m_dpy,m_glWindow); ++ else if (m_invisibleCursor) ++ XDefineCursor(m_dpy,m_glWindow, m_invisibleCursor); + } + + void CWinSystemX11::ResetOSScreensaver() +@@ -429,8 +445,6 @@ void CWinSystemX11::ResetOSScreensaver() + { + m_screensaverReset.StartZero(); + XResetScreenSaver(m_dpy); +- //need to flush the output buffer, since we don't check for events on m_dpy +- XFlush(m_dpy); + } + } + else +@@ -446,13 +460,27 @@ void CWinSystemX11::NotifyAppActiveChange(bool bActivated) + + m_minimized = !bActivated; + } ++ ++void CWinSystemX11::NotifyAppFocusChange(bool bGaining) ++{ ++ if (bGaining && m_bWasFullScreenBeforeMinimize && !m_bIgnoreNextFocusMessage && ++ !g_graphicsContext.IsFullScreenRoot()) ++ g_graphicsContext.ToggleFullScreenRoot(); ++ if (!bGaining) ++ m_bIgnoreNextFocusMessage = false; ++} ++ + bool CWinSystemX11::Minimize() + { + m_bWasFullScreenBeforeMinimize = g_graphicsContext.IsFullScreenRoot(); + if (m_bWasFullScreenBeforeMinimize) ++ { ++ m_bIgnoreNextFocusMessage = true; + g_graphicsContext.ToggleFullScreenRoot(); ++ } ++ ++ XIconifyWindow(m_dpy, m_glWindow, DefaultScreen(m_dpy)); + +- SDL_WM_IconifyWindow(); + m_minimized = true; + return true; + } +@@ -462,13 +490,13 @@ bool CWinSystemX11::Restore() + } + bool CWinSystemX11::Hide() + { +- XUnmapWindow(m_dpy, m_wmWindow); ++ XUnmapWindow(m_dpy, m_glWindow); + XSync(m_dpy, False); + return true; + } + bool CWinSystemX11::Show(bool raise) + { +- XMapWindow(m_dpy, m_wmWindow); ++ XMapWindow(m_dpy, m_glWindow); + XSync(m_dpy, False); + m_minimized = false; + return true; +@@ -500,6 +528,7 @@ void CWinSystemX11::CheckDisplayEvents() + if (bGotEvent || bTimeout) + { + CLog::Log(LOGDEBUG, "%s - notify display reset event", __FUNCTION__); ++ RefreshWindow(); + + CSingleLock lock(m_resourceSection); + +@@ -558,4 +587,151 @@ bool CWinSystemX11::EnableFrameLimiter() + return m_minimized; + } + ++bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen) ++{ ++ bool changeWindow = false; ++ bool changeSize = false; ++ bool mouseActive = false; ++ float mouseX, mouseY; ++ ++ if (m_glWindow && (m_bFullScreen != fullscreen)) ++ { ++ mouseActive = g_Mouse.IsActive(); ++ if (mouseActive) ++ { ++ Window root_return, child_return; ++ int root_x_return, root_y_return; ++ int win_x_return, win_y_return; ++ unsigned int mask_return; ++ bool isInWin = XQueryPointer(m_dpy, m_glWindow, &root_return, &child_return, ++ &root_x_return, &root_y_return, ++ &win_x_return, &win_y_return, ++ &mask_return); ++ if (isInWin) ++ { ++ mouseX = (float)win_x_return/m_nWidth; ++ mouseY = (float)win_y_return/m_nHeight; ++ g_Mouse.SetActive(false); ++ } ++ else ++ mouseActive = false; ++ } ++ DestroyWindow(); ++ } ++ ++ // create main window ++ if (!m_glWindow) ++ { ++ GLint att[] = ++ { ++ GLX_RGBA, ++ GLX_RED_SIZE, 8, ++ GLX_GREEN_SIZE, 8, ++ GLX_BLUE_SIZE, 8, ++ GLX_ALPHA_SIZE, 8, ++ GLX_DEPTH_SIZE, 24, ++ GLX_DOUBLEBUFFER, ++ None ++ }; ++ Colormap cmap; ++ XSetWindowAttributes swa; ++ XVisualInfo *vi; ++ ++ vi = glXChooseVisual(m_dpy, DefaultScreen(m_dpy), att); ++ cmap = XCreateColormap(m_dpy, RootWindow(m_dpy, vi->screen), vi->visual, AllocNone); ++ ++ int def_vis = (vi->visual == DefaultVisual(m_dpy, vi->screen)); ++ swa.override_redirect = fullscreen ? True : False; ++ swa.border_pixel = fullscreen ? 0 : 5; ++ swa.background_pixel = def_vis ? BlackPixel(m_dpy, vi->screen) : 0; ++ swa.colormap = cmap; ++ swa.background_pixel = def_vis ? BlackPixel(m_dpy, vi->screen) : 0; ++ swa.event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask | ++ ButtonPressMask | ButtonReleaseMask | PointerMotionMask | ++ PropertyChangeMask | StructureNotifyMask | KeymapStateMask | ++ EnterWindowMask | LeaveWindowMask | ExposureMask; ++ unsigned long mask = CWBackPixel | CWBorderPixel | CWColormap | CWOverrideRedirect | CWEventMask; ++ ++ m_glWindow = XCreateWindow(m_dpy, RootWindow(m_dpy, vi->screen), ++ 0, 0, width, height, 0, vi->depth, ++ InputOutput, vi->visual, ++ mask, &swa); ++ ++ // define invisible cursor ++ Pixmap bitmapNoData; ++ XColor black; ++ static char noData[] = { 0,0,0,0,0,0,0,0 }; ++ black.red = black.green = black.blue = 0; ++ ++ bitmapNoData = XCreateBitmapFromData(m_dpy, m_glWindow, noData, 8, 8); ++ m_invisibleCursor = XCreatePixmapCursor(m_dpy, bitmapNoData, bitmapNoData, ++ &black, &black, 0, 0); ++ XFreePixmap(m_dpy, bitmapNoData); ++ XDefineCursor(m_dpy,m_glWindow, m_invisibleCursor); ++ ++ //init X11 events ++ CWinEvents::Init(m_dpy, m_glWindow); ++ ++ changeWindow = true; ++ changeSize = true; ++ } ++ ++ if (!CWinEvents::HasStructureChanged() && ((width != m_nWidth) || (height != m_nHeight))) ++ { ++ changeSize = true; ++ } ++ ++ if (changeSize || changeWindow) ++ { ++ XResizeWindow(m_dpy, m_glWindow, width, height); ++ } ++ ++ if (changeWindow) ++ { ++ if (!fullscreen) ++ { ++ XWMHints wm_hints; ++ XClassHint class_hints; ++ XTextProperty windowName, iconName; ++ std::string titleString = "XBMC Media Center"; ++ char *title = (char*)titleString.c_str(); ++ ++ XStringListToTextProperty(&title, 1, &windowName); ++ XStringListToTextProperty(&title, 1, &iconName); ++ wm_hints.initial_state = NormalState; ++ wm_hints.input = True; ++ wm_hints.icon_pixmap = None; ++ wm_hints.flags = StateHint | IconPixmapHint | InputHint; ++ ++ XSetWMProperties(m_dpy, m_glWindow, &windowName, &iconName, ++ NULL, 0, NULL, &wm_hints, ++ NULL); ++ ++ // register interest in the delete window message ++ Atom wmDeleteMessage = XInternAtom(m_dpy, "WM_DELETE_WINDOW", False); ++ XSetWMProtocols(m_dpy, m_glWindow, &wmDeleteMessage, 1); ++ } ++ XMapRaised(m_dpy, m_glWindow); ++ XSync(m_dpy,TRUE); ++ ++ if (changeWindow && mouseActive) ++ { ++ XWarpPointer(m_dpy, None, m_glWindow, 0, 0, 0, 0, mouseX*width, mouseY*height); ++ } ++ ++ if (fullscreen) ++ { ++ int result = -1; ++ while (result != GrabSuccess) ++ { ++ result = XGrabPointer(m_dpy, m_glWindow, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, m_glWindow, None, CurrentTime); ++ XbmcThreads::ThreadSleep(100); ++ } ++ XGrabKeyboard(m_dpy, m_glWindow, True, GrabModeAsync, GrabModeAsync, CurrentTime); ++ ++ } ++ } ++ return true; ++} ++ + #endif +diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h +index 2dd8a9f..9616d17 100644 +--- a/xbmc/windowing/X11/WinSystemX11.h ++++ b/xbmc/windowing/X11/WinSystemX11.h +@@ -52,6 +52,7 @@ class CWinSystemX11 : public CWinSystemBase + virtual bool EnableFrameLimiter(); + + virtual void NotifyAppActiveChange(bool bActivated); ++ virtual void NotifyAppFocusChange(bool bGaining); + + virtual bool Minimize(); + virtual bool Restore() ; +@@ -64,19 +65,21 @@ class CWinSystemX11 : public CWinSystemBase + Display* GetDisplay() { return m_dpy; } + GLXWindow GetWindow() { return m_glWindow; } + GLXContext GetGlxContext() { return m_glContext; } ++ void RefreshWindow(); + + protected: + bool RefreshGlxContext(); + void CheckDisplayEvents(); + void OnLostDevice(); ++ bool SetWindow(int width, int height, bool fullscreen); + +- SDL_Surface* m_SDLSurface; ++ Window m_glWindow; + GLXContext m_glContext; +- GLXWindow m_glWindow; +- Window m_wmWindow; + Display* m_dpy; ++ Cursor m_invisibleCursor; + bool m_bWasFullScreenBeforeMinimize; + bool m_minimized; ++ bool m_bIgnoreNextFocusMessage; + int m_RREventBase; + CCriticalSection m_resourceSection; + std::vector m_resources; +-- +1.7.10 + + +From 58fa894afaffbc990ee1ab87ff55db30e36ab2c2 Mon Sep 17 00:00:00 2001 +From: FernetMenta +Date: Thu, 5 Jul 2012 15:24:22 +0200 +Subject: [PATCH 15/73] X11: Add xbmc icon + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 126 ++++++++++++++++++++++++++++++++++- + xbmc/windowing/X11/WinSystemX11.h | 2 + + 2 files changed, 127 insertions(+), 1 deletion(-) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index 76ef462..c854598 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -134,6 +134,9 @@ bool CWinSystemX11::DestroyWindow() + XDestroyWindow(m_dpy, m_glWindow); + m_glWindow = 0; + ++ if (m_icon) ++ XFreePixmap(m_dpy, m_icon); ++ + return true; + } + +@@ -688,8 +691,10 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen) + + if (changeWindow) + { ++ m_icon = None; + if (!fullscreen) + { ++ CreateIconPixmap(); + XWMHints wm_hints; + XClassHint class_hints; + XTextProperty windowName, iconName; +@@ -700,7 +705,7 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen) + XStringListToTextProperty(&title, 1, &iconName); + wm_hints.initial_state = NormalState; + wm_hints.input = True; +- wm_hints.icon_pixmap = None; ++ wm_hints.icon_pixmap = m_icon; + wm_hints.flags = StateHint | IconPixmapHint | InputHint; + + XSetWMProperties(m_dpy, m_glWindow, &windowName, &iconName, +@@ -734,4 +739,123 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen) + return true; + } + ++bool CWinSystemX11::CreateIconPixmap() ++{ ++ int depth; ++ XImage *img = NULL; ++ Visual *vis; ++ XWindowAttributes wndattribs; ++ XVisualInfo visInfo; ++ double rRatio; ++ double gRatio; ++ double bRatio; ++ int outIndex = 0; ++ int i,j; ++ int numBufBytes; ++ unsigned char *buf; ++ uint32_t *newBuf = 0; ++ size_t numNewBufBytes; ++ ++ // Get visual Info ++ XGetWindowAttributes(m_dpy, m_glWindow, &wndattribs); ++ visInfo.visualid = wndattribs.visual->visualid; ++ int nvisuals = 0; ++ XVisualInfo* visuals = XGetVisualInfo(m_dpy, VisualIDMask, &visInfo, &nvisuals); ++ if (nvisuals != 1) ++ { ++ CLog::Log(LOGERROR, "CWinSystemX11::CreateIconPixmap - could not find visual"); ++ return false; ++ } ++ visInfo = visuals[0]; ++ XFree(visuals); ++ ++ depth = visInfo.depth; ++ vis = visInfo.visual; ++ ++ if (depth < 15) ++ { ++ CLog::Log(LOGERROR, "CWinSystemX11::CreateIconPixmap - no suitable depth"); ++ return false; ++ } ++ ++ rRatio = vis->red_mask / 255.0; ++ gRatio = vis->green_mask / 255.0; ++ bRatio = vis->blue_mask / 255.0; ++ ++ CTexture iconTexture; ++ iconTexture.LoadFromFile("special://xbmc/media/icon.png"); ++ buf = iconTexture.GetPixels(); ++ ++ numBufBytes = iconTexture.GetWidth() * iconTexture.GetHeight() * 4; ++ ++ if (depth>=24) ++ numNewBufBytes = (4 * (iconTexture.GetWidth() * iconTexture.GetHeight())); ++ else ++ numNewBufBytes = (2 * (iconTexture.GetWidth() * iconTexture.GetHeight())); ++ ++ newBuf = (uint32_t*)malloc(numNewBufBytes); ++ if (!newBuf) ++ { ++ CLog::Log(LOGERROR, "CWinSystemX11::CreateIconPixmap - malloc failed"); ++ return false; ++ } ++ ++ for (i=0; ired_mask; ++ g &= vis->green_mask; ++ b &= vis->blue_mask; ++ newBuf[outIndex] = r | g | b; ++ ++outIndex; ++ } ++ } ++ img = XCreateImage(m_dpy, vis, depth,ZPixmap, 0, (char *)newBuf, ++ iconTexture.GetWidth(), iconTexture.GetHeight(), ++ (depth>=24)?32:16, 0); ++ if (!img) ++ { ++ CLog::Log(LOGERROR, "CWinSystemX11::CreateIconPixmap - could not create image"); ++ free(newBuf); ++ return false; ++ } ++ if (!XInitImage(img)) ++ { ++ CLog::Log(LOGERROR, "CWinSystemX11::CreateIconPixmap - init image failed"); ++ XDestroyImage(img); ++ return false; ++ } ++ ++ // set byte order ++ union ++ { ++ char c[sizeof(short)]; ++ short s; ++ } order; ++ order.s = 1; ++ if ((1 == order.c[0])) ++ { ++ img->byte_order = LSBFirst; ++ } ++ else ++ { ++ img->byte_order = MSBFirst; ++ } ++ ++ // create icon pixmap from image ++ m_icon = XCreatePixmap(m_dpy, m_glWindow, img->width, img->height, depth); ++ GC gc = XCreateGC(m_dpy, m_glWindow, 0, NULL); ++ XPutImage(m_dpy, m_icon, gc, img, 0, 0, 0, 0, img->width, img->height); ++ XFreeGC(m_dpy, gc); ++ XDestroyImage(img); // this also frees newBuf ++ ++ return true; ++} ++ + #endif +diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h +index 9616d17..debf714 100644 +--- a/xbmc/windowing/X11/WinSystemX11.h ++++ b/xbmc/windowing/X11/WinSystemX11.h +@@ -77,6 +77,7 @@ class CWinSystemX11 : public CWinSystemBase + GLXContext m_glContext; + Display* m_dpy; + Cursor m_invisibleCursor; ++ Pixmap m_icon; + bool m_bWasFullScreenBeforeMinimize; + bool m_minimized; + bool m_bIgnoreNextFocusMessage; +@@ -88,6 +89,7 @@ class CWinSystemX11 : public CWinSystemBase + private: + bool IsSuitableVisual(XVisualInfo *vInfo); + static int XErrorHandler(Display* dpy, XErrorEvent* error); ++ bool CreateIconPixmap(); + + CStopWatch m_screensaverReset; + }; +-- +1.7.10 + + +From cad2ac7f357906f10f100a038ff28e83a69c68e8 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sun, 20 May 2012 14:11:26 +0200 +Subject: [PATCH 16/73] X11: add SDL joystick until we have a better solution + +--- + xbmc/windowing/WinEventsX11.cpp | 26 ++++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp +index 24477ae..2ec86a8 100644 +--- a/xbmc/windowing/WinEventsX11.cpp ++++ b/xbmc/windowing/WinEventsX11.cpp +@@ -35,6 +35,10 @@ + #include "guilib/GUIWindowManager.h" + #include "input/MouseStat.h" + ++#ifdef HAS_SDL_JOYSTICK ++#include "input/SDLJoystick.h" ++#endif ++ + CWinEventsX11* CWinEventsX11::WinEvents = 0; + + static uint32_t SymMappingsX11[][2] = +@@ -547,6 +551,28 @@ bool CWinEventsX11::MessagePump() + + ret |= ProcessKeyRepeat(); + ++#ifdef HAS_SDL_JOYSTICK ++ SDL_Event event; ++ while (SDL_PollEvent(&event)) ++ { ++ switch(event.type) ++ { ++ case SDL_JOYBUTTONUP: ++ case SDL_JOYBUTTONDOWN: ++ case SDL_JOYAXISMOTION: ++ case SDL_JOYBALLMOTION: ++ case SDL_JOYHATMOTION: ++ g_Joystick.Update(event); ++ ret = true; ++ break; ++ ++ default: ++ break; ++ } ++ memset(&event, 0, sizeof(SDL_Event)); ++ } ++#endif ++ + return ret; + } + +-- +1.7.10 + + +From fdefd4cf296518f31ad1165268fccd651e08dd3c Mon Sep 17 00:00:00 2001 +From: Joakim Plate +Date: Thu, 5 Jul 2012 12:35:55 +0200 +Subject: [PATCH 17/73] X11: factor out code handling device reset + notification + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 22 ++++++++++++++-------- + xbmc/windowing/X11/WinSystemX11.h | 1 + + 2 files changed, 15 insertions(+), 8 deletions(-) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index c854598..70557d0 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -530,14 +530,7 @@ void CWinSystemX11::CheckDisplayEvents() + + if (bGotEvent || bTimeout) + { +- CLog::Log(LOGDEBUG, "%s - notify display reset event", __FUNCTION__); +- RefreshWindow(); +- +- CSingleLock lock(m_resourceSection); +- +- // tell any shared resources +- for (vector::iterator i = m_resources.begin(); i != m_resources.end(); i++) +- (*i)->OnResetDevice(); ++ NotifyXRREvent(); + + // reset fail safe timer + m_dpyLostTime = 0; +@@ -545,6 +538,19 @@ void CWinSystemX11::CheckDisplayEvents() + #endif + } + ++void CWinSystemX11::NotifyXRREvent() ++{ ++ CLog::Log(LOGDEBUG, "%s - notify display reset event", __FUNCTION__); ++ RefreshWindow(); ++ ++ CSingleLock lock(m_resourceSection); ++ ++ // tell any shared resources ++ for (vector::iterator i = m_resources.begin(); i != m_resources.end(); i++) ++ (*i)->OnResetDevice(); ++ ++} ++ + void CWinSystemX11::OnLostDevice() + { + CLog::Log(LOGDEBUG, "%s - notify display change event", __FUNCTION__); +diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h +index debf714..8c28e3f 100644 +--- a/xbmc/windowing/X11/WinSystemX11.h ++++ b/xbmc/windowing/X11/WinSystemX11.h +@@ -66,6 +66,7 @@ class CWinSystemX11 : public CWinSystemBase + GLXWindow GetWindow() { return m_glWindow; } + GLXContext GetGlxContext() { return m_glContext; } + void RefreshWindow(); ++ void NotifyXRREvent(); + + protected: + bool RefreshGlxContext(); +-- +1.7.10 + + +From 9a409794d1eb8ee0c4b0b1124dea7dd30af32c06 Mon Sep 17 00:00:00 2001 +From: FernetMenta +Date: Thu, 5 Jul 2012 15:02:00 +0200 +Subject: [PATCH 18/73] X11: move xrandr events to WinEventsX11 + +--- + xbmc/windowing/WinEventsX11.cpp | 42 +++++++++++++++++++++++++++++++++++ + xbmc/windowing/WinEventsX11.h | 5 +++++ + xbmc/windowing/X11/WinSystemX11.cpp | 6 ++++- + 3 files changed, 52 insertions(+), 1 deletion(-) + +diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp +index 2ec86a8..5946a33 100644 +--- a/xbmc/windowing/WinEventsX11.cpp ++++ b/xbmc/windowing/WinEventsX11.cpp +@@ -35,6 +35,10 @@ + #include "guilib/GUIWindowManager.h" + #include "input/MouseStat.h" + ++#if defined(HAS_XRANDR) ++#include ++#endif ++ + #ifdef HAS_SDL_JOYSTICK + #include "input/SDLJoystick.h" + #endif +@@ -203,6 +207,7 @@ bool CWinEventsX11::Init(Display *dpy, Window win) + WinEvents->m_keymodState = 0; + WinEvents->m_wmDeleteMessage = XInternAtom(dpy, "WM_DELETE_WINDOW", False); + WinEvents->m_structureChanged = false; ++ WinEvents->m_xrrEventPending = false; + memset(&(WinEvents->m_lastKey), 0, sizeof(XBMC_Event)); + + // open input method +@@ -266,6 +271,13 @@ bool CWinEventsX11::Init(Display *dpy, Window win) + WinEvents->m_symLookupTable[SymMappingsX11[i][0]] = SymMappingsX11[i][1]; + } + ++ // register for xrandr events ++#if defined(HAS_XRANDR) ++ int iReturn; ++ XRRQueryExtension(WinEvents->m_display, &WinEvents->m_RREventBase, &iReturn); ++ XRRSelectInput(WinEvents->m_display, WinEvents->m_window, RRScreenChangeNotifyMask); ++#endif ++ + return true; + } + +@@ -288,6 +300,15 @@ bool CWinEventsX11::HasStructureChanged() + return ret; + } + ++void CWinEventsX11::SetXRRFailSafeTimer(int millis) ++{ ++ if (!WinEvents) ++ return; ++ ++ WinEvents->m_xrrFailSafeTimer.Set(millis); ++ WinEvents->m_xrrEventPending = true; ++} ++ + bool CWinEventsX11::MessagePump() + { + if (!WinEvents) +@@ -547,10 +568,31 @@ bool CWinEventsX11::MessagePump() + break; + } + }// switch event.type ++ ++#if defined(HAS_XRANDR) ++ if (WinEvents && (xevent.type == WinEvents->m_RREventBase + RRScreenChangeNotify)) ++ { ++ XRRUpdateConfiguration(&xevent); ++ if (xevent.xgeneric.serial != serial) ++ g_Windowing.NotifyXRREvent(); ++ WinEvents->m_xrrEventPending = false; ++ serial = xevent.xgeneric.serial; ++ } ++#endif ++ + }// while + + ret |= ProcessKeyRepeat(); + ++#if defined(HAS_XRANDR) ++ if (WinEvents && WinEvents->m_xrrEventPending && WinEvents->m_xrrFailSafeTimer.IsTimePast()) ++ { ++ CLog::Log(LOGERROR,"CWinEventsX11::MessagePump - missed XRR Events"); ++ g_Windowing.NotifyXRREvent(); ++ WinEvents->m_xrrEventPending = false; ++ } ++#endif ++ + #ifdef HAS_SDL_JOYSTICK + SDL_Event event; + while (SDL_PollEvent(&event)) +diff --git a/xbmc/windowing/WinEventsX11.h b/xbmc/windowing/WinEventsX11.h +index e9b7553..6100933 100644 +--- a/xbmc/windowing/WinEventsX11.h ++++ b/xbmc/windowing/WinEventsX11.h +@@ -33,6 +33,8 @@ class CWinEventsX11 : public CWinEventsBase + static bool Init(Display *dpy, Window win); + static void Quit(); + static bool HasStructureChanged(); ++ static void PendingResize(int width, int height); ++ static void SetXRRFailSafeTimer(int millis); + static bool MessagePump(); + + protected: +@@ -54,4 +56,7 @@ class CWinEventsX11 : public CWinEventsBase + std::map m_symLookupTable; + int m_keymodState; + bool m_structureChanged; ++ int m_RREventBase; ++ XbmcThreads::EndTime m_xrrFailSafeTimer; ++ bool m_xrrEventPending; + }; +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index 70557d0..1cce843 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -507,7 +507,7 @@ bool CWinSystemX11::Show(bool raise) + + void CWinSystemX11::CheckDisplayEvents() + { +-#if defined(HAS_XRANDR) ++#if defined(HAS_XRANDR) && defined(HAS_SDL_VIDEO_X11) + bool bGotEvent(false); + bool bTimeout(false); + XEvent Event; +@@ -563,8 +563,12 @@ void CWinSystemX11::OnLostDevice() + (*i)->OnLostDevice(); + } + ++#if defined(HAS_SDL_VIDEO_X11) + // fail safe timer + m_dpyLostTime = CurrentHostCounter(); ++#else ++ CWinEvents::SetXRRFailSafeTimer(3000); ++#endif + } + + void CWinSystemX11::Register(IDispResource *resource) +-- +1.7.10 + + +From 1dc579a2d5c608cfd4f799971759d18cbd2957e5 Mon Sep 17 00:00:00 2001 +From: FernetMenta +Date: Thu, 12 Apr 2012 15:43:56 +0200 +Subject: [PATCH 19/73] xrandr: remove method RestoreState + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 13 +++++++++++-- + xbmc/windowing/X11/XRandR.cpp | 19 ------------------- + xbmc/windowing/X11/XRandR.h | 1 - + 3 files changed, 11 insertions(+), 22 deletions(-) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index 1cce843..e13ffa4 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -77,9 +77,18 @@ bool CWinSystemX11::InitWindowSystem() + bool CWinSystemX11::DestroyWindowSystem() + { + #if defined(HAS_XRANDR) +- //restore videomode on exit ++ //restore desktop resolution on exit + if (m_bFullScreen) +- g_xrandr.RestoreState(); ++ { ++ XOutput out; ++ XMode mode; ++ out.name = g_settings.m_ResInfo[RES_DESKTOP].strOutput; ++ mode.w = g_settings.m_ResInfo[RES_DESKTOP].iWidth; ++ mode.h = g_settings.m_ResInfo[RES_DESKTOP].iHeight; ++ mode.hz = g_settings.m_ResInfo[RES_DESKTOP].fRefreshRate; ++ mode.id = g_settings.m_ResInfo[RES_DESKTOP].strId; ++ g_xrandr.SetMode(out, mode); ++ } + #endif + + if (m_dpy) +diff --git a/xbmc/windowing/X11/XRandR.cpp b/xbmc/windowing/X11/XRandR.cpp +index d8e9161..59755a6 100644 +--- a/xbmc/windowing/X11/XRandR.cpp ++++ b/xbmc/windowing/X11/XRandR.cpp +@@ -139,25 +139,6 @@ void CXRandR::SaveState() + Query(true); + } + +-void CXRandR::RestoreState() +-{ +- vector::iterator outiter; +- for (outiter=m_current.begin() ; outiter!=m_current.end() ; outiter++) +- { +- vector modes = (*outiter).modes; +- vector::iterator modeiter; +- for (modeiter=modes.begin() ; modeiter!=modes.end() ; modeiter++) +- { +- XMode mode = *modeiter; +- if (mode.isCurrent) +- { +- SetMode(*outiter, mode); +- return; +- } +- } +- } +-} +- + bool CXRandR::SetMode(XOutput output, XMode mode) + { + if ((output.name == m_currentOutput && mode.id == m_currentMode) || (output.name == "" && mode.id == "")) +diff --git a/xbmc/windowing/X11/XRandR.h b/xbmc/windowing/X11/XRandR.h +index 2a269d0..5b64633 100644 +--- a/xbmc/windowing/X11/XRandR.h ++++ b/xbmc/windowing/X11/XRandR.h +@@ -99,7 +99,6 @@ class CXRandR + bool SetMode(XOutput output, XMode mode); + void LoadCustomModeLinesToAllOutputs(void); + void SaveState(); +- void RestoreState(); + //bool Has1080i(); + //bool Has1080p(); + //bool Has720p(); +-- +1.7.10 + + +From 4a6f0e986fc27b356041a4b1bb989e0e594c8aa7 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sun, 20 May 2012 13:17:10 +0200 +Subject: [PATCH 20/73] xrandr: observe orientation + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 61 +++++++++++++++++++++++++++++++++-- + xbmc/windowing/X11/WinSystemX11.h | 2 ++ + xbmc/windowing/X11/XRandR.cpp | 7 ++++ + xbmc/windowing/X11/XRandR.h | 1 + + 4 files changed, 68 insertions(+), 3 deletions(-) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index e13ffa4..6b0aa92 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -170,15 +170,24 @@ bool CWinSystemX11::ResizeWindow(int newWidth, int newHeight, int newLeft, int n + + void CWinSystemX11::RefreshWindow() + { +- g_xrandr.Query(true); ++ if (!g_xrandr.Query(true)) ++ { ++ CLog::Log(LOGERROR, "WinSystemX11::RefreshWindow - failed to query xrandr"); ++ return; ++ } + XOutput out = g_xrandr.GetCurrentOutput(); + XMode mode = g_xrandr.GetCurrentMode(out.name); + ++ RotateResolutions(); ++ + // only overwrite desktop resolution, if we are not in fullscreen mode + if (!g_graphicsContext.IsFullScreenVideo()) + { + CLog::Log(LOGDEBUG, "CWinSystemX11::RefreshWindow - store desktop resolution, width: %d, height: %d, hz: %2.2f", mode.w, mode.h, mode.hz); +- UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.w, mode.h, mode.hz); ++ if (!out.isRotated) ++ UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.w, mode.h, mode.hz); ++ else ++ UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.h, mode.w, mode.hz); + g_settings.m_ResInfo[RES_DESKTOP].strId = mode.id; + g_settings.m_ResInfo[RES_DESKTOP].strOutput = out.name; + } +@@ -234,6 +243,14 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl + XOutput currout = g_xrandr.GetCurrentOutput(); + XMode currmode = g_xrandr.GetCurrentMode(currout.name); + ++ // flip h/w when rotated ++ if (m_bIsRotated) ++ { ++ int w = mode.w; ++ mode.w = mode.h; ++ mode.h = w; ++ } ++ + // only call xrandr if mode changes + if (currout.name != out.name || currmode.w != mode.w || currmode.h != mode.h || + currmode.hz != mode.hz || currmode.id != mode.id) +@@ -266,7 +283,11 @@ void CWinSystemX11::UpdateResolutions() + { + XOutput out = g_xrandr.GetCurrentOutput(); + XMode mode = g_xrandr.GetCurrentMode(out.name); +- UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.w, mode.h, mode.hz); ++ m_bIsRotated = out.isRotated; ++ if (!m_bIsRotated) ++ UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.w, mode.h, mode.hz); ++ else ++ UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.h, mode.w, mode.hz); + g_settings.m_ResInfo[RES_DESKTOP].strId = mode.id; + g_settings.m_ResInfo[RES_DESKTOP].strOutput = out.name; + } +@@ -305,6 +326,16 @@ void CWinSystemX11::UpdateResolutions() + res.iHeight = mode.h; + res.iScreenWidth = mode.w; + res.iScreenHeight = mode.h; ++ if (!m_bIsRotated) ++ { ++ res.iWidth = mode.w; ++ res.iHeight = mode.h; ++ } ++ else ++ { ++ res.iWidth = mode.h; ++ res.iHeight = mode.w; ++ } + if (mode.h>0 && mode.w>0 && out.hmm>0 && out.wmm>0) + res.fPixelRatio = ((float)out.wmm/(float)mode.w) / (((float)out.hmm/(float)mode.h)); + else +@@ -332,6 +363,30 @@ void CWinSystemX11::UpdateResolutions() + + } + ++void CWinSystemX11::RotateResolutions() ++{ ++#if defined(HAS_XRANDR) ++ XOutput out = g_xrandr.GetCurrentOutput(); ++ if (out.isRotated == m_bIsRotated) ++ return; ++ ++ for (unsigned int i = 0; i < g_settings.m_ResInfo.size(); ++i) ++ { ++ int width = g_settings.m_ResInfo[i].iWidth; ++ g_settings.m_ResInfo[i].iWidth = g_settings.m_ResInfo[i].iHeight; ++ g_settings.m_ResInfo[i].iHeight = width; ++ } ++ // update desktop resolution ++// int h = g_settings.m_ResInfo[RES_DESKTOP].iHeight; ++// int w = g_settings.m_ResInfo[RES_DESKTOP].iWidth; ++// float hz = g_settings.m_ResInfo[RES_DESKTOP].fRefreshRate; ++// UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, w, h, hz); ++ ++ m_bIsRotated = out.isRotated; ++ ++#endif ++} ++ + bool CWinSystemX11::IsSuitableVisual(XVisualInfo *vInfo) + { + int value; +diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h +index 8c28e3f..93cf5db 100644 +--- a/xbmc/windowing/X11/WinSystemX11.h ++++ b/xbmc/windowing/X11/WinSystemX11.h +@@ -73,12 +73,14 @@ class CWinSystemX11 : public CWinSystemBase + void CheckDisplayEvents(); + void OnLostDevice(); + bool SetWindow(int width, int height, bool fullscreen); ++ void RotateResolutions(); + + Window m_glWindow; + GLXContext m_glContext; + Display* m_dpy; + Cursor m_invisibleCursor; + Pixmap m_icon; ++ bool m_bIsRotated; + bool m_bWasFullScreenBeforeMinimize; + bool m_minimized; + bool m_bIgnoreNextFocusMessage; +diff --git a/xbmc/windowing/X11/XRandR.cpp b/xbmc/windowing/X11/XRandR.cpp +index 59755a6..45aeb71 100644 +--- a/xbmc/windowing/X11/XRandR.cpp ++++ b/xbmc/windowing/X11/XRandR.cpp +@@ -98,6 +98,13 @@ bool CXRandR::Query(bool force) + xoutput.y = (output->Attribute("y") != NULL ? atoi(output->Attribute("y")) : 0); + xoutput.wmm = (output->Attribute("wmm") != NULL ? atoi(output->Attribute("wmm")) : 0); + xoutput.hmm = (output->Attribute("hmm") != NULL ? atoi(output->Attribute("hmm")) : 0); ++ if (output->Attribute("rotation") != NULL ++ && (strcasecmp(output->Attribute("rotation"), "left") == 0 || strcasecmp(output->Attribute("rotation"), "right") == 0)) ++ { ++ xoutput.isRotated = true; ++ } ++ else ++ xoutput.isRotated = false; + + if (!xoutput.isConnected) + continue; +diff --git a/xbmc/windowing/X11/XRandR.h b/xbmc/windowing/X11/XRandR.h +index 5b64633..618bd68 100644 +--- a/xbmc/windowing/X11/XRandR.h ++++ b/xbmc/windowing/X11/XRandR.h +@@ -86,6 +86,7 @@ class XOutput + int wmm; + int hmm; + std::vector modes; ++ bool isRotated; + }; + + class CXRandR +-- +1.7.10 + + +From 97e5811e05a4ecde7249b2f76283729ff300fda9 Mon Sep 17 00:00:00 2001 +From: FernetMenta +Date: Thu, 5 Jul 2012 11:54:15 +0200 +Subject: [PATCH 21/73] xrandr: allow getting info for multiple screen's + +Refactored by: Joakim Plate +--- + xbmc/windowing/X11/XRandR.cpp | 65 ++++++++++++++++++++++++++++++++--------- + xbmc/windowing/X11/XRandR.h | 8 +++-- + 2 files changed, 57 insertions(+), 16 deletions(-) + +diff --git a/xbmc/windowing/X11/XRandR.cpp b/xbmc/windowing/X11/XRandR.cpp +index 45aeb71..cc933b9 100644 +--- a/xbmc/windowing/X11/XRandR.cpp ++++ b/xbmc/windowing/X11/XRandR.cpp +@@ -39,6 +39,7 @@ + CXRandR::CXRandR(bool query) + { + m_bInit = false; ++ m_numScreens = 1; + if (query) + Query(); + } +@@ -55,11 +56,21 @@ bool CXRandR::Query(bool force) + return false; + + m_outputs.clear(); +- m_current.clear(); ++ // query all screens ++ for(unsigned int screennum=0; screennumValue(), "screen") != 0) ++ if (strcasecmp(pRootElement->Value(), "screen") != screennum) + { + // TODO ERROR + return false; +@@ -92,6 +103,7 @@ bool CXRandR::Query(bool force) + xoutput.name.TrimLeft(" \n\r\t"); + xoutput.name.TrimRight(" \n\r\t"); + xoutput.isConnected = (strcasecmp(output->Attribute("connected"), "true") == 0); ++ xoutput.screen = screennum; + xoutput.w = (output->Attribute("w") != NULL ? atoi(output->Attribute("w")) : 0); + xoutput.h = (output->Attribute("h") != NULL ? atoi(output->Attribute("h")) : 0); + xoutput.x = (output->Attribute("x") != NULL ? atoi(output->Attribute("x")) : 0); +@@ -123,7 +135,6 @@ bool CXRandR::Query(bool force) + xoutput.modes.push_back(xmode); + if (xmode.isCurrent) + { +- m_current.push_back(xoutput); + hascurrent = true; + } + } +@@ -247,17 +258,6 @@ bool CXRandR::SetMode(XOutput output, XMode mode) + return true; + } + +-XOutput CXRandR::GetCurrentOutput() +-{ +- Query(); +- for (unsigned int j = 0; j < m_outputs.size(); j++) +- { +- if(m_outputs[j].isConnected) +- return m_outputs[j]; +- } +- XOutput empty; +- return empty; +-} + XMode CXRandR::GetCurrentMode(CStdString outputName) + { + Query(); +@@ -331,6 +331,43 @@ void CXRandR::LoadCustomModeLinesToAllOutputs(void) + } + } + ++void CXRandR::SetNumScreens(unsigned int num) ++{ ++ m_numScreens = num; ++ m_bInit = false; ++} ++ ++bool CXRandR::IsOutputConnected(CStdString name) ++{ ++ bool result = false; ++ Query(); ++ ++ for (unsigned int i = 0; i < m_outputs.size(); ++i) ++ { ++ if (m_outputs[i].name == name) ++ { ++ result = true; ++ break; ++ } ++ } ++ return result; ++} ++ ++XOutput* CXRandR::GetOutput(CStdString outputName) ++{ ++ XOutput *result = 0; ++ Query(); ++ for (unsigned int i = 0; i < m_outputs.size(); ++i) ++ { ++ if (m_outputs[i].name == outputName) ++ { ++ result = &m_outputs[i]; ++ break; ++ } ++ } ++ return result; ++} ++ + CXRandR g_xrandr; + + #endif // HAS_XRANDR +diff --git a/xbmc/windowing/X11/XRandR.h b/xbmc/windowing/X11/XRandR.h +index 618bd68..0824af5 100644 +--- a/xbmc/windowing/X11/XRandR.h ++++ b/xbmc/windowing/X11/XRandR.h +@@ -79,6 +79,7 @@ class XOutput + } + CStdString name; + bool isConnected; ++ int screen; + int w; + int h; + int x; +@@ -94,12 +95,15 @@ class CXRandR + public: + CXRandR(bool query=false); + bool Query(bool force=false); ++ bool Query(bool force, int screennum); + std::vector GetModes(void); +- XOutput GetCurrentOutput(); + XMode GetCurrentMode(CStdString outputName); ++ XOutput *GetOutput(CStdString outputName); + bool SetMode(XOutput output, XMode mode); + void LoadCustomModeLinesToAllOutputs(void); + void SaveState(); ++ void SetNumScreens(unsigned int num); ++ bool IsOutputConnected(CStdString name); + //bool Has1080i(); + //bool Has1080p(); + //bool Has720p(); +@@ -107,10 +111,10 @@ class CXRandR + + private: + bool m_bInit; +- std::vector m_current; + std::vector m_outputs; + CStdString m_currentOutput; + CStdString m_currentMode; ++ unsigned int m_numScreens; + }; + + extern CXRandR g_xrandr; +-- +1.7.10 + + +From 2b379b9ce21b6d61b44b647b79ef3587dbbcf0ec Mon Sep 17 00:00:00 2001 +From: FernetMenta +Date: Thu, 5 Jul 2012 11:44:00 +0200 +Subject: [PATCH 22/73] X11: fix multi-head setups + +--- + language/English/strings.po | 4 +- + xbmc/rendering/gl/RenderSystemGL.h | 1 + + xbmc/settings/GUISettings.cpp | 5 + + xbmc/settings/GUIWindowSettingsCategory.cpp | 60 +++++- + xbmc/settings/GUIWindowSettingsCategory.h | 1 + + xbmc/windowing/WinEventsX11.cpp | 7 + + xbmc/windowing/X11/WinSystemX11.cpp | 262 ++++++++++++++++----------- + xbmc/windowing/X11/WinSystemX11.h | 10 +- + 8 files changed, 235 insertions(+), 115 deletions(-) + +diff --git a/language/English/strings.po b/language/English/strings.po +index 88292d3..bba7284 100644 +--- a/language/English/strings.po ++++ b/language/English/strings.po +@@ -895,7 +895,9 @@ msgctxt "#245" + msgid "Sizing: (%i,%i)->(%i,%i) (Zoom x%2.2f) AR:%2.2f:1 (Pixels: %2.2f:1) (VShift: %2.2f)" + msgstr "" + +-#empty string with id 246 ++msgctxt "#246" ++msgid "Monitor" ++msgstr "" + + msgctxt "#247" + msgid "Scripts" +diff --git a/xbmc/rendering/gl/RenderSystemGL.h b/xbmc/rendering/gl/RenderSystemGL.h +index efe5493..85d780d 100644 +--- a/xbmc/rendering/gl/RenderSystemGL.h ++++ b/xbmc/rendering/gl/RenderSystemGL.h +@@ -44,6 +44,7 @@ class CRenderSystemGL : public CRenderSystemBase + virtual bool IsExtSupported(const char* extension); + + virtual void SetVSync(bool vsync); ++ virtual void ResetVSync() { m_bVsyncInit = false; } + + virtual void SetViewPort(CRect& viewPort); + virtual void GetViewPort(CRect& viewPort); +diff --git a/xbmc/settings/GUISettings.cpp b/xbmc/settings/GUISettings.cpp +index 4cdb093..0e320e1 100644 +--- a/xbmc/settings/GUISettings.cpp ++++ b/xbmc/settings/GUISettings.cpp +@@ -392,11 +392,16 @@ void CGUISettings::Initialize() + AddGroup(SETTINGS_SYSTEM, 13000); + CSettingsCategory* vs = AddCategory(SETTINGS_SYSTEM, "videoscreen", 21373); + ++#if defined(HAS_GLX) ++ AddString(vs, "videoscreen.monitor", 246, "", SPIN_CONTROL_TEXT); ++#endif ++ + // this setting would ideally not be saved, as its value is systematically derived from videoscreen.screenmode. + // contains a DISPLAYMODE + #if !defined(TARGET_DARWIN_IOS_ATV2) && !defined(TARGET_RASPBERRY_PI) + AddInt(vs, "videoscreen.screen", 240, 0, -1, 1, 32, SPIN_CONTROL_TEXT); + #endif ++ + // this setting would ideally not be saved, as its value is systematically derived from videoscreen.screenmode. + // contains an index to the g_settings.m_ResInfo array. the only meaningful fields are iScreen, iWidth, iHeight. + #if defined(TARGET_DARWIN) +diff --git a/xbmc/settings/GUIWindowSettingsCategory.cpp b/xbmc/settings/GUIWindowSettingsCategory.cpp +index d988598..3c19a06 100644 +--- a/xbmc/settings/GUIWindowSettingsCategory.cpp ++++ b/xbmc/settings/GUIWindowSettingsCategory.cpp +@@ -528,6 +528,12 @@ void CGUIWindowSettingsCategory::CreateSettings() + FillInRefreshRates(strSetting, g_guiSettings.GetResolution(), false); + continue; + } ++ else if (strSetting.Equals("videoscreen.monitor")) ++ { ++ AddSetting(pSetting, group->GetWidth(), iControlID); ++ FillInMonitors(strSetting); ++ continue; ++ } + else if (strSetting.Equals("lookandfeel.skintheme")) + { + AddSetting(pSetting, group->GetWidth(), iControlID); +@@ -1494,6 +1500,20 @@ void CGUIWindowSettingsCategory::OnSettingChanged(BaseSettingControlPtr pSetting + // Cascade + FillInResolutions("videoscreen.resolution", mode, RES_DESKTOP, true); + } ++ else if (strSetting.Equals("videoscreen.monitor")) ++ { ++ CSettingString *pSettingString = (CSettingString *)pSettingControl->GetSetting(); ++ CGUISpinControlEx *pControl = (CGUISpinControlEx *)GetControl(pSettingControl->GetID()); ++ CStdString currentMonitor = pControl->GetCurrentLabel(); ++ if (!g_Windowing.IsCurrentOutput(currentMonitor)) ++ { ++ g_guiSettings.SetString("videoscreen.monitor", currentMonitor); ++ g_Windowing.UpdateResolutions(); ++ DisplayMode mode = g_guiSettings.GetInt("videoscreen.screen"); ++ // Cascade ++ FillInResolutions("videoscreen.resolution", mode, RES_DESKTOP, true); ++ } ++ } + else if (strSetting.Equals("videoscreen.resolution")) + { + RESOLUTION nextRes = (RESOLUTION) g_guiSettings.GetInt("videoscreen.resolution"); +@@ -2430,11 +2450,15 @@ DisplayMode CGUIWindowSettingsCategory::FillInScreens(CStdString strSetting, RES + if (g_advancedSettings.m_canWindowed) + pControl->AddLabel(g_localizeStrings.Get(242), -1); + ++#if !defined(HAS_GLX) + for (int idx = 0; idx < g_Windowing.GetNumScreens(); idx++) + { + strScreen.Format(g_localizeStrings.Get(241), g_settings.m_ResInfo[RES_DESKTOP + idx].iScreen + 1); + pControl->AddLabel(strScreen, g_settings.m_ResInfo[RES_DESKTOP + idx].iScreen); + } ++#else ++ pControl->AddLabel(g_localizeStrings.Get(244), 0); ++#endif + pControl->SetValue(mode); + g_guiSettings.SetInt("videoscreen.screen", mode); + } +@@ -2442,6 +2466,36 @@ DisplayMode CGUIWindowSettingsCategory::FillInScreens(CStdString strSetting, RES + return mode; + } + ++void CGUIWindowSettingsCategory::FillInMonitors(CStdString strSetting) ++{ ++ // we expect "videoscreen.monitor" but it might be hidden on some platforms, ++ // so check that we actually have a visable control. ++ CBaseSettingControl *control = GetSetting(strSetting); ++ if (control) ++ { ++ control->SetDelayed(); ++ CGUISpinControlEx *pControl = (CGUISpinControlEx *)GetControl(control->GetID()); ++ pControl->Clear(); ++ ++ std::vector monitors; ++ g_Windowing.GetConnectedOutputs(&monitors); ++ ++ int currentMonitor = 0; ++ for (unsigned int i=0; iAddLabel(monitors[i], i); ++ } ++ ++ pControl->SetValue(currentMonitor); ++ g_guiSettings.SetString("videoscreen.monitor", g_settings.m_ResInfo[RES_DESKTOP].strOutput); ++ } ++} ++ ++ + void CGUIWindowSettingsCategory::FillInResolutions(CStdString strSetting, DisplayMode mode, RESOLUTION res, bool UserChange) + { + BaseSettingControlPtr control = GetSetting(strSetting); +@@ -2570,13 +2624,15 @@ void CGUIWindowSettingsCategory::OnRefreshRateChanged(RESOLUTION nextRes) + RESOLUTION lastRes = g_graphicsContext.GetVideoResolution(); + bool cancelled = false; + ++ bool outputChanged = !g_Windowing.IsCurrentOutput(g_guiSettings.GetString("videoscreen.monitor")); ++ + g_guiSettings.SetResolution(nextRes); +- g_graphicsContext.SetVideoResolution(nextRes); ++ g_graphicsContext.SetVideoResolution(nextRes, outputChanged); + + if (!CGUIDialogYesNo::ShowAndGetInput(13110, 13111, 20022, 20022, -1, -1, cancelled, 10000)) + { + g_guiSettings.SetResolution(lastRes); +- g_graphicsContext.SetVideoResolution(lastRes); ++ g_graphicsContext.SetVideoResolution(lastRes, outputChanged); + + DisplayMode mode = FillInScreens("videoscreen.screen", lastRes); + FillInResolutions("videoscreen.resolution", mode, lastRes, false); +diff --git a/xbmc/settings/GUIWindowSettingsCategory.h b/xbmc/settings/GUIWindowSettingsCategory.h +index 5142c6e..0d4649d 100644 +--- a/xbmc/settings/GUIWindowSettingsCategory.h ++++ b/xbmc/settings/GUIWindowSettingsCategory.h +@@ -51,6 +51,7 @@ class CGUIWindowSettingsCategory : + void FillInSoundSkins(CSetting *pSetting); + void FillInLanguages(CSetting *pSetting, const std::vector &languages = std::vector(), const std::vector &languageKeys = std::vector()); + DisplayMode FillInScreens(CStdString strSetting, RESOLUTION res); ++ void FillInMonitors(CStdString strSetting); + void FillInResolutions(CStdString strSetting, DisplayMode mode, RESOLUTION res, bool UserChange); + void FillInRefreshRates(CStdString strSetting, RESOLUTION res, bool UserChange); + void OnRefreshRateChanged(RESOLUTION resolution); +diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp +index 5946a33..6c22358 100644 +--- a/xbmc/windowing/WinEventsX11.cpp ++++ b/xbmc/windowing/WinEventsX11.cpp +@@ -517,9 +517,16 @@ bool CWinEventsX11::MessagePump() + break; + } + ++ case EnterNotify: ++ { ++ g_Windowing.NotifyMouseCoverage(true); ++ break; ++ } ++ + // lose mouse coverage + case LeaveNotify: + { ++ g_Windowing.NotifyMouseCoverage(false); + g_Mouse.SetActive(false); + break; + } +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index 6b0aa92..5f913f1 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -33,6 +33,7 @@ + #include "cores/VideoRenderers/RenderManager.h" + #include "utils/TimeUtils.h" + #include "settings/GUISettings.h" ++#include "windowing/WindowingFactory.h" + + #if defined(HAS_XRANDR) + #include +@@ -54,6 +55,7 @@ + m_bIgnoreNextFocusMessage = false; + m_dpyLostTime = 0; + m_invisibleCursor = 0; ++ m_bIsInternalXrr = false; + + XSetErrorHandler(XErrorHandler); + } +@@ -66,7 +68,8 @@ bool CWinSystemX11::InitWindowSystem() + { + if ((m_dpy = XOpenDisplay(NULL))) + { +- return CWinSystemBase::InitWindowSystem(); ++ bool ret = CWinSystemBase::InitWindowSystem(); ++ return ret; + } + else + CLog::Log(LOGERROR, "GLX Error: No Display found"); +@@ -103,6 +106,8 @@ bool CWinSystemX11::DestroyWindowSystem() + + //we don't call XCloseDisplay() here, since ati keeps a pointer to our m_dpy + //so instead we just let m_dpy die on exit ++ // i have seen core dumps on ATI if the display is not closed here ++ XCloseDisplay(m_dpy); + } + + // m_SDLSurface is free()'d by SDL_Quit(). +@@ -125,7 +130,10 @@ bool CWinSystemX11::DestroyWindow() + return true; + + if (m_glContext) ++ { ++ glFinish(); + glXMakeCurrent(m_dpy, None, NULL); ++ } + + if (m_invisibleCursor) + { +@@ -155,7 +163,7 @@ bool CWinSystemX11::ResizeWindow(int newWidth, int newHeight, int newLeft, int n + && m_nHeight == newHeight) + return true; + +- if (!SetWindow(newWidth, newHeight, false)) ++ if (!SetWindow(newWidth, newHeight, false, g_guiSettings.GetString("videoscreen.monitor"))) + { + return false; + } +@@ -164,58 +172,11 @@ bool CWinSystemX11::ResizeWindow(int newWidth, int newHeight, int newLeft, int n + m_nWidth = newWidth; + m_nHeight = newHeight; + m_bFullScreen = false; ++ m_currentOutput = g_guiSettings.GetString("videoscreen.monitor"); + + return false; + } + +-void CWinSystemX11::RefreshWindow() +-{ +- if (!g_xrandr.Query(true)) +- { +- CLog::Log(LOGERROR, "WinSystemX11::RefreshWindow - failed to query xrandr"); +- return; +- } +- XOutput out = g_xrandr.GetCurrentOutput(); +- XMode mode = g_xrandr.GetCurrentMode(out.name); +- +- RotateResolutions(); +- +- // only overwrite desktop resolution, if we are not in fullscreen mode +- if (!g_graphicsContext.IsFullScreenVideo()) +- { +- CLog::Log(LOGDEBUG, "CWinSystemX11::RefreshWindow - store desktop resolution, width: %d, height: %d, hz: %2.2f", mode.w, mode.h, mode.hz); +- if (!out.isRotated) +- UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.w, mode.h, mode.hz); +- else +- UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.h, mode.w, mode.hz); +- g_settings.m_ResInfo[RES_DESKTOP].strId = mode.id; +- g_settings.m_ResInfo[RES_DESKTOP].strOutput = out.name; +- } +- +- RESOLUTION_INFO res; +- unsigned int i; +- bool found(false); +- for (i = RES_DESKTOP; i < g_settings.m_ResInfo.size(); ++i) +- { +- if (g_settings.m_ResInfo[i].strId == mode.id) +- { +- found = true; +- break; +- } +- } +- +- if (!found) +- { +- CLog::Log(LOGERROR, "CWinSystemX11::RefreshWindow - could not find resolution"); +- return; +- } +- +- if (g_graphicsContext.IsFullScreenRoot()) +- g_graphicsContext.SetVideoResolution((RESOLUTION)i, true); +- else +- g_graphicsContext.SetVideoResolution(RES_WINDOW, true); +-} +- + bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays) + { + +@@ -240,8 +201,7 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl + mode.id = g_settings.m_ResInfo[RES_DESKTOP].strId; + } + +- XOutput currout = g_xrandr.GetCurrentOutput(); +- XMode currmode = g_xrandr.GetCurrentMode(currout.name); ++ XMode currmode = g_xrandr.GetCurrentMode(out.name); + + // flip h/w when rotated + if (m_bIsRotated) +@@ -252,16 +212,17 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl + } + + // only call xrandr if mode changes +- if (currout.name != out.name || currmode.w != mode.w || currmode.h != mode.h || ++ if (currmode.w != mode.w || currmode.h != mode.h || + currmode.hz != mode.hz || currmode.id != mode.id) + { + CLog::Log(LOGNOTICE, "CWinSystemX11::SetFullScreen - calling xrandr"); + OnLostDevice(); ++ m_bIsInternalXrr = true; + g_xrandr.SetMode(out, mode); + } + #endif + +- if (!SetWindow(res.iWidth, res.iHeight, fullScreen)) ++ if (!SetWindow(res.iWidth, res.iHeight, fullScreen, g_guiSettings.GetString("videoscreen.monitor"))) + return false; + + RefreshGlxContext(); +@@ -269,6 +230,7 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl + m_nWidth = res.iWidth; + m_nHeight = res.iHeight; + m_bFullScreen = fullScreen; ++ m_currentOutput = g_guiSettings.GetString("videoscreen.monitor"); + + return true; + } +@@ -277,19 +239,30 @@ void CWinSystemX11::UpdateResolutions() + { + CWinSystemBase::UpdateResolutions(); + +- + #if defined(HAS_XRANDR) +- if(g_xrandr.Query()) +- { +- XOutput out = g_xrandr.GetCurrentOutput(); +- XMode mode = g_xrandr.GetCurrentMode(out.name); +- m_bIsRotated = out.isRotated; ++ CStdString currentMonitor; ++ int numScreens = XScreenCount(m_dpy); ++ g_xrandr.SetNumScreens(numScreens); ++ if(g_xrandr.Query(true)) ++ { ++ currentMonitor = g_guiSettings.GetString("videoscreen.monitor"); ++ // check if the monitor is connected ++ XOutput *out = g_xrandr.GetOutput(currentMonitor); ++ if (!out) ++ { ++ // choose first output ++ currentMonitor = g_xrandr.GetModes()[0].name; ++ out = g_xrandr.GetOutput(currentMonitor); ++ g_guiSettings.SetString("videoscreen.monitor", currentMonitor); ++ } ++ XMode mode = g_xrandr.GetCurrentMode(currentMonitor); ++ m_bIsRotated = out->isRotated; + if (!m_bIsRotated) +- UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.w, mode.h, mode.hz); ++ UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], out->screen, mode.w, mode.h, mode.hz); + else +- UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.h, mode.w, mode.hz); ++ UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], out->screen, mode.h, mode.w, mode.hz); + g_settings.m_ResInfo[RES_DESKTOP].strId = mode.id; +- g_settings.m_ResInfo[RES_DESKTOP].strOutput = out.name; ++ g_settings.m_ResInfo[RES_DESKTOP].strOutput = currentMonitor; + } + else + #endif +@@ -300,23 +273,26 @@ void CWinSystemX11::UpdateResolutions() + UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, w, h, 0.0); + } + +- + #if defined(HAS_XRANDR) + ++ // erase previous stored modes ++ if (g_settings.m_ResInfo.size() > RES_CUSTOM) ++ { ++ std::vector::iterator firstCustom = g_settings.m_ResInfo.begin()+RES_CUSTOM; ++ g_settings.m_ResInfo.erase(firstCustom, g_settings.m_ResInfo.end()); ++ } ++ + CLog::Log(LOGINFO, "Available videomodes (xrandr):"); +- vector::iterator outiter; +- vector outs; +- outs = g_xrandr.GetModes(); +- CLog::Log(LOGINFO, "Number of connected outputs: %"PRIdS"", outs.size()); ++ ++ XOutput *out = g_xrandr.GetOutput(currentMonitor); + string modename = ""; + +- for (outiter = outs.begin() ; outiter != outs.end() ; outiter++) ++ if (out != NULL) + { +- XOutput out = *outiter; + vector::iterator modeiter; +- CLog::Log(LOGINFO, "Output '%s' has %"PRIdS" modes", out.name.c_str(), out.modes.size()); ++ CLog::Log(LOGINFO, "Output '%s' has %"PRIdS" modes", out->name.c_str(), out->modes.size()); + +- for (modeiter = out.modes.begin() ; modeiter!=out.modes.end() ; modeiter++) ++ for (modeiter = out->modes.begin() ; modeiter!=out->modes.end() ; modeiter++) + { + XMode mode = *modeiter; + CLog::Log(LOGINFO, "ID:%s Name:%s Refresh:%f Width:%d Height:%d", +@@ -336,15 +312,15 @@ void CWinSystemX11::UpdateResolutions() + res.iWidth = mode.h; + res.iHeight = mode.w; + } +- if (mode.h>0 && mode.w>0 && out.hmm>0 && out.wmm>0) +- res.fPixelRatio = ((float)out.wmm/(float)mode.w) / (((float)out.hmm/(float)mode.h)); ++ if (mode.h>0 && mode.w>0 && out->hmm>0 && out->wmm>0) ++ res.fPixelRatio = ((float)out->wmm/(float)mode.w) / (((float)out->hmm/(float)mode.h)); + else + res.fPixelRatio = 1.0f; + + CLog::Log(LOGINFO, "Pixel Ratio: %f", res.fPixelRatio); + +- res.strMode.Format("%s: %s @ %.2fHz", out.name.c_str(), mode.name.c_str(), mode.hz); +- res.strOutput = out.name; ++ res.strMode.Format("%s: %s @ %.2fHz", out->name.c_str(), mode.name.c_str(), mode.hz); ++ res.strOutput = out->name; + res.strId = mode.id; + res.iSubtitles = (int)(0.95*mode.h); + res.fRefreshRate = mode.hz; +@@ -363,28 +339,19 @@ void CWinSystemX11::UpdateResolutions() + + } + +-void CWinSystemX11::RotateResolutions() ++void CWinSystemX11::GetConnectedOutputs(std::vector *outputs) + { +-#if defined(HAS_XRANDR) +- XOutput out = g_xrandr.GetCurrentOutput(); +- if (out.isRotated == m_bIsRotated) +- return; +- +- for (unsigned int i = 0; i < g_settings.m_ResInfo.size(); ++i) ++ vector outs; ++ outs = g_xrandr.GetModes(); ++ for(unsigned int i=0; ipush_back(outs[i].name); + } +- // update desktop resolution +-// int h = g_settings.m_ResInfo[RES_DESKTOP].iHeight; +-// int w = g_settings.m_ResInfo[RES_DESKTOP].iWidth; +-// float hz = g_settings.m_ResInfo[RES_DESKTOP].fRefreshRate; +-// UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, w, h, hz); +- +- m_bIsRotated = out.isRotated; ++} + +-#endif ++bool CWinSystemX11::IsCurrentOutput(CStdString output) ++{ ++ return m_currentOutput.Equals(output); + } + + bool CWinSystemX11::IsSuitableVisual(XVisualInfo *vInfo) +@@ -414,8 +381,11 @@ bool CWinSystemX11::RefreshGlxContext() + if (m_glContext) + { + CLog::Log(LOGDEBUG, "CWinSystemX11::RefreshGlxContext: refreshing context"); ++ glFinish(); + glXMakeCurrent(m_dpy, None, NULL); + glXMakeCurrent(m_dpy, m_glWindow, m_glContext); ++ XSync(m_dpy, FALSE); ++ g_Windowing.ResetVSync(); + return true; + } + +@@ -481,6 +451,8 @@ bool CWinSystemX11::RefreshGlxContext() + { + // make this context current + glXMakeCurrent(m_dpy, m_glWindow, m_glContext); ++ g_Windowing.ResetVSync(); ++ XSync(m_dpy, False); + retVal = true; + } + else +@@ -522,24 +494,53 @@ void CWinSystemX11::ResetOSScreensaver() + + void CWinSystemX11::NotifyAppActiveChange(bool bActivated) + { +- if (bActivated && m_bWasFullScreenBeforeMinimize && !g_graphicsContext.IsFullScreenRoot()) ++ if (bActivated && m_bWasFullScreenBeforeMinimize && !m_bFullScreen) ++ { + g_graphicsContext.ToggleFullScreenRoot(); + ++ m_bWasFullScreenBeforeMinimize = false; ++ } + m_minimized = !bActivated; + } + + void CWinSystemX11::NotifyAppFocusChange(bool bGaining) + { + if (bGaining && m_bWasFullScreenBeforeMinimize && !m_bIgnoreNextFocusMessage && +- !g_graphicsContext.IsFullScreenRoot()) ++ !m_bFullScreen) ++ { ++ m_bWasFullScreenBeforeMinimize = false; + g_graphicsContext.ToggleFullScreenRoot(); ++ m_minimized = false; ++ } + if (!bGaining) + m_bIgnoreNextFocusMessage = false; + } + ++void CWinSystemX11::NotifyMouseCoverage(bool covered) ++{ ++ if (!m_bFullScreen) ++ return; ++ ++ if (covered) ++ { ++ int result = -1; ++ while (result != GrabSuccess && result != AlreadyGrabbed) ++ { ++ result = XGrabPointer(m_dpy, m_glWindow, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); ++ XbmcThreads::ThreadSleep(100); ++ } ++ XGrabKeyboard(m_dpy, m_glWindow, True, GrabModeAsync, GrabModeAsync, CurrentTime); ++ } ++ else ++ { ++ XUngrabKeyboard(m_dpy, CurrentTime); ++ XUngrabPointer(m_dpy, CurrentTime); ++ } ++} ++ + bool CWinSystemX11::Minimize() + { +- m_bWasFullScreenBeforeMinimize = g_graphicsContext.IsFullScreenRoot(); ++ m_bWasFullScreenBeforeMinimize = m_bFullScreen; + if (m_bWasFullScreenBeforeMinimize) + { + m_bIgnoreNextFocusMessage = true; +@@ -605,13 +606,46 @@ void CWinSystemX11::CheckDisplayEvents() + void CWinSystemX11::NotifyXRREvent() + { + CLog::Log(LOGDEBUG, "%s - notify display reset event", __FUNCTION__); +- RefreshWindow(); ++ m_windowDirty = true; + +- CSingleLock lock(m_resourceSection); ++ // if external event update resolutions ++ if (!m_bIsInternalXrr) ++ { ++ UpdateResolutions(); ++ } ++ else if (!g_xrandr.Query(true)) ++ { ++ CLog::Log(LOGERROR, "WinSystemX11::RefreshWindow - failed to query xrandr"); ++ return; ++ } ++ m_bIsInternalXrr = false; + +- // tell any shared resources +- for (vector::iterator i = m_resources.begin(); i != m_resources.end(); i++) +- (*i)->OnResetDevice(); ++ CStdString currentOutput = g_guiSettings.GetString("videoscreen.monitor"); ++ XOutput *out = g_xrandr.GetOutput(currentOutput); ++ XMode mode = g_xrandr.GetCurrentMode(currentOutput); ++ ++ RESOLUTION_INFO res; ++ unsigned int i; ++ bool found(false); ++ for (i = RES_DESKTOP; i < g_settings.m_ResInfo.size(); ++i) ++ { ++ if (g_settings.m_ResInfo[i].strId == mode.id) ++ { ++ found = true; ++ break; ++ } ++ } ++ ++ if (!found) ++ { ++ CLog::Log(LOGERROR, "CWinSystemX11::RefreshWindow - could not find resolution"); ++ i = RES_DESKTOP; ++ } ++ ++ if (g_graphicsContext.IsFullScreenRoot()) ++ g_graphicsContext.SetVideoResolution((RESOLUTION)i, true); ++ else ++ g_graphicsContext.SetVideoResolution(RES_WINDOW, true); + + } + +@@ -664,14 +698,14 @@ bool CWinSystemX11::EnableFrameLimiter() + return m_minimized; + } + +-bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen) ++bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStdString &output) + { + bool changeWindow = false; + bool changeSize = false; + bool mouseActive = false; + float mouseX, mouseY; + +- if (m_glWindow && (m_bFullScreen != fullscreen)) ++ if (m_glWindow && ((m_bFullScreen != fullscreen) || !m_currentOutput.Equals(output) || m_windowDirty)) + { + mouseActive = g_Mouse.IsActive(); + if (mouseActive) +@@ -693,6 +727,7 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen) + else + mouseActive = false; + } ++ OnLostDevice(); + DestroyWindow(); + } + +@@ -714,7 +749,11 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen) + XSetWindowAttributes swa; + XVisualInfo *vi; + +- vi = glXChooseVisual(m_dpy, DefaultScreen(m_dpy), att); ++ XOutput *out = g_xrandr.GetOutput(output); ++ if (!out) ++ out = g_xrandr.GetOutput(m_currentOutput); ++ m_nScreen = out->screen; ++ vi = glXChooseVisual(m_dpy, m_nScreen, att); + cmap = XCreateColormap(m_dpy, RootWindow(m_dpy, vi->screen), vi->visual, AllocNone); + + int def_vis = (vi->visual == DefaultVisual(m_dpy, vi->screen)); +@@ -730,7 +769,7 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen) + unsigned long mask = CWBackPixel | CWBorderPixel | CWColormap | CWOverrideRedirect | CWEventMask; + + m_glWindow = XCreateWindow(m_dpy, RootWindow(m_dpy, vi->screen), +- 0, 0, width, height, 0, vi->depth, ++ out->x, out->y, width, height, 0, vi->depth, + InputOutput, vi->visual, + mask, &swa); + +@@ -801,14 +840,19 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen) + if (fullscreen) + { + int result = -1; +- while (result != GrabSuccess) ++ while (result != GrabSuccess && result != AlreadyGrabbed) + { +- result = XGrabPointer(m_dpy, m_glWindow, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, m_glWindow, None, CurrentTime); ++ result = XGrabPointer(m_dpy, m_glWindow, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); + XbmcThreads::ThreadSleep(100); + } + XGrabKeyboard(m_dpy, m_glWindow, True, GrabModeAsync, GrabModeAsync, CurrentTime); +- + } ++ CSingleLock lock(m_resourceSection); ++ // tell any shared resources ++ for (vector::iterator i = m_resources.begin(); i != m_resources.end(); i++) ++ (*i)->OnResetDevice(); ++ ++ m_windowDirty = false; + } + return true; + } +diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h +index 93cf5db..71034fc 100644 +--- a/xbmc/windowing/X11/WinSystemX11.h ++++ b/xbmc/windowing/X11/WinSystemX11.h +@@ -65,15 +65,16 @@ class CWinSystemX11 : public CWinSystemBase + Display* GetDisplay() { return m_dpy; } + GLXWindow GetWindow() { return m_glWindow; } + GLXContext GetGlxContext() { return m_glContext; } +- void RefreshWindow(); + void NotifyXRREvent(); ++ void GetConnectedOutputs(std::vector *outputs); ++ bool IsCurrentOutput(CStdString output); ++ void NotifyMouseCoverage(bool covered); + + protected: + bool RefreshGlxContext(); + void CheckDisplayEvents(); + void OnLostDevice(); +- bool SetWindow(int width, int height, bool fullscreen); +- void RotateResolutions(); ++ bool SetWindow(int width, int height, bool fullscreen, const CStdString &output); + + Window m_glWindow; + GLXContext m_glContext; +@@ -88,6 +89,9 @@ class CWinSystemX11 : public CWinSystemBase + CCriticalSection m_resourceSection; + std::vector m_resources; + uint64_t m_dpyLostTime; ++ CStdString m_currentOutput; ++ bool m_windowDirty; ++ bool m_bIsInternalXrr; + + private: + bool IsSuitableVisual(XVisualInfo *vInfo); +-- +1.7.10 + + +From 2a747f13a0a50dea0883d0d3c701ef290235a99b Mon Sep 17 00:00:00 2001 +From: FernetMenta +Date: Thu, 5 Jul 2012 11:36:32 +0200 +Subject: [PATCH 23/73] X11: remove all DefaultScreen and RootWindow macros + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 6 +++--- + xbmc/windowing/X11/WinSystemX11.h | 1 + + xbmc/windowing/X11/WinSystemX11GL.cpp | 2 +- + 3 files changed, 5 insertions(+), 4 deletions(-) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index 5f913f1..af1307c 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -267,7 +267,7 @@ void CWinSystemX11::UpdateResolutions() + else + #endif + { +- int x11screen = DefaultScreen(m_dpy); ++ int x11screen = m_nScreen; + int w = DisplayWidth(m_dpy, x11screen); + int h = DisplayHeight(m_dpy, x11screen); + UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, w, h, 0.0); +@@ -393,7 +393,7 @@ bool CWinSystemX11::RefreshGlxContext() + XVisualInfo *visuals; + XVisualInfo *vInfo = NULL; + int availableVisuals = 0; +- vMask.screen = DefaultScreen(m_dpy); ++ vMask.screen = m_nScreen; + XWindowAttributes winAttr; + + /* Assume a depth of 24 in case the below calls to XGetWindowAttributes() +@@ -547,7 +547,7 @@ bool CWinSystemX11::Minimize() + g_graphicsContext.ToggleFullScreenRoot(); + } + +- XIconifyWindow(m_dpy, m_glWindow, DefaultScreen(m_dpy)); ++ XIconifyWindow(m_dpy, m_glWindow, m_nScreen); + + m_minimized = true; + return true; +diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h +index 71034fc..3bb4b8e 100644 +--- a/xbmc/windowing/X11/WinSystemX11.h ++++ b/xbmc/windowing/X11/WinSystemX11.h +@@ -47,6 +47,7 @@ class CWinSystemX11 : public CWinSystemBase + virtual bool SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays); + virtual void UpdateResolutions(); + virtual int GetNumScreens() { return 1; } ++ virtual int GetCurrentScreen() { return m_nScreen; } + virtual void ShowOSMouse(bool show); + virtual void ResetOSScreensaver(); + virtual bool EnableFrameLimiter(); +diff --git a/xbmc/windowing/X11/WinSystemX11GL.cpp b/xbmc/windowing/X11/WinSystemX11GL.cpp +index f858f88..d192697 100644 +--- a/xbmc/windowing/X11/WinSystemX11GL.cpp ++++ b/xbmc/windowing/X11/WinSystemX11GL.cpp +@@ -203,7 +203,7 @@ bool CWinSystemX11GL::CreateNewWindow(const CStdString& name, bool fullScreen, R + return false; + + m_glxext = " "; +- m_glxext += (const char*)glXQueryExtensionsString(m_dpy, DefaultScreen(m_dpy)); ++ m_glxext += (const char*)glXQueryExtensionsString(m_dpy, m_nScreen); + m_glxext += " "; + + CLog::Log(LOGDEBUG, "GLX_EXTENSIONS:%s", m_glxext.c_str()); +-- +1.7.10 + + +From cf018ebbf1eae8f5ae2914ef347aac5f963c0d71 Mon Sep 17 00:00:00 2001 +From: FernetMenta +Date: Thu, 5 Jul 2012 11:45:22 +0200 +Subject: [PATCH 24/73] X11: remove all DefaultScreen and RootWindow macros + (VideoRefClock) + +Note this is on a separate display connection. +--- + xbmc/video/VideoReferenceClock.cpp | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +diff --git a/xbmc/video/VideoReferenceClock.cpp b/xbmc/video/VideoReferenceClock.cpp +index 9785fe7..0004e07 100644 +--- a/xbmc/video/VideoReferenceClock.cpp ++++ b/xbmc/video/VideoReferenceClock.cpp +@@ -270,7 +270,7 @@ bool CVideoReferenceClock::SetupGLX() + } + + bool ExtensionFound = false; +- istringstream Extensions(glXQueryExtensionsString(m_Dpy, DefaultScreen(m_Dpy))); ++ istringstream Extensions(glXQueryExtensionsString(m_Dpy, g_Windowing.GetCurrentScreen())); + string ExtensionStr; + + while (!ExtensionFound) +@@ -297,7 +297,7 @@ bool CVideoReferenceClock::SetupGLX() + m_bIsATI = true; + } + +- m_vInfo = glXChooseVisual(m_Dpy, DefaultScreen(m_Dpy), singleBufferAttributes); ++ m_vInfo = glXChooseVisual(m_Dpy, g_Windowing.GetCurrentScreen(), singleBufferAttributes); + if (!m_vInfo) + { + CLog::Log(LOGDEBUG, "CVideoReferenceClock: glXChooseVisual returned NULL"); +@@ -308,15 +308,16 @@ bool CVideoReferenceClock::SetupGLX() + { + Swa.border_pixel = 0; + Swa.event_mask = StructureNotifyMask; +- Swa.colormap = XCreateColormap(m_Dpy, RootWindow(m_Dpy, m_vInfo->screen), m_vInfo->visual, AllocNone ); ++ Swa.colormap = XCreateColormap(m_Dpy, g_Windowing.GetWindow(), m_vInfo->visual, AllocNone ); + SwaMask = CWBorderPixel | CWColormap | CWEventMask; + +- m_Window = XCreateWindow(m_Dpy, RootWindow(m_Dpy, m_vInfo->screen), 0, 0, 256, 256, 0, ++ m_Window = XCreateWindow(m_Dpy, g_Windowing.GetWindow(), 0, 0, 256, 256, 0, + m_vInfo->depth, InputOutput, m_vInfo->visual, SwaMask, &Swa); + } + else + { +- m_pixmap = XCreatePixmap(m_Dpy, DefaultRootWindow(m_Dpy), 256, 256, m_vInfo->depth); ++ Window window = g_Windowing.GetWindow(); ++ m_pixmap = XCreatePixmap(m_Dpy, window, 256, 256, m_vInfo->depth); + if (!m_pixmap) + { + CLog::Log(LOGDEBUG, "CVideoReferenceClock: unable to create pixmap"); +@@ -383,7 +384,7 @@ bool CVideoReferenceClock::SetupGLX() + + //set up receiving of RandR events, we'll get one when the refreshrate changes + XRRQueryExtension(m_Dpy, &m_RREventBase, &ReturnV); +- XRRSelectInput(m_Dpy, RootWindow(m_Dpy, m_vInfo->screen), RRScreenChangeNotifyMask); ++ XRRSelectInput(m_Dpy, g_Windowing.GetWindow(), RRScreenChangeNotifyMask); + + UpdateRefreshrate(true); //forced refreshrate update + m_MissedVblanks = 0; +@@ -518,7 +519,7 @@ int CVideoReferenceClock::GetRandRRate() + int RefreshRate; + XRRScreenConfiguration *CurrInfo; + +- CurrInfo = XRRGetScreenInfo(m_Dpy, RootWindow(m_Dpy, m_vInfo->screen)); ++ CurrInfo = XRRGetScreenInfo(m_Dpy, g_Windowing.GetWindow()); + RefreshRate = XRRConfigCurrentRate(CurrInfo); + XRRFreeScreenConfigInfo(CurrInfo); + +-- +1.7.10 + + +From 5d8bfcd52e5a189515629c15c73434ef6c6bcc88 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Wed, 20 Jun 2012 17:37:11 +0200 +Subject: [PATCH 25/73] X11: recreate gl context after output has changed + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 24 ++++++++++++++---------- + xbmc/windowing/X11/WinSystemX11.h | 1 + + xbmc/windowing/X11/WinSystemX11GL.cpp | 9 +++++++++ + 3 files changed, 24 insertions(+), 10 deletions(-) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index af1307c..d3d15e2 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -168,7 +168,6 @@ bool CWinSystemX11::ResizeWindow(int newWidth, int newHeight, int newLeft, int n + return false; + } + +- RefreshGlxContext(); + m_nWidth = newWidth; + m_nHeight = newHeight; + m_bFullScreen = false; +@@ -219,14 +218,13 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl + OnLostDevice(); + m_bIsInternalXrr = true; + g_xrandr.SetMode(out, mode); ++ return true; + } + #endif + + if (!SetWindow(res.iWidth, res.iHeight, fullScreen, g_guiSettings.GetString("videoscreen.monitor"))) + return false; + +- RefreshGlxContext(); +- + m_nWidth = res.iWidth; + m_nHeight = res.iHeight; + m_bFullScreen = fullScreen; +@@ -381,11 +379,8 @@ bool CWinSystemX11::RefreshGlxContext() + if (m_glContext) + { + CLog::Log(LOGDEBUG, "CWinSystemX11::RefreshGlxContext: refreshing context"); +- glFinish(); + glXMakeCurrent(m_dpy, None, NULL); + glXMakeCurrent(m_dpy, m_glWindow, m_glContext); +- XSync(m_dpy, FALSE); +- g_Windowing.ResetVSync(); + return true; + } + +@@ -445,14 +440,14 @@ bool CWinSystemX11::RefreshGlxContext() + { + glXMakeCurrent(m_dpy, None, NULL); + glXDestroyContext(m_dpy, m_glContext); ++ XSync(m_dpy, FALSE); ++ m_newGlContext = true; + } + + if ((m_glContext = glXCreateContext(m_dpy, vInfo, NULL, True))) + { + // make this context current + glXMakeCurrent(m_dpy, m_glWindow, m_glContext); +- g_Windowing.ResetVSync(); +- XSync(m_dpy, False); + retVal = true; + } + else +@@ -729,6 +724,7 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd + } + OnLostDevice(); + DestroyWindow(); ++ m_windowDirty = true; + } + + // create main window +@@ -847,13 +843,21 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd + } + XGrabKeyboard(m_dpy, m_glWindow, True, GrabModeAsync, GrabModeAsync, CurrentTime); + } ++ ++ CDirtyRegionList dr; ++ RefreshGlxContext(); ++ XSync(m_dpy, FALSE); ++ g_graphicsContext.Clear(0); ++ g_graphicsContext.Flip(dr); ++ g_Windowing.ResetVSync(); ++ m_windowDirty = false; ++ + CSingleLock lock(m_resourceSection); + // tell any shared resources + for (vector::iterator i = m_resources.begin(); i != m_resources.end(); i++) + (*i)->OnResetDevice(); +- +- m_windowDirty = false; + } ++ + return true; + } + +diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h +index 3bb4b8e..cc28f56 100644 +--- a/xbmc/windowing/X11/WinSystemX11.h ++++ b/xbmc/windowing/X11/WinSystemX11.h +@@ -93,6 +93,7 @@ class CWinSystemX11 : public CWinSystemBase + CStdString m_currentOutput; + bool m_windowDirty; + bool m_bIsInternalXrr; ++ bool m_newGlContext; + + private: + bool IsSuitableVisual(XVisualInfo *vInfo); +diff --git a/xbmc/windowing/X11/WinSystemX11GL.cpp b/xbmc/windowing/X11/WinSystemX11GL.cpp +index d192697..0f2d1d2 100644 +--- a/xbmc/windowing/X11/WinSystemX11GL.cpp ++++ b/xbmc/windowing/X11/WinSystemX11GL.cpp +@@ -23,6 +23,7 @@ + + #include "WinSystemX11GL.h" + #include "utils/log.h" ++#include "Application.h" + + CWinSystemX11GL::CWinSystemX11GL() + { +@@ -245,17 +246,25 @@ bool CWinSystemX11GL::CreateNewWindow(const CStdString& name, bool fullScreen, R + + bool CWinSystemX11GL::ResizeWindow(int newWidth, int newHeight, int newLeft, int newTop) + { ++ m_newGlContext = false; + CWinSystemX11::ResizeWindow(newWidth, newHeight, newLeft, newTop); + CRenderSystemGL::ResetRenderSystem(newWidth, newHeight, false, 0); + ++ if (m_newGlContext) ++ g_application.ReloadSkin(); ++ + return true; + } + + bool CWinSystemX11GL::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays) + { ++ m_newGlContext = false; + CWinSystemX11::SetFullScreen(fullScreen, res, blankOtherDisplays); + CRenderSystemGL::ResetRenderSystem(res.iWidth, res.iHeight, fullScreen, res.fRefreshRate); + ++ if (m_newGlContext) ++ g_application.ReloadSkin(); ++ + return true; + } + +-- +1.7.10 + + +From bd9a29b7661c75152174959f9f269f32c13a658b Mon Sep 17 00:00:00 2001 +From: FernetMenta +Date: Thu, 5 Jul 2012 12:06:25 +0200 +Subject: [PATCH 26/73] X11: hook video reference clock in windowing + +--- + xbmc/video/VideoReferenceClock.cpp | 71 ++++++++++++++++++++++++++---------- + xbmc/video/VideoReferenceClock.h | 13 ++++++- + 2 files changed, 63 insertions(+), 21 deletions(-) + +diff --git a/xbmc/video/VideoReferenceClock.cpp b/xbmc/video/VideoReferenceClock.cpp +index 0004e07..fa8e35a 100644 +--- a/xbmc/video/VideoReferenceClock.cpp ++++ b/xbmc/video/VideoReferenceClock.cpp +@@ -135,12 +135,23 @@ + m_Context = NULL; + m_pixmap = None; + m_glPixmap = None; +- m_RREventBase = 0; + m_UseNvSettings = true; + m_bIsATI = false; + #endif + } + ++CVideoReferenceClock::~CVideoReferenceClock() ++{ ++#if defined(HAS_GLX) ++ // some ATI voodoo, if we don't close the display, we crash on exit ++ if (m_Dpy) ++ { ++ XCloseDisplay(m_Dpy); ++ m_Dpy = NULL; ++ } ++#endif ++} ++ + void CVideoReferenceClock::Process() + { + bool SetupSuccess = false; +@@ -151,6 +162,10 @@ void CVideoReferenceClock::Process() + m_D3dCallback.Reset(); + g_Windowing.Register(&m_D3dCallback); + #endif ++#if defined(HAS_GLX) && defined(HAS_XRANDR) ++ g_Windowing.Register(this); ++ m_xrrEvent = false; ++#endif + + while(!m_bStop) + { +@@ -211,6 +226,16 @@ void CVideoReferenceClock::Process() + //clean up the vblank clock + #if defined(HAS_GLX) && defined(HAS_XRANDR) + CleanupGLX(); ++ if (m_xrrEvent) ++ { ++ m_releaseEvent.Set(); ++ while (!m_bStop) ++ { ++ if (m_resetEvent.WaitMSec(100)) ++ break; ++ } ++ m_xrrEvent = false; ++ } + #elif defined(_WIN32) && defined(HAS_DX) + CleanupD3D(); + #elif defined(TARGET_DARWIN) +@@ -222,6 +247,9 @@ void CVideoReferenceClock::Process() + #if defined(_WIN32) && defined(HAS_DX) + g_Windowing.Unregister(&m_D3dCallback); + #endif ++#if defined(HAS_GLX) ++ g_Windowing.Unregister(this); ++#endif + } + + bool CVideoReferenceClock::WaitStarted(int MSecs) +@@ -231,6 +259,24 @@ bool CVideoReferenceClock::WaitStarted(int MSecs) + } + + #if defined(HAS_GLX) && defined(HAS_XRANDR) ++ ++void CVideoReferenceClock::OnLostDevice() ++{ ++ if (!m_xrrEvent) ++ { ++ m_releaseEvent.Reset(); ++ m_resetEvent.Reset(); ++ m_xrrEvent = true; ++ m_releaseEvent.Wait(); ++ } ++} ++ ++void CVideoReferenceClock::OnResetDevice() ++{ ++ m_xrrEvent = false; ++ m_resetEvent.Set(); ++} ++ + bool CVideoReferenceClock::SetupGLX() + { + int singleBufferAttributes[] = { +@@ -382,10 +428,6 @@ bool CVideoReferenceClock::SetupGLX() + return false; + } + +- //set up receiving of RandR events, we'll get one when the refreshrate changes +- XRRQueryExtension(m_Dpy, &m_RREventBase, &ReturnV); +- XRRSelectInput(m_Dpy, g_Windowing.GetWindow(), RRScreenChangeNotifyMask); +- + UpdateRefreshrate(true); //forced refreshrate update + m_MissedVblanks = 0; + +@@ -586,6 +628,9 @@ void CVideoReferenceClock::RunGLX() + + while(!m_bStop) + { ++ if (m_xrrEvent) ++ return; ++ + //wait for the next vblank + if (!m_bIsATI) + { +@@ -649,7 +694,6 @@ void CVideoReferenceClock::RunGLX() + UpdateClock((int)(VblankCount - PrevVblankCount), true); + SingleLock.Leave(); + SendVblankSignal(); +- UpdateRefreshrate(); + IsReset = false; + } + else if (!m_bStop) +@@ -1186,23 +1230,10 @@ bool CVideoReferenceClock::UpdateRefreshrate(bool Forced /*= false*/) + + #if defined(HAS_GLX) && defined(HAS_XRANDR) + +- //check for RandR events +- bool GotEvent = Forced || m_RefreshChanged == 2; +- XEvent Event; +- while (XCheckTypedEvent(m_Dpy, m_RREventBase + RRScreenChangeNotify, &Event)) +- { +- if (Event.type == m_RREventBase + RRScreenChangeNotify) +- { +- CLog::Log(LOGDEBUG, "CVideoReferenceClock: Received RandR event %i", Event.type); +- GotEvent = true; +- } +- XRRUpdateConfiguration(&Event); +- } +- + if (!Forced) + m_RefreshChanged = 0; + +- if (!GotEvent) //refreshrate did not change ++ if (!Forced) //refreshrate did not change + return false; + + //the refreshrate can be wrong on nvidia drivers, so read it from nvidia-settings when it's available +diff --git a/xbmc/video/VideoReferenceClock.h b/xbmc/video/VideoReferenceClock.h +index dcc4f09..7eb6317 100644 +--- a/xbmc/video/VideoReferenceClock.h ++++ b/xbmc/video/VideoReferenceClock.h +@@ -30,6 +30,7 @@ + #include + #include + #include ++ #include "guilib/DispResource.h" + #elif defined(_WIN32) && defined(HAS_DX) + #include + #include "guilib/D3DResource.h" +@@ -56,9 +57,13 @@ class CD3DCallback : public ID3DResource + #endif + + class CVideoReferenceClock : public CThread ++#if defined(HAS_GLX) && defined(HAS_XRANDR) ++ ,public IDispResource ++#endif + { + public: + CVideoReferenceClock(); ++ virtual ~CVideoReferenceClock(); + + int64_t GetTime(bool interpolated = true); + int64_t GetFrequency(); +@@ -75,6 +80,11 @@ class CVideoReferenceClock : public CThread + void VblankHandler(int64_t nowtime, double fps); + #endif + ++#if defined(HAS_GLX) && defined(HAS_XRANDR) ++ virtual void OnLostDevice(); ++ virtual void OnResetDevice(); ++#endif ++ + private: + void Process(); + bool UpdateRefreshrate(bool Forced = false); +@@ -121,7 +131,8 @@ class CVideoReferenceClock : public CThread + GLXContext m_Context; + Pixmap m_pixmap; + GLXPixmap m_glPixmap; +- int m_RREventBase; ++ bool m_xrrEvent; ++ CEvent m_releaseEvent, m_resetEvent; + + bool m_UseNvSettings; + bool m_bIsATI; +-- +1.7.10 + + +From 702f79eab647ec68030c99d6113976f3c602e87c Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 21 Jun 2012 17:26:51 +0200 +Subject: [PATCH 27/73] X11: fix video calibrations + +--- + xbmc/settings/Settings.cpp | 1 + + xbmc/windowing/WinSystem.h | 1 + + xbmc/windowing/X11/WinSystemX11.cpp | 36 ++++++++++++++++++++++++++++++++++- + xbmc/windowing/X11/WinSystemX11.h | 1 + + 4 files changed, 38 insertions(+), 1 deletion(-) + +diff --git a/xbmc/settings/Settings.cpp b/xbmc/settings/Settings.cpp +index 8a430ad..fde6e4e 100644 +--- a/xbmc/settings/Settings.cpp ++++ b/xbmc/settings/Settings.cpp +@@ -55,6 +55,7 @@ + #include "filesystem/File.h" + #include "filesystem/DirectoryCache.h" + #include "DatabaseManager.h" ++#include "windowing/WindowingFactory.h" + + using namespace std; + using namespace XFILE; +diff --git a/xbmc/windowing/WinSystem.h b/xbmc/windowing/WinSystem.h +index 05c5eda..852d085 100644 +--- a/xbmc/windowing/WinSystem.h ++++ b/xbmc/windowing/WinSystem.h +@@ -100,6 +100,7 @@ class CWinSystemBase + std::vector ScreenResolutions(int screen); + std::vector RefreshRates(int screen, int width, int height, uint32_t dwFlags); + REFRESHRATE DefaultRefreshRate(int screen, std::vector rates); ++ virtual bool HasCalibration(const RESOLUTION_INFO &resInfo) { return true; }; + + protected: + void UpdateDesktopResolution(RESOLUTION_INFO& newRes, int screen, int width, int height, float refreshRate, uint32_t dwFlags = 0); +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index d3d15e2..487b324 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -320,7 +320,7 @@ void CWinSystemX11::UpdateResolutions() + res.strMode.Format("%s: %s @ %.2fHz", out->name.c_str(), mode.name.c_str(), mode.hz); + res.strOutput = out->name; + res.strId = mode.id; +- res.iSubtitles = (int)(0.95*mode.h); ++ res.iSubtitles = (int)(0.965*mode.h); + res.fRefreshRate = mode.hz; + res.bFullScreen = true; + +@@ -333,8 +333,42 @@ void CWinSystemX11::UpdateResolutions() + g_settings.m_ResInfo.push_back(res); + } + } ++ g_settings.ApplyCalibrations(); + #endif ++} ++ ++bool CWinSystemX11::HasCalibration(const RESOLUTION_INFO &resInfo) ++{ ++ XOutput *out = g_xrandr.GetOutput(m_currentOutput); ++ ++ // keep calibrations done on a not connected output ++ if (!out->name.Equals(resInfo.strOutput)) ++ return true; ++ ++ // keep calibrations not updated with resolution data ++ if (resInfo.iWidth == 0) ++ return true; ++ ++ float fPixRatio; ++ if (resInfo.iHeight>0 && resInfo.iWidth>0 && out->hmm>0 && out->wmm>0) ++ fPixRatio = ((float)out->wmm/(float)resInfo.iWidth) / (((float)out->hmm/(float)resInfo.iHeight)); ++ else ++ fPixRatio = 1.0f; + ++ if (resInfo.Overscan.left != 0) ++ return true; ++ if (resInfo.Overscan.top != 0) ++ return true; ++ if (resInfo.Overscan.right != resInfo.iWidth) ++ return true; ++ if (resInfo.Overscan.bottom != resInfo.iHeight) ++ return true; ++ if (resInfo.fPixelRatio != fPixRatio) ++ return true; ++ if (resInfo.iSubtitles != (int)(0.965*resInfo.iHeight)) ++ return true; ++ ++ return false; + } + + void CWinSystemX11::GetConnectedOutputs(std::vector *outputs) +diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h +index cc28f56..c046c86 100644 +--- a/xbmc/windowing/X11/WinSystemX11.h ++++ b/xbmc/windowing/X11/WinSystemX11.h +@@ -61,6 +61,7 @@ class CWinSystemX11 : public CWinSystemBase + virtual bool Show(bool raise = true); + virtual void Register(IDispResource *resource); + virtual void Unregister(IDispResource *resource); ++ virtual bool HasCalibration(const RESOLUTION_INFO &resInfo); + + // Local to WinSystemX11 only + Display* GetDisplay() { return m_dpy; } +-- +1.7.10 + + +From 07920e322c9770ebb99becd104ebce0789c502fa Mon Sep 17 00:00:00 2001 +From: FernetMenta +Date: Thu, 5 Jul 2012 12:00:26 +0200 +Subject: [PATCH 28/73] X11: deactivate screen saver on startup + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 29 +++++++++++++++++++++++++++++ + xbmc/windowing/X11/WinSystemX11.h | 1 + + 2 files changed, 30 insertions(+) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index 487b324..b3e7ab5 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -521,6 +521,33 @@ void CWinSystemX11::ResetOSScreensaver() + } + } + ++void CWinSystemX11::EnableSystemScreenSaver(bool bEnable) ++{ ++ if (!m_dpy) ++ return; ++ ++ if (bEnable) ++ XForceScreenSaver(m_dpy, ScreenSaverActive); ++ else ++ { ++ Window root_return, child_return; ++ int root_x_return, root_y_return; ++ int win_x_return, win_y_return; ++ unsigned int mask_return; ++ bool isInWin = XQueryPointer(m_dpy, RootWindow(m_dpy, m_nScreen), &root_return, &child_return, ++ &root_x_return, &root_y_return, ++ &win_x_return, &win_y_return, ++ &mask_return); ++ ++ XWarpPointer(m_dpy, None, RootWindow(m_dpy, m_nScreen), 0, 0, 0, 0, root_x_return+300, root_y_return+300); ++ XSync(m_dpy, FALSE); ++ XWarpPointer(m_dpy, None, RootWindow(m_dpy, m_nScreen), 0, 0, 0, 0, 0, 0); ++ XSync(m_dpy, FALSE); ++ XWarpPointer(m_dpy, None, RootWindow(m_dpy, m_nScreen), 0, 0, 0, 0, root_x_return, root_y_return); ++ XSync(m_dpy, FALSE); ++ } ++} ++ + void CWinSystemX11::NotifyAppActiveChange(bool bActivated) + { + if (bActivated && m_bWasFullScreenBeforeMinimize && !m_bFullScreen) +@@ -764,6 +791,8 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd + // create main window + if (!m_glWindow) + { ++ EnableSystemScreenSaver(false); ++ + GLint att[] = + { + GLX_RGBA, +diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h +index c046c86..e953d2d 100644 +--- a/xbmc/windowing/X11/WinSystemX11.h ++++ b/xbmc/windowing/X11/WinSystemX11.h +@@ -51,6 +51,7 @@ class CWinSystemX11 : public CWinSystemBase + virtual void ShowOSMouse(bool show); + virtual void ResetOSScreensaver(); + virtual bool EnableFrameLimiter(); ++ virtual void EnableSystemScreenSaver(bool bEnable); + + virtual void NotifyAppActiveChange(bool bActivated); + virtual void NotifyAppFocusChange(bool bGaining); +-- +1.7.10 + + +From 835bcc9c7fd477012492ffc4cad2bdd9ce506064 Mon Sep 17 00:00:00 2001 +From: FernetMenta +Date: Thu, 5 Jul 2012 12:10:09 +0200 +Subject: [PATCH 29/73] X11: change method of going full-screen + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index b3e7ab5..91f92c1 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -34,6 +34,7 @@ + #include "utils/TimeUtils.h" + #include "settings/GUISettings.h" + #include "windowing/WindowingFactory.h" ++#include + + #if defined(HAS_XRANDR) + #include +@@ -816,7 +817,7 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd + cmap = XCreateColormap(m_dpy, RootWindow(m_dpy, vi->screen), vi->visual, AllocNone); + + int def_vis = (vi->visual == DefaultVisual(m_dpy, vi->screen)); +- swa.override_redirect = fullscreen ? True : False; ++ swa.override_redirect = False; + swa.border_pixel = fullscreen ? 0 : 5; + swa.background_pixel = def_vis ? BlackPixel(m_dpy, vi->screen) : 0; + swa.colormap = cmap; +@@ -832,6 +833,12 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd + InputOutput, vi->visual, + mask, &swa); + ++ if (fullscreen) ++ { ++ Atom fs = XInternAtom(m_dpy, "_NET_WM_STATE_FULLSCREEN", True); ++ XChangeProperty(m_dpy, m_glWindow, XInternAtom(m_dpy, "_NET_WM_STATE", True), XA_ATOM, 32, PropModeReplace, (unsigned char *) &fs, 1); ++ } ++ + // define invisible cursor + Pixmap bitmapNoData; + XColor black; +-- +1.7.10 + + +From e2442797ff82b3ed8053f1a6422863ffce9cbe5f Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 28 Jun 2012 19:12:39 +0200 +Subject: [PATCH 30/73] X11: reset key repeat and key modifier on focus lost + and gain + +--- + xbmc/windowing/WinEventsX11.cpp | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp +index 6c22358..d86205d 100644 +--- a/xbmc/windowing/WinEventsX11.cpp ++++ b/xbmc/windowing/WinEventsX11.cpp +@@ -359,6 +359,8 @@ bool CWinEventsX11::MessagePump() + if (WinEvents->m_xic) + XSetICFocus(WinEvents->m_xic); + g_application.m_AppFocused = true; ++ memset(&(WinEvents->m_lastKey), 0, sizeof(XBMC_Event)); ++ WinEvents->m_keymodState = 0; + if (serial == xevent.xfocus.serial) + break; + g_Windowing.NotifyAppFocusChange(g_application.m_AppFocused); +@@ -370,6 +372,7 @@ bool CWinEventsX11::MessagePump() + if (WinEvents->m_xic) + XUnsetICFocus(WinEvents->m_xic); + g_application.m_AppFocused = false; ++ memset(&(WinEvents->m_lastKey), 0, sizeof(XBMC_Event)); + g_Windowing.NotifyAppFocusChange(g_application.m_AppFocused); + serial = xevent.xfocus.serial; + break; +-- +1.7.10 + + +From 77a22163a7f611e9183b7cd0b817fc51a42d45de Mon Sep 17 00:00:00 2001 +From: Joakim Plate +Date: Thu, 5 Jul 2012 14:18:46 +0200 +Subject: [PATCH 31/73] X11: replace custom utf8 to unicode with charset + convertor (squash to x11 events) + +--- + xbmc/windowing/WinEventsX11.cpp | 119 ++++----------------------------------- + xbmc/windowing/WinEventsX11.h | 2 - + 2 files changed, 11 insertions(+), 110 deletions(-) + +diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp +index d86205d..76702e6 100644 +--- a/xbmc/windowing/WinEventsX11.cpp ++++ b/xbmc/windowing/WinEventsX11.cpp +@@ -32,6 +32,7 @@ + #include "X11/keysymdef.h" + #include "X11/XF86keysym.h" + #include "utils/log.h" ++#include "utils/CharsetConverter.h" + #include "guilib/GUIWindowManager.h" + #include "input/MouseStat.h" + +@@ -161,7 +162,6 @@ + m_display = 0; + m_window = 0; + m_keybuf = 0; +- m_utf16buf = 0; + } + + CWinEventsX11::~CWinEventsX11() +@@ -172,12 +172,6 @@ + m_keybuf = 0; + } + +- if (m_utf16buf) +- { +- free(m_utf16buf); +- m_utf16buf = 0; +- } +- + if (m_xic) + { + XUnsetICFocus(m_xic); +@@ -203,7 +197,6 @@ bool CWinEventsX11::Init(Display *dpy, Window win) + WinEvents->m_display = dpy; + WinEvents->m_window = win; + WinEvents->m_keybuf = (char*)malloc(32*sizeof(char)); +- WinEvents->m_utf16buf = (uint16_t*)malloc(32*sizeof(uint16_t)); + WinEvents->m_keymodState = 0; + WinEvents->m_wmDeleteMessage = XInternAtom(dpy, "WM_DELETE_WINDOW", False); + WinEvents->m_structureChanged = false; +@@ -433,8 +426,6 @@ bool CWinEventsX11::MessagePump() + } + + Status status; +- int utf16size; +- int utf16length; + int len; + len = Xutf8LookupString(WinEvents->m_xic, &xevent.xkey, + WinEvents->m_keybuf, sizeof(WinEvents->m_keybuf), +@@ -453,36 +444,29 @@ bool CWinEventsX11::MessagePump() + case XLookupChars: + case XLookupBoth: + { +- if (len == 0) +- break; +- utf16size = len * sizeof(uint16_t); +- if (utf16size > sizeof(WinEvents->m_utf16buf)) +- { +- WinEvents->m_utf16buf = (uint16_t *)realloc(WinEvents->m_utf16buf,utf16size); +- if (WinEvents->m_utf16buf == NULL) +- { +- break; +- } +- } +- utf16length = Utf8ToUnicode(WinEvents->m_keybuf, len, WinEvents->m_utf16buf, utf16size); +- if (utf16length < 0) ++ CStdString data(WinEvents->m_keybuf, len); ++ CStdStringW keys; ++ g_charsetConverter.utf8ToW(data, keys, false); ++ ++ if (keys.length() == 0) + { + break; + } +- for (unsigned int i = 0; i < utf16length - 1; i++) ++ ++ for (unsigned int i = 0; i < keys.length() - 1; i++) + { + newEvent.key.keysym.sym = XBMCK_UNKNOWN; +- newEvent.key.keysym.unicode = WinEvents->m_utf16buf[i]; ++ newEvent.key.keysym.unicode = keys[i]; + newEvent.key.state = xevent.xkey.state; + newEvent.key.type = xevent.xkey.type; + ret |= ProcessKey(newEvent, 500); + } +- if (utf16length > 0) ++ if (keys.length() > 0) + { + newEvent.key.keysym.scancode = xevent.xkey.keycode; + xkeysym = XLookupKeysym(&xevent.xkey, 0); + newEvent.key.keysym.sym = LookupXbmcKeySym(xkeysym); +- newEvent.key.keysym.unicode = WinEvents->m_utf16buf[utf16length - 1]; ++ newEvent.key.keysym.unicode = keys[keys.length() - 1]; + newEvent.key.state = xevent.xkey.state; + newEvent.key.type = xevent.xkey.type; + +@@ -743,87 +727,6 @@ bool CWinEventsX11::ProcessKeyRepeat() + return false; + } + +-int CWinEventsX11::Utf8ToUnicode(const char *utf8, const int utf8Length, uint16_t *utf16, const int utf16MaxLength) +-{ +- // p moves over the output buffer. max_ptr points to the next to the last slot of the buffer. +- uint16_t *p = utf16; +- uint16_t const *const maxPtr = utf16 + utf16MaxLength; +- +- // end_of_input points to the last byte of input as opposed to the next to the last byte. +- char const *const endOfInput = utf8 + utf8Length - 1; +- +- while (utf8 <= endOfInput) +- { +- unsigned char const c = *utf8; +- if (p >= maxPtr) +- { +- //No more output space. +- return -1; +- } +- if (c < 0x80) +- { +- //One byte ASCII. +- *p++ = c; +- utf8 += 1; +- } +- else if (c < 0xC0) +- { +- // Follower byte without preceding leader bytes. +- return -1; +- } +- // 11 bits +- else if (c < 0xE0) +- { +- // Two byte sequence. We need one follower byte. +- if (endOfInput - utf8 < 1 || (((utf8[1] ^ 0x80)) & 0xC0)) +- { +- return -1; +- } +- *p++ = (uint16_t)(((c & 0x1F) << 6) + (utf8[1] & 0x3F)); +- utf8 += 2; +- } +- // 16 bis +- else if (c < 0xF0) +- { +- // Three byte sequence. We need two follower byte. +- if (endOfInput - utf8 < 2 || ((utf8[1] ^ 0x80) & 0xC0) || ((utf8[2] ^ 0x80) & 0xC0)) +- { +- return -1; +- } +- *p++ = (uint16_t)(((c & 0xF) << 12) + ((utf8[1] & 0x3F) << 6) + (utf8[2] & 0x3F)); +- utf8 += 3; +- } +- // 21 bits +- else if (c < 0xF8) +- { +- int plane; +- // Four byte sequence. We need three follower bytes. +- if (endOfInput - utf8 < 3 || ((utf8[1] ^ 0x80) & 0xC0) || +- ((utf8[2] ^ 0x80) & 0xC0) || ((utf8[3] ^ 0x80) & 0xC0)) +- { +- return -1; +- } +- uint32_t unicode = ((c & 0x7) << 18) + ((utf8[1] & 0x3F) << 12) + +- ((utf8[2] & 0x3F) << 6) + (utf8[3] & 0x3F); +- utf8 += 4; +- CLog::Log(LOGERROR, "CWinEventsX11::Utf8ToUnicode: 4 byte unicode not supported"); +- } +- // 26 bits +- else if (c < 0xFC) +- { +- CLog::Log(LOGERROR, "CWinEventsX11::Utf8ToUnicode: 4 byte unicode not supported"); +- utf8 += 5; +- } +- // 31 bit +- else +- { +- CLog::Log(LOGERROR, "CWinEventsX11::Utf8ToUnicode: 4 byte unicode not supported"); +- utf8 += 6; +- } +- } +- return p - utf16; +-} +- + XBMCKey CWinEventsX11::LookupXbmcKeySym(KeySym keysym) + { + // try direct mapping first +diff --git a/xbmc/windowing/WinEventsX11.h b/xbmc/windowing/WinEventsX11.h +index 6100933..72955ad 100644 +--- a/xbmc/windowing/WinEventsX11.h ++++ b/xbmc/windowing/WinEventsX11.h +@@ -38,7 +38,6 @@ class CWinEventsX11 : public CWinEventsBase + static bool MessagePump(); + + protected: +- static int Utf8ToUnicode(const char *utf8, const int utf8Length, uint16_t *utf16, const int utf16MaxLength); + static XBMCKey LookupXbmcKeySym(KeySym keysym); + static bool ProcessKey(XBMC_Event &event, int repeatDelay); + static bool ProcessKeyRepeat(); +@@ -48,7 +47,6 @@ class CWinEventsX11 : public CWinEventsBase + Window m_window; + Atom m_wmDeleteMessage; + char *m_keybuf; +- uint16_t *m_utf16buf; + XIM m_xim; + XIC m_xic; + XBMC_Event m_lastKey; +-- +1.7.10 + + +From e060b3197bbac54b79b604bbbf9a8e86257980f5 Mon Sep 17 00:00:00 2001 +From: Joakim Plate +Date: Thu, 5 Jul 2012 14:23:54 +0200 +Subject: [PATCH 32/73] X11: fixed invalid usage of sizeof() (squash into x11 + changes) + +--- + xbmc/windowing/WinEventsX11.cpp | 11 +++++++---- + xbmc/windowing/WinEventsX11.h | 1 + + 2 files changed, 8 insertions(+), 4 deletions(-) + +diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp +index 76702e6..c31877e 100644 +--- a/xbmc/windowing/WinEventsX11.cpp ++++ b/xbmc/windowing/WinEventsX11.cpp +@@ -162,6 +162,7 @@ + m_display = 0; + m_window = 0; + m_keybuf = 0; ++ m_keybuf_len = 0; + } + + CWinEventsX11::~CWinEventsX11() +@@ -196,7 +197,8 @@ bool CWinEventsX11::Init(Display *dpy, Window win) + WinEvents = new CWinEventsX11(); + WinEvents->m_display = dpy; + WinEvents->m_window = win; +- WinEvents->m_keybuf = (char*)malloc(32*sizeof(char)); ++ WinEvents->m_keybuf_len = 32*sizeof(char); ++ WinEvents->m_keybuf = (char*)malloc(WinEvents->m_keybuf_len); + WinEvents->m_keymodState = 0; + WinEvents->m_wmDeleteMessage = XInternAtom(dpy, "WM_DELETE_WINDOW", False); + WinEvents->m_structureChanged = false; +@@ -428,13 +430,14 @@ bool CWinEventsX11::MessagePump() + Status status; + int len; + len = Xutf8LookupString(WinEvents->m_xic, &xevent.xkey, +- WinEvents->m_keybuf, sizeof(WinEvents->m_keybuf), ++ WinEvents->m_keybuf, WinEvents->m_keybuf_len, + &xkeysym, &status); + if (status == XBufferOverflow) + { +- WinEvents->m_keybuf = (char*)realloc(WinEvents->m_keybuf, len*sizeof(char)); ++ WinEvents->m_keybuf_len = len; ++ WinEvents->m_keybuf = (char*)realloc(WinEvents->m_keybuf, WinEvents->m_keybuf_len); + len = Xutf8LookupString(WinEvents->m_xic, &xevent.xkey, +- WinEvents->m_keybuf, sizeof(WinEvents->m_keybuf), ++ WinEvents->m_keybuf, WinEvents->m_keybuf_len, + &xkeysym, &status); + } + switch (status) +diff --git a/xbmc/windowing/WinEventsX11.h b/xbmc/windowing/WinEventsX11.h +index 72955ad..102a076 100644 +--- a/xbmc/windowing/WinEventsX11.h ++++ b/xbmc/windowing/WinEventsX11.h +@@ -47,6 +47,7 @@ class CWinEventsX11 : public CWinEventsBase + Window m_window; + Atom m_wmDeleteMessage; + char *m_keybuf; ++ size_t m_keybuf_len; + XIM m_xim; + XIC m_xic; + XBMC_Event m_lastKey; +-- +1.7.10 + + +From c52af3ba68292f08331cbbbc940dfcea838a2f44 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sat, 9 Jun 2012 18:23:53 +0200 +Subject: [PATCH 33/73] add missing keys to xbmc keytable + +--- + xbmc/input/XBMC_keytable.cpp | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/xbmc/input/XBMC_keytable.cpp b/xbmc/input/XBMC_keytable.cpp +index aaf65ba..9d7922f 100644 +--- a/xbmc/input/XBMC_keytable.cpp ++++ b/xbmc/input/XBMC_keytable.cpp +@@ -179,6 +179,8 @@ + , { XBMCK_LAUNCH_APP2, 0, 0, XBMCVK_LAUNCH_APP2, "launch_app2_pc_icon" } + , { XBMCK_LAUNCH_FILE_BROWSER, 0, 0, XBMCVK_LAUNCH_FILE_BROWSER, "launch_file_browser" } + , { XBMCK_LAUNCH_MEDIA_CENTER, 0, 0, XBMCVK_LAUNCH_MEDIA_CENTER, "launch_media_center" } ++, { XBMCK_PLAY, 0, 0, XBMCVK_MEDIA_PLAY_PAUSE, "play_pause" } ++, { XBMCK_STOP, 0, 0, XBMCVK_MEDIA_STOP, "stop" } + + // Function keys + , { XBMCK_F1, 0, 0, XBMCVK_F1, "f1"} +-- +1.7.10 + + +From 25587ee807eca2fc9dde4528e3fc930b337e38b0 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Fri, 16 Mar 2012 15:57:51 +0100 +Subject: [PATCH 34/73] videorefclock: temp deactivate of nv settings + +--- + xbmc/video/VideoReferenceClock.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/xbmc/video/VideoReferenceClock.cpp b/xbmc/video/VideoReferenceClock.cpp +index fa8e35a..85e36c7 100644 +--- a/xbmc/video/VideoReferenceClock.cpp ++++ b/xbmc/video/VideoReferenceClock.cpp +@@ -135,7 +135,7 @@ + m_Context = NULL; + m_pixmap = None; + m_glPixmap = None; +- m_UseNvSettings = true; ++ m_UseNvSettings = false; + m_bIsATI = false; + #endif + } +-- +1.7.10 + + +From 4f8a95de09408321e2df3da891536c314fe3b4d2 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 20 Aug 2012 09:09:09 +0200 +Subject: [PATCH 35/73] videorefclock: ask graphics context for refresh rate + +--- + xbmc/video/VideoReferenceClock.cpp | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/xbmc/video/VideoReferenceClock.cpp b/xbmc/video/VideoReferenceClock.cpp +index 85e36c7..8209163 100644 +--- a/xbmc/video/VideoReferenceClock.cpp ++++ b/xbmc/video/VideoReferenceClock.cpp +@@ -30,6 +30,7 @@ + #include + #include + #include "windowing/WindowingFactory.h" ++ #include "guilib/GraphicContext.h" + #define NVSETTINGSCMD "nvidia-settings -nt -q RefreshRate3" + #elif defined(TARGET_DARWIN_OSX) + #include +@@ -1254,7 +1255,7 @@ bool CVideoReferenceClock::UpdateRefreshrate(bool Forced /*= false*/) + } + + CSingleLock SingleLock(m_CritSection); +- m_RefreshRate = GetRandRRate(); ++ m_RefreshRate = MathUtils::round_int(g_graphicsContext.GetFPS()); + + CLog::Log(LOGDEBUG, "CVideoReferenceClock: Detected refreshrate: %i hertz", (int)m_RefreshRate); + +-- +1.7.10 + + +From 85d81f0c933cb0a75c2c21de86b4065e3db86002 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 9 Jul 2012 14:00:18 +0200 +Subject: [PATCH 36/73] X11: fix icon texture after + cc5ed3c2474084ebc0373a3046410e6f766e03f4 + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 43 +++++++++++++++++++++-------------- + 1 file changed, 26 insertions(+), 17 deletions(-) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index 91f92c1..174ccef 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -874,22 +874,24 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd + if (!fullscreen) + { + CreateIconPixmap(); +- XWMHints wm_hints; +- XClassHint class_hints; ++ XWMHints *wm_hints; + XTextProperty windowName, iconName; + std::string titleString = "XBMC Media Center"; + char *title = (char*)titleString.c_str(); + + XStringListToTextProperty(&title, 1, &windowName); + XStringListToTextProperty(&title, 1, &iconName); +- wm_hints.initial_state = NormalState; +- wm_hints.input = True; +- wm_hints.icon_pixmap = m_icon; +- wm_hints.flags = StateHint | IconPixmapHint | InputHint; + ++ wm_hints = XAllocWMHints(); ++ wm_hints->initial_state = NormalState; ++ wm_hints->icon_pixmap = m_icon; ++ wm_hints->flags = StateHint | IconPixmapHint; ++ ++ XSync(m_dpy,False); + XSetWMProperties(m_dpy, m_glWindow, &windowName, &iconName, +- NULL, 0, NULL, &wm_hints, ++ NULL, 0, NULL, wm_hints, + NULL); ++ XFree(wm_hints); + + // register interest in the delete window message + Atom wmDeleteMessage = XInternAtom(m_dpy, "WM_DELETE_WINDOW", False); +@@ -974,16 +976,21 @@ bool CWinSystemX11::CreateIconPixmap() + gRatio = vis->green_mask / 255.0; + bRatio = vis->blue_mask / 255.0; + +- CTexture iconTexture; +- iconTexture.LoadFromFile("special://xbmc/media/icon.png"); +- buf = iconTexture.GetPixels(); ++ CBaseTexture *iconTexture = CBaseTexture::LoadFromFile("special://xbmc/media/icon.png"); ++ ++ if (!iconTexture) ++ return false; + +- numBufBytes = iconTexture.GetWidth() * iconTexture.GetHeight() * 4; ++ buf = iconTexture->GetPixels(); ++ ++ numBufBytes = iconTexture->GetWidth() * iconTexture->GetHeight() * 4; ++ int wid = iconTexture->GetWidth(); ++ int hi = iconTexture->GetHeight(); + + if (depth>=24) +- numNewBufBytes = (4 * (iconTexture.GetWidth() * iconTexture.GetHeight())); ++ numNewBufBytes = (4 * (iconTexture->GetWidth() * iconTexture->GetHeight())); + else +- numNewBufBytes = (2 * (iconTexture.GetWidth() * iconTexture.GetHeight())); ++ numNewBufBytes = (2 * (iconTexture->GetWidth() * iconTexture->GetHeight())); + + newBuf = (uint32_t*)malloc(numNewBufBytes); + if (!newBuf) +@@ -992,11 +999,11 @@ bool CWinSystemX11::CreateIconPixmap() + return false; + } + +- for (i=0; iGetHeight();++i) + { +- for (j=0; jGetWidth();++j) + { +- unsigned int pos = i*iconTexture.GetPitch()+j*4; ++ unsigned int pos = i*iconTexture->GetPitch()+j*4; + unsigned int r, g, b; + r = (buf[pos+2] * rRatio); + g = (buf[pos+1] * gRatio); +@@ -1009,7 +1016,7 @@ bool CWinSystemX11::CreateIconPixmap() + } + } + img = XCreateImage(m_dpy, vis, depth,ZPixmap, 0, (char *)newBuf, +- iconTexture.GetWidth(), iconTexture.GetHeight(), ++ iconTexture->GetWidth(), iconTexture->GetHeight(), + (depth>=24)?32:16, 0); + if (!img) + { +@@ -1047,6 +1054,8 @@ bool CWinSystemX11::CreateIconPixmap() + XFreeGC(m_dpy, gc); + XDestroyImage(img); // this also frees newBuf + ++ delete iconTexture; ++ + return true; + } + +-- +1.7.10 + + +From 111c2f8fd0f6b698fbff0fda6dc6c17ce3644626 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Tue, 10 Jul 2012 11:14:12 +0200 +Subject: [PATCH 37/73] X11: check for window manager + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 74 ++++++++++++++++++++++++++++++++++- + xbmc/windowing/X11/WinSystemX11.h | 1 + + 2 files changed, 73 insertions(+), 2 deletions(-) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index 174ccef..4f1ae26 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -816,8 +816,10 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd + vi = glXChooseVisual(m_dpy, m_nScreen, att); + cmap = XCreateColormap(m_dpy, RootWindow(m_dpy, vi->screen), vi->visual, AllocNone); + ++ bool hasWM = HasWindowManager(); ++ + int def_vis = (vi->visual == DefaultVisual(m_dpy, vi->screen)); +- swa.override_redirect = False; ++ swa.override_redirect = hasWM ? False : True; + swa.border_pixel = fullscreen ? 0 : 5; + swa.background_pixel = def_vis ? BlackPixel(m_dpy, vi->screen) : 0; + swa.colormap = cmap; +@@ -833,7 +835,7 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd + InputOutput, vi->visual, + mask, &swa); + +- if (fullscreen) ++ if (fullscreen && hasWM) + { + Atom fs = XInternAtom(m_dpy, "_NET_WM_STATE_FULLSCREEN", True); + XChangeProperty(m_dpy, m_glWindow, XInternAtom(m_dpy, "_NET_WM_STATE", True), XA_ATOM, 32, PropModeReplace, (unsigned char *) &fs, 1); +@@ -1059,4 +1061,72 @@ bool CWinSystemX11::CreateIconPixmap() + return true; + } + ++bool CWinSystemX11::HasWindowManager() ++{ ++ Window wm_check; ++ unsigned char *data; ++ int status, real_format; ++ Atom real_type, prop; ++ unsigned long items_read, items_left, i; ++ char req = 0; ++ ++ prop = XInternAtom(m_dpy, "_NET_SUPPORTING_WM_CHECK", True); ++ if (prop == None) ++ return false; ++ status = XGetWindowProperty(m_dpy, DefaultRootWindow(m_dpy), prop, ++ 0L, 1L, False, XA_WINDOW, &real_type, &real_format, ++ &items_read, &items_left, &data); ++ if(status != Success || ! items_read) ++ { ++ if(status == Success) ++ XFree(data); ++ return false; ++ } ++ ++ wm_check = ((Window*)data)[0]; ++ XFree(data); ++ ++ status = XGetWindowProperty(m_dpy, wm_check, prop, ++ 0L, 1L, False, XA_WINDOW, &real_type, &real_format, ++ &items_read, &items_left, &data); ++ ++ if(status != Success || !items_read) ++ { ++ if(status == Success) ++ XFree(data); ++ return false; ++ } ++ ++ if(wm_check != ((Window*)data)[0]) ++ { ++ XFree(data); ++ return false; ++ } ++ ++ XFree(data); ++ ++ prop = XInternAtom(m_dpy, "_NET_WM_NAME", True); ++ if (prop == None) ++ { ++ CLog::Log(LOGDEBUG,"Window Manager Name: "); ++ return true; ++ } ++ ++ status = XGetWindowProperty(m_dpy, wm_check, prop, ++ 0L, (~0L), False, AnyPropertyType, &real_type, &real_format, ++ &items_read, &items_left, &data); ++ ++ if(status == Success && items_read) ++ { ++ CLog::Log(LOGDEBUG,"Window Manager Name: %s", data); ++ } ++ else ++ CLog::Log(LOGDEBUG,"Window Manager Name: "); ++ ++ if(status == Success) ++ XFree(data); ++ ++ return true; ++} ++ + #endif +diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h +index e953d2d..0b7c10a 100644 +--- a/xbmc/windowing/X11/WinSystemX11.h ++++ b/xbmc/windowing/X11/WinSystemX11.h +@@ -101,6 +101,7 @@ class CWinSystemX11 : public CWinSystemBase + bool IsSuitableVisual(XVisualInfo *vInfo); + static int XErrorHandler(Display* dpy, XErrorEvent* error); + bool CreateIconPixmap(); ++ bool HasWindowManager(); + + CStopWatch m_screensaverReset; + }; +-- +1.7.10 + + +From f1051e1991e5ef5d83ce428b841ac365082042ec Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 12 Jul 2012 11:11:47 +0200 +Subject: [PATCH 38/73] X11: dont set window on xrandr if no mode available + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index 4f1ae26..c11ea89 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -665,16 +665,17 @@ void CWinSystemX11::NotifyXRREvent() + CLog::Log(LOGDEBUG, "%s - notify display reset event", __FUNCTION__); + m_windowDirty = true; + ++ if (!g_xrandr.Query(true)) ++ { ++ CLog::Log(LOGERROR, "WinSystemX11::RefreshWindow - failed to query xrandr"); ++ return; ++ } ++ + // if external event update resolutions + if (!m_bIsInternalXrr) + { + UpdateResolutions(); + } +- else if (!g_xrandr.Query(true)) +- { +- CLog::Log(LOGERROR, "WinSystemX11::RefreshWindow - failed to query xrandr"); +- return; +- } + m_bIsInternalXrr = false; + + CStdString currentOutput = g_guiSettings.GetString("videoscreen.monitor"); +-- +1.7.10 + + +From 83b9c33e88077d957884ee22316c218e570dc3d5 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 26 Jul 2012 09:34:28 +0200 +Subject: [PATCH 39/73] X11: fix crash after a resolution change on startup + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index c11ea89..0bd72d4 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -219,7 +219,8 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl + OnLostDevice(); + m_bIsInternalXrr = true; + g_xrandr.SetMode(out, mode); +- return true; ++ if (m_glWindow) ++ return true; + } + #endif + +-- +1.7.10 + + +From b8956ed57f1b683ae79d7306c7461a31c894e9a9 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sat, 15 Sep 2012 18:27:29 +0200 +Subject: [PATCH 40/73] X11: lock graphics context in NotifyXRREvent + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index 0bd72d4..ef83133 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -666,6 +666,8 @@ void CWinSystemX11::NotifyXRREvent() + CLog::Log(LOGDEBUG, "%s - notify display reset event", __FUNCTION__); + m_windowDirty = true; + ++ CSingleLock lock(g_graphicsContext); ++ + if (!g_xrandr.Query(true)) + { + CLog::Log(LOGERROR, "WinSystemX11::RefreshWindow - failed to query xrandr"); +-- +1.7.10 + + +From aed5d244b81b1a0b171b7fea3b332decafc96c56 Mon Sep 17 00:00:00 2001 +From: Rainer Hochecker +Date: Sat, 8 Oct 2011 16:45:13 +0200 +Subject: [PATCH 41/73] ffmpeg: add xvba hwaccel + +--- + lib/ffmpeg/configure | 8 ++ + lib/ffmpeg/libavcodec/Makefile | 7 +- + lib/ffmpeg/libavcodec/allcodecs.c | 4 + + lib/ffmpeg/libavcodec/h264.c | 1 + + lib/ffmpeg/libavcodec/mpegvideo.c | 1 + + lib/ffmpeg/libavcodec/xvba.c | 66 ++++++++++++ + lib/ffmpeg/libavcodec/xvba.h | 71 ++++++++++++ + lib/ffmpeg/libavcodec/xvba_h264.c | 189 ++++++++++++++++++++++++++++++++ + lib/ffmpeg/libavcodec/xvba_internal.h | 24 +++++ + lib/ffmpeg/libavcodec/xvba_mpeg2.c | 52 +++++++++ + lib/ffmpeg/libavcodec/xvba_vc1.c | 190 +++++++++++++++++++++++++++++++++ + lib/ffmpeg/libavcodec/xvmc_internal.h | 4 +- + lib/ffmpeg/libavutil/pixdesc.c | 6 ++ + lib/ffmpeg/libavutil/pixfmt.h | 1 + + 14 files changed, 622 insertions(+), 2 deletions(-) + create mode 100644 lib/ffmpeg/libavcodec/xvba.c + create mode 100644 lib/ffmpeg/libavcodec/xvba.h + create mode 100644 lib/ffmpeg/libavcodec/xvba_h264.c + create mode 100644 lib/ffmpeg/libavcodec/xvba_internal.h + create mode 100644 lib/ffmpeg/libavcodec/xvba_mpeg2.c + create mode 100644 lib/ffmpeg/libavcodec/xvba_vc1.c + +diff --git a/lib/ffmpeg/configure b/lib/ffmpeg/configure +index c06005b..157cfd3 100755 +--- a/lib/ffmpeg/configure ++++ b/lib/ffmpeg/configure +@@ -113,6 +113,7 @@ Configuration options: + --enable-vdpau enable VDPAU code [autodetect] + --disable-dxva2 disable DXVA2 code + --disable-vda disable VDA code ++ --disable-xvba disable XVBA code + --enable-runtime-cpudetect detect cpu capabilities at runtime (bigger binary) + --enable-hardcoded-tables use hardcoded tables instead of runtime generation + --disable-safe-bitstream-reader +@@ -1084,6 +1085,7 @@ CONFIG_LIST=" + vaapi + vda + vdpau ++ xvba + version3 + x11grab + zlib +@@ -1423,6 +1425,7 @@ h264_dxva2_hwaccel_select="dxva2 h264_decoder" + h264_vaapi_hwaccel_select="vaapi h264_decoder" + h264_vda_hwaccel_deps="VideoDecodeAcceleration_VDADecoder_h pthreads" + h264_vda_hwaccel_select="vda h264_decoder" ++h264_xvba_hwaccel_select="xvba h264_decoder" + h264_vdpau_decoder_select="vdpau h264_decoder" + imc_decoder_select="fft mdct sinewin" + jpegls_decoder_select="golomb" +@@ -1459,6 +1462,7 @@ mpeg4_crystalhd_decoder_select="crystalhd" + mpeg4_decoder_select="h263_decoder mpeg4video_parser" + mpeg4_encoder_select="h263_encoder" + mpeg4_vaapi_hwaccel_select="vaapi mpeg4_decoder" ++mpeg2_xvba_hwaccel_select="xvba mpeg2video_decoder" + mpeg4_vdpau_decoder_select="vdpau mpeg4_decoder" + msmpeg4_crystalhd_decoder_select="crystalhd" + msmpeg4v1_decoder_select="h263_decoder" +@@ -1501,6 +1505,7 @@ vc1_decoder_select="h263_decoder h264chroma" + vc1_dxva2_hwaccel_deps="dxva2api_h" + vc1_dxva2_hwaccel_select="dxva2 vc1_decoder" + vc1_vaapi_hwaccel_select="vaapi vc1_decoder" ++vc1_xvba_hwaccel_select="xvba vc1_decoder" + vc1_vdpau_decoder_select="vdpau vc1_decoder" + vc1image_decoder_select="vc1_decoder" + vorbis_decoder_select="mdct" +@@ -1525,6 +1530,7 @@ wmv3_dxva2_hwaccel_select="vc1_dxva2_hwaccel" + wmv3_vaapi_hwaccel_select="vc1_vaapi_hwaccel" + wmv3_vdpau_decoder_select="vc1_vdpau_decoder" + wmv3image_decoder_select="wmv3_decoder" ++wmv3_xvba_hwaccel_select="vc1_xvba_hwaccel" + zlib_decoder_select="zlib" + zlib_encoder_select="zlib" + zmbv_decoder_select="zlib" +@@ -1533,6 +1539,7 @@ zmbv_encoder_select="zlib" + crystalhd_deps="libcrystalhd_libcrystalhd_if_h" + vaapi_deps="va_va_h" + vda_deps="VideoDecodeAcceleration_VDADecoder_h pthreads" ++xvba_deps="amd_amdxvba_h" + vdpau_deps="vdpau_vdpau_h vdpau_vdpau_x11_h" + + # parsers +@@ -3062,6 +3069,7 @@ check_header sys/select.h + check_header termios.h + check_header vdpau/vdpau.h + check_header vdpau/vdpau_x11.h ++check_header amd/amdxvba.h + check_cpp_condition vdpau/vdpau.h "defined(VDP_DECODER_PROFILE_MPEG4_PART2_SP)" && enable vdpau_mpeg4_support + + check_header X11/extensions/XvMClib.h +diff --git a/lib/ffmpeg/libavcodec/Makefile b/lib/ffmpeg/libavcodec/Makefile +index 972cc59..fc441bf 100644 +--- a/lib/ffmpeg/libavcodec/Makefile ++++ b/lib/ffmpeg/libavcodec/Makefile +@@ -3,7 +3,7 @@ include $(SUBDIR)../config.mak + NAME = avcodec + FFLIBS = avutil + +-HEADERS = avcodec.h avfft.h dxva2.h opt.h vaapi.h vda.h vdpau.h version.h xvmc.h ++HEADERS = avcodec.h avfft.h dxva2.h opt.h vaapi.h vda.h vdpau.h version.h xvmc.h xvba.h + + OBJS = allcodecs.o \ + audioconvert.o \ +@@ -51,6 +51,7 @@ OBJS-$(CONFIG_SINEWIN) += sinewin.o + OBJS-$(CONFIG_VAAPI) += vaapi.o + OBJS-$(CONFIG_VDA) += vda.o + OBJS-$(CONFIG_VDPAU) += vdpau.o ++OBJS-$(CONFIG_XVBA) += xvba.o + + # decoders/encoders/hardware accelerators + OBJS-$(CONFIG_A64MULTI_ENCODER) += a64multienc.o elbg.o +@@ -201,6 +202,7 @@ OBJS-$(CONFIG_H264_DECODER) += h264.o \ + OBJS-$(CONFIG_H264_DXVA2_HWACCEL) += dxva2_h264.o + OBJS-$(CONFIG_H264_VAAPI_HWACCEL) += vaapi_h264.o + OBJS-$(CONFIG_H264_VDA_HWACCEL) += vda_h264.o ++OBJS-$(CONFIG_H264_XVBA_HWACCEL) += xvba_h264.o + OBJS-$(CONFIG_HUFFYUV_DECODER) += huffyuv.o + OBJS-$(CONFIG_HUFFYUV_ENCODER) += huffyuv.o + OBJS-$(CONFIG_IDCIN_DECODER) += idcinvideo.o +@@ -284,6 +286,7 @@ OBJS-$(CONFIG_MPEG1VIDEO_ENCODER) += mpeg12enc.o mpegvideo_enc.o \ + mpegvideo.o error_resilience.o + OBJS-$(CONFIG_MPEG2_DXVA2_HWACCEL) += dxva2_mpeg2.o + OBJS-$(CONFIG_MPEG2_VAAPI_HWACCEL) += vaapi_mpeg2.o ++OBJS-$(CONFIG_MPEG2_XVBA_HWACCEL) += xvba_mpeg2.o + OBJS-$(CONFIG_MPEG2VIDEO_DECODER) += mpeg12.o mpeg12data.o \ + mpegvideo.o error_resilience.o + OBJS-$(CONFIG_MPEG2VIDEO_ENCODER) += mpeg12enc.o mpegvideo_enc.o \ +@@ -431,6 +434,7 @@ OBJS-$(CONFIG_VC1_DECODER) += vc1dec.o vc1.o vc1data.o vc1dsp.o \ + intrax8.o intrax8dsp.o + OBJS-$(CONFIG_VC1_DXVA2_HWACCEL) += dxva2_vc1.o + OBJS-$(CONFIG_VC1_VAAPI_HWACCEL) += vaapi_vc1.o ++OBJS-$(CONFIG_VC1_XVBA_HWACCEL) += xvba_vc1.o + OBJS-$(CONFIG_VCR1_DECODER) += vcr1.o + OBJS-$(CONFIG_VCR1_ENCODER) += vcr1.o + OBJS-$(CONFIG_VMDAUDIO_DECODER) += vmdav.o +@@ -732,6 +736,7 @@ SKIPHEADERS-$(CONFIG_LIBDIRAC) += libdirac.h + SKIPHEADERS-$(CONFIG_LIBSCHROEDINGER) += libschroedinger.h + SKIPHEADERS-$(CONFIG_VAAPI) += vaapi_internal.h + SKIPHEADERS-$(CONFIG_VDA) += vda_internal.h ++SKIPHEADERS-$(CONFIG_XVBA) += xvba_internal.h + SKIPHEADERS-$(CONFIG_VDPAU) += vdpau.h + SKIPHEADERS-$(CONFIG_XVMC) += xvmc.h + SKIPHEADERS-$(HAVE_W32THREADS) += w32pthreads.h +diff --git a/lib/ffmpeg/libavcodec/allcodecs.c b/lib/ffmpeg/libavcodec/allcodecs.c +index 32f3f52..0ff178e 100644 +--- a/lib/ffmpeg/libavcodec/allcodecs.c ++++ b/lib/ffmpeg/libavcodec/allcodecs.c +@@ -59,14 +59,18 @@ void avcodec_register_all(void) + REGISTER_HWACCEL (H264_VAAPI, h264_vaapi); + REGISTER_HWACCEL (H264_VDA, h264_vda); + REGISTER_HWACCEL (MPEG1_VDPAU, mpeg1_vdpau); ++ REGISTER_HWACCEL (H264_XVBA, h264_xvba); + REGISTER_HWACCEL (MPEG2_DXVA2, mpeg2_dxva2); + REGISTER_HWACCEL (MPEG2_VAAPI, mpeg2_vaapi); + REGISTER_HWACCEL (MPEG2_VDPAU, mpeg2_vdpau); + REGISTER_HWACCEL (MPEG4_VAAPI, mpeg4_vaapi); ++ REGISTER_HWACCEL (MPEG2_XVBA, mpeg2_xvba); + REGISTER_HWACCEL (VC1_DXVA2, vc1_dxva2); + REGISTER_HWACCEL (VC1_VAAPI, vc1_vaapi); ++ REGISTER_HWACCEL (VC1_XVBA, vc1_xvba); + REGISTER_HWACCEL (WMV3_DXVA2, wmv3_dxva2); + REGISTER_HWACCEL (WMV3_VAAPI, wmv3_vaapi); ++ REGISTER_HWACCEL (WMV3_XVBA, wmv3_xvba); + + /* video codecs */ + REGISTER_ENCODER (A64MULTI, a64multi); +diff --git a/lib/ffmpeg/libavcodec/h264.c b/lib/ffmpeg/libavcodec/h264.c +index c4785db..e9e7546 100644 +--- a/lib/ffmpeg/libavcodec/h264.c ++++ b/lib/ffmpeg/libavcodec/h264.c +@@ -60,6 +60,7 @@ + PIX_FMT_DXVA2_VLD, + PIX_FMT_VAAPI_VLD, + PIX_FMT_VDA_VLD, ++ PIX_FMT_XVBA_VLD, + PIX_FMT_YUVJ420P, + PIX_FMT_NONE + }; +diff --git a/lib/ffmpeg/libavcodec/mpegvideo.c b/lib/ffmpeg/libavcodec/mpegvideo.c +index 04c149a..b22b631 100644 +--- a/lib/ffmpeg/libavcodec/mpegvideo.c ++++ b/lib/ffmpeg/libavcodec/mpegvideo.c +@@ -136,6 +136,7 @@ static void dct_unquantize_h263_inter_c(MpegEncContext *s, + PIX_FMT_DXVA2_VLD, + PIX_FMT_VAAPI_VLD, + PIX_FMT_VDA_VLD, ++ PIX_FMT_XVBA_VLD, + PIX_FMT_YUV420P, + PIX_FMT_NONE + }; +diff --git a/lib/ffmpeg/libavcodec/xvba.c b/lib/ffmpeg/libavcodec/xvba.c +new file mode 100644 +index 0000000..be29e5d +--- /dev/null ++++ b/lib/ffmpeg/libavcodec/xvba.c +@@ -0,0 +1,66 @@ ++/* ++ * HW decode acceleration for MPEG-2, H.264 and VC-1 ++ * ++ * Copyright (C) 2005-2011 Team XBMC ++ * ++ * This file is part of FFmpeg. ++ * ++ * FFmpeg is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * FFmpeg is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with FFmpeg; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++ ++/** ++ * \addtogroup XVBA_Decoding ++ * ++ * @{ ++ */ ++ ++#include ++#include "xvba.h" ++#include "xvba_internal.h" ++#include "avcodec.h" ++ ++int ff_xvba_translate_profile(int profile) { ++ ++ if (profile == 66) ++ return 1; ++ else if (profile == 77) ++ return 2; ++ else if (profile == 100) ++ return 3; ++ else if (profile == 0) ++ return 4; ++ else if (profile == 1) ++ return 5; ++ else if (profile == 3) ++ return 6; ++ else ++ return -1; ++} ++ ++void ff_xvba_add_slice_data(struct xvba_render_state *render, const uint8_t *buffer, uint32_t size) { ++ ++ render->buffers = av_fast_realloc( ++ render->buffers, ++ &render->buffers_alllocated, ++ sizeof(struct xvba_bitstream_buffers)*(render->num_slices + 1) ++ ); ++ ++ render->buffers[render->num_slices].buffer = buffer; ++ render->buffers[render->num_slices].size = size; ++ ++ render->num_slices++; ++} ++ +diff --git a/lib/ffmpeg/libavcodec/xvba.h b/lib/ffmpeg/libavcodec/xvba.h +new file mode 100644 +index 0000000..9f9ff0c +--- /dev/null ++++ b/lib/ffmpeg/libavcodec/xvba.h +@@ -0,0 +1,71 @@ ++/* ++ * HW decode acceleration for MPEG-2, H.264 and VC-1 ++ * ++ * Copyright (C) 2005-2011 Team XBMC ++ * ++ * This file is part of FFmpeg. ++ * ++ * FFmpeg is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * FFmpeg is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with FFmpeg; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++#ifndef AVCODEC_XVBA_H ++#define AVCODEC_XVBA_H ++ ++#include ++#include ++#include ++ ++ ++/** ++ * \defgroup XVBA_Decoding VA API Decoding ++ * \ingroup Decoder ++ * @{ ++ */ ++ ++/** \brief The videoSurface is used for rendering. */ ++#define FF_XVBA_STATE_USED_FOR_RENDER 1 ++ ++/** ++ * \brief The videoSurface is needed for reference/prediction. ++ * The codec manipulates this. ++ */ ++#define FF_XVBA_STATE_USED_FOR_REFERENCE 2 ++ ++/** ++ * \brief The videoSurface holds a decoded frame. ++ * The codec manipulates this. ++ */ ++#define FF_XVBA_STATE_DECODED 4 ++ ++/* @} */ ++ ++struct xvba_bitstream_buffers ++{ ++ const void *buffer; ++ unsigned int size; ++}; ++ ++struct xvba_render_state { ++ ++ int state; ///< Holds FF_XVBA_STATE_* values. ++ void *surface; ++ XVBAPictureDescriptor *picture_descriptor; ++ XVBAQuantMatrixAvc *iq_matrix; ++ unsigned int num_slices; ++ struct xvba_bitstream_buffers *buffers; ++ uint32_t buffers_alllocated; ++}; ++ ++#endif /* AVCODEC_XVBA_H */ +diff --git a/lib/ffmpeg/libavcodec/xvba_h264.c b/lib/ffmpeg/libavcodec/xvba_h264.c +new file mode 100644 +index 0000000..a077442 +--- /dev/null ++++ b/lib/ffmpeg/libavcodec/xvba_h264.c +@@ -0,0 +1,189 @@ ++/* ++ * H.264 HW decode acceleration through XVBA ++ * ++ * Copyright (C) 2005-2011 Team XBMC ++ * ++ * This file is part of FFmpeg. ++ * ++ * FFmpeg is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * FFmpeg is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with FFmpeg; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++#include "xvba.h" ++#include "xvba_internal.h" ++#include "h264.h" ++#include ++ ++/** @file ++ * This file implements the glue code between FFmpeg's and XvBA API's ++ * structures for H.264 decoding. ++ */ ++ ++ ++/** Initialize and start decoding a frame with XVBA. */ ++static int start_frame(AVCodecContext *avctx, ++ av_unused const uint8_t *buffer, ++ av_unused uint32_t size) ++{ ++ H264Context * const h = avctx->priv_data; ++ MpegEncContext * const s = &h->s; ++ struct xvba_render_state *render; ++ XVBAPictureDescriptor *pic_descriptor; ++ int i; ++ ++ render = (struct xvba_render_state *)s->current_picture_ptr->f.data[0]; ++ assert(render); ++ ++ if (render->picture_descriptor == 0) ++ return -1; ++ ++ pic_descriptor = render->picture_descriptor; ++ ++ for (i = 0; i < 2; ++i) { ++ int foc = s->current_picture_ptr->field_poc[i]; ++ if (foc == INT_MAX) ++ foc = 0; ++ pic_descriptor->avc_curr_field_order_cnt_list[i] = foc; ++ } ++ ++ pic_descriptor->avc_frame_num = h->frame_num; ++ ++ render->num_slices = 0; ++ ++ return 0; ++} ++ ++/** End a hardware decoding based frame. */ ++static int end_frame(AVCodecContext *avctx) ++{ ++ H264Context * const h = avctx->priv_data; ++ MpegEncContext * const s = &h->s; ++ struct xvba_render_state *render; ++ XVBAPictureDescriptor *pic_descriptor; ++ XVBAQuantMatrixAvc *iq_matrix; ++ ++ render = (struct xvba_render_state *)s->current_picture_ptr->f.data[0]; ++ assert(render); ++ ++ if (render->picture_descriptor == 0 || render->iq_matrix == 0) ++ return -1; ++ ++ pic_descriptor = render->picture_descriptor; ++ iq_matrix = render->iq_matrix; ++ ++ av_dlog(avctx, "end_frame()\n"); ++ ++ /* Fill in Picture Parameters*/ ++ pic_descriptor->profile = ff_xvba_translate_profile(avctx->profile); ++ pic_descriptor->level = avctx->level; ++ pic_descriptor->width_in_mb = s->mb_width; ++ pic_descriptor->height_in_mb = s->mb_height; ++ pic_descriptor->picture_structure = s->picture_structure; ++ pic_descriptor->chroma_format = s->chroma_format ? s->chroma_format : 1; ++ pic_descriptor->avc_intra_flag = (h->slice_type == AV_PICTURE_TYPE_I) ? 1 : 0; ++ pic_descriptor->avc_reference = (s->current_picture_ptr->f.reference & 3) ? 1 : 0; ++ ++ pic_descriptor->avc_bit_depth_luma_minus8 = h->sps.bit_depth_luma - 8; ++ pic_descriptor->avc_bit_depth_chroma_minus8 = h->sps.bit_depth_chroma - 8; ++ pic_descriptor->avc_log2_max_frame_num_minus4 = h->sps.log2_max_frame_num -4; ++ pic_descriptor->avc_pic_order_cnt_type = h->sps.poc_type; ++ pic_descriptor->avc_log2_max_pic_order_cnt_lsb_minus4 = h->sps.log2_max_poc_lsb - 4; ++ pic_descriptor->avc_num_ref_frames = h->sps.ref_frame_count; ++ pic_descriptor->avc_reserved_8bit = 0; ++ ++ /* Set correct level */ ++ if (pic_descriptor->level == 41) { ++ const unsigned int mbw = pic_descriptor->width_in_mb; ++ const unsigned int mbh = pic_descriptor->height_in_mb; ++ const unsigned int max_ref_frames = 12288 * 1024 / (mbw * mbh * 384); ++ const unsigned int num_ref_frames = pic_descriptor->avc_num_ref_frames; ++ if (max_ref_frames < num_ref_frames) ++ pic_descriptor->level = 51; ++ } ++ ++ pic_descriptor->avc_num_slice_groups_minus1 = h->pps.slice_group_count - 1; ++ pic_descriptor->avc_num_ref_idx_l0_active_minus1 = h->pps.ref_count[0] - 1; ++ pic_descriptor->avc_num_ref_idx_l1_active_minus1 = h->pps.ref_count[1] - 1; ++ ++ pic_descriptor->avc_pic_init_qp_minus26 = h->pps.init_qp - 26; ++ pic_descriptor->avc_pic_init_qs_minus26 = h->pps.init_qs - 26; ++ pic_descriptor->avc_chroma_qp_index_offset = h->pps.chroma_qp_index_offset[0]; ++ pic_descriptor->avc_second_chroma_qp_index_offset = h->pps.chroma_qp_index_offset[1]; ++ pic_descriptor->avc_slice_group_change_rate_minus1 = 0; // not implemented in ffmpeg ++ pic_descriptor->avc_reserved_16bit = 0; // must be 0 ++ memset(pic_descriptor->avc_field_order_cnt_list,0,sizeof(pic_descriptor->avc_field_order_cnt_list)); // must be 0 ++ memset(pic_descriptor->avc_slice_group_map,0,sizeof(pic_descriptor->avc_slice_group_map)); // must be 0 ++ ++ // sps ++ pic_descriptor->sps_info.avc.delta_pic_always_zero_flag = h->sps.delta_pic_order_always_zero_flag; ++ pic_descriptor->sps_info.avc.direct_8x8_inference_flag = h->sps.direct_8x8_inference_flag; ++ pic_descriptor->sps_info.avc.frame_mbs_only_flag = h->sps.frame_mbs_only_flag; ++ pic_descriptor->sps_info.avc.gaps_in_frame_num_value_allowed_flag = h->sps.gaps_in_frame_num_allowed_flag; ++ pic_descriptor->sps_info.avc.mb_adaptive_frame_field_flag = h->sps.mb_aff; ++ pic_descriptor->sps_info.avc.residual_colour_transform_flag = h->sps.residual_color_transform_flag; ++ pic_descriptor->sps_info.avc.xvba_avc_sps_reserved = 0; ++ ++ // pps ++ pic_descriptor->pps_info.avc.entropy_coding_mode_flag = h->pps.cabac; ++ pic_descriptor->pps_info.avc.pic_order_present_flag = h->pps.pic_order_present; ++ pic_descriptor->pps_info.avc.weighted_pred_flag = h->pps.weighted_pred; ++ pic_descriptor->pps_info.avc.weighted_bipred_idc = h->pps.weighted_bipred_idc; ++ pic_descriptor->pps_info.avc.deblocking_filter_control_present_flag = h->pps.deblocking_filter_parameters_present; ++ pic_descriptor->pps_info.avc.constrained_intra_pred_flag = h->pps.constrained_intra_pred; ++ pic_descriptor->pps_info.avc.redundant_pic_cnt_present_flag = h->pps.redundant_pic_cnt_present; ++ pic_descriptor->pps_info.avc.transform_8x8_mode_flag = h->pps.transform_8x8_mode; ++ pic_descriptor->pps_info.avc.xvba_avc_pps_reserved = 0; // must be 0 ++ ++ memcpy(iq_matrix->bScalingLists4x4, h->pps.scaling_matrix4, sizeof(iq_matrix->bScalingLists4x4)); ++ memcpy(iq_matrix->bScalingLists8x8[0], h->pps.scaling_matrix8[0], sizeof(iq_matrix->bScalingLists8x8[0])); ++ memcpy(iq_matrix->bScalingLists8x8[1], h->pps.scaling_matrix8[3], sizeof(iq_matrix->bScalingLists8x8[0])); ++ ++ // Wait for an I-frame before start decoding. Workaround for ATI UVD and UVD+ GPUs ++ if (!h->got_first_iframe) { ++ if (h->slice_type != AV_PICTURE_TYPE_I && h->slice_type != AV_PICTURE_TYPE_SI) ++ return -1; ++ h->got_first_iframe = 1; ++ } ++ ++ ff_draw_horiz_band(s, 0, s->avctx->height); ++ ++ return 0; ++} ++ ++/** Decode the given H.264 slice with XVBA. */ ++static int decode_slice(AVCodecContext *avctx, ++ const uint8_t *buffer, ++ uint32_t size) ++{ ++ H264Context * const h = avctx->priv_data; ++ MpegEncContext * const s = &h->s; ++ struct xvba_render_state *render; ++ ++ render = (struct xvba_render_state *)s->current_picture_ptr->f.data[0]; ++ assert(render); ++ ++ ff_xvba_add_slice_data(render, buffer, size); ++ ++ return 0; ++} ++ ++AVHWAccel ff_h264_xvba_hwaccel = { ++ .name = "h264_xvba", ++ .type = AVMEDIA_TYPE_VIDEO, ++ .id = CODEC_ID_H264, ++ .pix_fmt = PIX_FMT_XVBA_VLD, ++ .start_frame = start_frame, ++ .end_frame = end_frame, ++ .decode_slice = decode_slice, ++}; +diff --git a/lib/ffmpeg/libavcodec/xvba_internal.h b/lib/ffmpeg/libavcodec/xvba_internal.h +new file mode 100644 +index 0000000..9653f85 +--- /dev/null ++++ b/lib/ffmpeg/libavcodec/xvba_internal.h +@@ -0,0 +1,24 @@ ++/* ++ * HW decode acceleration for MPEG-2, H.264 and VC-1 ++ * ++ * Copyright (C) 2005-2011 Team XBMC ++ * ++ * This file is part of FFmpeg. ++ * ++ * FFmpeg is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * FFmpeg is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with FFmpeg; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++int ff_xvba_translate_profile(int profile); ++void ff_xvba_add_slice_data(struct xvba_render_state *render, const uint8_t *buffer, uint32_t size); +diff --git a/lib/ffmpeg/libavcodec/xvba_mpeg2.c b/lib/ffmpeg/libavcodec/xvba_mpeg2.c +new file mode 100644 +index 0000000..552ef95 +--- /dev/null ++++ b/lib/ffmpeg/libavcodec/xvba_mpeg2.c +@@ -0,0 +1,52 @@ ++/* ++ * MPEG-2 HW decode acceleration through XVBA ++ * ++ * Copyright (C) 2005-2011 Team XBMC ++ * ++ * This file is part of FFmpeg. ++ * ++ * FFmpeg is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * FFmpeg is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with FFmpeg; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++#include "dsputil.h" ++ ++static int start_frame(AVCodecContext *avctx, av_unused const uint8_t *buffer, av_unused uint32_t size) ++{ ++ struct MpegEncContext * const s = avctx->priv_data; ++ return 0; ++} ++ ++static int end_frame(AVCodecContext *avctx) ++{ ++ return 0; ++} ++ ++static int decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) ++{ ++ struct MpegEncContext * const s = avctx->priv_data; ++ return 0; ++} ++ ++AVHWAccel ff_mpeg2_xvba_hwaccel = { ++ .name = "mpeg2_xvba", ++ .type = AVMEDIA_TYPE_VIDEO, ++ .id = CODEC_ID_MPEG2VIDEO, ++ .pix_fmt = PIX_FMT_XVBA_VLD, ++ .capabilities = 0, ++ .start_frame = start_frame, ++ .end_frame = end_frame, ++ .decode_slice = decode_slice, ++ .priv_data_size = 0, ++}; +diff --git a/lib/ffmpeg/libavcodec/xvba_vc1.c b/lib/ffmpeg/libavcodec/xvba_vc1.c +new file mode 100644 +index 0000000..7315b62 +--- /dev/null ++++ b/lib/ffmpeg/libavcodec/xvba_vc1.c +@@ -0,0 +1,190 @@ ++/* ++ * VC-1 HW decode acceleration through XVBA ++ * ++ * Copyright (C) 2005-2011 Team XBMC ++ * ++ * This file is part of FFmpeg. ++ * ++ * FFmpeg is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * FFmpeg is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with FFmpeg; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++#include "xvba.h" ++#include "xvba_internal.h" ++#include "vc1.h" ++#include "vc1data.h" ++#include ++ ++ ++/** @file ++ * Implement structures of ffmpeg <-> XvBA ++ */ ++ ++/* Initialize and start decoding a frame with XvBA */ ++static int start_frame(AVCodecContext *avctx, ++ av_unused const uint8_t *buffer, ++ av_unused uint32_t size) ++{ ++ VC1Context * const v = avctx->priv_data; ++ MpegEncContext * const s = &v->s; ++ struct xvba_render_state *render; ++ ++ render = (struct xvba_render_state *)s->current_picture_ptr->f.data[0]; ++ assert(render); ++ ++ render->num_slices = 0; ++ return 0; ++} ++ ++/* End a hardware decoding based frame */ ++static int end_frame(AVCodecContext *avctx) ++{ ++ VC1Context* const v = avctx->priv_data; ++ MpegEncContext* const s = &v->s; ++ struct xvba_render_state *render, *last, *next; ++ XVBAPictureDescriptor *pic_descriptor; ++ ++ render = (struct xvba_render_state *)s->current_picture_ptr->f.data[0]; ++ assert(render); ++ ++ if (render->picture_descriptor == 0) ++ return -1; ++ ++ pic_descriptor = render->picture_descriptor; ++ ++ av_dlog(avctx, "xvba_vc1_end_frame()\n"); ++ ++ memset(pic_descriptor, 0, sizeof(*pic_descriptor)); ++ ++ /* Fill in Parameters - for reference see AMD sdk documentation */ ++ pic_descriptor->profile = ff_xvba_translate_profile(v->profile); ++ pic_descriptor->level = v->level; ++ //done like in va-driver and vaapi ++ if (v->profile == PROFILE_ADVANCED) { ++ pic_descriptor->width_in_mb = s->avctx->coded_width; ++ pic_descriptor->height_in_mb = s->avctx->coded_height; ++ } else { ++ pic_descriptor->width_in_mb = s->mb_width; ++ pic_descriptor->height_in_mb = s->mb_height; ++ } ++ pic_descriptor->picture_structure = s->picture_structure; ++ // xvba-video set this to 1 only 4:2:0 supported ++ // doc says: if not set, choose 1 - we try this ++ pic_descriptor->chroma_format = 1; ++ pic_descriptor->avc_intra_flag = s->pict_type == AV_PICTURE_TYPE_I || v->bi_type == 1; ++ pic_descriptor->avc_reference = (s->current_picture_ptr->f.reference & 3) ? 1 : 0; ++ ++ // VC-1 explicit parameters see page 30 of sdk ++ // sps_info ++ pic_descriptor->sps_info.vc1.postprocflag = v->postprocflag; ++ ++ // done as in vaapi ++ pic_descriptor->sps_info.vc1.pulldown = v->broadcast; ++ pic_descriptor->sps_info.vc1.interlace = v->interlace; ++ pic_descriptor->sps_info.vc1.tfcntrflag = v->tfcntrflag; ++ pic_descriptor->sps_info.vc1.finterpflag = v->finterpflag; ++ pic_descriptor->sps_info.vc1.reserved = 1; ++ // eventually check if this makes sense together with interlace ++ pic_descriptor->sps_info.vc1.psf = v->psf; ++ // what about if it is a frame (page 31) ++ // looked at xvba-driver ++ pic_descriptor->sps_info.vc1.second_field = !s->first_field; ++ pic_descriptor->sps_info.vc1.xvba_vc1_sps_reserved = 0; ++ ++ // VC-1 explicit parameters see page 30 of sdk ++ // pps_info ++ pic_descriptor->pps_info.vc1.panscan_flag = v->panscanflag; ++ pic_descriptor->pps_info.vc1.refdist_flag = v->refdist_flag; ++ pic_descriptor->pps_info.vc1.loopfilter = s->loop_filter; ++ pic_descriptor->pps_info.vc1.fastuvmc = v->fastuvmc; ++ pic_descriptor->pps_info.vc1.extended_mv = v->extended_mv; ++ pic_descriptor->pps_info.vc1.dquant = v->dquant; ++ pic_descriptor->pps_info.vc1.vstransform = v->vstransform; ++ pic_descriptor->pps_info.vc1.overlap = v->overlap; ++ pic_descriptor->pps_info.vc1.quantizer = v->quantizer_mode; ++ pic_descriptor->pps_info.vc1.extended_dmv = v->extended_dmv; ++ pic_descriptor->pps_info.vc1.maxbframes = s->avctx->max_b_frames; ++ pic_descriptor->pps_info.vc1.rangered = (pic_descriptor->profile == PROFILE_SIMPLE) ? 0 : v->rangered; ++ pic_descriptor->pps_info.vc1.syncmarker = (pic_descriptor->profile == PROFILE_SIMPLE) ? 0 : s->resync_marker; ++ pic_descriptor->pps_info.vc1.multires = v->multires; ++ pic_descriptor->pps_info.vc1.reserved = 1; ++ pic_descriptor->pps_info.vc1.range_mapy_flag = v->range_mapy_flag; ++ pic_descriptor->pps_info.vc1.range_mapy = v->range_mapy; ++ pic_descriptor->pps_info.vc1.range_mapuv_flag = v->range_mapuv_flag; ++ pic_descriptor->pps_info.vc1.range_mapuv = v->range_mapuv; ++ pic_descriptor->pps_info.vc1.xvba_vc1_pps_reserved = 0; ++ ++ pic_descriptor->past_surface = 0; ++ pic_descriptor->future_surface = 0; ++ switch (s->pict_type) { ++ case AV_PICTURE_TYPE_B: ++ next = (struct xvba_render_state *)s->next_picture.f.data[0]; ++ assert(next); ++ if (next) ++ pic_descriptor->past_surface = next->surface; ++ // fall-through ++ case AV_PICTURE_TYPE_P: ++ last = (struct xvba_render_state *)s->last_picture.f.data[0]; ++ assert(last); ++ if (last) ++ pic_descriptor->future_surface = last->surface; ++ break; ++ } ++ ++ ff_draw_horiz_band(s, 0, s->avctx->height); ++ ++ return 0; ++} ++ ++static int decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) ++{ ++ VC1Context* const v = avctx->priv_data; ++ MpegEncContext* const s = &v->s; ++ struct xvba_render_state *render; ++ ++ render = (struct xvba_render_state *)s->current_picture_ptr->f.data[0]; ++ assert(render); ++ ++ if (avctx->codec_id == CODEC_ID_VC1 && ++ size >= 4 && IS_MARKER(AV_RB32(buffer))) { ++ buffer += 4; ++ size -= 4; ++ } ++ ++ ff_xvba_add_slice_data(render, buffer, size); ++ ++ return 0; ++} ++ ++#if CONFIG_WMV3_XVBA_HWACCEL ++AVHWAccel ff_wmv3_xvba_hwaccel = { ++ .name = "wmv3_xvba", ++ .type = AVMEDIA_TYPE_VIDEO, ++ .id = CODEC_ID_WMV3, ++ .pix_fmt = PIX_FMT_XVBA_VLD, ++ .start_frame = start_frame, ++ .end_frame = end_frame, ++ .decode_slice = decode_slice, ++}; ++#endif ++ ++AVHWAccel ff_vc1_xvba_hwaccel = { ++ .name = "vc1_xvba", ++ .type = AVMEDIA_TYPE_VIDEO, ++ .id = CODEC_ID_VC1, ++ .pix_fmt = PIX_FMT_XVBA_VLD, ++ .start_frame = start_frame, ++ .end_frame = end_frame, ++ .decode_slice = decode_slice, ++}; +diff --git a/lib/ffmpeg/libavcodec/xvmc_internal.h b/lib/ffmpeg/libavcodec/xvmc_internal.h +index 04197ce..d925eb1 100644 +--- a/lib/ffmpeg/libavcodec/xvmc_internal.h ++++ b/lib/ffmpeg/libavcodec/xvmc_internal.h +@@ -1,5 +1,7 @@ + /* +- * XVideo Motion Compensation internal functions ++ * HW decode acceleration for MPEG-2, H.264 and VC-1 ++ * ++ * Copyright (C) 2005-2011 Team XBMC + * + * This file is part of FFmpeg. + * +diff --git a/lib/ffmpeg/libavutil/pixdesc.c b/lib/ffmpeg/libavutil/pixdesc.c +index e73fbfe..5abbd14 100644 +--- a/lib/ffmpeg/libavutil/pixdesc.c ++++ b/lib/ffmpeg/libavutil/pixdesc.c +@@ -874,6 +874,12 @@ void av_write_image_line(const uint16_t *src, uint8_t *data[4], const int linesi + .log2_chroma_h = 1, + .flags = PIX_FMT_HWACCEL, + }, ++ [PIX_FMT_XVBA_VLD] = { ++ .name = "xvba_vld", ++ .log2_chroma_w = 1, ++ .log2_chroma_h = 1, ++ .flags = PIX_FMT_HWACCEL, ++ }, + [PIX_FMT_YUV420P9LE] = { + .name = "yuv420p9le", + .nb_components = 3, +diff --git a/lib/ffmpeg/libavutil/pixfmt.h b/lib/ffmpeg/libavutil/pixfmt.h +index f0d9c01..0f8cf7b 100644 +--- a/lib/ffmpeg/libavutil/pixfmt.h ++++ b/lib/ffmpeg/libavutil/pixfmt.h +@@ -129,6 +129,7 @@ enum PixelFormat { + PIX_FMT_YUV444P16BE, ///< planar YUV 4:4:4, 48bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + PIX_FMT_VDPAU_MPEG4, ///< MPEG4 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers + PIX_FMT_DXVA2_VLD, ///< HW decoding through DXVA2, Picture.data[3] contains a LPDIRECT3DSURFACE9 pointer ++ PIX_FMT_XVBA_VLD, ///< HW decoding through DXVA2, Picture.data[3] contains a vaapi_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers + + PIX_FMT_RGB444LE, ///< packed RGB 4:4:4, 16bpp, (msb)4A 4R 4G 4B(lsb), little-endian, most significant bits to 0 + PIX_FMT_RGB444BE, ///< packed RGB 4:4:4, 16bpp, (msb)4A 4R 4G 4B(lsb), big-endian, most significant bits to 0 +-- +1.7.10 + + +From 922cada27e255bc3f685b700c2ffa4a146f87624 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 12 Apr 2012 12:09:31 +0200 +Subject: [PATCH 42/73] xvba: add decoder + +--- + configure.in | 48 + + language/English/strings.po | 12 +- + xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 218 +- + xbmc/cores/VideoRenderers/LinuxRendererGL.h | 15 +- + xbmc/cores/VideoRenderers/RenderFormats.h | 1 + + xbmc/cores/VideoRenderers/RenderManager.cpp | 9 +- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h | 4 + + .../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 16 + + xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in | 4 + + xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp | 2354 ++++++++++++++++++++ + xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.h | 382 ++++ + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 3 + + xbmc/settings/GUISettings.cpp | 3 + + xbmc/settings/VideoSettings.h | 2 + + xbmc/video/dialogs/GUIDialogVideoSettings.cpp | 1 + + 15 files changed, 3064 insertions(+), 8 deletions(-) + create mode 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp + create mode 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.h + +diff --git a/configure.in b/configure.in +index 350d960..3660fa4 100644 +--- a/configure.in ++++ b/configure.in +@@ -124,6 +124,8 @@ vaapi_not_found="== Could not find libva. VAAPI support disabled. ==" + vaapi_disabled="== VAAPI support manually disabled. ==" + crystalhd_not_found="== Could not find libcrystalhd. CrystalHD support disabled. ==" + crystalhd_disabled="== CrystalHD support manually disabled. ==" ++xvba_not_found="== Could not find amdxvba.h. XVBA support disabled. ==" ++xvba_disabled="== XVBA support manually disabled. ==" + vdadecoder_enabled="== VDADecoder support enabled. ==" + vdadecoder_disabled="== VDADecoder support manually disabled. ==" + vtbdecoder_enabled="== VTBDecoder support enabled. ==" +@@ -247,6 +249,12 @@ AC_ARG_ENABLE([crystalhd], + [enable CrystalHD decoding (default is auto)])], + [use_crystalhd=$enableval], + [use_crystalhd=auto]) ++ ++AC_ARG_ENABLE([xvba], ++ [AS_HELP_STRING([--enable-xvba], ++ [enable XVBA decoding (default is auto)])], ++ [use_xvba=$enableval], ++ [use_xvba=auto]) + + AC_ARG_ENABLE([vdadecoder], + [AS_HELP_STRING([--enable-vdadecoder], +@@ -1759,6 +1767,38 @@ else + USE_CRYSTALHD=0 + fi + ++# XVBA ++if test "x$use_xvba" != "xno"; then ++ if test "$host_vendor" = "apple" ; then ++ if test "x$use_xvba" = "xyes"; then ++ AC_MSG_ERROR([XVBA not supported on this platform]) ++ else ++ use_xvba="no" ++ AC_MSG_NOTICE($xvba_disabled) ++ fi ++ USE_XVBA=0 ++ else ++ initial_val=$use_xvba ++ AC_CHECK_HEADER([amd/amdxvba.h],, use_xvba=no, [#include ]) ++ ++ if test "x$use_xvba" = "xno"; then ++ if test "x$initial_val" = "xyes"; then ++ AC_MSG_ERROR($xvba_not_found) ++ else ++ AC_MSG_RESULT($xvba_not_found) ++ fi ++ USE_XVBA=0 ++ else ++ AC_DEFINE([HAVE_LIBXVBA], [1], [Define to 1 if you have the 'xvba' header (amdxvba.h)]) ++ USE_XVBA=1 ++ fi ++ fi ++else ++ AC_MSG_NOTICE($xvba_disabled) ++ USE_XVBA=0 ++fi ++ ++ + # VDADecoder + if test "x$use_vdadecoder" != "xno"; then + if test "$host_vendor" = "apple" ; then +@@ -1970,6 +2010,12 @@ else + final_message="$final_message\n CrystalHD:\tNo" + fi + ++if test "x$use_xvba" != "xno"; then ++ final_message="$final_message\n XVBA:\t\tYes" ++else ++ final_message="$final_message\n XVBA:\t\tNo" ++fi ++ + if test "x$use_vdadecoder" != "xno"; then + final_message="$final_message\n VDADecoder:\tYes" + else +@@ -2443,6 +2489,7 @@ AC_SUBST(USE_OPENGLES) + AC_SUBST(USE_VDPAU) + AC_SUBST(USE_VAAPI) + AC_SUBST(USE_CRYSTALHD) ++AC_SUBST(USE_XVBA) + AC_SUBST(USE_LIBSMBCLIENT) + AC_SUBST(USE_LIBNFS) + AC_SUBST(USE_LIBAFPCLIENT) +@@ -2626,6 +2673,7 @@ XB_CONFIG_MODULE([lib/ffmpeg], [ + `if test "x$use_vdpau" != "xno"; then echo --enable-vdpau; else echo --disable-vdpau; fi` \ + `if test "x$use_vaapi" != "xno"; then echo --enable-vaapi; else echo --disable-vaapi; fi` \ + `if test "$use_optimizations" != "no"; then echo --enable-optimizations; else echo --disable-optimizations; fi` \ ++ `if test "x$use_xvba" != "xno"; then echo --enable-xvba; else echo --disable-xvba; fi` \ + --enable-protocol=http \ + --enable-pthreads \ + --enable-runtime-cpudetect \ +diff --git a/language/English/strings.po b/language/English/strings.po +index bba7284..ede18b3 100644 +--- a/language/English/strings.po ++++ b/language/English/strings.po +@@ -5124,7 +5124,11 @@ msgctxt "#13436" + msgid "Allow Vdpau OpenGL interop YUV" + msgstr "" + +-#empty strings from id 13437 to 13499 ++msgctxt "#13437" ++msgid "Allow hardware acceleration (XVBA)" ++msgstr "" ++ ++#empty strings from id 13438 to 13499 + + msgctxt "#13500" + msgid "A/V sync method" +@@ -6346,7 +6350,11 @@ msgctxt "#16325" + msgid "VDPAU - Bob" + msgstr "" + +-#empty strings from id 16326 to 16399 ++msgctxt "#16326" ++msgid "XVBA" ++msgstr "" ++ ++#empty strings from id 16327 to 16399 + + msgctxt "#16400" + msgid "Post-processing" +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +index b281ca7..ec3606a 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +@@ -63,6 +63,9 @@ + VA_MICRO_VERSION == 0 && VA_SDS_VERSION < 5))) + + #endif ++#ifdef HAVE_LIBXVBA ++#include "cores/dvdplayer/DVDCodecs/Video/XVBA.h" ++#endif + + #ifdef TARGET_DARWIN + #include "osx/CocoaInterface.h" +@@ -129,6 +132,9 @@ + #ifdef HAVE_LIBVDPAU + vdpau = NULL; + #endif ++#ifdef HAVE_LIBXVBA ++ xvba = NULL; ++#endif + } + + CLinuxRendererGL::YUVBUFFER::~YUVBUFFER() +@@ -604,6 +610,9 @@ void CLinuxRendererGL::ReleaseBuffer(int idx) + #ifdef HAVE_LIBVDPAU + SAFE_RELEASE(buf.vdpau); + #endif ++#ifdef HAVE_LIBXVBA ++ SAFE_RELEASE(buf.xvba); ++#endif + #ifdef HAVE_LIBVA + buf.vaapi.surface.reset(); + #endif +@@ -879,7 +888,7 @@ void CLinuxRendererGL::UpdateVideoFilter() + case VS_SCALINGMETHOD_LINEAR: + SetTextureFilter(m_scalingMethod == VS_SCALINGMETHOD_NEAREST ? GL_NEAREST : GL_LINEAR); + m_renderQuality = RQ_SINGLEPASS; +- if (((m_renderMethod & RENDER_VDPAU) || (m_renderMethod & RENDER_VAAPI)) && m_nonLinStretch) ++ if (((m_renderMethod & RENDER_VDPAU) || (m_renderMethod & RENDER_VAAPI) || (m_renderMethod & RENDER_XVBA)) && m_nonLinStretch) + { + m_pVideoFilterShader = new StretchFilterShader(); + if (!m_pVideoFilterShader->CompileAndLink()) +@@ -965,6 +974,11 @@ void CLinuxRendererGL::LoadShaders(int field) + CLog::Log(LOGNOTICE, "GL: Using CVBREF render method"); + m_renderMethod = RENDER_CVREF; + } ++ else if (m_format == RENDER_FMT_XVBA) ++ { ++ CLog::Log(LOGNOTICE, "GL: Using XVBA render method"); ++ m_renderMethod = RENDER_XVBA; ++ } + else + { + int requestedMethod = g_guiSettings.GetInt("videoplayer.rendermethod"); +@@ -1113,6 +1127,12 @@ void CLinuxRendererGL::LoadShaders(int field) + m_textureCreate = &CLinuxRendererGL::CreateCVRefTexture; + m_textureDelete = &CLinuxRendererGL::DeleteCVRefTexture; + } ++ else if (m_format == RENDER_FMT_XVBA) ++ { ++ m_textureUpload = &CLinuxRendererGL::UploadXVBATexture; ++ m_textureCreate = &CLinuxRendererGL::CreateXVBATexture; ++ m_textureDelete = &CLinuxRendererGL::DeleteXVBATexture; ++ } + else + { + // setup default YV12 texture handlers +@@ -1225,6 +1245,13 @@ void CLinuxRendererGL::Render(DWORD flags, int renderBuffer) + RenderVAAPI(renderBuffer, m_currentField); + } + #endif ++#ifdef HAVE_LIBXVBA ++ else if (m_renderMethod & RENDER_XVBA) ++ { ++ UpdateVideoFilter(); ++ RenderXVBA(renderBuffer, m_currentField); ++ } ++#endif + else + { + // RENDER_CVREF uses the same render as the default case +@@ -1732,6 +1759,77 @@ void CLinuxRendererGL::RenderVAAPI(int index, int field) + #endif + } + ++void CLinuxRendererGL::RenderXVBA(int index, int field) ++{ ++#ifdef HAVE_LIBXVBA ++ YUVPLANE &plane = m_buffers[index].fields[0][1]; ++ ++ glEnable(m_textureTarget); ++ glActiveTextureARB(GL_TEXTURE0); ++ ++ glBindTexture(m_textureTarget, plane.id); ++ ++ // Try some clamping or wrapping ++ glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); ++ glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); ++ ++ if (m_pVideoFilterShader) ++ { ++ GLint filter; ++ if (!m_pVideoFilterShader->GetTextureFilter(filter)) ++ filter = m_scalingMethod == VS_SCALINGMETHOD_NEAREST ? GL_NEAREST : GL_LINEAR; ++ ++ glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, filter); ++ glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, filter); ++ m_pVideoFilterShader->SetSourceTexture(0); ++ m_pVideoFilterShader->SetWidth(m_sourceWidth); ++ m_pVideoFilterShader->SetHeight(m_sourceHeight); ++ ++ //disable non-linear stretch when a dvd menu is shown, parts of the menu are rendered through the overlay renderer ++ //having non-linear stretch on breaks the alignment ++ if (g_application.m_pPlayer && g_application.m_pPlayer->IsInMenu()) ++ m_pVideoFilterShader->SetNonLinStretch(1.0); ++ else ++ m_pVideoFilterShader->SetNonLinStretch(pow(g_settings.m_fPixelRatio, g_advancedSettings.m_videoNonLinStretchRatio)); ++ ++ m_pVideoFilterShader->Enable(); ++ } ++ else ++ { ++ GLint filter = m_scalingMethod == VS_SCALINGMETHOD_NEAREST ? GL_NEAREST : GL_LINEAR; ++ glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, filter); ++ glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, filter); ++ } ++ ++ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); ++ VerifyGLState(); ++ ++ glBegin(GL_QUADS); ++ if (m_textureTarget==GL_TEXTURE_2D) ++ { ++ glTexCoord2f(plane.rect.x1, plane.rect.y1); glVertex2f(m_destRect.x1, m_destRect.y1); ++ glTexCoord2f(plane.rect.x2, plane.rect.y1); glVertex2f(m_destRect.x2, m_destRect.y1); ++ glTexCoord2f(plane.rect.x2, plane.rect.y2); glVertex2f(m_destRect.x2, m_destRect.y2); ++ glTexCoord2f(plane.rect.x1, plane.rect.y2); glVertex2f(m_destRect.x1, m_destRect.y2); ++ } ++ else ++ { ++ glTexCoord2f(m_destRect.x1, m_destRect.y1); glVertex4f(m_destRect.x1, m_destRect.y1, 0.0f, 0.0f); ++ glTexCoord2f(m_destRect.x2, m_destRect.y1); glVertex4f(m_destRect.x2, m_destRect.y1, 1.0f, 0.0f); ++ glTexCoord2f(m_destRect.x2, m_destRect.y2); glVertex4f(m_destRect.x2, m_destRect.y2, 1.0f, 1.0f); ++ glTexCoord2f(m_destRect.x1, m_destRect.y2); glVertex4f(m_destRect.x1, m_destRect.y2, 0.0f, 1.0f); ++ } ++ glEnd(); ++ VerifyGLState(); ++ ++ if (m_pVideoFilterShader) ++ m_pVideoFilterShader->Disable(); ++ ++ glBindTexture (m_textureTarget, 0); ++ glDisable(m_textureTarget); ++#endif ++} ++ + void CLinuxRendererGL::RenderSoftware(int index, int field) + { + // used for textues uploaded from rgba or CVPixelBuffers. +@@ -2783,6 +2881,93 @@ bool CLinuxRendererGL::CreateCVRefTexture(int index) + return true; + } + ++void CLinuxRendererGL::DeleteXVBATexture(int index) ++{ ++#ifdef HAVE_LIBXVBA ++ YUVPLANE &plane = m_buffers[index].fields[0][0]; ++ YUVFIELDS &fields = m_buffers[index].fields; ++ ++ SAFE_RELEASE(m_buffers[index].xvba); ++ ++ if(plane.id && glIsTexture(plane.id)) ++ glDeleteTextures(1, &plane.id); ++ plane.id = 0; ++ fields[0][1].id = 0; ++#endif ++} ++ ++bool CLinuxRendererGL::CreateXVBATexture(int index) ++{ ++#ifdef HAVE_LIBXVBA ++ YV12Image &im = m_buffers[index].image; ++ YUVFIELDS &fields = m_buffers[index].fields; ++ YUVPLANE &plane = fields[0][0]; ++ ++ DeleteXVBATexture(index); ++ ++ memset(&im , 0, sizeof(im)); ++ memset(&fields, 0, sizeof(fields)); ++ ++ glGenTextures(1, &plane.id); ++ ++ m_eventTexturesDone[index]->Set(); ++#endif ++ return true; ++} ++ ++void CLinuxRendererGL::UploadXVBATexture(int index) ++{ ++#ifdef HAVE_LIBXVBA ++ XVBA::CXvbaRenderPicture *xvba = m_buffers[index].xvba; ++ YV12Image &im = m_buffers[index].image; ++ ++ YUVFIELDS &fields = m_buffers[index].fields; ++ YUVPLANE &plane = fields[0][1]; ++ ++ if (!xvba) ++ { ++ fields[0][1].id = fields[0][0].id; ++ m_eventTexturesDone[index]->Set(); ++ CLog::Log(LOGWARNING,"CLinuxRendererGL::UploadXVBATexture no xvba texture, index: %d", index); ++ return; ++ } ++// xvba->Transfer(); ++ ++ fields[0][1].id = xvba->texture; ++ ++ im.height = xvba->texHeight; ++ im.width = xvba->texWidth; ++ ++ plane.texwidth = xvba->texWidth; ++ plane.texheight = xvba->texHeight; ++ plane.pixpertex_x = 1; ++ plane.pixpertex_y = 1; ++ ++ plane.rect = m_sourceRect; ++ plane.width = im.width; ++ plane.height = im.height; ++ ++ plane.height /= plane.pixpertex_y; ++ plane.rect.y1 /= plane.pixpertex_y; ++ plane.rect.y2 /= plane.pixpertex_y; ++ plane.width /= plane.pixpertex_x; ++ plane.rect.x1 /= plane.pixpertex_x; ++ plane.rect.x2 /= plane.pixpertex_x; ++ ++ if (m_textureTarget == GL_TEXTURE_2D) ++ { ++ plane.height /= plane.texheight; ++ plane.rect.y1 /= plane.texheight; ++ plane.rect.y2 /= plane.texheight; ++ plane.width /= plane.texwidth; ++ plane.rect.x1 /= plane.texwidth; ++ plane.rect.x2 /= plane.texwidth; ++ } ++ ++ m_eventTexturesDone[index]->Set(); ++#endif ++} ++ + void CLinuxRendererGL::UploadYUV422PackedTexture(int source) + { + YUVBUFFER& buf = m_buffers[source]; +@@ -3368,6 +3553,9 @@ bool CLinuxRendererGL::Supports(ERENDERFEATURE feature) + if (m_renderMethod & RENDER_VAAPI) + return false; + ++ if (m_renderMethod & RENDER_XVBA) ++ return false; ++ + return (m_renderMethod & RENDER_GLSL) + || (m_renderMethod & RENDER_ARB) + || ((m_renderMethod & RENDER_SW) && glewIsSupported("GL_ARB_imaging") == GL_TRUE); +@@ -3381,6 +3569,9 @@ bool CLinuxRendererGL::Supports(ERENDERFEATURE feature) + if (m_renderMethod & RENDER_VAAPI) + return false; + ++ if (m_renderMethod & RENDER_XVBA) ++ return false; ++ + return (m_renderMethod & RENDER_GLSL) + || (m_renderMethod & RENDER_ARB) + || ((m_renderMethod & RENDER_SW) && glewIsSupported("GL_ARB_imaging") == GL_TRUE); +@@ -3404,7 +3595,8 @@ bool CLinuxRendererGL::Supports(ERENDERFEATURE feature) + if (feature == RENDERFEATURE_NONLINSTRETCH) + { + if (((m_renderMethod & RENDER_GLSL) && !(m_renderMethod & RENDER_POT)) || +- (m_renderMethod & RENDER_VDPAU) || (m_renderMethod & RENDER_VAAPI)) ++ (m_renderMethod & RENDER_VDPAU) || (m_renderMethod & RENDER_VAAPI) || ++ (m_renderMethod & RENDER_XVBA)) + return true; + } + +@@ -3476,6 +3668,16 @@ bool CLinuxRendererGL::Supports(EINTERLACEMETHOD method) + return false; + } + ++ if(m_renderMethod & RENDER_XVBA) ++ { ++#ifdef HAVE_LIBXVBA ++ XVBA::CXvbaRenderPicture *xvba = m_buffers[m_iYV12RenderBuffer].xvba; ++ if(xvba) ++ return xvba->xvba->Supports(method); ++#endif ++ return false; ++ } ++ + #ifdef TARGET_DARWIN + // YADIF too slow for HD but we have no methods to fall back + // to something that works so just turn it off. +@@ -3518,7 +3720,7 @@ bool CLinuxRendererGL::Supports(ESCALINGMETHOD method) + || method == VS_SCALINGMETHOD_LANCZOS3) + { + if ((glewIsSupported("GL_EXT_framebuffer_object") && (m_renderMethod & RENDER_GLSL)) || +- (m_renderMethod & RENDER_VDPAU) || (m_renderMethod & RENDER_VAAPI)) ++ (m_renderMethod & RENDER_VDPAU) || (m_renderMethod & RENDER_VAAPI) || (m_renderMethod & RENDER_XVBA)) + { + // spline36 and lanczos3 are only allowed through advancedsettings.xml + if(method != VS_SCALINGMETHOD_SPLINE36 +@@ -3610,4 +3812,14 @@ void CLinuxRendererGL::AddProcessor(struct __CVBuffer *cvBufferRef, int index) + } + #endif + ++#ifdef HAVE_LIBXVBA ++void CLinuxRendererGL::AddProcessor(XVBA::CXvbaRenderPicture* xvba, int index) ++{ ++ YUVBUFFER &buf = m_buffers[index]; ++ XVBA::CXvbaRenderPicture *pic = xvba->Acquire(); ++ SAFE_RELEASE(buf.xvba); ++ buf.xvba = pic; ++} ++#endif ++ + #endif +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.h b/xbmc/cores/VideoRenderers/LinuxRendererGL.h +index 2fc34ae..e76624b 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.h ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.h +@@ -43,6 +43,8 @@ + namespace Shaders { class BaseVideoFilterShader; } + namespace VAAPI { struct CHolder; } + namespace VDPAU { class CVdpauRenderPicture; } ++namespace XVBA { class CXvbaRenderPicture; } ++ + + #define NUM_BUFFERS 10 + +@@ -90,6 +92,7 @@ enum RenderMethod + RENDER_POT=0x10, + RENDER_VAAPI=0x20, + RENDER_CVREF = 0x40, ++ RENDER_XVBA=0x80, + }; + + enum RenderQuality +@@ -151,7 +154,9 @@ class CLinuxRendererGL : public CBaseRenderer + #ifdef TARGET_DARWIN + virtual void AddProcessor(struct __CVBuffer *cvBufferRef, int index); + #endif +- ++#ifdef HAVE_LIBXVBA ++ virtual void AddProcessor(XVBA::CXvbaRenderPicture* xvba, int index); ++#endif + virtual void RenderUpdate(bool clear, DWORD flags = 0, DWORD alpha = 255); + + // Feature support +@@ -210,6 +215,10 @@ class CLinuxRendererGL : public CBaseRenderer + void DeleteYUV422PackedTexture(int index); + bool CreateYUV422PackedTexture(int index); + ++ void UploadXVBATexture(int index); ++ void DeleteXVBATexture(int index); ++ bool CreateXVBATexture(int index); ++ + void UploadRGBTexture(int index); + void ToRGBFrame(YV12Image* im, unsigned flipIndexPlane, unsigned flipIndexBuf); + void ToRGBFields(YV12Image* im, unsigned flipIndexPlaneTop, unsigned flipIndexPlaneBot, unsigned flipIndexBuf); +@@ -225,6 +234,7 @@ class CLinuxRendererGL : public CBaseRenderer + void RenderVDPAU(int renderBuffer, int field); // render using vdpau hardware + void RenderProgressiveWeave(int renderBuffer, int field); // render using vdpau hardware + void RenderVAAPI(int renderBuffer, int field); // render using vdpau hardware ++ void RenderXVBA(int renderBuffer, int field); // render using xvba hardware + + struct + { +@@ -292,6 +302,9 @@ class CLinuxRendererGL : public CBaseRenderer + #ifdef TARGET_DARWIN_OSX + struct __CVBuffer *cvBufferRef; + #endif ++#ifdef HAVE_LIBXVBA ++ XVBA::CXvbaRenderPicture *xvba; ++#endif + }; + + typedef YUVBUFFER YUVBUFFERS[NUM_BUFFERS]; +diff --git a/xbmc/cores/VideoRenderers/RenderFormats.h b/xbmc/cores/VideoRenderers/RenderFormats.h +index 0262c60..a727d94 100644 +--- a/xbmc/cores/VideoRenderers/RenderFormats.h ++++ b/xbmc/cores/VideoRenderers/RenderFormats.h +@@ -35,6 +35,7 @@ enum ERenderFormat { + RENDER_FMT_OMXEGL, + RENDER_FMT_CVBREF, + RENDER_FMT_BYPASS, ++ RENDER_FMT_XVBA, + }; + + #endif +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index a521680..0506823 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -250,8 +250,9 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi + + // check if decoder supports buffering + m_bCodecSupportsBuffering = false; +- if (format == RENDER_FMT_VDPAU || +- format == RENDER_FMT_VDPAU_420) ++ if (format == RENDER_FMT_VDPAU ++ || format == RENDER_FMT_VDPAU_420 ++ || format == RENDER_FMT_XVBA) + m_bCodecSupportsBuffering = true; + + bool result = m_pRenderer->Configure(width, height, d_width, d_height, fps, flags, format, extended_format, orientation); +@@ -873,6 +874,10 @@ int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic) + else if(pic.format == RENDER_FMT_VAAPI) + m_pRenderer->AddProcessor(*pic.vaapi, index); + #endif ++#ifdef HAVE_LIBXVBA ++ else if(pic.format == RENDER_FMT_XVBA) ++ m_pRenderer->AddProcessor(pic.xvba, index); ++#endif + m_pRenderer->ReleaseImage(index, false); + + return index; +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h +index 98d8f89..76d3575 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h +@@ -35,6 +35,7 @@ + namespace DXVA { class CSurfaceContext; } + namespace VAAPI { struct CHolder; } + namespace VDPAU { class CVdpauRenderPicture; } ++namespace XVBA { class CXvbaRenderPicture; } + class COpenMax; + class COpenMaxVideo; + struct OpenMaxVideoBuffer; +@@ -60,6 +61,9 @@ struct DVDVideoPicture + struct { + VAAPI::CHolder* vaapi; + }; ++ struct { ++ XVBA::CXvbaRenderPicture* xvba; ++ }; + + struct { + COpenMax *openMax; +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +index a6e42e5..b3252ec 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +@@ -56,6 +56,9 @@ + #ifdef HAVE_LIBVA + #include "VAAPI.h" + #endif ++#ifdef HAVE_LIBXVBA ++#include "XVBA.h" ++#endif + + using namespace boost; + +@@ -100,6 +103,19 @@ enum PixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx + dec->Release(); + } + #endif ++#ifdef HAVE_LIBXVBA ++ if(*cur == PIX_FMT_XVBA_VLD && g_guiSettings.GetBool("videoplayer.usexvba")) ++ { ++ XVBA::CDecoder* dec = new XVBA::CDecoder(); ++ if(dec->Open(avctx, *cur, ctx->m_uSurfacesCount)) ++ { ++ ctx->SetHardware(dec); ++ return *cur; ++ } ++ else ++ dec->Release(); ++ } ++#endif + #ifdef HAVE_LIBVA + // mpeg4 vaapi decoding is disabled + if(*cur == PIX_FMT_VAAPI_VLD && g_guiSettings.GetBool("videoplayer.usevaapi") +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in b/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in +index 176ceff..c58422b 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in +@@ -14,6 +14,10 @@ ifeq (@USE_CRYSTALHD@,1) + SRCS += CrystalHD.cpp + SRCS += DVDVideoCodecCrystalHD.cpp + endif ++ifeq (@USE_XVBA@,1) ++SRCS+= XVBA.cpp \ ++ ++endif + ifeq (@USE_VDA@,1) + SRCS += DVDVideoCodecVDA.cpp + endif +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp +new file mode 100644 +index 0000000..e8e376a +--- /dev/null ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp +@@ -0,0 +1,2354 @@ ++/* ++ * Copyright (C) 2005-2011 Team XBMC ++ * http://www.xbmc.org ++ * ++ * This Program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2, or (at your option) ++ * any later version. ++ * ++ * This Program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with XBMC; see the file COPYING. If not, write to ++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ++ * http://www.gnu.org/copyleft/gpl.html ++ * ++ */ ++ ++#include "system.h" ++#ifdef HAVE_LIBXVBA ++ ++#include "system_gl.h" ++#include ++#include ++#include "XVBA.h" ++#include "windowing/WindowingFactory.h" ++#include "guilib/GraphicContext.h" ++#include "settings/GUISettings.h" ++#include "settings/Settings.h" ++#include "utils/TimeUtils.h" ++#include "cores/dvdplayer/DVDClock.h" ++ ++using namespace XVBA; ++ ++// XVBA interface ++ ++#define XVBA_LIBRARY "libXvBAW.so.1" ++ ++typedef Bool (*XVBAQueryExtensionProc) (Display *dpy, int *vers); ++typedef Status (*XVBACreateContextProc) (void *input, void *output); ++typedef Status (*XVBADestroyContextProc) (void *context); ++typedef Bool (*XVBAGetSessionInfoProc) (void *input, void *output); ++typedef Status (*XVBACreateSurfaceProc) (void *input, void *output); ++typedef Status (*XVBACreateGLSharedSurfaceProc)(void *input, void *output); ++typedef Status (*XVBADestroySurfaceProc) (void *surface); ++typedef Status (*XVBACreateDecodeBuffersProc) (void *input, void *output); ++typedef Status (*XVBADestroyDecodeBuffersProc) (void *input); ++typedef Status (*XVBAGetCapDecodeProc) (void *input, void *output); ++typedef Status (*XVBACreateDecodeProc) (void *input, void *output); ++typedef Status (*XVBADestroyDecodeProc) (void *session); ++typedef Status (*XVBAStartDecodePictureProc) (void *input); ++typedef Status (*XVBADecodePictureProc) (void *input); ++typedef Status (*XVBAEndDecodePictureProc) (void *input); ++typedef Status (*XVBASyncSurfaceProc) (void *input, void *output); ++typedef Status (*XVBAGetSurfaceProc) (void *input); ++typedef Status (*XVBATransferSurfaceProc) (void *input); ++ ++static struct ++{ ++ XVBAQueryExtensionProc QueryExtension; ++ XVBACreateContextProc CreateContext; ++ XVBADestroyContextProc DestroyContext; ++ XVBAGetSessionInfoProc GetSessionInfo; ++ XVBACreateSurfaceProc CreateSurface; ++ XVBACreateGLSharedSurfaceProc CreateGLSharedSurface; ++ XVBADestroySurfaceProc DestroySurface; ++ XVBACreateDecodeBuffersProc CreateDecodeBuffers; ++ XVBADestroyDecodeBuffersProc DestroyDecodeBuffers; ++ XVBAGetCapDecodeProc GetCapDecode; ++ XVBACreateDecodeProc CreateDecode; ++ XVBADestroyDecodeProc DestroyDecode; ++ XVBAStartDecodePictureProc StartDecodePicture; ++ XVBADecodePictureProc DecodePicture; ++ XVBAEndDecodePictureProc EndDecodePicture; ++ XVBASyncSurfaceProc SyncSurface; ++ XVBAGetSurfaceProc GetSurface; ++ XVBATransferSurfaceProc TransferSurface; ++}g_XVBA_vtable; ++ ++//----------------------------------------------------------------------------- ++//----------------------------------------------------------------------------- ++ ++CXVBAContext *CXVBAContext::m_context = 0; ++CCriticalSection CXVBAContext::m_section; ++Display *CXVBAContext::m_display = 0; ++void *CXVBAContext::m_dlHandle = 0; ++ ++CXVBAContext::CXVBAContext() ++{ ++ m_context = 0; ++// m_dlHandle = 0; ++ m_xvbaContext = 0; ++ m_refCount = 0; ++} ++ ++void CXVBAContext::Release() ++{ ++ CSingleLock lock(m_section); ++ ++ m_refCount--; ++ if (m_refCount <= 0) ++ { ++ Close(); ++ delete this; ++ m_context = 0; ++ } ++} ++ ++void CXVBAContext::Close() ++{ ++ CLog::Log(LOGNOTICE, "XVBA::Close - closing decoder context"); ++ ++ DestroyContext(); ++// if (m_dlHandle) ++// { ++// dlclose(m_dlHandle); ++// m_dlHandle = 0; ++// } ++} ++ ++bool CXVBAContext::EnsureContext(CXVBAContext **ctx) ++{ ++ CSingleLock lock(m_section); ++ ++ if (m_context) ++ { ++ m_context->m_refCount++; ++ *ctx = m_context; ++ return true; ++ } ++ ++ m_context = new CXVBAContext(); ++ *ctx = m_context; ++ { ++ CSingleLock gLock(g_graphicsContext); ++ if (!m_context->LoadSymbols() || !m_context->CreateContext()) ++ { ++ delete m_context; ++ m_context = 0; ++ return false; ++ } ++ } ++ ++ m_context->m_refCount++; ++ ++ *ctx = m_context; ++ return true; ++} ++ ++bool CXVBAContext::LoadSymbols() ++{ ++ if (!m_dlHandle) ++ { ++ m_dlHandle = dlopen(XVBA_LIBRARY, RTLD_LAZY); ++ if (!m_dlHandle) ++ { ++ const char* error = dlerror(); ++ if (!error) ++ error = "dlerror() returned NULL"; ++ ++ CLog::Log(LOGERROR,"XVBA::LoadSymbols: Unable to get handle to lib: %s", error); ++ return false; ++ } ++ } ++ else ++ return true; ++ ++#define INIT_PROC(PREFIX, PROC) do { \ ++ g_##PREFIX##_vtable.PROC = (PREFIX##PROC##Proc) \ ++ dlsym(m_dlHandle, #PREFIX #PROC); \ ++ } while (0) ++ ++#define INIT_PROC_CHECK(PREFIX, PROC) do { \ ++ dlerror(); \ ++ INIT_PROC(PREFIX, PROC); \ ++ if (dlerror()) { \ ++ dlclose(m_dlHandle); \ ++ m_dlHandle = NULL; \ ++ return false; \ ++ } \ ++ } while (0) ++ ++#define XVBA_INIT_PROC(PROC) INIT_PROC_CHECK(XVBA, PROC) ++ ++ XVBA_INIT_PROC(QueryExtension); ++ XVBA_INIT_PROC(CreateContext); ++ XVBA_INIT_PROC(DestroyContext); ++ XVBA_INIT_PROC(GetSessionInfo); ++ XVBA_INIT_PROC(CreateSurface); ++ XVBA_INIT_PROC(CreateGLSharedSurface); ++ XVBA_INIT_PROC(DestroySurface); ++ XVBA_INIT_PROC(CreateDecodeBuffers); ++ XVBA_INIT_PROC(DestroyDecodeBuffers); ++ XVBA_INIT_PROC(GetCapDecode); ++ XVBA_INIT_PROC(CreateDecode); ++ XVBA_INIT_PROC(DestroyDecode); ++ XVBA_INIT_PROC(StartDecodePicture); ++ XVBA_INIT_PROC(DecodePicture); ++ XVBA_INIT_PROC(EndDecodePicture); ++ XVBA_INIT_PROC(SyncSurface); ++ XVBA_INIT_PROC(GetSurface); ++ XVBA_INIT_PROC(TransferSurface); ++ ++#undef XVBA_INIT_PROC ++#undef INIT_PROC ++ ++ return true; ++} ++ ++bool CXVBAContext::CreateContext() ++{ ++ if (m_xvbaContext) ++ return true; ++ ++ CLog::Log(LOGNOTICE,"XVBA::CreateContext - creating decoder context"); ++ ++ Drawable window; ++ { CSingleLock lock(g_graphicsContext); ++ if (!m_display) ++ m_display = XOpenDisplay(NULL); ++ window = 0; ++ } ++ ++ int version; ++ if (!g_XVBA_vtable.QueryExtension(m_display, &version)) ++ return false; ++ CLog::Log(LOGNOTICE,"XVBA::CreateContext - opening xvba version: %i", version); ++ ++ // create XVBA Context ++ XVBA_Create_Context_Input contextInput; ++ XVBA_Create_Context_Output contextOutput; ++ contextInput.size = sizeof(contextInput); ++ contextInput.display = m_display; ++ contextInput.draw = window; ++ contextOutput.size = sizeof(contextOutput); ++ if(Success != g_XVBA_vtable.CreateContext(&contextInput, &contextOutput)) ++ { ++ CLog::Log(LOGERROR,"XVBA::CreateContext - failed to create context"); ++ return false; ++ } ++ m_xvbaContext = contextOutput.context; ++ ++ return true; ++} ++ ++void CXVBAContext::DestroyContext() ++{ ++ if (!m_xvbaContext) ++ return; ++ ++ g_XVBA_vtable.DestroyContext(m_xvbaContext); ++ m_xvbaContext = 0; ++// XCloseDisplay(m_display); ++} ++ ++void *CXVBAContext::GetContext() ++{ ++ return m_xvbaContext; ++} ++ ++//----------------------------------------------------------------------------- ++//----------------------------------------------------------------------------- ++ ++static unsigned int decoderId = 0; ++ ++CDecoder::CDecoder() : m_xvbaOutput(&m_inMsgEvent) ++{ ++ m_xvbaConfig.context = 0; ++ m_xvbaConfig.xvbaSession = 0; ++ m_xvbaConfig.videoSurfaces = &m_videoSurfaces; ++ m_xvbaConfig.videoSurfaceSec = &m_videoSurfaceSec; ++ m_xvbaConfig.apiSec = &m_apiSec; ++ ++ m_displayState = XVBA_OPEN; ++} ++ ++CDecoder::~CDecoder() ++{ ++ Close(); ++} ++ ++typedef struct { ++ unsigned int size; ++ unsigned int num_of_decodecaps; ++ XVBADecodeCap decode_caps_list[]; ++} XVBA_GetCapDecode_Output_Base; ++ ++void CDecoder::OnLostDevice() ++{ ++ CLog::Log(LOGNOTICE,"XVBA::OnLostDevice event"); ++ ++ CSingleLock lock(m_decoderSection); ++ DestroySession(); ++ if (m_xvbaConfig.context) ++ m_xvbaConfig.context->Release(); ++ m_xvbaConfig.context = 0; ++ ++ m_displayState = XVBA_LOST; ++ m_displayEvent.Reset(); ++} ++ ++void CDecoder::OnResetDevice() ++{ ++ CLog::Log(LOGNOTICE,"XVBA::OnResetDevice event"); ++ ++ CSingleLock lock(m_decoderSection); ++ if (m_displayState == XVBA_LOST) ++ { ++ m_displayState = XVBA_RESET; ++ lock.Leave(); ++ m_displayEvent.Set(); ++ } ++} ++ ++bool CDecoder::Open(AVCodecContext* avctx, const enum PixelFormat fmt, unsigned int surfaces) ++{ ++ std::string Vendor = g_Windowing.GetRenderVendor(); ++ std::transform(Vendor.begin(), Vendor.end(), Vendor.begin(), ::tolower); ++ if (Vendor.compare(0, 3, "ati") != 0) ++ { ++ return false; ++ } ++ ++ m_decoderId = decoderId++; ++ ++ CLog::Log(LOGNOTICE,"(XVBA::Open) opening xvba decoder, id: %d", m_decoderId); ++ ++ if(avctx->coded_width == 0 ++ || avctx->coded_height == 0) ++ { ++ CLog::Log(LOGWARNING,"(XVBA) no width/height available, can't init"); ++ return false; ++ } ++ ++ if (!m_dllAvUtil.Load()) ++ return false; ++ ++ if (!CXVBAContext::EnsureContext(&m_xvbaConfig.context)) ++ return false; ++ ++ // xvba get session info ++ XVBA_GetSessionInfo_Input sessionInput; ++ XVBA_GetSessionInfo_Output sessionOutput; ++ sessionInput.size = sizeof(sessionInput); ++ sessionInput.context = m_xvbaConfig.context->GetContext(); ++ sessionOutput.size = sizeof(sessionOutput); ++ if (Success != g_XVBA_vtable.GetSessionInfo(&sessionInput, &sessionOutput)) ++ { ++ CLog::Log(LOGERROR,"(XVBA) can't get session info"); ++ return false; ++ } ++ if (sessionOutput.getcapdecode_output_size == 0) ++ { ++ CLog::Log(LOGERROR,"(XVBA) session decode not supported"); ++ return false; ++ } ++ ++ // get decoder capabilities ++ XVBA_GetCapDecode_Input capInput; ++ XVBA_GetCapDecode_Output *capOutput; ++ capInput.size = sizeof(capInput); ++ capInput.context = m_xvbaConfig.context->GetContext(); ++ capOutput = (XVBA_GetCapDecode_Output *)calloc(sessionOutput.getcapdecode_output_size, 1); ++ capOutput->size = sessionOutput.getcapdecode_output_size; ++ if (Success != g_XVBA_vtable.GetCapDecode(&capInput, capOutput)) ++ { ++ CLog::Log(LOGERROR,"(XVBA) can't get decode capabilities"); ++ return false; ++ } ++ ++ int match = -1; ++ if (avctx->codec_id == CODEC_ID_H264) ++ { ++ // search for profile high ++ for (unsigned int i = 0; i < capOutput->num_of_decodecaps; ++i) ++ { ++ if (capOutput->decode_caps_list[i].capability_id == XVBA_H264 && ++ capOutput->decode_caps_list[i].flags == XVBA_H264_HIGH) ++ { ++ match = (int) i; ++ break; ++ } ++ } ++ if (match < 0) ++ { ++ CLog::Log(LOGNOTICE, "(XVBA::Open) - profile XVBA_H264_HIGH not found"); ++ } ++ } ++ else if (avctx->codec_id == CODEC_ID_VC1) ++ { ++ // search for profile advanced ++ for (unsigned int i = 0; i < capOutput->num_of_decodecaps; ++i) ++ { ++ if (capOutput->decode_caps_list[i].capability_id == XVBA_VC1 && ++ capOutput->decode_caps_list[i].flags == XVBA_VC1_ADVANCED) ++ { ++ match = (int) i; ++ break; ++ } ++ } ++ if (match < 0) ++ { ++ CLog::Log(LOGNOTICE, "(XVBA::Open) - profile XVBA_VC1_ADVANCED not found"); ++ } ++ } ++ else if (avctx->codec_id == CODEC_ID_MPEG2VIDEO) ++ { ++ // search for profile high ++ for (unsigned int i = 0; i < capOutput->num_of_decodecaps; ++i) ++ { ++ if (capOutput->decode_caps_list[i].capability_id == XVBA_MPEG2_VLD) ++ { ++ // XXX: uncomment when implemented ++ // match = (int) i; ++ // break; ++ } ++ } ++ if (match < 0) ++ { ++ CLog::Log(LOGNOTICE, "(XVBA::Open) - profile XVBA_MPEG2_VLD not found"); ++ } ++ } ++ else if (avctx->codec_id == CODEC_ID_WMV3) ++ { ++ // search for profile high ++ for (unsigned int i = 0; i < capOutput->num_of_decodecaps; ++i) ++ { ++ if (capOutput->decode_caps_list[i].capability_id == XVBA_VC1 && ++ capOutput->decode_caps_list[i].flags == XVBA_VC1_MAIN) ++ { ++ match = (int) i; ++ break; ++ } ++ } ++ if (match < 0) ++ { ++ CLog::Log(LOGNOTICE, "(XVBA::Open) - profile XVBA_VC1_MAIN not found"); ++ } ++ } ++ ++ if (match < 0) ++ { ++ free(capOutput); ++ return false; ++ } ++ ++ CLog::Log(LOGNOTICE,"(XVBA) using decoder capability id: %i flags: %i", ++ capOutput->decode_caps_list[match].capability_id, ++ capOutput->decode_caps_list[match].flags); ++ CLog::Log(LOGNOTICE,"(XVBA) using surface type: %x", ++ capOutput->decode_caps_list[match].surface_type); ++ ++ m_xvbaConfig.decoderCap = capOutput->decode_caps_list[match]; ++ ++ free(capOutput); ++ ++ // set some varables ++ m_xvbaConfig.xvbaSession = 0; ++ m_xvbaBufferPool.data_buffer = 0; ++ m_xvbaBufferPool.iq_matrix_buffer = 0; ++ m_xvbaBufferPool.picture_descriptor_buffer = 0; ++ m_presentPicture = 0; ++ m_xvbaConfig.numRenderBuffers = surfaces; ++ m_decoderThread = CThread::GetCurrentThreadId(); ++ m_speed = DVD_PLAYSPEED_NORMAL; ++ ++ if (1) //g_guiSettings.GetBool("videoplayer.usexvbasharedsurface")) ++ m_xvbaConfig.useSharedSurfaces = true; ++ else ++ m_xvbaConfig.useSharedSurfaces = false; ++ ++ m_displayState = XVBA_OPEN; ++ ++ // setup ffmpeg ++ avctx->thread_count = 1; ++ avctx->get_buffer = CDecoder::FFGetBuffer; ++ avctx->release_buffer = CDecoder::FFReleaseBuffer; ++ avctx->draw_horiz_band = CDecoder::FFDrawSlice; ++ avctx->slice_flags = SLICE_FLAG_CODED_ORDER|SLICE_FLAG_ALLOW_FIELD; ++ ++ g_Windowing.Register(this); ++ return true; ++} ++ ++void CDecoder::Close() ++{ ++ CLog::Log(LOGNOTICE, "XVBA::Close - closing decoder, id: %d", m_decoderId); ++ ++ if (!m_xvbaConfig.context) ++ return; ++ ++ DestroySession(); ++ if (m_xvbaConfig.context) ++ m_xvbaConfig.context->Release(); ++ m_xvbaConfig.context = 0; ++ ++ while (!m_videoSurfaces.empty()) ++ { ++ xvba_render_state *render = m_videoSurfaces.back(); ++ if(render->buffers_alllocated > 0) ++ m_dllAvUtil.av_free(render->buffers); ++ m_videoSurfaces.pop_back(); ++ free(render); ++ } ++ ++ g_Windowing.Unregister(this); ++ m_dllAvUtil.Unload(); ++} ++ ++long CDecoder::Release() ++{ ++ // check if we should do some pre-cleanup here ++ // a second decoder might need resources ++ if (m_xvbaConfig.xvbaSession) ++ { ++ CSingleLock lock(m_decoderSection); ++ CLog::Log(LOGNOTICE,"XVBA::Release pre-cleanup"); ++ DestroySession(true); ++ } ++ return IHardwareDecoder::Release(); ++} ++ ++long CDecoder::ReleasePicReference() ++{ ++ return IHardwareDecoder::Release(); ++} ++ ++bool CDecoder::Supports(EINTERLACEMETHOD method) ++{ ++ if(method == VS_INTERLACEMETHOD_AUTO) ++ return true; ++ ++ if (1) //g_guiSettings.GetBool("videoplayer.usexvbasharedsurface")) ++ { ++ if (method == VS_INTERLACEMETHOD_XVBA) ++ return true; ++ } ++ ++ return false; ++} ++ ++void CDecoder::ResetState() ++{ ++ m_displayState = XVBA_OPEN; ++} ++ ++int CDecoder::Check(AVCodecContext* avctx) ++{ ++ EDisplayState state; ++ ++ { CSingleLock lock(m_decoderSection); ++ state = m_displayState; ++ } ++ ++ if (state == XVBA_LOST) ++ { ++ CLog::Log(LOGNOTICE,"XVBA::Check waiting for display reset event"); ++ if (!m_displayEvent.WaitMSec(2000)) ++ { ++ CLog::Log(LOGERROR, "XVBA::Check - device didn't reset in reasonable time"); ++ state = XVBA_RESET;; ++ } ++ else ++ { CSingleLock lock(m_decoderSection); ++ state = m_displayState; ++ } ++ } ++ if (state == XVBA_RESET || state == XVBA_ERROR) ++ { ++ CLog::Log(LOGNOTICE,"XVBA::Check - Attempting recovery"); ++ ++ CSingleLock gLock(g_graphicsContext); ++ CSingleLock lock(m_decoderSection); ++ ++ DestroySession(); ++ ResetState(); ++ CXVBAContext::EnsureContext(&m_xvbaConfig.context); ++ ++ if (state == XVBA_RESET) ++ return VC_FLUSHED; ++ else ++ return VC_ERROR; ++ } ++ return 0; ++} ++ ++void CDecoder::SetError(const char* function, const char* msg, int line) ++{ ++ CLog::Log(LOGERROR, "XVBA::%s - %s, line %d", function, msg, line); ++ CSingleLock lock(m_decoderSection); ++ m_displayState = XVBA_ERROR; ++} ++ ++bool CDecoder::CreateSession(AVCodecContext* avctx) ++{ ++ m_xvbaConfig.surfaceWidth = (avctx->coded_width+15) & ~15; ++ m_xvbaConfig.surfaceHeight = (avctx->coded_height+15) & ~15; ++ ++ m_xvbaConfig.vidWidth = avctx->width; ++ m_xvbaConfig.vidHeight = avctx->height; ++ ++ XVBA_Create_Decode_Session_Input sessionInput; ++ XVBA_Create_Decode_Session_Output sessionOutput; ++ ++ sessionInput.size = sizeof(sessionInput); ++ sessionInput.width = m_xvbaConfig.surfaceWidth; ++ sessionInput.height = m_xvbaConfig.surfaceHeight; ++ sessionInput.context = m_xvbaConfig.context->GetContext(); ++ sessionInput.decode_cap = &m_xvbaConfig.decoderCap; ++ sessionOutput.size = sizeof(sessionOutput); ++ ++ if (Success != g_XVBA_vtable.CreateDecode(&sessionInput, &sessionOutput)) ++ { ++ SetError(__FUNCTION__, "failed to create decoder session", __LINE__); ++ CLog::Log(LOGERROR, "Decoder failed with following stats: m_surfaceWidth %u, m_surfaceHeight %u," ++ " m_vidWidth %u, m_vidHeight %u, coded_width %d, coded_height %d", ++ m_xvbaConfig.surfaceWidth, ++ m_xvbaConfig.surfaceHeight, ++ m_xvbaConfig.vidWidth, ++ m_xvbaConfig.vidHeight, ++ avctx->coded_width, ++ avctx->coded_height); ++ return false; ++ } ++ m_xvbaConfig.xvbaSession = sessionOutput.session; ++ ++ // create decode buffers ++ XVBA_Create_DecodeBuff_Input bufferInput; ++ XVBA_Create_DecodeBuff_Output bufferOutput; ++ ++ bufferInput.size = sizeof(bufferInput); ++ bufferInput.session = m_xvbaConfig.xvbaSession; ++ bufferInput.buffer_type = XVBA_PICTURE_DESCRIPTION_BUFFER; ++ bufferInput.num_of_buffers = 1; ++ bufferOutput.size = sizeof(bufferOutput); ++ if (Success != g_XVBA_vtable.CreateDecodeBuffers(&bufferInput, &bufferOutput) ++ || bufferOutput.num_of_buffers_in_list != 1) ++ { ++ SetError(__FUNCTION__, "failed to create picture buffer", __LINE__); ++ return false; ++ } ++ m_xvbaBufferPool.picture_descriptor_buffer = bufferOutput.buffer_list; ++ ++ // data buffer ++ bufferInput.buffer_type = XVBA_DATA_BUFFER; ++ if (Success != g_XVBA_vtable.CreateDecodeBuffers(&bufferInput, &bufferOutput) ++ || bufferOutput.num_of_buffers_in_list != 1) ++ { ++ SetError(__FUNCTION__, "failed to create data buffer", __LINE__); ++ return false; ++ } ++ m_xvbaBufferPool.data_buffer = bufferOutput.buffer_list; ++ ++ // QO Buffer ++ bufferInput.buffer_type = XVBA_QM_BUFFER; ++ if (Success != g_XVBA_vtable.CreateDecodeBuffers(&bufferInput, &bufferOutput) ++ || bufferOutput.num_of_buffers_in_list != 1) ++ { ++ SetError(__FUNCTION__, "failed to create qm buffer", __LINE__); ++ return false; ++ } ++ m_xvbaBufferPool.iq_matrix_buffer = bufferOutput.buffer_list; ++ ++ ++ // initialize output ++ CSingleLock lock(g_graphicsContext); ++ m_xvbaConfig.stats = &m_bufferStats; ++ m_bufferStats.Reset(); ++ m_xvbaOutput.Start(); ++ Message *reply; ++ if (m_xvbaOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::INIT, ++ &reply, ++ 2000, ++ &m_xvbaConfig, ++ sizeof(m_xvbaConfig))) ++ { ++ bool success = reply->signal == COutputControlProtocol::ACC ? true : false; ++ reply->Release(); ++ if (!success) ++ { ++ CLog::Log(LOGERROR, "XVBA::%s - vdpau output returned error", __FUNCTION__); ++ m_xvbaOutput.Dispose(); ++ return false; ++ } ++ } ++ else ++ { ++ CLog::Log(LOGERROR, "XVBA::%s - failed to init output", __FUNCTION__); ++ m_xvbaOutput.Dispose(); ++ return false; ++ } ++ m_inMsgEvent.Reset(); ++ ++ return true; ++} ++ ++void CDecoder::DestroySession(bool precleanup /*= false*/) ++{ ++ // wait for unfinished decoding jobs ++ XbmcThreads::EndTime timer; ++ if (m_xvbaConfig.xvbaSession) ++ { ++ for (unsigned int i = 0; i < m_videoSurfaces.size(); ++i) ++ { ++ xvba_render_state *render = m_videoSurfaces[i]; ++ if (render->surface) ++ { ++ XVBA_Surface_Sync_Input syncInput; ++ XVBA_Surface_Sync_Output syncOutput; ++ syncInput.size = sizeof(syncInput); ++ syncInput.session = m_xvbaConfig.xvbaSession; ++ syncInput.surface = render->surface; ++ syncInput.query_status = XVBA_GET_SURFACE_STATUS; ++ syncOutput.size = sizeof(syncOutput); ++ timer.Set(1000); ++ while(!timer.IsTimePast()) ++ { ++ if (Success != g_XVBA_vtable.SyncSurface(&syncInput, &syncOutput)) ++ { ++ CLog::Log(LOGERROR,"XVBA::DestroySession - failed sync surface"); ++ break; ++ } ++ if (!(syncOutput.status_flags & XVBA_STILL_PENDING)) ++ break; ++ Sleep(10); ++ } ++ if (timer.IsTimePast()) ++ CLog::Log(LOGERROR,"XVBA::DestroySession - unfinished decoding job"); ++ } ++ } ++ } ++ ++ if (precleanup) ++ { ++ Message *reply; ++ if (m_xvbaOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::PRECLEANUP, ++ &reply, ++ 2000)) ++ { ++ bool success = reply->signal == COutputControlProtocol::ACC ? true : false; ++ reply->Release(); ++ if (!success) ++ { ++ CLog::Log(LOGERROR, "XVBA::%s - pre-cleanup returned error", __FUNCTION__); ++ m_displayState = XVBA_ERROR; ++ } ++ } ++ else ++ { ++ CLog::Log(LOGERROR, "XVBA::%s - pre-cleanup timed out", __FUNCTION__); ++ m_displayState = XVBA_ERROR; ++ } ++ } ++ else ++ m_xvbaOutput.Dispose(); ++ ++ XVBA_Destroy_Decode_Buffers_Input bufInput; ++ bufInput.size = sizeof(bufInput); ++ bufInput.num_of_buffers_in_list = 1; ++ bufInput.session = m_xvbaConfig.xvbaSession; ++ ++ for (unsigned int i=0; isurface) ++ { ++ g_XVBA_vtable.DestroySurface(render->surface); ++ render->surface = 0; ++ render->state = 0; ++ render->picture_descriptor = 0; ++ render->iq_matrix = 0; ++ } ++ } ++ ++ if (m_xvbaConfig.xvbaSession) ++ g_XVBA_vtable.DestroyDecode(m_xvbaConfig.xvbaSession); ++ m_xvbaConfig.xvbaSession = 0; ++} ++ ++bool CDecoder::IsSurfaceValid(xvba_render_state *render) ++{ ++ // find render state in queue ++ bool found(false); ++ unsigned int i; ++ for(i = 0; i < m_videoSurfaces.size(); ++i) ++ { ++ if(m_videoSurfaces[i] == render) ++ { ++ found = true; ++ break; ++ } ++ } ++ if (!found) ++ { ++ CLog::Log(LOGERROR,"%s - video surface not found", __FUNCTION__); ++ return false; ++ } ++ if (m_videoSurfaces[i]->surface == 0) ++ { ++ m_videoSurfaces[i]->state = 0; ++ return false; ++ } ++ ++ return true; ++} ++ ++bool CDecoder::EnsureDataControlBuffers(unsigned int num) ++{ ++ if (m_xvbaBufferPool.data_control_buffers.size() >= num) ++ return true; ++ ++ unsigned int missing = num - m_xvbaBufferPool.data_control_buffers.size(); ++ ++ XVBA_Create_DecodeBuff_Input bufferInput; ++ XVBA_Create_DecodeBuff_Output bufferOutput; ++ bufferInput.size = sizeof(bufferInput); ++ bufferInput.session = m_xvbaConfig.xvbaSession; ++ bufferInput.buffer_type = XVBA_DATA_CTRL_BUFFER; ++ bufferInput.num_of_buffers = 1; ++ bufferOutput.size = sizeof(bufferOutput); ++ ++ for (unsigned int i=0; iopaque; ++ CDecoder* xvba = (CDecoder*)ctx->GetHardware(); ++ unsigned int i; ++ ++ CSingleLock lock(xvba->m_decoderSection); ++ ++ xvba_render_state * render = NULL; ++ render = (xvba_render_state*)pic->data[0]; ++ if(!render) ++ { ++ CLog::Log(LOGERROR, "XVBA::FFReleaseBuffer - invalid context handle provided"); ++ return; ++ } ++ ++ for(i=0; i<4; i++) ++ pic->data[i]= NULL; ++ ++ // find render state in queue ++ if (!xvba->IsSurfaceValid(render)) ++ { ++ CLog::Log(LOGDEBUG, "XVBA::FFReleaseBuffer - ignoring invalid buffer"); ++ return; ++ } ++ ++ render->state &= ~FF_XVBA_STATE_USED_FOR_REFERENCE; ++} ++ ++void CDecoder::FFDrawSlice(struct AVCodecContext *avctx, ++ const AVFrame *src, int offset[4], ++ int y, int type, int height) ++{ ++ CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)avctx->opaque; ++ CDecoder* xvba = (CDecoder*)ctx->GetHardware(); ++ ++ CSingleLock lock(xvba->m_decoderSection); ++ ++ if(xvba->m_displayState != XVBA_OPEN) ++ return; ++ ++ if(src->linesize[0] || src->linesize[1] || src->linesize[2] ++ || offset[0] || offset[1] || offset[2]) ++ { ++ CLog::Log(LOGERROR, "XVBA::FFDrawSlice - invalid linesizes or offsets provided"); ++ return; ++ } ++ ++ xvba_render_state * render; ++ ++ render = (xvba_render_state*)src->data[0]; ++ if(!render) ++ { ++ CLog::Log(LOGERROR, "XVBA::FFDrawSlice - invalid context handle provided"); ++ return; ++ } ++ ++ // ffmpeg vc-1 decoder does not flush, make sure the data buffer is still valid ++ if (!xvba->IsSurfaceValid(render)) ++ { ++ CLog::Log(LOGWARNING, "XVBA::FFDrawSlice - ignoring invalid buffer"); ++ return; ++ } ++ ++ // decoding ++ XVBA_Decode_Picture_Start_Input startInput; ++ startInput.size = sizeof(startInput); ++ startInput.session = xvba->m_xvbaConfig.xvbaSession; ++ startInput.target_surface = render->surface; ++ { CSingleLock lock(xvba->m_apiSec); ++ if (Success != g_XVBA_vtable.StartDecodePicture(&startInput)) ++ { ++ xvba->SetError(__FUNCTION__, "failed to start decoding", __LINE__); ++ return; ++ } ++ } ++ ++ XVBA_Decode_Picture_Input picInput; ++ picInput.size = sizeof(picInput); ++ picInput.session = xvba->m_xvbaConfig.xvbaSession; ++ XVBABufferDescriptor *list[2]; ++ picInput.buffer_list = list; ++ list[0] = xvba->m_xvbaBufferPool.picture_descriptor_buffer; ++ picInput.num_of_buffers_in_list = 1; ++ if (avctx->codec_id == CODEC_ID_H264) ++ { ++ list[1] = xvba->m_xvbaBufferPool.iq_matrix_buffer; ++ picInput.num_of_buffers_in_list = 2; ++ } ++ ++ { CSingleLock lock(xvba->m_apiSec); ++ if (Success != g_XVBA_vtable.DecodePicture(&picInput)) ++ { ++ xvba->SetError(__FUNCTION__, "failed to decode picture 1", __LINE__); ++ return; ++ } ++ } ++ ++ if (!xvba->EnsureDataControlBuffers(render->num_slices)) ++ return; ++ ++ XVBADataCtrl *dataControl; ++ int location = 0; ++ xvba->m_xvbaBufferPool.data_buffer->data_size_in_buffer = 0; ++ for (unsigned int j = 0; j < render->num_slices; ++j) ++ { ++ int startCodeSize = 0; ++ uint8_t startCode[] = {0x00,0x00,0x01}; ++ if (avctx->codec_id == CODEC_ID_H264) ++ { ++ startCodeSize = 3; ++ memcpy((uint8_t*)xvba->m_xvbaBufferPool.data_buffer->bufferXVBA+location, ++ startCode, 3); ++ } ++ else if (avctx->codec_id == CODEC_ID_VC1 && ++ (memcmp(render->buffers[j].buffer, startCode, 3) != 0)) ++ { ++ startCodeSize = 4; ++ uint8_t sdf = 0x0d; ++ memcpy((uint8_t*)xvba->m_xvbaBufferPool.data_buffer->bufferXVBA+location, ++ startCode, 3); ++ memcpy((uint8_t*)xvba->m_xvbaBufferPool.data_buffer->bufferXVBA+location+3, ++ &sdf, 1); ++ } ++ // check for potential buffer overwrite ++ unsigned int bytesToCopy = render->buffers[j].size; ++ unsigned int freeBufferSize = xvba->m_xvbaBufferPool.data_buffer->buffer_size - ++ xvba->m_xvbaBufferPool.data_buffer->data_size_in_buffer; ++ if (bytesToCopy >= freeBufferSize) ++ { ++ xvba->SetError(__FUNCTION__, "bitstream buffer too large, maybe corrupted packet", __LINE__); ++ return; ++ } ++ memcpy((uint8_t*)xvba->m_xvbaBufferPool.data_buffer->bufferXVBA+location+startCodeSize, ++ render->buffers[j].buffer, ++ render->buffers[j].size); ++ dataControl = (XVBADataCtrl*)xvba->m_xvbaBufferPool.data_control_buffers[j]->bufferXVBA; ++ dataControl->SliceDataLocation = location; ++ dataControl->SliceBytesInBuffer = render->buffers[j].size+startCodeSize; ++ dataControl->SliceBitsInBuffer = dataControl->SliceBytesInBuffer * 8; ++ xvba->m_xvbaBufferPool.data_buffer->data_size_in_buffer += dataControl->SliceBytesInBuffer; ++ location += dataControl->SliceBytesInBuffer; ++ } ++ ++ int bufSize = xvba->m_xvbaBufferPool.data_buffer->data_size_in_buffer; ++ int padding = bufSize % 128; ++ if (padding) ++ { ++ padding = 128 - padding; ++ xvba->m_xvbaBufferPool.data_buffer->data_size_in_buffer += padding; ++ memset((uint8_t*)xvba->m_xvbaBufferPool.data_buffer->bufferXVBA+bufSize,0,padding); ++ } ++ ++ picInput.num_of_buffers_in_list = 2; ++ for (unsigned int i = 0; i < render->num_slices; ++i) ++ { ++ list[0] = xvba->m_xvbaBufferPool.data_buffer; ++ list[0]->data_offset = 0; ++ list[1] = xvba->m_xvbaBufferPool.data_control_buffers[i]; ++ list[1]->data_size_in_buffer = sizeof(*dataControl); ++ { CSingleLock lock(xvba->m_apiSec); ++ if (Success != g_XVBA_vtable.DecodePicture(&picInput)) ++ { ++ xvba->SetError(__FUNCTION__, "failed to decode picture 2", __LINE__); ++ return; ++ } ++ } ++ } ++ XVBA_Decode_Picture_End_Input endInput; ++ endInput.size = sizeof(endInput); ++ endInput.session = xvba->m_xvbaConfig.xvbaSession; ++ { CSingleLock lock(xvba->m_apiSec); ++ if (Success != g_XVBA_vtable.EndDecodePicture(&endInput)) ++ { ++ xvba->SetError(__FUNCTION__, "failed to decode picture 3", __LINE__); ++ return; ++ } ++ } ++ ++ // decode sync and error ++ XVBA_Surface_Sync_Input syncInput; ++ XVBA_Surface_Sync_Output syncOutput; ++ syncInput.size = sizeof(syncInput); ++ syncInput.session = xvba->m_xvbaConfig.xvbaSession; ++ syncInput.surface = render->surface; ++ syncInput.query_status = XVBA_GET_SURFACE_STATUS; ++ syncOutput.size = sizeof(syncOutput); ++ int64_t start = CurrentHostCounter(); ++ while (1) ++ { ++ { CSingleLock lock(xvba->m_apiSec); ++ if (Success != g_XVBA_vtable.SyncSurface(&syncInput, &syncOutput)) ++ { ++ xvba->SetError(__FUNCTION__, "failed sync surface 1", __LINE__); ++ return; ++ } ++ } ++ if (!(syncOutput.status_flags & XVBA_STILL_PENDING)) ++ break; ++ if (CurrentHostCounter() - start > CurrentHostFrequency()) ++ { ++ xvba->SetError(__FUNCTION__, "timed out waiting for surface", __LINE__); ++ break; ++ } ++ usleep(100); ++ } ++ render->state |= FF_XVBA_STATE_DECODED; ++} ++ ++int CDecoder::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic) ++{ ++ CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)avctx->opaque; ++ CDecoder* xvba = (CDecoder*)ctx->GetHardware(); ++ ++ pic->data[0] = ++ pic->data[1] = ++ pic->data[2] = ++ pic->data[3] = 0; ++ ++ pic->linesize[0] = ++ pic->linesize[1] = ++ pic->linesize[2] = ++ pic->linesize[3] = 0; ++ ++ CSingleLock lock(xvba->m_decoderSection); ++ ++ if(xvba->m_displayState != XVBA_OPEN) ++ return -1; ++ ++ if (xvba->m_xvbaConfig.xvbaSession == 0) ++ { ++ if (!xvba->CreateSession(avctx)) ++ return -1; ++ } ++ ++ xvba_render_state * render = NULL; ++ // find unused surface ++ { CSingleLock lock(xvba->m_videoSurfaceSec); ++ for(unsigned int i = 0; i < xvba->m_videoSurfaces.size(); ++i) ++ { ++ if(!(xvba->m_videoSurfaces[i]->state & (FF_XVBA_STATE_USED_FOR_REFERENCE | FF_XVBA_STATE_USED_FOR_RENDER))) ++ { ++ render = xvba->m_videoSurfaces[i]; ++ render->state = 0; ++ break; ++ } ++ } ++ } ++ ++ // create a new render state ++ if (render == NULL) ++ { ++ render = (xvba_render_state*)calloc(sizeof(xvba_render_state), 1); ++ if (render == NULL) ++ { ++ CLog::Log(LOGERROR, "XVBA::FFGetBuffer - calloc failed"); ++ return -1; ++ } ++ render->surface = 0; ++ render->buffers_alllocated = 0; ++ CSingleLock lock(xvba->m_videoSurfaceSec); ++ xvba->m_videoSurfaces.push_back(render); ++ } ++ ++ // create a new surface ++ if (render->surface == 0) ++ { ++ XVBA_Create_Surface_Input surfaceInput; ++ XVBA_Create_Surface_Output surfaceOutput; ++ surfaceInput.size = sizeof(surfaceInput); ++ surfaceInput.surface_type = xvba->m_xvbaConfig.decoderCap.surface_type; ++ surfaceInput.width = xvba->m_xvbaConfig.surfaceWidth; ++ surfaceInput.height = xvba->m_xvbaConfig.surfaceHeight; ++ surfaceInput.session = xvba->m_xvbaConfig.xvbaSession; ++ surfaceOutput.size = sizeof(surfaceOutput); ++ { CSingleLock lock(xvba->m_apiSec); ++ if (Success != g_XVBA_vtable.CreateSurface(&surfaceInput, &surfaceOutput)) ++ { ++ xvba->SetError(__FUNCTION__, "failed to create video surface", __LINE__); ++ return -1; ++ } ++ } ++ render->surface = surfaceOutput.surface; ++ render->picture_descriptor = (XVBAPictureDescriptor *)xvba->m_xvbaBufferPool.picture_descriptor_buffer->bufferXVBA; ++ render->iq_matrix = (XVBAQuantMatrixAvc *)xvba->m_xvbaBufferPool.iq_matrix_buffer->bufferXVBA; ++ CLog::Log(LOGDEBUG, "XVBA::FFGetBuffer - created video surface"); ++ } ++ ++ if (render == NULL) ++ return -1; ++ ++ pic->data[0] = (uint8_t*)render; ++ ++ pic->type= FF_BUFFER_TYPE_USER; ++ ++ render->state |= FF_XVBA_STATE_USED_FOR_REFERENCE; ++ render->state &= ~FF_XVBA_STATE_DECODED; ++ pic->reordered_opaque= avctx->reordered_opaque; ++ ++ return 0; ++} ++ ++int CDecoder::Decode(AVCodecContext* avctx, AVFrame* frame) ++{ ++ int result = Check(avctx); ++ if (result) ++ return result; ++ ++ CSingleLock lock(m_decoderSection); ++ ++ if(frame) ++ { // we have a new frame from decoder ++ ++ xvba_render_state * render = (xvba_render_state*)frame->data[0]; ++ if(!render) ++ { ++ CLog::Log(LOGERROR, "XVBA::Decode - no render buffer"); ++ return VC_ERROR; ++ } ++ ++ // ffmpeg vc-1 decoder does not flush, make sure the data buffer is still valid ++ if (!IsSurfaceValid(render)) ++ { ++ CLog::Log(LOGWARNING, "XVBA::Decode - ignoring invalid buffer"); ++ return VC_BUFFER; ++ } ++ if (!(render->state & FF_XVBA_STATE_DECODED)) ++ { ++ CLog::Log(LOGDEBUG, "XVBA::Decode - ffmpeg failed"); ++ return VC_BUFFER; ++ } ++ ++ CSingleLock lock(m_videoSurfaceSec); ++ render->state |= FF_XVBA_STATE_USED_FOR_RENDER; ++ lock.Leave(); ++ ++ // send frame to output for processing ++ CXvbaDecodedPicture pic; ++ memset(&pic.DVDPic, 0, sizeof(pic.DVDPic)); ++ ((CDVDVideoCodecFFmpeg*)avctx->opaque)->GetPictureCommon(&pic.DVDPic); ++ pic.render = render; ++ m_bufferStats.IncDecoded(); ++ m_xvbaOutput.m_dataPort.SendOutMessage(COutputDataProtocol::NEWFRAME, &pic, sizeof(pic)); ++ ++ m_codecControl = pic.DVDPic.iFlags & (DVP_FLAG_DRAIN | DVP_FLAG_NO_POSTPROC); ++ } ++ ++ int retval = 0; ++ uint16_t decoded, processed, render; ++ Message *msg; ++ while (m_xvbaOutput.m_controlPort.ReceiveInMessage(&msg)) ++ { ++ if (msg->signal == COutputControlProtocol::ERROR) ++ { ++ m_displayState = XVBA_ERROR; ++ retval |= VC_ERROR; ++ } ++ msg->Release(); ++ } ++ ++ m_bufferStats.Get(decoded, processed, render); ++ ++ uint64_t startTime = CurrentHostCounter(); ++ while (!retval) ++ { ++ if (m_xvbaOutput.m_dataPort.ReceiveInMessage(&msg)) ++ { ++ if (msg->signal == COutputDataProtocol::PICTURE) ++ { ++ if (m_presentPicture) ++ { ++ m_presentPicture->ReturnUnused(); ++ m_presentPicture = 0; ++ } ++ ++ m_presentPicture = *(CXvbaRenderPicture**)msg->data; ++ m_presentPicture->xvba = this; ++ m_bufferStats.DecRender(); ++ m_bufferStats.Get(decoded, processed, render); ++ retval |= VC_PICTURE; ++ } ++ msg->Release(); ++ } ++ else if (m_xvbaOutput.m_controlPort.ReceiveInMessage(&msg)) ++ { ++ if (msg->signal == COutputControlProtocol::STATS) ++ { ++ m_bufferStats.Get(decoded, processed, render); ++ } ++ else ++ { ++ m_displayState = XVBA_ERROR; ++ retval |= VC_ERROR; ++ } ++ msg->Release(); ++ } ++ ++ if ((m_codecControl & DVP_FLAG_DRAIN)) ++ { ++ if (decoded + processed + render < 2) ++ { ++ retval |= VC_BUFFER; ++ } ++ } ++ else ++ { ++ if (decoded + processed + render < 4) ++ { ++ retval |= VC_BUFFER; ++ } ++ } ++ ++ if (!retval && !m_inMsgEvent.WaitMSec(2000)) ++ break; ++ } ++ uint64_t diff = CurrentHostCounter() - startTime; ++ if (retval & VC_PICTURE) ++ { ++ m_bufferStats.SetParams(diff, m_speed); ++ if (diff*1000/CurrentHostFrequency() > 50) ++ CLog::Log(LOGDEBUG,"XVBA::Decode long wait: %d", (int)((diff*1000)/CurrentHostFrequency())); ++ } ++ ++ if (!retval) ++ { ++ CLog::Log(LOGERROR, "XVBA::%s - timed out waiting for output message", __FUNCTION__); ++ m_displayState = XVBA_ERROR; ++ retval |= VC_ERROR; ++ } ++ ++ return retval; ++ ++} ++ ++bool CDecoder::GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture) ++{ ++ CSingleLock lock(m_decoderSection); ++ ++ if (m_displayState != XVBA_OPEN) ++ return false; ++ ++ *picture = m_presentPicture->DVDPic; ++ picture->xvba = m_presentPicture; ++ ++ return true; ++} ++ ++void CDecoder::ReturnRenderPicture(CXvbaRenderPicture *renderPic) ++{ ++ m_xvbaOutput.m_dataPort.SendOutMessage(COutputDataProtocol::RETURNPIC, &renderPic, sizeof(renderPic)); ++} ++ ++ ++//void CDecoder::CopyYV12(int index, uint8_t *dest) ++//{ ++// CSharedLock lock(m_decoderSection); ++// ++// { CSharedLock dLock(m_displaySection); ++// if(m_displayState != XVBA_OPEN) ++// return; ++// } ++// ++// if (!m_flipBuffer[index].outPic) ++// { ++// CLog::Log(LOGWARNING, "XVBA::Present: present picture is NULL"); ++// return; ++// } ++// ++// XVBA_GetSurface_Target target; ++// target.size = sizeof(target); ++// target.surfaceType = XVBA_YV12; ++// target.flag = XVBA_FRAME; ++// ++// XVBA_Get_Surface_Input input; ++// input.size = sizeof(input); ++// input.session = m_xvbaSession; ++// input.src_surface = m_flipBuffer[index].outPic->render->surface; ++// input.target_buffer = dest; ++// input.target_pitch = m_surfaceWidth; ++// input.target_width = m_surfaceWidth; ++// input.target_height = m_surfaceHeight; ++// input.target_parameter = target; ++// { CSingleLock lock(m_apiSec); ++// if (Success != g_XVBA_vtable.GetSurface(&input)) ++// { ++// CLog::Log(LOGERROR,"(XVBA::CopyYV12) failed to get surface"); ++// } ++// } ++//} ++ ++void CDecoder::Reset() ++{ ++ CSingleLock lock(m_decoderSection); ++ ++ if (!m_xvbaConfig.xvbaSession) ++ return; ++ ++ Message *reply; ++ if (m_xvbaOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::FLUSH, ++ &reply, ++ 2000)) ++ { ++ bool success = reply->signal == COutputControlProtocol::ACC ? true : false; ++ reply->Release(); ++ if (!success) ++ { ++ CLog::Log(LOGERROR, "XVBA::%s - flush returned error", __FUNCTION__); ++ m_displayState = XVBA_ERROR; ++ } ++ else ++ m_bufferStats.Reset(); ++ } ++ else ++ { ++ CLog::Log(LOGERROR, "XVBA::%s - flush timed out", __FUNCTION__); ++ m_displayState = XVBA_ERROR; ++ } ++} ++ ++bool CDecoder::CanSkipDeint() ++{ ++ return m_bufferStats.CanSkipDeint(); ++} ++ ++void CDecoder::SetSpeed(int speed) ++{ ++ m_speed = speed; ++} ++ ++//----------------------------------------------------------------------------- ++// RenderPicture ++//----------------------------------------------------------------------------- ++ ++CXvbaRenderPicture* CXvbaRenderPicture::Acquire() ++{ ++ CSingleLock lock(*renderPicSection); ++ ++ if (refCount == 0) ++ xvba->Acquire(); ++ ++ refCount++; ++ return this; ++} ++ ++long CXvbaRenderPicture::Release() ++{ ++ CSingleLock lock(*renderPicSection); ++ ++ refCount--; ++ if (refCount > 0) ++ return refCount; ++ ++ lock.Leave(); ++ xvba->ReturnRenderPicture(this); ++ xvba->ReleasePicReference(); ++ ++ return refCount; ++} ++ ++void CXvbaRenderPicture::ReturnUnused() ++{ ++ { CSingleLock lock(*renderPicSection); ++ if (refCount > 0) ++ return; ++ } ++ if (xvba) ++ xvba->ReturnRenderPicture(this); ++} ++ ++//----------------------------------------------------------------------------- ++// Output ++//----------------------------------------------------------------------------- ++COutput::COutput(CEvent *inMsgEvent) : ++ CThread("XVBA Output Thread"), ++ m_controlPort("OutputControlPort", inMsgEvent, &m_outMsgEvent), ++ m_dataPort("OutputDataPort", inMsgEvent, &m_outMsgEvent) ++{ ++ m_inMsgEvent = inMsgEvent; ++ ++ CXvbaRenderPicture pic; ++ pic.renderPicSection = &m_bufferPool.renderPicSec; ++ pic.refCount = 0; ++ for (unsigned int i = 0; i < NUM_RENDER_PICS; i++) ++ { ++ m_bufferPool.allRenderPics.push_back(pic); ++ } ++ for (unsigned int i = 0; i < m_bufferPool.allRenderPics.size(); ++i) ++ { ++ m_bufferPool.freeRenderPics.push_back(&m_bufferPool.allRenderPics[i]); ++ } ++} ++ ++void COutput::Start() ++{ ++ Create(); ++} ++ ++COutput::~COutput() ++{ ++ Dispose(); ++ ++ m_bufferPool.freeRenderPics.clear(); ++ m_bufferPool.usedRenderPics.clear(); ++ m_bufferPool.allRenderPics.clear(); ++} ++ ++void COutput::Dispose() ++{ ++ CSingleLock lock(g_graphicsContext); ++ m_bStop = true; ++ m_outMsgEvent.Set(); ++ StopThread(); ++ m_controlPort.Purge(); ++ m_dataPort.Purge(); ++} ++ ++void COutput::OnStartup() ++{ ++ CLog::Log(LOGNOTICE, "COutput::OnStartup: Output Thread created"); ++} ++ ++void COutput::OnExit() ++{ ++ CLog::Log(LOGNOTICE, "COutput::OnExit: Output Thread terminated"); ++} ++ ++enum OUTPUT_STATES ++{ ++ O_TOP = 0, // 0 ++ O_TOP_ERROR, // 1 ++ O_TOP_UNCONFIGURED, // 2 ++ O_TOP_CONFIGURED, // 3 ++ O_TOP_CONFIGURED_WAIT_RES1, // 4 ++ O_TOP_CONFIGURED_WAIT_DEC, // 5 ++ O_TOP_CONFIGURED_STEP1, // 6 ++ O_TOP_CONFIGURED_WAIT_RES2, // 7 ++ O_TOP_CONFIGURED_STEP2, // 8 ++}; ++ ++int OUTPUT_parentStates[] = { ++ -1, ++ 0, //TOP_ERROR ++ 0, //TOP_UNCONFIGURED ++ 0, //TOP_CONFIGURED ++ 3, //TOP_CONFIGURED_WAIT_RES1 ++ 3, //TOP_CONFIGURED_WAIT_DEC ++ 3, //TOP_CONFIGURED_STEP1 ++ 3, //TOP_CONFIGURED_WAIT_RES2 ++ 3, //TOP_CONFIGURED_STEP2 ++}; ++ ++void COutput::StateMachine(int signal, Protocol *port, Message *msg) ++{ ++ for (int state = m_state; ; state = OUTPUT_parentStates[state]) ++ { ++ switch (state) ++ { ++ case O_TOP: // TOP ++ if (port == &m_controlPort) ++ { ++ switch (signal) ++ { ++ case COutputControlProtocol::FLUSH: ++ msg->Reply(COutputControlProtocol::ACC); ++ return; ++ case COutputControlProtocol::PRECLEANUP: ++ msg->Reply(COutputControlProtocol::ACC); ++ return; ++ default: ++ break; ++ } ++ } ++ else if (port == &m_dataPort) ++ { ++ switch (signal) ++ { ++ case COutputDataProtocol::RETURNPIC: ++ CXvbaRenderPicture *pic; ++ pic = *((CXvbaRenderPicture**)msg->data); ++ ProcessReturnPicture(pic); ++ return; ++ default: ++ break; ++ } ++ } ++ { ++ std::string portName = port == NULL ? "timer" : port->portName; ++ CLog::Log(LOGWARNING, "COutput::%s - signal: %d form port: %s not handled for state: %d", __FUNCTION__, signal, portName.c_str(), m_state); ++ } ++ return; ++ ++ case O_TOP_ERROR: ++ m_extTimeout = 1000; ++ break; ++ ++ case O_TOP_UNCONFIGURED: ++ if (port == &m_controlPort) ++ { ++ switch (signal) ++ { ++ case COutputControlProtocol::INIT: ++ CXvbaConfig *data; ++ data = (CXvbaConfig*)msg->data; ++ if (data) ++ { ++ m_config = *data; ++ } ++ Init(); ++ EnsureBufferPool(); ++ if (!m_xvbaError) ++ { ++ m_state = O_TOP_CONFIGURED_WAIT_RES1; ++ msg->Reply(COutputControlProtocol::ACC); ++ } ++ else ++ { ++ m_state = O_TOP_ERROR; ++ msg->Reply(COutputControlProtocol::ERROR); ++ } ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case O_TOP_CONFIGURED: ++ if (port == &m_controlPort) ++ { ++ switch (signal) ++ { ++ case COutputControlProtocol::FLUSH: ++ m_state = O_TOP_CONFIGURED_WAIT_RES1; ++ Flush(); ++ msg->Reply(COutputControlProtocol::ACC); ++ return; ++ case COutputControlProtocol::PRECLEANUP: ++ m_state = O_TOP_UNCONFIGURED; ++ m_extTimeout = 10000; ++ Flush(); ++ ReleaseBufferPool(true); ++ msg->Reply(COutputControlProtocol::ACC); ++ return; ++ default: ++ break; ++ } ++ } ++ else if (port == &m_dataPort) ++ { ++ switch (signal) ++ { ++ case COutputDataProtocol::NEWFRAME: ++ CXvbaDecodedPicture *frame; ++ frame = (CXvbaDecodedPicture*)msg->data; ++ if (frame) ++ { ++ m_decodedPics.push(*frame); ++ m_extTimeout = 0; ++ } ++ return; ++ case COutputDataProtocol::RETURNPIC: ++ CXvbaRenderPicture *pic; ++ pic = *((CXvbaRenderPicture**)msg->data); ++ ProcessReturnPicture(pic); ++ m_controlPort.SendInMessage(COutputControlProtocol::STATS); ++ m_extTimeout = 0; ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case O_TOP_CONFIGURED_WAIT_RES1: ++ if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case COutputControlProtocol::TIMEOUT: ++ if (!m_decodedPics.empty() && FindFreeSurface() >= 0 && !m_bufferPool.freeRenderPics.empty()) ++ { ++ m_state = O_TOP_CONFIGURED_WAIT_DEC; ++ m_bStateMachineSelfTrigger = true; ++ } ++ else ++ { ++ if (m_extTimeout != 0) ++ { ++ uint16_t decoded, processed, render; ++ m_config.stats->Get(decoded, processed, render); ++// CLog::Log(LOGDEBUG, "CVDPAU::COutput - timeout idle: decoded: %d, proc: %d, render: %d", decoded, processed, render); ++ } ++ m_extTimeout = 100; ++ } ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case O_TOP_CONFIGURED_WAIT_DEC: ++ if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case COutputControlProtocol::TIMEOUT: ++ if (IsDecodingFinished()) ++ { ++ m_state = O_TOP_CONFIGURED_STEP1; ++ m_bStateMachineSelfTrigger = true; ++ } ++ else ++ { ++ m_extTimeout = 1; ++ } ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case O_TOP_CONFIGURED_STEP1: ++ if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case COutputControlProtocol::TIMEOUT: ++ m_processPicture = m_decodedPics.front(); ++ m_decodedPics.pop(); ++ InitCycle(); ++ CXvbaRenderPicture *pic; ++ pic = ProcessPicture(); ++ if (pic) ++ { ++ m_config.stats->IncRender(); ++ m_dataPort.SendInMessage(COutputDataProtocol::PICTURE, &pic, sizeof(pic)); ++ } ++ if (m_xvbaError) ++ { ++ m_state = O_TOP_ERROR; ++ return; ++ } ++ if (m_deinterlacing && !m_deintSkip) ++ { ++ m_state = O_TOP_CONFIGURED_WAIT_RES2; ++ m_extTimeout = 0; ++ } ++ else ++ { ++ FiniCycle(); ++ m_state = O_TOP_CONFIGURED_WAIT_RES1; ++ m_extTimeout = 0; ++ } ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case O_TOP_CONFIGURED_WAIT_RES2: ++ if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case COutputControlProtocol::TIMEOUT: ++ if (FindFreeSurface() >= 0 && !m_bufferPool.freeRenderPics.empty()) ++ { ++ m_state = O_TOP_CONFIGURED_STEP2; ++ m_bStateMachineSelfTrigger = true; ++ } ++ else ++ { ++ if (m_extTimeout != 0) ++ { ++ uint16_t decoded, processed, render; ++ m_config.stats->Get(decoded, processed, render); ++ CLog::Log(LOGDEBUG, "CVDPAU::COutput - timeout idle: decoded: %d, proc: %d, render: %d", decoded, processed, render); ++ } ++ m_extTimeout = 100; ++ } ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case O_TOP_CONFIGURED_STEP2: ++ if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case COutputControlProtocol::TIMEOUT: ++ CXvbaRenderPicture *pic; ++ m_deintStep = 1; ++ pic = ProcessPicture(); ++ if (pic) ++ { ++ m_config.stats->IncRender(); ++ m_dataPort.SendInMessage(COutputDataProtocol::PICTURE, &pic, sizeof(pic)); ++ } ++ if (m_xvbaError) ++ { ++ m_state = O_TOP_ERROR; ++ return; ++ } ++ FiniCycle(); ++ m_state = O_TOP_CONFIGURED_WAIT_RES1; ++ m_extTimeout = 0; ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ default: // we are in no state, should not happen ++ CLog::Log(LOGERROR, "COutput::%s - no valid state: %d", __FUNCTION__, m_state); ++ return; ++ } ++ } // for ++} ++ ++void COutput::Process() ++{ ++ Message *msg; ++ Protocol *port; ++ bool gotMsg; ++ ++ m_state = O_TOP_UNCONFIGURED; ++ m_extTimeout = 1000; ++ m_bStateMachineSelfTrigger = false; ++ ++ while (!m_bStop) ++ { ++ gotMsg = false; ++ ++ if (m_bStateMachineSelfTrigger) ++ { ++ m_bStateMachineSelfTrigger = false; ++ // self trigger state machine ++ StateMachine(msg->signal, port, msg); ++ if (!m_bStateMachineSelfTrigger) ++ { ++ msg->Release(); ++ msg = NULL; ++ } ++ continue; ++ } ++ // check control port ++ else if (m_controlPort.ReceiveOutMessage(&msg)) ++ { ++ gotMsg = true; ++ port = &m_controlPort; ++ } ++ // check data port ++ else if (m_dataPort.ReceiveOutMessage(&msg)) ++ { ++ gotMsg = true; ++ port = &m_dataPort; ++ } ++ if (gotMsg) ++ { ++ StateMachine(msg->signal, port, msg); ++ if (!m_bStateMachineSelfTrigger) ++ { ++ msg->Release(); ++ msg = NULL; ++ } ++ continue; ++ } ++ ++ // wait for message ++ else if (m_outMsgEvent.WaitMSec(m_extTimeout)) ++ { ++ continue; ++ } ++ // time out ++ else ++ { ++ msg = m_controlPort.GetMessage(); ++ msg->signal = COutputControlProtocol::TIMEOUT; ++ port = 0; ++ // signal timeout to state machine ++ StateMachine(msg->signal, port, msg); ++ if (!m_bStateMachineSelfTrigger) ++ { ++ msg->Release(); ++ msg = NULL; ++ } ++ } ++ } ++ Flush(); ++ Uninit(); ++} ++ ++bool COutput::Init() ++{ ++ if (!CreateGlxContext()) ++ return false; ++ ++ m_xvbaError = false; ++ m_processPicture.render = 0; ++ m_fence = None; ++ ++ return true; ++} ++ ++bool COutput::Uninit() ++{ ++ ReleaseBufferPool(); ++ DestroyGlxContext(); ++ return true; ++} ++ ++void COutput::Flush() ++{ ++ while (!m_decodedPics.empty()) ++ { ++ CXvbaDecodedPicture pic = m_decodedPics.front(); ++ m_decodedPics.pop(); ++ CSingleLock lock(*m_config.videoSurfaceSec); ++ if (pic.render) ++ pic.render->state &= ~(FF_XVBA_STATE_USED_FOR_RENDER | FF_XVBA_STATE_DECODED); ++ } ++ ++ if (m_processPicture.render) ++ { ++ CSingleLock lock(*m_config.videoSurfaceSec); ++ m_processPicture.render->state &= ~(FF_XVBA_STATE_USED_FOR_RENDER | FF_XVBA_STATE_DECODED); ++ m_processPicture.render = 0; ++ } ++ ++ Message *msg; ++ while (m_dataPort.ReceiveOutMessage(&msg)) ++ { ++ if (msg->signal == COutputDataProtocol::NEWFRAME) ++ { ++ CXvbaDecodedPicture pic = *(CXvbaDecodedPicture*)msg->data; ++ CSingleLock lock(*m_config.videoSurfaceSec); ++ if (pic.render) ++ pic.render->state &= ~(FF_XVBA_STATE_USED_FOR_RENDER | FF_XVBA_STATE_DECODED); ++ } ++ else if (msg->signal == COutputDataProtocol::RETURNPIC) ++ { ++ CXvbaRenderPicture *pic; ++ pic = *((CXvbaRenderPicture**)msg->data); ++ ProcessReturnPicture(pic); ++ } ++ msg->Release(); ++ } ++ ++ while (m_dataPort.ReceiveInMessage(&msg)) ++ { ++ if (msg->signal == COutputDataProtocol::PICTURE) ++ { ++ CXvbaRenderPicture *pic; ++ pic = *((CXvbaRenderPicture**)msg->data); ++ ProcessReturnPicture(pic); ++ } ++ } ++} ++ ++bool COutput::IsDecodingFinished() ++{ ++ return true; ++ ++ // check for decoding to be finished ++ CXvbaDecodedPicture decodedPic = m_decodedPics.front(); ++ ++ XVBA_Surface_Sync_Input syncInput; ++ XVBA_Surface_Sync_Output syncOutput; ++ syncInput.size = sizeof(syncInput); ++ syncInput.session = m_config.xvbaSession; ++ syncInput.surface = decodedPic.render->surface; ++ syncInput.query_status = XVBA_GET_SURFACE_STATUS; ++ syncOutput.size = sizeof(syncOutput); ++ { CSingleLock lock(*(m_config.apiSec)); ++ if (Success != g_XVBA_vtable.SyncSurface(&syncInput, &syncOutput)) ++ { ++ CLog::Log(LOGERROR,"XVBA - failed sync surface"); ++ m_xvbaError = true; ++ return false; ++ } ++ } ++ if (!(syncOutput.status_flags & XVBA_STILL_PENDING)) ++ return true; ++ ++ return false; ++} ++ ++CXvbaRenderPicture* COutput::ProcessPicture() ++{ ++ CXvbaRenderPicture *retPic = 0; ++ ++ if (m_deintStep == 1) ++ { ++ if(m_field == XVBA_TOP_FIELD) ++ m_field = XVBA_BOTTOM_FIELD; ++ else ++ m_field = XVBA_TOP_FIELD; ++ } ++ ++ // find unused shared surface ++ unsigned int idx = FindFreeSurface(); ++ XvbaBufferPool::GLVideoSurface *glSurface = &m_bufferPool.glSurfaces[idx]; ++ glSurface->used = true; ++ glSurface->field = m_field; ++ glSurface->render = m_processPicture.render; ++ glSurface->transferred = false; ++ ++ int cmd = 0; ++ m_config.stats->GetCmd(cmd); ++ ++// if (m_fence) ++// glDeleteSync(m_fence); ++// m_fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); ++ ++ // transfer surface ++ XVBA_Transfer_Surface_Input transInput; ++ transInput.size = sizeof(transInput); ++ transInput.session = m_config.xvbaSession; ++ transInput.src_surface = m_processPicture.render->surface; ++ transInput.target_surface = glSurface->glSurface; ++ transInput.flag = m_field; ++ { CSingleLock lock(*(m_config.apiSec)); ++ if (Success != g_XVBA_vtable.TransferSurface(&transInput)) ++ { ++ CLog::Log(LOGERROR,"(XVBA) failed to transfer surface"); ++ m_xvbaError = true; ++ return retPic; ++ } ++ } ++ ++ // prepare render pic ++ retPic = m_bufferPool.freeRenderPics.front(); ++ m_bufferPool.freeRenderPics.pop_front(); ++ m_bufferPool.usedRenderPics.push_back(retPic); ++ retPic->sourceIdx = glSurface->id; ++ retPic->DVDPic = m_processPicture.DVDPic; ++ retPic->valid = true; ++ retPic->texture = glSurface->texture; ++ retPic->crop = CRect(0,0,0,0); ++ retPic->texWidth = m_config.surfaceWidth; ++ retPic->texHeight = m_config.surfaceHeight; ++ retPic->xvbaOutput = this; ++ ++ // set repeat pic for de-interlacing ++ if (m_deinterlacing) ++ { ++ if (m_deintStep == 1) ++ { ++ retPic->DVDPic.pts = DVD_NOPTS_VALUE; ++ retPic->DVDPic.dts = DVD_NOPTS_VALUE; ++ } ++ retPic->DVDPic.iRepeatPicture = 0.0; ++ } ++ ++ return retPic; ++} ++ ++void COutput::ProcessReturnPicture(CXvbaRenderPicture *pic) ++{ ++ std::deque::iterator it; ++ it = std::find(m_bufferPool.usedRenderPics.begin(), m_bufferPool.usedRenderPics.end(), pic); ++ if (it == m_bufferPool.usedRenderPics.end()) ++ { ++ CLog::Log(LOGWARNING, "COutput::ProcessReturnPicture - pic not found"); ++ return; ++ } ++ m_bufferPool.usedRenderPics.erase(it); ++ m_bufferPool.freeRenderPics.push_back(pic); ++ if (!pic->valid) ++ { ++ CLog::Log(LOGDEBUG, "COutput::%s - return of invalid render pic", __FUNCTION__); ++ return; ++ } ++ ++ xvba_render_state *render = m_bufferPool.glSurfaces[pic->sourceIdx].render; ++ if (render) ++ { ++ // check if video surface is referenced by other glSurfaces ++ bool referenced(false); ++ for (unsigned int i=0; isourceIdx) ++ continue; ++ if (m_bufferPool.glSurfaces[i].render == render) ++ { ++ referenced = true; ++ break; ++ } ++ } ++ if (m_processPicture.render == render) ++ referenced = true; ++ ++ // release video surface ++ if (!referenced) ++ { ++ CSingleLock lock(*m_config.videoSurfaceSec); ++ render->state &= ~(FF_XVBA_STATE_USED_FOR_RENDER | FF_XVBA_STATE_DECODED); ++ } ++ ++ // unreference video surface ++ m_bufferPool.glSurfaces[pic->sourceIdx].render = 0; ++ ++ m_bufferPool.glSurfaces[pic->sourceIdx].used = false; ++ return; ++ } ++} ++ ++int COutput::FindFreeSurface() ++{ ++ // find free shared surface ++ unsigned int i; ++ for (i = 0; i < m_bufferPool.glSurfaces.size(); ++i) ++ { ++ if (!m_bufferPool.glSurfaces[i].used) ++ break; ++ } ++ if (i == m_bufferPool.glSurfaces.size()) ++ return -1; ++ else ++ return i; ++} ++ ++void COutput::InitCycle() ++{ ++ uint64_t latency; ++ int speed; ++ m_config.stats->GetParams(latency, speed); ++ latency = (latency*1000)/CurrentHostFrequency(); ++ ++ m_config.stats->SetCanSkipDeint(false); ++ ++ EDEINTERLACEMODE mode = g_settings.m_currentVideoSettings.m_DeinterlaceMode; ++ EINTERLACEMETHOD method = g_settings.m_currentVideoSettings.m_InterlaceMethod; ++ bool interlaced = m_processPicture.DVDPic.iFlags & DVP_FLAG_INTERLACED; ++ ++ if (mode == VS_DEINTERLACEMODE_FORCE || ++ (mode == VS_DEINTERLACEMODE_AUTO && interlaced)) ++ { ++ if((method == VS_INTERLACEMETHOD_AUTO && interlaced) ++ || method == VS_INTERLACEMETHOD_XVBA) ++ { ++ m_deinterlacing = true; ++ m_deintSkip = false; ++ m_config.stats->SetCanSkipDeint(true); ++ ++ if (m_processPicture.DVDPic.iFlags & DVP_FLAG_DROPDEINT) ++ { ++ m_deintSkip = true; ++ } ++ ++ // do only half deinterlacing ++ if (speed != DVD_PLAYSPEED_NORMAL || !g_graphicsContext.IsFullScreenVideo()) ++ { ++ m_config.stats->SetCanSkipDeint(false); ++ m_deintSkip = true; ++ } ++ ++ if(m_processPicture.DVDPic.iFlags & DVP_FLAG_TOP_FIELD_FIRST) ++ m_field = XVBA_TOP_FIELD; ++ else ++ m_field = XVBA_BOTTOM_FIELD; ++ } ++ } ++ else ++ { ++ m_deinterlacing = false; ++ m_field = XVBA_FRAME; ++ } ++ ++ m_processPicture.DVDPic.format = RENDER_FMT_XVBA; ++ m_processPicture.DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST | ++ DVP_FLAG_REPEAT_TOP_FIELD | ++ DVP_FLAG_INTERLACED); ++ m_processPicture.DVDPic.iWidth = m_config.vidWidth; ++ m_processPicture.DVDPic.iHeight = m_config.vidHeight; ++ ++ m_deintStep = 0; ++} ++ ++void COutput::FiniCycle() ++{ ++// { CSingleLock lock(*m_config.videoSurfaceSec); ++// m_processPicture.render->state &= ~FF_XVBA_STATE_USED_FOR_RENDER; ++// } ++ m_processPicture.render = 0; ++ m_config.stats->DecDecoded(); ++} ++ ++bool COutput::EnsureBufferPool() ++{ ++ if (m_config.useSharedSurfaces && m_bufferPool.glSurfaces.empty()) ++ { ++ GLenum textureTarget; ++ if (!glewIsSupported("GL_ARB_texture_non_power_of_two") && glewIsSupported("GL_ARB_texture_rectangle")) ++ { ++ textureTarget = GL_TEXTURE_RECTANGLE_ARB; ++ } ++ else ++ textureTarget = GL_TEXTURE_2D; ++ ++ // create shared surfaces ++ XvbaBufferPool::GLVideoSurface surface; ++ for (unsigned int i = 0; i < NUM_RENDER_PICS; ++i) ++ { ++ glEnable(textureTarget); ++ glGenTextures(1, &surface.texture); ++ glBindTexture(textureTarget, surface.texture); ++ glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); ++ glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); ++ glTexParameteri(textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); ++ glTexParameteri(textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); ++ glPixelStorei(GL_UNPACK_ALIGNMENT, 4); ++ glTexImage2D(textureTarget, 0, GL_RGBA, m_config.surfaceWidth, m_config.surfaceHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); ++ ++ XVBA_Create_GLShared_Surface_Input surfInput; ++ XVBA_Create_GLShared_Surface_Output surfOutput; ++ surfInput.size = sizeof(surfInput); ++ surfInput.session = m_config.xvbaSession; ++ surfInput.gltexture = surface.texture; ++ surfInput.glcontext = m_glContext; ++ surfOutput.size = sizeof(surfOutput); ++ surfOutput.surface = 0; ++ if (Success != g_XVBA_vtable.CreateGLSharedSurface(&surfInput, &surfOutput)) ++ { ++ CLog::Log(LOGERROR,"(XVBA) failed to create shared surface"); ++ m_xvbaError = true; ++ break; ++ } ++ CLog::Log(LOGDEBUG, "XVBA::GetTexture - created shared surface"); ++ ++ surface.glSurface = surfOutput.surface; ++ surface.id = i; ++ surface.used = false; ++ surface.render = 0; ++ m_bufferPool.glSurfaces.push_back(surface); ++ } ++ glDisable(textureTarget); ++ } ++ ++ return true; ++} ++ ++void COutput::ReleaseBufferPool(bool precleanup /*= false*/) ++{ ++// if (m_fence) ++// { ++// uint64_t maxTimeout = 1000000000LL; ++// glClientWaitSync(m_fence, GL_SYNC_FLUSH_COMMANDS_BIT, maxTimeout); ++// glDeleteSync(m_fence); ++// m_fence = None; ++// } ++ ++ CSingleLock lock(m_bufferPool.renderPicSec); ++ ++ for (unsigned int i = 0; i < m_bufferPool.glSurfaces.size(); ++i) ++ { ++ if (m_bufferPool.glSurfaces[i].glSurface) ++ { ++ g_XVBA_vtable.DestroySurface(m_bufferPool.glSurfaces[i].glSurface); ++ m_bufferPool.glSurfaces[i].glSurface = 0; ++ } ++ if (m_bufferPool.glSurfaces[i].texture && !precleanup) ++ { ++ glDeleteTextures(1, &m_bufferPool.glSurfaces[i].texture); ++ m_bufferPool.glSurfaces[i].texture = 0; ++ } ++ m_bufferPool.glSurfaces[i].render = 0; ++ m_bufferPool.glSurfaces[i].used = true; ++ } ++ ++ if (!precleanup) ++ { ++ m_bufferPool.glSurfaces.clear(); ++ ++ // invalidate all used render pictures ++ for (unsigned int i = 0; i < m_bufferPool.usedRenderPics.size(); ++i) ++ { ++ m_bufferPool.usedRenderPics[i]->valid = false; ++ } ++ } ++} ++ ++void COutput::PreReleaseBufferPool() ++{ ++ CSingleLock lock(m_bufferPool.renderPicSec); ++ ++ if (m_config.useSharedSurfaces) ++ { ++ for (unsigned int i = 0; i < m_bufferPool.glSurfaces.size(); ++i) ++ { ++ if (!m_bufferPool.glSurfaces[i].used) ++ { ++ g_XVBA_vtable.DestroySurface(m_bufferPool.glSurfaces[i].glSurface); ++ glDeleteTextures(1, &m_bufferPool.glSurfaces[i].texture); ++ m_bufferPool.glSurfaces[i].glSurface = 0; ++ m_bufferPool.glSurfaces[i].used = true; ++ } ++ } ++ } ++} ++ ++bool COutput::CreateGlxContext() ++{ ++ GLXContext glContext; ++ ++ m_Display = g_Windowing.GetDisplay(); ++ glContext = g_Windowing.GetGlxContext(); ++ m_Window = g_Windowing.GetWindow(); ++ ++ // Get our window attribs. ++ XWindowAttributes wndattribs; ++ XGetWindowAttributes(m_Display, m_Window, &wndattribs); ++ ++ // Get visual Info ++ XVisualInfo visInfo; ++ visInfo.visualid = wndattribs.visual->visualid; ++ int nvisuals = 0; ++ XVisualInfo* visuals = XGetVisualInfo(m_Display, VisualIDMask, &visInfo, &nvisuals); ++ if (nvisuals != 1) ++ { ++ CLog::Log(LOGERROR, "XVBA::COutput::CreateGlxContext - could not find visual"); ++ return false; ++ } ++ visInfo = visuals[0]; ++ XFree(visuals); ++ ++ m_pixmap = XCreatePixmap(m_Display, ++ m_Window, ++ 192, ++ 108, ++ visInfo.depth); ++ if (!m_pixmap) ++ { ++ CLog::Log(LOGERROR, "XVBA::COutput::CreateGlxContext - Unable to create XPixmap"); ++ return false; ++ } ++ ++ // create gl pixmap ++ m_glPixmap = glXCreateGLXPixmap(m_Display, &visInfo, m_pixmap); ++ ++ if (!m_glPixmap) ++ { ++ CLog::Log(LOGINFO, "XVBA::COutput::CreateGlxContext - Could not create glPixmap"); ++ return false; ++ } ++ ++ m_glContext = glXCreateContext(m_Display, &visInfo, glContext, True); ++ ++ if (!glXMakeCurrent(m_Display, m_glPixmap, m_glContext)) ++ { ++ CLog::Log(LOGINFO, "XVBA::COutput::CreateGlxContext - Could not make Pixmap current"); ++ return false; ++ } ++ ++ CLog::Log(LOGNOTICE, "XVBA::COutput::CreateGlxContext - created context"); ++ return true; ++} ++ ++bool COutput::DestroyGlxContext() ++{ ++ if (m_glContext) ++ { ++ glXMakeCurrent(m_Display, None, NULL); ++ glXDestroyContext(m_Display, m_glContext); ++ } ++ m_glContext = 0; ++ ++ if (m_glPixmap) ++ glXDestroyPixmap(m_Display, m_glPixmap); ++ m_glPixmap = 0; ++ ++ if (m_pixmap) ++ XFreePixmap(m_Display, m_pixmap); ++ m_pixmap = 0; ++ ++ return true; ++} ++ ++#endif +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.h +new file mode 100644 +index 0000000..f38444c +--- /dev/null ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.h +@@ -0,0 +1,382 @@ ++/* ++ * Copyright (C) 2005-2011 Team XBMC ++ * http://www.xbmc.org ++ * ++ * This Program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2, or (at your option) ++ * any later version. ++ * ++ * This Program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with XBMC; see the file COPYING. If not, write to ++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ++ * http://www.gnu.org/copyleft/gpl.html ++ * ++ */ ++#pragma once ++ ++#include "X11/Xlib.h" ++#include "amd/amdxvba.h" ++#include "DllAvCodec.h" ++#include "DVDCodecs/Video/DVDVideoCodecFFmpeg.h" ++#include "threads/Thread.h" ++#include "threads/CriticalSection.h" ++#include "threads/SharedSection.h" ++#include "threads/Event.h" ++#include "guilib/DispResource.h" ++#include "guilib/Geometry.h" ++#include "libavcodec/xvba.h" ++#include "utils/ActorProtocol.h" ++#include "settings/VideoSettings.h" ++#include ++#include ++#include ++ ++using namespace Actor; ++ ++ ++namespace XVBA ++{ ++ ++//----------------------------------------------------------------------------- ++// XVBA data structs ++//----------------------------------------------------------------------------- ++ ++class CDecoder; ++class CXVBAContext; ++class COutput; ++ ++#define NUM_RENDER_PICS 9 ++ ++/** ++ * Buffer statistics used to control number of frames in queue ++ */ ++ ++class CXvbaBufferStats ++{ ++public: ++ uint16_t decodedPics; ++ uint16_t processedPics; ++ uint16_t renderPics; ++ uint64_t latency; // time decoder has waited for a frame, ideally there is no latency ++ int playSpeed; ++ bool canSkipDeint; ++ int processCmd; ++ ++ void IncDecoded() { CSingleLock l(m_sec); decodedPics++;} ++ void DecDecoded() { CSingleLock l(m_sec); decodedPics--;} ++ void IncProcessed() { CSingleLock l(m_sec); processedPics++;} ++ void DecProcessed() { CSingleLock l(m_sec); processedPics--;} ++ void IncRender() { CSingleLock l(m_sec); renderPics++;} ++ void DecRender() { CSingleLock l(m_sec); renderPics--;} ++ void Reset() { CSingleLock l(m_sec); decodedPics=0; processedPics=0;renderPics=0;latency=0;} ++ void Get(uint16_t &decoded, uint16_t &processed, uint16_t &render) {CSingleLock l(m_sec); decoded = decodedPics, processed=processedPics, render=renderPics;} ++ void SetParams(uint64_t time, int speed) { CSingleLock l(m_sec); latency = time; playSpeed = speed; } ++ void GetParams(uint64_t &lat, int &speed) { CSingleLock l(m_sec); lat = latency; speed = playSpeed; } ++ void SetCmd(int cmd) { CSingleLock l(m_sec); processCmd = cmd; } ++ void GetCmd(int &cmd) { CSingleLock l(m_sec); cmd = processCmd; processCmd = 0; } ++ void SetCanSkipDeint(bool canSkip) { CSingleLock l(m_sec); canSkipDeint = canSkip; } ++ bool CanSkipDeint() { CSingleLock l(m_sec); if (canSkipDeint) return true; else return false;} ++private: ++ CCriticalSection m_sec; ++}; ++ ++/** ++ * CXvbaConfig holds all configuration parameters needed by vdpau ++ * The structure is sent to the internal classes CMixer and COutput ++ * for init. ++ */ ++ ++struct CXvbaConfig ++{ ++ int surfaceWidth; ++ int surfaceHeight; ++ int vidWidth; ++ int vidHeight; ++ int outWidth; ++ int outHeight; ++ bool useSharedSurfaces; ++ ++ CXVBAContext *context; ++ XVBADecodeCap decoderCap; ++ void *xvbaSession; ++ std::vector *videoSurfaces; ++ CCriticalSection *videoSurfaceSec; ++ CCriticalSection *apiSec; ++ ++ CXvbaBufferStats *stats; ++ int numRenderBuffers; ++ uint32_t maxReferences; ++}; ++ ++/** ++ * Holds a decoded frame ++ * Input to COutput for further processing ++ */ ++struct CXvbaDecodedPicture ++{ ++ DVDVideoPicture DVDPic; ++ xvba_render_state *render; ++}; ++ ++/** ++ * Ready to render textures ++ * Sent from COutput back to CDecoder ++ * Objects are referenced by DVDVideoPicture and are sent ++ * to renderer ++ */ ++class CXvbaRenderPicture ++{ ++ friend class CDecoder; ++ friend class COutput; ++public: ++ DVDVideoPicture DVDPic; ++ int texWidth, texHeight; ++ CRect crop; ++ GLuint texture; ++ uint32_t sourceIdx; ++ bool valid; ++ CDecoder *xvba; ++ CXvbaRenderPicture* Acquire(); ++ long Release(); ++private: ++ void ReturnUnused(); ++ int refCount; ++ CCriticalSection *renderPicSection; ++ COutput *xvbaOutput; ++}; ++ ++//----------------------------------------------------------------------------- ++// Output ++//----------------------------------------------------------------------------- ++ ++/** ++ * Buffer pool holds allocated xvba and gl resources ++ * Embedded in COutput ++ */ ++struct XvbaBufferPool ++{ ++ struct GLVideoSurface ++ { ++ unsigned int id; ++ bool used; ++ bool transferred; ++ GLuint texture; ++ void *glSurface; ++ xvba_render_state *render; ++ XVBA_SURFACE_FLAG field; ++ }; ++ std::vector glSurfaces; ++ std::vector allRenderPics; ++ std::deque usedRenderPics; ++ std::deque freeRenderPics; ++ CCriticalSection renderPicSec; ++}; ++ ++class COutputControlProtocol : public Protocol ++{ ++public: ++ COutputControlProtocol(std::string name, CEvent* inEvent, CEvent *outEvent) : Protocol(name, inEvent, outEvent) {}; ++ enum OutSignal ++ { ++ INIT, ++ FLUSH, ++ PRECLEANUP, ++ TIMEOUT, ++ }; ++ enum InSignal ++ { ++ ACC, ++ ERROR, ++ STATS, ++ }; ++}; ++ ++class COutputDataProtocol : public Protocol ++{ ++public: ++ COutputDataProtocol(std::string name, CEvent* inEvent, CEvent *outEvent) : Protocol(name, inEvent, outEvent) {}; ++ enum OutSignal ++ { ++ NEWFRAME = 0, ++ RETURNPIC, ++ }; ++ enum InSignal ++ { ++ PICTURE, ++ }; ++}; ++ ++/** ++ * COutput is embedded in CDecoder and embeds CMixer ++ * The class has its own OpenGl context which is shared with render thread ++ * COuput generated ready to render textures and passes them back to ++ * CDecoder ++ */ ++class COutput : private CThread ++{ ++public: ++ COutput(CEvent *inMsgEvent); ++ virtual ~COutput(); ++ void Start(); ++ void Dispose(); ++ COutputControlProtocol m_controlPort; ++ COutputDataProtocol m_dataPort; ++protected: ++ void OnStartup(); ++ void OnExit(); ++ void Process(); ++ void StateMachine(int signal, Protocol *port, Message *msg); ++ bool HasWork(); ++ bool IsDecodingFinished(); ++ CXvbaRenderPicture* ProcessPicture(); ++ void ProcessReturnPicture(CXvbaRenderPicture *pic); ++ int FindFreeSurface(); ++ void InitCycle(); ++ void FiniCycle(); ++ bool Init(); ++ bool Uninit(); ++ void Flush(); ++ bool CreateGlxContext(); ++ bool DestroyGlxContext(); ++ bool EnsureBufferPool(); ++ void ReleaseBufferPool(bool precleanup = false); ++ void PreReleaseBufferPool(); ++ CEvent m_outMsgEvent; ++ CEvent *m_inMsgEvent; ++ int m_state; ++ bool m_bStateMachineSelfTrigger; ++ ++ // extended state variables for state machine ++ int m_extTimeout; ++ bool m_xvbaError; ++ CXvbaConfig m_config; ++ XvbaBufferPool m_bufferPool; ++ Display *m_Display; ++ Window m_Window; ++ GLXContext m_glContext; ++ GLXWindow m_glWindow; ++ Pixmap m_pixmap; ++ GLXPixmap m_glPixmap; ++ GLsync m_fence; ++ std::queue m_decodedPics; ++ CXvbaDecodedPicture m_processPicture; ++ XVBA_SURFACE_FLAG m_field; ++ bool m_deinterlacing; ++ int m_deintStep; ++ bool m_deintSkip; ++}; ++ ++//----------------------------------------------------------------------------- ++// XVBA decoder ++//----------------------------------------------------------------------------- ++ ++class CXVBAContext ++{ ++public: ++ static bool EnsureContext(CXVBAContext **ctx); ++ void *GetContext(); ++ void Release(); ++private: ++ CXVBAContext(); ++ void Close(); ++ bool LoadSymbols(); ++ bool CreateContext(); ++ void DestroyContext(); ++ static CXVBAContext *m_context; ++ static CCriticalSection m_section; ++ static Display *m_display; ++ int m_refCount; ++ static void *m_dlHandle; ++ void *m_xvbaContext; ++}; ++ ++class CDecoder : public CDVDVideoCodecFFmpeg::IHardwareDecoder, ++ public IDispResource ++{ ++ friend class CXvbaRenderPicture; ++ ++public: ++ ++ struct pictureAge ++ { ++ int b_age; ++ int ip_age[2]; ++ }; ++ ++ enum EDisplayState ++ { XVBA_OPEN ++ , XVBA_RESET ++ , XVBA_LOST ++ , XVBA_ERROR ++ }; ++ ++ CDecoder(); ++ virtual ~CDecoder(); ++ virtual void OnLostDevice(); ++ virtual void OnResetDevice(); ++ ++ virtual bool Open(AVCodecContext* avctx, const enum PixelFormat fmt, unsigned int surfaces = 0); ++ virtual int Decode (AVCodecContext* avctx, AVFrame* frame); ++ virtual bool GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture); ++ virtual void Reset(); ++ virtual void Close(); ++ virtual int Check(AVCodecContext* avctx); ++ virtual long Release(); ++ virtual const std::string Name() { return "xvba"; } ++ virtual bool CanSkipDeint(); ++ virtual void SetSpeed(int speed); ++ ++ bool Supports(EINTERLACEMETHOD method); ++ long ReleasePicReference(); ++ ++protected: ++ bool CreateSession(AVCodecContext* avctx); ++ void DestroySession(bool precleanup = false); ++ bool EnsureDataControlBuffers(unsigned int num); ++ void ResetState(); ++ void SetError(const char* function, const char* msg, int line); ++ bool IsSurfaceValid(xvba_render_state *render); ++ void ReturnRenderPicture(CXvbaRenderPicture *renderPic); ++ ++ // callbacks for ffmpeg ++ static void FFReleaseBuffer(AVCodecContext *avctx, AVFrame *pic); ++ static void FFDrawSlice(struct AVCodecContext *avctx, ++ const AVFrame *src, int offset[4], ++ int y, int type, int height); ++ static int FFGetBuffer(AVCodecContext *avctx, AVFrame *pic); ++ ++ DllAvUtil m_dllAvUtil; ++ CCriticalSection m_decoderSection; ++ CEvent m_displayEvent; ++ EDisplayState m_displayState; ++ CXvbaConfig m_xvbaConfig; ++ std::vector m_videoSurfaces; ++ CCriticalSection m_apiSec, m_videoSurfaceSec; ++ ThreadIdentifier m_decoderThread; ++ ++ unsigned int m_decoderId; ++ struct XVBABufferPool ++ { ++ XVBABufferDescriptor *picture_descriptor_buffer; ++ XVBABufferDescriptor *iq_matrix_buffer; ++ XVBABufferDescriptor *data_buffer; ++ std::vector data_control_buffers; ++ }; ++ XVBABufferPool m_xvbaBufferPool; ++ ++ COutput m_xvbaOutput; ++ CXvbaBufferStats m_bufferStats; ++ CEvent m_inMsgEvent; ++ CXvbaRenderPicture *m_presentPicture; ++ ++ int m_speed; ++ int m_codecControl; ++}; ++ ++} +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +index 15a39fa..e5e71f3 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -1162,6 +1162,9 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) + case RENDER_FMT_NONE: + formatstr = "NONE"; + break; ++ case RENDER_FMT_XVBA: ++ formatstr = "XVBA"; ++ break; + } + + if(m_bAllowFullscreen) +diff --git a/xbmc/settings/GUISettings.cpp b/xbmc/settings/GUISettings.cpp +index 0e320e1..10ef779 100644 +--- a/xbmc/settings/GUISettings.cpp ++++ b/xbmc/settings/GUISettings.cpp +@@ -696,6 +696,9 @@ void CGUISettings::Initialize() + #ifdef HAVE_LIBVA + AddBool(vp, "videoplayer.usevaapi", 13426, true); + #endif ++#ifdef HAVE_LIBXVBA ++ AddBool(vp, "videoplayer.usexvba", 13437, true); ++#endif + #ifdef HAS_DX + AddBool(g_sysinfo.IsVistaOrHigher() ? vp: NULL, "videoplayer.usedxva2", 13427, g_sysinfo.IsVistaOrHigher() ? true : false); + #endif +diff --git a/xbmc/settings/VideoSettings.h b/xbmc/settings/VideoSettings.h +index f8093b2..f54a837 100644 +--- a/xbmc/settings/VideoSettings.h ++++ b/xbmc/settings/VideoSettings.h +@@ -65,6 +65,8 @@ enum EINTERLACEMETHOD + VS_INTERLACEMETHOD_SW_BLEND = 20, + VS_INTERLACEMETHOD_AUTO_ION = 21, + ++ VS_INTERLACEMETHOD_XVBA = 22, ++ + VS_INTERLACEMETHOD_MAX // do not use and keep as last enum value. + }; + +diff --git a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp +index f25d10d..f6b1ea4 100644 +--- a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp ++++ b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp +@@ -110,6 +110,7 @@ void CGUIDialogVideoSettings::CreateSettings() + entries.push_back(make_pair(VS_INTERLACEMETHOD_DXVA_BOB , 16320)); + entries.push_back(make_pair(VS_INTERLACEMETHOD_DXVA_BEST , 16321)); + entries.push_back(make_pair(VS_INTERLACEMETHOD_AUTO_ION , 16325)); ++ entries.push_back(make_pair(VS_INTERLACEMETHOD_XVBA , 16326)); + + /* remove unsupported methods */ + for(vector >::iterator it = entries.begin(); it != entries.end();) +-- +1.7.10 + + +From 517eda0bf58a6376a82839ab92e51b97c143edf1 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 23 Aug 2012 19:39:49 +0200 +Subject: [PATCH 43/73] ffmpeg: add av_find_default_stream_index to interface + +--- + lib/DllAvFormat.h | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/lib/DllAvFormat.h b/lib/DllAvFormat.h +index 9bda3f3..bf31fcb 100644 +--- a/lib/DllAvFormat.h ++++ b/lib/DllAvFormat.h +@@ -98,6 +98,7 @@ class DllAvFormatInterface + virtual int avformat_write_header (AVFormatContext *s, AVDictionary **options)=0; + virtual int av_write_trailer(AVFormatContext *s)=0; + virtual int av_write_frame (AVFormatContext *s, AVPacket *pkt)=0; ++ virtual int av_find_default_stream_index(AVFormatContext *s)=0; + }; + + #if (defined USE_EXTERNAL_FFMPEG) || (defined TARGET_DARWIN) +@@ -153,6 +154,7 @@ class DllAvFormat : public DllDynamic, DllAvFormatInterface + virtual int avformat_write_header (AVFormatContext *s, AVDictionary **options) { return ::avformat_write_header (s, options); } + virtual int av_write_trailer(AVFormatContext *s) { return ::av_write_trailer(s); } + virtual int av_write_frame (AVFormatContext *s, AVPacket *pkt) { return ::av_write_frame(s, pkt); } ++ virtual int av_find_default_stream_index(AVFormatContext *s) { return ::av_find_default_stream_index(s); } + + // DLL faking. + virtual bool ResolveExports() { return true; } +@@ -209,6 +211,7 @@ class DllAvFormat : public DllDynamic, DllAvFormatInterface + DEFINE_METHOD2(int, avformat_write_header , (AVFormatContext *p1, AVDictionary **p2)) + DEFINE_METHOD1(int, av_write_trailer, (AVFormatContext *p1)) + DEFINE_METHOD2(int, av_write_frame , (AVFormatContext *p1, AVPacket *p2)) ++ DEFINE_METHOD1(int, av_find_default_stream_index, (AVFormatContext *p1)) + BEGIN_METHOD_RESOLVE() + RESOLVE_METHOD_RENAME(av_register_all, av_register_all_dont_call) + RESOLVE_METHOD(av_find_input_format) +@@ -243,6 +246,7 @@ class DllAvFormat : public DllDynamic, DllAvFormatInterface + RESOLVE_METHOD(avformat_write_header) + RESOLVE_METHOD(av_write_trailer) + RESOLVE_METHOD(av_write_frame) ++ RESOLVE_METHOD(av_find_default_stream_index) + END_METHOD_RESOLVE() + + /* dependencies of libavformat */ +-- +1.7.10 + + +From 23be471842ae9ea7bd62c18261a5e96a11045d04 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 20 Aug 2012 16:06:39 +0200 +Subject: [PATCH 44/73] dvdplayer: observe pts counter overflow + +--- + .../cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp | 198 +++++++++++++++++++- + xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h | 4 + + 2 files changed, 201 insertions(+), 1 deletion(-) + +diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +index 7c0ab03..f91be3c 100644 +--- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp ++++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +@@ -18,13 +18,13 @@ + * + */ + +-#include "system.h" + #ifndef __STDC_CONSTANT_MACROS + #define __STDC_CONSTANT_MACROS + #endif + #ifndef __STDC_LIMIT_MACROS + #define __STDC_LIMIT_MACROS + #endif ++#include "system.h" + #ifdef _LINUX + #include "stdint.h" + #endif +@@ -495,6 +495,9 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput) + AddStream(i); + } + ++ m_bPtsWrapChecked = false; ++ m_bPtsWrap = false; ++ + return true; + } + +@@ -605,6 +608,12 @@ double CDVDDemuxFFmpeg::ConvertTimestamp(int64_t pts, int den, int num) + if (pts == (int64_t)AV_NOPTS_VALUE) + return DVD_NOPTS_VALUE; + ++ if (m_bPtsWrap) ++ { ++ if (pts < m_iStartTime && pts < m_iEndTime) ++ pts += m_iMaxTime; ++ } ++ + // do calculations in floats as they can easily overflow otherwise + // we don't care for having a completly exact timestamp anyway + double timestamp = (double)pts * num / den; +@@ -729,6 +738,24 @@ DemuxPacket* CDVDDemuxFFmpeg::Read() + pkt.pts = AV_NOPTS_VALUE; + } + ++ if (!m_bPtsWrapChecked && m_pFormatContext->iformat->flags & AVFMT_TS_DISCONT) ++ { ++ int defaultStream = m_dllAvFormat.av_find_default_stream_index(m_pFormatContext); ++ int64_t duration = m_pFormatContext->streams[defaultStream]->duration * 1.5; ++ m_iMaxTime = 1LL<streams[defaultStream]->pts_wrap_bits; ++ m_iStartTime = m_pFormatContext->streams[defaultStream]->start_time; ++ if (m_iStartTime != DVD_NOPTS_VALUE) ++ { ++ m_iEndTime = (m_iStartTime + duration) & ~m_iMaxTime; ++ if (m_iEndTime < m_iStartTime) ++ { ++ CLog::Log(LOGNOTICE,"CDVDDemuxFFmpeg::Read - file contains pts overflow"); ++ m_bPtsWrap = true; ++ } ++ } ++ m_bPtsWrapChecked = true; ++ } ++ + // copy contents into our own packet + pPacket->iSize = pkt.size; + +@@ -845,10 +872,20 @@ bool CDVDDemuxFFmpeg::SeekTime(int time, bool backwords, double *startpts) + int ret; + { + CSingleLock lock(m_critSection); ++ + ret = m_dllAvFormat.av_seek_frame(m_pFormatContext, -1, seek_pts, backwords ? AVSEEK_FLAG_BACKWARD : 0); + + if(ret >= 0) ++ { + UpdateCurrentPTS(); ++ ++ // seek may fail silently on streams which allow discontinuity ++ // if current timestamp is way off asume a pts overflow and try bisect seek ++ if (m_bPtsWrap && fabs(time - m_iCurrentPts/1000) > 10000) ++ { ++ ret = SeekTimeDiscont(seek_pts, backwords) ? 1 : -1; ++ } ++ } + } + + if(m_iCurrentPts == DVD_NOPTS_VALUE) +@@ -867,6 +904,165 @@ bool CDVDDemuxFFmpeg::SeekTime(int time, bool backwords, double *startpts) + return (ret >= 0); + } + ++bool CDVDDemuxFFmpeg::SeekTimeDiscont(int64_t pts, bool backwards) ++{ ++ // this code is taken from ffmpeg function ff_gen_search ++ // it is modified to assume a pts overflow if timestamp < start_time ++ if (!m_pFormatContext->iformat->read_timestamp) ++ return false; ++ ++ int defaultStream = m_dllAvFormat.av_find_default_stream_index(m_pFormatContext); ++ ++ if (defaultStream < 0) ++ { ++ return false; ++ } ++ ++ // timestamp for default must be expressed in AV_TIME_BASE units ++ pts = m_dllAvUtil.av_rescale_rnd(pts, m_pFormatContext->streams[defaultStream]->time_base.den, ++ AV_TIME_BASE * (int64_t)m_pFormatContext->streams[defaultStream]->time_base.num, ++ AV_ROUND_NEAR_INF); ++ ++ int64_t pos, pos_min, pos_max, pos_limit, ts, ts_min, ts_max; ++ int64_t start_pos, filesize; ++ int no_change; ++ ++ pos_min = m_pFormatContext->data_offset; ++ ts_min = m_pFormatContext->iformat->read_timestamp(m_pFormatContext, defaultStream, ++ &pos_min, INT64_MAX); ++ if (ts_min == AV_NOPTS_VALUE) ++ return false; ++ ++ if(ts_min >= pts) ++ { ++ pos = pos_min; ++ return true; ++ } ++ ++ int step= 1024; ++ filesize = m_pInput->GetLength(); ++ pos_max = filesize - 1; ++ do ++ { ++ pos_max -= step; ++ ts_max = m_pFormatContext->iformat->read_timestamp(m_pFormatContext, defaultStream, ++ &pos_max, pos_max + step); ++ step += step; ++ }while (ts_max == AV_NOPTS_VALUE && pos_max >= step); ++ ++ if (ts_max == AV_NOPTS_VALUE) ++ return false; ++ ++ if (ts_max < m_iStartTime && ts_max < m_iEndTime) ++ ts_max += m_iMaxTime; ++ ++ for(;;) ++ { ++ int64_t tmp_pos = pos_max + 1; ++ int64_t tmp_ts = m_pFormatContext->iformat->read_timestamp(m_pFormatContext, defaultStream, ++ &tmp_pos, INT64_MAX); ++ if(tmp_ts == AV_NOPTS_VALUE) ++ break; ++ ++ if (tmp_ts < m_iStartTime && tmp_ts < m_iEndTime) ++ tmp_ts += m_iMaxTime; ++ ++ ts_max = tmp_ts; ++ pos_max = tmp_pos; ++ if (tmp_pos >= filesize) ++ break; ++ } ++ pos_limit = pos_max; ++ ++ if(ts_max <= pts) ++ { ++ bool ret = SeekByte(pos_max); ++ if (ret) ++ { ++ m_iCurrentPts = ConvertTimestamp(ts_max, m_pFormatContext->streams[defaultStream]->time_base.den, ++ m_pFormatContext->streams[defaultStream]->time_base.num); ++ } ++ return ret; ++ } ++ ++ if(ts_min > ts_max) ++ { ++ return false; ++ } ++ else if (ts_min == ts_max) ++ { ++ pos_limit = pos_min; ++ } ++ ++ no_change=0; ++ while (pos_min < pos_limit) ++ { ++ if (no_change == 0) ++ { ++ int64_t approximate_keyframe_distance= pos_max - pos_limit; ++ // interpolate position (better than dichotomy) ++ pos = m_dllAvUtil.av_rescale_rnd(pts - ts_min, pos_max - pos_min, ++ ts_max - ts_min, AV_ROUND_NEAR_INF) ++ + pos_min - approximate_keyframe_distance; ++ } ++ else if (no_change == 1) ++ { ++ // bisection, if interpolation failed to change min or max pos last time ++ pos = (pos_min + pos_limit) >> 1; ++ } ++ else ++ { ++ /* linear search if bisection failed, can only happen if there ++ are very few or no keyframes between min/max */ ++ pos = pos_min; ++ } ++ if (pos <= pos_min) ++ pos= pos_min + 1; ++ else if (pos > pos_limit) ++ pos= pos_limit; ++ start_pos = pos; ++ ++ ts = m_pFormatContext->iformat->read_timestamp(m_pFormatContext, defaultStream, ++ &pos, INT64_MAX); ++ if (pos == pos_max) ++ no_change++; ++ else ++ no_change=0; ++ ++ if (ts == AV_NOPTS_VALUE) ++ { ++ return false; ++ } ++ ++ if (ts < m_iStartTime && ts < m_iEndTime) ++ ts += m_iMaxTime; ++ ++ if (pts <= ts) ++ { ++ pos_limit = start_pos - 1; ++ pos_max = pos; ++ ts_max = ts; ++ } ++ if (pts >= ts) ++ { ++ pos_min = pos; ++ ts_min = ts; ++ } ++ } ++ ++ pos = (backwards) ? pos_min : pos_max; ++ ts = (backwards) ? ts_min : ts_max; ++ ++ bool ret = SeekByte(pos); ++ if (ret) ++ { ++ m_iCurrentPts = ConvertTimestamp(ts, m_pFormatContext->streams[defaultStream]->time_base.den, ++ m_pFormatContext->streams[defaultStream]->time_base.num); ++ } ++ ++ return ret; ++} ++ + bool CDVDDemuxFFmpeg::SeekByte(int64_t pos) + { + g_demuxer.set(this); +diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h +index 2b5f2e8..e0acf29 100644 +--- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h ++++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h +@@ -97,6 +97,7 @@ class CDVDDemuxFFmpeg : public CDVDDemux + DemuxPacket* Read(); + + bool SeekTime(int time, bool backwords = false, double* startpts = NULL); ++ bool SeekTimeDiscont(int64_t pts, bool backwards); + bool SeekByte(int64_t pos); + int GetStreamLength(); + CDemuxStream* GetStream(int iStreamId); +@@ -141,5 +142,8 @@ class CDVDDemuxFFmpeg : public CDVDDemux + XbmcThreads::EndTime m_timeout; + + CDVDInputStream* m_pInput; ++ ++ bool m_bPtsWrap, m_bPtsWrapChecked; ++ int64_t m_iStartTime, m_iMaxTime, m_iEndTime; + }; + +-- +1.7.10 + + +From 66382788a903f99ba317e972ba0445fc68320750 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Tue, 2 Oct 2012 13:02:10 +0200 +Subject: [PATCH 45/73] dvdplayer: avoid short screen flicker caused by + unnecessary reconfigure of renderer + +--- + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +index e5e71f3..8b02d81 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -1033,7 +1033,7 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) + || m_output.height != pPicture->iHeight + || m_output.dwidth != pPicture->iDisplayWidth + || m_output.dheight != pPicture->iDisplayHeight +- || m_output.framerate != config_framerate ++ || (!m_bFpsInvalid && fmod(m_output.framerate, config_framerate) != 0.0 ) + || m_output.color_format != (unsigned int)pPicture->format + || m_output.extended_format != pPicture->extended_format + || ( m_output.color_matrix != pPicture->color_matrix && pPicture->color_matrix != 0 ) // don't reconfigure on unspecified +@@ -1184,7 +1184,7 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) + m_output.height = pPicture->iHeight; + m_output.dwidth = pPicture->iDisplayWidth; + m_output.dheight = pPicture->iDisplayHeight; +- m_output.framerate = config_framerate; ++ m_output.framerate = config_framerate == 0.0 ? g_graphicsContext.GetFPS() : config_framerate; + m_output.color_format = pPicture->format; + m_output.extended_format = pPicture->extended_format; + m_output.color_matrix = pPicture->color_matrix; +-- +1.7.10 + + +From 04f4521c1938a7ac17acd59f3bd6be59c7ba8184 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sat, 16 Jun 2012 12:46:30 +0200 +Subject: [PATCH 46/73] xvba: do not use vaapi if xvba is present + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp +index a2b9195..43a05b3 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp +@@ -261,6 +261,15 @@ void CDecoder::Close() + + bool CDecoder::Open(AVCodecContext *avctx, enum PixelFormat fmt, unsigned int surfaces) + { ++#ifdef HAVE_LIBXVBA ++ std::string Vendor = g_Windowing.GetRenderVendor(); ++ std::transform(Vendor.begin(), Vendor.end(), Vendor.begin(), ::tolower); ++ if (Vendor.compare(0, 3, "ati") == 0) ++ { ++ return false; ++ } ++#endif ++ + VAEntrypoint entrypoint = VAEntrypointVLD; + VAProfile profile; + +-- +1.7.10 + + +From a133b7fa119e859ec50b9f05a33de984105234f3 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 11 Oct 2012 12:05:50 +0200 +Subject: [PATCH 47/73] vdpau: advanced settings for auto deinterlacing + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 8 ++++---- + xbmc/settings/AdvancedSettings.cpp | 4 ++++ + xbmc/settings/AdvancedSettings.h | 2 ++ + 3 files changed, 10 insertions(+), 4 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +index 235f565..d95797b 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +@@ -1770,10 +1770,10 @@ EINTERLACEMETHOD CMixer::GetDeinterlacingMethod(bool log /* = false */) + if (method == VS_INTERLACEMETHOD_AUTO) + { + int deint = -1; +-// if (m_config.outHeight >= 720) +-// deint = g_advancedSettings.m_videoVDPAUdeintHD; +-// else +-// deint = g_advancedSettings.m_videoVDPAUdeintSD; ++ if (m_config.outHeight >= 720) ++ deint = g_advancedSettings.m_videoVDPAUdeintHD; ++ else ++ deint = g_advancedSettings.m_videoVDPAUdeintSD; + + if (deint != -1) + { +diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp +index 844f8e8..d913924 100644 +--- a/xbmc/settings/AdvancedSettings.cpp ++++ b/xbmc/settings/AdvancedSettings.cpp +@@ -106,6 +106,8 @@ void CAdvancedSettings::Initialize() + m_videoAllowMpeg4VAAPI = false; + m_videoDisableBackgroundDeinterlace = false; + m_videoCaptureUseOcclusionQuery = -1; //-1 is auto detect ++ m_videoVDPAUdeintHD = -1; ++ m_videoVDPAUdeintSD = -1; + m_videoVDPAUtelecine = false; + m_videoVDPAUdeintSkipChromaHD = false; + m_DXVACheckCompatibility = false; +@@ -503,6 +505,8 @@ void CAdvancedSettings::ParseSettingsFile(const CStdString &file) + XMLUtils::GetBoolean(pElement,"allowmpeg4vaapi",m_videoAllowMpeg4VAAPI); + XMLUtils::GetBoolean(pElement, "disablebackgrounddeinterlace", m_videoDisableBackgroundDeinterlace); + XMLUtils::GetInt(pElement, "useocclusionquery", m_videoCaptureUseOcclusionQuery, -1, 1); ++ XMLUtils::GetInt(pElement,"vdpauHDdeint",m_videoVDPAUdeintHD); ++ XMLUtils::GetInt(pElement,"vdpauSDdeint",m_videoVDPAUdeintSD); + XMLUtils::GetBoolean(pElement,"vdpauInvTelecine",m_videoVDPAUtelecine); + XMLUtils::GetBoolean(pElement,"vdpauHDdeintSkipChroma",m_videoVDPAUdeintSkipChromaHD); + +diff --git a/xbmc/settings/AdvancedSettings.h b/xbmc/settings/AdvancedSettings.h +index 72718e5..aaa4702 100644 +--- a/xbmc/settings/AdvancedSettings.h ++++ b/xbmc/settings/AdvancedSettings.h +@@ -133,6 +133,8 @@ class CAdvancedSettings + int m_videoPercentSeekBackwardBig; + CStdString m_videoPPFFmpegDeint; + CStdString m_videoPPFFmpegPostProc; ++ int m_videoVDPAUdeintHD; ++ int m_videoVDPAUdeintSD; + bool m_videoVDPAUtelecine; + bool m_videoVDPAUdeintSkipChromaHD; + bool m_musicUseTimeSeeking; +-- +1.7.10 + + +From 62540aeaa356823bd34e9367ac39eef23a6e4ce4 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 11 Oct 2012 13:01:08 +0200 +Subject: [PATCH 48/73] dvdplayer: correct determination if video is playing + +--- + xbmc/cores/dvdplayer/DVDPlayer.cpp | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp +index 6fcb6b3..f76691d 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp +@@ -2382,9 +2382,16 @@ bool CDVDPlayer::IsPaused() const + + bool CDVDPlayer::HasVideo() const + { +- if (m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD)) return true; ++ bool hasVideo(false); + +- return m_SelectionStreams.Count(STREAM_VIDEO) > 0 ? true : false; ++ if (m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD)) ++ hasVideo = true; ++ else if (m_SelectionStreams.Count(STREAM_VIDEO) > 0) ++ hasVideo = true; ++ else if (g_renderManager.IsConfigured()) ++ hasVideo = true; ++ ++ return hasVideo; + } + + bool CDVDPlayer::HasAudio() const +-- +1.7.10 + + +From 5a093bbd60d1ca47ed7c5e4639f28dafc1b565c1 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sun, 14 Oct 2012 13:46:54 +0200 +Subject: [PATCH 49/73] rendermanager: fix stuttering in non full-screen mode, + squash to add buffering + +--- + xbmc/cores/VideoRenderers/RenderManager.cpp | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index 0506823..b141c80 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -1057,8 +1057,9 @@ void CXBMCRenderManager::PrepareNextRender() + presenttime = clocktime + MAXPRESENTDELAY; + + m_sleeptime = presenttime - clocktime; ++ double frametime = 1 / g_graphicsContext.GetFPS(); + +- if (g_graphicsContext.IsFullScreenVideo() || presenttime <= clocktime+0.01) ++ if (g_graphicsContext.IsFullScreenVideo() || presenttime <= clocktime + frametime) + { + m_presentPts = m_renderBuffers[idx].pts; + m_presenttime = presenttime; +-- +1.7.10 + + +From d0597caa2c922575efdf081d719d5665c626ffec Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sun, 14 Oct 2012 17:54:02 +0200 +Subject: [PATCH 50/73] rendermanager: forgot to set flip event if buffering + is not used + +--- + xbmc/cores/VideoRenderers/RenderManager.cpp | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index b141c80..9290f80 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -1096,17 +1096,17 @@ void CXBMCRenderManager::NotifyDisplayFlip() + if (!m_pRenderer) + return; + +- if (m_iNumRenderBuffers < 3) +- return; +- +- int last = m_iDisplayedRenderBuffer; +- m_iDisplayedRenderBuffer = (m_iCurrentRenderBuffer + m_iNumRenderBuffers - 1) % m_iNumRenderBuffers; +- +- if (last != m_iDisplayedRenderBuffer +- && m_iDisplayedRenderBuffer != m_iCurrentRenderBuffer) ++ if (m_iNumRenderBuffers >= 3) + { +- m_pRenderer->ReleaseBuffer(m_iDisplayedRenderBuffer); +- m_overlays.ReleaseBuffer(m_iDisplayedRenderBuffer); ++ int last = m_iDisplayedRenderBuffer; ++ m_iDisplayedRenderBuffer = (m_iCurrentRenderBuffer + m_iNumRenderBuffers - 1) % m_iNumRenderBuffers; ++ ++ if (last != m_iDisplayedRenderBuffer ++ && m_iDisplayedRenderBuffer != m_iCurrentRenderBuffer) ++ { ++ m_pRenderer->ReleaseBuffer(m_iDisplayedRenderBuffer); ++ m_overlays.ReleaseBuffer(m_iDisplayedRenderBuffer); ++ } + } + + lock.Leave(); +-- +1.7.10 + + +From c485392afa608bfbcf903fa53a9dd824258c96dd Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Fri, 26 Oct 2012 15:30:22 +0200 +Subject: [PATCH 51/73] vdpau: fix small mem leak + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +index d95797b..fec4b88 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +@@ -2052,6 +2052,8 @@ void CMixer::Uninit() + m_outputSurfaces.pop(); + } + m_config.vdpProcs.vdp_video_mixer_destroy(m_videoMixer); ++ ++ delete [] m_BlackBar; + } + + void CMixer::Flush() +-- +1.7.10 + + +From 9d7228a84013e409149d7b05d34545d1bdf06e27 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 29 Oct 2012 18:25:56 +0100 +Subject: [PATCH 52/73] xvba: do not render if there is no valid texture + +--- + xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +index ec3606a..7c3adcb 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +@@ -2924,16 +2924,14 @@ void CLinuxRendererGL::UploadXVBATexture(int index) + YUVFIELDS &fields = m_buffers[index].fields; + YUVPLANE &plane = fields[0][1]; + +- if (!xvba) ++ if (!xvba || !xvba->valid) + { +- fields[0][1].id = fields[0][0].id; + m_eventTexturesDone[index]->Set(); +- CLog::Log(LOGWARNING,"CLinuxRendererGL::UploadXVBATexture no xvba texture, index: %d", index); ++ m_skipRender = true; + return; + } +-// xvba->Transfer(); + +- fields[0][1].id = xvba->texture; ++ plane.id = xvba->texture; + + im.height = xvba->texHeight; + im.width = xvba->texWidth; +-- +1.7.10 + + +From 85be082db41b27cdd3824b8360dc021e17a84c22 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Fri, 2 Nov 2012 13:20:03 +0100 +Subject: [PATCH 53/73] player: fix rewind + +--- + xbmc/cores/dvdplayer/DVDMessage.h | 5 ++++- + xbmc/cores/dvdplayer/DVDPlayer.cpp | 33 ++++++++++++++++++++----------- + xbmc/cores/dvdplayer/DVDPlayer.h | 7 ++++--- + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 10 ++++++---- + xbmc/cores/dvdplayer/DVDPlayerVideo.h | 1 + + 5 files changed, 36 insertions(+), 20 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDMessage.h b/xbmc/cores/dvdplayer/DVDMessage.h +index 30b2f5c..b9831d4 100644 +--- a/xbmc/cores/dvdplayer/DVDMessage.h ++++ b/xbmc/cores/dvdplayer/DVDMessage.h +@@ -218,7 +218,7 @@ class CDVDMsgPlayerSetState : public CDVDMsg + class CDVDMsgPlayerSeek : public CDVDMsg + { + public: +- CDVDMsgPlayerSeek(int time, bool backward, bool flush = true, bool accurate = true, bool restore = true, bool trickplay = false) ++ CDVDMsgPlayerSeek(int time, bool backward, bool flush = true, bool accurate = true, bool restore = true, bool trickplay = false, bool sync = true) + : CDVDMsg(PLAYER_SEEK) + , m_time(time) + , m_backward(backward) +@@ -226,6 +226,7 @@ class CDVDMsgPlayerSeek : public CDVDMsg + , m_accurate(accurate) + , m_restore(restore) + , m_trickplay(trickplay) ++ , m_sync(sync) + {} + int GetTime() { return m_time; } + bool GetBackward() { return m_backward; } +@@ -233,6 +234,7 @@ class CDVDMsgPlayerSeek : public CDVDMsg + bool GetAccurate() { return m_accurate; } + bool GetRestore() { return m_restore; } + bool GetTrickPlay() { return m_trickplay; } ++ bool GetSync() { return m_sync; } + private: + int m_time; + bool m_backward; +@@ -240,6 +242,7 @@ class CDVDMsgPlayerSeek : public CDVDMsg + bool m_accurate; + bool m_restore; // whether to restore any EDL cut time + bool m_trickplay; ++ bool m_sync; + }; + + class CDVDMsgPlayerSeekChapter : public CDVDMsg +diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp +index f76691d..07df0d8 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp +@@ -1543,11 +1543,13 @@ void CDVDPlayer::HandlePlaySpeed() + } + else if (m_CurrentVideo.id >= 0 + && (m_CurrentVideo.inited == true || GetPlaySpeed() < 0) // allow rewind at end of file +- && m_SpeedState.lastpts != m_dvdPlayerVideo.GetCurrentPts() ++ && (m_SpeedState.lastpts != m_dvdPlayerVideo.GetCurrentPts() || fabs(m_SpeedState.lastabstime - CDVDClock::GetAbsoluteClock()) > DVD_MSEC_TO_TIME(200)) ++ && (m_dvdPlayerVideo.GetCurrentPts() != DVD_NOPTS_VALUE) + && m_SpeedState.lasttime != GetTime()) + { + m_SpeedState.lastpts = m_dvdPlayerVideo.GetCurrentPts(); + m_SpeedState.lasttime = GetTime(); ++ m_SpeedState.lastabstime = CDVDClock::GetAbsoluteClock(); + // check how much off clock video is when ff/rw:ing + // a problem here is that seeking isn't very accurate + // and since the clock will be resynced after seek +@@ -1566,7 +1568,7 @@ void CDVDPlayer::HandlePlaySpeed() + { + CLog::Log(LOGDEBUG, "CDVDPlayer::Process - Seeking to catch up"); + int64_t iTime = (int64_t)DVD_TIME_TO_MSEC(m_clock.GetClock() + m_State.time_offset + 500000.0 * m_playSpeed / DVD_PLAYSPEED_NORMAL); +- m_messenger.Put(new CDVDMsgPlayerSeek(iTime, (GetPlaySpeed() < 0), true, false, false, true)); ++ m_messenger.Put(new CDVDMsgPlayerSeek(iTime, (GetPlaySpeed() < 0), true, false, false, true, false)); + } + } + } +@@ -2030,7 +2032,7 @@ void CDVDPlayer::HandleMessages() + if(!m_pSubtitleDemuxer->SeekTime(time, msg.GetBackward())) + CLog::Log(LOGDEBUG, "failed to seek subtitle demuxer: %d, success", time); + } +- FlushBuffers(!msg.GetFlush(), start, msg.GetAccurate()); ++ FlushBuffers(!msg.GetFlush(), start, msg.GetAccurate(), msg.GetSync()); + } + else + CLog::Log(LOGWARNING, "error while seeking"); +@@ -2168,9 +2170,10 @@ void CDVDPlayer::HandleMessages() + double offset; + offset = CDVDClock::GetAbsoluteClock() - m_State.timestamp; + offset *= m_playSpeed / DVD_PLAYSPEED_NORMAL; ++ offset = DVD_TIME_TO_MSEC(offset); + if(offset > 1000) offset = 1000; + if(offset < -1000) offset = -1000; +- m_State.time += DVD_TIME_TO_MSEC(offset); ++ m_State.time += offset; + m_State.timestamp = CDVDClock::GetAbsoluteClock(); + } + +@@ -2186,7 +2189,8 @@ void CDVDPlayer::HandleMessages() + // do a seek after rewind, clock is not in sync with current pts + if (m_playSpeed < 0 && speed >= 0) + { +- m_messenger.Put(new CDVDMsgPlayerSeek(GetTime(), true, true, true)); ++ int64_t iTime = (int64_t)DVD_TIME_TO_MSEC(m_clock.GetClock() + m_State.time_offset); ++ m_messenger.Put(new CDVDMsgPlayerSeek(iTime, true, true, false, false, true)); + } + + // if playspeed is different then DVD_PLAYSPEED_NORMAL or DVD_PLAYSPEED_PAUSE +@@ -2767,10 +2771,11 @@ int64_t CDVDPlayer::GetTime() + { + offset = CDVDClock::GetAbsoluteClock() - m_State.timestamp; + offset *= m_playSpeed / DVD_PLAYSPEED_NORMAL; ++ offset = DVD_TIME_TO_MSEC(offset); + if(offset > 1000) offset = 1000; + if(offset < -1000) offset = -1000; + } +- return llrint(m_State.time + DVD_TIME_TO_MSEC(offset)); ++ return llrint(m_State.time + offset); + } + + // return length in msec +@@ -3140,7 +3145,7 @@ bool CDVDPlayer::CloseTeletextStream(bool bWaitForBuffers) + return true; + } + +-void CDVDPlayer::FlushBuffers(bool queued, double pts, bool accurate) ++void CDVDPlayer::FlushBuffers(bool queued, double pts, bool accurate, bool sync) + { + double startpts; + if(accurate) +@@ -3152,19 +3157,23 @@ void CDVDPlayer::FlushBuffers(bool queued, double pts, bool accurate) + if(startpts != DVD_NOPTS_VALUE) + startpts -= m_offset_pts; + +- m_CurrentAudio.inited = false; ++ if (sync) ++ { ++ m_CurrentAudio.inited = false; ++ m_CurrentVideo.inited = false; ++ m_CurrentSubtitle.inited = false; ++ m_CurrentTeletext.inited = false; ++ } ++ + m_CurrentAudio.dts = DVD_NOPTS_VALUE; + m_CurrentAudio.startpts = startpts; + +- m_CurrentVideo.inited = false; + m_CurrentVideo.dts = DVD_NOPTS_VALUE; + m_CurrentVideo.startpts = startpts; + +- m_CurrentSubtitle.inited = false; + m_CurrentSubtitle.dts = DVD_NOPTS_VALUE; + m_CurrentSubtitle.startpts = startpts; + +- m_CurrentTeletext.inited = false; + m_CurrentTeletext.dts = DVD_NOPTS_VALUE; + m_CurrentTeletext.startpts = startpts; + +@@ -3208,7 +3217,7 @@ void CDVDPlayer::FlushBuffers(bool queued, double pts, bool accurate) + m_CurrentTeletext.started = false; + } + +- if(pts != DVD_NOPTS_VALUE) ++ if(pts != DVD_NOPTS_VALUE && sync) + m_clock.Discontinuity(pts); + UpdatePlayState(0); + } +diff --git a/xbmc/cores/dvdplayer/DVDPlayer.h b/xbmc/cores/dvdplayer/DVDPlayer.h +index d3c201e..70ecea9 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayer.h ++++ b/xbmc/cores/dvdplayer/DVDPlayer.h +@@ -310,7 +310,7 @@ class CDVDPlayer : public IPlayer, public CThread, public IDVDPlayer + bool GetCachingTimes(double& play_left, double& cache_left, double& file_offset); + + +- void FlushBuffers(bool queued, double pts = DVD_NOPTS_VALUE, bool accurate = true); ++ void FlushBuffers(bool queued, double pts = DVD_NOPTS_VALUE, bool accurate = true, bool sync = true); + + void HandleMessages(); + void HandlePlaySpeed(); +@@ -359,8 +359,9 @@ class CDVDPlayer : public IPlayer, public CThread, public IDVDPlayer + int m_playSpeed; + struct SSpeedState + { +- double lastpts; // holds last display pts during ff/rw operations +- double lasttime; ++ double lastpts; // holds last display pts during ff/rw operations ++ int64_t lasttime; ++ double lastabstime; + } m_SpeedState; + + int m_errorCount; +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +index 8b02d81..d26ab9c 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -1268,13 +1268,13 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) + + if( m_speed < 0 ) + { +- double decoderPts = m_droppingStats.m_lastDecoderPts; ++ double inputPts = m_droppingStats.m_lastPts; + double renderPts = m_droppingStats.m_lastRenderPts; + if (pts > renderPts) + { +- if (decoderPts >= renderPts) ++ if (inputPts >= renderPts) + { +- Sleep(200); ++ Sleep(50); + } + return result | EOS_DROPPED; + } +@@ -1571,7 +1571,7 @@ double CDVDPlayerVideo::GetCurrentPts() + + if( m_stalled ) + iRenderPts = DVD_NOPTS_VALUE; +- else ++ else if ( m_speed == DVD_PLAYSPEED_NORMAL) + iRenderPts = iRenderPts - max(0.0, iSleepTime); + + return iRenderPts; +@@ -1671,6 +1671,8 @@ int CDVDPlayerVideo::CalcDropRequirement(double pts) + int iSkippedDeint = 0; + int iBufferLevel; + ++ m_droppingStats.m_lastPts = pts; ++ + // get decoder stats + if (!m_pVideoCodec->GetPts(iDecoderPts, iSkippedDeint, interlaced)) + iDecoderPts = pts; +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.h b/xbmc/cores/dvdplayer/DVDPlayerVideo.h +index 509d5f7..7cddda7 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.h ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.h +@@ -51,6 +51,7 @@ class CDroppingStats + double m_totalGain; + double m_lastDecoderPts; + double m_lastRenderPts; ++ double m_lastPts; + unsigned int m_lateFrames; + unsigned int m_dropRequests; + bool m_requestOutputDrop; +-- +1.7.10 + + +From 024ecda241754f02ad985fab9116e33b06b8d174 Mon Sep 17 00:00:00 2001 +From: fritsch +Date: Fri, 2 Nov 2012 17:56:12 +0100 +Subject: [PATCH 54/73] xvba: do not create decoder for surfaces larger than + width 2048 or height 1536 + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp +index e8e376a..b73c48a 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp +@@ -335,6 +335,21 @@ bool CDecoder::Open(AVCodecContext* avctx, const enum PixelFormat fmt, unsigned + return false; + } + ++ // Fixme: Revisit with new SDK ++ // Workaround for 0.74.01-AES-2 that does not signal if surfaces are too large ++ // it seems that xvba does not support anything > 2k ++ // return false, for files that are larger ++ // if you are unlucky, this would kill your decoder ++ // we limit to 2048x1536(+8) now - as this was tested working ++ int surfaceWidth = (avctx->coded_width+15) & ~15; ++ int surfaceHeight = (avctx->coded_height+15) & ~15; ++ if(surfaceHeight > 1544 || surfaceWidth > 2048) ++ { ++ CLog::Log(LOGERROR, "Surface too large, decoder skipped: surfaceWidth %u, surfaceHeight %u", ++ surfaceWidth, surfaceHeight); ++ return false; ++ } ++ + if (!m_dllAvUtil.Load()) + return false; + +-- +1.7.10 + + +From 98ebb0d0232cf4a7ea2082f9f16e210a39e983e8 Mon Sep 17 00:00:00 2001 +From: fritsch +Date: Sun, 4 Nov 2012 16:24:10 +0100 +Subject: [PATCH 55/73] xvba: add string for available decoders - we are + important so make sure we are there + +--- + xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp +index 0cea7a9..6fb74b7 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp +@@ -169,6 +169,11 @@ CDVDVideoCodec* CDVDFactoryCodec::CreateVideoCodec(CDVDStreamInfo &hint, unsigne + #elif defined(_LINUX) && !defined(TARGET_DARWIN) + hwSupport += "VAAPI:no "; + #endif ++#if defined(HAVE_LIBXVBA) && defined(TARGET_LINUX) ++ hwSupport += "XVBA:yes "; ++#elif defined(TARGET_LINUX) ++ hwSupport += "XVBA:no "; ++#endif + + CLog::Log(LOGDEBUG, "CDVDFactoryCodec: compiled in hardware support: %s", hwSupport.c_str()); + +-- +1.7.10 + + +From 84e701f7db6603a2942611d5c74ba645c625ec0d Mon Sep 17 00:00:00 2001 +From: fritsch +Date: Thu, 22 Nov 2012 21:32:21 +0100 +Subject: [PATCH 56/73] xvba: revisit Artefacts. There are more broken video + files out there + +--- + lib/ffmpeg/libavcodec/xvba_h264.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/lib/ffmpeg/libavcodec/xvba_h264.c b/lib/ffmpeg/libavcodec/xvba_h264.c +index a077442..87af687 100644 +--- a/lib/ffmpeg/libavcodec/xvba_h264.c ++++ b/lib/ffmpeg/libavcodec/xvba_h264.c +@@ -102,10 +102,16 @@ static int end_frame(AVCodecContext *avctx) + pic_descriptor->avc_num_ref_frames = h->sps.ref_frame_count; + pic_descriptor->avc_reserved_8bit = 0; + +- /* Set correct level */ +- if (pic_descriptor->level == 41) { ++ /* Set a level that can decode stuff in every case without a lookup table ++ xvba seems to have problems only when the number of Reframes goes beyond ++ the max support number of Level4.1@High. So in praxis decoding a Level 3.0 ++ file that in deed has level4.1@High specs does not matter. We use this fact ++ and check if the ref_frames stay in the range Level4.1@high can decode if ++ not, we set Level5.1 */ ++ if (pic_descriptor->avc_num_ref_frames > 4) { + const unsigned int mbw = pic_descriptor->width_in_mb; + const unsigned int mbh = pic_descriptor->height_in_mb; ++ // this matches Level4.1@High stats to differ between <= 4.1 and 5.1 + const unsigned int max_ref_frames = 12288 * 1024 / (mbw * mbh * 384); + const unsigned int num_ref_frames = pic_descriptor->avc_num_ref_frames; + if (max_ref_frames < num_ref_frames) +-- +1.7.10 + + +From afd776e3e90a1787ce4c3392266d70368de4e164 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Fri, 23 Nov 2012 09:42:02 +0100 +Subject: [PATCH 57/73] xvba: reactivate accidently disabled + IsDecodingFinished + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp +index b73c48a..47ff25f 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp +@@ -1949,8 +1949,6 @@ void COutput::Flush() + + bool COutput::IsDecodingFinished() + { +- return true; +- + // check for decoding to be finished + CXvbaDecodedPicture decodedPic = m_decodedPics.front(); + +-- +1.7.10 + + +From 37576c15f9e3a0c2dce593e9d9cb5a7863845de7 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Fri, 23 Nov 2012 17:41:12 +0100 +Subject: [PATCH 58/73] xrandr: fix query for multiple screens + +--- + xbmc/windowing/X11/XRandR.cpp | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/xbmc/windowing/X11/XRandR.cpp b/xbmc/windowing/X11/XRandR.cpp +index cc933b9..533e03d 100644 +--- a/xbmc/windowing/X11/XRandR.cpp ++++ b/xbmc/windowing/X11/XRandR.cpp +@@ -57,12 +57,14 @@ bool CXRandR::Query(bool force) + + m_outputs.clear(); + // query all screens ++ // we are happy if at least one screen returns results ++ bool success = false; + for(unsigned int screennum=0; screennum +Date: Sun, 2 Dec 2012 15:46:55 +0100 +Subject: [PATCH 59/73] X11: add debug log to print out refresh after xrr + event + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index ef83133..76c6362 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -685,6 +685,12 @@ void CWinSystemX11::NotifyXRREvent() + XOutput *out = g_xrandr.GetOutput(currentOutput); + XMode mode = g_xrandr.GetCurrentMode(currentOutput); + ++ if (out) ++ CLog::Log(LOGDEBUG, "%s - current output: %s, mode: %s, refresh: %.3f", __FUNCTION__ ++ , out->name.c_str(), mode.id.c_str(), mode.hz); ++ else ++ CLog::Log(LOGWARNING, "%s - output name not set", __FUNCTION__); ++ + RESOLUTION_INFO res; + unsigned int i; + bool found(false); +-- +1.7.10 + + +From d418ae1053a3842eb3e6a3bbd84666a5ee3defe2 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Tue, 11 Dec 2012 11:08:13 +0100 +Subject: [PATCH 60/73] X11: dont call XCloseDisplay on shutdown, it crashes + when powered doen by cec on ATI + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index 76c6362..e4e25b2 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -108,7 +108,8 @@ bool CWinSystemX11::DestroyWindowSystem() + //we don't call XCloseDisplay() here, since ati keeps a pointer to our m_dpy + //so instead we just let m_dpy die on exit + // i have seen core dumps on ATI if the display is not closed here +- XCloseDisplay(m_dpy); ++ // crashes when shutting down via cec ++// XCloseDisplay(m_dpy); + } + + // m_SDLSurface is free()'d by SDL_Quit(). +-- +1.7.10 + + +From 3b700401e9aace50b5ce6c5d7ba2a2e33bb5217f Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Wed, 12 Dec 2012 09:52:17 +0100 +Subject: [PATCH 61/73] vdpau: make interop gl default and remove setting, + rename and intvert interop yuv + +--- + language/English/strings.po | 2 +- + xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 17 ++++++++++------- + xbmc/settings/GUISettings.cpp | 3 +-- + xbmc/settings/GUIWindowSettingsCategory.cpp | 23 +++-------------------- + 4 files changed, 15 insertions(+), 30 deletions(-) + +diff --git a/language/English/strings.po b/language/English/strings.po +index ede18b3..281a8a1 100644 +--- a/language/English/strings.po ++++ b/language/English/strings.po +@@ -5121,7 +5121,7 @@ msgid "Allow Vdpau OpenGL interop" + msgstr "" + + msgctxt "#13436" +-msgid "Allow Vdpau OpenGL interop YUV" ++msgid "Prefer VDPAU Video Mixer" + msgstr "" + + msgctxt "#13437" +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +index fec4b88..ad140fb 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +@@ -365,12 +365,15 @@ bool CDecoder::Supports(EINTERLACEMETHOD method) + || method == VS_INTERLACEMETHOD_AUTO) + return true; + +- if (g_guiSettings.GetBool("videoplayer.usevdpauinteropyuv")) ++ if (!m_vdpauConfig.usePixmaps) + { + if (method == VS_INTERLACEMETHOD_RENDER_BOB) + return true; + } + ++ if (method == VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE) ++ return false; ++ + for(SInterlaceMapping* p = g_interlace_mapping; p->method != VS_INTERLACEMETHOD_NONE; p++) + { + if(p->method == method) +@@ -1847,7 +1850,7 @@ void CMixer::SetDeinterlacing() + + SetDeintSkipChroma(); + +- m_config.useInteropYuv = g_guiSettings.GetBool("videoplayer.usevdpauinteropyuv"); ++ m_config.useInteropYuv = !g_guiSettings.GetBool("videoplayer.usevdpaumixer"); + } + + void CMixer::SetDeintSkipChroma() +@@ -2039,7 +2042,7 @@ void CMixer::Init() + m_vdpError = false; + + m_config.upscale = g_advancedSettings.m_videoVDPAUScaling; +- m_config.useInteropYuv = g_guiSettings.GetBool("videoplayer.usevdpauinteropyuv"); ++ m_config.useInteropYuv = !g_guiSettings.GetBool("videoplayer.usevdpaumixer"); + + CreateVdpauMixer(); + } +@@ -2149,11 +2152,12 @@ void CMixer::InitCycle() + DVP_FLAG_INTERLACED); + m_config.useInteropYuv = false; + } +- else if (method == VS_INTERLACEMETHOD_RENDER_BOB && m_config.useInteropYuv) ++ else if (method == VS_INTERLACEMETHOD_RENDER_BOB) + { + m_mixersteps = 1; + m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME; + m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU_420; ++ m_config.useInteropYuv = true; + } + else + { +@@ -3185,7 +3189,7 @@ bool COutput::GLInit() + glVDPAUGetSurfaceivNV = NULL; + #endif + +- m_config.usePixmaps = !g_guiSettings.GetBool("videoplayer.usevdpauinterop"); ++ m_config.usePixmaps = false; + + #ifdef GL_NV_vdpau_interop + if (glewIsSupported("GL_NV_vdpau_interop")) +@@ -3217,8 +3221,7 @@ bool COutput::GLInit() + #endif + { + m_config.usePixmaps = true; +- g_guiSettings.SetBool("videoplayer.usevdpauinterop",false); +- g_guiSettings.SetBool("videoplayer.usevdpauinteropyuv",false); ++ g_guiSettings.SetBool("videoplayer.usevdpaumixer",true); + } + if (!glXBindTexImageEXT) + glXBindTexImageEXT = (PFNGLXBINDTEXIMAGEEXTPROC)glXGetProcAddress((GLubyte *) "glXBindTexImageEXT"); +diff --git a/xbmc/settings/GUISettings.cpp b/xbmc/settings/GUISettings.cpp +index 10ef779..a4bd524 100644 +--- a/xbmc/settings/GUISettings.cpp ++++ b/xbmc/settings/GUISettings.cpp +@@ -690,8 +690,7 @@ void CGUISettings::Initialize() + + #ifdef HAVE_LIBVDPAU + AddBool(vp, "videoplayer.usevdpau", 13425, true); +- AddBool(vp, "videoplayer.usevdpauinterop", 13435, true); +- AddBool(vp, "videoplayer.usevdpauinteropyuv", 13436, false); ++ AddBool(vp, "videoplayer.usevdpaumixer", 13436, true); + #endif + #ifdef HAVE_LIBVA + AddBool(vp, "videoplayer.usevaapi", 13426, true); +diff --git a/xbmc/settings/GUIWindowSettingsCategory.cpp b/xbmc/settings/GUIWindowSettingsCategory.cpp +index 3c19a06..b9f18e4 100644 +--- a/xbmc/settings/GUIWindowSettingsCategory.cpp ++++ b/xbmc/settings/GUIWindowSettingsCategory.cpp +@@ -602,9 +602,9 @@ void CGUIWindowSettingsCategory::UpdateSettings() + pControl->SetEnabled(true); + } + } +- else if (strSetting.Equals("videoplayer.usevdpauinteropyuv")) ++ else if (strSetting.Equals("videoplayer.usevdpaumixer")) + { +- bool hasInterop = g_guiSettings.GetBool("videoplayer.usevdpauinterop"); ++ bool hasInterop = true; + #ifndef GL_NV_vdpau_interop + hasInterop = false; + #endif +@@ -616,24 +616,7 @@ void CGUIWindowSettingsCategory::UpdateSettings() + else + { + pControl->SetEnabled(false); +- g_guiSettings.SetBool("videoplayer.usevdpauinteropyuv",false); +- } +- } +- else if (strSetting.Equals("videoplayer.usevdpauinterop")) +- { +- bool hasInterop = g_guiSettings.GetBool("videoplayer.usevdpau"); +-#ifndef GL_NV_vdpau_interop +- hasInterop = false; +-#endif +- CGUIControl *pControl = (CGUIControl *)GetControl(pSettingControl->GetID()); +- if (pControl && hasInterop && glewIsSupported("GL_NV_vdpau_interop")) +- { +- pControl->SetEnabled(true); +- } +- else +- { +- pControl->SetEnabled(false); +- g_guiSettings.SetBool("videoplayer.usevdpauinterop",false); ++ g_guiSettings.SetBool("videoplayer.usevdpaumixer",true); + } + } + else +-- +1.7.10 + + +From a060312a4e236858bf3c9a97d663c5643796b649 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Wed, 12 Dec 2012 18:34:47 +0100 +Subject: [PATCH 62/73] vdpau: drop studio level conversion + +--- + language/English/strings.po | 6 +- + xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 4 +- + xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 94 +----------------------- + xbmc/settings/GUISettings.cpp | 1 - + 4 files changed, 7 insertions(+), 98 deletions(-) + +diff --git a/language/English/strings.po b/language/English/strings.po +index 281a8a1..fc896b3 100644 +--- a/language/English/strings.po ++++ b/language/English/strings.po +@@ -4371,11 +4371,7 @@ msgctxt "#13121" + msgid "VDPAU HQ Upscaling level" + msgstr "" + +-msgctxt "#13122" +-msgid "VDPAU Studio level color conversion" +-msgstr "" +- +-#empty strings from id 13123 to 13129 ++#empty strings from id 13122 to 13129 + + msgctxt "#13130" + msgid "Blank other displays" +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +index 7c3adcb..0bb924b 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +@@ -3545,7 +3545,7 @@ bool CLinuxRendererGL::Supports(ERENDERFEATURE feature) + { + if(feature == RENDERFEATURE_BRIGHTNESS) + { +- if ((m_renderMethod & RENDER_VDPAU) && !g_guiSettings.GetBool("videoplayer.vdpaustudiolevel")) ++ if (m_renderMethod & RENDER_VDPAU) + return true; + + if (m_renderMethod & RENDER_VAAPI) +@@ -3561,7 +3561,7 @@ bool CLinuxRendererGL::Supports(ERENDERFEATURE feature) + + if(feature == RENDERFEATURE_CONTRAST) + { +- if ((m_renderMethod & RENDER_VDPAU) && !g_guiSettings.GetBool("videoplayer.vdpaustudiolevel")) ++ if (m_renderMethod & RENDER_VDPAU) + return true; + + if (m_renderMethod & RENDER_VAAPI) +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +index ad140fb..5851e1a 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +@@ -57,15 +57,6 @@ + }; + const size_t decoder_profile_count = sizeof(decoder_profiles)/sizeof(CDecoder::Desc); + +-//static float studioCSC[3][4] = +-//{ +-// { 1.0f, 0.0f, 1.57480000f,-0.78740000f}, +-// { 1.0f,-0.18737736f,-0.46813736f, 0.32775736f}, +-// { 1.0f, 1.85556000f, 0.0f,-0.92780000f} +-//}; +-static float studioCSCKCoeffs601[3] = {0.299, 0.587, 0.114}; //BT601 {Kr, Kg, Kb} +-static float studioCSCKCoeffs709[3] = {0.2126, 0.7152, 0.0722}; //BT709 {Kr, Kg, Kb} +- + static struct SInterlaceMapping + { + const EINTERLACEMETHOD method; +@@ -1614,74 +1605,6 @@ void CMixer::PostProcOff() + DisableHQScaling(); + } + +- +-bool CMixer::GenerateStudioCSCMatrix(VdpColorStandard colorStandard, VdpCSCMatrix &studioCSCMatrix) +-{ +- // instead use studioCSCKCoeffs601[3], studioCSCKCoeffs709[3] to generate float[3][4] matrix (float studioCSC[3][4]) +- // m00 = mRY = red: luma factor (contrast factor) (1.0) +- // m10 = mGY = green: luma factor (contrast factor) (1.0) +- // m20 = mBY = blue: luma factor (contrast factor) (1.0) +- // +- // m01 = mRB = red: blue color diff coeff (0.0) +- // m11 = mGB = green: blue color diff coeff (-2Kb(1-Kb)/(Kg)) +- // m21 = mBB = blue: blue color diff coeff ((1-Kb)/0.5) +- // +- // m02 = mRR = red: red color diff coeff ((1-Kr)/0.5) +- // m12 = mGR = green: red color diff coeff (-2Kr(1-Kr)/(Kg)) +- // m22 = mBR = blue: red color diff coeff (0.0) +- // +- // m03 = mRC = red: colour zero offset (brightness factor) (-(1-Kr)/0.5 * (128/255)) +- // m13 = mGC = green: colour zero offset (brightness factor) ((256/255) * (Kb(1-Kb) + Kr(1-Kr)) / Kg) +- // m23 = mBC = blue: colour zero offset (brightness factor) (-(1-Kb)/0.5 * (128/255)) +- +- // columns +- int Y = 0; +- int Cb = 1; +- int Cr = 2; +- int C = 3; +- // rows +- int R = 0; +- int G = 1; +- int B = 2; +- // colour standard coefficients for red, geen, blue +- double Kr, Kg, Kb; +- // colour diff zero position (use standard 8-bit coding precision) +- double CDZ = 128; //256*0.5 +- // range excursion (use standard 8-bit coding precision) +- double EXC = 255; //256-1 +- +- if (colorStandard == VDP_COLOR_STANDARD_ITUR_BT_601) +- { +- Kr = studioCSCKCoeffs601[0]; +- Kg = studioCSCKCoeffs601[1]; +- Kb = studioCSCKCoeffs601[2]; +- } +- else // assume VDP_COLOR_STANDARD_ITUR_BT_709 +- { +- Kr = studioCSCKCoeffs709[0]; +- Kg = studioCSCKCoeffs709[1]; +- Kb = studioCSCKCoeffs709[2]; +- } +- // we keep luma unscaled to retain the levels present in source so that 16-235 luma is converted to RGB 16-235 +- studioCSCMatrix[R][Y] = 1.0; +- studioCSCMatrix[G][Y] = 1.0; +- studioCSCMatrix[B][Y] = 1.0; +- +- studioCSCMatrix[R][Cb] = 0.0; +- studioCSCMatrix[G][Cb] = (double)-2 * Kb * (1 - Kb) / Kg; +- studioCSCMatrix[B][Cb] = (double)(1 - Kb) / 0.5; +- +- studioCSCMatrix[R][Cr] = (double)(1 - Kr) / 0.5; +- studioCSCMatrix[G][Cr] = (double)-2 * Kr * (1 - Kr) / Kg; +- studioCSCMatrix[B][Cr] = 0.0; +- +- studioCSCMatrix[R][C] = (double)-1 * studioCSCMatrix[R][Cr] * CDZ/EXC; +- studioCSCMatrix[G][C] = (double)-1 * (studioCSCMatrix[G][Cb] + studioCSCMatrix[G][Cr]) * CDZ/EXC; +- studioCSCMatrix[B][C] = (double)-1 * studioCSCMatrix[B][Cb] * CDZ/EXC; +- +- return true; +-} +- + void CMixer::SetColor() + { + VdpStatus vdp_st; +@@ -1701,19 +1624,10 @@ void CMixer::SetColor() + //vdp_st = vdp_generate_csc_matrix(&m_Procamp, VDP_COLOR_STANDARD_ITUR_BT_601, &m_CSCMatrix); + + VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX }; +- if (g_guiSettings.GetBool("videoplayer.vdpaustudiolevel")) +- { +- float studioCSC[3][4]; +- GenerateStudioCSCMatrix(colorStandard, studioCSC); +- void const * pm_CSCMatix[] = { &studioCSC }; +- vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix); +- } +- else +- { +- vdp_st = m_config.vdpProcs.vdp_generate_csc_matrix(&m_Procamp, colorStandard, &m_CSCMatrix); +- void const * pm_CSCMatix[] = { &m_CSCMatrix }; +- vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix); +- } ++ vdp_st = m_config.vdpProcs.vdp_generate_csc_matrix(&m_Procamp, colorStandard, &m_CSCMatrix); ++ void const * pm_CSCMatix[] = { &m_CSCMatrix }; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix); ++ + CheckStatus(vdp_st, __LINE__); + } + +diff --git a/xbmc/settings/GUISettings.cpp b/xbmc/settings/GUISettings.cpp +index a4bd524..67aeec9 100644 +--- a/xbmc/settings/GUISettings.cpp ++++ b/xbmc/settings/GUISettings.cpp +@@ -772,7 +772,6 @@ void CGUISettings::Initialize() + AddSeparator(vp, "videoplayer.sep1.5"); + #ifdef HAVE_LIBVDPAU + AddBool(NULL, "videoplayer.vdpauUpscalingLevel", 13121, false); +- AddBool(vp, "videoplayer.vdpaustudiolevel", 13122, false); + #endif + #endif + AddSeparator(vp, "videoplayer.sep5"); +-- +1.7.10 + + +From 6d03704ce1cbc7d09d684da1ced478b2b59c0b35 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Gr=C3=A9gory=20Coutant?= +Date: Wed, 12 Dec 2012 19:49:47 +0100 +Subject: [PATCH 63/73] x11: support for multiple x screens + +--- + xbmc/windowing/X11/XRandR.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/xbmc/windowing/X11/XRandR.cpp b/xbmc/windowing/X11/XRandR.cpp +index 533e03d..7a16488 100644 +--- a/xbmc/windowing/X11/XRandR.cpp ++++ b/xbmc/windowing/X11/XRandR.cpp +@@ -92,7 +92,7 @@ bool CXRandR::Query(bool force, int screennum) + pclose(file); + + TiXmlElement *pRootElement = xmlDoc.RootElement(); +- if (strcasecmp(pRootElement->Value(), "screen") != screennum) ++ if (atoi(pRootElement->Attribute("id")) != screennum) + { + // TODO ERROR + return false; +-- +1.7.10 + + +From 597c8449084e1e5ebfebfb31db570f7826d06517 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Wed, 12 Dec 2012 20:28:49 +0100 +Subject: [PATCH 64/73] vdpau: observe ffmpeg tags for color space + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 38 ++++++++++++++++-------- + xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h | 1 + + 2 files changed, 27 insertions(+), 12 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +index 5851e1a..8858614 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +@@ -907,6 +907,7 @@ int CDecoder::Decode(AVCodecContext *avctx, AVFrame *pFrame) + memset(&pic.DVDPic, 0, sizeof(pic.DVDPic)); + ((CDVDVideoCodecFFmpeg*)avctx->opaque)->GetPictureCommon(&pic.DVDPic); + pic.render = render; ++ pic.DVDPic.color_matrix = avctx->colorspace; + m_bufferStats.IncDecoded(); + m_vdpauOutput.m_dataPort.SendOutMessage(COutputDataProtocol::NEWFRAME, &pic, sizeof(pic)); + +@@ -1513,10 +1514,6 @@ void CMixer::InitCSCMatrix(int Width) + m_Procamp.contrast = 1.0; + m_Procamp.saturation = 1.0; + m_Procamp.hue = 0; +- vdp_st = m_config.vdpProcs.vdp_generate_csc_matrix(&m_Procamp, +- (Width < 1000)? VDP_COLOR_STANDARD_ITUR_BT_601 : VDP_COLOR_STANDARD_ITUR_BT_709, +- &m_CSCMatrix); +- CheckStatus(vdp_st, __LINE__); + } + + void CMixer::CheckFeatures() +@@ -1527,11 +1524,13 @@ void CMixer::CheckFeatures() + m_Upscale = m_config.upscale; + } + if (m_Brightness != g_settings.m_currentVideoSettings.m_Brightness || +- m_Contrast != g_settings.m_currentVideoSettings.m_Contrast) ++ m_Contrast != g_settings.m_currentVideoSettings.m_Contrast || ++ m_ColorMatrix != m_mixerInput[1].DVDPic.color_matrix) + { + SetColor(); + m_Brightness = g_settings.m_currentVideoSettings.m_Brightness; + m_Contrast = g_settings.m_currentVideoSettings.m_Contrast; ++ m_ColorMatrix = m_mixerInput[1].DVDPic.color_matrix; + } + if (m_NoiseReduction != g_settings.m_currentVideoSettings.m_NoiseReduction) + { +@@ -1615,13 +1614,27 @@ void CMixer::SetColor() + m_Procamp.contrast = (float)((g_settings.m_currentVideoSettings.m_Contrast)+50) / 100; + + VdpColorStandard colorStandard; +-// if(vid_height >= 600 || vid_width > 1024) +- if(m_config.surfaceWidth > 1000) +- colorStandard = VDP_COLOR_STANDARD_ITUR_BT_709; +- //vdp_st = vdp_generate_csc_matrix(&m_Procamp, VDP_COLOR_STANDARD_ITUR_BT_709, &m_CSCMatrix); +- else +- colorStandard = VDP_COLOR_STANDARD_ITUR_BT_601; +- //vdp_st = vdp_generate_csc_matrix(&m_Procamp, VDP_COLOR_STANDARD_ITUR_BT_601, &m_CSCMatrix); ++ switch(m_mixerInput[1].DVDPic.color_matrix) ++ { ++ case AVCOL_SPC_BT709: ++ colorStandard = VDP_COLOR_STANDARD_ITUR_BT_709; ++ break; ++ case AVCOL_SPC_BT470BG: ++ case AVCOL_SPC_SMPTE170M: ++ colorStandard = VDP_COLOR_STANDARD_ITUR_BT_601; ++ break; ++ case AVCOL_SPC_SMPTE240M: ++ colorStandard = VDP_COLOR_STANDARD_SMPTE_240M; ++ break; ++ case AVCOL_SPC_FCC: ++ case AVCOL_SPC_UNSPECIFIED: ++ case AVCOL_SPC_RGB: ++ default: ++ if(m_config.surfaceWidth > 1000) ++ colorStandard = VDP_COLOR_STANDARD_ITUR_BT_709; ++ else ++ colorStandard = VDP_COLOR_STANDARD_ITUR_BT_601; ++ } + + VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX }; + vdp_st = m_config.vdpProcs.vdp_generate_csc_matrix(&m_Procamp, colorStandard, &m_CSCMatrix); +@@ -1952,6 +1965,7 @@ void CMixer::Init() + m_Sharpness = 0.0; + m_DeintMode = 0; + m_Deint = 0; ++ m_ColorMatrix = 0; + m_PostProc = false; + m_vdpError = false; + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h +index 4d1559c..471ad68 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h +@@ -334,6 +334,7 @@ class CMixer : private CThread + int m_DeintMode; + int m_Deint; + int m_Upscale; ++ unsigned int m_ColorMatrix : 4; + uint32_t *m_BlackBar; + VdpVideoMixerPictureStructure m_mixerfield; + int m_mixerstep; +-- +1.7.10 + + +From 3f9308d76025ef1e31923fa9a06587f75c00f870 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 20 Dec 2012 19:35:38 +0100 +Subject: [PATCH 65/73] fix compile error after recent change + +--- + xbmc/settings/GUIWindowSettingsCategory.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/xbmc/settings/GUIWindowSettingsCategory.cpp b/xbmc/settings/GUIWindowSettingsCategory.cpp +index b9f18e4..cacb32a 100644 +--- a/xbmc/settings/GUIWindowSettingsCategory.cpp ++++ b/xbmc/settings/GUIWindowSettingsCategory.cpp +@@ -2453,7 +2453,7 @@ void CGUIWindowSettingsCategory::FillInMonitors(CStdString strSetting) + { + // we expect "videoscreen.monitor" but it might be hidden on some platforms, + // so check that we actually have a visable control. +- CBaseSettingControl *control = GetSetting(strSetting); ++ BaseSettingControlPtr control = GetSetting(strSetting); + if (control) + { + control->SetDelayed(); +-- +1.7.10 + + +From 213792b2678760d42740d581a1ee71e186a31c4d Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 24 Dec 2012 16:02:42 +0100 +Subject: [PATCH 66/73] pvr: increase changes counter of stream on stream + change, cosmetics after + dd307930d39d92f145a01a16600cd00e01ec39be + +--- + xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp +index 8c984f6..034e545 100644 +--- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp ++++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp +@@ -348,9 +348,7 @@ void CDVDDemuxPVRClient::RequestStreams() + if (stm) + { + st = dynamic_cast(stm); +- if (!st +- || (st->codec != (CodecID)props.stream[i].iCodecId) +- || (st->iChannels != props.stream[i].iChannels)) ++ if (!st || (st->codec != (CodecID)props.stream[i].iCodecId)) + DisposeStream(i); + } + if (!m_streams[i]) +@@ -367,6 +365,7 @@ void CDVDDemuxPVRClient::RequestStreams() + st->iBitsPerSample = props.stream[i].iBitsPerSample; + m_streams[i] = st; + st->m_parser_split = true; ++ st->changes++; + } + else if (props.stream[i].iCodecType == AVMEDIA_TYPE_VIDEO) + { +-- +1.7.10 + + +From e810d3bd68e89e800fba217e88184c2df0fe4040 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 17 Jan 2013 16:03:22 +0100 +Subject: [PATCH 67/73] X11: add keymapping for XF86XK_Sleep + +--- + xbmc/windowing/WinEventsX11.cpp | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp +index c31877e..ed31c04 100644 +--- a/xbmc/windowing/WinEventsX11.cpp ++++ b/xbmc/windowing/WinEventsX11.cpp +@@ -143,6 +143,7 @@ + , {XK_Break, XBMCK_BREAK} + , {XK_Menu, XBMCK_MENU} + , {XF86XK_PowerOff, XBMCK_POWER} ++, {XF86XK_Sleep, XBMCK_SLEEP} + , {XK_EcuSign, XBMCK_EURO} + , {XK_Undo, XBMCK_UNDO} + /* Media keys */ +-- +1.7.10 + + +From 2cb807b2f801f06723cde1bdd636550c08fc08ab Mon Sep 17 00:00:00 2001 +From: fritsch +Date: Sat, 12 Jan 2013 13:03:50 +0100 +Subject: [PATCH 68/73] dvdplayer: Allow multithread decoding for hi10p + content by default + +This allows decoding of some hi10p material on e.g. AMD Fusion with +both cores at the max. This introduces a new advancedsetting named +disablehi10pmultithreading to disable hi10p decoded multithreaded. +--- + .../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 18 ++++++++++++++++-- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h | 1 + + xbmc/settings/AdvancedSettings.cpp | 2 ++ + xbmc/settings/AdvancedSettings.h | 1 + + 4 files changed, 20 insertions(+), 2 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +index b3252ec..3f8a6e8 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +@@ -154,6 +154,7 @@ enum PixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx + m_iScreenHeight = 0; + m_iOrientation = 0; + m_bSoftware = false; ++ m_isHi10p = false; + m_pHardware = NULL; + m_iLastKeyframe = 0; + m_dts = DVD_NOPTS_VALUE; +@@ -204,7 +205,10 @@ bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options + case FF_PROFILE_H264_HIGH_444_PREDICTIVE: + case FF_PROFILE_H264_HIGH_444_INTRA: + case FF_PROFILE_H264_CAVLC_444: ++ // this is needed to not open the decoders + m_bSoftware = true; ++ // this we need to enable multithreading for hi10p via advancedsettings ++ m_isHi10p = true; + break; + } + } +@@ -277,8 +281,18 @@ bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options + m_pCodecContext->codec_tag = hints.codec_tag; + /* Only allow slice threading, since frame threading is more + * sensitive to changes in frame sizes, and it causes crashes +- * during HW accell */ +- m_pCodecContext->thread_type = FF_THREAD_SLICE; ++ * during HW accell - so we unset it in this case. ++ * ++ * When we detect Hi10p and user did not disable hi10pmultithreading ++ * via advancedsettings.xml we keep the ffmpeg default thread type. ++ * */ ++ if(m_isHi10p && !g_advancedSettings.m_videoDisableHi10pMultithreading) ++ { ++ CLog::Log(LOGDEBUG,"CDVDVideoCodecFFmpeg::Open() Keep default threading for Hi10p: %d", ++ m_pCodecContext->thread_type); ++ } ++ else ++ m_pCodecContext->thread_type = FF_THREAD_SLICE; + + #if defined(TARGET_DARWIN_IOS) + // ffmpeg with enabled neon will crash and burn if this is enabled +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h +index bf4367c..db1d2b2 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h +@@ -116,6 +116,7 @@ class CDVDVideoCodecFFmpeg : public CDVDVideoCodec + + std::string m_name; + bool m_bSoftware; ++ bool m_isHi10p; + IHardwareDecoder *m_pHardware; + int m_iLastKeyframe; + double m_dts; +diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp +index d913924..6a48309 100644 +--- a/xbmc/settings/AdvancedSettings.cpp ++++ b/xbmc/settings/AdvancedSettings.cpp +@@ -116,6 +116,7 @@ void CAdvancedSettings::Initialize() + m_DXVANoDeintProcForProgressive = false; + m_videoFpsDetect = 1; + m_videoDefaultLatency = 0.0; ++ m_videoDisableHi10pMultithreading = false; + + m_musicUseTimeSeeking = true; + m_musicTimeSeekForward = 10; +@@ -502,6 +503,7 @@ void CAdvancedSettings::ParseSettingsFile(const CStdString &file) + XMLUtils::GetBoolean(pElement,"enablehighqualityhwscalers", m_videoEnableHighQualityHwScalers); + XMLUtils::GetFloat(pElement,"autoscalemaxfps",m_videoAutoScaleMaxFps, 0.0f, 1000.0f); + XMLUtils::GetBoolean(pElement,"allowmpeg4vdpau",m_videoAllowMpeg4VDPAU); ++ XMLUtils::GetBoolean(pElement,"disablehi10pmultithreading",m_videoDisableHi10pMultithreading); + XMLUtils::GetBoolean(pElement,"allowmpeg4vaapi",m_videoAllowMpeg4VAAPI); + XMLUtils::GetBoolean(pElement, "disablebackgrounddeinterlace", m_videoDisableBackgroundDeinterlace); + XMLUtils::GetInt(pElement, "useocclusionquery", m_videoCaptureUseOcclusionQuery, -1, 1); +diff --git a/xbmc/settings/AdvancedSettings.h b/xbmc/settings/AdvancedSettings.h +index aaa4702..863e4f3 100644 +--- a/xbmc/settings/AdvancedSettings.h ++++ b/xbmc/settings/AdvancedSettings.h +@@ -168,6 +168,7 @@ class CAdvancedSettings + bool m_DXVAForceProcessorRenderer; + bool m_DXVANoDeintProcForProgressive; + int m_videoFpsDetect; ++ bool m_videoDisableHi10pMultithreading; + + CStdString m_videoDefaultPlayer; + CStdString m_videoDefaultDVDPlayer; +-- +1.7.10 + + +From 5e52fa15742e1300ac394738ead4ca2792c4812c Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 21 Jan 2013 09:00:19 +0100 +Subject: [PATCH 69/73] X11: remove toggle full screen after resume + +--- + xbmc/powermanagement/PowerManager.cpp | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/xbmc/powermanagement/PowerManager.cpp b/xbmc/powermanagement/PowerManager.cpp +index a5534c9..7e2ddc6 100644 +--- a/xbmc/powermanagement/PowerManager.cpp ++++ b/xbmc/powermanagement/PowerManager.cpp +@@ -223,11 +223,6 @@ void CPowerManager::OnWake() + #if defined(_WIN32) + ShowWindow(g_hWnd,SW_RESTORE); + SetForegroundWindow(g_hWnd); +-#elif !defined(TARGET_DARWIN_OSX) +- // Hack to reclaim focus, thus rehiding system mouse pointer. +- // Surely there's a better way? +- g_graphicsContext.ToggleFullScreenRoot(); +- g_graphicsContext.ToggleFullScreenRoot(); + #endif + } + g_application.ResetScreenSaver(); +-- +1.7.10 + + +From e8f3e20dfb3bde4434e2aea69b34e22ba1859a31 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Wed, 23 Jan 2013 17:03:02 +0100 +Subject: [PATCH 70/73] xrandr: set screen on mode change command + +--- + xbmc/windowing/X11/XRandR.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/xbmc/windowing/X11/XRandR.cpp b/xbmc/windowing/X11/XRandR.cpp +index 7a16488..6531ba3 100644 +--- a/xbmc/windowing/X11/XRandR.cpp ++++ b/xbmc/windowing/X11/XRandR.cpp +@@ -246,7 +246,7 @@ bool CXRandR::SetMode(XOutput output, XMode mode) + m_currentMode = modeFound.id; + char cmd[255]; + if (getenv("XBMC_BIN_HOME")) +- snprintf(cmd, sizeof(cmd), "%s/xbmc-xrandr --output %s --mode %s", getenv("XBMC_BIN_HOME"), outputFound.name.c_str(), modeFound.id.c_str()); ++ snprintf(cmd, sizeof(cmd), "%s/xbmc-xrandr --screen %d --output %s --mode %s", getenv("XBMC_BIN_HOME"), outputFound.screen, outputFound.name.c_str(), modeFound.id.c_str()); + else + return false; + CLog::Log(LOGINFO, "XRANDR: %s", cmd); +-- +1.7.10 + + +From f229dba603070e1f0528d395c9d5d63f9044ae6e Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Wed, 23 Jan 2013 17:03:39 +0100 +Subject: [PATCH 71/73] X11: recreate glx context when output changes + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 6 +++--- + xbmc/windowing/X11/WinSystemX11.h | 2 +- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index e4e25b2..b87e264 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -409,11 +409,11 @@ bool CWinSystemX11::IsSuitableVisual(XVisualInfo *vInfo) + return true; + } + +-bool CWinSystemX11::RefreshGlxContext() ++bool CWinSystemX11::RefreshGlxContext(bool force) + { + bool retVal = false; + +- if (m_glContext) ++ if (m_glContext && !force) + { + CLog::Log(LOGDEBUG, "CWinSystemX11::RefreshGlxContext: refreshing context"); + glXMakeCurrent(m_dpy, None, NULL); +@@ -930,7 +930,7 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd + } + + CDirtyRegionList dr; +- RefreshGlxContext(); ++ RefreshGlxContext(!m_currentOutput.Equals(output)); + XSync(m_dpy, FALSE); + g_graphicsContext.Clear(0); + g_graphicsContext.Flip(dr); +diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h +index 0b7c10a..33b1739 100644 +--- a/xbmc/windowing/X11/WinSystemX11.h ++++ b/xbmc/windowing/X11/WinSystemX11.h +@@ -74,7 +74,7 @@ class CWinSystemX11 : public CWinSystemBase + void NotifyMouseCoverage(bool covered); + + protected: +- bool RefreshGlxContext(); ++ bool RefreshGlxContext(bool force); + void CheckDisplayEvents(); + void OnLostDevice(); + bool SetWindow(int width, int height, bool fullscreen, const CStdString &output); +-- +1.7.10 + + +From ae08a23a2f4fd78139e2ebca8a4a87ab619feb0b Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sun, 27 Jan 2013 12:10:19 +0100 +Subject: [PATCH 72/73] vdpau: switch off de-interlacing on ff + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +index 8858614..3e21d9d 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +@@ -2043,8 +2043,9 @@ void CMixer::InitCycle() + EINTERLACEMETHOD method = GetDeinterlacingMethod(); + bool interlaced = m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_INTERLACED; + +- if (mode == VS_DEINTERLACEMODE_FORCE || +- (mode == VS_DEINTERLACEMODE_AUTO && interlaced)) ++ if (!(flags & DVP_FLAG_NO_POSTPROC) && ++ (mode == VS_DEINTERLACEMODE_FORCE || ++ (mode == VS_DEINTERLACEMODE_AUTO && interlaced))) + { + if((method == VS_INTERLACEMETHOD_AUTO && interlaced) + || method == VS_INTERLACEMETHOD_VDPAU_BOB +-- +1.7.10 + + +From 1ea917e026e8c5df15de6ce6276cba9e58d09d3d Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sat, 2 Feb 2013 13:17:09 +0100 +Subject: [PATCH 73/73] vdpau: fix mp4 part2 decoding, activate by default + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 8 ++------ + xbmc/settings/AdvancedSettings.cpp | 2 +- + 2 files changed, 3 insertions(+), 7 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +index 3e21d9d..524efae 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +@@ -127,10 +127,9 @@ bool CDecoder::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int + VdpDecoderProfile profile = 0; + if(avctx->codec_id == CODEC_ID_H264) + profile = VDP_DECODER_PROFILE_H264_HIGH; +-#ifdef VDP_DECODER_PROFILE_MPEG4_PART2_ASP + else if(avctx->codec_id == CODEC_ID_MPEG4) + profile = VDP_DECODER_PROFILE_MPEG4_PART2_ASP; +-#endif ++ + if(profile) + { + if (!CDVDCodecUtils::IsVP3CompatibleWidth(avctx->coded_width)) +@@ -530,13 +529,10 @@ void CDecoder::ReadFormatOf( PixelFormat fmt + vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_ADVANCED; + vdp_chroma_type = VDP_CHROMA_TYPE_420; + break; +-#if (defined PIX_FMT_VDPAU_MPEG4_IN_AVUTIL) && \ +- (defined VDP_DECODER_PROFILE_MP) + case PIX_FMT_VDPAU_MPEG4: +- vdp_decoder_profile = VDP_DECOPEG4_PART2_ASP; ++ vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG4_PART2_ASP; + vdp_chroma_type = VDP_CHROMA_TYPE_420; + break; +-#endif + default: + vdp_decoder_profile = 0; + vdp_chroma_type = 0; +diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp +index 6a48309..d390ec7 100644 +--- a/xbmc/settings/AdvancedSettings.cpp ++++ b/xbmc/settings/AdvancedSettings.cpp +@@ -102,7 +102,7 @@ void CAdvancedSettings::Initialize() + m_videoNonLinStretchRatio = 0.5f; + m_videoEnableHighQualityHwScalers = false; + m_videoAutoScaleMaxFps = 30.0f; +- m_videoAllowMpeg4VDPAU = false; ++ m_videoAllowMpeg4VDPAU = true; + m_videoAllowMpeg4VAAPI = false; + m_videoDisableBackgroundDeinterlace = false; + m_videoCaptureUseOcclusionQuery = -1; //-1 is auto detect +-- +1.7.10 + diff --git a/packages/mediacenter/xbmc/patches/xbmc-995.09-revert-rpi-fixes.patch b/packages/mediacenter/xbmc/patches/xbmc-995.09-revert-rpi-fixes.patch new file mode 100644 index 0000000000..b7d03823ff --- /dev/null +++ b/packages/mediacenter/xbmc/patches/xbmc-995.09-revert-rpi-fixes.patch @@ -0,0 +1,64 @@ +diff -Naur xbmc-12.0.2/xbmc/cores/omxplayer/OMXPlayerVideo.cpp xbmc-12.0.2.patch/xbmc/cores/omxplayer/OMXPlayerVideo.cpp +--- xbmc-12.0.2/xbmc/cores/omxplayer/OMXPlayerVideo.cpp 2013-02-19 19:04:39.000000000 +0100 ++++ xbmc-12.0.2.patch/xbmc/cores/omxplayer/OMXPlayerVideo.cpp 2013-02-22 18:18:47.298296862 +0100 +@@ -124,7 +124,6 @@ + m_started = false; + m_stalled = m_messageQueue.GetPacketCount(CDVDMsg::DEMUXER_PACKET) == 0; + m_autosync = 1; +- m_iSleepEndTime = DVD_NOPTS_VALUE; + + m_audio_count = m_av_clock->HasAudio(); + +@@ -453,23 +452,13 @@ + m_dropbase = 0.0f; + #endif + +- // DVDPlayer sleeps until m_iSleepEndTime here before calling FlipPage. +- // Video playback in asynchronous in OMXPlayer, so we don't want to do that here, as it prevents the video fifo from being kept full. +- // So, we keep track of when FlipPage would have been called on DVDPlayer and return early if it is not time. +- // m_iSleepEndTime == DVD_NOPTS_VALUE means we are not waiting to call FlipPage, otherwise it is the time we want to call FlipPage +- if (m_iSleepEndTime == DVD_NOPTS_VALUE) { +- m_iSleepEndTime = iCurrentClock + iSleepTime; +- } +- +- if (!CThread::m_bStop && m_av_clock->GetAbsoluteClock(false) < m_iSleepEndTime + DVD_MSEC_TO_TIME(500)) +- return; +- + double pts_media = m_av_clock->OMXMediaTime(false, false); + ProcessOverlays(iGroupId, pts_media); + +- g_renderManager.FlipPage(CThread::m_bStop, m_iSleepEndTime / DVD_TIME_BASE, -1, FS_NONE); ++ while(!CThread::m_bStop && m_av_clock->GetAbsoluteClock(false) < (iCurrentClock + iSleepTime + DVD_MSEC_TO_TIME(500)) ) ++ Sleep(1); + +- m_iSleepEndTime = DVD_NOPTS_VALUE; ++ g_renderManager.FlipPage(CThread::m_bStop, (iCurrentClock + iSleepTime) / DVD_TIME_BASE, -1, FS_NONE); + + //m_av_clock->WaitAbsoluteClock((iCurrentClock + iSleepTime)); + } +@@ -580,14 +569,12 @@ + m_av_clock->OMXReset(false); + m_av_clock->UnLock(); + m_started = false; +- m_iSleepEndTime = DVD_NOPTS_VALUE; + } + else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) // private message sent by (COMXPlayerVideo::Flush()) + { + CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_FLUSH"); + m_stalled = true; + m_started = false; +- m_iSleepEndTime = DVD_NOPTS_VALUE; + m_av_clock->Lock(); + m_av_clock->OMXStop(false); + m_omxVideo.Reset(); +diff -Naur xbmc-12.0.2/xbmc/cores/omxplayer/OMXPlayerVideo.h xbmc-12.0.2.patch/xbmc/cores/omxplayer/OMXPlayerVideo.h +--- xbmc-12.0.2/xbmc/cores/omxplayer/OMXPlayerVideo.h 2013-02-19 19:04:39.000000000 +0100 ++++ xbmc-12.0.2.patch/xbmc/cores/omxplayer/OMXPlayerVideo.h 2013-02-22 18:18:44.166310881 +0100 +@@ -49,7 +49,6 @@ + bool m_open; + CDVDStreamInfo m_hints; + double m_iCurrentPts; +- double m_iSleepEndTime; + OMXClock *m_av_clock; + COMXVideo m_omxVideo; + float m_fFrameRate; diff --git a/packages/mediacenter/xbmc/patches/xbmc-995.10-xvba_rpi_fixes-059b89b.patch b/packages/mediacenter/xbmc/patches/xbmc-995.10-xvba_rpi_fixes-059b89b.patch new file mode 100644 index 0000000000..a93becfe17 --- /dev/null +++ b/packages/mediacenter/xbmc/patches/xbmc-995.10-xvba_rpi_fixes-059b89b.patch @@ -0,0 +1,1148 @@ +From bc4a2f53976c71c403b91ab1aa6138f966a90480 Mon Sep 17 00:00:00 2001 +From: unknown +Date: Fri, 18 Jan 2013 15:16:38 +0100 +Subject: [PATCH 1/7] multi-screen: fix compilation on windows + +--- + xbmc/settings/GUIWindowSettingsCategory.cpp | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/xbmc/settings/GUIWindowSettingsCategory.cpp b/xbmc/settings/GUIWindowSettingsCategory.cpp +index cacb32a..cbf0acb 100644 +--- a/xbmc/settings/GUIWindowSettingsCategory.cpp ++++ b/xbmc/settings/GUIWindowSettingsCategory.cpp +@@ -528,12 +528,14 @@ void CGUIWindowSettingsCategory::CreateSettings() + FillInRefreshRates(strSetting, g_guiSettings.GetResolution(), false); + continue; + } ++#if defined(HAS_GLX) + else if (strSetting.Equals("videoscreen.monitor")) + { + AddSetting(pSetting, group->GetWidth(), iControlID); + FillInMonitors(strSetting); + continue; + } ++#endif + else if (strSetting.Equals("lookandfeel.skintheme")) + { + AddSetting(pSetting, group->GetWidth(), iControlID); +@@ -1483,6 +1485,7 @@ void CGUIWindowSettingsCategory::OnSettingChanged(BaseSettingControlPtr pSetting + // Cascade + FillInResolutions("videoscreen.resolution", mode, RES_DESKTOP, true); + } ++#if defined(HAS_GLX) + else if (strSetting.Equals("videoscreen.monitor")) + { + CSettingString *pSettingString = (CSettingString *)pSettingControl->GetSetting(); +@@ -1497,6 +1500,7 @@ void CGUIWindowSettingsCategory::OnSettingChanged(BaseSettingControlPtr pSetting + FillInResolutions("videoscreen.resolution", mode, RES_DESKTOP, true); + } + } ++#endif + else if (strSetting.Equals("videoscreen.resolution")) + { + RESOLUTION nextRes = (RESOLUTION) g_guiSettings.GetInt("videoscreen.resolution"); +@@ -2451,6 +2455,7 @@ DisplayMode CGUIWindowSettingsCategory::FillInScreens(CStdString strSetting, RES + + void CGUIWindowSettingsCategory::FillInMonitors(CStdString strSetting) + { ++#if defined(HAS_GLX) + // we expect "videoscreen.monitor" but it might be hidden on some platforms, + // so check that we actually have a visable control. + BaseSettingControlPtr control = GetSetting(strSetting); +@@ -2476,6 +2481,7 @@ void CGUIWindowSettingsCategory::FillInMonitors(CStdString strSetting) + pControl->SetValue(currentMonitor); + g_guiSettings.SetString("videoscreen.monitor", g_settings.m_ResInfo[RES_DESKTOP].strOutput); + } ++#endif + } + + +@@ -2607,7 +2613,10 @@ void CGUIWindowSettingsCategory::OnRefreshRateChanged(RESOLUTION nextRes) + RESOLUTION lastRes = g_graphicsContext.GetVideoResolution(); + bool cancelled = false; + +- bool outputChanged = !g_Windowing.IsCurrentOutput(g_guiSettings.GetString("videoscreen.monitor")); ++ bool outputChanged = true; ++#if defined(HAS_GLX) ++ outputChanged = !g_Windowing.IsCurrentOutput(g_guiSettings.GetString("videoscreen.monitor")); ++#endif + + g_guiSettings.SetResolution(nextRes); + g_graphicsContext.SetVideoResolution(nextRes, outputChanged); +-- +1.7.10 + + +From 3724a6e137d00f92b5eb4e419883ae239f0562f8 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Fri, 22 Feb 2013 09:57:17 +0100 +Subject: [PATCH 2/7] buffering back ports + +--- + xbmc/cores/IPlayer.h | 5 ++ + xbmc/cores/VideoRenderers/BaseRenderer.h | 7 ++- + xbmc/cores/VideoRenderers/LinuxRendererGL.h | 6 +- + xbmc/cores/VideoRenderers/OverlayRenderer.cpp | 17 +++--- + xbmc/cores/VideoRenderers/OverlayRenderer.h | 8 +-- + xbmc/cores/VideoRenderers/RenderManager.cpp | 64 +++++++++++++--------- + xbmc/cores/VideoRenderers/RenderManager.h | 73 ++++++++++++++++++++++--- + xbmc/cores/dvdplayer/DVDPlayer.cpp | 7 ++- + xbmc/cores/dvdplayer/DVDPlayer.h | 2 + + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 18 +++++- + 10 files changed, 150 insertions(+), 57 deletions(-) + +diff --git a/xbmc/cores/IPlayer.h b/xbmc/cores/IPlayer.h +index f2aa227..cbf2faa 100644 +--- a/xbmc/cores/IPlayer.h ++++ b/xbmc/cores/IPlayer.h +@@ -229,6 +229,11 @@ class IPlayer + */ + virtual void GetSubtitleCapabilities(std::vector &subCaps) { subCaps.assign(1,IPC_SUBS_ALL); }; + ++ /*! ++ \brief called by RenderManager in order to schedule frames ++ */ ++ virtual double GetClock(double& absolute, bool interpolated = true) {return 0; }; ++ + protected: + IPlayerCallback& m_callback; + }; +diff --git a/xbmc/cores/VideoRenderers/BaseRenderer.h b/xbmc/cores/VideoRenderers/BaseRenderer.h +index b02d536..60b7197 100644 +--- a/xbmc/cores/VideoRenderers/BaseRenderer.h ++++ b/xbmc/cores/VideoRenderers/BaseRenderer.h +@@ -26,10 +26,11 @@ + + #define MAX_PLANES 3 + #define MAX_FIELDS 3 ++#define NUM_BUFFERS 10 + + typedef struct YV12Image + { +- BYTE * plane[MAX_PLANES]; ++ uint8_t* plane[MAX_PLANES]; + int planesize[MAX_PLANES]; + unsigned stride[MAX_PLANES]; + unsigned width; +@@ -84,8 +85,8 @@ class CBaseRenderer + virtual void Flush() {}; + + virtual unsigned int GetProcessorSize() { return 0; } +- virtual unsigned int GetMaxProcessorSize() { return 0; } +- virtual void SetProcessorSize(int numBuffers) { } ++ virtual unsigned int GetMaxBufferSize() { return 0; } ++ virtual void SetBufferSize(int numBuffers) { } + virtual void ReleaseBuffer(int idx) { } + + virtual bool Supports(ERENDERFEATURE feature) { return false; } +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.h b/xbmc/cores/VideoRenderers/LinuxRendererGL.h +index e76624b..a189892 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.h ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.h +@@ -46,8 +46,6 @@ + namespace XVBA { class CXvbaRenderPicture; } + + +-#define NUM_BUFFERS 10 +- + #undef ALIGN + #define ALIGN(value, alignment) (((value)+((alignment)-1))&~((alignment)-1)) + #define CLAMP(a, min, max) ((a) > (max) ? (max) : ( (a) < (min) ? (min) : a )) +@@ -141,8 +139,8 @@ class CLinuxRendererGL : public CBaseRenderer + virtual void Reset(); /* resets renderer after seek for example */ + virtual void Flush(); + virtual void ReleaseBuffer(int idx); +- virtual void SetProcessorSize(int numBuffers) { m_NumYV12Buffers = numBuffers; } +- virtual unsigned int GetMaxProcessorSize() { return NUM_BUFFERS; } ++ virtual void SetBufferSize(int numBuffers) { m_NumYV12Buffers = numBuffers; } ++ virtual unsigned int GetMaxBufferSize() { return NUM_BUFFERS; } + virtual unsigned int GetProcessorSize() { return m_NumYV12Buffers; } + + #ifdef HAVE_LIBVDPAU +diff --git a/xbmc/cores/VideoRenderers/OverlayRenderer.cpp b/xbmc/cores/VideoRenderers/OverlayRenderer.cpp +index 94aaaf5..5236390 100644 +--- a/xbmc/cores/VideoRenderers/OverlayRenderer.cpp ++++ b/xbmc/cores/VideoRenderers/OverlayRenderer.cpp +@@ -93,24 +93,28 @@ long COverlayMainThread::Release() + + CRenderer::~CRenderer() + { +- for(int i = 0; i < 2; i++) ++ for(int i = 0; i < NUM_BUFFERS; i++) + Release(m_buffers[i]); + } + +-void CRenderer::AddOverlay(CDVDOverlay* o, double pts) ++void CRenderer::AddOverlay(CDVDOverlay* o, double pts, int index) + { + CSingleLock lock(m_section); + ++ m_decode = index; ++ + SElement e; + e.pts = pts; + e.overlay_dvd = o->Acquire(); + m_buffers[m_decode].push_back(e); + } + +-void CRenderer::AddOverlay(COverlay* o, double pts) ++void CRenderer::AddOverlay(COverlay* o, double pts, int index) + { + CSingleLock lock(m_section); + ++ m_decode = index; ++ + SElement e; + e.pts = pts; + e.overlay = o->Acquire(); +@@ -163,13 +167,6 @@ void CRenderer::Flip() + m_render = (m_render + 1) % m_iNumBuffers; + } + +-void CRenderer::SetBuffer(int idx) +-{ +- CSingleLock lock(m_section); +- Release(m_buffers[idx]); +- m_decode = idx; +-} +- + void CRenderer::ReleaseBuffer(int idx) + { + CSingleLock lock(m_section); +diff --git a/xbmc/cores/VideoRenderers/OverlayRenderer.h b/xbmc/cores/VideoRenderers/OverlayRenderer.h +index c6740a5..66c592a 100644 +--- a/xbmc/cores/VideoRenderers/OverlayRenderer.h ++++ b/xbmc/cores/VideoRenderers/OverlayRenderer.h +@@ -23,6 +23,7 @@ + #pragma once + + #include "threads/CriticalSection.h" ++#include "BaseRenderer.h" + + #include + +@@ -92,14 +93,13 @@ + CRenderer(); + ~CRenderer(); + +- void AddOverlay(CDVDOverlay* o, double pts); +- void AddOverlay(COverlay* o, double pts); ++ void AddOverlay(CDVDOverlay* o, double pts, int index); ++ void AddOverlay(COverlay* o, double pts, int index); + void AddCleanup(COverlay* o); + void Flip(); + void Render(); + void Flush(); + void SetNumBuffers(int numBuffers) { m_iNumBuffers = numBuffers; } +- void SetBuffer(int idx); + void ReleaseBuffer(int idx); + + protected: +@@ -127,7 +127,7 @@ + void Release(SElementV& list); + + CCriticalSection m_section; +- SElementV m_buffers[10]; ++ SElementV m_buffers[NUM_BUFFERS]; + int m_iNumBuffers; + int m_decode; + int m_render; +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index 9290f80..ca454eb 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -228,7 +228,7 @@ CStdString CXBMCRenderManager::GetVSyncState() + return state; + } + +-bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsigned int d_width, unsigned int d_height, float fps, unsigned flags, ERenderFormat format, unsigned extended_format, unsigned int orientation) ++bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsigned int d_width, unsigned int d_height, float fps, unsigned flags, ERenderFormat format, unsigned extended_format, unsigned int orientation, bool buffering) + { + /* make sure any queued frame was fully presented */ + double timeout = m_presenttime + 0.1; +@@ -248,12 +248,8 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi + return false; + } + +- // check if decoder supports buffering +- m_bCodecSupportsBuffering = false; +- if (format == RENDER_FMT_VDPAU +- || format == RENDER_FMT_VDPAU_420 +- || format == RENDER_FMT_XVBA) +- m_bCodecSupportsBuffering = true; ++ // set buffering ++ m_bCodecSupportsBuffering = buffering; + + bool result = m_pRenderer->Configure(width, height, d_width, d_height, fps, flags, format, extended_format, orientation); + if(result) +@@ -325,7 +321,7 @@ void CXBMCRenderManager::RenderUpdate(bool clear, DWORD flags, DWORD alpha) + m_presentevent.Set(); + } + +-unsigned int CXBMCRenderManager::PreInit(CDVDClock *pClock) ++unsigned int CXBMCRenderManager::PreInit() + { + CRetakeLock lock(m_sharedSection); + +@@ -333,7 +329,6 @@ unsigned int CXBMCRenderManager::PreInit(CDVDClock *pClock) + m_presenterr = 0.0; + m_errorindex = 0; + memset(m_errorbuff, 0, sizeof(m_errorbuff)); +- m_pClock = pClock; + + m_bIsStarted = false; + m_bPauseDrawing = false; +@@ -617,10 +612,12 @@ void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0L + } + } + +- FlipFreeBuffer(); +- m_renderBuffers[m_iOutputRenderBuffer].pts = timestamp; +- m_renderBuffers[m_iOutputRenderBuffer].presentfield = presentfield; +- m_renderBuffers[m_iOutputRenderBuffer].presentmethod = presentmethod; ++ if (FlipFreeBuffer() >= 0) ++ { ++ m_renderBuffers[m_iOutputRenderBuffer].pts = timestamp; ++ m_renderBuffers[m_iOutputRenderBuffer].presentfield = presentfield; ++ m_renderBuffers[m_iOutputRenderBuffer].presentmethod = presentmethod; ++ } + m_speed = speed; + } + +@@ -880,9 +877,17 @@ int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic) + #endif + m_pRenderer->ReleaseImage(index, false); + ++ m_bRenderBufferUsed = true; + return index; + } + ++void CXBMCRenderManager::AddOverlay(CDVDOverlay* o, double pts) ++{ ++ CSharedLock lock(m_sharedSection); ++ m_overlays.AddOverlay(o, pts, (m_iOutputRenderBuffer + 1) % m_iNumRenderBuffers); ++ m_bRenderBufferUsed = true; ++} ++ + bool CXBMCRenderManager::Supports(ERENDERFEATURE feature) + { + CSharedLock lock(m_sharedSection); +@@ -939,31 +944,28 @@ EINTERLACEMETHOD CXBMCRenderManager::AutoInterlaceMethodInternal(EINTERLACEMETHO + return mInt; + } + +-int CXBMCRenderManager::WaitForBuffer(volatile bool& bStop) ++int CXBMCRenderManager::WaitForBuffer(volatile bool& bStop, int timeout) + { + CSharedLock lock(m_sharedSection); + if (!m_pRenderer) + return -1; + + //wait up to a second as this is our slowest allowed output rate +- double timeout = GetPresentTime() + 0.1; ++ double maxwait = GetPresentTime() + (float)timeout/1000; + while(!HasFreeBuffer() && !bStop) + { + lock.Leave(); +- m_flipEvent.WaitMSec(50); +- if(GetPresentTime() > timeout && !bStop) ++ m_flipEvent.WaitMSec(std::min(50, timeout)); ++ if(GetPresentTime() > maxwait && !bStop) + { +- CLog::Log(LOGWARNING, "CRenderManager::WaitForBuffer - timeout waiting for buffer"); ++ if (timeout != 0) ++ CLog::Log(LOGWARNING, "CRenderManager::WaitForBuffer - timeout waiting for buffer"); + return -1; + } + lock.Enter(); + } + lock.Leave(); + +- { CRetakeLock lock(m_sharedSection); +- m_overlays.SetBuffer((m_iOutputRenderBuffer + 1) % m_iNumRenderBuffers); +- } +- + if (bStop) + return -1; + +@@ -987,10 +989,17 @@ int CXBMCRenderManager::FlipFreeBuffer() + // See "Render Buffer State Description" in header for information. + if (HasFreeBuffer()) + { ++ if (!m_bRenderBufferUsed) ++ { ++ return -1; ++ } ++ m_bRenderBufferUsed = false; + m_bAllRenderBuffersDisplayed = false; + m_iOutputRenderBuffer = (m_iOutputRenderBuffer + 1) % m_iNumRenderBuffers; + return m_iOutputRenderBuffer; + } ++ else ++ return -1; + } + + bool CXBMCRenderManager::HasFreeBuffer() +@@ -1013,7 +1022,7 @@ bool CXBMCRenderManager::HasFreeBuffer() + + void CXBMCRenderManager::ResetRenderBuffer() + { +- m_iNumRenderBuffers = m_pRenderer->GetMaxProcessorSize(); ++ m_iNumRenderBuffers = m_pRenderer->GetMaxBufferSize(); + m_iNumRenderBuffers = std::min(5, m_iNumRenderBuffers); + m_iNumRenderBuffers = std::max(2, m_iNumRenderBuffers); + +@@ -1022,7 +1031,7 @@ void CXBMCRenderManager::ResetRenderBuffer() + + CLog::Log(LOGNOTICE,"CXBMCRenderManager::ResetRenderBuffer - using %d render buffers", m_iNumRenderBuffers); + m_overlays.SetNumBuffers(m_iNumRenderBuffers); +- m_pRenderer->SetProcessorSize(m_iNumRenderBuffers); ++ m_pRenderer->SetBufferSize(m_iNumRenderBuffers); + + m_iCurrentRenderBuffer = 0; + m_iOutputRenderBuffer = 0; +@@ -1031,6 +1040,7 @@ void CXBMCRenderManager::ResetRenderBuffer() + m_sleeptime = 1.0; + m_presentPts = DVD_NOPTS_VALUE; + m_speed = 0; ++ m_bRenderBufferUsed = false; + } + + void CXBMCRenderManager::PrepareNextRender() +@@ -1045,7 +1055,11 @@ void CXBMCRenderManager::PrepareNextRender() + } + + double iClockSleep, iPlayingClock, iCurrentClock; +- iPlayingClock = m_pClock->GetClock(iCurrentClock, false); ++ if (g_application.m_pPlayer) ++ iPlayingClock = g_application.m_pPlayer->GetClock(iCurrentClock, false); ++ else ++ iPlayingClock = iCurrentClock = 0; ++ + iClockSleep = m_renderBuffers[idx].pts - iPlayingClock; + + if (m_speed) +diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h +index 6746957..1a460c7 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.h ++++ b/xbmc/cores/VideoRenderers/RenderManager.h +@@ -66,21 +66,44 @@ class CXBMCRenderManager + void SetViewMode(int iViewMode); + + // Functions called from mplayer +- bool Configure(unsigned int width, unsigned int height, unsigned int d_width, unsigned int d_height, float fps, unsigned flags, ERenderFormat format, unsigned extended_format, unsigned int orientation); ++ /** ++ * Called by video player to configure renderer ++ * @param width width of decoded frame ++ * @param height height of decoded frame ++ * @param d_width displayed width of frame (aspect ratio) ++ * @param d_height displayed height of frame ++ * @param fps frames per second of video ++ * @param flags see RenderFlags.h ++ * @param format see RenderFormats.h ++ * @param extended_format used by DXVA ++ * @param orientation ++ * @param buffering enable buffering in renderer, defaults to false ++ */ ++ bool Configure(unsigned int width, unsigned int height, unsigned int d_width, unsigned int d_height, float fps, unsigned flags, ERenderFormat format, unsigned extended_format, unsigned int orientation, bool buffering = false); + bool IsConfigured(); + + int AddVideoPicture(DVDVideoPicture& picture); + ++ /** ++ * Called by video player to flip render buffers ++ * If buffering is enabled this method does not block. In case of disabled buffering ++ * this method blocks waiting for the render thread to pass by. ++ * When buffering is used there might be no free buffer available after the call to ++ * this method. Player has to call WaitForBuffer. A free buffer will become ++ * available after the main thread has flipped front / back buffers. ++ * ++ * @param bStop reference to stop flag of calling thread ++ * @param timestamp pts of frame delivered with AddVideoPicture ++ * @param source depreciated ++ * @param sync signals frame, top, or bottom field ++ * @param speed current speed of player, needed to calculate presenttime when buffering is avtive ++ */ + void FlipPage(volatile bool& bStop, double timestamp = 0.0, int source = -1, EFIELDSYNC sync = FS_NONE, int speed = 0); +- unsigned int PreInit(CDVDClock *pClock); ++ unsigned int PreInit(); + void UnInit(); + bool Flush(); + +- void AddOverlay(CDVDOverlay* o, double pts) +- { +- CSharedLock lock(m_sharedSection); +- m_overlays.AddOverlay(o, pts); +- } ++ void AddOverlay(CDVDOverlay* o, double pts); + + void AddCleanup(OVERLAY::COverlay* o) + { +@@ -132,11 +155,43 @@ class CXBMCRenderManager + CSharedSection& GetSection() { return m_sharedSection; }; + + void RegisterRenderUpdateCallBack(const void *ctx, RenderUpdateCallBackFn fn); +- int WaitForBuffer(volatile bool& bStop); ++ ++ /** ++ * If player uses buffering it has to wait for a buffer before it calls ++ * AddVideoPicture and AddOverlay. It waits for max 50 ms before it returns -1 ++ * in case no buffer is available. Player may call this in a loop and decides ++ * by itself when it wants to drop a frame. ++ * If no buffering is requested in Configure, player does not need to call this, ++ * because FlipPage will block. ++ */ ++ int WaitForBuffer(volatile bool& bStop, int timeout = 100); ++ ++ /** ++ * Called by application right after flip. The buffer which has been rendered to ++ * display becomes available for player to deliver a new frame. ++ */ + void NotifyDisplayFlip(); ++ ++ /** ++ * Can be called by player for lateness detection. This is done best by ++ * looking at the end of the queue. ++ */ + bool GetStats(double &sleeptime, double &pts, int &bufferLevel); ++ ++ /** ++ * Called by application (main thread) to query if there is any frame to render ++ */ + bool HasFrame(); ++ ++ /** ++ * Video player can dynamically enable/disable buffering. In situations like ++ * rewind buffering is not ideal. ++ */ + void EnableBuffering(bool enable); ++ ++ /** ++ * Video player call this on flush in oder to discard any queued frames ++ */ + void DiscardBuffer(); + + protected: +@@ -202,6 +257,7 @@ class CXBMCRenderManager + bool m_bUseBuffering; + bool m_bCodecSupportsBuffering; + int m_speed; ++ bool m_bRenderBufferUsed; + CEvent m_flipEvent; + + struct +@@ -225,7 +281,6 @@ class CXBMCRenderManager + int m_presentsource; + CEvent m_presentevent; + CEvent m_flushEvent; +- CDVDClock *m_pClock; + + + OVERLAY::CRenderer m_overlays; +diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp +index 07df0d8..18fae70 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp +@@ -463,7 +463,7 @@ bool CDVDPlayer::OpenFile(const CFileItem& file, const CPlayerOptions &options) + m_ready.Reset(); + + #if defined(HAS_VIDEO_PLAYBACK) +- g_renderManager.PreInit(&m_clock); ++ g_renderManager.PreInit(); + #endif + + Create(); +@@ -4097,3 +4097,8 @@ bool CDVDPlayer::CachePVRStream(void) const + !g_PVRManager.IsPlayingRecording() && + g_advancedSettings.m_bPVRCacheInDvdPlayer; + } ++ ++double CDVDPlayer::GetClock(double& absolute, bool interpolated) ++{ ++ return m_clock.GetClock(absolute, interpolated); ++} +diff --git a/xbmc/cores/dvdplayer/DVDPlayer.h b/xbmc/cores/dvdplayer/DVDPlayer.h +index 70ecea9..2b67d4c 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayer.h ++++ b/xbmc/cores/dvdplayer/DVDPlayer.h +@@ -252,6 +252,8 @@ class CDVDPlayer : public IPlayer, public CThread, public IDVDPlayer + virtual bool SwitchChannel(const PVR::CPVRChannel &channel); + virtual bool CachePVRStream(void) const; + ++ virtual double GetClock(double& absolute, bool interpolated = true); ++ + enum ECacheState + { CACHESTATE_DONE = 0 + , CACHESTATE_FULL // player is filling up the demux queue +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +index d26ab9c..19ba35d 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -1117,53 +1117,69 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) + } + + CStdString formatstr; ++ bool buffering; + + switch(pPicture->format) + { + case RENDER_FMT_YUV420P: + formatstr = "YV12"; ++ buffering = true; + break; + case RENDER_FMT_YUV420P16: + formatstr = "YV12P16"; ++ buffering = true; + break; + case RENDER_FMT_YUV420P10: + formatstr = "YV12P10"; ++ buffering = true; + break; + case RENDER_FMT_NV12: + formatstr = "NV12"; ++ buffering = true; + break; + case RENDER_FMT_UYVY422: + formatstr = "UYVY"; ++ buffering = true; + break; + case RENDER_FMT_YUYV422: + formatstr = "YUY2"; ++ buffering = true; + break; + case RENDER_FMT_VDPAU: + formatstr = "VDPAU"; ++ buffering = true; + break; + case RENDER_FMT_VDPAU_420: + formatstr = "VDPAU_420"; ++ buffering = true; + break; + case RENDER_FMT_DXVA: + formatstr = "DXVA"; ++ buffering = true; + break; + case RENDER_FMT_VAAPI: + formatstr = "VAAPI"; ++ buffering = false; + break; + case RENDER_FMT_OMXEGL: + formatstr = "OMXEGL"; ++ buffering = false; + break; + case RENDER_FMT_CVBREF: + formatstr = "BGRA"; ++ buffering = false; + break; + case RENDER_FMT_BYPASS: + formatstr = "BYPASS"; ++ buffering = false; + break; + case RENDER_FMT_NONE: + formatstr = "NONE"; ++ buffering = false; + break; + case RENDER_FMT_XVBA: + formatstr = "XVBA"; ++ buffering = true; + break; + } + +@@ -1174,7 +1190,7 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) + } + + CLog::Log(LOGDEBUG,"%s - change configuration. %dx%d. framerate: %4.2f. format: %s",__FUNCTION__,pPicture->iWidth, pPicture->iHeight, config_framerate, formatstr.c_str()); +- if(!g_renderManager.Configure(pPicture->iWidth, pPicture->iHeight, pPicture->iDisplayWidth, pPicture->iDisplayHeight, config_framerate, flags, pPicture->format, pPicture->extended_format, m_hints.orientation)) ++ if(!g_renderManager.Configure(pPicture->iWidth, pPicture->iHeight, pPicture->iDisplayWidth, pPicture->iDisplayHeight, config_framerate, flags, pPicture->format, pPicture->extended_format, m_hints.orientation, buffering)) + { + CLog::Log(LOGERROR, "%s - failed to configure renderer", __FUNCTION__); + return EOS_ABORT; +-- +1.7.10 + + +From 1cfeec2846a58b7e2ad44471bb085cef9d2c687d Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sat, 16 Feb 2013 08:32:18 +0100 +Subject: [PATCH 3/7] add buffering for GLES + +--- + xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 10 ---------- + xbmc/cores/VideoRenderers/LinuxRendererGLES.h | 6 ++++-- + 2 files changed, 4 insertions(+), 12 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +index 2a59e2b..1bf2f3b 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +@@ -135,13 +135,6 @@ + delete m_dllSwScale; + } + +-void CLinuxRendererGLES::ManageTextures() +-{ +- m_NumYV12Buffers = 2; +- //m_iYV12RenderBuffer = 0; +- return; +-} +- + bool CLinuxRendererGLES::ValidateRenderTarget() + { + if (!m_bValidated) +@@ -395,7 +388,6 @@ void CLinuxRendererGLES::Update(bool bPauseDrawing) + { + if (!m_bConfigured) return; + ManageDisplay(); +- ManageTextures(); + } + + void CLinuxRendererGLES::RenderUpdate(bool clear, DWORD flags, DWORD alpha) +@@ -409,7 +401,6 @@ void CLinuxRendererGLES::RenderUpdate(bool clear, DWORD flags, DWORD alpha) + if (m_renderMethod & RENDER_BYPASS) + { + ManageDisplay(); +- ManageTextures(); + // if running bypass, then the player might need the src/dst rects + // for sizing video playback on a layer other than the gles layer. + if (m_RenderUpdateCallBackFn) +@@ -449,7 +440,6 @@ void CLinuxRendererGLES::RenderUpdate(bool clear, DWORD flags, DWORD alpha) + return; + + ManageDisplay(); +- ManageTextures(); + + g_graphicsContext.BeginPaint(); + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h +index c6b69db..5bae10d 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h +@@ -41,7 +41,7 @@ + class COpenMaxVideo; + typedef std::vector Features; + +-#define NUM_BUFFERS 3 ++#define NUM_BUFFERS 10 + + + #undef ALIGN +@@ -138,6 +138,9 @@ class CLinuxRendererGLES : public CBaseRenderer + virtual void UnInit(); + virtual void Reset(); /* resets renderer after seek for example */ + virtual void ReorderDrawPoints(); ++ virtual void SetBufferSize(int numBuffers) { m_NumYV12Buffers = numBuffers; } ++ virtual unsigned int GetMaxBufferSize() { return NUM_BUFFERS; } ++ virtual unsigned int GetProcessorSize() { return m_NumYV12Buffers; } + + virtual void RenderUpdate(bool clear, DWORD flags = 0, DWORD alpha = 255); + +@@ -162,7 +165,6 @@ class CLinuxRendererGLES : public CBaseRenderer + protected: + virtual void Render(DWORD flags, int index); + +- virtual void ManageTextures(); + int NextYV12Texture(); + virtual bool ValidateRenderTarget(); + virtual void LoadShaders(int field=FIELD_FULL); +-- +1.7.10 + + +From 20fe728e43350442747c05adde545103516f377b Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sun, 10 Feb 2013 18:40:30 +0100 +Subject: [PATCH 4/7] OMXPlayer: adapt to buffering + +--- + xbmc/cores/omxplayer/OMXPlayer.cpp | 6 ++++++ + xbmc/cores/omxplayer/OMXPlayer.h | 2 ++ + xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 21 +++++++++++++-------- + 3 files changed, 21 insertions(+), 8 deletions(-) + +diff --git a/xbmc/cores/omxplayer/OMXPlayer.cpp b/xbmc/cores/omxplayer/OMXPlayer.cpp +index 60aa9ab..b4eda41 100644 +--- a/xbmc/cores/omxplayer/OMXPlayer.cpp ++++ b/xbmc/cores/omxplayer/OMXPlayer.cpp +@@ -4210,4 +4210,10 @@ void COMXPlayer::GetSubtitleCapabilities(std::vector &subCaps) + subCaps.push_back(IPC_SUBS_ALL); + } + ++double COMXPlayer::GetClock(double& absolute, bool interpolated) ++{ ++ m_av_clock.GetClock(absolute, interpolated); ++ return m_av_clock.OMXMediaTime(false, false); ++} ++ + #endif +diff --git a/xbmc/cores/omxplayer/OMXPlayer.h b/xbmc/cores/omxplayer/OMXPlayer.h +index d606e84..ad9d1e6 100644 +--- a/xbmc/cores/omxplayer/OMXPlayer.h ++++ b/xbmc/cores/omxplayer/OMXPlayer.h +@@ -332,6 +332,8 @@ class COMXPlayer : public IPlayer, public CThread, public IDVDPlayer + virtual void GetScalingMethods(std::vector &scalingMethods); + virtual void GetAudioCapabilities(std::vector &audioCaps); + virtual void GetSubtitleCapabilities(std::vector &subCaps); ++ ++ virtual double GetClock(double& absolute, bool interpolated = true); + protected: + friend class COMXSelectionStreams; + +diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp +index 90f94aa..ecf4c9a 100644 +--- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp ++++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp +@@ -158,6 +158,8 @@ bool OMXPlayerVideo::OpenStream(CDVDStreamInfo &hints) + m_open = true; + m_send_eos = false; + ++ g_renderManager.EnableBuffering(false); ++ + return true; + } + +@@ -358,7 +360,7 @@ void OMXPlayerVideo::Output(int iGroupId, double pts, bool bDropPacket) + + if(!g_renderManager.Configure(m_hints.width, m_hints.height, + iDisplayWidth, iDisplayHeight, m_fps, flags, format, 0, +- m_hints.orientation)) ++ m_hints.orientation, true)) + { + CLog::Log(LOGERROR, "%s - failed to configure renderer", __FUNCTION__); + return; +@@ -452,15 +454,15 @@ void OMXPlayerVideo::Output(int iGroupId, double pts, bool bDropPacket) + m_dropbase = 0.0f; + #endif + +- double pts_media = m_av_clock->OMXMediaTime(false, false); +- ProcessOverlays(iGroupId, pts_media); +- +- while(!CThread::m_bStop && m_av_clock->GetAbsoluteClock(false) < (iCurrentClock + iSleepTime + DVD_MSEC_TO_TIME(500)) ) +- Sleep(1); ++ int buffer = g_renderManager.WaitForBuffer(m_bStop, 0); ++ if (buffer < 0) ++ return; + +- g_renderManager.FlipPage(CThread::m_bStop, (iCurrentClock + iSleepTime) / DVD_TIME_BASE, -1, FS_NONE); ++ double pts_overlay = m_av_clock->OMXMediaTime(false, false) ++ + 2* (double)DVD_TIME_BASE / g_graphicsContext.GetFPS(); ++ ProcessOverlays(iGroupId, pts_overlay); + +- //m_av_clock->WaitAbsoluteClock((iCurrentClock + iSleepTime)); ++ g_renderManager.FlipPage(CThread::m_bStop, pts_overlay, -1, FS_NONE, m_speed); + } + + void OMXPlayerVideo::Process() +@@ -569,6 +571,7 @@ void OMXPlayerVideo::Process() + m_av_clock->OMXReset(false); + m_av_clock->UnLock(); + m_started = false; ++ g_renderManager.EnableBuffering(false); + } + else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) // private message sent by (COMXPlayerVideo::Flush()) + { +@@ -580,6 +583,7 @@ void OMXPlayerVideo::Process() + m_omxVideo.Reset(); + m_av_clock->OMXReset(false); + m_av_clock->UnLock(); ++ g_renderManager.EnableBuffering(false); + } + else if (pMsg->IsType(CDVDMsg::PLAYER_SETSPEED)) + { +@@ -664,6 +668,7 @@ void OMXPlayerVideo::Process() + m_codecname = m_omxVideo.GetDecoderName(); + m_started = true; + m_messageParent.Put(new CDVDMsgInt(CDVDMsg::PLAYER_STARTED, DVDPLAYER_VIDEO)); ++ g_renderManager.EnableBuffering(true); + } + + // guess next frame pts. iDuration is always valid +-- +1.7.10 + + +From 192e1b003ddbda567342c42fb20ce5c7dee28ab1 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 21 Feb 2013 18:09:07 +0100 +Subject: [PATCH 5/7] fix ass subs for GLES + +--- + xbmc/cores/VideoRenderers/OverlayRendererGL.cpp | 33 +++++++++++++++-------- + 1 file changed, 22 insertions(+), 11 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/OverlayRendererGL.cpp b/xbmc/cores/VideoRenderers/OverlayRendererGL.cpp +index 4375d19..ed8e48d 100644 +--- a/xbmc/cores/VideoRenderers/OverlayRendererGL.cpp ++++ b/xbmc/cores/VideoRenderers/OverlayRendererGL.cpp +@@ -359,7 +359,7 @@ static void LoadTexture(GLenum target + + void COverlayGlyphGL::Render(SRenderState& state) + { +- if (m_texture == 0) ++ if ((m_texture == 0) || (m_count == 0)) + return; + + glEnable(GL_TEXTURE_2D); +@@ -418,21 +418,32 @@ void COverlayGlyphGL::Render(SRenderState& state) + GLint colLoc = g_Windowing.GUIShaderGetCol(); + GLint tex0Loc = g_Windowing.GUIShaderGetCoord0(); + +- glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(VERTEX), (char*)m_vertex + offsetof(VERTEX, x)); +- glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(VERTEX), (char*)m_vertex + offsetof(VERTEX, r)); +- glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(VERTEX), (char*)m_vertex + offsetof(VERTEX, u)); ++ // stack object until VBOs will be used ++ std::vector vecVertices( 6 * m_count); ++ VERTEX *vertices = &vecVertices[0]; ++ ++ for (int i=0; i +Date: Sun, 24 Feb 2013 09:55:00 +0100 +Subject: [PATCH 6/7] flip free buffer after overlay has been released + +--- + xbmc/cores/VideoRenderers/OverlayRenderer.cpp | 19 ++++++++++++------- + xbmc/cores/VideoRenderers/OverlayRenderer.h | 6 +++--- + xbmc/cores/VideoRenderers/RenderManager.cpp | 6 ++++-- + xbmc/cores/VideoRenderers/RenderManager.h | 1 + + 4 files changed, 20 insertions(+), 12 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/OverlayRenderer.cpp b/xbmc/cores/VideoRenderers/OverlayRenderer.cpp +index 5236390..3039751 100644 +--- a/xbmc/cores/VideoRenderers/OverlayRenderer.cpp ++++ b/xbmc/cores/VideoRenderers/OverlayRenderer.cpp +@@ -127,27 +127,32 @@ void CRenderer::AddCleanup(COverlay* o) + m_cleanup.push_back(o->Acquire()); + } + +-void CRenderer::Release(SElementV& list) ++long CRenderer::Release(SElementV& list) + { + SElementV l = list; + list.clear(); + ++ long count = 0; + for(SElementV::iterator it = l.begin(); it != l.end(); it++) + { + if(it->overlay) +- it->overlay->Release(); ++ count += it->overlay->Release(); + if(it->overlay_dvd) +- it->overlay_dvd->Release(); ++ count += it->overlay_dvd->Release(); + } ++ return count; + } + +-void CRenderer::Release(COverlayV& list) ++long CRenderer::Release(COverlayV& list) + { + COverlayV l = list; + list.clear(); + ++ long count = 0; + for(COverlayV::iterator it = l.begin(); it != l.end(); it++) +- (*it)->Release(); ++ count += (*it)->Release(); ++ ++ return count; + } + + void CRenderer::Flush() +@@ -167,10 +172,10 @@ void CRenderer::Flip() + m_render = (m_render + 1) % m_iNumBuffers; + } + +-void CRenderer::ReleaseBuffer(int idx) ++long CRenderer::ReleaseBuffer(int idx) + { + CSingleLock lock(m_section); +- Release(m_buffers[idx]); ++ return Release(m_buffers[idx]); + } + + void CRenderer::Render() +diff --git a/xbmc/cores/VideoRenderers/OverlayRenderer.h b/xbmc/cores/VideoRenderers/OverlayRenderer.h +index 66c592a..2fcac4a 100644 +--- a/xbmc/cores/VideoRenderers/OverlayRenderer.h ++++ b/xbmc/cores/VideoRenderers/OverlayRenderer.h +@@ -100,7 +100,7 @@ + void Render(); + void Flush(); + void SetNumBuffers(int numBuffers) { m_iNumBuffers = numBuffers; } +- void ReleaseBuffer(int idx); ++ long ReleaseBuffer(int idx); + + protected: + +@@ -123,8 +123,8 @@ + COverlay* Convert(CDVDOverlay* o, double pts); + COverlay* Convert(CDVDOverlaySSA* o, double pts); + +- void Release(COverlayV& list); +- void Release(SElementV& list); ++ long Release(COverlayV& list); ++ long Release(SElementV& list); + + CCriticalSection m_section; + SElementV m_buffers[NUM_BUFFERS]; +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index ca454eb..bc2e403 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -989,7 +989,7 @@ int CXBMCRenderManager::FlipFreeBuffer() + // See "Render Buffer State Description" in header for information. + if (HasFreeBuffer()) + { +- if (!m_bRenderBufferUsed) ++ if (!m_bRenderBufferUsed && !m_bOverlayReleased) + { + return -1; + } +@@ -1041,6 +1041,7 @@ void CXBMCRenderManager::ResetRenderBuffer() + m_presentPts = DVD_NOPTS_VALUE; + m_speed = 0; + m_bRenderBufferUsed = false; ++ m_bOverlayReleased = false; + } + + void CXBMCRenderManager::PrepareNextRender() +@@ -1119,7 +1120,8 @@ void CXBMCRenderManager::NotifyDisplayFlip() + && m_iDisplayedRenderBuffer != m_iCurrentRenderBuffer) + { + m_pRenderer->ReleaseBuffer(m_iDisplayedRenderBuffer); +- m_overlays.ReleaseBuffer(m_iDisplayedRenderBuffer); ++ if (m_overlays.ReleaseBuffer(m_iDisplayedRenderBuffer) > 0) ++ m_bOverlayReleased = true; + } + } + +diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h +index 1a460c7..fd85882 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.h ++++ b/xbmc/cores/VideoRenderers/RenderManager.h +@@ -258,6 +258,7 @@ class CXBMCRenderManager + bool m_bCodecSupportsBuffering; + int m_speed; + bool m_bRenderBufferUsed; ++ bool m_bOverlayReleased; + CEvent m_flipEvent; + + struct +-- +1.7.10 + + +From 059b89b5e0b50af7560783a4e6a0638ab9f2680c Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sun, 24 Feb 2013 17:38:25 +0100 +Subject: [PATCH 7/7] RverlayRenderer: align buffers with index in + renderManager + +--- + xbmc/cores/VideoRenderers/OverlayRenderer.cpp | 7 +++++-- + xbmc/cores/VideoRenderers/OverlayRenderer.h | 2 +- + xbmc/cores/VideoRenderers/RenderManager.cpp | 5 +++-- + 3 files changed, 9 insertions(+), 5 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/OverlayRenderer.cpp b/xbmc/cores/VideoRenderers/OverlayRenderer.cpp +index 3039751..5592eca 100644 +--- a/xbmc/cores/VideoRenderers/OverlayRenderer.cpp ++++ b/xbmc/cores/VideoRenderers/OverlayRenderer.cpp +@@ -166,10 +166,13 @@ void CRenderer::Flush() + Release(m_cleanup); + } + +-void CRenderer::Flip() ++void CRenderer::Flip(int source) + { + CSingleLock lock(m_section); +- m_render = (m_render + 1) % m_iNumBuffers; ++ if( source >= 0 && source < m_iNumBuffers ) ++ m_render = source; ++ else ++ m_render = (m_render + 1) % m_iNumBuffers; + } + + long CRenderer::ReleaseBuffer(int idx) +diff --git a/xbmc/cores/VideoRenderers/OverlayRenderer.h b/xbmc/cores/VideoRenderers/OverlayRenderer.h +index 2fcac4a..627dd9f 100644 +--- a/xbmc/cores/VideoRenderers/OverlayRenderer.h ++++ b/xbmc/cores/VideoRenderers/OverlayRenderer.h +@@ -96,7 +96,7 @@ + void AddOverlay(CDVDOverlay* o, double pts, int index); + void AddOverlay(COverlay* o, double pts, int index); + void AddCleanup(COverlay* o); +- void Flip(); ++ void Flip(int source); + void Render(); + void Flush(); + void SetNumBuffers(int numBuffers) { m_iNumBuffers = numBuffers; } +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index bc2e403..099eb4d 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -303,7 +303,7 @@ void CXBMCRenderManager::RenderUpdate(bool clear, DWORD flags, DWORD alpha) + if(m_presentstep == PRESENT_FLIP) + { + FlipRenderBuffer(); +- m_overlays.Flip(); ++ m_overlays.Flip(m_presentsource); + m_pRenderer->FlipPage(m_presentsource); + m_presentstep = PRESENT_FRAME; + m_presentevent.Set(); +@@ -703,7 +703,7 @@ void CXBMCRenderManager::Present() + if(m_presentstep == PRESENT_FLIP) + { + FlipRenderBuffer(); +- m_overlays.Flip(); ++ m_overlays.Flip(m_presentsource); + m_pRenderer->FlipPage(m_presentsource); + m_presentstep = PRESENT_FRAME; + m_presentevent.Set(); +@@ -994,6 +994,7 @@ int CXBMCRenderManager::FlipFreeBuffer() + return -1; + } + m_bRenderBufferUsed = false; ++ m_bOverlayReleased = false; + m_bAllRenderBuffersDisplayed = false; + m_iOutputRenderBuffer = (m_iOutputRenderBuffer + 1) % m_iNumRenderBuffers; + return m_iOutputRenderBuffer; +-- +1.7.10 +