diff --git a/packages/mediacenter/xbmc-theme-Confluence/meta b/packages/mediacenter/xbmc-theme-Confluence/meta index 0430faf0d3..f74c78c9b8 100644 --- a/packages/mediacenter/xbmc-theme-Confluence/meta +++ b/packages/mediacenter/xbmc-theme-Confluence/meta @@ -20,6 +20,9 @@ PKG_NAME="xbmc-theme-Confluence" PKG_VERSION="12.1" +if [ "$XBMC" = "master" ]; then + PKG_VERSION="8ad691a" +fi PKG_REV="1" PKG_ARCH="any" PKG_LICENSE="GPL" diff --git a/packages/mediacenter/xbmc/meta b/packages/mediacenter/xbmc/meta index 6417432f69..6c1a5c11fa 100644 --- a/packages/mediacenter/xbmc/meta +++ b/packages/mediacenter/xbmc/meta @@ -20,6 +20,9 @@ PKG_NAME="xbmc" PKG_VERSION="12.1" +if [ "$XBMC" = "master" ]; then + PKG_VERSION="8ad691a" +fi PKG_REV="1" PKG_ARCH="any" PKG_LICENSE="GPL" diff --git a/packages/mediacenter/xbmc/patches/8ad691a/xbmc-995.01-xvba_support-028576f.patch b/packages/mediacenter/xbmc/patches/8ad691a/xbmc-995.01-xvba_support-028576f.patch new file mode 100644 index 0000000000..87b7447833 --- /dev/null +++ b/packages/mediacenter/xbmc/patches/8ad691a/xbmc-995.01-xvba_support-028576f.patch @@ -0,0 +1,22265 @@ +From bc8e7bffd14182e49faed647b7a549bab8a0ccd4 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 28 May 2012 10:03:31 +0200 +Subject: [PATCH 01/99] VideoRenerers: add buffering + +--- + xbmc/Application.cpp | 3 + + xbmc/cores/IPlayer.h | 2 + + 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 | 24 +- + xbmc/cores/VideoRenderers/OverlayRenderer.h | 9 +- + xbmc/cores/VideoRenderers/RenderManager.cpp | 289 ++++++++++++++++++++---- + xbmc/cores/VideoRenderers/RenderManager.h | 63 +++++- + xbmc/cores/VideoRenderers/WinRenderer.cpp | 8 +- + xbmc/cores/VideoRenderers/WinRenderer.h | 2 +- + xbmc/cores/dvdplayer/DVDPlayer.cpp | 5 + + xbmc/cores/dvdplayer/DVDPlayer.h | 2 + + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 34 ++- + 16 files changed, 412 insertions(+), 100 deletions(-) + +diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp +index b4b1bff..944b29f 100644 +--- a/xbmc/Application.cpp ++++ b/xbmc/Application.cpp +@@ -2471,7 +2471,10 @@ void CApplication::Render() + m_lastFrameTime = XbmcThreads::SystemClockMillis(); + + if (flip) ++ { + g_graphicsContext.Flip(dirtyRegions); ++ g_renderManager.NotifyDisplayFlip(); ++ } + CTimeUtils::UpdateFrameTime(flip); + + g_renderManager.UpdateResolution(); +diff --git a/xbmc/cores/IPlayer.h b/xbmc/cores/IPlayer.h +index 6b713dc..9be9e22 100644 +--- a/xbmc/cores/IPlayer.h ++++ b/xbmc/cores/IPlayer.h +@@ -244,6 +244,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/BaseRenderer.h b/xbmc/cores/VideoRenderers/BaseRenderer.h +index 3e1944d..34fbd19 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 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.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +index 7d53d86..fb98d05 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +@@ -251,14 +251,6 @@ bool CLinuxRendererGL::ValidateRenderer() + return true; + } + +- +-void CLinuxRendererGL::ManageTextures() +-{ +- m_NumYV12Buffers = 2; +- //m_iYV12RenderBuffer = 0; +- return; +-} +- + bool CLinuxRendererGL::ValidateRenderTarget() + { + if (!m_bValidated) +@@ -619,13 +611,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(); + m_scalingMethodGui = (ESCALINGMETHOD)-1; + } + +@@ -642,7 +649,6 @@ void CLinuxRendererGL::RenderUpdate(bool clear, DWORD flags, DWORD alpha) + } + + ManageDisplay(); +- ManageTextures(); + + g_graphicsContext.BeginPaint(); + +@@ -799,7 +805,6 @@ unsigned int CLinuxRendererGL::PreInit() + m_resolution = RES_DESKTOP; + + m_iYV12RenderBuffer = 0; +- m_NumYV12Buffers = 2; + + m_formats.push_back(RENDER_FMT_YUV420P); + GLint size; +@@ -2482,7 +2487,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(); +@@ -3436,26 +3441,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 40e31c5..fc513db 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 SetBufferSize(int numBuffers) { m_NumYV12Buffers = numBuffers; } ++ virtual unsigned int GetMaxBufferSize() { 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 cca55c7..31b8de4 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +@@ -1992,16 +1992,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 cf814d7..c1d51b9 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 30267a2..ce7c3e9 100644 +--- a/xbmc/cores/VideoRenderers/OverlayRenderer.cpp ++++ b/xbmc/cores/VideoRenderers/OverlayRenderer.cpp +@@ -91,29 +91,32 @@ long COverlayMainThread::Release() + CRenderer::CRenderer() + { + m_render = 0; +- m_decode = (m_render + 1) % 2; + } + + 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(); +@@ -153,20 +156,23 @@ 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; +- +- 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 5790703..b532ee3 100644 +--- a/xbmc/cores/VideoRenderers/OverlayRenderer.h ++++ b/xbmc/cores/VideoRenderers/OverlayRenderer.h +@@ -92,12 +92,14 @@ + 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 ReleaseBuffer(int idx); + + protected: + +@@ -125,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 14c3084..df15e0a 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" +@@ -233,7 +234,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; +@@ -253,6 +254,9 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi + return false; + } + ++ // set buffering ++ m_bCodecSupportsBuffering = buffering; ++ + bool result = m_pRenderer->Configure(width, height, d_width, d_height, fps, flags, format, extended_format, orientation); + if(result) + { +@@ -267,6 +271,7 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi + m_bReconfigured = true; + m_presentstep = PRESENT_IDLE; + m_presentevent.Set(); ++ ResetRenderBuffer(); + } + + return result; +@@ -298,8 +303,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; +@@ -344,6 +353,10 @@ unsigned int CXBMCRenderManager::PreInit() + + UpdateDisplayLatency(); + ++ m_bUseBuffering = false; ++ m_bCodecSupportsBuffering = true; ++ ResetRenderBuffer(); ++ + return m_pRenderer->PreInit(); + } + +@@ -372,7 +385,9 @@ bool CXBMCRenderManager::Flush() + + CRetakeLock lock(m_sharedSection); + m_pRenderer->Flush(); ++ m_overlays.Flush(); + m_flushEvent.Set(); ++ ResetRenderBuffer(); + } + else + { +@@ -540,25 +555,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 /*= 1000*/) + { +- 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; +@@ -566,57 +577,66 @@ 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 = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode; + EINTERLACEMETHOD interlacemethod = AutoInterlaceMethodInternal(CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod); + + 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 + { + bool invert = false; +- 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; ++ } + } + } + } +@@ -680,8 +700,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; +@@ -805,11 +829,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; +@@ -835,19 +859,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); + +@@ -909,3 +933,172 @@ EINTERLACEMETHOD CXBMCRenderManager::AutoInterlaceMethodInternal(EINTERLACEMETHO + + return mInt; + } ++ ++int CXBMCRenderManager::WaitForBuffer(volatile bool& bStop, int timeout) ++{ ++ CSharedLock lock(m_sharedSection); ++ if (!m_pRenderer) ++ return -1; ++ ++ double maxwait = GetPresentTime() + (float)timeout/1000; ++ while(!HasFreeBuffer() && !bStop) ++ { ++ lock.Leave(); ++ m_flipEvent.WaitMSec(std::min(50, timeout)); ++ if(GetPresentTime() > maxwait && !bStop) ++ { ++ if (timeout != 0) ++ CLog::Log(LOGWARNING, "CRenderManager::WaitForBuffer - timeout waiting for buffer"); ++ return -1; ++ } ++ lock.Enter(); ++ } ++ lock.Leave(); ++ ++ 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->GetMaxBufferSize(); ++ 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->SetBufferSize(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) ++ return; ++ ++ double iClockSleep, iPlayingClock, iCurrentClock; ++ 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) ++ 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; ++ double frametime = 1 / g_graphicsContext.GetFPS(); ++ ++ if (g_graphicsContext.IsFullScreenVideo() || presenttime <= clocktime + frametime) ++ { ++ 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) ++ { ++ 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 e79a12b..6ba1653 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; } +@@ -65,12 +66,12 @@ 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 = false); + bool IsConfigured(); + + int AddVideoPicture(DVDVideoPicture& picture); + +- void FlipPage(volatile bool& bStop, double timestamp = 0.0, int source = -1, EFIELDSYNC sync = FS_NONE); ++ void FlipPage(volatile bool& bStop, double timestamp = 0.0, int source = -1, EFIELDSYNC sync = FS_NONE, int speed = 1000); + unsigned int PreInit(); + void UnInit(); + bool Flush(); +@@ -78,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) +@@ -132,6 +133,24 @@ class CXBMCRenderManager + + void RegisterRenderUpdateCallBack(const void *ctx, RenderUpdateCallBackFn fn); + ++ /** ++ * 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(); ++ void EnableBuffering(bool enable); ++ void DiscardBuffer(); ++ + protected: + void Render(bool clear, DWORD flags, DWORD alpha); + +@@ -139,6 +158,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 +195,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; +diff --git a/xbmc/cores/VideoRenderers/WinRenderer.cpp b/xbmc/cores/VideoRenderers/WinRenderer.cpp +index 6ed53dc..c108096 100644 +--- a/xbmc/cores/VideoRenderers/WinRenderer.cpp ++++ b/xbmc/cores/VideoRenderers/WinRenderer.cpp +@@ -262,12 +262,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]; +@@ -283,7 +283,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 251aa31..ff9dfdf 100644 +--- a/xbmc/cores/VideoRenderers/WinRenderer.h ++++ b/xbmc/cores/VideoRenderers/WinRenderer.h +@@ -158,7 +158,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 cdf5876..38c3f1e 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp +@@ -4157,3 +4157,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 fa6c99f..a76b1ee 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayer.h ++++ b/xbmc/cores/dvdplayer/DVDPlayer.h +@@ -246,6 +246,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 f1ebec2..eefafc9 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -262,6 +262,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) +@@ -437,6 +438,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()) + { +@@ -449,6 +451,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; +@@ -600,6 +603,8 @@ void CDVDPlayerVideo::Process() + + m_pVideoCodec->Reset(); + m_packets.clear(); ++ picture.iFlags &= ~DVP_FLAG_ALLOCATED; ++ g_renderManager.DiscardBuffer(); + break; + } + +@@ -714,6 +719,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 +@@ -1102,47 +1108,61 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) + } + + CStdString formatstr; ++ bool buffering = false; + + 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_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; + } + +@@ -1153,7 +1173,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; +@@ -1331,6 +1351,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); + +@@ -1347,7 +1377,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.8.1.5 + + +From 59639f3be692e46d010d0fc5ce3360f8581c5d8e Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sat, 16 Feb 2013 08:32:18 +0100 +Subject: [PATCH 02/99] 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 31b8de4..086d9d5 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +@@ -145,13 +145,6 @@ + delete m_dllSwScale; + } + +-void CLinuxRendererGLES::ManageTextures() +-{ +- m_NumYV12Buffers = 2; +- //m_iYV12RenderBuffer = 0; +- return; +-} +- + bool CLinuxRendererGLES::ValidateRenderTarget() + { + if (!m_bValidated) +@@ -405,7 +398,6 @@ void CLinuxRendererGLES::Update(bool bPauseDrawing) + { + if (!m_bConfigured) return; + ManageDisplay(); +- ManageTextures(); + } + + void CLinuxRendererGLES::RenderUpdate(bool clear, DWORD flags, DWORD alpha) +@@ -419,7 +411,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) +@@ -459,7 +450,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 c1d51b9..eef86cd 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.8.1.5 + + +From d8b3b60e37806e75e9cccabf2968375ffa753505 Mon Sep 17 00:00:00 2001 +From: unknown +Date: Sat, 16 Feb 2013 11:17:02 +0100 +Subject: [PATCH 03/99] WinRenderer: add buffering + +--- + xbmc/cores/VideoRenderers/WinRenderer.cpp | 14 ++++++-------- + xbmc/cores/VideoRenderers/WinRenderer.h | 12 +++++------- + 2 files changed, 11 insertions(+), 15 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/WinRenderer.cpp b/xbmc/cores/VideoRenderers/WinRenderer.cpp +index c108096..d470c25 100644 +--- a/xbmc/cores/VideoRenderers/WinRenderer.cpp ++++ b/xbmc/cores/VideoRenderers/WinRenderer.cpp +@@ -112,21 +112,19 @@ static enum PixelFormat PixelFormatFromFormat(ERenderFormat format) + + void CWinRenderer::ManageTextures() + { +- int neededbuffers = 2; +- +- if( m_NumYV12Buffers < neededbuffers ) ++ if( m_NumYV12Buffers < m_neededBuffers ) + { +- for(int i = m_NumYV12Buffers; i neededbuffers ) ++ else if( m_NumYV12Buffers > m_neededBuffers ) + { +- m_NumYV12Buffers = neededbuffers; ++ m_NumYV12Buffers = m_neededBuffers; + m_iYV12RenderBuffer = m_iYV12RenderBuffer % m_NumYV12Buffers; + +- for(int i = m_NumYV12Buffers-1; i>=neededbuffers;i--) ++ for(int i = m_NumYV12Buffers-1; i>=m_neededBuffers;i--) + DeleteYV12Texture(i); + } + } +diff --git a/xbmc/cores/VideoRenderers/WinRenderer.h b/xbmc/cores/VideoRenderers/WinRenderer.h +index ff9dfdf..755c1b9 100644 +--- a/xbmc/cores/VideoRenderers/WinRenderer.h ++++ b/xbmc/cores/VideoRenderers/WinRenderer.h +@@ -32,13 +32,7 @@ + #include "cores/VideoRenderers/RenderFlags.h" + #include "cores/VideoRenderers/RenderFormats.h" + +-//#define MP_DIRECTRENDERING +- +-#ifdef MP_DIRECTRENDERING +-#define NUM_BUFFERS 3 +-#else +-#define NUM_BUFFERS 2 +-#endif ++#define NUM_BUFFERS 10 + + #define ALIGN(value, alignment) (((value)+((alignment)-1))&~((alignment)-1)) + #define CLAMP(a, min, max) ((a) > (max) ? (max) : ( (a) < (min) ? (min) : a )) +@@ -177,6 +171,8 @@ class CWinRenderer : public CBaseRenderer + void RenderUpdate(bool clear, DWORD flags = 0, DWORD alpha = 255); + + virtual unsigned int GetProcessorSize() { return m_processor.Size(); } ++ virtual void SetBufferSize(int numBuffers) { m_neededBuffers = numBuffers; } ++ virtual unsigned int GetMaxBufferSize() { return NUM_BUFFERS; } + + protected: + virtual void Render(DWORD flags); +@@ -246,6 +242,8 @@ class CWinRenderer : public CBaseRenderer + // the separable HQ scalers need this info, but could the m_destRect be used instead? + unsigned int m_destWidth; + unsigned int m_destHeight; ++ ++ int m_neededBuffers; + }; + + #else +-- +1.8.1.5 + + +From 56218388a098bd2167ab7c07360fcb03d6bbbe0c Mon Sep 17 00:00:00 2001 +From: unknown +Date: Sat, 16 Feb 2013 11:17:32 +0100 +Subject: [PATCH 04/99] DXVA: activate buffering in renderer + +--- + 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 eefafc9..12c4cb7 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -1142,7 +1142,7 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) + break; + case RENDER_FMT_DXVA: + formatstr = "DXVA"; +- buffering = false; ++ buffering = true; + break; + case RENDER_FMT_VAAPI: + formatstr = "VAAPI"; +-- +1.8.1.5 + + +From abaefc97d407b30eab430b7faa369d9ab9117762 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Tue, 2 Oct 2012 10:49:09 +0200 +Subject: [PATCH 05/99] 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 fb98d05..cf258c0 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +@@ -267,7 +267,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.8.1.5 + + +From bc6e28672c1d310c143862093c2de038435391fe Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 28 May 2012 10:17:33 +0200 +Subject: [PATCH 06/99] 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 944b29f..2d55cb9 100644 +--- a/xbmc/Application.cpp ++++ b/xbmc/Application.cpp +@@ -425,8 +425,6 @@ + #endif + m_currentStack = new CFileItemList; + +- m_frameCount = 0; +- + m_bPresentFrame = false; + m_bPlatformDirectories = true; + +@@ -2328,28 +2326,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() +@@ -2369,7 +2357,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 +@@ -2383,13 +2370,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 +@@ -2413,8 +2397,6 @@ void CApplication::Render() + else if (lowfps) + singleFrameTime = 200; // 5 fps, <=200 ms latency to wake up + } +- +- decrement = true; + } + } + +@@ -2479,13 +2461,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) +@@ -5729,12 +5704,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; +@@ -5967,7 +5936,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 841eb4b..df59114 100644 +--- a/xbmc/Application.h ++++ b/xbmc/Application.h +@@ -443,10 +443,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 df15e0a..03dfe2b 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -1102,3 +1102,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 6ba1653..a215852 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.h ++++ b/xbmc/cores/VideoRenderers/RenderManager.h +@@ -148,6 +148,7 @@ class CXBMCRenderManager + * display becomes available for player to deliver a new frame. + */ + void NotifyDisplayFlip(); ++ bool HasFrame(); + void EnableBuffering(bool enable); + void DiscardBuffer(); + +-- +1.8.1.5 + + +From fb69e5ba3ea8ffaf43d5134bdca2de8a776c5f89 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 28 May 2012 11:02:29 +0200 +Subject: [PATCH 07/99] 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 aa7de02..2f4038f 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +@@ -111,7 +111,7 @@ enum PixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx + } + + 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 5d10f31..0cd89e8 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 2840c52..1385833 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.8.1.5 + + +From be4ce83c2e54084d2c5585e335b7820837b58c84 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sat, 16 Feb 2013 20:17:29 +0100 +Subject: [PATCH 08/99] add buffering - some documentation + +--- + xbmc/cores/IPlayer.h | 3 +++ + xbmc/cores/VideoRenderers/RenderManager.h | 40 +++++++++++++++++++++++++++++++ + 2 files changed, 43 insertions(+) + +diff --git a/xbmc/cores/IPlayer.h b/xbmc/cores/IPlayer.h +index 9be9e22..3198aa5 100644 +--- a/xbmc/cores/IPlayer.h ++++ b/xbmc/cores/IPlayer.h +@@ -244,6 +244,9 @@ 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: +diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h +index a215852..f1ce77f 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.h ++++ b/xbmc/cores/VideoRenderers/RenderManager.h +@@ -66,11 +66,38 @@ class CXBMCRenderManager + void SetViewMode(int iViewMode); + + // Functions called from mplayer ++ /** ++ * 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 for some optimizations like keeping the gui responsive on rewind ++ */ + void FlipPage(volatile bool& bStop, double timestamp = 0.0, int source = -1, EFIELDSYNC sync = FS_NONE, int speed = 1000); + unsigned int PreInit(); + void UnInit(); +@@ -148,8 +175,21 @@ class CXBMCRenderManager + * display becomes available for player to deliver a new frame. + */ + void NotifyDisplayFlip(); ++ ++ /** ++ * 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: +-- +1.8.1.5 + + +From f63b01cea084334ef39135ae964c410049c6e574 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Tue, 19 Feb 2013 09:06:22 +0100 +Subject: [PATCH 09/99] move NUM_BUFFERS up to BaseRenderer.h + +--- + xbmc/cores/VideoRenderers/BaseRenderer.h | 3 ++- + xbmc/cores/VideoRenderers/LinuxRendererGL.h | 2 -- + xbmc/cores/VideoRenderers/LinuxRendererGLES.h | 2 -- + xbmc/cores/VideoRenderers/OverlayRenderer.cpp | 2 +- + xbmc/cores/VideoRenderers/OverlayRenderer.h | 3 ++- + xbmc/cores/VideoRenderers/WinRenderer.h | 2 -- + 6 files changed, 5 insertions(+), 9 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/BaseRenderer.h b/xbmc/cores/VideoRenderers/BaseRenderer.h +index 34fbd19..675ca35 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; +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.h b/xbmc/cores/VideoRenderers/LinuxRendererGL.h +index fc513db..332a4cc 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.h ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.h +@@ -44,8 +44,6 @@ + namespace Shaders { class BaseVideoFilterShader; } + namespace VAAPI { struct CHolder; } + +-#define NUM_BUFFERS 10 +- + + #undef ALIGN + #define ALIGN(value, alignment) (((value)+((alignment)-1))&~((alignment)-1)) +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h +index eef86cd..d5eefc6 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h +@@ -41,8 +41,6 @@ + class COpenMaxVideo; + typedef std::vector Features; + +-#define NUM_BUFFERS 10 +- + + #undef ALIGN + #define ALIGN(value, alignment) (((value)+((alignment)-1))&~((alignment)-1)) +diff --git a/xbmc/cores/VideoRenderers/OverlayRenderer.cpp b/xbmc/cores/VideoRenderers/OverlayRenderer.cpp +index ce7c3e9..794b737 100644 +--- a/xbmc/cores/VideoRenderers/OverlayRenderer.cpp ++++ b/xbmc/cores/VideoRenderers/OverlayRenderer.cpp +@@ -95,7 +95,7 @@ long COverlayMainThread::Release() + + CRenderer::~CRenderer() + { +- for(int i = 0; i < 10; i++) ++ for(int i = 0; i < NUM_BUFFERS; i++) + Release(m_buffers[i]); + } + +diff --git a/xbmc/cores/VideoRenderers/OverlayRenderer.h b/xbmc/cores/VideoRenderers/OverlayRenderer.h +index b532ee3..5f6cf40 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 + +@@ -127,7 +128,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/WinRenderer.h b/xbmc/cores/VideoRenderers/WinRenderer.h +index 755c1b9..4892500 100644 +--- a/xbmc/cores/VideoRenderers/WinRenderer.h ++++ b/xbmc/cores/VideoRenderers/WinRenderer.h +@@ -32,8 +32,6 @@ + #include "cores/VideoRenderers/RenderFlags.h" + #include "cores/VideoRenderers/RenderFormats.h" + +-#define NUM_BUFFERS 10 +- + #define ALIGN(value, alignment) (((value)+((alignment)-1))&~((alignment)-1)) + #define CLAMP(a, min, max) ((a) > (max) ? (max) : ( (a) < (min) ? (min) : a )) + +-- +1.8.1.5 + + +From a37563b411342de017c7e9d92a3df623bfa634d9 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sun, 24 Feb 2013 09:55:00 +0100 +Subject: [PATCH 10/99] OverlayRenderer: align buffers with index in + renderManager + +--- + xbmc/cores/VideoRenderers/OverlayRenderer.cpp | 7 +++++-- + xbmc/cores/VideoRenderers/OverlayRenderer.h | 2 +- + xbmc/cores/VideoRenderers/RenderManager.cpp | 6 ++++-- + 3 files changed, 10 insertions(+), 5 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/OverlayRenderer.cpp b/xbmc/cores/VideoRenderers/OverlayRenderer.cpp +index 794b737..fcab22b 100644 +--- a/xbmc/cores/VideoRenderers/OverlayRenderer.cpp ++++ b/xbmc/cores/VideoRenderers/OverlayRenderer.cpp +@@ -163,10 +163,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; + } + + void CRenderer::ReleaseBuffer(int idx) +diff --git a/xbmc/cores/VideoRenderers/OverlayRenderer.h b/xbmc/cores/VideoRenderers/OverlayRenderer.h +index 5f6cf40..4e414b4 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 03dfe2b..e400bdb 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -309,7 +309,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(); +@@ -706,7 +706,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(); +@@ -958,6 +958,8 @@ int CXBMCRenderManager::WaitForBuffer(volatile bool& bStop, int timeout) + if (bStop) + return -1; + ++ // make sure overlay buffer is released, this won't happen on AddOverlay ++ m_overlays.ReleaseBuffer((m_iOutputRenderBuffer + 1) % m_iNumRenderBuffers); + return 1; + } + +-- +1.8.1.5 + + +From e04329bf09f01c6ba48c2b1742bd8d03c18ade67 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Tue, 26 Feb 2013 09:00:21 +0100 +Subject: [PATCH 11/99] add buffering - submit absolute time to render buffers + +--- + xbmc/cores/IPlayer.h | 5 ----- + xbmc/cores/VideoRenderers/RenderManager.cpp | 18 ++---------------- + xbmc/cores/VideoRenderers/RenderManager.h | 5 ++--- + xbmc/cores/dvdplayer/DVDPlayer.cpp | 5 ----- + xbmc/cores/dvdplayer/DVDPlayer.h | 2 -- + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 2 +- + 6 files changed, 5 insertions(+), 32 deletions(-) + +diff --git a/xbmc/cores/IPlayer.h b/xbmc/cores/IPlayer.h +index 3198aa5..6b713dc 100644 +--- a/xbmc/cores/IPlayer.h ++++ b/xbmc/cores/IPlayer.h +@@ -244,11 +244,6 @@ 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/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index e400bdb..be5e03f 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -577,7 +577,6 @@ void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0L + { CRetakeLock lock(m_sharedSection); + if(!m_pRenderer) return; + +- double presenttime = timestamp; + EFIELDSYNC presentfield = sync; + EPRESENTMETHOD presentmethod; + +@@ -1022,7 +1021,6 @@ void CXBMCRenderManager::ResetRenderBuffer() + m_iDisplayedRenderBuffer = 0; + m_bAllRenderBuffersDisplayed = true; + m_sleeptime = 1.0; +- m_presentPts = DVD_NOPTS_VALUE; + m_speed = 0; + } + +@@ -1032,19 +1030,8 @@ void CXBMCRenderManager::PrepareNextRender() + if (idx < 0) + return; + +- double iClockSleep, iPlayingClock, iCurrentClock; +- 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) +- iClockSleep = iClockSleep * DVD_PLAYSPEED_NORMAL / m_speed; +- +- double presenttime = (iCurrentClock + iClockSleep) / DVD_TIME_BASE; +- double clocktime = iCurrentClock / DVD_TIME_BASE; ++ double presenttime = m_renderBuffers[idx].timestamp; ++ double clocktime = GetPresentTime(); + if(presenttime - clocktime > MAXPRESENTDELAY) + presenttime = clocktime + MAXPRESENTDELAY; + +@@ -1053,7 +1040,6 @@ void CXBMCRenderManager::PrepareNextRender() + + if (g_graphicsContext.IsFullScreenVideo() || presenttime <= clocktime + frametime) + { +- m_presentPts = m_renderBuffers[idx].pts; + m_presenttime = presenttime; + m_presentmethod = m_renderBuffers[idx].presentmethod; + m_presentfield = m_renderBuffers[idx].presentfield; +diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h +index f1ce77f..ac404c2 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.h ++++ b/xbmc/cores/VideoRenderers/RenderManager.h +@@ -93,7 +93,7 @@ class CXBMCRenderManager + * 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 timestamp of frame delivered with AddVideoPicture + * @param source depreciated + * @param sync signals frame, top, or bottom field + * @param speed current speed of player, needed for some optimizations like keeping the gui responsive on rewind +@@ -259,13 +259,12 @@ class CXBMCRenderManager + + struct + { +- double pts; ++ double timestamp; + EFIELDSYNC presentfield; + EPRESENTMETHOD presentmethod; + }m_renderBuffers[5]; + + double m_sleeptime; +- double m_presentPts; + + double m_presenttime; + double m_presentcorr; +diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp +index 38c3f1e..cdf5876 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp +@@ -4157,8 +4157,3 @@ 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 a76b1ee..fa6c99f 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayer.h ++++ b/xbmc/cores/dvdplayer/DVDPlayer.h +@@ -246,8 +246,6 @@ 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 12c4cb7..642484d 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -1377,7 +1377,7 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) + if (index < 0) + return EOS_DROPPED; + +- g_renderManager.FlipPage(CThread::m_bStop, pts, -1, mDisplayField, m_speed); ++ g_renderManager.FlipPage(CThread::m_bStop, (iCurrentClock + iSleepTime) / DVD_TIME_BASE, -1, mDisplayField, m_speed); + + return result; + #else +-- +1.8.1.5 + + +From 91a45c6df6e8555de6863713496dbc5dea39768d Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Fri, 1 Mar 2013 08:05:00 +0100 +Subject: [PATCH 12/99] RenderManager: some rework to buffering + +--- + xbmc/cores/VideoRenderers/RenderManager.cpp | 20 +++++++++++--------- + 1 file changed, 11 insertions(+), 9 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index be5e03f..71b7f87 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -617,9 +617,11 @@ void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0L + } + + FlipFreeBuffer(); +- m_renderBuffers[m_iOutputRenderBuffer].pts = timestamp; ++ m_renderBuffers[m_iOutputRenderBuffer].timestamp = timestamp; + m_renderBuffers[m_iOutputRenderBuffer].presentfield = presentfield; + m_renderBuffers[m_iOutputRenderBuffer].presentmethod = presentmethod; ++ if (!m_bUseBuffering) ++ PrepareNextRender(); + m_speed = speed; + } + +@@ -828,14 +830,14 @@ int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic) + if (!m_pRenderer) + return -1; + +- if(m_pRenderer->AddVideoPicture(&pic, (m_iOutputRenderBuffer + 1) % m_iNumRenderBuffers)) ++ int index = (m_iOutputRenderBuffer + 1) % m_iNumRenderBuffers; ++ ++ if(m_pRenderer->AddVideoPicture(&pic, index)) + return 1; + + YV12Image image; +- int index = m_pRenderer->GetImage(&image, (m_iOutputRenderBuffer + 1) % m_iNumRenderBuffers); +- +- if(index < 0) +- return index; ++ if (m_pRenderer->GetImage(&image, index) < 0) ++ return -1; + + if(pic.format == RENDER_FMT_YUV420P + || pic.format == RENDER_FMT_YUV420P10 +@@ -939,14 +941,14 @@ int CXBMCRenderManager::WaitForBuffer(volatile bool& bStop, int timeout) + if (!m_pRenderer) + return -1; + +- double maxwait = GetPresentTime() + (float)timeout/1000; ++ XbmcThreads::EndTime endtime(timeout); + while(!HasFreeBuffer() && !bStop) + { + lock.Leave(); + m_flipEvent.WaitMSec(std::min(50, timeout)); +- if(GetPresentTime() > maxwait && !bStop) ++ if(endtime.IsTimePast()) + { +- if (timeout != 0) ++ if (timeout != 0 && !bStop) + CLog::Log(LOGWARNING, "CRenderManager::WaitForBuffer - timeout waiting for buffer"); + return -1; + } +-- +1.8.1.5 + + +From adc41556c36049f05eadb70c1bc0c48bd8f40df2 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Fri, 1 Mar 2013 08:07:07 +0100 +Subject: [PATCH 13/99] dvdplayer: disable buffering unil dropping is improved + +--- + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +index 642484d..106bf53 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -1114,35 +1114,35 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) + { + case RENDER_FMT_YUV420P: + formatstr = "YV12"; +- buffering = true; ++ buffering = false; + break; + case RENDER_FMT_YUV420P16: + formatstr = "YV12P16"; +- buffering = true; ++ buffering = false; + break; + case RENDER_FMT_YUV420P10: + formatstr = "YV12P10"; +- buffering = true; ++ buffering = false; + break; + case RENDER_FMT_NV12: + formatstr = "NV12"; +- buffering = true; ++ buffering = false; + break; + case RENDER_FMT_UYVY422: + formatstr = "UYVY"; +- buffering = true; ++ buffering = false; + break; + case RENDER_FMT_YUYV422: + formatstr = "YUY2"; +- buffering = true; ++ buffering = false; + break; + case RENDER_FMT_VDPAU: + formatstr = "VDPAU"; +- buffering = true; ++ buffering = false; + break; + case RENDER_FMT_DXVA: + formatstr = "DXVA"; +- buffering = true; ++ buffering = false; + break; + case RENDER_FMT_VAAPI: + formatstr = "VAAPI"; +-- +1.8.1.5 + + +From cef7dd8ebf48b7a27bcba5f1a72d0a90f2d76147 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sat, 2 Mar 2013 12:00:51 +0100 +Subject: [PATCH 14/99] RenderManager: skip very late frames in render buffer + +--- + xbmc/cores/VideoRenderers/RenderManager.cpp | 40 ++++++++++++++++++++++++++--- + 1 file changed, 37 insertions(+), 3 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index 71b7f87..cd8c490 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -54,7 +54,7 @@ + #include "../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h" + #include "../dvdplayer/DVDCodecs/DVDCodecUtils.h" + +-#define MAXPRESENTDELAY 0.500 ++#define MAXPRESENTDELAY 0.200 + + /* at any point we want an exclusive lock on rendermanager */ + /* we must make sure we don't have a graphiccontext lock */ +@@ -1032,13 +1032,47 @@ void CXBMCRenderManager::PrepareNextRender() + if (idx < 0) + return; + +- double presenttime = m_renderBuffers[idx].timestamp; + double clocktime = GetPresentTime(); ++ double frametime = 1 / g_graphicsContext.GetFPS(); ++ ++ // look ahead in the queue ++ // if the next frame is already late, skip the one we are about to render ++ // drop buffers if time has jumped back ++ int skipToPos = 0; ++ int count = 1; ++ int i = idx; ++ while (i != m_iOutputRenderBuffer) ++ { ++ int idx_next = (i + 1) % m_iNumRenderBuffers; ++ if (m_renderBuffers[idx_next].timestamp < m_renderBuffers[i].timestamp-frametime || ++ m_renderBuffers[idx_next].timestamp <= (clocktime-frametime)) ++ { ++ skipToPos = count; ++ } ++ count++; ++ i = idx_next; ++ } ++ count = 1; ++ while (idx != m_iOutputRenderBuffer) ++ { ++ int idx_next = (idx + 1) % m_iNumRenderBuffers; ++ if (count <= skipToPos) ++ { ++ FlipRenderBuffer(); ++ idx = idx_next; ++ CLog::Log(LOGDEBUG,"%s - skip frame at render buffer index: %d", __FUNCTION__, idx); ++ } ++ else ++ break; ++ count++; ++ } ++ ++ double presenttime = m_renderBuffers[idx].timestamp; ++ + if(presenttime - clocktime > MAXPRESENTDELAY) + presenttime = clocktime + MAXPRESENTDELAY; + + m_sleeptime = presenttime - clocktime; +- double frametime = 1 / g_graphicsContext.GetFPS(); + + if (g_graphicsContext.IsFullScreenVideo() || presenttime <= clocktime + frametime) + { +-- +1.8.1.5 + + +From 18190e0837198319b3b90e45a064b0fd5fdae6e7 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sat, 2 Mar 2013 12:10:17 +0100 +Subject: [PATCH 15/99] renderbuffers: drop enable/disable in this iteration + +--- + xbmc/cores/VideoRenderers/RenderManager.cpp | 4 ++++ + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 4 ---- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index cd8c490..374c138 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -272,6 +272,7 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi + m_presentstep = PRESENT_IDLE; + m_presentevent.Set(); + ResetRenderBuffer(); ++ EnableBuffering(buffering); + } + + return result; +@@ -1089,7 +1090,10 @@ void CXBMCRenderManager::EnableBuffering(bool enable) + CRetakeLock lock(m_sharedSection); + + if (m_iNumRenderBuffers < 3) ++ { ++ m_bUseBuffering = false; + return; ++ } + + m_bUseBuffering = enable; + if (!m_bUseBuffering) +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +index 106bf53..f6b8c5e 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -262,7 +262,6 @@ 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) +@@ -438,7 +437,6 @@ 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()) + { +@@ -451,7 +449,6 @@ 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; +@@ -719,7 +716,6 @@ 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 +-- +1.8.1.5 + + +From d1aefdfd4b492a8b54e421a6966d7979850fc757 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sat, 2 Mar 2013 12:31:11 +0100 +Subject: [PATCH 16/99] RenderManager: add method SetSpeed + +--- + xbmc/cores/VideoRenderers/RenderManager.cpp | 10 +++++++--- + xbmc/cores/VideoRenderers/RenderManager.h | 8 ++++++-- + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 3 ++- + 3 files changed, 15 insertions(+), 6 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index 374c138..73dea8a 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -556,7 +556,7 @@ 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*/, int speed /*= 1000*/) ++void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0LL*/, int source /*= -1*/, EFIELDSYNC sync /*= FS_NONE*/) + { + if (!m_bUseBuffering) + { +@@ -623,7 +623,6 @@ void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0L + m_renderBuffers[m_iOutputRenderBuffer].presentmethod = presentmethod; + if (!m_bUseBuffering) + PrepareNextRender(); +- m_speed = speed; + } + + g_application.NewFrame(); +@@ -1024,7 +1023,7 @@ void CXBMCRenderManager::ResetRenderBuffer() + m_iDisplayedRenderBuffer = 0; + m_bAllRenderBuffersDisplayed = true; + m_sleeptime = 1.0; +- m_speed = 0; ++ m_speed = DVD_PLAYSPEED_NORMAL; + } + + void CXBMCRenderManager::PrepareNextRender() +@@ -1108,6 +1107,11 @@ void CXBMCRenderManager::DiscardBuffer() + m_iOutputRenderBuffer = m_iCurrentRenderBuffer; + } + ++void CXBMCRenderManager::SetSpeed(int speed) ++{ ++ m_speed = speed; ++} ++ + void CXBMCRenderManager::NotifyDisplayFlip() + { + CRetakeLock lock(m_sharedSection); +diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h +index ac404c2..bb36a82 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.h ++++ b/xbmc/cores/VideoRenderers/RenderManager.h +@@ -96,9 +96,8 @@ class CXBMCRenderManager + * @param timestamp of frame delivered with AddVideoPicture + * @param source depreciated + * @param sync signals frame, top, or bottom field +- * @param speed current speed of player, needed for some optimizations like keeping the gui responsive on rewind + */ +- void FlipPage(volatile bool& bStop, double timestamp = 0.0, int source = -1, EFIELDSYNC sync = FS_NONE, int speed = 1000); ++ void FlipPage(volatile bool& bStop, double timestamp = 0.0, int source = -1, EFIELDSYNC sync = FS_NONE); + unsigned int PreInit(); + void UnInit(); + bool Flush(); +@@ -192,6 +191,11 @@ class CXBMCRenderManager + */ + void DiscardBuffer(); + ++ /** ++ * notify RenderManager about play speed ++ */ ++ void SetSpeed(int speed); ++ + protected: + void Render(bool clear, DWORD flags, DWORD alpha); + +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +index f6b8c5e..0959246 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -468,6 +468,7 @@ void CDVDPlayerVideo::Process() + m_iNrOfPicturesNotToSkip = 0; + if (m_pVideoCodec) + m_pVideoCodec->SetSpeed(m_speed); ++ g_renderManager.SetSpeed(m_speed); + } + else if (pMsg->IsType(CDVDMsg::PLAYER_STARTED)) + { +@@ -1373,7 +1374,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, m_speed); ++ g_renderManager.FlipPage(CThread::m_bStop, (iCurrentClock + iSleepTime) / DVD_TIME_BASE, -1, mDisplayField); + + return result; + #else +-- +1.8.1.5 + + +From f32d73a6d15a8d3f48a3f7f1ef64d216b8821b0e Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 4 Apr 2013 10:20:36 +0200 +Subject: [PATCH 17/99] RenderManager: return bufferlevel with WaitForBuffer + +--- + xbmc/cores/VideoRenderers/RenderManager.cpp | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index 73dea8a..8e9b2c0 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -941,6 +941,7 @@ int CXBMCRenderManager::WaitForBuffer(volatile bool& bStop, int timeout) + if (!m_pRenderer) + return -1; + ++ int bufferlevel = 1; + XbmcThreads::EndTime endtime(timeout); + while(!HasFreeBuffer() && !bStop) + { +@@ -954,6 +955,9 @@ int CXBMCRenderManager::WaitForBuffer(volatile bool& bStop, int timeout) + } + lock.Enter(); + } ++ if (m_iNumRenderBuffers >= 3) ++ bufferlevel = (m_iOutputRenderBuffer - m_iCurrentRenderBuffer + m_iNumRenderBuffers) % m_iNumRenderBuffers; ++ + lock.Leave(); + + if (bStop) +@@ -961,7 +965,8 @@ int CXBMCRenderManager::WaitForBuffer(volatile bool& bStop, int timeout) + + // make sure overlay buffer is released, this won't happen on AddOverlay + m_overlays.ReleaseBuffer((m_iOutputRenderBuffer + 1) % m_iNumRenderBuffers); +- return 1; ++ ++ return bufferlevel; + } + + int CXBMCRenderManager::GetNextRenderBufferIndex() +-- +1.8.1.5 + + +From 49c56979ea29676de305ec3dcca015869be9bf27 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sun, 10 Feb 2013 18:40:30 +0100 +Subject: [PATCH 18/99] OMXPlayer: adapt to buffering + +--- + xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 28 +++++++++++----------------- + 1 file changed, 11 insertions(+), 17 deletions(-) + +diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp +index ae2da00..7d60e8b 100644 +--- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp ++++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp +@@ -347,25 +347,19 @@ void OMXPlayerVideo::Output(int iGroupId, double pts, bool bDropPacket) + 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)) ++ int timeout = 50; ++ if (GetDecoderFreeSpace() > 0.2 * GetDecoderBufferSize()) ++ timeout = 0; ++ int bufferlevel = g_renderManager.WaitForBuffer(m_bStop, timeout); ++ if (bufferlevel < 0) + return; + +- double pts_media = m_av_clock->OMXMediaTime(false); +- ProcessOverlays(iGroupId, pts_media); +- +- g_renderManager.FlipPage(CThread::m_bStop, m_iSleepEndTime / DVD_TIME_BASE, -1, FS_NONE); +- +- m_iSleepEndTime = DVD_NOPTS_VALUE; ++ double pts_overlay = m_av_clock->OMXMediaTime(false) ++ + (bufferlevel+1)* iFrameDuration; ++ ProcessOverlays(iGroupId, pts_overlay); + +- //m_av_clock->WaitAbsoluteClock((iCurrentClock + iSleepTime)); ++ double timestamp = (CDVDClock::GetAbsoluteClock(false) + (bufferlevel+1) * iFrameDuration) / DVD_TIME_BASE; ++ g_renderManager.FlipPage(CThread::m_bStop, timestamp, -1, FS_NONE); + } + + void OMXPlayerVideo::Process() +@@ -809,7 +803,7 @@ void OMXPlayerVideo::ResolutionUpdateCallBack(uint32_t width, uint32_t height) + + if(!g_renderManager.Configure(width, height, + iDisplayWidth, iDisplayHeight, m_fFrameRate, flags, format, 0, +- m_hints.orientation)) ++ m_hints.orientation, true)) + { + CLog::Log(LOGERROR, "%s - failed to configure renderer", __FUNCTION__); + return; +-- +1.8.1.5 + + +From 98e7a304ec9d746d5c6bfc22aa26601c5afde8d0 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 28 May 2012 10:34:39 +0200 +Subject: [PATCH 19/99] videoplayer: adapt lateness detection and dropping to + buffering + +--- + xbmc/cores/VideoRenderers/RenderManager.cpp | 17 +- + xbmc/cores/VideoRenderers/RenderManager.h | 11 +- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h | 14 ++ + .../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 31 +++ + .../DVDCodecs/Video/DVDVideoCodecFFmpeg.h | 7 + + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 227 ++++++++++++++++----- + xbmc/cores/dvdplayer/DVDPlayerVideo.h | 24 +++ + 7 files changed, 283 insertions(+), 48 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index 8e9b2c0..2fdc9e5 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -556,7 +556,7 @@ 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*/, double pts /* = 0 */, int source /*= -1*/, EFIELDSYNC sync /*= FS_NONE*/) + { + if (!m_bUseBuffering) + { +@@ -618,6 +618,7 @@ void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0L + } + + FlipFreeBuffer(); ++ m_renderBuffers[m_iOutputRenderBuffer].pts = pts; + m_renderBuffers[m_iOutputRenderBuffer].timestamp = timestamp; + m_renderBuffers[m_iOutputRenderBuffer].presentfield = presentfield; + m_renderBuffers[m_iOutputRenderBuffer].presentmethod = presentmethod; +@@ -1029,6 +1030,7 @@ void CXBMCRenderManager::ResetRenderBuffer() + m_bAllRenderBuffersDisplayed = true; + m_sleeptime = 1.0; + m_speed = DVD_PLAYSPEED_NORMAL; ++ m_presentPts = DVD_NOPTS_VALUE; + } + + void CXBMCRenderManager::PrepareNextRender() +@@ -1081,6 +1083,7 @@ void CXBMCRenderManager::PrepareNextRender() + + if (g_graphicsContext.IsFullScreenVideo() || presenttime <= clocktime + frametime) + { ++ m_presentPts = m_renderBuffers[idx].pts; + m_presenttime = presenttime; + m_presentmethod = m_renderBuffers[idx].presentmethod; + m_presentfield = m_renderBuffers[idx].presentfield; +@@ -1140,6 +1143,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 bb36a82..d290cef 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.h ++++ b/xbmc/cores/VideoRenderers/RenderManager.h +@@ -94,10 +94,11 @@ class CXBMCRenderManager + * + * @param bStop reference to stop flag of calling thread + * @param timestamp of frame delivered with AddVideoPicture ++ * @param pts used for lateness detection + * @param source depreciated + * @param sync signals frame, top, or bottom field + */ +- void FlipPage(volatile bool& bStop, double timestamp = 0.0, int source = -1, EFIELDSYNC sync = FS_NONE); ++ void FlipPage(volatile bool& bStop, double timestamp = 0.0, double pts = 0.0, int source = -1, EFIELDSYNC sync = FS_NONE); + unsigned int PreInit(); + void UnInit(); + bool Flush(); +@@ -181,6 +182,12 @@ class CXBMCRenderManager + bool HasFrame(); + + /** ++ * 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); ++ ++ /** + * Video player can dynamically enable/disable buffering. In situations like + * rewind buffering is not ideal. + */ +@@ -263,12 +270,14 @@ class CXBMCRenderManager + + struct + { ++ double pts; + double timestamp; + EFIELDSYNC presentfield; + EPRESENTMETHOD presentmethod; + }m_renderBuffers[5]; + + double m_sleeptime; ++ double m_presentPts; + + double m_presenttime; + double m_presentcorr; +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h +index 2c46b0b..5931e2f 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: +@@ -243,4 +250,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 2f4038f..0905dc7 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +@@ -148,6 +148,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() +@@ -356,6 +357,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 +@@ -557,6 +566,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); + +@@ -655,6 +665,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; + +@@ -877,3 +903,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 e857a24..3e3f5a3 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; }; +@@ -120,4 +123,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 0959246..e05a9fc 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(); + } + else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) // private message sent by (CDVDPlayerVideo::Flush()) + { +@@ -449,6 +452,7 @@ void CDVDPlayerVideo::Process() + //we need to recalculate the framerate + //TODO: this needs to be set on a streamchange instead + ResetFrameRateCalc(); ++ m_droppingStats.Reset(); + + m_stalled = true; + m_started = false; +@@ -466,9 +470,11 @@ void CDVDPlayerVideo::Process() + m_speed = static_cast(pMsg)->m_value; + if(m_speed == DVD_PLAYSPEED_PAUSE) + m_iNrOfPicturesNotToSkip = 0; ++ + if (m_pVideoCodec) + m_pVideoCodec->SetSpeed(m_speed); + g_renderManager.SetSpeed(m_speed); ++ m_droppingStats.Reset(); + } + else if (pMsg->IsType(CDVDMsg::PLAYER_STARTED)) + { +@@ -514,6 +520,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 +@@ -523,6 +551,7 @@ void CDVDPlayerVideo::Process() + bRequestDrop = false; + m_iDroppedRequest = 0; + m_iLateFrames = 0; ++ m_droppingStats.m_requestOutputDrop = false; + } + #endif + +@@ -570,15 +599,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) +@@ -1269,50 +1291,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 ((m_droppingStats.m_requestOutputDrop && !(pPicture->iFlags & DVP_FLAG_NOSKIP)) ++ || (pPicture->iFlags & DVP_FLAG_DROPPED)) + { +- 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 +- { +- 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 ) + { + m_droptime += iFrameDuration; + #ifndef PROFILE +@@ -1374,7 +1376,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, (iCurrentClock + iSleepTime) / DVD_TIME_BASE, pts, -1, mDisplayField); + + return result; + #else +@@ -1673,3 +1675,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 d1c9b94..5310522 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.8.1.5 + + +From ff334a316bd9b9383a3e1b54ff0b2160ca8ec878 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sun, 2 Sep 2012 16:05:21 +0200 +Subject: [PATCH 20/99] 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 e05a9fc..5fcf1f4 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -1275,22 +1275,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)) + { +@@ -1595,6 +1579,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 + +@@ -1713,6 +1713,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 5310522..f395897 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.8.1.5 + + +From e2c82ad705ca82b0b5ab0c056846967a186f8f5f Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sat, 16 Feb 2013 18:25:53 +0100 +Subject: [PATCH 21/99] videoplayer: some rework and documentation + +--- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h | 29 ++++++++++++++++++++-- + .../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 11 ++++++++ + .../DVDCodecs/Video/DVDVideoCodecFFmpeg.h | 2 +- + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 2 +- + 4 files changed, 40 insertions(+), 4 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h +index 5931e2f..ac126fe 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h +@@ -132,7 +132,6 @@ struct DVDVideoUserData + #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 + { +@@ -251,10 +250,36 @@ class CDVDVideoCodec + return 0; + } + +- virtual bool GetPts(double &pts, int &skippedDeint, int &interlaced) ++ /** ++ * For calculation of dropping requirements player asks for some information. ++ * ++ * - pts : right after decoder, used to detect gaps (dropped frames in decoder) ++ * - skippedDeint : indicates if decoder has just skipped a deinterlacing cycle ++ * instead of dropping a full frame ++ * - interlaced : when detecting gaps in pts, player needs to know whether ++ * it's interlaced or not ++ * ++ * If codec does not implement this method, pts of decoded frame at input ++ * video player is used. In case coded does post-proc and de-interlacing there ++ * may be quite some frames queued up between exit decoder and entry player. ++ */ ++ virtual bool GetCodecStats(double &pts, int &skippedDeint, int &interlaced) + { + return false; + } + ++ /** ++ * Codec can be informed by player with the following flags: ++ * ++ * DVP_FLAG_NO_POSTPROC : if speed is not normal the codec can switch off ++ * postprocessing and de-interlacing ++ * ++ * DVP_FLAG_DRAIN : codecs may do postprocessing and de-interlacing. ++ * If video buffers in RenderManager are about to run dry, ++ * this is signaled to codec. Codec can wait for post-proc ++ * to be finished instead of returning empty and getting another ++ * packet. ++ * ++ */ + virtual void SetCodecControl(int flags) {} + }; +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +index 0905dc7..75132de 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +@@ -904,6 +904,17 @@ unsigned CDVDVideoCodecFFmpeg::GetConvergeCount() + return 0; + } + ++bool CDVDVideoCodecFFmpeg::GetCodecStats(double &pts, int &skippedDeint, int &interlaced) ++{ ++ pts = m_decoderPts; ++ skippedDeint = m_skippedDeint; ++ if (m_pFrame) ++ interlaced = m_pFrame->interlaced_frame; ++ else ++ interlaced = 0; ++ return true; ++} ++ + 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 3e3f5a3..598b82e 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h +@@ -61,7 +61,7 @@ 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 bool GetCodecStats(double &pts, int &skippedDeint, int &interlaced); + virtual void SetCodecControl(int flags); + + bool IsHardwareAllowed() { return !m_bSoftware; } +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +index 5fcf1f4..530c796 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -1690,7 +1690,7 @@ int CDVDPlayerVideo::CalcDropRequirement(double pts) + int iBufferLevel; + + // get decoder stats +- if (!m_pVideoCodec->GetPts(iDecoderPts, iSkippedDeint, interlaced)) ++ if (!m_pVideoCodec->GetCodecStats(iDecoderPts, iSkippedDeint, interlaced)) + iDecoderPts = pts; + if (iDecoderPts == DVD_NOPTS_VALUE) + iDecoderPts = pts; +-- +1.8.1.5 + + +From 8767bc9cc6fa21a0b085c351b095d54bdcfa287a Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Fri, 1 Mar 2013 09:57:16 +0100 +Subject: [PATCH 22/99] Revert "dvdplayer: disable buffering unit dropping is + improves" + +This reverts commit de1caf5686c1fb53cb7ab11b356e6c22770740db. +--- + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +index 530c796..f9bd450 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -1133,35 +1133,35 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) + { + case RENDER_FMT_YUV420P: + formatstr = "YV12"; +- buffering = false; ++ buffering = true; + break; + case RENDER_FMT_YUV420P16: + formatstr = "YV12P16"; +- buffering = false; ++ buffering = true; + break; + case RENDER_FMT_YUV420P10: + formatstr = "YV12P10"; +- buffering = false; ++ buffering = true; + break; + case RENDER_FMT_NV12: + formatstr = "NV12"; +- buffering = false; ++ buffering = true; + break; + case RENDER_FMT_UYVY422: + formatstr = "UYVY"; +- buffering = false; ++ buffering = true; + break; + case RENDER_FMT_YUYV422: + formatstr = "YUY2"; +- buffering = false; ++ buffering = true; + break; + case RENDER_FMT_VDPAU: + formatstr = "VDPAU"; +- buffering = false; ++ buffering = true; + break; + case RENDER_FMT_DXVA: + formatstr = "DXVA"; +- buffering = false; ++ buffering = true; + break; + case RENDER_FMT_VAAPI: + formatstr = "VAAPI"; +-- +1.8.1.5 + + +From 00d7a368b713bece2de3e302665329b08f89fa0d Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 4 Apr 2013 15:44:20 +0200 +Subject: [PATCH 23/99] OMXPlayerVideo: adapt to change in FlipPage + +--- + xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp +index 7d60e8b..1986e33 100644 +--- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp ++++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp +@@ -359,7 +359,7 @@ void OMXPlayerVideo::Output(int iGroupId, double pts, bool bDropPacket) + ProcessOverlays(iGroupId, pts_overlay); + + double timestamp = (CDVDClock::GetAbsoluteClock(false) + (bufferlevel+1) * iFrameDuration) / DVD_TIME_BASE; +- g_renderManager.FlipPage(CThread::m_bStop, timestamp, -1, FS_NONE); ++ g_renderManager.FlipPage(CThread::m_bStop, timestamp, 0.0, -1, FS_NONE); + } + + void OMXPlayerVideo::Process() +-- +1.8.1.5 + + +From 70db6d325e9e20f7d234e17d67e6095fd705c541 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sat, 7 Apr 2012 09:19:00 +0200 +Subject: [PATCH 24/99] 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 | 3 +- + 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 | 3824 ++++++++++++++------ + xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h | 662 +++- + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 4 + + xbmc/settings/AdvancedSettings.cpp | 8 +- + xbmc/settings/AdvancedSettings.h | 4 +- + xbmc/settings/GUISettings.cpp | 2 + + .../settings/windows/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(+), 1216 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 8ccd55d..063ad68 100644 +--- a/language/English/strings.po ++++ b/language/English/strings.po +@@ -5405,7 +5405,15 @@ msgctxt "#13435" + msgid "Enable HQ Scalers for scalings above %" + msgstr "" + +-#empty strings from id 13436 to 13499 ++msgctxt "#13436" ++msgid "Allow Vdpau OpenGL interop" ++msgstr "" ++ ++msgctxt "#13437" ++msgid "Allow Vdpau OpenGL interop YUV" ++msgstr "" ++ ++#empty strings from id 13438 to 13499 + + #: xbmc/settings/GUISettings.cpp + msgctxt "#13500" +@@ -6429,7 +6437,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 c8c8a2e..0799a4b 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 cf258c0..556bed5 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +@@ -706,6 +706,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); + +@@ -786,11 +798,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; + } + +@@ -1117,6 +1124,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; +@@ -1192,7 +1205,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) + { +@@ -1558,17 +1574,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); +@@ -1626,8 +1637,6 @@ void CLinuxRendererGL::RenderVDPAU(int index, int field) + if (m_pVideoFilterShader) + m_pVideoFilterShader->Disable(); + +- vdpau->ReleasePixmap(); +- + glBindTexture (m_textureTarget, 0); + glDisable(m_textureTarget); + #endif +@@ -2312,12 +2321,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 + } + +@@ -2351,11 +2362,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) + { +@@ -3293,12 +3445,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; + } +@@ -3391,14 +3544,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; +@@ -3441,11 +3587,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 332a4cc..67605fc 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.h ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.h +@@ -38,12 +38,11 @@ + + class CRenderCapture; + +-class CVDPAU; + class CBaseTexture; + namespace Shaders { class BaseYUV2RGBShader; } + namespace Shaders { class BaseVideoFilterShader; } + namespace VAAPI { struct CHolder; } +- ++namespace VDPAU { class CVdpauRenderPicture; } + + #undef ALIGN + #define ALIGN(value, alignment) (((value)+((alignment)-1))&~((alignment)-1)) +@@ -142,7 +141,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); +@@ -193,6 +192,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); +@@ -219,6 +222,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 +@@ -279,7 +283,7 @@ class CLinuxRendererGL : public CBaseRenderer + GLuint pbo[MAX_PLANES]; + + #ifdef HAVE_LIBVDPAU +- CVDPAU* vdpau; ++ VDPAU::CVdpauRenderPicture *vdpau; + #endif + #ifdef HAVE_LIBVA + VAAPI::CHolder& vaapi; +@@ -325,6 +329,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 4e8d7e9..6ed62be 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 2fdc9e5..2bfd270 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -860,7 +860,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 d290cef..f0e2c18 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 5b58f61..95f4a1e 100644 +--- a/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp ++++ b/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp +@@ -214,6 +214,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 ac126fe..2bf79fe 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 75132de..2589fe3 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; +@@ -214,14 +214,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 598b82e..7d243f8 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 a781585..8f1f5dc 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +@@ -34,11 +34,16 @@ + #include "settings/MediaSettings.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}, +@@ -52,14 +57,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 + { +@@ -70,113 +77,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; +- past[0] = NULL; +- past[1] = NULL; +- current = NULL; +- future = NULL; +- tmpNoiseReduction = 0.0f; +- tmpSharpness = 0.0f; +- vdp_get_proc_address = NULL; +- vdp_device_destroy = NULL; +- vdp_video_surface_create = NULL; +- vdp_video_surface_destroy = NULL; +- vdp_video_surface_put_bits_y_cb_cr = NULL; +- vdp_video_surface_get_bits_y_cb_cr = NULL; +- vdp_output_surface_put_bits_y_cb_cr = NULL; +- vdp_output_surface_put_bits_native = NULL; +- vdp_output_surface_create = NULL; +- vdp_output_surface_destroy = NULL; +- vdp_output_surface_get_bits_native = NULL; +- vdp_output_surface_render_output_surface = NULL; +- vdp_output_surface_put_bits_indexed = NULL; +- vdp_video_mixer_create = NULL; +- vdp_video_mixer_set_feature_enables = NULL; +- vdp_video_mixer_query_parameter_support = NULL; +- vdp_video_mixer_query_feature_support = NULL; +- vdp_video_mixer_destroy = NULL; +- vdp_video_mixer_render = 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) +@@ -184,6 +108,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) + { +@@ -195,8 +121,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; + } + } +@@ -205,8 +129,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(); + +@@ -224,25 +149,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); +@@ -251,17 +174,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()) + { +@@ -277,188 +203,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; + } + +@@ -472,16 +321,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(); +@@ -496,7 +342,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) +@@ -505,90 +351,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_video_mixer_create(vdp_device, +- m_feature_count, +- m_features, +- ARSIZE(parameters), +- parameters, +- parameter_values, +- &videoMixer); +- CheckStatus(vdp_st, __LINE__); +- +- SetHWUpscaling(); +- } +- +- if (tmpBrightness != CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness || +- tmpContrast != CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast) +- { +- SetColor(); +- tmpBrightness = CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness; +- tmpContrast = CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast; +- } +- if (tmpNoiseReduction != CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction) +- { +- tmpNoiseReduction = CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction; +- SetNoiseReduction(); +- } +- if (tmpSharpness != CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness) +- { +- tmpSharpness = CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness; +- SetSharpness(); +- } +- if ( tmpDeintMode != CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode || +- tmpDeintGUI != CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod || +- (tmpDeintGUI == VS_INTERLACEMETHOD_AUTO && tmpDeint != AutoInterlaceMethod())) +- { +- tmpDeintMode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode; +- tmpDeintGUI = CMediaSettings::Get().GetCurrentVideoSettings().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) +@@ -597,162 +381,12 @@ bool CVDPAU::Supports(EINTERLACEMETHOD method) + return false; + } + +-EINTERLACEMETHOD CVDPAU::AutoInterlaceMethod() +-{ +- return VS_INTERLACEMETHOD_VDPAU_TEMPORAL; +-} +- +-void CVDPAU::SetColor() +-{ +- VdpStatus vdp_st; +- +- if (tmpBrightness != CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness) +- m_Procamp.brightness = (float)((CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness)-50) / 100; +- if (tmpContrast != CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast) +- m_Procamp.contrast = (float)((CMediaSettings::Get().GetCurrentVideoSettings().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("videoscreen.limitedrange")) +- { +- 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 (!CMediaSettings::Get().GetCurrentVideoSettings().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[] = { &CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction }; +- CLog::Log(LOGNOTICE,"Setting Noise Reduction to %f",CMediaSettings::Get().GetCurrentVideoSettings().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 (!CMediaSettings::Get().GetCurrentVideoSettings().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[] = { &CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness }; +- CLog::Log(LOGNOTICE,"Setting Sharpness to %f",CMediaSettings::Get().GetCurrentVideoSettings().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 = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode; +- EINTERLACEMETHOD method = CMediaSettings::Get().GetCurrentVideoSettings().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; + +@@ -762,151 +396,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; + +- for (unsigned int i = 0; i < m_videoSurfaces.size(); ++i) ++ 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) + { + 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__)) +@@ -914,8 +512,7 @@ void CVDPAU::FiniVDPAUOutput() + } + } + +- +-void CVDPAU::ReadFormatOf( PixelFormat fmt ++void CDecoder::ReadFormatOf( PixelFormat fmt + , VdpDecoderProfile &vdp_decoder_profile + , VdpChromaType &vdp_chroma_type) + { +@@ -942,9 +539,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 +@@ -955,170 +552,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); ++ m_vdpauConfig.surfaceWidth, ++ m_vdpauConfig.surfaceHeight, ++ m_vdpauConfig.maxReferences, ++ &m_vdpauConfig.vdpDecoder); + if (CheckStatus(vdp_st, __LINE__)) + return false; + +- vdp_st = vdp_presentation_queue_create(vdp_device, +- vdp_flip_target, +- &vdp_flip_queue); +- 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:"); +@@ -1128,7 +633,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) + { +@@ -1137,13 +642,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) + +@@ -1167,7 +672,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); +@@ -1194,34 +699,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; ++ } + } + } + +@@ -1230,21 +734,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); +@@ -1265,18 +770,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; +@@ -1284,15 +777,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) +@@ -1301,6 +795,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; + +@@ -1315,21 +811,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]) +@@ -1359,59 +852,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 = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode; +- EINTERLACEMETHOD method = CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod; +- if (method == VS_INTERLACEMETHOD_AUTO) +- method = AutoInterlaceMethod(); +- + if(pFrame) + { // we have a new frame from decoder + +@@ -1419,7 +894,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)) +@@ -1428,258 +906,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(); ++ } ++ ++ m_bufferStats.Get(decoded, processed, render); + +- if (mode == VS_DEINTERLACEMODE_FORCE +- || (mode == VS_DEINTERLACEMODE_AUTO && m_DVDVideoPics.front().iFlags & DVP_FLAG_INTERLACED)) ++ 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_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; +- } ++ CSingleLock lock(m_DecoderSection); + +- *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(); +- +- 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) + { +@@ -1697,4 +1083,2424 @@ 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 != CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness || ++ m_Contrast != CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast) ++ { ++ SetColor(); ++ m_Brightness = CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness; ++ m_Contrast = CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast; ++ } ++ if (m_NoiseReduction != CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction) ++ { ++ m_NoiseReduction = CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction; ++ SetNoiseReduction(); ++ } ++ if (m_Sharpness != CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness) ++ { ++ m_Sharpness = CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness; ++ SetSharpness(); ++ } ++ if (m_DeintMode != CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode || ++ m_Deint != CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod) ++ { ++ m_DeintMode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode; ++ m_Deint = CMediaSettings::Get().GetCurrentVideoSettings().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 != CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness) ++ m_Procamp.brightness = (float)((CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness)-50) / 100; ++ if (m_Contrast != CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast) ++ m_Procamp.contrast = (float)((CMediaSettings::Get().GetCurrentVideoSettings().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 (!CMediaSettings::Get().GetCurrentVideoSettings().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[] = { &CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction }; ++ CLog::Log(LOGNOTICE,"Setting Noise Reduction to %f",CMediaSettings::Get().GetCurrentVideoSettings().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 (!CMediaSettings::Get().GetCurrentVideoSettings().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[] = { &CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness }; ++ CLog::Log(LOGNOTICE,"Setting Sharpness to %f",CMediaSettings::Get().GetCurrentVideoSettings().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 = CMediaSettings::Get().GetCurrentVideoSettings().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 = CMediaSettings::Get().GetCurrentVideoSettings().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); ++ ++ delete [] m_BlackBar; ++} ++ ++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 = CMediaSettings::Get().GetCurrentVideoSettings().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 fa1ca38..96c4de9 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-2013 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 f9bd450..082956f 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -1159,6 +1159,10 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) + formatstr = "VDPAU"; + buffering = true; + break; ++ case RENDER_FMT_VDPAU_420: ++ formatstr = "VDPAU_420"; ++ buffering = true; ++ break; + case RENDER_FMT_DXVA: + formatstr = "DXVA"; + buffering = true; +diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp +index f4b02db..3b2f842 100644 +--- a/xbmc/settings/AdvancedSettings.cpp ++++ b/xbmc/settings/AdvancedSettings.cpp +@@ -122,7 +122,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; +@@ -130,6 +130,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; +@@ -532,7 +534,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); +@@ -541,6 +543,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 b6bf23a..8572436 100644 +--- a/xbmc/settings/AdvancedSettings.h ++++ b/xbmc/settings/AdvancedSettings.h +@@ -137,6 +137,8 @@ class CAdvancedSettings : public ISettingsHandler + int m_videoPercentSeekBackwardBig; + CStdString m_videoPPFFmpegDeint; + CStdString m_videoPPFFmpegPostProc; ++ bool m_videoVDPAUtelecine; ++ bool m_videoVDPAUdeintSkipChromaHD; + bool m_musicUseTimeSeeking; + int m_musicTimeSeekForward; + int m_musicTimeSeekBackward; +@@ -152,7 +154,7 @@ class CAdvancedSettings : public ISettingsHandler + 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 128a711..ed26e55 100644 +--- a/xbmc/settings/GUISettings.cpp ++++ b/xbmc/settings/GUISettings.cpp +@@ -721,6 +721,8 @@ void CGUISettings::Initialize() + + #ifdef HAVE_LIBVDPAU + AddBool(vp, "videoplayer.usevdpau", 13425, true); ++ AddBool(vp, "videoplayer.usevdpauinterop", 13436, true); ++ AddBool(vp, "videoplayer.usevdpauinteropyuv", 13437, false); + #endif + #ifdef HAVE_LIBVA + AddBool(vp, "videoplayer.usevaapi", 13426, true); +diff --git a/xbmc/settings/windows/GUIWindowSettingsCategory.cpp b/xbmc/settings/windows/GUIWindowSettingsCategory.cpp +index 6f57416..a5d5b1e 100644 +--- a/xbmc/settings/windows/GUIWindowSettingsCategory.cpp ++++ b/xbmc/settings/windows/GUIWindowSettingsCategory.cpp +@@ -597,6 +597,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 eec7e1f..2329751 100644 +--- a/xbmc/utils/Makefile ++++ b/xbmc/utils/Makefile +@@ -69,6 +69,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 c90bf49..6fe786e 100644 +--- a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp ++++ b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp +@@ -105,7 +105,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 e425327..3dae22c 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.8.1.5 + + +From 3cc27650be1fd90515a31fcf26f942dfd40f0cdc Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Wed, 12 Dec 2012 09:52:17 +0100 +Subject: [PATCH 25/99] vdpau: make interop gl default and remove setting, + rename and intvert interop yuv + +--- + language/English/strings.po | 8 ++------ + xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 17 +++++++++------- + xbmc/settings/GUISettings.cpp | 3 +-- + .../settings/windows/GUIWindowSettingsCategory.cpp | 23 +++------------------- + 4 files changed, 16 insertions(+), 35 deletions(-) + +diff --git a/language/English/strings.po b/language/English/strings.po +index 063ad68..05f2eca 100644 +--- a/language/English/strings.po ++++ b/language/English/strings.po +@@ -5406,14 +5406,10 @@ msgid "Enable HQ Scalers for scalings above %" + msgstr "" + + msgctxt "#13436" +-msgid "Allow Vdpau OpenGL interop" ++msgid "Prefer VDPAU Video Mixer" + msgstr "" + +-msgctxt "#13437" +-msgid "Allow Vdpau OpenGL interop YUV" +-msgstr "" +- +-#empty strings from id 13438 to 13499 ++#empty strings from id 13437 to 13499 + + #: xbmc/settings/GUISettings.cpp + msgctxt "#13500" +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +index 8f1f5dc..67fa2c5 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +@@ -367,12 +367,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) +@@ -1849,7 +1852,7 @@ void CMixer::SetDeinterlacing() + + SetDeintSkipChroma(); + +- m_config.useInteropYuv = g_guiSettings.GetBool("videoplayer.usevdpauinteropyuv"); ++ m_config.useInteropYuv = !g_guiSettings.GetBool("videoplayer.usevdpaumixer"); + } + + void CMixer::SetDeintSkipChroma() +@@ -2041,7 +2044,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(); + } +@@ -2151,11 +2154,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 + { +@@ -3187,7 +3191,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")) +@@ -3219,8 +3223,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 ed26e55..6a2d352 100644 +--- a/xbmc/settings/GUISettings.cpp ++++ b/xbmc/settings/GUISettings.cpp +@@ -721,8 +721,7 @@ void CGUISettings::Initialize() + + #ifdef HAVE_LIBVDPAU + AddBool(vp, "videoplayer.usevdpau", 13425, true); +- AddBool(vp, "videoplayer.usevdpauinterop", 13436, true); +- AddBool(vp, "videoplayer.usevdpauinteropyuv", 13437, false); ++ AddBool(vp, "videoplayer.usevdpaumixer", 13436, true); + #endif + #ifdef HAVE_LIBVA + AddBool(vp, "videoplayer.usevaapi", 13426, true); +diff --git a/xbmc/settings/windows/GUIWindowSettingsCategory.cpp b/xbmc/settings/windows/GUIWindowSettingsCategory.cpp +index a5d5b1e..6973d12 100644 +--- a/xbmc/settings/windows/GUIWindowSettingsCategory.cpp ++++ b/xbmc/settings/windows/GUIWindowSettingsCategory.cpp +@@ -597,9 +597,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 +@@ -611,24 +611,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.8.1.5 + + +From fc7add0d3ae9c2e6cdbe1549a5a814eee2e00e4a Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Wed, 12 Dec 2012 18:34:47 +0100 +Subject: [PATCH 26/99] vdpau: drop studio level conversion + +--- + language/English/strings.po | 7 +- + xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 4 +- + xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 94 ++------------------------ + xbmc/settings/GUISettings.cpp | 1 - + 4 files changed, 7 insertions(+), 99 deletions(-) + +diff --git a/language/English/strings.po b/language/English/strings.po +index 05f2eca..d9022ef 100644 +--- a/language/English/strings.po ++++ b/language/English/strings.po +@@ -4625,12 +4625,7 @@ msgctxt "#13121" + msgid "VDPAU HQ Upscaling level" + msgstr "" + +-#: xbmc/settings/GUISettings.cpp +-msgctxt "#13122" +-msgid "VDPAU Studio level color conversion" +-msgstr "" +- +-#empty strings from id 13123 to 13129 ++#empty strings from id 13122 to 13129 + + #: xbmc/settings/GUISettings.cpp + msgctxt "#13130" +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +index 556bed5..7a6ccfb 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +@@ -3361,7 +3361,7 @@ bool CLinuxRendererGL::Supports(ERENDERFEATURE feature) + { + if(feature == RENDERFEATURE_BRIGHTNESS) + { +- if ((m_renderMethod & RENDER_VDPAU) && !g_guiSettings.GetBool("videoscreen.limitedrange")) ++ if (m_renderMethod & RENDER_VDPAU) + return true; + + if (m_renderMethod & RENDER_VAAPI) +@@ -3374,7 +3374,7 @@ bool CLinuxRendererGL::Supports(ERENDERFEATURE feature) + + if(feature == RENDERFEATURE_CONTRAST) + { +- if ((m_renderMethod & RENDER_VDPAU) && !g_guiSettings.GetBool("videoscreen.limitedrange")) ++ 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 67fa2c5..65c5e97 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +@@ -59,15 +59,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; +@@ -1616,74 +1607,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; +@@ -1703,19 +1626,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 6a2d352..51d04c0 100644 +--- a/xbmc/settings/GUISettings.cpp ++++ b/xbmc/settings/GUISettings.cpp +@@ -800,7 +800,6 @@ void CGUISettings::Initialize() + AddSeparator(vp, "videoplayer.sep1.5"); + #ifdef HAVE_LIBVDPAU + AddBool(NULL, "videoplayer.vdpauUpscalingLevel", 13121, false); +- AddBool(NULL, "videoplayer.vdpaustudiolevel", 0, false); //depreciated + #endif + #endif + AddSeparator(vp, "videoplayer.sep5"); +-- +1.8.1.5 + + +From 618e0d530f8e67338aa7543d1e260f8fc937c4ad Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Wed, 12 Dec 2012 20:28:49 +0100 +Subject: [PATCH 27/99] 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 65c5e97..1ad0701 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +@@ -909,6 +909,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)); + +@@ -1515,10 +1516,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() +@@ -1529,11 +1526,13 @@ void CMixer::CheckFeatures() + m_Upscale = m_config.upscale; + } + if (m_Brightness != CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness || +- m_Contrast != CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast) ++ m_Contrast != CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast || ++ m_ColorMatrix != m_mixerInput[1].DVDPic.color_matrix) + { + SetColor(); + m_Brightness = CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness; + m_Contrast = CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast; ++ m_ColorMatrix = m_mixerInput[1].DVDPic.color_matrix; + } + if (m_NoiseReduction != CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction) + { +@@ -1617,13 +1616,27 @@ void CMixer::SetColor() + m_Procamp.contrast = (float)((CMediaSettings::Get().GetCurrentVideoSettings().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); +@@ -1954,6 +1967,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 96c4de9..173de37 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.8.1.5 + + +From a33ec1ccf7902ef3fd1c226ab81a16abf7826d12 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sun, 27 Jan 2013 12:10:19 +0100 +Subject: [PATCH 28/99] 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 1ad0701..4212924 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +@@ -2045,8 +2045,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.8.1.5 + + +From 51aa5369487d855e65c40a4a9e692c6cf55feb3a Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sat, 2 Feb 2013 13:17:09 +0100 +Subject: [PATCH 29/99] 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 4212924..66985ae 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +@@ -129,10 +129,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)) +@@ -532,13 +531,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 3b2f842..256e6bd 100644 +--- a/xbmc/settings/AdvancedSettings.cpp ++++ b/xbmc/settings/AdvancedSettings.cpp +@@ -126,7 +126,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.8.1.5 + + +From e32b2050cb953c55ae48048dc61b684952701596 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sat, 2 Mar 2013 15:19:19 +0100 +Subject: [PATCH 30/99] vdpau: re-add limited range conversion + +--- + xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 4 +- + xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 86 +++++++++++++++++++++++++- + 2 files changed, 85 insertions(+), 5 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +index 7a6ccfb..556bed5 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +@@ -3361,7 +3361,7 @@ bool CLinuxRendererGL::Supports(ERENDERFEATURE feature) + { + if(feature == RENDERFEATURE_BRIGHTNESS) + { +- if (m_renderMethod & RENDER_VDPAU) ++ if ((m_renderMethod & RENDER_VDPAU) && !g_guiSettings.GetBool("videoscreen.limitedrange")) + return true; + + if (m_renderMethod & RENDER_VAAPI) +@@ -3374,7 +3374,7 @@ bool CLinuxRendererGL::Supports(ERENDERFEATURE feature) + + if(feature == RENDERFEATURE_CONTRAST) + { +- if (m_renderMethod & RENDER_VDPAU) ++ if ((m_renderMethod & RENDER_VDPAU) && !g_guiSettings.GetBool("videoscreen.limitedrange")) + 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 66985ae..4bdfb5b 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +@@ -72,6 +72,9 @@ + , {VS_INTERLACEMETHOD_NONE , (VdpVideoMixerFeature)-1} + }; + ++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} ++ + //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 +@@ -1602,6 +1605,73 @@ 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; +@@ -1635,9 +1705,19 @@ void CMixer::SetColor() + } + + VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX }; +- 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); ++ if (g_guiSettings.GetBool("videoscreen.limitedrange")) ++ { ++ 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__); + } +-- +1.8.1.5 + + +From bcc03f23f5bd74575d0544cecee8bad5abacfed1 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Tue, 25 Sep 2012 12:14:15 +0200 +Subject: [PATCH 31/99] 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 556bed5..4d987ea 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +@@ -1222,7 +1222,8 @@ void CLinuxRendererGL::Render(DWORD flags, int renderBuffer) + break; + + case RQ_MULTIPASS: +- RenderMultiPass(renderBuffer, m_currentField); ++ RenderToFBO(renderBuffer, m_currentField); ++ RenderFromFBO(); + VerifyGLState(); + break; + } +@@ -1345,12 +1346,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 67605fc..84ddbd8 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.h ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.h +@@ -216,7 +216,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.8.1.5 + + +From 0974c77d026ed5c3f51ba5e4eec010ae1347a21b Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Tue, 25 Sep 2012 13:20:47 +0200 +Subject: [PATCH 32/99] 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 4d987ea..aec758b 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +@@ -706,18 +706,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); + +@@ -1217,13 +1205,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; + } +@@ -1346,7 +1342,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]; + +@@ -1448,6 +1444,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); +@@ -1566,6 +1564,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 84ddbd8..dff7e1c 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.h ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.h +@@ -216,12 +216,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.8.1.5 + + +From 212eb79916a6bcc6b57fb364af67523c1fdb00ba Mon Sep 17 00:00:00 2001 +From: fritsch +Date: Thu, 28 Mar 2013 10:38:37 +0100 +Subject: [PATCH 33/99] VDPAU: silence compiler warnings + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 19 ++++++++----------- + 1 file changed, 8 insertions(+), 11 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +index 4bdfb5b..e8f86c4 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +@@ -234,7 +234,7 @@ long CDecoder::Release() + } + } + } +- IHardwareDecoder::Release(); ++ return IHardwareDecoder::Release(); + } + + long CDecoder::ReleasePicReference() +@@ -1403,8 +1403,8 @@ void CMixer::StateMachine(int signal, Protocol *port, Message *msg) + + void CMixer::Process() + { +- Message *msg; +- Protocol *port; ++ Message *msg = NULL; ++ Protocol *port = NULL; + bool gotMsg; + + m_state = M_TOP_UNCONFIGURED; +@@ -1509,7 +1509,6 @@ void CMixer::CreateVdpauMixer() + + 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; +@@ -2640,8 +2639,8 @@ void COutput::StateMachine(int signal, Protocol *port, Message *msg) + + void COutput::Process() + { +- Message *msg; +- Protocol *port; ++ Message *msg = NULL; ++ Protocol *port = NULL; + bool gotMsg; + + m_state = O_TOP_UNCONFIGURED; +@@ -2852,7 +2851,6 @@ CVdpauRenderPicture* COutput::ProcessMixerPicture() + 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); + } +@@ -3010,7 +3008,7 @@ bool COutput::EnsureBufferPool() + { + // create pixmpas + VdpauBufferPool::Pixmaps pixmap; +- int numPixmaps = NUM_RENDER_PICS; ++ unsigned int numPixmaps = NUM_RENDER_PICS; + for (unsigned int i = 0; i < numPixmaps; i++) + { + pixmap.pixmap = None; +@@ -3264,7 +3262,7 @@ void COutput::GLMapSurfaces() + if (m_config.videoSurfaces->size() != m_bufferPool.glVideoSurfaceMap.size()) + { + CSingleLock lock(*m_config.videoSurfaceSec); +- for (int i = 0; i < m_config.videoSurfaces->size(); i++) ++ for (unsigned int i = 0; i < m_config.videoSurfaces->size(); i++) + { + if ((*m_config.videoSurfaces)[i]->surface == VDP_INVALID_HANDLE) + continue; +@@ -3312,7 +3310,7 @@ void COutput::GLMapSurfaces() + if (m_bufferPool.glOutputSurfaceMap.size() != m_bufferPool.numOutputSurfaces) + { + VdpauBufferPool::GLVideoSurface glSurface; +- for (int i=m_bufferPool.glOutputSurfaceMap.size(); i +Date: Mon, 25 Feb 2013 08:47:10 +0100 +Subject: [PATCH 34/99] vdpau: release more resources on pre-cleanup + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 72 +++++++++++++++++++++++--- + xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h | 2 + + 2 files changed, 68 insertions(+), 6 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +index e8f86c4..fb41a72 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +@@ -1147,6 +1147,11 @@ void CMixer::Dispose() + m_dataPort.Purge(); + } + ++bool CMixer::IsActive() ++{ ++ return IsRunning(); ++} ++ + void CMixer::OnStartup() + { + CLog::Log(LOGNOTICE, "CMixer::OnStartup: Output Thread created"); +@@ -2536,6 +2541,7 @@ void COutput::StateMachine(int signal, Protocol *port, Message *msg) + return; + case COutputControlProtocol::PRECLEANUP: + Flush(); ++ PreCleanup(); + msg->Reply(COutputControlProtocol::ACC); + return; + default: +@@ -2742,15 +2748,18 @@ bool COutput::Uninit() + + void COutput::Flush() + { +- Message *reply; +- if (m_mixer.m_controlPort.SendOutMessageSync(CMixerControlProtocol::FLUSH, ++ if (m_mixer.IsActive()) ++ { ++ Message *reply; ++ if (m_mixer.m_controlPort.SendOutMessageSync(CMixerControlProtocol::FLUSH, + &reply, + 2000)) +- { +- reply->Release(); ++ { ++ reply->Release(); ++ } ++ else ++ CLog::Log(LOGERROR, "Coutput::%s - failed to flush mixer", __FUNCTION__); + } +- else +- CLog::Log(LOGERROR, "Coutput::%s - failed to flush mixer", __FUNCTION__); + + Message *msg; + while (m_mixer.m_dataPort.ReceiveInMessage(&msg)) +@@ -3088,6 +3097,57 @@ void COutput::ReleaseBufferPool() + } + } + ++void COutput::PreCleanup() ++{ ++ ++ VdpStatus vdp_st; ++ ++ m_mixer.Dispose(); ++ ++ CSingleLock lock(m_bufferPool.renderPicSec); ++ for (unsigned int i = 0; i < m_bufferPool.outputSurfaces.size(); ++i) ++ { ++ if (m_bufferPool.outputSurfaces[i] == VDP_INVALID_HANDLE) ++ continue; ++ ++ // check if output surface is in use ++ bool used = false; ++ std::deque::iterator it; ++ for (it = m_bufferPool.usedRenderPics.begin(); it != m_bufferPool.usedRenderPics.end(); ++it) ++ { ++ if (((*it)->sourceIdx == m_bufferPool.outputSurfaces[i]) && (*it)->valid) ++ { ++ used = true; ++ break; ++ } ++ } ++ if (used) ++ continue; ++ ++#ifdef GL_NV_vdpau_interop ++ // unmap surface ++ std::map::iterator it_map; ++ it_map = m_bufferPool.glOutputSurfaceMap.find(m_bufferPool.outputSurfaces[i]); ++ if (it_map == m_bufferPool.glOutputSurfaceMap.end()) ++ { ++ CLog::Log(LOGERROR, "%s - could not find gl surface", __FUNCTION__); ++ continue; ++ } ++ glVDPAUUnregisterSurfaceNV(it_map->second.glVdpauSurface); ++ glDeleteTextures(1, it_map->second.texture); ++ m_bufferPool.glOutputSurfaceMap.erase(it_map); ++#endif ++ ++ vdp_st = m_config.vdpProcs.vdp_output_surface_destroy(m_bufferPool.outputSurfaces[i]); ++ CheckStatus(vdp_st, __LINE__); ++ ++ m_bufferPool.outputSurfaces[i] = VDP_INVALID_HANDLE; ++ ++ CLog::Log(LOGDEBUG, "VDPAU::PreCleanup - released output surface"); ++ } ++ ++} ++ + void COutput::InitMixer() + { + for (unsigned int i = 0; i < m_bufferPool.outputSurfaces.size(); ++i) +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h +index 173de37..4b1c53b 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h +@@ -286,6 +286,7 @@ class CMixer : private CThread + virtual ~CMixer(); + void Start(); + void Dispose(); ++ bool IsActive(); + CMixerControlProtocol m_controlPort; + CMixerDataProtocol m_dataPort; + protected: +@@ -454,6 +455,7 @@ class COutput : private CThread + bool DestroyGlxContext(); + bool EnsureBufferPool(); + void ReleaseBufferPool(); ++ void PreCleanup(); + void InitMixer(); + bool GLInit(); + void GLMapSurfaces(); +-- +1.8.1.5 + + +From 06284b5ef47214fbafabb3a3314b52eb11643c99 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Wed, 6 Mar 2013 07:35:10 +0100 +Subject: [PATCH 35/99] vdpau: set deinterlacing method to auto, if default + method not supported + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +index fb41a72..82a46aa 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +@@ -2172,13 +2172,15 @@ void CMixer::InitCycle() + } + else + { +- CLog::Log(LOGERROR, "CMixer::%s - interlace method not supported", __FUNCTION__); ++ CLog::Log(LOGERROR, "CMixer::%s - interlace method: %d not supported, setting to AUTO", __FUNCTION__, method); + 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); ++ ++ CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod = VS_INTERLACEMETHOD_AUTO; + } + } + else +-- +1.8.1.5 + + +From 4cf2067e69ddca2a34a1cbab9e051a44928bdf99 Mon Sep 17 00:00:00 2001 +From: wsnipex +Date: Sun, 4 Nov 2012 14:05:52 +0100 +Subject: [PATCH 36/99] 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 f0e4905..7fd9483 100644 +--- a/configure.in ++++ b/configure.in +@@ -527,6 +527,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" +@@ -2785,12 +2793,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.8.1.5 + + +From 495740af553a38a06ec35cfbf0c8df9c8da7befd Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 28 May 2012 10:41:31 +0200 +Subject: [PATCH 37/99] 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 082956f..0a00d64 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -734,6 +734,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.8.1.5 + + +From ed99ff6fc460d7f6947fa2c2f1cc13c7774f3830 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 28 May 2012 10:43:06 +0200 +Subject: [PATCH 38/99] 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 0a00d64..598d33d 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -1625,7 +1625,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.8.1.5 + + +From a68a0b415887700c406589e43d7e323a2fb58420 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 28 May 2012 10:49:05 +0200 +Subject: [PATCH 39/99] 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 cdf5876..c877d12 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp +@@ -1559,7 +1559,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()) + { +@@ -2222,6 +2222,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.8.1.5 + + +From d711f316c238a8fc7fa7134ee37b2ca6527619ea Mon Sep 17 00:00:00 2001 +From: FernetMenta +Date: Thu, 5 Jul 2012 15:22:05 +0200 +Subject: [PATCH 40/99] 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 2d55cb9..d2c4e53 100644 +--- a/xbmc/Application.cpp ++++ b/xbmc/Application.cpp +@@ -851,7 +851,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 8f099d3..ced8068 100644 +--- a/xbmc/system.h ++++ b/xbmc/system.h +@@ -160,16 +160,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 5feb800..49adcdf 100644 +--- a/xbmc/windowing/WinEvents.h ++++ b/xbmc/windowing/WinEvents.h +@@ -56,6 +56,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 e28b712..68e482e 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/DisplaySettings.h" + #include "settings/Settings.h" +@@ -33,27 +32,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); + } +@@ -66,18 +68,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 +@@ -115,45 +105,37 @@ bool CWinSystemX11::DestroyWindowSystem() + + bool CWinSystemX11::CreateNewWindow(const CStdString& name, bool fullScreen, RESOLUTION_INFO& res, PHANDLE_EVENT_FUNC userFunction) + { +- RESOLUTION_INFO& desktop = CDisplaySettings::Get().GetResolutionInfo(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; + } + +@@ -163,65 +145,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() +@@ -323,17 +345,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; +@@ -345,8 +360,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 +@@ -417,7 +430,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() +@@ -431,8 +447,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 +@@ -448,13 +462,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; + } +@@ -464,13 +492,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; +@@ -502,6 +530,7 @@ void CWinSystemX11::CheckDisplayEvents() + if (bGotEvent || bTimeout) + { + CLog::Log(LOGDEBUG, "%s - notify display reset event", __FUNCTION__); ++ RefreshWindow(); + + CSingleLock lock(m_resourceSection); + +@@ -560,4 +589,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 3dae22c..25faaef 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.8.1.5 + + +From 0c5779548bb5623e4f69249649fc69fbf0b42388 Mon Sep 17 00:00:00 2001 +From: FernetMenta +Date: Thu, 5 Jul 2012 15:24:22 +0200 +Subject: [PATCH 41/99] 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 68e482e..9ee8d18 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -136,6 +136,9 @@ bool CWinSystemX11::DestroyWindow() + XDestroyWindow(m_dpy, m_glWindow); + m_glWindow = 0; + ++ if (m_icon) ++ XFreePixmap(m_dpy, m_icon); ++ + return true; + } + +@@ -690,8 +693,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; +@@ -702,7 +707,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, +@@ -736,4 +741,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 25faaef..c1e6cf1 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.8.1.5 + + +From da4b840e008d1afa5068407c68cb46aaf7bdf2af Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sun, 20 May 2012 14:11:26 +0200 +Subject: [PATCH 42/99] 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.8.1.5 + + +From c597a590ca501f7039ae8ee9b46cd8dd8652cf82 Mon Sep 17 00:00:00 2001 +From: Joakim Plate +Date: Thu, 5 Jul 2012 12:35:55 +0200 +Subject: [PATCH 43/99] 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 9ee8d18..fd51dc0 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -532,14 +532,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; +@@ -547,6 +540,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 c1e6cf1..041ea55 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.8.1.5 + + +From ddbe75e700c8b061fa7b939accccdca9119f5938 Mon Sep 17 00:00:00 2001 +From: FernetMenta +Date: Thu, 5 Jul 2012 15:02:00 +0200 +Subject: [PATCH 44/99] 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 fd51dc0..d495443 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -509,7 +509,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; +@@ -565,8 +565,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.8.1.5 + + +From 00c446aaa736a4d40ed68555d89ebf03247f838e Mon Sep 17 00:00:00 2001 +From: FernetMenta +Date: Thu, 12 Apr 2012 15:43:56 +0200 +Subject: [PATCH 45/99] 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 d495443..d7afc3f 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -79,9 +79,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 9069436..5b2421a 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 e3450fe..cf22fbf 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.8.1.5 + + +From 59f522ed510493a8ad478734a4b81a258775b13d Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sun, 20 May 2012 13:17:10 +0200 +Subject: [PATCH 46/99] xrandr: observe orientation + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 89 ++++++++++++++++++++++++++++++------- + xbmc/windowing/X11/WinSystemX11.h | 2 + + xbmc/windowing/X11/XRandR.cpp | 7 +++ + xbmc/windowing/X11/XRandR.h | 1 + + 4 files changed, 82 insertions(+), 17 deletions(-) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index d7afc3f..6b320f2 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -84,11 +84,11 @@ bool CWinSystemX11::DestroyWindowSystem() + { + 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; ++ out.name = CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP).strOutput; ++ mode.w = CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP).iWidth; ++ mode.h = CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP).iHeight; ++ mode.hz = CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP).fRefreshRate; ++ mode.id = CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP).strId; + g_xrandr.SetMode(out, mode); + } + #endif +@@ -172,25 +172,34 @@ 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); +- g_settings.m_ResInfo[RES_DESKTOP].strId = mode.id; +- g_settings.m_ResInfo[RES_DESKTOP].strOutput = out.name; ++ if (!out.isRotated) ++ UpdateDesktopResolution(CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP), 0, mode.w, mode.h, mode.hz); ++ else ++ UpdateDesktopResolution(CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP), 0, mode.h, mode.w, mode.hz); ++ CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP).strId = mode.id; ++ CDisplaySettings::Get().GetResolutionInfo(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) ++ for (i = RES_DESKTOP; i < CDisplaySettings::Get().ResolutionInfoSize(); ++i) + { +- if (g_settings.m_ResInfo[i].strId == mode.id) ++ if (CDisplaySettings::Get().GetResolutionInfo(i).strId == mode.id) + { + found = true; + break; +@@ -226,16 +235,24 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl + } + 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; ++ out.name = CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP).strOutput; ++ mode.w = CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP).iWidth; ++ mode.h = CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP).iHeight; ++ mode.hz = CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP).fRefreshRate; ++ mode.id = CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP).strId; + } + + 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) +@@ -268,7 +285,11 @@ void CWinSystemX11::UpdateResolutions() + { + XOutput out = g_xrandr.GetCurrentOutput(); + XMode mode = g_xrandr.GetCurrentMode(out.name); +- UpdateDesktopResolution(CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP), 0, mode.w, mode.h, mode.hz); ++ m_bIsRotated = out.isRotated; ++ if (!m_bIsRotated) ++ UpdateDesktopResolution(CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP), 0, mode.w, mode.h, mode.hz); ++ else ++ UpdateDesktopResolution(CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP), 0, mode.h, mode.w, mode.hz); + CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP).strId = mode.id; + CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP).strOutput = out.name; + } +@@ -307,6 +328,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 +@@ -334,6 +365,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 < CDisplaySettings::Get().ResolutionInfoSize(); ++i) ++ { ++ int width = CDisplaySettings::Get().GetResolutionInfo(i).iWidth; ++ CDisplaySettings::Get().GetResolutionInfo(i).iWidth = CDisplaySettings::Get().GetResolutionInfo(i).iHeight; ++ CDisplaySettings::Get().GetResolutionInfo(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 041ea55..0d4436b 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 5b2421a..2204667 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 cf22fbf..71ffab4 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.8.1.5 + + +From 496033c7d354f3a2c80c23c23fe8dc6262549265 Mon Sep 17 00:00:00 2001 +From: FernetMenta +Date: Thu, 5 Jul 2012 11:54:15 +0200 +Subject: [PATCH 47/99] 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 2204667..75c84ea 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 71ffab4..26c2653 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.8.1.5 + + +From dbcc9388cfbc1c1bc8ec8d2c729f08ffaa46b63d Mon Sep 17 00:00:00 2001 +From: FernetMenta +Date: Thu, 5 Jul 2012 11:44:00 +0200 +Subject: [PATCH 48/99] X11: fix multi-head setups + +--- + language/English/strings.po | 4 +- + xbmc/rendering/gl/RenderSystemGL.h | 1 + + xbmc/settings/DisplaySettings.cpp | 9 + + xbmc/settings/DisplaySettings.h | 1 + + xbmc/settings/GUISettings.cpp | 5 + + .../settings/windows/GUIWindowSettingsCategory.cpp | 60 ++++- + xbmc/settings/windows/GUIWindowSettingsCategory.h | 1 + + xbmc/windowing/WinEventsX11.cpp | 7 + + xbmc/windowing/X11/WinSystemX11.cpp | 258 ++++++++++++--------- + xbmc/windowing/X11/WinSystemX11.h | 10 +- + 10 files changed, 241 insertions(+), 115 deletions(-) + +diff --git a/language/English/strings.po b/language/English/strings.po +index d9022ef..242081b 100644 +--- a/language/English/strings.po ++++ b/language/English/strings.po +@@ -937,7 +937,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 5c7a288..f3fd4fb 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/DisplaySettings.cpp b/xbmc/settings/DisplaySettings.cpp +index 7784641..3680a6a 100644 +--- a/xbmc/settings/DisplaySettings.cpp ++++ b/xbmc/settings/DisplaySettings.cpp +@@ -380,3 +380,12 @@ RESOLUTION CDisplaySettings::GetResolutionFromString(const std::string &strResol + + return RES_DESKTOP; + } ++ ++void CDisplaySettings::ClearCustomResolutions() ++{ ++ if (m_resolutions.size() > RES_CUSTOM) ++ { ++ std::vector::iterator firstCustom = m_resolutions.begin()+RES_CUSTOM; ++ m_resolutions.erase(firstCustom, m_resolutions.end()); ++ } ++} +diff --git a/xbmc/settings/DisplaySettings.h b/xbmc/settings/DisplaySettings.h +index aff6ddb..d53641e 100644 +--- a/xbmc/settings/DisplaySettings.h ++++ b/xbmc/settings/DisplaySettings.h +@@ -70,6 +70,7 @@ class CDisplaySettings : public ISubSettings + + void ApplyCalibrations(); + void UpdateCalibrations(); ++ void ClearCustomResolutions(); + + float GetZoomAmount() const { return m_zoomAmount; } + void SetZoomAmount(float zoomAmount) { m_zoomAmount = zoomAmount; } +diff --git a/xbmc/settings/GUISettings.cpp b/xbmc/settings/GUISettings.cpp +index 51d04c0..44f5bff 100644 +--- a/xbmc/settings/GUISettings.cpp ++++ b/xbmc/settings/GUISettings.cpp +@@ -415,11 +415,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 resolution info array in CDisplaySettings. the only meaningful fields are iScreen, iWidth, iHeight. + #if defined(TARGET_DARWIN) +diff --git a/xbmc/settings/windows/GUIWindowSettingsCategory.cpp b/xbmc/settings/windows/GUIWindowSettingsCategory.cpp +index 6973d12..20719ba 100644 +--- a/xbmc/settings/windows/GUIWindowSettingsCategory.cpp ++++ b/xbmc/settings/windows/GUIWindowSettingsCategory.cpp +@@ -529,6 +529,12 @@ void CGUIWindowSettingsCategory::CreateSettings() + FillInRefreshRates(strSetting, CDisplaySettings::Get().GetDisplayResolution(), 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); +@@ -1425,6 +1431,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"); +@@ -2362,11 +2382,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), CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP + idx).iScreen + 1); + pControl->AddLabel(strScreen, CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP + idx).iScreen); + } ++#else ++ pControl->AddLabel(g_localizeStrings.Get(244), 0); ++#endif + pControl->SetValue(mode); + g_guiSettings.SetInt("videoscreen.screen", mode); + } +@@ -2374,6 +2398,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", CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP).strOutput); ++ } ++} ++ ++ + void CGUIWindowSettingsCategory::FillInResolutions(CStdString strSetting, DisplayMode mode, RESOLUTION res, bool UserChange) + { + BaseSettingControlPtr control = GetSetting(strSetting); +@@ -2502,13 +2556,15 @@ void CGUIWindowSettingsCategory::OnRefreshRateChanged(RESOLUTION nextRes) + RESOLUTION lastRes = g_graphicsContext.GetVideoResolution(); + bool cancelled = false; + ++ bool outputChanged = !g_Windowing.IsCurrentOutput(g_guiSettings.GetString("videoscreen.monitor")); ++ + CDisplaySettings::Get().SetCurrentResolution(nextRes, true); +- g_graphicsContext.SetVideoResolution(nextRes); ++ g_graphicsContext.SetVideoResolution(nextRes, outputChanged); + + if (!CGUIDialogYesNo::ShowAndGetInput(13110, 13111, 20022, 20022, -1, -1, cancelled, 10000)) + { + CDisplaySettings::Get().SetCurrentResolution(lastRes, true); +- 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/windows/GUIWindowSettingsCategory.h b/xbmc/settings/windows/GUIWindowSettingsCategory.h +index 74b222c..7391d0b 100644 +--- a/xbmc/settings/windows/GUIWindowSettingsCategory.h ++++ b/xbmc/settings/windows/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 6b320f2..eac6853 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -35,6 +35,7 @@ + #include "cores/VideoRenderers/RenderManager.h" + #include "utils/TimeUtils.h" + #include "settings/GUISettings.h" ++#include "windowing/WindowingFactory.h" + + #if defined(HAS_XRANDR) + #include +@@ -56,6 +57,7 @@ + m_bIgnoreNextFocusMessage = false; + m_dpyLostTime = 0; + m_invisibleCursor = 0; ++ m_bIsInternalXrr = false; + + XSetErrorHandler(XErrorHandler); + } +@@ -68,7 +70,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"); +@@ -105,6 +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); + } + + // m_SDLSurface is free()'d by SDL_Quit(). +@@ -127,7 +132,10 @@ bool CWinSystemX11::DestroyWindow() + return true; + + if (m_glContext) ++ { ++ glFinish(); + glXMakeCurrent(m_dpy, None, NULL); ++ } + + if (m_invisibleCursor) + { +@@ -157,7 +165,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; + } +@@ -166,58 +174,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(CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP), 0, mode.w, mode.h, mode.hz); +- else +- UpdateDesktopResolution(CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP), 0, mode.h, mode.w, mode.hz); +- CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP).strId = mode.id; +- CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP).strOutput = out.name; +- } +- +- RESOLUTION_INFO res; +- unsigned int i; +- bool found(false); +- for (i = RES_DESKTOP; i < CDisplaySettings::Get().ResolutionInfoSize(); ++i) +- { +- if (CDisplaySettings::Get().GetResolutionInfo(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) + { + +@@ -242,8 +203,7 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl + mode.id = CDisplaySettings::Get().GetResolutionInfo(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) +@@ -254,16 +214,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(); +@@ -271,6 +232,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; + } +@@ -279,19 +241,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(CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP), 0, mode.w, mode.h, mode.hz); ++ UpdateDesktopResolution(CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP), out->screen, mode.w, mode.h, mode.hz); + else +- UpdateDesktopResolution(CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP), 0, mode.h, mode.w, mode.hz); ++ UpdateDesktopResolution(CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP), out->screen, mode.h, mode.w, mode.hz); + CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP).strId = mode.id; +- CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP).strOutput = out.name; ++ CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP).strOutput = currentMonitor; + } + else + #endif +@@ -302,23 +275,22 @@ void CWinSystemX11::UpdateResolutions() + UpdateDesktopResolution(CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP), 0, w, h, 0.0); + } + +- + #if defined(HAS_XRANDR) + ++ // erase previous stored modes ++ CDisplaySettings::Get().ClearCustomResolutions(); ++ + 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", +@@ -338,15 +310,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; +@@ -365,28 +337,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 < CDisplaySettings::Get().ResolutionInfoSize(); ++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) +@@ -416,8 +379,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; + } + +@@ -483,6 +449,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 +@@ -524,24 +492,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; +@@ -607,13 +604,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 < CDisplaySettings::Get().ResolutionInfoSize(); ++i) ++ { ++ if (CDisplaySettings::Get().GetResolutionInfo(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); + + } + +@@ -666,14 +696,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) +@@ -695,6 +725,7 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen) + else + mouseActive = false; + } ++ OnLostDevice(); + DestroyWindow(); + } + +@@ -716,7 +747,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)); +@@ -732,7 +767,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); + +@@ -803,14 +838,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 0d4436b..0336b3b 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.8.1.5 + + +From 1dbbd007d0d7ffe359d29fc8e17edcd8a0b7606e Mon Sep 17 00:00:00 2001 +From: FernetMenta +Date: Thu, 5 Jul 2012 11:36:32 +0200 +Subject: [PATCH 49/99] 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 eac6853..4b7b43d 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -269,7 +269,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(CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP), 0, w, h, 0.0); +@@ -391,7 +391,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() +@@ -545,7 +545,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 0336b3b..393399f 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 1bea366..cc39720 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.8.1.5 + + +From f4954d7c3d86ad408a728f962cc3e40970609925 Mon Sep 17 00:00:00 2001 +From: FernetMenta +Date: Thu, 5 Jul 2012 11:45:22 +0200 +Subject: [PATCH 50/99] 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 d76a830..e3e9b4a 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.8.1.5 + + +From 7f44f00e6cc6f76a0901f8f56c470747c64489cb Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Wed, 20 Jun 2012 17:37:11 +0200 +Subject: [PATCH 51/99] 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 4b7b43d..21d38b3 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -170,7 +170,6 @@ bool CWinSystemX11::ResizeWindow(int newWidth, int newHeight, int newLeft, int n + return false; + } + +- RefreshGlxContext(); + m_nWidth = newWidth; + m_nHeight = newHeight; + m_bFullScreen = false; +@@ -221,14 +220,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; +@@ -379,11 +377,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; + } + +@@ -443,14 +438,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 +@@ -727,6 +722,7 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd + } + OnLostDevice(); + DestroyWindow(); ++ m_windowDirty = true; + } + + // create main window +@@ -845,13 +841,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 393399f..2227320 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 cc39720..dda7b14 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.8.1.5 + + +From c5d4f541de4598d5ba6ea5505539da0a2bdf5220 Mon Sep 17 00:00:00 2001 +From: FernetMenta +Date: Thu, 5 Jul 2012 12:06:25 +0200 +Subject: [PATCH 52/99] 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 e3e9b4a..178ccce 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 ace9bf5..5db85e5 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.8.1.5 + + +From 5d6617628f011139daab64e4faebd2d827bf4f33 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 21 Jun 2012 17:26:51 +0200 +Subject: [PATCH 53/99] 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 1083e23..3344db2 100644 +--- a/xbmc/settings/Settings.cpp ++++ b/xbmc/settings/Settings.cpp +@@ -25,6 +25,7 @@ + #include "threads/SingleLock.h" + #include "utils/log.h" + #include "utils/XBMCTinyXML.h" ++#include "windowing/WindowingFactory.h" + + using namespace std; + using namespace XFILE; +diff --git a/xbmc/windowing/WinSystem.h b/xbmc/windowing/WinSystem.h +index 118a076..2536c0a 100644 +--- a/xbmc/windowing/WinSystem.h ++++ b/xbmc/windowing/WinSystem.h +@@ -103,6 +103,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 21d38b3..558f694 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -318,7 +318,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; + +@@ -331,8 +331,42 @@ void CWinSystemX11::UpdateResolutions() + CDisplaySettings::Get().AddResolutionInfo(res); + } + } ++ CDisplaySettings::Get().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 2227320..630c0e2 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.8.1.5 + + +From 364381526f0defa779c8873c36534e3d6199250f Mon Sep 17 00:00:00 2001 +From: FernetMenta +Date: Thu, 5 Jul 2012 12:00:26 +0200 +Subject: [PATCH 54/99] 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 558f694..706f8e4 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -519,6 +519,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) +@@ -762,6 +789,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 630c0e2..f78f613 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.8.1.5 + + +From 3cae383b54ed460088cec192c57252a44c740ecc Mon Sep 17 00:00:00 2001 +From: FernetMenta +Date: Thu, 5 Jul 2012 12:10:09 +0200 +Subject: [PATCH 55/99] 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 706f8e4..a1ffb8d 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -36,6 +36,7 @@ + #include "utils/TimeUtils.h" + #include "settings/GUISettings.h" + #include "windowing/WindowingFactory.h" ++#include + + #if defined(HAS_XRANDR) + #include +@@ -814,7 +815,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; +@@ -830,6 +831,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.8.1.5 + + +From 7effbe5b9767e3de691c475e77802e0383dadaf4 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 28 Jun 2012 19:12:39 +0200 +Subject: [PATCH 56/99] 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.8.1.5 + + +From 12b95358ade9f8f1da5d0a4245d807c38eed78ea Mon Sep 17 00:00:00 2001 +From: Joakim Plate +Date: Thu, 5 Jul 2012 14:18:46 +0200 +Subject: [PATCH 57/99] 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.8.1.5 + + +From 02ae520e61653d32aca22713bfdcbcc873f9206a Mon Sep 17 00:00:00 2001 +From: Joakim Plate +Date: Thu, 5 Jul 2012 14:23:54 +0200 +Subject: [PATCH 58/99] 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.8.1.5 + + +From 1c3867b2f8a39a4e52a071cc1ff5d6684066633a Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sat, 9 Jun 2012 18:23:53 +0200 +Subject: [PATCH 59/99] 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 f18e9b1..066cd77 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.8.1.5 + + +From 14e49e26496bd91ee4e62f95f3fe961f4bb89dd5 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Fri, 16 Mar 2012 15:57:51 +0100 +Subject: [PATCH 60/99] 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 178ccce..1b1b9cf 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.8.1.5 + + +From fd58c701a14f8e54931ed7e8cbff85d5127bf732 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 20 Aug 2012 09:09:09 +0200 +Subject: [PATCH 61/99] 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 1b1b9cf..e2d3a15 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.8.1.5 + + +From 547bbd1dbaf36c2e810eda2890d60dd74865e3fa Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 9 Jul 2012 14:00:18 +0200 +Subject: [PATCH 62/99] 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 a1ffb8d..3acc5d4 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -872,22 +872,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); +@@ -972,16 +974,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) +@@ -990,11 +997,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); +@@ -1007,7 +1014,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) + { +@@ -1045,6 +1052,8 @@ bool CWinSystemX11::CreateIconPixmap() + XFreeGC(m_dpy, gc); + XDestroyImage(img); // this also frees newBuf + ++ delete iconTexture; ++ + return true; + } + +-- +1.8.1.5 + + +From bb952a1b1434979c2167ae6639c2a98b8a631e5c Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Tue, 10 Jul 2012 11:14:12 +0200 +Subject: [PATCH 63/99] 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 3acc5d4..fea6ada 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -814,8 +814,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; +@@ -831,7 +833,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); +@@ -1057,4 +1059,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 f78f613..f479c27 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.8.1.5 + + +From 39d560bb777e57598544d862154af71b7588681f Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 12 Jul 2012 11:11:47 +0200 +Subject: [PATCH 64/99] 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 fea6ada..f38fb73 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -663,16 +663,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.8.1.5 + + +From a88be64d537ad54109821e406766dbf94b3505b1 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 26 Jul 2012 09:34:28 +0200 +Subject: [PATCH 65/99] 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 f38fb73..ea47a72 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -221,7 +221,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.8.1.5 + + +From 4ab0ec9b0861b88d7855a9d747572c84d8cfce3f Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sat, 15 Sep 2012 18:27:29 +0200 +Subject: [PATCH 66/99] 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 ea47a72..d0fd15a 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -664,6 +664,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.8.1.5 + + +From 882c738cd45ca2815e2e81747fd9f2dcead0c97f Mon Sep 17 00:00:00 2001 +From: Rainer Hochecker +Date: Sat, 8 Oct 2011 16:45:13 +0200 +Subject: [PATCH 67/99] 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 | 195 ++++++++++++++++++++++++++++++++++ + 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, 628 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..87af687 +--- /dev/null ++++ b/lib/ffmpeg/libavcodec/xvba_h264.c +@@ -0,0 +1,195 @@ ++/* ++ * 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 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) ++ 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.8.1.5 + + +From 9e5341bc19067ce05bd5137050d0d43af908c9f8 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 12 Apr 2012 12:09:31 +0200 +Subject: [PATCH 68/99] xvba: add decoder + +--- + configure.in | 48 + + language/English/strings.po | 12 +- + xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 216 +- + xbmc/cores/VideoRenderers/LinuxRendererGL.h | 15 +- + xbmc/cores/VideoRenderers/RenderFormats.h | 1 + + xbmc/cores/VideoRenderers/RenderManager.cpp | 4 + + .../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 | 2368 ++++++++++++++++++++ + xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.h | 382 ++++ + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 4 + + xbmc/settings/GUISettings.cpp | 3 + + xbmc/settings/VideoSettings.h | 2 + + xbmc/video/dialogs/GUIDialogVideoSettings.cpp | 1 + + 15 files changed, 3074 insertions(+), 6 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 7fd9483..054c49d 100644 +--- a/configure.in ++++ b/configure.in +@@ -126,6 +126,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], +@@ -1786,6 +1794,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 +@@ -1995,6 +2035,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 +@@ -2458,6 +2504,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) +@@ -2640,6 +2687,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 242081b..5b26122 100644 +--- a/language/English/strings.po ++++ b/language/English/strings.po +@@ -5406,7 +5406,11 @@ msgctxt "#13436" + msgid "Prefer VDPAU Video Mixer" + msgstr "" + +-#empty strings from id 13437 to 13499 ++msgctxt "#13437" ++msgid "Allow hardware acceleration (XVBA)" ++msgstr "" ++ ++#empty strings from id 13438 to 13499 + + #: xbmc/settings/GUISettings.cpp + msgctxt "#13500" +@@ -6433,7 +6437,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 aec758b..b69de25 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +@@ -66,6 +66,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" +@@ -132,6 +135,9 @@ + #ifdef HAVE_LIBVDPAU + vdpau = NULL; + #endif ++#ifdef HAVE_LIBXVBA ++ xvba = NULL; ++#endif + } + + CLinuxRendererGL::YUVBUFFER::~YUVBUFFER() +@@ -620,6 +626,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 +@@ -896,7 +905,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()) +@@ -982,6 +991,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"); +@@ -1130,6 +1144,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 +@@ -1242,6 +1262,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 +@@ -1749,6 +1776,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. +@@ -2800,6 +2898,91 @@ 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 || !xvba->valid) ++ { ++ m_eventTexturesDone[index]->Set(); ++ m_skipRender = true; ++ return; ++ } ++ ++ plane.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]; +@@ -3385,6 +3568,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); +@@ -3398,6 +3584,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); +@@ -3421,7 +3610,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; + } + +@@ -3493,6 +3683,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. +@@ -3542,7 +3742,7 @@ bool CLinuxRendererGL::Supports(ESCALINGMETHOD method) + return false; + + 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 +@@ -3634,4 +3834,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 dff7e1c..b135dec 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; } ++ + + #undef ALIGN + #define ALIGN(value, alignment) (((value)+((alignment)-1))&~((alignment)-1)) +@@ -88,6 +90,7 @@ enum RenderMethod + RENDER_POT=0x10, + RENDER_VAAPI=0x20, + RENDER_CVREF = 0x40, ++ RENDER_XVBA=0x80, + }; + + enum RenderQuality +@@ -149,7 +152,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 +@@ -208,6 +213,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); +@@ -223,6 +232,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 + { +@@ -290,6 +300,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 6ed62be..70ae9bf 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 2bfd270..9e5a9d5 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -876,6 +876,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 2bf79fe..4d7dbb1 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 2589fe3..5dee086 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..41e6a5b +--- /dev/null ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp +@@ -0,0 +1,2368 @@ ++/* ++ * 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 "settings/MediaSettings.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; ++ } ++ ++ // 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; ++ ++ 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 = NULL; ++ Protocol *port = NULL; ++ 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() ++{ ++ // 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 = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode; ++ EINTERLACEMETHOD method = CMediaSettings::Get().GetCurrentVideoSettings().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 598d33d..cf0aa2b 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -1189,6 +1189,10 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) + formatstr = "NONE"; + buffering = false; + break; ++ case RENDER_FMT_XVBA: ++ formatstr = "XVBA"; ++ buffering = true; ++ break; + } + + if(m_bAllowFullscreen) +diff --git a/xbmc/settings/GUISettings.cpp b/xbmc/settings/GUISettings.cpp +index 44f5bff..a11a906 100644 +--- a/xbmc/settings/GUISettings.cpp ++++ b/xbmc/settings/GUISettings.cpp +@@ -731,6 +731,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 3ca4c8b..ae6221c 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 6fe786e..2958744 100644 +--- a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp ++++ b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp +@@ -112,6 +112,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.8.1.5 + + +From de5c20861d69ea772eadd7480c667f1bbf49296f Mon Sep 17 00:00:00 2001 +From: fritsch +Date: Sun, 4 Nov 2012 16:24:10 +0100 +Subject: [PATCH 69/99] 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 eedde21..6d0d9eb 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp +@@ -171,6 +171,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.8.1.5 + + +From e6ec3bda4655f69dafaf4e66952209c0706b7e4e Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sat, 16 Jun 2012 12:46:30 +0200 +Subject: [PATCH 70/99] 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 0cd89e8..db251bc 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.8.1.5 + + +From 26295980f4a9a4edc2323110fc2840cdbc5ae554 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 23 Aug 2012 19:39:49 +0200 +Subject: [PATCH 71/99] 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 58462c5..6a1c5e2 100644 +--- a/lib/DllAvFormat.h ++++ b/lib/DllAvFormat.h +@@ -97,6 +97,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) +@@ -151,6 +152,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; } +@@ -206,6 +208,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) +@@ -239,6 +242,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.8.1.5 + + +From 2235b2161edec32b4184c0b32dd609fa1896d557 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 20 Aug 2012 16:06:39 +0200 +Subject: [PATCH 72/99] dvdplayer: observe pts counter overflow + +--- + .../cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp | 198 ++++++++++++++++++++- + xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h | 3 + + 2 files changed, 200 insertions(+), 1 deletion(-) + +diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +index 3cc0dea..b11de52 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 +@@ -502,6 +502,9 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput) + AddStream(i); + } + ++ m_bPtsWrapChecked = false; ++ m_bPtsWrap = false; ++ + return true; + } + +@@ -606,6 +609,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; +@@ -728,6 +737,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; + +@@ -842,10 +869,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) +@@ -864,6 +901,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) + { + CSingleLock lock(m_critSection); +diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h +index eb2f68c..8a7a5de 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,7 @@ class CDVDDemuxFFmpeg : public CDVDDemux + unsigned m_program; + XbmcThreads::EndTime m_timeout; + ++ bool m_bPtsWrap, m_bPtsWrapChecked; ++ int64_t m_iStartTime, m_iMaxTime, m_iEndTime; + }; + +-- +1.8.1.5 + + +From 8c52a8f798ae79d0e651daa7d621b3388ea9a751 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Tue, 2 Oct 2012 13:02:10 +0200 +Subject: [PATCH 73/99] 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 cf0aa2b..e1935c1 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -1045,7 +1045,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 +@@ -1212,7 +1212,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.8.1.5 + + +From 2d208bbebd410f6e8a31d2feb570202ebceaa2f3 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 11 Oct 2012 12:05:50 +0200 +Subject: [PATCH 74/99] 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 82a46aa..d96d8c2 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +@@ -1782,10 +1782,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 256e6bd..9d12c77 100644 +--- a/xbmc/settings/AdvancedSettings.cpp ++++ b/xbmc/settings/AdvancedSettings.cpp +@@ -130,6 +130,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; +@@ -543,6 +545,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 8572436..7ac18ed 100644 +--- a/xbmc/settings/AdvancedSettings.h ++++ b/xbmc/settings/AdvancedSettings.h +@@ -137,6 +137,8 @@ class CAdvancedSettings : public ISettingsHandler + 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.8.1.5 + + +From fc35670fbd7281330e3f822db3a33a8acca9a223 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Fri, 2 Nov 2012 13:20:03 +0100 +Subject: [PATCH 75/99] player: fix rewind + +--- + xbmc/cores/dvdplayer/DVDMessage.h | 5 ++++- + xbmc/cores/dvdplayer/DVDPlayer.cpp | 30 +++++++++++++++++++----------- + xbmc/cores/dvdplayer/DVDPlayer.h | 7 ++++--- + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 10 ++++++---- + xbmc/cores/dvdplayer/DVDPlayerVideo.h | 1 + + 5 files changed, 34 insertions(+), 19 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDMessage.h b/xbmc/cores/dvdplayer/DVDMessage.h +index 0dac948..6de5207 100644 +--- a/xbmc/cores/dvdplayer/DVDMessage.h ++++ b/xbmc/cores/dvdplayer/DVDMessage.h +@@ -220,7 +220,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) +@@ -228,6 +228,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; } +@@ -235,6 +236,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; +@@ -242,6 +244,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 c877d12..e585c66 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp +@@ -1560,11 +1560,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 +@@ -1583,7 +1585,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)); + } + } + } +@@ -2068,7 +2070,7 @@ void CDVDPlayer::HandleMessages() + // dts after successful seek + m_StateInput.dts = start; + +- FlushBuffers(!msg.GetFlush(), start, msg.GetAccurate()); ++ FlushBuffers(!msg.GetFlush(), start, msg.GetAccurate(), msg.GetSync()); + } + else + CLog::Log(LOGWARNING, "error while seeking"); +@@ -2207,9 +2209,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(); + } + +@@ -2225,7 +2228,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 +@@ -3173,7 +3177,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) +@@ -3185,19 +3189,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; + +@@ -3241,7 +3249,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 fa6c99f..6ca43d4 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayer.h ++++ b/xbmc/cores/dvdplayer/DVDPlayer.h +@@ -304,7 +304,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(); +@@ -353,8 +353,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 e1935c1..cc3f0de 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -1296,13 +1296,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; + } +@@ -1599,7 +1599,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; +@@ -1699,6 +1699,8 @@ int CDVDPlayerVideo::CalcDropRequirement(double pts) + int iSkippedDeint = 0; + int iBufferLevel; + ++ m_droppingStats.m_lastPts = pts; ++ + // get decoder stats + if (!m_pVideoCodec->GetCodecStats(iDecoderPts, iSkippedDeint, interlaced)) + iDecoderPts = pts; +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.h b/xbmc/cores/dvdplayer/DVDPlayerVideo.h +index f395897..c9bf2f4 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.8.1.5 + + +From d95fef6b1d4279ce37e7de1221c0211a1f0b9a72 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Fri, 23 Nov 2012 17:41:12 +0100 +Subject: [PATCH 76/99] 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 75c84ea..2343ec0 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 77/99] 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 d0fd15a..0c70c1f 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -683,6 +683,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.8.1.5 + + +From 843f118a8aae7f81f6460bd620dd006e8f8f9993 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Tue, 11 Dec 2012 11:08:13 +0100 +Subject: [PATCH 78/99] 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 0c70c1f..0a1bafa 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -110,7 +110,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.8.1.5 + + +From c7b7b04f58c8efada9a9df8dc7d6875ce2b6b79d 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 79/99] 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 2343ec0..9fcaec5 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.8.1.5 + + +From f8c9e26ed6d726fec5c6fd9af7485a8221e4b27c Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 20 Dec 2012 19:35:38 +0100 +Subject: [PATCH 80/99] fix compile error after recent change + +--- + xbmc/settings/windows/GUIWindowSettingsCategory.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/xbmc/settings/windows/GUIWindowSettingsCategory.cpp b/xbmc/settings/windows/GUIWindowSettingsCategory.cpp +index 20719ba..78dccb6 100644 +--- a/xbmc/settings/windows/GUIWindowSettingsCategory.cpp ++++ b/xbmc/settings/windows/GUIWindowSettingsCategory.cpp +@@ -2402,7 +2402,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.8.1.5 + + +From 095df2325981d0b1ec101b4bc49d98688b74b50d Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 24 Dec 2012 16:02:42 +0100 +Subject: [PATCH 81/99] 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 58742de..6cc0730 100644 +--- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp ++++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp +@@ -349,9 +349,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]) +@@ -368,6 +366,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.8.1.5 + + +From 7d79118016ea48278c2ff4ce6c403428d0ba2df7 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 17 Jan 2013 16:03:22 +0100 +Subject: [PATCH 82/99] 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.8.1.5 + + +From 89a86f234253d50926c105a437f1da96a5654caa Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 21 Jan 2013 09:00:19 +0100 +Subject: [PATCH 83/99] 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 0756b1e..0d0ba71 100644 +--- a/xbmc/powermanagement/PowerManager.cpp ++++ b/xbmc/powermanagement/PowerManager.cpp +@@ -254,11 +254,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.8.1.5 + + +From 780c12e3e5b90cab556d297985c1e79dd84dd2b2 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Wed, 23 Jan 2013 17:03:02 +0100 +Subject: [PATCH 84/99] 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 9fcaec5..b91178e 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.8.1.5 + + +From cfbc5a0c5e981dc4f842b413a04f4546e070be4d Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Wed, 23 Jan 2013 17:03:39 +0100 +Subject: [PATCH 85/99] 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 0a1bafa..cbff7e1 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -407,11 +407,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); +@@ -928,7 +928,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 f479c27..7345c06 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.8.1.5 + + +From 66f7f3345b6d1ccd81ca817a53c567f1cdf92dc2 Mon Sep 17 00:00:00 2001 +From: unknown +Date: Fri, 18 Jan 2013 15:16:38 +0100 +Subject: [PATCH 86/99] multi-screen: fix compilation on windows + +--- + xbmc/settings/windows/GUIWindowSettingsCategory.cpp | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/xbmc/settings/windows/GUIWindowSettingsCategory.cpp b/xbmc/settings/windows/GUIWindowSettingsCategory.cpp +index 78dccb6..cafc732 100644 +--- a/xbmc/settings/windows/GUIWindowSettingsCategory.cpp ++++ b/xbmc/settings/windows/GUIWindowSettingsCategory.cpp +@@ -529,12 +529,14 @@ void CGUIWindowSettingsCategory::CreateSettings() + FillInRefreshRates(strSetting, CDisplaySettings::Get().GetDisplayResolution(), 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); +@@ -1431,6 +1433,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(); +@@ -1445,6 +1448,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"); +@@ -2400,6 +2404,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); +@@ -2425,6 +2430,7 @@ void CGUIWindowSettingsCategory::FillInMonitors(CStdString strSetting) + pControl->SetValue(currentMonitor); + g_guiSettings.SetString("videoscreen.monitor", CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP).strOutput); + } ++#endif + } + + +@@ -2556,7 +2562,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 + + CDisplaySettings::Get().SetCurrentResolution(nextRes, true); + g_graphicsContext.SetVideoResolution(nextRes, outputChanged); +-- +1.8.1.5 + + +From 4ec0e391510ccdb2429b1321fcffdf01371a6575 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Fri, 14 Dec 2012 14:19:15 +0100 +Subject: [PATCH 87/99] pvr: do not show selection dialog for a single menu + hook + +--- + xbmc/pvr/addons/PVRClients.cpp | 19 +++++++++++-------- + 1 file changed, 11 insertions(+), 8 deletions(-) + +diff --git a/xbmc/pvr/addons/PVRClients.cpp b/xbmc/pvr/addons/PVRClients.cpp +index 1c61362..e88c295 100644 +--- a/xbmc/pvr/addons/PVRClients.cpp ++++ b/xbmc/pvr/addons/PVRClients.cpp +@@ -729,16 +729,19 @@ void CPVRClients::ProcessMenuHooks(int iClientID, PVR_MENUHOOK_CAT cat) + if (GetConnectedClient(iClientID, client) && client->HaveMenuHooks(cat)) + { + hooks = client->GetMenuHooks(); +- std::vector hookIDs; ++ int selection = 0; + +- CGUIDialogSelect* pDialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT); +- pDialog->Reset(); +- pDialog->SetHeading(19196); +- for (unsigned int i = 0; i < hooks->size(); i++) +- pDialog->Add(client->GetString(hooks->at(i).iLocalizedStringId)); +- pDialog->DoModal(); ++ if (hooks->size() > 1) ++ { ++ CGUIDialogSelect* pDialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT); ++ pDialog->Reset(); ++ pDialog->SetHeading(19196); ++ for (unsigned int i = 0; i < hooks->size(); i++) ++ pDialog->Add(client->GetString(hooks->at(i).iLocalizedStringId)); ++ pDialog->DoModal(); ++ selection = pDialog->GetSelectedLabel(); ++ } + +- int selection = pDialog->GetSelectedLabel(); + if (selection >= 0) + client->CallMenuHook(hooks->at(selection)); + } +-- +1.8.1.5 + + +From ea458e0f3e37f4b9174246a65a3323f47c323856 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sun, 3 Feb 2013 08:17:16 +0100 +Subject: [PATCH 88/99] X11: use default screen parameters if no output + connected + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 55 ++++++++++++++++++++++--------------- + 1 file changed, 33 insertions(+), 22 deletions(-) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index cbff7e1..ea531ae 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -205,25 +205,27 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl + } + + XMode currmode = g_xrandr.GetCurrentMode(out.name); +- +- // flip h/w when rotated +- if (m_bIsRotated) ++ if (!currmode.name.empty()) + { +- int w = mode.w; +- mode.w = mode.h; +- mode.h = w; +- } ++ // 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 (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); +- if (m_glWindow) +- return true; ++ // only call xrandr if mode changes ++ 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); ++ if (m_glWindow) ++ return true; ++ } + } + #endif + +@@ -270,9 +272,10 @@ void CWinSystemX11::UpdateResolutions() + else + #endif + { +- int x11screen = m_nScreen; +- int w = DisplayWidth(m_dpy, x11screen); +- int h = DisplayHeight(m_dpy, x11screen); ++ g_guiSettings.SetString("videoscreen.monitor", "Default"); ++ m_nScreen = DefaultScreen(m_dpy); ++ int w = DisplayWidth(m_dpy, m_nScreen); ++ int h = DisplayHeight(m_dpy, m_nScreen); + UpdateDesktopResolution(CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP), 0, w, h, 0.0); + } + +@@ -817,11 +820,19 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd + Colormap cmap; + XSetWindowAttributes swa; + XVisualInfo *vi; ++ int x0 = 0; ++ int y0 = 0; + + XOutput *out = g_xrandr.GetOutput(output); + if (!out) + out = g_xrandr.GetOutput(m_currentOutput); +- m_nScreen = out->screen; ++ if (out) ++ { ++ m_nScreen = out->screen; ++ x0 = out->x; ++ y0 = out->y; ++ } ++ + vi = glXChooseVisual(m_dpy, m_nScreen, att); + cmap = XCreateColormap(m_dpy, RootWindow(m_dpy, vi->screen), vi->visual, AllocNone); + +@@ -840,7 +851,7 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd + unsigned long mask = CWBackPixel | CWBorderPixel | CWColormap | CWOverrideRedirect | CWEventMask; + + m_glWindow = XCreateWindow(m_dpy, RootWindow(m_dpy, vi->screen), +- out->x, out->y, width, height, 0, vi->depth, ++ x0, y0, width, height, 0, vi->depth, + InputOutput, vi->visual, + mask, &swa); + +-- +1.8.1.5 + + +From 3a01b7f8744913e9989a0ed7016e6c9773b7d129 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sat, 23 Mar 2013 15:13:32 +0100 +Subject: [PATCH 89/99] X11: create parent window + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 69 +++++++++++++++++++++++-------------- + xbmc/windowing/X11/WinSystemX11.h | 2 +- + 2 files changed, 44 insertions(+), 27 deletions(-) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index ea531ae..2d9cf2a 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -53,6 +53,7 @@ + m_glContext = NULL; + m_dpy = NULL; + m_glWindow = 0; ++ m_mainWindow = 0; + m_bWasFullScreenBeforeMinimize = false; + m_minimized = false; + m_bIgnoreNextFocusMessage = false; +@@ -130,7 +131,7 @@ bool CWinSystemX11::CreateNewWindow(const CStdString& name, bool fullScreen, RES + + bool CWinSystemX11::DestroyWindow() + { +- if (!m_glWindow) ++ if (!m_mainWindow) + return true; + + if (m_glContext) +@@ -141,19 +142,21 @@ bool CWinSystemX11::DestroyWindow() + + if (m_invisibleCursor) + { +- XUndefineCursor(m_dpy, m_glWindow); ++ XUndefineCursor(m_dpy, m_mainWindow); + XFreeCursor(m_dpy, m_invisibleCursor); + m_invisibleCursor = 0; + } + + CWinEvents::Quit(); + +- XUnmapWindow(m_dpy, m_glWindow); ++ XUnmapWindow(m_dpy, m_mainWindow); + XSync(m_dpy,TRUE); + XUngrabKeyboard(m_dpy, CurrentTime); + XUngrabPointer(m_dpy, CurrentTime); + XDestroyWindow(m_dpy, m_glWindow); ++ XDestroyWindow(m_dpy, m_mainWindow); + m_glWindow = 0; ++ m_mainWindow = 0; + + if (m_icon) + XFreePixmap(m_dpy, m_icon); +@@ -223,7 +226,7 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl + OnLostDevice(); + m_bIsInternalXrr = true; + g_xrandr.SetMode(out, mode); +- if (m_glWindow) ++ if (m_mainWindow) + return true; + } + } +@@ -501,9 +504,9 @@ bool CWinSystemX11::RefreshGlxContext(bool force) + void CWinSystemX11::ShowOSMouse(bool show) + { + if (show) +- XUndefineCursor(m_dpy,m_glWindow); ++ XUndefineCursor(m_dpy,m_mainWindow); + else if (m_invisibleCursor) +- XDefineCursor(m_dpy,m_glWindow, m_invisibleCursor); ++ XDefineCursor(m_dpy,m_mainWindow, m_invisibleCursor); + } + + void CWinSystemX11::ResetOSScreensaver() +@@ -586,10 +589,10 @@ void CWinSystemX11::NotifyMouseCoverage(bool covered) + int result = -1; + while (result != GrabSuccess && result != AlreadyGrabbed) + { +- result = XGrabPointer(m_dpy, m_glWindow, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); ++ result = XGrabPointer(m_dpy, m_mainWindow, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); + XbmcThreads::ThreadSleep(100); + } +- XGrabKeyboard(m_dpy, m_glWindow, True, GrabModeAsync, GrabModeAsync, CurrentTime); ++ XGrabKeyboard(m_dpy, m_mainWindow, True, GrabModeAsync, GrabModeAsync, CurrentTime); + } + else + { +@@ -607,7 +610,7 @@ bool CWinSystemX11::Minimize() + g_graphicsContext.ToggleFullScreenRoot(); + } + +- XIconifyWindow(m_dpy, m_glWindow, m_nScreen); ++ XIconifyWindow(m_dpy, m_mainWindow, m_nScreen); + + m_minimized = true; + return true; +@@ -618,13 +621,13 @@ bool CWinSystemX11::Restore() + } + bool CWinSystemX11::Hide() + { +- XUnmapWindow(m_dpy, m_glWindow); ++ XUnmapWindow(m_dpy, m_mainWindow); + XSync(m_dpy, False); + return true; + } + bool CWinSystemX11::Show(bool raise) + { +- XMapWindow(m_dpy, m_glWindow); ++ XMapWindow(m_dpy, m_mainWindow); + XSync(m_dpy, False); + m_minimized = false; + return true; +@@ -774,7 +777,7 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd + bool mouseActive = false; + float mouseX, mouseY; + +- if (m_glWindow && ((m_bFullScreen != fullscreen) || !m_currentOutput.Equals(output) || m_windowDirty)) ++ if (m_mainWindow && ((m_bFullScreen != fullscreen) || !m_currentOutput.Equals(output) || m_windowDirty)) + { + mouseActive = g_Mouse.IsActive(); + if (mouseActive) +@@ -783,7 +786,7 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd + 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, ++ bool isInWin = XQueryPointer(m_dpy, m_mainWindow, &root_return, &child_return, + &root_x_return, &root_y_return, + &win_x_return, &win_y_return, + &mask_return); +@@ -802,7 +805,7 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd + } + + // create main window +- if (!m_glWindow) ++ if (!m_mainWindow) + { + EnableSystemScreenSaver(false); + +@@ -843,22 +846,31 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd + 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), ++ m_mainWindow = XCreateWindow(m_dpy, RootWindow(m_dpy, vi->screen), + x0, y0, width, height, 0, vi->depth, + InputOutput, vi->visual, + mask, &swa); + ++ swa.override_redirect = False; ++ swa.border_pixel = 0; ++ swa.event_mask = 0; ++ mask = CWBackPixel | CWBorderPixel | CWColormap | CWOverrideRedirect | CWColormap; ++ ++ m_glWindow = XCreateWindow(m_dpy, m_mainWindow, ++ 0, 0, width, height, 0, vi->depth, ++ InputOutput, vi->visual, ++ mask, &swa); ++ + 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); ++ XChangeProperty(m_dpy, m_mainWindow, XInternAtom(m_dpy, "_NET_WM_STATE", True), XA_ATOM, 32, PropModeReplace, (unsigned char *) &fs, 1); + } + + // define invisible cursor +@@ -867,14 +879,14 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd + 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); ++ bitmapNoData = XCreateBitmapFromData(m_dpy, m_mainWindow, 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); ++ XDefineCursor(m_dpy,m_mainWindow, m_invisibleCursor); + + //init X11 events +- CWinEvents::Init(m_dpy, m_glWindow); ++ CWinEvents::Init(m_dpy, m_mainWindow); + + changeWindow = true; + changeSize = true; +@@ -887,13 +899,17 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd + + if (changeSize || changeWindow) + { ++ XResizeWindow(m_dpy, m_mainWindow, width, height); ++ } ++ ++ if ((width != m_nWidth) || (height != m_nHeight) || changeWindow) ++ { + XResizeWindow(m_dpy, m_glWindow, width, height); + } + + if (changeWindow) + { + m_icon = None; +- if (!fullscreen) + { + CreateIconPixmap(); + XWMHints *wm_hints; +@@ -910,21 +926,22 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd + wm_hints->flags = StateHint | IconPixmapHint; + + XSync(m_dpy,False); +- XSetWMProperties(m_dpy, m_glWindow, &windowName, &iconName, ++ XSetWMProperties(m_dpy, m_mainWindow, &windowName, &iconName, + 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); +- XSetWMProtocols(m_dpy, m_glWindow, &wmDeleteMessage, 1); ++ XSetWMProtocols(m_dpy, m_mainWindow, &wmDeleteMessage, 1); + } + XMapRaised(m_dpy, m_glWindow); ++ XMapRaised(m_dpy, m_mainWindow); + XSync(m_dpy,TRUE); + + if (changeWindow && mouseActive) + { +- XWarpPointer(m_dpy, None, m_glWindow, 0, 0, 0, 0, mouseX*width, mouseY*height); ++ XWarpPointer(m_dpy, None, m_mainWindow, 0, 0, 0, 0, mouseX*width, mouseY*height); + } + + if (fullscreen) +@@ -932,10 +949,10 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd + int result = -1; + while (result != GrabSuccess && result != AlreadyGrabbed) + { +- result = XGrabPointer(m_dpy, m_glWindow, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); ++ result = XGrabPointer(m_dpy, m_mainWindow, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); + XbmcThreads::ThreadSleep(100); + } +- XGrabKeyboard(m_dpy, m_glWindow, True, GrabModeAsync, GrabModeAsync, CurrentTime); ++ XGrabKeyboard(m_dpy, m_mainWindow, True, GrabModeAsync, GrabModeAsync, CurrentTime); + } + + CDirtyRegionList dr; +diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h +index 7345c06..770ae84 100644 +--- a/xbmc/windowing/X11/WinSystemX11.h ++++ b/xbmc/windowing/X11/WinSystemX11.h +@@ -79,7 +79,7 @@ class CWinSystemX11 : public CWinSystemBase + void OnLostDevice(); + bool SetWindow(int width, int height, bool fullscreen, const CStdString &output); + +- Window m_glWindow; ++ Window m_glWindow, m_mainWindow; + GLXContext m_glContext; + Display* m_dpy; + Cursor m_invisibleCursor; +-- +1.8.1.5 + + +From 44a2a225774081fac096909d77202eb785187369 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sun, 24 Mar 2013 12:30:12 +0100 +Subject: [PATCH 90/99] X11: use system key repeat rate instead of hardcoded + one, taken from 58fd64b194e38b73b5f3132744bab35e994e7441 + +--- + xbmc/windowing/WinEventsX11.cpp | 58 +++++++++++++---------------------------- + xbmc/windowing/WinEventsX11.h | 5 +--- + 2 files changed, 19 insertions(+), 44 deletions(-) + +diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp +index ed31c04..ac95100 100644 +--- a/xbmc/windowing/WinEventsX11.cpp ++++ b/xbmc/windowing/WinEventsX11.cpp +@@ -204,7 +204,6 @@ bool CWinEventsX11::Init(Display *dpy, Window win) + 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 + char *old_locale = NULL, *old_modifiers = NULL; +@@ -319,20 +318,6 @@ bool CWinEventsX11::MessagePump() + 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; + +@@ -355,7 +340,6 @@ 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; +@@ -368,7 +352,6 @@ 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; +@@ -424,7 +407,7 @@ bool CWinEventsX11::MessagePump() + { + newEvent.key.keysym.unicode = keybuf[0]; + } +- ret |= ProcessKey(newEvent, 500); ++ ret |= ProcessKey(newEvent); + break; + } + +@@ -463,7 +446,7 @@ bool CWinEventsX11::MessagePump() + newEvent.key.keysym.unicode = keys[i]; + newEvent.key.state = xevent.xkey.state; + newEvent.key.type = xevent.xkey.type; +- ret |= ProcessKey(newEvent, 500); ++ ret |= ProcessKey(newEvent); + } + if (keys.length() > 0) + { +@@ -474,7 +457,7 @@ bool CWinEventsX11::MessagePump() + newEvent.key.state = xevent.xkey.state; + newEvent.key.type = xevent.xkey.type; + +- ret |= ProcessKey(newEvent, 500); ++ ret |= ProcessKey(newEvent); + } + break; + } +@@ -485,7 +468,7 @@ bool CWinEventsX11::MessagePump() + newEvent.key.keysym.sym = LookupXbmcKeySym(xkeysym); + newEvent.key.state = xevent.xkey.state; + newEvent.key.type = xevent.xkey.type; +- ret |= ProcessKey(newEvent, 500); ++ ret |= ProcessKey(newEvent); + break; + } + +@@ -495,6 +478,18 @@ bool CWinEventsX11::MessagePump() + + case KeyRelease: + { ++ // if we have a queued press directly after, this is a repeat ++ if( XEventsQueued( WinEvents->m_display, QueuedAfterReading ) ) ++ { ++ XEvent next_event; ++ XPeekEvent( WinEvents->m_display, &next_event ); ++ if(next_event.type == KeyPress ++ && next_event.xkey.window == xevent.xkey.window ++ && next_event.xkey.keycode == xevent.xkey.keycode ++ && (next_event.xkey.time - xevent.xkey.time < 2) ) ++ continue; ++ } ++ + XBMC_Event newEvent; + KeySym xkeysym; + memset(&newEvent, 0, sizeof(newEvent)); +@@ -504,7 +499,7 @@ bool CWinEventsX11::MessagePump() + newEvent.key.keysym.sym = LookupXbmcKeySym(xkeysym); + newEvent.key.state = xevent.xkey.state; + newEvent.key.type = xevent.xkey.type; +- ret |= ProcessKey(newEvent, 0); ++ ret |= ProcessKey(newEvent); + break; + } + +@@ -580,8 +575,6 @@ bool CWinEventsX11::MessagePump() + + }// while + +- ret |= ProcessKeyRepeat(); +- + #if defined(HAS_XRANDR) + if (WinEvents && WinEvents->m_xrrEventPending && WinEvents->m_xrrFailSafeTimer.IsTimePast()) + { +@@ -616,7 +609,7 @@ bool CWinEventsX11::MessagePump() + return ret; + } + +-bool CWinEventsX11::ProcessKey(XBMC_Event &event, int repeatDelay) ++bool CWinEventsX11::ProcessKey(XBMC_Event &event) + { + if (event.type == XBMC_KEYDOWN) + { +@@ -654,8 +647,6 @@ bool CWinEventsX11::ProcessKey(XBMC_Event &event, int repeatDelay) + 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) +@@ -696,7 +687,6 @@ bool CWinEventsX11::ProcessKey(XBMC_Event &event, int repeatDelay) + break; + } + event.key.keysym.mod = (XBMCMod)WinEvents->m_keymodState; +- memset(&(WinEvents->m_lastKey), 0, sizeof(event)); + } + + return g_application.OnEvent(event); +@@ -719,18 +709,6 @@ bool CWinEventsX11::ProcessShortcuts(XBMC_Event& event) + 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; +-} +- + XBMCKey CWinEventsX11::LookupXbmcKeySym(KeySym keysym) + { + // try direct mapping first +diff --git a/xbmc/windowing/WinEventsX11.h b/xbmc/windowing/WinEventsX11.h +index 102a076..5b1f3fa 100644 +--- a/xbmc/windowing/WinEventsX11.h ++++ b/xbmc/windowing/WinEventsX11.h +@@ -39,8 +39,7 @@ class CWinEventsX11 : public CWinEventsBase + + protected: + static XBMCKey LookupXbmcKeySym(KeySym keysym); +- static bool ProcessKey(XBMC_Event &event, int repeatDelay); +- static bool ProcessKeyRepeat(); ++ static bool ProcessKey(XBMC_Event &event); + static bool ProcessShortcuts(XBMC_Event& event); + static CWinEventsX11 *WinEvents; + Display *m_display; +@@ -50,8 +49,6 @@ class CWinEventsX11 : public CWinEventsBase + size_t m_keybuf_len; + XIM m_xim; + XIC m_xic; +- XBMC_Event m_lastKey; +- XbmcThreads::EndTime m_repeatKeyTimeout; + std::map m_symLookupTable; + int m_keymodState; + bool m_structureChanged; +-- +1.8.1.5 + + +From 94ed25178f52533a04c0674dfcbf89ca4f3a2c61 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sun, 24 Mar 2013 16:04:48 +0100 +Subject: [PATCH 91/99] linux: use CLOCK_MONOTONIC_RAW as this is not subject + to NTP + +--- + xbmc/threads/SystemClock.cpp | 2 +- + xbmc/utils/TimeUtils.cpp | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/xbmc/threads/SystemClock.cpp b/xbmc/threads/SystemClock.cpp +index 5a1c3ea..6dea6bf 100644 +--- a/xbmc/threads/SystemClock.cpp ++++ b/xbmc/threads/SystemClock.cpp +@@ -42,7 +42,7 @@ + now_time = (uint64_t)timeGetTime(); + #else + struct timespec ts = {}; +- clock_gettime(CLOCK_MONOTONIC, &ts); ++ clock_gettime(CLOCK_MONOTONIC_RAW, &ts); + now_time = (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000); + #endif + if (!start_time_set) +diff --git a/xbmc/utils/TimeUtils.cpp b/xbmc/utils/TimeUtils.cpp +index 8304ef6..ba27257 100644 +--- a/xbmc/utils/TimeUtils.cpp ++++ b/xbmc/utils/TimeUtils.cpp +@@ -43,7 +43,7 @@ int64_t CurrentHostCounter(void) + return( (int64_t)PerformanceCount.QuadPart ); + #else + struct timespec now; +- clock_gettime(CLOCK_MONOTONIC, &now); ++ clock_gettime(CLOCK_MONOTONIC_RAW, &now); + return( ((int64_t)now.tv_sec * 1000000000L) + now.tv_nsec ); + #endif + } +-- +1.8.1.5 + + +From d08b9ccdd27d11581c1e2e9618117b90cd40f5a3 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 28 Mar 2013 15:18:05 +0100 +Subject: [PATCH 92/99] OMXPlayerAudio: fix incorrect usage of flag stalled + +--- + xbmc/cores/omxplayer/OMXPlayerAudio.cpp | 18 +++++++++++++----- + xbmc/cores/omxplayer/OMXPlayerAudio.h | 1 + + 2 files changed, 14 insertions(+), 5 deletions(-) + +diff --git a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp +index 797ba28..bfb7105 100644 +--- a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp ++++ b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp +@@ -80,6 +80,7 @@ class COMXMsgAudioCodecChange : public CDVDMsg + m_send_eos = false; + m_bad_state = false; + m_hints_current.Clear(); ++ m_output_stalled = false; + + m_av_clock->SetMasterClock(false); + +@@ -169,6 +170,7 @@ void OMXPlayerAudio::OpenStream(CDVDStreamInfo &hints, COMXAudioCodecOMX *codec) + m_use_passthrough = (g_guiSettings.GetInt("audiooutput.mode") == AUDIO_HDMI) ? true : false ; + m_use_hw_decode = g_advancedSettings.m_omxHWAudioDecode; + m_send_eos = false; ++ m_output_stalled = m_stalled; + } + + bool OMXPlayerAudio::CloseStream(bool bWaitForBuffers) +@@ -457,11 +459,11 @@ bool OMXPlayerAudio::Decode(DemuxPacket *pkt, bool bDropPacket) + } + + if(bDropPacket) +- m_stalled = false; ++ m_stalled = m_output_stalled = false; + + if(m_omxAudio.GetCacheTime() < 0.1 /*&& min(99,m_messageQueue.GetLevel() + MathUtils::round_int(100.0/8.0*GetCacheTime())) > 10*/) + { +- m_stalled = true; ++ m_output_stalled = true; + if(!m_av_clock->OMXAudioBuffer() && m_av_clock->HasVideo() && m_speed == DVD_PLAYSPEED_NORMAL) + { + clock_gettime(CLOCK_REALTIME, &m_starttime); +@@ -469,6 +471,9 @@ bool OMXPlayerAudio::Decode(DemuxPacket *pkt, bool bDropPacket) + } + } + ++ if (m_stalled && m_omxAudio.GetCacheTime() > 0.0) ++ m_stalled = false; ++ + // signal to our parent that we have initialized + if(m_started == false) + { +@@ -493,6 +498,7 @@ void OMXPlayerAudio::Process() + + if (ret == MSGQ_TIMEOUT) + { ++ m_stalled = true; + Sleep(10); + continue; + } +@@ -512,12 +518,13 @@ void OMXPlayerAudio::Process() + CLog::Log(LOGINFO, "Audio: dts:%.0f pts:%.0f size:%d (s:%d f:%d d:%d l:%d) s:%d %d/%d late:%d,%d", pPacket->dts, pPacket->pts, + (int)pPacket->iSize, m_started, m_flush, bPacketDrop, m_stalled, m_speed, 0, 0, (int)m_omxAudio.GetAudioRenderingLatency(), (int)m_hints_current.samplerate); + #endif ++ m_stalled = false; + if(Decode(pPacket, m_speed > DVD_PLAYSPEED_NORMAL || m_speed < 0 || bPacketDrop)) + { +- if (m_stalled && (m_omxAudio.GetCacheTime() > (AUDIO_BUFFER_SECONDS * 0.75f))) ++ if (m_output_stalled && (m_omxAudio.GetCacheTime() > (AUDIO_BUFFER_SECONDS * 0.75f))) + { + CLog::Log(LOGINFO, "COMXPlayerAudio - Switching to normal playback"); +- m_stalled = false; ++ m_stalled = m_output_stalled = false; + if(m_av_clock->HasVideo() && m_av_clock->OMXAudioBuffer()) + m_av_clock->OMXAudioBufferStop(); + } +@@ -527,7 +534,7 @@ void OMXPlayerAudio::Process() + //int iLevel = min(99,m_messageQueue.GetLevel() + MathUtils::round_int(100.0/8.0*GetCacheTime())); + if(/*iLevel < 10 &&*/ m_stalled && m_av_clock->OMXAudioBuffer() && (m_endtime.tv_sec - m_starttime.tv_sec) > 1) + { +- m_stalled = false; ++ m_stalled = m_output_stalled = false; + if(m_av_clock->HasVideo() && m_av_clock->OMXAudioBuffer()) + m_av_clock->OMXAudioBufferStop(); + } +@@ -578,6 +585,7 @@ void OMXPlayerAudio::Process() + m_av_clock->UnLock(); + m_syncclock = true; + m_stalled = true; ++ m_output_stalled = true; + m_started = false; + + if (m_pAudioCodec) +diff --git a/xbmc/cores/omxplayer/OMXPlayerAudio.h b/xbmc/cores/omxplayer/OMXPlayerAudio.h +index 7a749dd..4f04b54 100644 +--- a/xbmc/cores/omxplayer/OMXPlayerAudio.h ++++ b/xbmc/cores/omxplayer/OMXPlayerAudio.h +@@ -76,6 +76,7 @@ class OMXPlayerAudio : public CThread + + bool m_stalled; + bool m_started; ++ bool m_output_stalled; + + BitstreamStats m_audioStats; + +-- +1.8.1.5 + + +From 1accaa26e68a07f20effb9a2f6acc60a46959dfe Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 28 Mar 2013 15:18:53 +0100 +Subject: [PATCH 93/99] OMXPlayer: some caching fixes for pvr + +--- + xbmc/cores/omxplayer/OMXPlayer.cpp | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/xbmc/cores/omxplayer/OMXPlayer.cpp b/xbmc/cores/omxplayer/OMXPlayer.cpp +index 0f302ad..7e2336d 100644 +--- a/xbmc/cores/omxplayer/OMXPlayer.cpp ++++ b/xbmc/cores/omxplayer/OMXPlayer.cpp +@@ -1278,13 +1278,13 @@ void COMXPlayer::Process() + if (!IsValidStream(m_CurrentAudio) && m_player_audio.IsStalled()) CloseAudioStream(true); + if (!IsValidStream(m_CurrentVideo) && m_player_video.IsStalled()) CloseVideoStream(true); + if (!IsValidStream(m_CurrentSubtitle) && m_player_subtitle.IsStalled()) CloseSubtitleStream(true); +- if (!IsValidStream(m_CurrentTeletext)) CloseTeletextStream(true); ++// if (!IsValidStream(m_CurrentTeletext)) CloseTeletextStream(true); + + // see if we can find something better to play + if (IsBetterStream(m_CurrentAudio, pStream)) OpenAudioStream (pStream->iId, pStream->source); + if (IsBetterStream(m_CurrentVideo, pStream)) OpenVideoStream (pStream->iId, pStream->source); + if (IsBetterStream(m_CurrentSubtitle, pStream)) OpenSubtitleStream(pStream->iId, pStream->source); +- if (IsBetterStream(m_CurrentTeletext, pStream)) OpenTeletextStream(pStream->iId, pStream->source); ++// if (IsBetterStream(m_CurrentTeletext, pStream)) OpenTeletextStream(pStream->iId, pStream->source); + + if(m_change_volume) + { +@@ -2296,7 +2296,8 @@ void COMXPlayer::HandleMessages() + // 1. disable audio + // 2. skip frames and adjust their pts or the clock + m_playSpeed = speed; +- m_caching = CACHESTATE_DONE; ++ if (m_caching != CACHESTATE_PVR && m_playSpeed != DVD_PLAYSPEED_NORMAL) ++ SetCaching(CACHESTATE_DONE); + m_av_clock.SetSpeed(speed); + m_av_clock.OMXSetSpeed(speed); + m_player_audio.SetSpeed(speed); +-- +1.8.1.5 + + +From 43b8f16ccc227bbca41ce0b9c143c07f20747888 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 28 Mar 2013 20:50:59 +0100 +Subject: [PATCH 94/99] fix incorrect display of fps when dr kicks in + +--- + xbmc/Application.cpp | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp +index d2c4e53..9c4312a 100644 +--- a/xbmc/Application.cpp ++++ b/xbmc/Application.cpp +@@ -2450,13 +2450,14 @@ void CApplication::Render() + if (frameTime < singleFrameTime) + Sleep(singleFrameTime - frameTime); + } +- m_lastFrameTime = XbmcThreads::SystemClockMillis(); + + if (flip) + { + g_graphicsContext.Flip(dirtyRegions); + g_renderManager.NotifyDisplayFlip(); + } ++ ++ m_lastFrameTime = XbmcThreads::SystemClockMillis(); + CTimeUtils::UpdateFrameTime(flip); + + g_renderManager.UpdateResolution(); +-- +1.8.1.5 + + +From 77e60bd92692bdd5333f962733c4bc05cc20678c Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 4 Apr 2013 14:59:14 +0200 +Subject: [PATCH 95/99] X11: ignore EnterNotify when no WM is used + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index 2d9cf2a..398541a 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -581,7 +581,7 @@ void CWinSystemX11::NotifyAppFocusChange(bool bGaining) + + void CWinSystemX11::NotifyMouseCoverage(bool covered) + { +- if (!m_bFullScreen) ++ if (!m_bFullScreen || !HasWindowManager()) + return; + + if (covered) +-- +1.8.1.5 + + +From bf7d549ddab233da6d34511696638f31025c4fe0 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 18 Mar 2013 19:21:58 +0100 +Subject: [PATCH 96/99] mpegts: update AVProgram after pmt change + +--- + lib/ffmpeg/libavformat/mpegts.c | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/lib/ffmpeg/libavformat/mpegts.c b/lib/ffmpeg/libavformat/mpegts.c +index 6da6db5..ba0051a 100644 +--- a/lib/ffmpeg/libavformat/mpegts.c ++++ b/lib/ffmpeg/libavformat/mpegts.c +@@ -183,10 +183,25 @@ enum MpegTSState { + + extern AVInputFormat ff_mpegts_demuxer; + ++static void clear_avprogram(MpegTSContext *ts, unsigned int programid) ++{ ++ AVProgram *prg = NULL; ++ int i; ++ for(i=0; istream->nb_programs; i++) ++ if(ts->stream->programs[i]->id == programid){ ++ prg = ts->stream->programs[i]; ++ break; ++ } ++ if (!prg) ++ return; ++ prg->nb_stream_indexes = 0; ++} ++ + static void clear_program(MpegTSContext *ts, unsigned int programid) + { + int i; + ++ clear_avprogram(ts, programid); + for(i=0; inb_prg; i++) + if(ts->prg[i].id == programid) + ts->prg[i].nb_pids = 0; +@@ -194,6 +209,9 @@ static void clear_program(MpegTSContext *ts, unsigned int programid) + + static void clear_programs(MpegTSContext *ts) + { ++ int i; ++ for(i=0; inb_prg; i++) ++ clear_avprogram(ts, ts->prg[i].id); + av_freep(&ts->prg); + ts->nb_prg=0; + } +-- +1.8.1.5 + + +From 306e4677c82460e3506e0d8083aed9539834d379 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 18 Mar 2013 19:22:49 +0100 +Subject: [PATCH 97/99] mpegts: clear avprograms only for removed programs + +--- + lib/ffmpeg/libavformat/mpegts.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +diff --git a/lib/ffmpeg/libavformat/mpegts.c b/lib/ffmpeg/libavformat/mpegts.c +index ba0051a..f459c3a 100644 +--- a/lib/ffmpeg/libavformat/mpegts.c ++++ b/lib/ffmpeg/libavformat/mpegts.c +@@ -209,9 +209,6 @@ static void clear_program(MpegTSContext *ts, unsigned int programid) + + static void clear_programs(MpegTSContext *ts) + { +- int i; +- for(i=0; inb_prg; i++) +- clear_avprogram(ts, ts->prg[i].id); + av_freep(&ts->prg); + ts->nb_prg=0; + } +@@ -1616,6 +1613,17 @@ static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len + add_pid_to_pmt(ts, sid, pmt_pid); + } + } ++ ++ if (sid < 0) { ++ int i,j; ++ for (j=0; jstream->nb_programs; j++) { ++ for (i=0; inb_prg; i++) ++ if (ts->prg[i].id == ts->stream->programs[j]->id) ++ break; ++ if (i==ts->nb_prg) ++ clear_avprogram(ts, ts->stream->programs[j]->id); ++ } ++ } + } + + static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len) +-- +1.8.1.5 + + +From 2c252500aff03a5fd1c976581e5162d416b73240 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Tue, 13 Nov 2012 14:04:49 +0100 +Subject: [PATCH 98/99] demuxer ffmpeg: handle pmt changes + +--- + .../cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp | 117 ++++++++++++++++++--- + xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h | 12 +++ + 2 files changed, 112 insertions(+), 17 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +index b11de52..c5d956c 100644 +--- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp ++++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +@@ -213,6 +213,7 @@ static offset_t dvd_file_seek(void *h, offset_t pos, int whence) + m_bAVI = false; + m_speed = DVD_PLAYSPEED_NORMAL; + m_program = UINT_MAX; ++ m_AVPacket.result = -1; + } + + CDVDDemuxFFmpeg::~CDVDDemuxFFmpeg() +@@ -488,19 +489,10 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput) + if(i != m_program) + m_pFormatContext->programs[i]->discard = AVDISCARD_ALL; + } +- if(m_program != UINT_MAX) +- { +- // add streams from selected program +- for (unsigned int i = 0; i < m_pFormatContext->programs[m_program]->nb_stream_indexes; i++) +- AddStream(m_pFormatContext->programs[m_program]->stream_index[i]); +- } +- } +- // if there were no programs or they were all empty, add all streams +- if (m_program == UINT_MAX) +- { +- for (unsigned int i = 0; i < m_pFormatContext->nb_streams; i++) +- AddStream(i); + } ++ // add all streams, don't allow gaps in m_streams ++ for (unsigned int i = 0; i < m_pFormatContext->nb_streams; i++) ++ AddStream(i); + + m_bPtsWrapChecked = false; + m_bPtsWrap = false; +@@ -510,6 +502,12 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput) + + void CDVDDemuxFFmpeg::Dispose() + { ++ if(m_AVPacket.result >= 0) ++ { ++ m_dllAvCodec.av_free_packet(&m_AVPacket.packet); ++ m_AVPacket.result = -1; ++ } ++ + if (m_pFormatContext) + { + if (m_ioContext && m_pFormatContext->pb && m_pFormatContext->pb != m_ioContext) +@@ -653,10 +651,33 @@ DemuxPacket* CDVDDemuxFFmpeg::Read() + pkt.data = NULL; + pkt.stream_index = MAX_STREAMS; + +- // timeout reads after 100ms +- m_timeout.Set(20000); +- int result = m_dllAvFormat.av_read_frame(m_pFormatContext, &pkt); +- m_timeout.SetInfinite(); ++ int result = -1; ++ // check for saved packet after a program change ++ if(m_AVPacket.result >= 0) ++ { ++ // in case we did not move by seek or demuxer was flushed, ++ // take the packet of last read ++ if(m_AVPacket.pts == m_iCurrentPts) ++ { ++ pkt = m_AVPacket.packet; ++ result = m_AVPacket.result; ++ m_AVPacket.result = -1; ++ } ++ else ++ { ++ m_dllAvCodec.av_free_packet(&m_AVPacket.packet); ++ m_AVPacket.result = -1; ++ result = -1; ++ } ++ } ++ ++ if (result == -1) ++ { ++ // timeout reads after 100ms ++ m_timeout.Set(20000); ++ result = m_dllAvFormat.av_read_frame(m_pFormatContext, &pkt); ++ m_timeout.SetInfinite(); ++ } + + if (result == AVERROR(EINTR) || result == AVERROR(EAGAIN)) + { +@@ -667,6 +688,22 @@ DemuxPacket* CDVDDemuxFFmpeg::Read() + { + Flush(); + } ++ else if (IsProgramChange()) ++ { ++ // update streams ++ for (unsigned int i = 0; i < m_pFormatContext->nb_streams; i++) ++ AddStream(i); ++ ++ // save packet for next read ++ m_AVPacket.packet = pkt; ++ m_AVPacket.result = result; ++ m_AVPacket.pts = m_iCurrentPts; ++ ++ pPacket = CDVDDemuxUtils::AllocateDemuxPacket(0); ++ pPacket->iStreamId = DMX_SPECIALID_STREAMCHANGE; ++ ++ return pPacket; ++ } + else if (pkt.size < 0 || pkt.stream_index >= MAX_STREAMS) + { + // XXX, in some cases ffmpeg returns a negative packet size +@@ -803,12 +840,17 @@ DemuxPacket* CDVDDemuxFFmpeg::Read() + // check streams, can we make this a bit more simple? + if (pPacket && pPacket->iStreamId >= 0 && pPacket->iStreamId < MAX_STREAMS) + { +- if (!m_streams[pPacket->iStreamId] || ++ if (!IsActiveStream(pPacket->iStreamId)) ++ { ++ CLog::Log(LOGDEBUG,"CDVDDemuxFFmpeg::Read - got packet of inactive stream"); ++ } ++ else if (!m_streams[pPacket->iStreamId] || + m_streams[pPacket->iStreamId]->pPrivate != m_pFormatContext->streams[pPacket->iStreamId] || + m_streams[pPacket->iStreamId]->codec != m_pFormatContext->streams[pPacket->iStreamId]->codec->codec_id) + { + // content has changed, or stream did not yet exist + AddStream(pPacket->iStreamId); ++ m_streams[pPacket->iStreamId]->changes++; + } + // we already check for a valid m_streams[pPacket->iStreamId] above + else if (m_streams[pPacket->iStreamId]->type == STREAM_AUDIO) +@@ -818,6 +860,7 @@ DemuxPacket* CDVDDemuxFFmpeg::Read() + { + // content has changed + AddStream(pPacket->iStreamId); ++ m_streams[pPacket->iStreamId]->changes++; + } + } + else if (m_streams[pPacket->iStreamId]->type == STREAM_VIDEO) +@@ -827,6 +870,7 @@ DemuxPacket* CDVDDemuxFFmpeg::Read() + { + // content has changed + AddStream(pPacket->iStreamId); ++ m_streams[pPacket->iStreamId]->changes++; + } + } + } +@@ -1359,6 +1403,11 @@ void CDVDDemuxFFmpeg::AddStream(int iId) + else + m_streams[iId]->iPhysicalId = pStream->id; + } ++ if (!IsActiveStream(iId)) ++ { ++ m_streams[iId]->type = STREAM_NONE; ++ m_streams[iId]->codec = CODEC_ID_NONE; ++ } + } + + std::string CDVDDemuxFFmpeg::GetFileName() +@@ -1516,3 +1565,37 @@ void CDVDDemuxFFmpeg::GetStreamCodecName(int iStreamId, CStdString &strName) + strName = codec->name; + } + } ++ ++bool CDVDDemuxFFmpeg::IsActiveStream(int idx) ++{ ++ if (m_program == UINT_MAX) ++ return true; ++ ++ for (unsigned int i = 0; i < m_pFormatContext->programs[m_program]->nb_stream_indexes; i++) ++ { ++ if (idx == m_pFormatContext->programs[m_program]->stream_index[i] && ++ m_pFormatContext->streams[idx]->codec->codec_type != AVMEDIA_TYPE_UNKNOWN) ++ return true; ++ } ++ ++ return false; ++} ++ ++bool CDVDDemuxFFmpeg::IsProgramChange() ++{ ++ if (m_program == UINT_MAX) ++ return false; ++ ++ bool change(false); ++ int noOfStreams = GetNrOfStreams(); ++ for (int i = 0; i < noOfStreams; i++) ++ { ++ if ((m_streams[i]->type == STREAM_NONE && IsActiveStream(i)) || ++ (m_streams[i]->type != STREAM_NONE && !IsActiveStream(i))) ++ change = true; ++ } ++ if (noOfStreams != m_pFormatContext->nb_streams) ++ change = true; ++ ++ return change; ++} +diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h +index 8a7a5de..154a134 100644 +--- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h ++++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h +@@ -124,6 +124,8 @@ class CDVDDemuxFFmpeg : public CDVDDemux + + double ConvertTimestamp(int64_t pts, int den, int num); + void UpdateCurrentPTS(); ++ bool IsActiveStream(int idx); ++ bool IsProgramChange(); + + CCriticalSection m_critSection; + #define MAX_STREAMS 100 +@@ -144,5 +146,15 @@ class CDVDDemuxFFmpeg : public CDVDDemux + + bool m_bPtsWrap, m_bPtsWrapChecked; + int64_t m_iStartTime, m_iMaxTime, m_iEndTime; ++ ++ // Due to limitations of ffmpeg, we only can detect a program change ++ // with a packet. This struct saves the packet for the next read and ++ // signals STREAMCHANGE to player ++ struct ++ { ++ AVPacket packet; // packet ffmpeg returned ++ int result; // result from av_read_packet ++ double pts; // our current pts at the time we got the packet ++ }m_AVPacket; + }; + +-- +1.8.1.5 + + +From 028576f258d6fb89a1826d3c4b949b5017760383 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 8 Apr 2013 11:18:31 +0200 +Subject: [PATCH 99/99] squash to dropping control + +--- + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +index cc3f0de..576604b 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -40,6 +40,7 @@ + #include "DVDCodecs/DVDCodecs.h" + #include "DVDCodecs/Overlay/DVDOverlayCodecCC.h" + #include "DVDCodecs/Overlay/DVDOverlaySSA.h" ++#include "guilib/GraphicContext.h" + #include + #include + #include +-- +1.8.1.5 + diff --git a/packages/mediacenter/xbmc/patches/8ad691a/xbmc-995.10-disable-alt-tab.patch b/packages/mediacenter/xbmc/patches/8ad691a/xbmc-995.10-disable-alt-tab.patch new file mode 100644 index 0000000000..2ee2b7a271 --- /dev/null +++ b/packages/mediacenter/xbmc/patches/8ad691a/xbmc-995.10-disable-alt-tab.patch @@ -0,0 +1,12 @@ +diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp +index ed31c04..34fcfae 100644 +--- a/xbmc/windowing/WinEventsX11.cpp ++++ b/xbmc/windowing/WinEventsX11.cpp +@@ -709,7 +709,6 @@ bool CWinEventsX11::ProcessShortcuts(XBMC_Event& event) + switch(event.key.keysym.sym) + { + case XBMCK_TAB: // ALT+TAB to minimize/hide +- g_application.Minimize(); + return true; + + default: diff --git a/packages/mediacenter/xbmc/patches/8ad691a/xbmc-999.01-automake-1.13.patch b/packages/mediacenter/xbmc/patches/8ad691a/xbmc-999.01-automake-1.13.patch new file mode 100644 index 0000000000..a4703491b5 --- /dev/null +++ b/packages/mediacenter/xbmc/patches/8ad691a/xbmc-999.01-automake-1.13.patch @@ -0,0 +1,12 @@ +diff -Naur xbmc-8ad691a/lib/libdvd/libdvdcss/configure.ac xbmc-8ad691a.patch/lib/libdvd/libdvdcss/configure.ac +--- xbmc-8ad691a/lib/libdvd/libdvdcss/configure.ac 2013-04-08 12:03:51.000000000 +0200 ++++ xbmc-8ad691a.patch/lib/libdvd/libdvdcss/configure.ac 2013-04-08 14:20:14.793113682 +0200 +@@ -5,7 +5,7 @@ + AC_CANONICAL_SYSTEM + + AM_INIT_AUTOMAKE(libdvdcss, 1.2.12) +-AM_CONFIG_HEADER(config.h) ++AC_CONFIG_HEADERS(config.h) + + AC_PROG_CC + AC_STDC_HEADERS diff --git a/tools/mkpkg/mkpkg_xbmc-gotham b/tools/mkpkg/mkpkg_xbmc-gotham new file mode 100755 index 0000000000..faf3682ec5 --- /dev/null +++ b/tools/mkpkg/mkpkg_xbmc-gotham @@ -0,0 +1,81 @@ +#!/bin/sh +################################################################################ +# This file is part of OpenELEC - http://www.openelec.tv +# Copyright (C) 2009-2012 Stephan Raue (stephan@openelec.tv) +# +# 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 OpenELEC.tv; see the file COPYING. If not, write to +# the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110, USA. +# http://www.gnu.org/copyleft/gpl.html +################################################################################ + +PKG_NAME="xbmc" +PKG_VERSION="" +GIT_REPO="-b master git://github.com/xbmc/xbmc.git" +DEST_DIR="$PKG_NAME-gotham" + +echo "getting sources..." + if [ ! -d $DEST_DIR-latest ]; then + git clone $GIT_REPO $DEST_DIR-latest + fi + + cd $DEST_DIR-latest + git pull + + echo "getting version..." + GIT_REV=`git log -n1 --format=%h` + echo $GIT_REV + cd .. + + if [ -z "$PKG_VERSION" ]; then + PKG_VERSION="$GIT_REV" + fi + +echo "copying sources..." + rm -rf $PKG_NAME-$PKG_VERSION + cp -R $DEST_DIR-latest $PKG_NAME-$PKG_VERSION + echo "$GIT_REV" > $PKG_NAME-$PKG_VERSION/VERSION + +echo "cleaning sources..." + rm -rf $PKG_NAME-$PKG_VERSION/.git + +echo "seperating theme..." + rm -rf $PKG_NAME-theme-Confluence-$PKG_VERSION + mv $PKG_NAME-$PKG_VERSION/addons/skin.confluence $PKG_NAME-theme-Confluence-$PKG_VERSION + +echo "cleaning sources..." + rm -rf $PKG_NAME-$PKG_VERSION/visualisations + rm -rf $PKG_NAME-$PKG_VERSION/lib/libSDL-* + rm -rf $PKG_NAME-$PKG_VERSION/lib/libcurl-* + rm -rf $PKG_NAME-$PKG_VERSION/project + + for i in "Changelog" "Fake\ Episode\ Maker" "MingwBuildEnvironment" \ + "PackageMaker" "Translator" "XBMCLive" "XprPack" \ + "HardwareConfigure" "Mach5" "osx" "UpdateThumbs.py" "XBMCTex"; do + rm -rf $PKG_NAME-$PKG_VERSION/tools/$i + done + + for i in dll a lib so bat; do + find $PKG_NAME-$PKG_VERSION -name *.$i -exec rm -rf {} ";" + done + + # bundled win32 binaries + rm -r $PKG_NAME-$PKG_VERSION/xbmc/visualizations/XBMCProjectM/win32 + +echo "packing sources..." + tar cvJf $PKG_NAME-$PKG_VERSION.tar.xz $PKG_NAME-$PKG_VERSION + tar cvJf $PKG_NAME-theme-Confluence-$PKG_VERSION.tar.xz $PKG_NAME-theme-Confluence-$PKG_VERSION + +echo "remove temporary sourcedir..." + rm -rf $PKG_NAME-$PKG_VERSION + rm -rf $PKG_NAME-theme-Confluence-$PKG_VERSION