From 5fbfde4edcd9d852f2a2d7de1cb09f388ddd393d Mon Sep 17 00:00:00 2001
From: wsnipex <wsnipex@a1.net>
Date: Sun, 4 Nov 2012 14:05:52 +0100
Subject: [PATCH 01/58] 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 beb58c1..82f457a 100644
--- a/configure.in
+++ b/configure.in
@@ -521,6 +521,14 @@ AC_ARG_ENABLE([external-ffmpeg],
   [use_external_ffmpeg=$use_external_libraries])
 
 ### End of external library options
+### PVR addons specific
+AC_ARG_ENABLE([pvraddons-with-dependencies],
+  [AS_HELP_STRING([--enable-pvraddons-with-dependencies],
+  [enable build of pvr addons with dependencies (default is no) 'Linux only'])],
+  [use_pvraddons_with_deps=$enableval],
+  [use_pvraddons_with_deps=no])
+
+### End PVR addons specific
 
 if test "x$host_vendor" != "xapple"; then
   DEFAULT_COMPILE_FLAGS="-fPIC -DPIC -D_REENTRANT"
@@ -2766,12 +2774,16 @@ XB_CONFIG_MODULE([pvr-addons], [
    if test "$USE_EXTERNAL_FFMPEG" = 1; then
       PVR_EXT_FFMPEG="--enable-external-ffmpeg"
    fi
+   if test "$use_pvraddons_with_deps" = "yes"; then
+      ADDONS_WITH_DEPS="--enable-addons-with-dependencies"
+   fi
   ./configure \
     --prefix="${prefix}" \
     --host=$host_alias \
     --build=$build_alias \
     --target=$target_alias \
     $PVR_EXT_FFMPEG \
+    $ADDONS_WITH_DEPS \
     CC="$CC" \
     CXX="$CXX" \
     CFLAGS="$CFLAGS" \
-- 
1.7.10


From 58b1544f23706cd4097442d43fd9f40e17dd1315 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Mon, 28 May 2012 10:03:31 +0200
Subject: [PATCH 02/58] VideoRenerers: add buffering

---
 xbmc/Application.cpp                            |    3 +
 xbmc/cores/VideoRenderers/BaseRenderer.h        |    5 +-
 xbmc/cores/VideoRenderers/LinuxRendererGL.cpp   |   41 ++--
 xbmc/cores/VideoRenderers/LinuxRendererGL.h     |   13 +-
 xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp |    8 +-
 xbmc/cores/VideoRenderers/LinuxRendererGLES.h   |    4 +-
 xbmc/cores/VideoRenderers/OverlayRenderer.cpp   |   19 +-
 xbmc/cores/VideoRenderers/OverlayRenderer.h     |    6 +-
 xbmc/cores/VideoRenderers/RenderManager.cpp     |  296 +++++++++++++++++++----
 xbmc/cores/VideoRenderers/RenderManager.h       |   48 +++-
 xbmc/cores/VideoRenderers/WinRenderer.cpp       |    8 +-
 xbmc/cores/VideoRenderers/WinRenderer.h         |    2 +-
 xbmc/cores/dvdplayer/DVDPlayer.cpp              |    2 +-
 xbmc/cores/dvdplayer/DVDPlayerVideo.cpp         |   18 +-
 14 files changed, 380 insertions(+), 93 deletions(-)

diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp
index ef18568..f85aaac 100644
--- a/xbmc/Application.cpp
+++ b/xbmc/Application.cpp
@@ -2345,7 +2345,10 @@ void CApplication::Render()
   m_lastFrameTime = XbmcThreads::SystemClockMillis();
 
   if (flip)
+  {
     g_graphicsContext.Flip(dirtyRegions);
+    g_renderManager.NotifyDisplayFlip();
+  }
   CTimeUtils::UpdateFrameTime(flip);
 
   g_TextureManager.FreeUnusedTextures();
diff --git a/xbmc/cores/VideoRenderers/BaseRenderer.h b/xbmc/cores/VideoRenderers/BaseRenderer.h
index 81d21d8..b02d536 100644
--- a/xbmc/cores/VideoRenderers/BaseRenderer.h
+++ b/xbmc/cores/VideoRenderers/BaseRenderer.h
@@ -80,10 +80,13 @@ class CBaseRenderer
   void GetVideoRect(CRect &source, CRect &dest);
   float GetAspectRatio() const;
 
-  virtual bool AddVideoPicture(DVDVideoPicture* picture) { return false; }
+  virtual bool AddVideoPicture(DVDVideoPicture* picture, int index) { return false; }
   virtual void Flush() {};
 
   virtual unsigned int GetProcessorSize() { return 0; }
+  virtual unsigned int GetMaxProcessorSize() { return 0; }
+  virtual void SetProcessorSize(int numBuffers) { }
+  virtual void ReleaseBuffer(int idx) { }
 
   virtual bool Supports(ERENDERFEATURE feature) { return false; }
 
diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
index 77b7495..a740954 100644
--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
@@ -235,14 +235,6 @@ bool CLinuxRendererGL::ValidateRenderer()
   return true;
 }
 
-
-void CLinuxRendererGL::ManageTextures()
-{
-  m_NumYV12Buffers = 2;
-  //m_iYV12RenderBuffer = 0;
-  return;
-}
-
 bool CLinuxRendererGL::ValidateRenderTarget()
 {
   if (!m_bValidated)
@@ -603,13 +595,28 @@ void CLinuxRendererGL::Flush()
   glFinish();
   m_bValidated = false;
   m_fbo.fbo.Cleanup();
+  m_iYV12RenderBuffer = 0;
+}
+
+void CLinuxRendererGL::ReleaseBuffer(int idx)
+{
+  YUVBUFFER &buf = m_buffers[idx];
+#ifdef HAVE_LIBVDPAU
+  SAFE_RELEASE(buf.vdpau);
+#endif
+#ifdef HAVE_LIBVA
+  buf.vaapi.surface.reset();
+#endif
+#ifdef TARGET_DARWIN
+  if (buf.cvBufferRef)
+    CVBufferRelease(buf.cvBufferRef);
+#endif
 }
 
 void CLinuxRendererGL::Update(bool bPauseDrawing)
 {
   if (!m_bConfigured) return;
   ManageDisplay();
-  ManageTextures();
 }
 
 void CLinuxRendererGL::RenderUpdate(bool clear, DWORD flags, DWORD alpha)
@@ -625,7 +632,6 @@ void CLinuxRendererGL::RenderUpdate(bool clear, DWORD flags, DWORD alpha)
   }
 
   ManageDisplay();
-  ManageTextures();
 
   g_graphicsContext.BeginPaint();
 
@@ -782,7 +788,6 @@ unsigned int CLinuxRendererGL::PreInit()
     m_resolution = RES_DESKTOP;
 
   m_iYV12RenderBuffer = 0;
-  m_NumYV12Buffers = 2;
 
   m_formats.push_back(RENDER_FMT_YUV420P);
   GLint size;
@@ -2465,7 +2470,7 @@ void CLinuxRendererGL::UploadVAAPITexture(int index)
   || status == VA_STATUS_ERROR_INVALID_DISPLAY)
   {
     va.display->lost(true);
-    for(int i = 0; i < NUM_BUFFERS; i++)
+    for(int i = 0; i < m_NumYV12Buffers; i++)
     {
       m_buffers[i].vaapi.display.reset();
       m_buffers[i].vaapi.surface.reset();
@@ -3417,26 +3422,26 @@ void CLinuxRendererGL::UnBindPbo(YUVBUFFER& buff)
 }
 
 #ifdef HAVE_LIBVDPAU
-void CLinuxRendererGL::AddProcessor(CVDPAU* vdpau)
+void CLinuxRendererGL::AddProcessor(CVDPAU* vdpau, int index)
 {
-  YUVBUFFER &buf = m_buffers[NextYV12Texture()];
+  YUVBUFFER &buf = m_buffers[index];
   SAFE_RELEASE(buf.vdpau);
   buf.vdpau = (CVDPAU*)vdpau->Acquire();
 }
 #endif
 
 #ifdef HAVE_LIBVA
-void CLinuxRendererGL::AddProcessor(VAAPI::CHolder& holder)
+void CLinuxRendererGL::AddProcessor(VAAPI::CHolder& holder, int index)
 {
-  YUVBUFFER &buf = m_buffers[NextYV12Texture()];
+  YUVBUFFER &buf = m_buffers[index];
   buf.vaapi.surface = holder.surface;
 }
 #endif
 
 #ifdef TARGET_DARWIN
-void CLinuxRendererGL::AddProcessor(struct __CVBuffer *cvBufferRef)
+void CLinuxRendererGL::AddProcessor(struct __CVBuffer *cvBufferRef, int index)
 {
-  YUVBUFFER &buf = m_buffers[NextYV12Texture()];
+  YUVBUFFER &buf = m_buffers[index];
   if (buf.cvBufferRef)
     CVBufferRelease(buf.cvBufferRef);
   buf.cvBufferRef = cvBufferRef;
diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.h b/xbmc/cores/VideoRenderers/LinuxRendererGL.h
index acebfe0..9f55fcb 100644
--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.h
+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.h
@@ -44,7 +44,7 @@
 namespace Shaders { class BaseVideoFilterShader; }
 namespace VAAPI   { struct CHolder; }
 
-#define NUM_BUFFERS 3
+#define NUM_BUFFERS 10
 
 
 #undef ALIGN
@@ -138,15 +138,19 @@ class CLinuxRendererGL : public CBaseRenderer
   virtual void         UnInit();
   virtual void         Reset(); /* resets renderer after seek for example */
   virtual void         Flush();
+  virtual void         ReleaseBuffer(int idx);
+  virtual void         SetProcessorSize(int numBuffers) { m_NumYV12Buffers = numBuffers; }
+  virtual unsigned int GetMaxProcessorSize() { return NUM_BUFFERS; }
+  virtual unsigned int GetProcessorSize() { return m_NumYV12Buffers; }
 
 #ifdef HAVE_LIBVDPAU
-  virtual void         AddProcessor(CVDPAU* vdpau);
+  virtual void         AddProcessor(CVDPAU* vdpau, int index);
 #endif
 #ifdef HAVE_LIBVA
-  virtual void         AddProcessor(VAAPI::CHolder& holder);
+  virtual void         AddProcessor(VAAPI::CHolder& holder, int index);
 #endif
 #ifdef TARGET_DARWIN
-  virtual void         AddProcessor(struct __CVBuffer *cvBufferRef);
+  virtual void         AddProcessor(struct __CVBuffer *cvBufferRef, int index);
 #endif
 
   virtual void RenderUpdate(bool clear, DWORD flags = 0, DWORD alpha = 255);
@@ -168,7 +172,6 @@ class CLinuxRendererGL : public CBaseRenderer
   void         DrawBlackBars();
 
   bool ValidateRenderer();
-  virtual void ManageTextures();
   int  NextYV12Texture();
   virtual bool ValidateRenderTarget();
   virtual void LoadShaders(int field=FIELD_FULL);
diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
index 0630f13..e832adc 100644
--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
+++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
@@ -1966,16 +1966,16 @@ EINTERLACEMETHOD CLinuxRendererGLES::AutoInterlaceMethod()
 }
 
 #ifdef HAVE_LIBOPENMAX
-void CLinuxRendererGLES::AddProcessor(COpenMax* openMax, DVDVideoPicture *picture)
+void CLinuxRendererGLES::AddProcessor(COpenMax* openMax, DVDVideoPicture *picture, int index)
 {
-  YUVBUFFER &buf = m_buffers[NextYV12Texture()];
+  YUVBUFFER &buf = m_buffers[index];
   buf.openMaxBuffer = picture->openMaxBuffer;
 }
 #endif
 #ifdef HAVE_VIDEOTOOLBOXDECODER
-void CLinuxRendererGLES::AddProcessor(struct __CVBuffer *cvBufferRef)
+void CLinuxRendererGLES::AddProcessor(struct __CVBuffer *cvBufferRef, int index)
 {
-  YUVBUFFER &buf = m_buffers[NextYV12Texture()];
+  YUVBUFFER &buf = m_buffers[index];
   if (buf.cvBufferRef)
     CVBufferRelease(buf.cvBufferRef);
   buf.cvBufferRef = cvBufferRef;
diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h
index 76b5437..c6b69db 100644
--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h
+++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h
@@ -153,10 +153,10 @@ class CLinuxRendererGLES : public CBaseRenderer
   virtual std::vector<ERenderFormat> SupportedFormats() { return m_formats; }
 
 #ifdef HAVE_LIBOPENMAX
-  virtual void         AddProcessor(COpenMax* openMax, DVDVideoPicture *picture);
+  virtual void         AddProcessor(COpenMax* openMax, DVDVideoPicture *picture, int index);
 #endif
 #ifdef HAVE_VIDEOTOOLBOXDECODER
-  virtual void         AddProcessor(struct __CVBuffer *cvBufferRef);
+  virtual void         AddProcessor(struct __CVBuffer *cvBufferRef, int index);
 #endif
 
 protected:
diff --git a/xbmc/cores/VideoRenderers/OverlayRenderer.cpp b/xbmc/cores/VideoRenderers/OverlayRenderer.cpp
index 19d2d7d..94aaaf5 100644
--- a/xbmc/cores/VideoRenderers/OverlayRenderer.cpp
+++ b/xbmc/cores/VideoRenderers/OverlayRenderer.cpp
@@ -89,7 +89,6 @@ long COverlayMainThread::Release()
 CRenderer::CRenderer()
 {
   m_render = 0;
-  m_decode = (m_render + 1) % 2;
 }
 
 CRenderer::~CRenderer()
@@ -151,20 +150,30 @@ void CRenderer::Flush()
 {
   CSingleLock lock(m_section);
 
-  for(int i = 0; i < 2; i++)
+  for(int i = 0; i < m_iNumBuffers; i++)
     Release(m_buffers[i]);
 
+  m_render = 0;
   Release(m_cleanup);
 }
 
 void CRenderer::Flip()
 {
   CSingleLock lock(m_section);
+  m_render = (m_render + 1) % m_iNumBuffers;
+}
 
-  m_render = m_decode;
-  m_decode =(m_decode + 1) % 2;
+void CRenderer::SetBuffer(int idx)
+{
+  CSingleLock lock(m_section);
+  Release(m_buffers[idx]);
+  m_decode = idx;
+}
 
-  Release(m_buffers[m_decode]);
+void CRenderer::ReleaseBuffer(int idx)
+{
+  CSingleLock lock(m_section);
+  Release(m_buffers[idx]);
 }
 
 void CRenderer::Render()
diff --git a/xbmc/cores/VideoRenderers/OverlayRenderer.h b/xbmc/cores/VideoRenderers/OverlayRenderer.h
index d2175d8..c6740a5 100644
--- a/xbmc/cores/VideoRenderers/OverlayRenderer.h
+++ b/xbmc/cores/VideoRenderers/OverlayRenderer.h
@@ -98,6 +98,9 @@
     void Flip();
     void Render();
     void Flush();
+    void SetNumBuffers(int numBuffers) { m_iNumBuffers = numBuffers; }
+    void SetBuffer(int idx);
+    void ReleaseBuffer(int idx);
 
   protected:
 
@@ -124,7 +127,8 @@
     void      Release(SElementV& list);
 
     CCriticalSection m_section;
-    SElementV        m_buffers[2];
+    SElementV        m_buffers[10];
+    int              m_iNumBuffers;
     int              m_decode;
     int              m_render;
 
diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp
index d22287d..eeb6c6f 100644
--- a/xbmc/cores/VideoRenderers/RenderManager.cpp
+++ b/xbmc/cores/VideoRenderers/RenderManager.cpp
@@ -28,6 +28,7 @@
 #include "utils/MathUtils.h"
 #include "threads/SingleLock.h"
 #include "utils/log.h"
+#include "utils/TimeUtils.h"
 
 #include "Application.h"
 #include "ApplicationMessenger.h"
@@ -247,6 +248,11 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi
     return false;
   }
 
+  // check if decoder supports buffering
+  m_bCodecSupportsBuffering = false;
+//  if (format == RENDER_FMT_VDPAU)
+//    m_bCodecSupportsBuffering = true;
+
   bool result = m_pRenderer->Configure(width, height, d_width, d_height, fps, flags, format, extended_format, orientation);
   if(result)
   {
@@ -261,6 +267,7 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi
     m_bReconfigured = true;
     m_presentstep = PRESENT_IDLE;
     m_presentevent.Set();
+    ResetRenderBuffer();
   }
 
   return result;
@@ -292,8 +299,12 @@ void CXBMCRenderManager::RenderUpdate(bool clear, DWORD flags, DWORD alpha)
     if (!m_pRenderer)
       return;
 
+    if (m_presentstep == PRESENT_IDLE)
+      PrepareNextRender();
+
     if(m_presentstep == PRESENT_FLIP)
     {
+      FlipRenderBuffer();
       m_overlays.Flip();
       m_pRenderer->FlipPage(m_presentsource);
       m_presentstep = PRESENT_FRAME;
@@ -312,7 +323,7 @@ void CXBMCRenderManager::RenderUpdate(bool clear, DWORD flags, DWORD alpha)
   m_presentevent.Set();
 }
 
-unsigned int CXBMCRenderManager::PreInit()
+unsigned int CXBMCRenderManager::PreInit(CDVDClock *pClock)
 {
   CRetakeLock<CExclusiveLock> lock(m_sharedSection);
 
@@ -320,6 +331,7 @@ unsigned int CXBMCRenderManager::PreInit()
   m_presenterr  = 0.0;
   m_errorindex  = 0;
   memset(m_errorbuff, 0, sizeof(m_errorbuff));
+  m_pClock = pClock;
 
   m_bIsStarted = false;
   m_bPauseDrawing = false;
@@ -338,6 +350,10 @@ unsigned int CXBMCRenderManager::PreInit()
 
   UpdateDisplayLatency();
 
+  m_bUseBuffering = false;
+  m_bCodecSupportsBuffering = true;
+  ResetRenderBuffer();
+
   return m_pRenderer->PreInit();
 }
 
@@ -366,7 +382,9 @@ bool CXBMCRenderManager::Flush()
 
     CRetakeLock<CExclusiveLock> lock(m_sharedSection);
     m_pRenderer->Flush();
+    m_overlays.Flush();
     m_flushEvent.Set();
+    ResetRenderBuffer();
   }
   else
   {
@@ -534,25 +552,21 @@ void CXBMCRenderManager::SetViewMode(int iViewMode)
     m_pRenderer->SetViewMode(iViewMode);
 }
 
-void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0LL*/, int source /*= -1*/, EFIELDSYNC sync /*= FS_NONE*/)
+void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0LL*/, int source /*= -1*/, EFIELDSYNC sync /*= FS_NONE*/, int speed /*= 0*/)
 {
-  if(timestamp - GetPresentTime() > MAXPRESENTDELAY)
-    timestamp =  GetPresentTime() + MAXPRESENTDELAY;
-
-  /* can't flip, untill timestamp */
-  if(!g_graphicsContext.IsFullScreenVideo())
-    WaitPresentTime(timestamp);
-
-  /* make sure any queued frame was fully presented */
-  double timeout = m_presenttime + 1.0;
-  while(m_presentstep != PRESENT_IDLE && !bStop)
+  if (!m_bUseBuffering)
   {
-    if(!m_presentevent.WaitMSec(100) && GetPresentTime() > timeout && !bStop)
+    /* make sure any queued frame was fully presented */
+    double timeout = m_presenttime + 1.0;
+    while(m_presentstep != PRESENT_IDLE && !bStop)
     {
-      CLog::Log(LOGWARNING, "CRenderManager::FlipPage - timeout waiting for previous frame");
-      return;
+      if(!m_presentevent.WaitMSec(100) && GetPresentTime() > timeout && !bStop)
+      {
+        CLog::Log(LOGWARNING, "CRenderManager::FlipPage - timeout waiting for previous frame");
+        return;
+      }
     }
-  };
+  }
 
   if(bStop)
     return;
@@ -560,58 +574,67 @@ void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0L
   { CRetakeLock<CExclusiveLock> lock(m_sharedSection);
     if(!m_pRenderer) return;
 
-    m_presenttime  = timestamp;
-    m_presentfield = sync;
-    m_presentstep  = PRESENT_FLIP;
-    m_presentsource = source;
+    double presenttime  = timestamp;
+    EFIELDSYNC presentfield = sync;
+    EPRESENTMETHOD presentmethod;
+
     EDEINTERLACEMODE deinterlacemode = g_settings.m_currentVideoSettings.m_DeinterlaceMode;
     EINTERLACEMETHOD interlacemethod = AutoInterlaceMethodInternal(g_settings.m_currentVideoSettings.m_InterlaceMethod);
 
     bool invert = false;
 
     if (deinterlacemode == VS_DEINTERLACEMODE_OFF)
-      m_presentmethod = PRESENT_METHOD_SINGLE;
+      presentmethod = PRESENT_METHOD_SINGLE;
     else
     {
-      if (deinterlacemode == VS_DEINTERLACEMODE_AUTO && m_presentfield == FS_NONE)
-        m_presentmethod = PRESENT_METHOD_SINGLE;
+      if (deinterlacemode == VS_DEINTERLACEMODE_AUTO && presentfield == FS_NONE)
+        presentmethod = PRESENT_METHOD_SINGLE;
       else
       {
-        if      (interlacemethod == VS_INTERLACEMETHOD_RENDER_BLEND)            m_presentmethod = PRESENT_METHOD_BLEND;
-        else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_WEAVE)            m_presentmethod = PRESENT_METHOD_WEAVE;
-        else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_WEAVE_INVERTED) { m_presentmethod = PRESENT_METHOD_WEAVE ; invert = true; }
-        else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BOB)              m_presentmethod = PRESENT_METHOD_BOB;
-        else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BOB_INVERTED)   { m_presentmethod = PRESENT_METHOD_BOB; invert = true; }
-        else if (interlacemethod == VS_INTERLACEMETHOD_DXVA_BOB)                m_presentmethod = PRESENT_METHOD_BOB;
-        else if (interlacemethod == VS_INTERLACEMETHOD_DXVA_BEST)               m_presentmethod = PRESENT_METHOD_BOB;
-        else                                                                    m_presentmethod = PRESENT_METHOD_SINGLE;
+        if      (interlacemethod == VS_INTERLACEMETHOD_RENDER_BLEND)            presentmethod = PRESENT_METHOD_BLEND;
+        else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_WEAVE)            presentmethod = PRESENT_METHOD_WEAVE;
+        else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_WEAVE_INVERTED) { presentmethod = PRESENT_METHOD_WEAVE ; invert = true; }
+        else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BOB)              presentmethod = PRESENT_METHOD_BOB;
+        else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BOB_INVERTED)   { presentmethod = PRESENT_METHOD_BOB; invert = true; }
+        else if (interlacemethod == VS_INTERLACEMETHOD_DXVA_BOB)                presentmethod = PRESENT_METHOD_BOB;
+        else if (interlacemethod == VS_INTERLACEMETHOD_DXVA_BEST)               presentmethod = PRESENT_METHOD_BOB;
+        else                                                                    presentmethod = PRESENT_METHOD_SINGLE;
 
         /* default to odd field if we want to deinterlace and don't know better */
-        if (deinterlacemode == VS_DEINTERLACEMODE_FORCE && m_presentfield == FS_NONE)
-          m_presentfield = FS_TOP;
+        if (deinterlacemode == VS_DEINTERLACEMODE_FORCE && presentfield == FS_NONE)
+          presentfield = FS_TOP;
 
         /* invert present field */
         if(invert)
         {
-          if( m_presentfield == FS_BOT )
-            m_presentfield = FS_TOP;
+          if( presentfield == FS_BOT )
+            presentfield = FS_TOP;
           else
-            m_presentfield = FS_BOT;
+            presentfield = FS_BOT;
         }
       }
     }
 
+    FlipFreeBuffer();
+    m_renderBuffers[m_iOutputRenderBuffer].pts = timestamp;
+    m_renderBuffers[m_iOutputRenderBuffer].presentfield = presentfield;
+    m_renderBuffers[m_iOutputRenderBuffer].presentmethod = presentmethod;
+    m_speed = speed;
   }
 
   g_application.NewFrame();
-  /* wait untill render thread have flipped buffers */
-  timeout = m_presenttime + 1.0;
-  while(m_presentstep == PRESENT_FLIP && !bStop)
+
+  if (!m_bUseBuffering)
   {
-    if(!m_presentevent.WaitMSec(100) && GetPresentTime() > timeout && !bStop)
+    /* wait untill render thread have flipped buffers */
+    double timeout = m_presenttime + 1.0;
+    while(m_presentstep == PRESENT_FLIP && !bStop)
     {
-      CLog::Log(LOGWARNING, "CRenderManager::FlipPage - timeout waiting for flip to complete");
-      return;
+      if(!m_presentevent.WaitMSec(100) && GetPresentTime() > timeout && !bStop)
+      {
+        CLog::Log(LOGWARNING, "CRenderManager::FlipPage - timeout waiting for flip to complete");
+        return;
+      }
     }
   }
 }
@@ -675,8 +698,12 @@ void CXBMCRenderManager::Present()
     if (!m_pRenderer)
       return;
 
+    if (m_presentstep == PRESENT_IDLE)
+      PrepareNextRender();
+
     if(m_presentstep == PRESENT_FLIP)
     {
+      FlipRenderBuffer();
       m_overlays.Flip();
       m_pRenderer->FlipPage(m_presentsource);
       m_presentstep = PRESENT_FRAME;
@@ -800,11 +827,11 @@ int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic)
   if (!m_pRenderer)
     return -1;
 
-  if(m_pRenderer->AddVideoPicture(&pic))
+  if(m_pRenderer->AddVideoPicture(&pic, (m_iOutputRenderBuffer + 1) % m_iNumRenderBuffers))
     return 1;
 
   YV12Image image;
-  int index = m_pRenderer->GetImage(&image);
+  int index = m_pRenderer->GetImage(&image, (m_iOutputRenderBuffer + 1) % m_iNumRenderBuffers);
 
   if(index < 0)
     return index;
@@ -830,19 +857,19 @@ int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic)
   }
 #ifdef HAVE_LIBVDPAU
   else if(pic.format == RENDER_FMT_VDPAU)
-    m_pRenderer->AddProcessor(pic.vdpau);
+    m_pRenderer->AddProcessor(pic.vdpau, index);
 #endif
 #ifdef HAVE_LIBOPENMAX
   else if(pic.format == RENDER_FMT_OMXEGL)
-    m_pRenderer->AddProcessor(pic.openMax, &pic);
+    m_pRenderer->AddProcessor(pic.openMax, &pic, index);
 #endif
 #ifdef TARGET_DARWIN
   else if(pic.format == RENDER_FMT_CVBREF)
-    m_pRenderer->AddProcessor(pic.cvBufferRef);
+    m_pRenderer->AddProcessor(pic.cvBufferRef, index);
 #endif
 #ifdef HAVE_LIBVA
   else if(pic.format == RENDER_FMT_VAAPI)
-    m_pRenderer->AddProcessor(*pic.vaapi);
+    m_pRenderer->AddProcessor(*pic.vaapi, index);
 #endif
   m_pRenderer->ReleaseImage(index, false);
 
@@ -904,3 +931,176 @@ EINTERLACEMETHOD CXBMCRenderManager::AutoInterlaceMethodInternal(EINTERLACEMETHO
 
   return mInt;
 }
+
+int CXBMCRenderManager::WaitForBuffer(volatile bool& bStop)
+{
+  CSharedLock lock(m_sharedSection);
+  if (!m_pRenderer)
+    return -1;
+
+  //wait up to a second as this is our slowest allowed output rate
+  double timeout = GetPresentTime() + 0.1;
+  while(!HasFreeBuffer() && !bStop)
+  {
+    lock.Leave();
+    m_flipEvent.WaitMSec(50);
+    if(GetPresentTime() > timeout && !bStop)
+    {
+      CLog::Log(LOGWARNING, "CRenderManager::WaitForBuffer - timeout waiting for buffer");
+      return -1;
+    }
+    lock.Enter();
+  }
+  lock.Leave();
+
+  { CRetakeLock<CExclusiveLock> lock(m_sharedSection);
+    m_overlays.SetBuffer((m_iOutputRenderBuffer + 1) % m_iNumRenderBuffers);
+  }
+
+  if (bStop)
+    return -1;
+
+  return 1;
+}
+
+int CXBMCRenderManager::GetNextRenderBufferIndex()
+{
+  if (m_iOutputRenderBuffer == m_iCurrentRenderBuffer)
+    return -1;
+  return (m_iCurrentRenderBuffer + 1) % m_iNumRenderBuffers;
+}
+
+void CXBMCRenderManager::FlipRenderBuffer()
+{
+  m_iCurrentRenderBuffer = GetNextRenderBufferIndex();
+}
+
+int CXBMCRenderManager::FlipFreeBuffer()
+{
+  // See "Render Buffer State Description" in header for information.
+  if (HasFreeBuffer())
+  {
+    m_bAllRenderBuffersDisplayed = false;
+    m_iOutputRenderBuffer = (m_iOutputRenderBuffer + 1) % m_iNumRenderBuffers;
+    return m_iOutputRenderBuffer;
+  }
+}
+
+bool CXBMCRenderManager::HasFreeBuffer()
+{
+  if (!m_bUseBuffering)
+  {
+    if (m_iOutputRenderBuffer != m_iCurrentRenderBuffer)
+      return false;
+    else
+      return true;
+  }
+
+  int outputPlus1 = (m_iOutputRenderBuffer + 1) % m_iNumRenderBuffers;
+  if ((m_iOutputRenderBuffer == m_iDisplayedRenderBuffer && !m_bAllRenderBuffersDisplayed)
+     || outputPlus1 == m_iCurrentRenderBuffer)
+    return false;
+  else
+    return true;
+}
+
+void CXBMCRenderManager::ResetRenderBuffer()
+{
+  m_iNumRenderBuffers = m_pRenderer->GetMaxProcessorSize();
+  m_iNumRenderBuffers = std::min(5, m_iNumRenderBuffers);
+  m_iNumRenderBuffers = std::max(2, m_iNumRenderBuffers);
+
+  if (!m_bCodecSupportsBuffering)
+    m_iNumRenderBuffers = 2;
+
+  CLog::Log(LOGNOTICE,"CXBMCRenderManager::ResetRenderBuffer - using %d render buffers", m_iNumRenderBuffers);
+  m_overlays.SetNumBuffers(m_iNumRenderBuffers);
+  m_pRenderer->SetProcessorSize(m_iNumRenderBuffers);
+
+  m_iCurrentRenderBuffer = 0;
+  m_iOutputRenderBuffer = 0;
+  m_iDisplayedRenderBuffer = 0;
+  m_bAllRenderBuffersDisplayed = true;
+  m_sleeptime = 1.0;
+  m_presentPts = DVD_NOPTS_VALUE;
+  m_speed = 0;
+}
+
+void CXBMCRenderManager::PrepareNextRender()
+{
+  int idx = GetNextRenderBufferIndex();
+  if (idx < 0)
+  {
+    if (m_speed >= DVD_PLAYSPEED_NORMAL && g_graphicsContext.IsFullScreenVideo())
+      CLog::Log(LOGDEBUG,"%s no buffer, out: %d, current: %d, display: %d",
+        __FUNCTION__, m_iOutputRenderBuffer, m_iCurrentRenderBuffer, m_iDisplayedRenderBuffer);
+    return;
+  }
+
+  double iClockSleep, iPlayingClock, iCurrentClock;
+  iPlayingClock = m_pClock->GetClock(iCurrentClock, false);
+  iClockSleep = m_renderBuffers[idx].pts - iPlayingClock;
+
+  if (m_speed)
+    iClockSleep = iClockSleep * DVD_PLAYSPEED_NORMAL / m_speed;
+
+  double presenttime = (iCurrentClock + iClockSleep) / DVD_TIME_BASE;
+  double clocktime = iCurrentClock / DVD_TIME_BASE;
+  if(presenttime - clocktime > MAXPRESENTDELAY)
+    presenttime = clocktime + MAXPRESENTDELAY;
+
+  m_sleeptime = presenttime - clocktime;
+
+  if (g_graphicsContext.IsFullScreenVideo() || presenttime <= clocktime+0.01)
+  {
+    m_presentPts = m_renderBuffers[idx].pts;
+    m_presenttime = presenttime;
+    m_presentmethod = m_renderBuffers[idx].presentmethod;
+    m_presentfield = m_renderBuffers[idx].presentfield;
+    m_presentstep  = PRESENT_FLIP;
+    m_presentsource = idx;
+  }
+}
+
+void CXBMCRenderManager::EnableBuffering(bool enable)
+{
+  CRetakeLock<CExclusiveLock> 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<CExclusiveLock> lock(m_sharedSection);
+  m_iOutputRenderBuffer = m_iCurrentRenderBuffer;
+}
+
+void CXBMCRenderManager::NotifyDisplayFlip()
+{
+  CRetakeLock<CExclusiveLock> lock(m_sharedSection);
+  if (!m_pRenderer)
+    return;
+
+  if (m_iNumRenderBuffers < 3)
+    return;
+
+  int last = m_iDisplayedRenderBuffer;
+  m_iDisplayedRenderBuffer = (m_iCurrentRenderBuffer + m_iNumRenderBuffers - 1) % m_iNumRenderBuffers;
+
+  if (last != m_iDisplayedRenderBuffer
+      && m_iDisplayedRenderBuffer != m_iCurrentRenderBuffer)
+  {
+    m_pRenderer->ReleaseBuffer(m_iDisplayedRenderBuffer);
+    m_overlays.ReleaseBuffer(m_iDisplayedRenderBuffer);
+  }
+
+  lock.Leave();
+  m_flipEvent.Set();
+}
diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h
index 7fe6bb2..34ff8d0 100644
--- a/xbmc/cores/VideoRenderers/RenderManager.h
+++ b/xbmc/cores/VideoRenderers/RenderManager.h
@@ -31,6 +31,7 @@
 #include "OverlayRenderer.h"
 
 class CRenderCapture;
+class CDVDClock;
 
 namespace DXVA { class CProcessor; }
 namespace VAAPI { class CSurfaceHolder; }
@@ -70,8 +71,8 @@ class CXBMCRenderManager
 
   int AddVideoPicture(DVDVideoPicture& picture);
 
-  void FlipPage(volatile bool& bStop, double timestamp = 0.0, int source = -1, EFIELDSYNC sync = FS_NONE);
-  unsigned int PreInit();
+  void FlipPage(volatile bool& bStop, double timestamp = 0.0, int source = -1, EFIELDSYNC sync = FS_NONE, int speed = 0);
+  unsigned int PreInit(CDVDClock *pClock);
   void UnInit();
   bool Flush();
 
@@ -131,6 +132,10 @@ class CXBMCRenderManager
   CSharedSection& GetSection() { return m_sharedSection; };
 
   void RegisterRenderUpdateCallBack(const void *ctx, RenderUpdateCallBackFn fn);
+  int WaitForBuffer(volatile bool& bStop);
+  void NotifyDisplayFlip();
+  void EnableBuffering(bool enable);
+  void DiscardBuffer();
 
 protected:
   void Render(bool clear, DWORD flags, DWORD alpha);
@@ -139,6 +144,13 @@ class CXBMCRenderManager
   void PresentFields(bool clear, DWORD flags, DWORD alpha);
   void PresentBlend(bool clear, DWORD flags, DWORD alpha);
 
+  int  GetNextRenderBufferIndex();
+  void FlipRenderBuffer();
+  int  FlipFreeBuffer();
+  bool HasFreeBuffer();
+  void ResetRenderBuffer();
+  void PrepareNextRender();
+
   EINTERLACEMETHOD AutoInterlaceMethodInternal(EINTERLACEMETHOD mInt);
 
   bool m_bPauseDrawing;   // true if we should pause rendering
@@ -169,6 +181,37 @@ class CXBMCRenderManager
   double m_displayLatency;
   void UpdateDisplayLatency();
 
+  // Render Buffer State Description:
+  //
+  // Output:      is the buffer about to or having its texture prepared for render (ie from output thread).
+  //              Cannot go past the "Displayed" buffer (otherwise we will probably overwrite buffers not yet
+  //              displayed or even rendered).
+  // Current:     is the current buffer being or having been submitted for render to back buffer.
+  //              Cannot go past "Output" buffer (else it would be rendering old output).
+  // Displayed:   is the buffer that is now considered to be safely copied from back buffer to front buffer
+  //              (we assume that after two swap-buffer flips for the same "Current" render buffer that that
+  //              buffer will be safe, but otherwise we consider that only the previous-to-"Current" is guaranteed).
+
+  int m_iCurrentRenderBuffer;
+  int m_iNumRenderBuffers;
+  int m_iOutputRenderBuffer;
+  int m_iDisplayedRenderBuffer;
+  bool m_bAllRenderBuffersDisplayed;
+  bool m_bUseBuffering;
+  bool m_bCodecSupportsBuffering;
+  int m_speed;
+  CEvent m_flipEvent;
+
+  struct
+  {
+    double pts;
+    EFIELDSYNC presentfield;
+    EPRESENTMETHOD presentmethod;
+  }m_renderBuffers[5];
+
+  double     m_sleeptime;
+  double     m_presentPts;
+
   double     m_presenttime;
   double     m_presentcorr;
   double     m_presenterr;
@@ -180,6 +223,7 @@ class CXBMCRenderManager
   int        m_presentsource;
   CEvent     m_presentevent;
   CEvent     m_flushEvent;
+  CDVDClock  *m_pClock;
 
 
   OVERLAY::CRenderer m_overlays;
diff --git a/xbmc/cores/VideoRenderers/WinRenderer.cpp b/xbmc/cores/VideoRenderers/WinRenderer.cpp
index 7842089..6e4433c 100644
--- a/xbmc/cores/VideoRenderers/WinRenderer.cpp
+++ b/xbmc/cores/VideoRenderers/WinRenderer.cpp
@@ -253,12 +253,12 @@ int CWinRenderer::NextYV12Texture()
     return -1;
 }
 
-bool CWinRenderer::AddVideoPicture(DVDVideoPicture* picture)
+bool CWinRenderer::AddVideoPicture(DVDVideoPicture* picture, int index)
 {
   if (m_renderMethod == RENDER_DXVA)
   {
-    int source = NextYV12Texture();
-    if(source < 0)
+    int source = index;
+    if(source < 0 || NextYV12Texture() < 0)
       return false;
 
     DXVABuffer *buf = (DXVABuffer*)m_VideoBuffers[source];
@@ -274,7 +274,7 @@ int CWinRenderer::GetImage(YV12Image *image, int source, bool readonly)
   if( source == AUTOSOURCE )
     source = NextYV12Texture();
 
-  if( source < 0 )
+  if( source < 0 || NextYV12Texture() < 0)
     return -1;
 
   YUVBuffer *buf = (YUVBuffer*)m_VideoBuffers[source];
diff --git a/xbmc/cores/VideoRenderers/WinRenderer.h b/xbmc/cores/VideoRenderers/WinRenderer.h
index 2ab5684..f493ba7 100644
--- a/xbmc/cores/VideoRenderers/WinRenderer.h
+++ b/xbmc/cores/VideoRenderers/WinRenderer.h
@@ -157,7 +157,7 @@ class CWinRenderer : public CBaseRenderer
   virtual bool         Configure(unsigned int width, unsigned int height, unsigned int d_width, unsigned int d_height, float fps, unsigned flags, ERenderFormat format, unsigned extended_format, unsigned int orientation);
   virtual int          GetImage(YV12Image *image, int source = AUTOSOURCE, bool readonly = false);
   virtual void         ReleaseImage(int source, bool preserve = false);
-  virtual bool         AddVideoPicture(DVDVideoPicture* picture);
+  virtual bool         AddVideoPicture(DVDVideoPicture* picture, int index);
   virtual void         FlipPage(int source);
   virtual unsigned int PreInit();
   virtual void         UnInit();
diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp
index 1a4c23c..bf47cd1 100644
--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp
@@ -462,7 +462,7 @@ bool CDVDPlayer::OpenFile(const CFileItem& file, const CPlayerOptions &options)
     m_ready.Reset();
 
 #if defined(HAS_VIDEO_PLAYBACK)
-    g_renderManager.PreInit();
+    g_renderManager.PreInit(&m_clock);
 #endif
 
     Create();
diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
index 3008c25..a4bb1ba 100644
--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
@@ -261,6 +261,7 @@ void CDVDPlayerVideo::OpenStream(CDVDStreamInfo &hint, CDVDVideoCodec* codec)
   m_stalled = m_messageQueue.GetPacketCount(CDVDMsg::DEMUXER_PACKET) == 0;
   m_started = false;
   m_codecname = m_pVideoCodec->GetName();
+  g_renderManager.EnableBuffering(false);
 }
 
 void CDVDPlayerVideo::CloseStream(bool bWaitForBuffers)
@@ -436,6 +437,7 @@ void CDVDPlayerVideo::Process()
       picture.iFlags &= ~DVP_FLAG_ALLOCATED;
       m_packets.clear();
       m_started = false;
+      g_renderManager.EnableBuffering(false);
     }
     else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) // private message sent by (CDVDPlayerVideo::Flush())
     {
@@ -448,6 +450,7 @@ void CDVDPlayerVideo::Process()
       //we need to recalculate the framerate
       //TODO: this needs to be set on a streamchange instead
       ResetFrameRateCalc();
+      g_renderManager.EnableBuffering(false);
 
       m_stalled = true;
       m_started = false;
@@ -586,6 +589,8 @@ void CDVDPlayerVideo::Process()
 
           m_pVideoCodec->Reset();
           m_packets.clear();
+          picture.iFlags &= ~DVP_FLAG_ALLOCATED;
+          g_renderManager.DiscardBuffer();
           break;
         }
 
@@ -700,6 +705,7 @@ void CDVDPlayerVideo::Process()
               m_codecname = m_pVideoCodec->GetName();
               m_started = true;
               m_messageParent.Put(new CDVDMsgInt(CDVDMsg::PLAYER_STARTED, DVDPLAYER_VIDEO));
+              g_renderManager.EnableBuffering(true);
             }
 
             // guess next frame pts. iDuration is always valid
@@ -1317,6 +1323,16 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts)
       mDisplayField = FS_BOT;
   }
 
+  int buffer = g_renderManager.WaitForBuffer(m_bStop);
+  while (buffer < 0 && !CThread::m_bStop &&
+         CDVDClock::GetAbsoluteClock(false) < iCurrentClock + iSleepTime + DVD_MSEC_TO_TIME(500) )
+  {
+    Sleep(1);
+    buffer = g_renderManager.WaitForBuffer(m_bStop);
+  }
+  if (buffer < 0)
+    return EOS_DROPPED;
+
   ProcessOverlays(pPicture, pts);
   AutoCrop(pPicture);
 
@@ -1333,7 +1349,7 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts)
   if (index < 0)
     return EOS_DROPPED;
 
-  g_renderManager.FlipPage(CThread::m_bStop, (iCurrentClock + iSleepTime) / DVD_TIME_BASE, -1, mDisplayField);
+  g_renderManager.FlipPage(CThread::m_bStop, pts, -1, mDisplayField, m_speed);
 
   return result;
 #else
-- 
1.7.10


From 2c7b662016485902950503f2a02542522dc744c9 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Tue, 2 Oct 2012 10:49:09 +0200
Subject: [PATCH 03/58] 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 a740954..15e5757 100644
--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
@@ -251,7 +251,7 @@ bool CLinuxRendererGL::ValidateRenderTarget()
     // function pointer for texture might change in
     // call to LoadShaders
     glFinish();
-    for (int i = 0 ; i < m_NumYV12Buffers ; i++)
+    for (int i = 0 ; i < NUM_BUFFERS ; i++)
       (this->*m_textureDelete)(i);
 
     // trigger update of video filters
-- 
1.7.10


From cc49be517f99d87e680418403d789fdca4bfdaeb Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Mon, 28 May 2012 10:17:33 +0200
Subject: [PATCH 04/58] 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 f85aaac..e9b9ba0 100644
--- a/xbmc/Application.cpp
+++ b/xbmc/Application.cpp
@@ -414,8 +414,6 @@
 #endif
   m_currentStack = new CFileItemList;
 
-  m_frameCount = 0;
-
   m_bPresentFrame = false;
   m_bPlatformDirectories = true;
 
@@ -2205,28 +2203,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<InversePredicate<int&> > cv(m_frameCond, InversePredicate<int&>(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()
@@ -2246,7 +2234,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
@@ -2260,13 +2247,10 @@ void CApplication::Render()
     m_bPresentFrame = false;
     if (!extPlayerActive && g_graphicsContext.IsFullScreenVideo() && !IsPaused())
     {
-      CSingleLock lock(m_frameMutex);
-
-      TightConditionVariable<int&> 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
@@ -2290,8 +2274,6 @@ void CApplication::Render()
         else if (lowfps)
           singleFrameTime = 200;  // 5 fps, <=200 ms latency to wake up
       }
-
-      decrement = true;
     }
   }
 
@@ -2355,13 +2337,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)
@@ -5580,12 +5555,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;
@@ -5818,7 +5787,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 33d500d..f0456be 100644
--- a/xbmc/Application.h
+++ b/xbmc/Application.h
@@ -424,10 +424,8 @@ class CApplication : public CXBApplicationEx, public IPlayerCallback, public IMs
   bool m_bEnableLegacyRes;
   bool m_bTestMode;
   bool m_bSystemScreenSaverEnable;
-
-  int        m_frameCount;
-  CCriticalSection m_frameMutex;
-  XbmcThreads::ConditionVariable  m_frameCond;
+  
+  CEvent m_frameEvent;
 
   VIDEO::CVideoInfoScanner *m_videoInfoScanner;
   MUSIC_INFO::CMusicInfoScanner *m_musicInfoScanner;
diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp
index eeb6c6f..4b897da 100644
--- a/xbmc/cores/VideoRenderers/RenderManager.cpp
+++ b/xbmc/cores/VideoRenderers/RenderManager.cpp
@@ -1104,3 +1104,14 @@ void CXBMCRenderManager::NotifyDisplayFlip()
   lock.Leave();
   m_flipEvent.Set();
 }
+
+bool CXBMCRenderManager::HasFrame()
+{
+  CSharedLock lock(m_sharedSection);
+  if (m_presentstep == PRESENT_IDLE &&
+      GetNextRenderBufferIndex() < 0 &&
+      m_speed > 0)
+    return false;
+  else
+    return true;
+}
diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h
index 34ff8d0..288175e 100644
--- a/xbmc/cores/VideoRenderers/RenderManager.h
+++ b/xbmc/cores/VideoRenderers/RenderManager.h
@@ -134,6 +134,7 @@ class CXBMCRenderManager
   void RegisterRenderUpdateCallBack(const void *ctx, RenderUpdateCallBackFn fn);
   int WaitForBuffer(volatile bool& bStop);
   void NotifyDisplayFlip();
+  bool HasFrame();
   void EnableBuffering(bool enable);
   void DiscardBuffer();
 
-- 
1.7.10


From 03fde5238101a7b0190b516fc6cb79c95966808f Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Mon, 28 May 2012 10:34:39 +0200
Subject: [PATCH 05/58] videoplayer: adopt lateness detection and dropping to
 buffering

---
 xbmc/cores/VideoRenderers/RenderManager.cpp        |   12 ++
 xbmc/cores/VideoRenderers/RenderManager.h          |    1 +
 .../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h      |   14 ++
 .../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp        |   31 +++
 .../DVDCodecs/Video/DVDVideoCodecFFmpeg.h          |    7 +
 xbmc/cores/dvdplayer/DVDPlayerVideo.cpp            |  224 ++++++++++++++++----
 xbmc/cores/dvdplayer/DVDPlayerVideo.h              |   24 +++
 7 files changed, 268 insertions(+), 45 deletions(-)

diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp
index 4b897da..f19797c 100644
--- a/xbmc/cores/VideoRenderers/RenderManager.cpp
+++ b/xbmc/cores/VideoRenderers/RenderManager.cpp
@@ -1105,6 +1105,18 @@ void CXBMCRenderManager::NotifyDisplayFlip()
   m_flipEvent.Set();
 }
 
+bool CXBMCRenderManager::GetStats(double &sleeptime, double &pts, int &bufferLevel)
+{
+  CSharedLock lock(m_sharedSection);
+  sleeptime = m_sleeptime;
+  pts = m_presentPts;
+  if (m_iNumRenderBuffers < 3)
+    bufferLevel = -1;
+  else
+    bufferLevel = (m_iOutputRenderBuffer - m_iCurrentRenderBuffer + m_iNumRenderBuffers) % m_iNumRenderBuffers;
+  return true;
+}
+
 bool CXBMCRenderManager::HasFrame()
 {
   CSharedLock lock(m_sharedSection);
diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h
index 288175e..9342586 100644
--- a/xbmc/cores/VideoRenderers/RenderManager.h
+++ b/xbmc/cores/VideoRenderers/RenderManager.h
@@ -134,6 +134,7 @@ class CXBMCRenderManager
   void RegisterRenderUpdateCallBack(const void *ctx, RenderUpdateCallBackFn fn);
   int WaitForBuffer(volatile bool& bStop);
   void NotifyDisplayFlip();
+  bool GetStats(double &sleeptime, double &pts, int &bufferLevel);
   bool HasFrame();
   void EnableBuffering(bool enable);
   void DiscardBuffer();
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
index 1d8bad3..5001aac 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
@@ -110,6 +110,10 @@ struct DVDVideoUserData
 #define DVP_FLAG_NOSKIP             0x00000010 // indicate this picture should never be dropped
 #define DVP_FLAG_DROPPED            0x00000020 // indicate that this picture has been dropped in decoder stage, will have no data
 
+#define DVP_FLAG_DROPDEINT          0x00000040 // indicate that this picture was requested to have been dropped in deint stage
+#define DVP_FLAG_NO_POSTPROC        0x00000100
+#define DVP_FLAG_DRAIN              0x00000200
+
 // DVP_FLAG 0x00000100 - 0x00000f00 is in use by libmpeg2!
 
 #define DVP_QSCALE_UNKNOWN          0
@@ -127,6 +131,9 @@ struct DVDVideoUserData
 #define VC_PICTURE  0x00000004  // the decoder got a picture, call Decode(NULL, 0) again to parse the rest of the data
 #define VC_USERDATA 0x00000008  // the decoder found some userdata,  call Decode(NULL, 0) again to parse the rest of the data
 #define VC_FLUSHED  0x00000010  // the decoder lost it's state, we need to restart decoding again
+#define VC_DROPPED  0x00000020  // needed to identify if a picture was dropped
+#define VC_HURRY    0x00000040
+
 class CDVDVideoCodec
 {
 public:
@@ -237,4 +244,11 @@ class CDVDVideoCodec
   {
     return 0;
   }
+
+  virtual bool GetPts(double &pts, int &skippedDeint, int &interlaced)
+  {
+    return false;
+  }
+
+  virtual void SetCodecControl(int flags) {}
 };
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
index 8f81637..af706bd 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
@@ -142,6 +142,7 @@ enum PixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx
   m_iLastKeyframe = 0;
   m_dts = DVD_NOPTS_VALUE;
   m_started = false;
+  m_decoderPts = DVD_NOPTS_VALUE;
 }
 
 CDVDVideoCodecFFmpeg::~CDVDVideoCodecFFmpeg()
@@ -340,6 +341,14 @@ void CDVDVideoCodecFFmpeg::SetDropState(bool bDrop)
 {
   if( m_pCodecContext )
   {
+    if (bDrop && m_pHardware && m_pHardware->CanSkipDeint())
+    {
+      m_requestSkipDeint = true;
+      bDrop = false;
+    }
+    else
+      m_requestSkipDeint = false;
+
     // i don't know exactly how high this should be set
     // couldn't find any good docs on it. think it varies
     // from codec to codec on what it does
@@ -541,6 +550,7 @@ int CDVDVideoCodecFFmpeg::Decode(BYTE* pData, int iSize, double dts, double pts)
 void CDVDVideoCodecFFmpeg::Reset()
 {
   m_started = false;
+  m_decoderPts = DVD_NOPTS_VALUE;
   m_iLastKeyframe = m_pCodecContext->has_b_frames;
   m_dllAvCodec.avcodec_flush_buffers(m_pCodecContext);
 
@@ -639,6 +649,22 @@ bool CDVDVideoCodecFFmpeg::GetPictureCommon(DVDVideoPicture* pDvdVideoPicture)
   else
     pDvdVideoPicture->pts = DVD_NOPTS_VALUE;
 
+  if (pDvdVideoPicture->pts != DVD_NOPTS_VALUE)
+    m_decoderPts = pDvdVideoPicture->pts;
+  else
+    m_decoderPts = m_dts;
+
+  if (m_requestSkipDeint)
+  {
+    pDvdVideoPicture->iFlags |= DVP_FLAG_DROPDEINT;
+    m_skippedDeint = 1;
+  }
+  else
+    m_skippedDeint = 0;
+
+  m_requestSkipDeint = false;
+  pDvdVideoPicture->iFlags |= m_codecControlFlags;
+
   if(!m_started)
     pDvdVideoPicture->iFlags |= DVP_FLAG_DROPPED;
 
@@ -861,3 +887,8 @@ unsigned CDVDVideoCodecFFmpeg::GetConvergeCount()
   else
     return 0;
 }
+
+void CDVDVideoCodecFFmpeg::SetCodecControl(int flags)
+{
+  m_codecControlFlags = flags;
+}
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h
index 61d0305..52e1113 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h
@@ -44,6 +44,7 @@ class CDVDVideoCodecFFmpeg : public CDVDVideoCodec
     virtual bool GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture) = 0;
     virtual int  Check     (AVCodecContext* avctx) = 0;
     virtual void Reset     () {}
+    virtual bool CanSkipDeint() {return false; }
     virtual const std::string Name() = 0;
     virtual CCriticalSection* Section() { return NULL; }
   };
@@ -60,6 +61,8 @@ class CDVDVideoCodecFFmpeg : public CDVDVideoCodec
   virtual unsigned int SetFilters(unsigned int filters);
   virtual const char* GetName() { return m_name.c_str(); }; // m_name is never changed after open
   virtual unsigned GetConvergeCount();
+  virtual bool GetPts(double &pts, int &skippedDeint, int &interlaced) {pts=m_decoderPts; skippedDeint=m_skippedDeint; if (m_pFrame) interlaced = m_pFrame->interlaced_frame; return true;}
+  virtual void SetCodecControl(int flags);
 
   bool               IsHardwareAllowed()                     { return !m_bSoftware; }
   IHardwareDecoder * GetHardware()                           { return m_pHardware; };
@@ -119,4 +122,8 @@ class CDVDVideoCodecFFmpeg : public CDVDVideoCodec
   double m_dts;
   bool   m_started;
   std::vector<PixelFormat> m_formats;
+  double m_decoderPts, m_decoderInterval;
+  int    m_skippedDeint;
+  bool   m_requestSkipDeint;
+  int    m_codecControlFlags;
 };
diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
index a4bb1ba..93908a7 100644
--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
@@ -326,8 +326,10 @@ void CDVDPlayerVideo::Process()
 
   int iDropped = 0; //frames dropped in a row
   bool bRequestDrop = false;
+  int iDropDirective;
 
   m_videoStats.Start();
+  m_droppingStats.Reset();
 
   while (!m_bStop)
   {
@@ -437,6 +439,7 @@ void CDVDPlayerVideo::Process()
       picture.iFlags &= ~DVP_FLAG_ALLOCATED;
       m_packets.clear();
       m_started = false;
+      m_droppingStats.Reset();
       g_renderManager.EnableBuffering(false);
     }
     else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) // private message sent by (CDVDPlayerVideo::Flush())
@@ -450,6 +453,7 @@ void CDVDPlayerVideo::Process()
       //we need to recalculate the framerate
       //TODO: this needs to be set on a streamchange instead
       ResetFrameRateCalc();
+      m_droppingStats.Reset();
       g_renderManager.EnableBuffering(false);
 
       m_stalled = true;
@@ -468,6 +472,7 @@ void CDVDPlayerVideo::Process()
       m_speed = static_cast<CDVDMsgInt*>(pMsg)->m_value;
       if(m_speed == DVD_PLAYSPEED_PAUSE)
         m_iNrOfPicturesNotToSkip = 0;
+      m_droppingStats.Reset();
     }
     else if (pMsg->IsType(CDVDMsg::PLAYER_STARTED))
     {
@@ -502,6 +507,28 @@ void CDVDPlayerVideo::Process()
         m_iNrOfPicturesNotToSkip = 1;
       }
 
+      bRequestDrop = false;
+      iDropDirective = CalcDropRequirement(pts);
+      if (iDropDirective & EOS_VERYLATE)
+      {
+        if (m_bAllowDrop)
+        {
+          m_pullupCorrection.Flush();
+          bRequestDrop = true;
+        }
+      }
+      int codecControl = 0;
+      if (iDropDirective & EOS_BUFFER_LEVEL)
+        codecControl |= DVP_FLAG_DRAIN;
+      if (m_speed > DVD_PLAYSPEED_NORMAL)
+        codecControl |= DVP_FLAG_NO_POSTPROC;
+      m_pVideoCodec->SetCodecControl(codecControl);
+      if (iDropDirective & EOS_DROPPED)
+      {
+        m_iDroppedFrames++;
+        iDropped++;
+      }
+
 #ifdef PROFILE
       bRequestDrop = false;
 #else
@@ -511,6 +538,7 @@ void CDVDPlayerVideo::Process()
         bRequestDrop = false;
         m_iDroppedRequest = 0;
         m_iLateFrames     = 0;
+        m_droppingStats.m_requestOutputDrop = false;
       }
 #endif
 
@@ -558,15 +586,8 @@ void CDVDPlayerVideo::Process()
       }
 
       m_videoStats.AddSampleBytes(pPacket->iSize);
-      // assume decoder dropped a picture if it didn't give us any
-      // picture from a demux packet, this should be reasonable
-      // for libavformat as a demuxer as it normally packetizes
-      // pictures when they come from demuxer
-      if(bRequestDrop && !bPacketDrop && (iDecoderState & VC_BUFFER) && !(iDecoderState & VC_PICTURE))
-      {
-        m_iDroppedFrames++;
-        iDropped++;
-      }
+
+      bRequestDrop = false;
 
       // loop while no error
       while (!m_bStop)
@@ -1244,50 +1265,30 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts)
   m_FlipTimeStamp += max(0.0, iSleepTime);
   m_FlipTimeStamp += iFrameDuration;
 
-  if (iSleepTime <= 0 && m_speed)
-    m_iLateFrames++;
-  else
-    m_iLateFrames = 0;
-
-  // ask decoder to drop frames next round, as we are very late
-  if(m_iLateFrames > 10)
-  {
-    if (!(pPicture->iFlags & DVP_FLAG_NOSKIP))
-    {
-      //if we're calculating the framerate,
-      //don't drop frames until we've calculated a stable framerate
-      if (m_bAllowDrop || m_speed != DVD_PLAYSPEED_NORMAL)
-      {
-        result |= EOS_VERYLATE;
-        m_pullupCorrection.Flush(); //dropped frames mess up the pattern, so just flush it
-      }
-
-      //if we requested 5 drops in a row and we're still late, drop on output
-      //this keeps a/v sync if the decoder can't drop, or we're still calculating the framerate
-      if (m_iDroppedRequest > 5)
-      {
-        m_iDroppedRequest--; //decrease so we only drop half the frames
-        return result | EOS_DROPPED;
-      }
-      m_iDroppedRequest++;
-    }
-  }
-  else
+  if ((m_droppingStats.m_requestOutputDrop && !(pPicture->iFlags & DVP_FLAG_NOSKIP))
+     || (pPicture->iFlags & DVP_FLAG_DROPPED))
   {
-    m_iDroppedRequest = 0;
+    m_droppingStats.AddOutputDropGain(pts, 1/m_fFrameRate);
+    m_droppingStats.m_requestOutputDrop = false;
+    CLog::Log(LOGDEBUG,"%s - dropped in output", __FUNCTION__);
+    return result | EOS_DROPPED;
   }
 
   if( m_speed < 0 )
   {
-    if( iClockSleep < -DVD_MSEC_TO_TIME(200)
-    && !(pPicture->iFlags & DVP_FLAG_NOSKIP) )
+    double decoderPts = m_droppingStats.m_lastDecoderPts;
+    double renderPts = m_droppingStats.m_lastRenderPts;
+    if (pts > renderPts)
+    {
+      if (decoderPts >= renderPts)
+      {
+        Sleep(200);
+      }
       return result | EOS_DROPPED;
+    }
   }
 
-  if( (pPicture->iFlags & DVP_FLAG_DROPPED) )
-    return result | EOS_DROPPED;
-
-  if( m_speed != DVD_PLAYSPEED_NORMAL && limited )
+  if( m_speed != DVD_PLAYSPEED_NORMAL && m_speed >= 0 && limited )
   {
     // calculate frame dropping pattern to render at this speed
     // we do that by deciding if this or next frame is closest
@@ -1648,3 +1649,136 @@ void CDVDPlayerVideo::CalcFrameRate()
     m_iFrameRateCount = 0;
   }
 }
+
+int CDVDPlayerVideo::CalcDropRequirement(double pts)
+{
+  int result = 0;
+  double iSleepTime;
+  double iDecoderPts, iRenderPts;
+  double iInterval;
+  int    interlaced;
+  double iGain;
+  double iLateness;
+  bool   bNewFrame;
+  int    iSkippedDeint = 0;
+  int    iBufferLevel;
+
+  // get decoder stats
+  if (!m_pVideoCodec->GetPts(iDecoderPts, iSkippedDeint, interlaced))
+    iDecoderPts = pts;
+  if (iDecoderPts == DVD_NOPTS_VALUE)
+    iDecoderPts = pts;
+
+  // get render stats
+  g_renderManager.GetStats(iSleepTime, iRenderPts, iBufferLevel);
+
+  if (iBufferLevel < 0)
+    result |= EOS_BUFFER_LEVEL;
+  else if (iBufferLevel < 2)
+  {
+    result |= EOS_BUFFER_LEVEL;
+    CLog::Log(LOGDEBUG,"CDVDPlayerVideo::CalcDropRequirement - hurry: %d", iBufferLevel);
+  }
+
+  bNewFrame = iDecoderPts != m_droppingStats.m_lastDecoderPts;
+
+  if (interlaced)
+    iInterval = 2/m_fFrameRate*(double)DVD_TIME_BASE;
+  else
+    iInterval = 1/m_fFrameRate*(double)DVD_TIME_BASE;
+
+  if (m_droppingStats.m_lastDecoderPts > 0
+      && bNewFrame
+      && m_bAllowDrop
+      && m_droppingStats.m_dropRequests > 0)
+  {
+    iGain = (iDecoderPts - m_droppingStats.m_lastDecoderPts - iInterval)/(double)DVD_TIME_BASE;
+    if (iSkippedDeint)
+    {
+      CDroppingStats::CGain gain;
+      gain.gain = 1/m_fFrameRate;
+      gain.pts = iDecoderPts;
+      m_droppingStats.m_gain.push_back(gain);
+      m_droppingStats.m_totalGain += gain.gain;
+      result |= EOS_DROPPED;
+      m_droppingStats.m_dropRequests = 0;
+      CLog::Log(LOGDEBUG,"CDVDPlayerVideo::CalcDropRequirement - dropped de-interlacing cycle, Sleeptime: %f, Bufferlevel: %d", iSleepTime, iBufferLevel);
+    }
+    else if (iGain > 1/m_fFrameRate)
+    {
+      CDroppingStats::CGain gain;
+      gain.gain = iGain;
+      gain.pts = iDecoderPts;
+      m_droppingStats.m_gain.push_back(gain);
+      m_droppingStats.m_totalGain += iGain;
+      result |= EOS_DROPPED;
+      m_droppingStats.m_dropRequests = 0;
+      CLog::Log(LOGDEBUG,"CDVDPlayerVideo::CalcDropRequirement - dropped in decoder, Sleeptime: %f, Bufferlevel: %d, Gain: %f", iSleepTime, iBufferLevel, iGain);
+    }
+  }
+  m_droppingStats.m_lastDecoderPts = iDecoderPts;
+
+  // subtract gains
+  while (!m_droppingStats.m_gain.empty() &&
+         iRenderPts >= m_droppingStats.m_gain.front().pts)
+  {
+    m_droppingStats.m_totalGain -= m_droppingStats.m_gain.front().gain;
+    m_droppingStats.m_gain.pop_front();
+  }
+
+  // calculate lateness
+  iLateness = iSleepTime + m_droppingStats.m_totalGain;
+  if (iLateness < 0 && m_speed)
+  {
+    if (bNewFrame)
+      m_droppingStats.m_lateFrames++;
+
+    // if lateness is smaller than frametime, we observe this state
+    // for 10 cycles
+    if (m_droppingStats.m_lateFrames > 10 || iLateness < -2/m_fFrameRate)
+    {
+      // is frame allowed to skip
+      if (m_iNrOfPicturesNotToSkip <= 0)
+      {
+        result |= EOS_VERYLATE;
+
+        // drop in output
+        if (m_droppingStats.m_dropRequests > 7 && g_graphicsContext.IsFullScreenVideo())
+        {
+          m_droppingStats.m_dropRequests--; //decrease so we only drop half the frames
+          m_droppingStats.m_requestOutputDrop = true;
+        }
+        else if (bNewFrame)
+          m_droppingStats.m_dropRequests++;
+      }
+    }
+  }
+  else
+  {
+    m_droppingStats.m_dropRequests = 0;
+    m_droppingStats.m_lateFrames = 0;
+    m_droppingStats.m_requestOutputDrop = false;
+  }
+  m_droppingStats.m_lastRenderPts = iRenderPts;
+  return result;
+}
+
+void CDroppingStats::Reset()
+{
+  m_gain.clear();
+  m_totalGain = 0;
+  m_lastDecoderPts = 0;
+  m_lastRenderPts = 0;
+  m_lateFrames = 0;
+  m_dropRequests = 0;
+  m_requestOutputDrop = false;
+}
+
+void CDroppingStats::AddOutputDropGain(double pts, double frametime)
+{
+  CDroppingStats::CGain gain;
+  gain.gain = frametime;
+  gain.pts = pts;
+  m_gain.push_back(gain);
+  m_totalGain += frametime;
+}
diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.h b/xbmc/cores/dvdplayer/DVDPlayerVideo.h
index fe7e12c..4913712 100644
--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.h
+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.h
@@ -37,6 +37,26 @@
 
 #define VIDEO_PICTURE_QUEUE_SIZE 1
 
+class CDroppingStats
+{
+public:
+  void Reset();
+  void AddOutputDropGain(double pts, double frametime);
+  struct CGain
+  {
+    double gain;
+    double pts;
+  };
+  std::deque<CGain> 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<DVDMessageListItem> m_packets;
+
+  CDroppingStats m_droppingStats;
 };
 
-- 
1.7.10


From 532dbba16199d9f40b427b23f4922582883746eb Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Mon, 28 May 2012 10:41:31 +0200
Subject: [PATCH 06/58] videoplayer: update frametime, it might change due to
 fps detection

---
 xbmc/cores/dvdplayer/DVDPlayerVideo.cpp |    2 ++
 1 file changed, 2 insertions(+)

diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
index 93908a7..4675556 100644
--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
@@ -721,6 +721,8 @@ void CDVDPlayerVideo::Process()
             CDVDCodecUtils::FreePicture(pTempYUVPackedPicture);
 #endif
 
+            frametime = (double)DVD_TIME_BASE/m_fFrameRate;
+
             if(m_started == false)
             {
               m_codecname = m_pVideoCodec->GetName();
-- 
1.7.10


From bba5b177fdc05dd35aa515757106c0b7f45501e5 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Mon, 28 May 2012 10:43:06 +0200
Subject: [PATCH 07/58] videoplayer: give streams with invalid fps a chance
 for fps detection

---
 xbmc/cores/dvdplayer/DVDPlayerVideo.cpp |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
index 4675556..2ef6358 100644
--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
@@ -1595,7 +1595,7 @@ void CDVDPlayerVideo::CalcFrameRate()
   double frameduration = m_pullupCorrection.GetFrameDuration();
 
   if (frameduration == DVD_NOPTS_VALUE ||
-      (g_advancedSettings.m_videoFpsDetect == 1 && m_pullupCorrection.GetPatternLength() > 1))
+      (g_advancedSettings.m_videoFpsDetect == 1 && (m_pullupCorrection.GetPatternLength() > 1 && !m_bFpsInvalid)))
   {
     //reset the stored framerates if no good framerate was detected
     m_fStableFrameRate = 0.0;
-- 
1.7.10


From 066a5bfdea464e3c2b1d42b7d95b94a0985340f0 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Mon, 28 May 2012 10:49:05 +0200
Subject: [PATCH 08/58] 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 bf47cd1..bd84086 100644
--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp
@@ -1554,7 +1554,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())
     {
@@ -2190,6 +2190,12 @@ void CDVDPlayer::HandleMessages()
           pvrinputstream->Pause( speed == 0 );
         }
 
+        // do a seek after rewind, clock is not in sync with current pts
+        if (m_playSpeed < 0 && speed >= 0)
+        {
+          m_messenger.Put(new CDVDMsgPlayerSeek(GetTime(), true, true, true));
+        }
+
         // if playspeed is different then DVD_PLAYSPEED_NORMAL or DVD_PLAYSPEED_PAUSE
         // audioplayer, stops outputing audio to audiorendere, but still tries to
         // sleep an correct amount for each packet
-- 
1.7.10


From 2ab8e42700f00f0abb0b87547bb7e310e5db5700 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Sun, 2 Sep 2012 16:05:21 +0200
Subject: [PATCH 09/58] video player: present correct pts to user for a/v sync
 (after buffering in renderer)

---
 xbmc/cores/dvdplayer/DVDPlayerVideo.cpp |   41 +++++++++++++++++++------------
 xbmc/cores/dvdplayer/DVDPlayerVideo.h   |    2 +-
 2 files changed, 26 insertions(+), 17 deletions(-)

diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
index 2ef6358..10e2225 100644
--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
@@ -1251,22 +1251,6 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts)
   else
     iSleepTime = iFrameSleep + (iClockSleep - iFrameSleep) / m_autosync;
 
-#ifdef PROFILE /* during profiling, try to play as fast as possible */
-  iSleepTime = 0;
-#endif
-
-  // present the current pts of this frame to user, and include the actual
-  // presentation delay, to allow him to adjust for it
-  if( m_stalled )
-    m_iCurrentPts = DVD_NOPTS_VALUE;
-  else
-    m_iCurrentPts = pts - max(0.0, iSleepTime);
-
-  // timestamp when we think next picture should be displayed based on current duration
-  m_FlipTimeStamp  = iCurrentClock;
-  m_FlipTimeStamp += max(0.0, iSleepTime);
-  m_FlipTimeStamp += iFrameDuration;
-
   if ((m_droppingStats.m_requestOutputDrop && !(pPicture->iFlags & DVP_FLAG_NOSKIP))
      || (pPicture->iFlags & DVP_FLAG_DROPPED))
   {
@@ -1571,6 +1555,22 @@ void CDVDPlayerVideo::ResetFrameRateCalc()
                         g_advancedSettings.m_videoFpsDetect == 0;
 }
 
+double CDVDPlayerVideo::GetCurrentPts()
+{
+  double iSleepTime, iRenderPts;
+  int iBufferLevel;
+
+  // get render stats
+  g_renderManager.GetStats(iSleepTime, iRenderPts, iBufferLevel);
+
+  if( m_stalled )
+    iRenderPts = DVD_NOPTS_VALUE;
+  else
+    iRenderPts = iRenderPts - max(0.0, iSleepTime);
+
+  return iRenderPts;
+}
+
 #define MAXFRAMERATEDIFF   0.01
 #define MAXFRAMESERR    1000
 
@@ -1689,6 +1689,15 @@ int CDVDPlayerVideo::CalcDropRequirement(double pts)
   else
     iInterval = 1/m_fFrameRate*(double)DVD_TIME_BASE;
 
+
+  m_FlipTimeStamp = m_pClock->GetAbsoluteClock() + max(0.0, iSleepTime) + iInterval;
+
+  if( m_stalled )
+    m_iCurrentPts = DVD_NOPTS_VALUE;
+  else
+    m_iCurrentPts = iRenderPts - max(0.0, iSleepTime);
+
+
   if (m_droppingStats.m_lastDecoderPts > 0
       && bNewFrame
       && m_bAllowDrop
diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.h b/xbmc/cores/dvdplayer/DVDPlayerVideo.h
index 4913712..509d5f7 100644
--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.h
+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.h
@@ -108,7 +108,7 @@ class CDVDPlayerVideo : public CThread
 
   bool InitializedOutputDevice();
 
-  double GetCurrentPts()                           { return m_iCurrentPts; }
+  double GetCurrentPts();
   int    GetPullupCorrection()                     { return m_pullupCorrection.GetPatternLength(); }
 
   double GetOutputDelay(); /* returns the expected delay, from that a packet is put in queue */
-- 
1.7.10


From 1692470e838c868b5e11c30a66faf493ae141321 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Mon, 28 May 2012 11:02:29 +0200
Subject: [PATCH 10/58] vaapi: adopt to buffering in renderer

---
 xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp |    2 +-
 xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp               |    3 ++-
 xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h                 |    1 +
 3 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
index af706bd..dae3b8e 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
@@ -106,7 +106,7 @@ enum PixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx
     && (avctx->codec_id != CODEC_ID_MPEG4 || g_advancedSettings.m_videoAllowMpeg4VAAPI)) 
     {
       VAAPI::CDecoder* dec = new VAAPI::CDecoder();
-      if(dec->Open(avctx, *cur))
+      if(dec->Open(avctx, *cur, ctx->m_uSurfacesCount))
       {
         ctx->SetHardware(dec);
         return *cur;
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp
index 9f5a960..a2b9195 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp
@@ -357,6 +357,7 @@ bool CDecoder::Open(AVCodecContext *avctx, enum PixelFormat fmt, unsigned int su
   CHECK(vaCreateConfig(m_display->get(), profile, entrypoint, &attrib, 1, &m_hwaccel->config_id))
   m_config = m_hwaccel->config_id;
 
+  m_renderbuffers_count = surfaces;
   if (!EnsureContext(avctx))
     return false;
 
@@ -388,7 +389,7 @@ bool CDecoder::EnsureContext(AVCodecContext *avctx)
     else
       m_refs = 2;
   }
-  return EnsureSurfaces(avctx, m_refs + 3);
+  return EnsureSurfaces(avctx, m_refs + m_renderbuffers_count + 1);
 }
 
 bool CDecoder::EnsureSurfaces(AVCodecContext *avctx, unsigned n_surfaces_count)
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h
index 863edc4..417cbc0 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h
@@ -122,6 +122,7 @@ class CDecoder
   static const unsigned  m_surfaces_max = 32;
   unsigned               m_surfaces_count;
   VASurfaceID            m_surfaces[m_surfaces_max];
+  unsigned               m_renderbuffers_count;
 
   int                    m_refs;
   std::list<CSurfacePtr> m_surfaces_used;
-- 
1.7.10


From 2d199663b2c266c77af4bf9217f2974ca7caabb8 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Sat, 7 Apr 2012 09:19:00 +0200
Subject: [PATCH 11/58] vdpau: redesign

---
 language/English/strings.po                        |   12 +-
 system/shaders/yuv2rgb_basic.glsl                  |   12 +
 xbmc/cores/VideoRenderers/LinuxRendererGL.cpp      |  203 +-
 xbmc/cores/VideoRenderers/LinuxRendererGL.h        |   13 +-
 xbmc/cores/VideoRenderers/RenderFormats.h          |    1 +
 xbmc/cores/VideoRenderers/RenderManager.cpp        |    8 +-
 xbmc/cores/VideoRenderers/RenderManager.h          |    2 +-
 .../VideoRenderers/VideoShaders/YUV2RGBShader.cpp  |    2 +
 .../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h      |    4 +-
 .../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp        |   23 +-
 .../DVDCodecs/Video/DVDVideoCodecFFmpeg.h          |    1 -
 xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp     | 3798 +++++++++++++++-----
 xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h       |  662 +++-
 xbmc/cores/dvdplayer/DVDPlayerVideo.cpp            |    3 +
 xbmc/settings/AdvancedSettings.cpp                 |    8 +-
 xbmc/settings/AdvancedSettings.h                   |    4 +-
 xbmc/settings/GUISettings.cpp                      |    2 +
 xbmc/settings/GUIWindowSettingsCategory.cpp        |   34 +
 xbmc/utils/ActorProtocol.cpp                       |  253 ++
 xbmc/utils/ActorProtocol.h                         |   87 +
 xbmc/utils/Makefile                                |    1 +
 xbmc/video/dialogs/GUIDialogVideoSettings.cpp      |    2 +-
 xbmc/windowing/X11/WinSystemX11.h                  |    1 +
 23 files changed, 3942 insertions(+), 1194 deletions(-)
 create mode 100644 xbmc/utils/ActorProtocol.cpp
 create mode 100644 xbmc/utils/ActorProtocol.h

diff --git a/language/English/strings.po b/language/English/strings.po
index 7d35a93..d046110 100644
--- a/language/English/strings.po
+++ b/language/English/strings.po
@@ -5114,7 +5114,15 @@ msgctxt "#13434"
 msgid "Play only this"
 msgstr ""
 
-#empty strings from id 13435 to 13499
+msgctxt "#13435"
+msgid "Allow Vdpau OpenGL interop"
+msgstr ""
+
+msgctxt "#13436"
+msgid "Allow Vdpau OpenGL interop YUV"
+msgstr ""
+
+#empty strings from id 13437 to 13499
 
 msgctxt "#13500"
 msgid "A/V sync method"
@@ -6333,7 +6341,7 @@ msgid "Software Blend"
 msgstr ""
 
 msgctxt "#16325"
-msgid "Auto - ION Optimized"
+msgid "VDPAU - Bob"
 msgstr ""
 
 #empty strings from id 16326 to 16399
diff --git a/system/shaders/yuv2rgb_basic.glsl b/system/shaders/yuv2rgb_basic.glsl
index 88c33b2..aa26174 100644
--- a/system/shaders/yuv2rgb_basic.glsl
+++ b/system/shaders/yuv2rgb_basic.glsl
@@ -70,6 +70,18 @@ void main()
   rgb.a = gl_Color.a;
   gl_FragColor = rgb;
 
+#elif defined(XBMC_VDPAU_NV12)
+
+  vec4 yuv, rgb;
+  yuv.rgba = vec4( texture2D(m_sampY, stretch(m_cordY)).r
+                 , texture2D(m_sampU, stretch(m_cordU)).r
+                 , texture2D(m_sampV, stretch(m_cordV)).g
+                 , 1.0 );
+
+  rgb   = m_yuvmat * yuv;
+  rgb.a = gl_Color.a;
+  gl_FragColor = rgb;
+
 #elif defined(XBMC_YUY2) || defined(XBMC_UYVY)
 
 #if(XBMC_texture_rectangle)
diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
index 15e5757..685d5c3 100644
--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
@@ -689,6 +689,18 @@ void CLinuxRendererGL::RenderUpdate(bool clear, DWORD flags, DWORD alpha)
     glDisable(GL_POLYGON_STIPPLE);
 
   }
+  else if(m_format == RENDER_FMT_VDPAU_420
+      && !(flags & RENDER_FLAG_BOTH))
+  {
+    glDisable(GL_BLEND);
+    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+    Render(flags | RENDER_FLAG_TOP, index);
+
+    glEnable(GL_BLEND);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    glColor4f(1.0f, 1.0f, 1.0f, 128 / 255.0f);
+    Render(flags | RENDER_FLAG_BOT , index);
+  }
   else
     Render(flags, index);
 
@@ -769,11 +781,6 @@ void CLinuxRendererGL::FlipPage(int source)
 
   m_buffers[m_iYV12RenderBuffer].flipindex = ++m_flipindex;
 
-#ifdef HAVE_LIBVDPAU  
-  if((m_renderMethod & RENDER_VDPAU) && m_buffers[m_iYV12RenderBuffer].vdpau)
-    m_buffers[m_iYV12RenderBuffer].vdpau->Present();
-#endif
-
   return;
 }
 
@@ -1100,6 +1107,12 @@ void CLinuxRendererGL::LoadShaders(int field)
     m_textureCreate = &CLinuxRendererGL::CreateVDPAUTexture;
     m_textureDelete = &CLinuxRendererGL::DeleteVDPAUTexture;
   }
+  else if (m_format == RENDER_FMT_VDPAU_420)
+  {
+    m_textureUpload = &CLinuxRendererGL::UploadVDPAUTexture420;
+    m_textureCreate = &CLinuxRendererGL::CreateVDPAUTexture420;
+    m_textureDelete = &CLinuxRendererGL::DeleteVDPAUTexture420;
+  }
   else if (m_format == RENDER_FMT_VAAPI)
   {
     m_textureUpload = &CLinuxRendererGL::UploadVAAPITexture;
@@ -1175,7 +1188,10 @@ void CLinuxRendererGL::Render(DWORD flags, int renderBuffer)
     m_currentField = FIELD_FULL;
 
   // call texture load function
+  m_skipRender = false;
   (this->*m_textureUpload)(renderBuffer);
+  if (m_skipRender)
+    return;
 
   if (m_renderMethod & RENDER_GLSL)
   {
@@ -1541,17 +1557,12 @@ void CLinuxRendererGL::RenderFromFBO()
 void CLinuxRendererGL::RenderVDPAU(int index, int field)
 {
 #ifdef HAVE_LIBVDPAU
-  YUVPLANE &plane = m_buffers[index].fields[field][0];
-  CVDPAU   *vdpau = m_buffers[m_iYV12RenderBuffer].vdpau;
-
-  if (!vdpau)
-    return;
+  YUVPLANE &plane = m_buffers[index].fields[0][1];
 
   glEnable(m_textureTarget);
   glActiveTextureARB(GL_TEXTURE0);
-  glBindTexture(m_textureTarget, plane.id);
 
-  vdpau->BindPixmap();
+  glBindTexture(m_textureTarget, plane.id);
 
   // Try some clamping or wrapping
   glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@@ -1609,8 +1620,6 @@ void CLinuxRendererGL::RenderVDPAU(int index, int field)
   if (m_pVideoFilterShader)
     m_pVideoFilterShader->Disable();
 
-  vdpau->ReleasePixmap();
-
   glBindTexture (m_textureTarget, 0);
   glDisable(m_textureTarget);
 #endif
@@ -2295,12 +2304,14 @@ void CLinuxRendererGL::DeleteVDPAUTexture(int index)
 {
 #ifdef HAVE_LIBVDPAU
   YUVPLANE &plane = m_buffers[index].fields[0][0];
+  YUVFIELDS &fields = m_buffers[index].fields;
 
   SAFE_RELEASE(m_buffers[index].vdpau);
 
   if(plane.id && glIsTexture(plane.id))
     glDeleteTextures(1, &plane.id);
   plane.id = 0;
+  fields[0][1].id = 0;
 #endif
 }
 
@@ -2334,11 +2345,152 @@ bool CLinuxRendererGL::CreateVDPAUTexture(int index)
 void CLinuxRendererGL::UploadVDPAUTexture(int index)
 {
 #ifdef HAVE_LIBVDPAU
+  VDPAU::CVdpauRenderPicture *vdpau = m_buffers[index].vdpau;
+
+  unsigned int flipindex = m_buffers[index].flipindex;
+  YUVFIELDS &fields = m_buffers[index].fields;
+  YUVPLANE &plane = fields[0][0];
+
+  if (!vdpau || !vdpau->valid)
+  {
+    m_eventTexturesDone[index]->Set();
+    m_skipRender = true;
+    return;
+  }
+
+  fields[0][1].id = vdpau->texture[0];
+
   m_eventTexturesDone[index]->Set();
-  glPixelStorei(GL_UNPACK_ALIGNMENT,1); //what's this for?
 #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();
+#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)
 {
@@ -3281,12 +3433,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;
   }
@@ -3372,14 +3525,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;
@@ -3422,11 +3568,12 @@ void CLinuxRendererGL::UnBindPbo(YUVBUFFER& buff)
 }
 
 #ifdef HAVE_LIBVDPAU
-void CLinuxRendererGL::AddProcessor(CVDPAU* vdpau, int index)
+void CLinuxRendererGL::AddProcessor(VDPAU::CVdpauRenderPicture *vdpau, int index)
 {
   YUVBUFFER &buf = m_buffers[index];
+  VDPAU::CVdpauRenderPicture *pic = vdpau->Acquire();
   SAFE_RELEASE(buf.vdpau);
-  buf.vdpau = (CVDPAU*)vdpau->Acquire();
+  buf.vdpau = pic;
 }
 #endif
 
diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.h b/xbmc/cores/VideoRenderers/LinuxRendererGL.h
index 9f55fcb..3218cd5 100644
--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.h
+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.h
@@ -38,15 +38,14 @@
 
 class CRenderCapture;
 
-class CVDPAU;
 class CBaseTexture;
 namespace Shaders { class BaseYUV2RGBShader; }
 namespace Shaders { class BaseVideoFilterShader; }
 namespace VAAPI   { struct CHolder; }
+namespace VDPAU   { class CVdpauRenderPicture; }
 
 #define NUM_BUFFERS 10
 
-
 #undef ALIGN
 #define ALIGN(value, alignment) (((value)+((alignment)-1))&~((alignment)-1))
 #define CLAMP(a, min, max) ((a) > (max) ? (max) : ( (a) < (min) ? (min) : a ))
@@ -144,7 +143,7 @@ class CLinuxRendererGL : public CBaseRenderer
   virtual unsigned int GetProcessorSize() { return m_NumYV12Buffers; }
 
 #ifdef HAVE_LIBVDPAU
-  virtual void         AddProcessor(CVDPAU* vdpau, int index);
+  virtual void         AddProcessor(VDPAU::CVdpauRenderPicture* vdpau, int index);
 #endif
 #ifdef HAVE_LIBVA
   virtual void         AddProcessor(VAAPI::CHolder& holder, int index);
@@ -195,6 +194,10 @@ class CLinuxRendererGL : public CBaseRenderer
   void DeleteVDPAUTexture(int index);
   bool CreateVDPAUTexture(int index);
 
+  void UploadVDPAUTexture420(int index);
+  void DeleteVDPAUTexture420(int index);
+  bool CreateVDPAUTexture420(int index);
+
   void UploadVAAPITexture(int index);
   void DeleteVAAPITexture(int index);
   bool CreateVAAPITexture(int index);
@@ -221,6 +224,7 @@ class CLinuxRendererGL : public CBaseRenderer
   void RenderSinglePass(int renderBuffer, int field); // single pass glsl renderer
   void RenderSoftware(int renderBuffer, int field);   // single pass s/w yuv2rgb renderer
   void RenderVDPAU(int renderBuffer, int field);      // render using vdpau hardware
+  void RenderVDPAUYV12(int renderBuffer, int field);      // render using vdpau hardware
   void RenderVAAPI(int renderBuffer, int field);      // render using vdpau hardware
 
   struct
@@ -281,7 +285,7 @@ class CLinuxRendererGL : public CBaseRenderer
     GLuint    pbo[MAX_PLANES];
 
 #ifdef HAVE_LIBVDPAU
-    CVDPAU*   vdpau;
+    VDPAU::CVdpauRenderPicture *vdpau;
 #endif
 #ifdef HAVE_LIBVA
     VAAPI::CHolder& vaapi;
@@ -327,6 +331,7 @@ class CLinuxRendererGL : public CBaseRenderer
   bool  m_nonLinStretch;
   bool  m_nonLinStretchGui;
   float m_pixelRatio;
+  bool  m_skipRender;
 };
 
 
diff --git a/xbmc/cores/VideoRenderers/RenderFormats.h b/xbmc/cores/VideoRenderers/RenderFormats.h
index 09f8f5d..0262c60 100644
--- a/xbmc/cores/VideoRenderers/RenderFormats.h
+++ b/xbmc/cores/VideoRenderers/RenderFormats.h
@@ -26,6 +26,7 @@ enum ERenderFormat {
   RENDER_FMT_YUV420P10,
   RENDER_FMT_YUV420P16,
   RENDER_FMT_VDPAU,
+  RENDER_FMT_VDPAU_420,
   RENDER_FMT_NV12,
   RENDER_FMT_UYVY422,
   RENDER_FMT_YUYV422,
diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp
index f19797c..a521680 100644
--- a/xbmc/cores/VideoRenderers/RenderManager.cpp
+++ b/xbmc/cores/VideoRenderers/RenderManager.cpp
@@ -250,8 +250,9 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi
 
   // check if decoder supports buffering
   m_bCodecSupportsBuffering = false;
-//  if (format == RENDER_FMT_VDPAU)
-//    m_bCodecSupportsBuffering = true;
+  if (format == RENDER_FMT_VDPAU ||
+      format == RENDER_FMT_VDPAU_420)
+    m_bCodecSupportsBuffering = true;
 
   bool result = m_pRenderer->Configure(width, height, d_width, d_height, fps, flags, format, extended_format, orientation);
   if(result)
@@ -856,7 +857,8 @@ int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic)
     CDVDCodecUtils::CopyDXVA2Picture(&image, &pic);
   }
 #ifdef HAVE_LIBVDPAU
-  else if(pic.format == RENDER_FMT_VDPAU)
+  else if(pic.format == RENDER_FMT_VDPAU
+       || pic.format == RENDER_FMT_VDPAU_420)
     m_pRenderer->AddProcessor(pic.vdpau, index);
 #endif
 #ifdef HAVE_LIBOPENMAX
diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h
index 9342586..6746957 100644
--- a/xbmc/cores/VideoRenderers/RenderManager.h
+++ b/xbmc/cores/VideoRenderers/RenderManager.h
@@ -35,7 +35,7 @@
 
 namespace DXVA { class CProcessor; }
 namespace VAAPI { class CSurfaceHolder; }
-class CVDPAU;
+namespace VDPAU { class CVdpauRenderPicture; }
 struct DVDVideoPicture;
 
 #define ERRORBUFFSIZE 30
diff --git a/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp b/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp
index 58f26b0..50606eb 100644
--- a/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp
+++ b/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp
@@ -201,6 +201,8 @@ static void CalculateYUVMatrixGL(GLfloat      res[4][4]
     m_defines += "#define XBMC_YUY2\n";
   else if (m_format == RENDER_FMT_UYVY422)
     m_defines += "#define XBMC_UYVY\n";
+  else if (RENDER_FMT_VDPAU_420)
+    m_defines += "#define XBMC_VDPAU_NV12\n";
   else
     CLog::Log(LOGERROR, "GL: BaseYUV2RGBGLSLShader - unsupported format %d", m_format);
 
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
index 5001aac..98d8f89 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
@@ -34,7 +34,7 @@
 
 namespace DXVA { class CSurfaceContext; }
 namespace VAAPI { struct CHolder; }
-class CVDPAU;
+namespace VDPAU { class CVdpauRenderPicture; }
 class COpenMax;
 class COpenMaxVideo;
 struct OpenMaxVideoBuffer;
@@ -55,7 +55,7 @@ struct DVDVideoPicture
       DXVA::CSurfaceContext* context;
     };
     struct {
-      CVDPAU* vdpau;
+      VDPAU::CVdpauRenderPicture* vdpau;
     };
     struct {
       VAAPI::CHolder* vaapi;
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
index dae3b8e..a6e42e5 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
@@ -71,14 +71,14 @@ enum PixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx
   while(*cur != PIX_FMT_NONE)
   {
 #ifdef HAVE_LIBVDPAU
-    if(CVDPAU::IsVDPAUFormat(*cur) && g_guiSettings.GetBool("videoplayer.usevdpau"))
+    if(VDPAU::CDecoder::IsVDPAUFormat(*cur) && g_guiSettings.GetBool("videoplayer.usevdpau"))
     {
       if(ctx->GetHardware())
         return *cur;
         
       CLog::Log(LOGNOTICE,"CDVDVideoCodecFFmpeg::GetFormat - Creating VDPAU(%ix%i)", avctx->width, avctx->height);
-      CVDPAU* vdp = new CVDPAU();
-      if(vdp->Open(avctx, *cur))
+      VDPAU::CDecoder* vdp = new VDPAU::CDecoder();
+      if(vdp->Open(avctx, *cur, ctx->m_uSurfacesCount))
       {
         ctx->SetHardware(vdp);
         return *cur;
@@ -205,14 +205,27 @@ bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options
           continue;
 
         CLog::Log(LOGNOTICE,"CDVDVideoCodecFFmpeg::Open() Creating VDPAU(%ix%i, %d)",hints.width, hints.height, hints.codec);
-        CVDPAU* vdp = new CVDPAU();
+
+        VDPAU::CDecoder* vdp = new VDPAU::CDecoder();
         m_pCodecContext = m_dllAvCodec.avcodec_alloc_context3(pCodec);
         m_pCodecContext->codec_id = hints.codec;
         m_pCodecContext->width    = hints.width;
         m_pCodecContext->height   = hints.height;
         m_pCodecContext->coded_width   = hints.width;
         m_pCodecContext->coded_height  = hints.height;
-        if(vdp->Open(m_pCodecContext, pCodec->pix_fmts ? pCodec->pix_fmts[0] : PIX_FMT_NONE))
+
+        // check number of surfaces used in renderer
+        unsigned int surfaces = 0;
+        for(std::vector<CDVDCodecOption>::iterator it = options.m_keys.begin(); it != options.m_keys.end(); it++)
+        {
+          if (it->m_name == "surfaces")
+          {
+            surfaces = std::atoi(it->m_value.c_str());
+            break;
+          }
+        }
+
+        if(vdp->Open(m_pCodecContext, pCodec->pix_fmts ? pCodec->pix_fmts[0] : PIX_FMT_NONE, surfaces))
         {
           m_pHardware = vdp;
           m_pCodecContext->codec_id = CODEC_ID_NONE; // ffmpeg will complain if this has been set
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h
index 52e1113..bf4367c 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h
@@ -28,7 +28,6 @@
 #include "DllSwScale.h"
 #include "DllAvFilter.h"
 
-class CVDPAU;
 class CCriticalSection;
 
 class CDVDVideoCodecFFmpeg : public CDVDVideoCodec
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp
index f70a4f9..235f565 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp
@@ -32,11 +32,16 @@
 #include "settings/AdvancedSettings.h"
 #include "Application.h"
 #include "utils/MathUtils.h"
+#include "utils/TimeUtils.h"
 #include "DVDCodecs/DVDCodecUtils.h"
+#include "cores/VideoRenderers/RenderFlags.h"
+
+using namespace VDPAU;
+#define NUM_RENDER_PICS 9
 
 #define ARSIZE(x) (sizeof(x) / sizeof((x)[0]))
 
-CVDPAU::Desc decoder_profiles[] = {
+CDecoder::Desc decoder_profiles[] = {
 {"MPEG1",        VDP_DECODER_PROFILE_MPEG1},
 {"MPEG2_SIMPLE", VDP_DECODER_PROFILE_MPEG2_SIMPLE},
 {"MPEG2_MAIN",   VDP_DECODER_PROFILE_MPEG2_MAIN},
@@ -50,14 +55,16 @@
 {"MPEG4_PART2_ASP", VDP_DECODER_PROFILE_MPEG4_PART2_ASP},
 #endif
 };
-const size_t decoder_profile_count = sizeof(decoder_profiles)/sizeof(CVDPAU::Desc);
+const size_t decoder_profile_count = sizeof(decoder_profiles)/sizeof(CDecoder::Desc);
 
-static float studioCSC[3][4] =
-{
-    { 1.0f,        0.0f, 1.57480000f,-0.78740000f},
-    { 1.0f,-0.18737736f,-0.46813736f, 0.32775736f},
-    { 1.0f, 1.85556000f,        0.0f,-0.92780000f}
-};
+//static float studioCSC[3][4] =
+//{
+//    { 1.0f,        0.0f, 1.57480000f,-0.78740000f},
+//    { 1.0f,-0.18737736f,-0.46813736f, 0.32775736f},
+//    { 1.0f, 1.85556000f,        0.0f,-0.92780000f}
+//};
+static float studioCSCKCoeffs601[3] = {0.299, 0.587, 0.114};  //BT601 {Kr, Kg, Kb}
+static float studioCSCKCoeffs709[3] = {0.2126, 0.7152, 0.0722};  //BT709 {Kr, Kg, Kb}
 
 static struct SInterlaceMapping
 {
@@ -68,88 +75,30 @@
 , {VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF        , VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL}
 , {VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL     , VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL}
 , {VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF, VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL}
-, {VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE     , VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE} 
+, {VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE     , VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE}
 , {VS_INTERLACEMETHOD_NONE                       , (VdpVideoMixerFeature)-1}
 };
 
 //since libvdpau 0.4, vdp_device_create_x11() installs a callback on the Display*,
 //if we unload libvdpau with dlclose(), we segfault on XCloseDisplay,
 //so we just keep a static handle to libvdpau around
-void* CVDPAU::dl_handle;
+void* CDecoder::dl_handle;
+
+//-----------------------------------------------------------------------------
+// CVDPAU
+//-----------------------------------------------------------------------------
 
-CVDPAU::CVDPAU()
+CDecoder::CDecoder() : m_vdpauOutput(&m_inMsgEvent)
 {
-  glXBindTexImageEXT = NULL;
-  glXReleaseTexImageEXT = NULL;
-  vdp_device = VDP_INVALID_HANDLE;
-  surfaceNum      = presentSurfaceNum = 0;
-  picAge.b_age    = picAge.ip_age[0] = picAge.ip_age[1] = 256*256*256*64;
-  vdpauConfigured = false;
-  m_DisplayState = VDPAU_OPEN;
-  m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
-  m_mixerstep  = 0;
+  m_vdpauConfig.vdpDevice = VDP_INVALID_HANDLE;
+  m_vdpauConfig.videoSurfaces = &m_videoSurfaces;
+  m_vdpauConfig.videoSurfaceSec = &m_videoSurfaceSec;
 
-  m_glPixmap = 0;
-  m_Pixmap = 0;
-  if (!glXBindTexImageEXT)
-    glXBindTexImageEXT    = (PFNGLXBINDTEXIMAGEEXTPROC)glXGetProcAddress((GLubyte *) "glXBindTexImageEXT");
-  if (!glXReleaseTexImageEXT)
-    glXReleaseTexImageEXT = (PFNGLXRELEASETEXIMAGEEXTPROC)glXGetProcAddress((GLubyte *) "glXReleaseTexImageEXT");
+  m_vdpauConfigured = false;
+  m_DisplayState = VDPAU_OPEN;
+}
 
-  totalAvailableOutputSurfaces = 0;
-  outputSurface = presentSurface = VDP_INVALID_HANDLE;
-  vdp_flip_target = VDP_INVALID_HANDLE;
-  vdp_flip_queue = VDP_INVALID_HANDLE;
-  vid_width = vid_height = OutWidth = OutHeight = 0;
-  surface_width = surface_height = 0;
-  
-  memset(&decoder, 0, sizeof(decoder));
-  memset(&outRect, 0, sizeof(outRect));
-  memset(&outRectVid, 0, sizeof(outRectVid));
-
-  m_Display = NULL;
-
-  tmpBrightness  = 0;
-  tmpContrast    = 0;
-  tmpDeintMode   = 0;
-  tmpDeintGUI    = 0;
-  tmpDeint       = 0;
-  max_references = 0;
-
-  for (int i = 0; i < NUM_OUTPUT_SURFACES; i++)
-    outputSurfaces[i] = VDP_INVALID_HANDLE;
-
-  videoMixer = VDP_INVALID_HANDLE;
-  m_BlackBar = NULL;
-
-  memset(m_features, 0, sizeof(m_features));
-  m_feature_count = 0;
-  m_vdpauOutputMethod = OUTPUT_NONE;
-
-  upScale = g_advancedSettings.m_videoVDPAUScaling;
-
-  vdp_video_mixer_set_attribute_values = NULL;
-  vdp_generate_csc_matrix = NULL;
-  vdp_presentation_queue_target_destroy = NULL;
-  vdp_presentation_queue_create = NULL;
-  vdp_presentation_queue_destroy = NULL;
-  vdp_presentation_queue_display = NULL;
-  vdp_presentation_queue_block_until_surface_idle = NULL;
-  vdp_presentation_queue_target_create_x11 = NULL;
-  vdp_presentation_queue_query_surface_status = NULL;
-  vdp_presentation_queue_get_time = NULL;
-  vdp_get_error_string = NULL;
-  vdp_decoder_create = NULL;
-  vdp_decoder_destroy = NULL;
-  vdp_decoder_render = NULL;
-  vdp_decoder_query_caps = NULL;
-  vdp_preemption_callback_register = NULL;
-  dl_vdp_device_create_x11 = NULL;
-  dl_vdp_get_proc_address = NULL;
-  dl_vdp_preemption_callback_register = NULL;
-}
-
-bool CVDPAU::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int surfaces)
+bool CDecoder::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int surfaces)
 {
   if(avctx->coded_width  == 0
   || avctx->coded_height == 0)
@@ -157,6 +106,8 @@ bool CVDPAU::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int su
     CLog::Log(LOGWARNING,"(VDPAU) no width/height available, can't init");
     return false;
   }
+  m_vdpauConfig.numRenderBuffers = surfaces;
+  m_decoderThread = CThread::GetCurrentThreadId();
 
   if (!dl_handle)
   {
@@ -168,8 +119,6 @@ bool CVDPAU::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int su
         error = "dlerror() returned NULL";
 
       CLog::Log(LOGNOTICE,"(VDPAU) Unable to get handle to libvdpau: %s", error);
-      //g_application.m_guiDialogKaiToast.QueueNotification(CGUIDialogKaiToast::Error, "VDPAU", error, 10000);
-
       return false;
     }
   }
@@ -178,8 +127,9 @@ bool CVDPAU::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int su
     return false;
 
   InitVDPAUProcs();
+  m_presentPicture = 0;
 
-  if (vdp_device != VDP_INVALID_HANDLE)
+  if (m_vdpauConfig.vdpDevice != VDP_INVALID_HANDLE)
   {
     SpewHardwareAvailable();
 
@@ -197,25 +147,23 @@ bool CVDPAU::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int su
    
       /* attempt to create a decoder with this width/height, some sizes are not supported by hw */
       VdpStatus vdp_st;
-      vdp_st = vdp_decoder_create(vdp_device, profile, avctx->coded_width, avctx->coded_height, 5, &decoder);
+      vdp_st = m_vdpauConfig.vdpProcs.vdp_decoder_create(m_vdpauConfig.vdpDevice, profile, avctx->coded_width, avctx->coded_height, 5, &m_vdpauConfig.vdpDecoder);
 
       if(vdp_st != VDP_STATUS_OK)
       {
-        CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) checking for decoder support\n", vdp_get_error_string(vdp_st), vdp_st);
+        CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) checking for decoder support\n", m_vdpauConfig.vdpProcs.vdp_get_error_string(vdp_st), vdp_st);
         FiniVDPAUProcs();
         return false;
       }
 
-      vdp_decoder_destroy(decoder);
+      m_vdpauConfig.vdpProcs.vdp_decoder_destroy(m_vdpauConfig.vdpDecoder);
       CheckStatus(vdp_st, __LINE__);
     }
 
-    InitCSCMatrix(avctx->coded_height);
-
     /* finally setup ffmpeg */
-    avctx->get_buffer      = CVDPAU::FFGetBuffer;
-    avctx->release_buffer  = CVDPAU::FFReleaseBuffer;
-    avctx->draw_horiz_band = CVDPAU::FFDrawSlice;
+    avctx->get_buffer      = CDecoder::FFGetBuffer;
+    avctx->release_buffer  = CDecoder::FFReleaseBuffer;
+    avctx->draw_horiz_band = CDecoder::FFDrawSlice;
     avctx->slice_flags=SLICE_FLAG_CODED_ORDER|SLICE_FLAG_ALLOW_FIELD;
 
     g_Windowing.Register(this);
@@ -224,17 +172,20 @@ bool CVDPAU::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int su
   return false;
 }
 
-CVDPAU::~CVDPAU()
+CDecoder::~CDecoder()
 {
   Close();
 }
 
-void CVDPAU::Close()
+void CDecoder::Close()
 {
   CLog::Log(LOGNOTICE, " (VDPAU) %s", __FUNCTION__);
 
+  CSingleLock lock(m_DecoderSection);
+
   FiniVDPAUOutput();
   FiniVDPAUProcs();
+  m_vdpauOutput.Dispose();
 
   while (!m_videoSurfaces.empty())
   {
@@ -250,188 +201,111 @@ void CVDPAU::Close()
   m_dllAvUtil.Unload();
 }
 
-bool CVDPAU::MakePixmapGL()
+long CDecoder::Release()
 {
-  int num=0;
-  int fbConfigIndex = 0;
-
-  int doubleVisAttributes[] = {
-    GLX_RENDER_TYPE, GLX_RGBA_BIT,
-    GLX_RED_SIZE, 8,
-    GLX_GREEN_SIZE, 8,
-    GLX_BLUE_SIZE, 8,
-    GLX_ALPHA_SIZE, 8,
-    GLX_DEPTH_SIZE, 8,
-    GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
-    GLX_BIND_TO_TEXTURE_RGBA_EXT, True,
-    GLX_DOUBLEBUFFER, True,
-    GLX_Y_INVERTED_EXT, True,
-    GLX_X_RENDERABLE, True,
-    None
-  };
-
-  int pixmapAttribs[] = {
-    GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
-    GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT,
-    None
-  };
-
-  GLXFBConfig *fbConfigs;
-  fbConfigs = glXChooseFBConfig(m_Display, DefaultScreen(m_Display), doubleVisAttributes, &num);
-  if (fbConfigs==NULL)
+  // check if we should do some pre-cleanup here
+  // a second decoder might need resources
+  if (m_vdpauConfigured == true)
   {
-    CLog::Log(LOGERROR, "GLX Error: MakePixmap: No compatible framebuffers found");
-    return false;
-  }
-  CLog::Log(LOGDEBUG, "Found %d fbconfigs.", num);
-  fbConfigIndex = 0;
-  CLog::Log(LOGDEBUG, "Using fbconfig index %d.", fbConfigIndex);
+    CSingleLock lock(m_DecoderSection);
+    CLog::Log(LOGNOTICE,"CVDPAU::Release pre-cleanup");
 
-  m_glPixmap = glXCreatePixmap(m_Display, fbConfigs[fbConfigIndex], m_Pixmap, pixmapAttribs);
+    Message *reply;
+    if (m_vdpauOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::PRECLEANUP,
+                                                   &reply,
+                                                   2000))
+    {
+      bool success = reply->signal == COutputControlProtocol::ACC ? true : false;
+      reply->Release();
+      if (!success)
+      {
+        CLog::Log(LOGERROR, "VDPAU::%s - pre-cleanup returned error", __FUNCTION__);
+        m_DisplayState = VDPAU_ERROR;
+      }
+    }
+    else
+    {
+      CLog::Log(LOGERROR, "VDPAU::%s - pre-cleanup timed out", __FUNCTION__);
+      m_DisplayState = VDPAU_ERROR;
+    }
 
-  if (!m_glPixmap)
-  {
-    CLog::Log(LOGINFO, "GLX Error: Could not create Pixmap");
-    XFree(fbConfigs);
-    return false;
+    for(unsigned int i = 0; i < m_videoSurfaces.size(); ++i)
+    {
+      vdpau_render_state *render = m_videoSurfaces[i];
+      if (render->surface != VDP_INVALID_HANDLE && !(render->state & FF_VDPAU_STATE_USED_FOR_RENDER))
+      {
+        m_vdpauConfig.vdpProcs.vdp_video_surface_destroy(render->surface);
+        render->surface = VDP_INVALID_HANDLE;
+      }
+    }
   }
-  XFree(fbConfigs);
+  IHardwareDecoder::Release();
+}
 
-  return true;
+long CDecoder::ReleasePicReference()
+{
+  return IHardwareDecoder::Release();
 }
 
-bool CVDPAU::MakePixmap(int width, int height)
+void CDecoder::SetWidthHeight(int width, int height)
 {
+  m_vdpauConfig.upscale = g_advancedSettings.m_videoVDPAUScaling;
+
   //pick the smallest dimensions, so we downscale with vdpau and upscale with opengl when appropriate
   //this requires the least amount of gpu memory bandwidth
-  if (g_graphicsContext.GetWidth() < width || g_graphicsContext.GetHeight() < height || upScale)
+  if (g_graphicsContext.GetWidth() < width || g_graphicsContext.GetHeight() < height || m_vdpauConfig.upscale >= 0)
   {
     //scale width to desktop size if the aspect ratio is the same or bigger than the desktop
     if ((double)height * g_graphicsContext.GetWidth() / width <= (double)g_graphicsContext.GetHeight())
     {
-      OutWidth = g_graphicsContext.GetWidth();
-      OutHeight = MathUtils::round_int((double)height * g_graphicsContext.GetWidth() / width);
+      m_vdpauConfig.outWidth = g_graphicsContext.GetWidth();
+      m_vdpauConfig.outHeight = MathUtils::round_int((double)height * g_graphicsContext.GetWidth() / width);
     }
     else //scale height to the desktop size if the aspect ratio is smaller than the desktop
     {
-      OutHeight = g_graphicsContext.GetHeight();
-      OutWidth = MathUtils::round_int((double)width * g_graphicsContext.GetHeight() / height);
+      m_vdpauConfig.outHeight = g_graphicsContext.GetHeight();
+      m_vdpauConfig.outWidth = MathUtils::round_int((double)width * g_graphicsContext.GetHeight() / height);
     }
   }
   else
   { //let opengl scale
-    OutWidth = width;
-    OutHeight = height;
-  }
-
-  CLog::Log(LOGNOTICE,"Creating %ix%i pixmap", OutWidth, OutHeight);
-
-    // Get our window attribs.
-  XWindowAttributes wndattribs;
-  XGetWindowAttributes(m_Display, DefaultRootWindow(m_Display), &wndattribs); // returns a status but I don't know what success is
-
-  m_Pixmap = XCreatePixmap(m_Display,
-                           DefaultRootWindow(m_Display),
-                           OutWidth,
-                           OutHeight,
-                           wndattribs.depth);
-  if (!m_Pixmap)
-  {
-    CLog::Log(LOGERROR, "GLX Error: MakePixmap: Unable to create XPixmap");
-    return false;
-  }
-
-  XGCValues values = {};
-  GC xgc;
-  values.foreground = BlackPixel (m_Display, DefaultScreen (m_Display));
-  xgc = XCreateGC(m_Display, m_Pixmap, GCForeground, &values);
-  XFillRectangle(m_Display, m_Pixmap, xgc, 0, 0, OutWidth, OutHeight);
-  XFreeGC(m_Display, xgc);
-
-  if(!MakePixmapGL())
-    return false;
-
-  return true;
-}
-
-void CVDPAU::BindPixmap()
-{
-  CSharedLock lock(m_DecoderSection);
-
-  { CSharedLock dLock(m_DisplaySection);
-    if (m_DisplayState != VDPAU_OPEN)
-      return;
-  }
-
-  if (m_glPixmap)
-  {
-    if(presentSurface != VDP_INVALID_HANDLE)
-    {
-      VdpPresentationQueueStatus status;
-      VdpTime time;
-      VdpStatus vdp_st;
-      vdp_st = vdp_presentation_queue_query_surface_status(
-                    vdp_flip_queue, presentSurface, &status, &time);
-      CheckStatus(vdp_st, __LINE__);
-      while(status != VDP_PRESENTATION_QUEUE_STATUS_VISIBLE && vdp_st == VDP_STATUS_OK)
-      {
-        Sleep(1);
-        vdp_st = vdp_presentation_queue_query_surface_status(
-                      vdp_flip_queue, presentSurface, &status, &time);
-        CheckStatus(vdp_st, __LINE__);
-      }
-    }
-    
-    glXBindTexImageEXT(m_Display, m_glPixmap, GLX_FRONT_LEFT_EXT, NULL);
-  }
-  else CLog::Log(LOGERROR,"(VDPAU) BindPixmap called without valid pixmap");
-}
-
-void CVDPAU::ReleasePixmap()
-{
-  CSharedLock lock(m_DecoderSection);
-
-  { CSharedLock dLock(m_DisplaySection);
-    if (m_DisplayState != VDPAU_OPEN)
-      return;
-  }
-
-  if (m_glPixmap)
-  {
-    glXReleaseTexImageEXT(m_Display, m_glPixmap, GLX_FRONT_LEFT_EXT);
+    m_vdpauConfig.outWidth = width;
+    m_vdpauConfig.outHeight = height;
   }
-  else CLog::Log(LOGERROR,"(VDPAU) ReleasePixmap called without valid pixmap");
+  CLog::Log(LOGDEBUG, "CVDPAU::SetWidthHeight Setting OutWidth: %i OutHeight: %i", m_vdpauConfig.outWidth, m_vdpauConfig.outHeight);
 }
 
-void CVDPAU::OnLostDevice()
+void CDecoder::OnLostDevice()
 {
   CLog::Log(LOGNOTICE,"CVDPAU::OnLostDevice event");
 
-  CExclusiveLock lock(m_DecoderSection);
+  CSingleLock lock(m_DecoderSection);
   FiniVDPAUOutput();
   FiniVDPAUProcs();
 
   m_DisplayState = VDPAU_LOST;
+  lock.Leave();
   m_DisplayEvent.Reset();
 }
 
-void CVDPAU::OnResetDevice()
+void CDecoder::OnResetDevice()
 {
   CLog::Log(LOGNOTICE,"CVDPAU::OnResetDevice event");
 
-  CExclusiveLock lock(m_DisplaySection);
+  CSingleLock lock(m_DecoderSection);
   if (m_DisplayState == VDPAU_LOST)
   {
     m_DisplayState = VDPAU_RESET;
+    lock.Leave();
     m_DisplayEvent.Set();
   }
 }
 
-int CVDPAU::Check(AVCodecContext* avctx)
+int CDecoder::Check(AVCodecContext* avctx)
 {
   EDisplayState state;
 
-  { CSharedLock lock(m_DisplaySection);
+  { CSingleLock lock(m_DecoderSection);
     state = m_DisplayState;
   }
 
@@ -445,16 +319,13 @@ int CVDPAU::Check(AVCodecContext* avctx)
     }
     else
     {
-      CSharedLock lock(m_DisplaySection);
+      CSingleLock lock(m_DecoderSection);
       state = m_DisplayState;
     }
   }
   if (state == VDPAU_RESET || state == VDPAU_ERROR)
   {
-    CLog::Log(LOGNOTICE,"Attempting recovery");
-
-    CSingleLock gLock(g_graphicsContext);
-    CExclusiveLock lock(m_DecoderSection);
+    CSingleLock lock(m_DecoderSection);
 
     FiniVDPAUOutput();
     FiniVDPAUProcs();
@@ -469,7 +340,7 @@ int CVDPAU::Check(AVCodecContext* avctx)
   return 0;
 }
 
-bool CVDPAU::IsVDPAUFormat(PixelFormat format)
+bool CDecoder::IsVDPAUFormat(PixelFormat format)
 {
   if ((format >= PIX_FMT_VDPAU_H264) && (format <= PIX_FMT_VDPAU_VC1)) return true;
 #if (defined PIX_FMT_VDPAU_MPEG4_IN_AVUTIL)
@@ -478,91 +349,28 @@ bool CVDPAU::IsVDPAUFormat(PixelFormat format)
   else return false;
 }
 
-void CVDPAU::CheckFeatures()
-{
-  if (videoMixer == VDP_INVALID_HANDLE)
-  {
-    CLog::Log(LOGNOTICE, " (VDPAU) Creating the video mixer");
-    // Creation of VideoMixer.
-    VdpVideoMixerParameter parameters[] = {
-      VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH,
-      VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT,
-      VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE
-    };
-
-    void const * parameter_values[] = {
-      &surface_width,
-      &surface_height,
-      &vdp_chroma_type
-    };
-
-    tmpBrightness = 0;
-    tmpContrast = 0;
-    tmpNoiseReduction = 0;
-    tmpSharpness = 0;
-
-    VdpStatus vdp_st = VDP_STATUS_ERROR;
-    vdp_st = vdp_video_mixer_create(vdp_device,
-                                    m_feature_count,
-                                    m_features,
-                                    ARSIZE(parameters),
-                                    parameters,
-                                    parameter_values,
-                                    &videoMixer);
-    CheckStatus(vdp_st, __LINE__);
-
-    SetHWUpscaling();
-  }
-
-  if (tmpBrightness != g_settings.m_currentVideoSettings.m_Brightness ||
-      tmpContrast   != g_settings.m_currentVideoSettings.m_Contrast)
-  {
-    SetColor();
-    tmpBrightness = g_settings.m_currentVideoSettings.m_Brightness;
-    tmpContrast = g_settings.m_currentVideoSettings.m_Contrast;
-  }
-  if (tmpNoiseReduction != g_settings.m_currentVideoSettings.m_NoiseReduction)
-  {
-    tmpNoiseReduction = g_settings.m_currentVideoSettings.m_NoiseReduction;
-    SetNoiseReduction();
-  }
-  if (tmpSharpness != g_settings.m_currentVideoSettings.m_Sharpness)
-  {
-    tmpSharpness = g_settings.m_currentVideoSettings.m_Sharpness;
-    SetSharpness();
-  }
-  if (  tmpDeintMode != g_settings.m_currentVideoSettings.m_DeinterlaceMode ||
-        tmpDeintGUI  != g_settings.m_currentVideoSettings.m_InterlaceMethod ||
-       (tmpDeintGUI == VS_INTERLACEMETHOD_AUTO && tmpDeint != AutoInterlaceMethod()))
-  {
-    tmpDeintMode = g_settings.m_currentVideoSettings.m_DeinterlaceMode;
-    tmpDeintGUI  = g_settings.m_currentVideoSettings.m_InterlaceMethod;
-    if (tmpDeintGUI == VS_INTERLACEMETHOD_AUTO)
-      tmpDeint = AutoInterlaceMethod();
-    else
-      tmpDeint = tmpDeintGUI;
-
-    SetDeinterlacing();
-  }
-}
-
-bool CVDPAU::Supports(VdpVideoMixerFeature feature)
+bool CDecoder::Supports(VdpVideoMixerFeature feature)
 {
-  for(int i = 0; i < m_feature_count; i++)
+  for(int i = 0; i < m_vdpauConfig.featureCount; i++)
   {
-    if(m_features[i] == feature)
+    if(m_vdpauConfig.vdpFeatures[i] == feature)
       return true;
   }
   return false;
 }
 
-bool CVDPAU::Supports(EINTERLACEMETHOD method)
+bool CDecoder::Supports(EINTERLACEMETHOD method)
 {
   if(method == VS_INTERLACEMETHOD_VDPAU_BOB
-  || method == VS_INTERLACEMETHOD_AUTO
-  || method == VS_INTERLACEMETHOD_AUTO_ION)
+  || method == VS_INTERLACEMETHOD_AUTO)
     return true;
 
+  if (g_guiSettings.GetBool("videoplayer.usevdpauinteropyuv"))
+  {
+    if (method == VS_INTERLACEMETHOD_RENDER_BOB)
+      return true;
+  }
+
   for(SInterlaceMapping* p = g_interlace_mapping; p->method != VS_INTERLACEMETHOD_NONE; p++)
   {
     if(p->method == method)
@@ -571,162 +379,12 @@ bool CVDPAU::Supports(EINTERLACEMETHOD method)
   return false;
 }
 
-EINTERLACEMETHOD CVDPAU::AutoInterlaceMethod()
-{
-  return VS_INTERLACEMETHOD_VDPAU_TEMPORAL;
-}
-
-void CVDPAU::SetColor()
-{
-  VdpStatus vdp_st;
-
-  if (tmpBrightness != g_settings.m_currentVideoSettings.m_Brightness)
-    m_Procamp.brightness = (float)((g_settings.m_currentVideoSettings.m_Brightness)-50) / 100;
-  if (tmpContrast != g_settings.m_currentVideoSettings.m_Contrast)
-    m_Procamp.contrast = (float)((g_settings.m_currentVideoSettings.m_Contrast)+50) / 100;
-
-  if(vid_height >= 600 || vid_width > 1024)
-    vdp_st = vdp_generate_csc_matrix(&m_Procamp, VDP_COLOR_STANDARD_ITUR_BT_709, &m_CSCMatrix);
-  else
-    vdp_st = vdp_generate_csc_matrix(&m_Procamp, VDP_COLOR_STANDARD_ITUR_BT_601, &m_CSCMatrix);
-
-  VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX };
-  if (g_guiSettings.GetBool("videoplayer.vdpaustudiolevel"))
-  {
-    void const * pm_CSCMatix[] = { &studioCSC };
-    vdp_st = vdp_video_mixer_set_attribute_values(videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix);
-  }
-  else
-  {
-    void const * pm_CSCMatix[] = { &m_CSCMatrix };
-    vdp_st = vdp_video_mixer_set_attribute_values(videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix);
-  }
-  CheckStatus(vdp_st, __LINE__);
-}
-
-void CVDPAU::SetNoiseReduction()
-{
-  if(!Supports(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION))
-    return;
-
-  VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION };
-  VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL };
-  VdpStatus vdp_st;
-
-  if (!g_settings.m_currentVideoSettings.m_NoiseReduction)
-  {
-    VdpBool enabled[]= {0};
-    vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
-    CheckStatus(vdp_st, __LINE__);
-    return;
-  }
-  VdpBool enabled[]={1};
-  vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
-  CheckStatus(vdp_st, __LINE__);
-  void* nr[] = { &g_settings.m_currentVideoSettings.m_NoiseReduction };
-  CLog::Log(LOGNOTICE,"Setting Noise Reduction to %f",g_settings.m_currentVideoSettings.m_NoiseReduction);
-  vdp_st = vdp_video_mixer_set_attribute_values(videoMixer, ARSIZE(attributes), attributes, nr);
-  CheckStatus(vdp_st, __LINE__);
-}
-
-void CVDPAU::SetSharpness()
-{
-  if(!Supports(VDP_VIDEO_MIXER_FEATURE_SHARPNESS))
-    return;
-  
-  VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_SHARPNESS };
-  VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL };
-  VdpStatus vdp_st;
-
-  if (!g_settings.m_currentVideoSettings.m_Sharpness)
-  {
-    VdpBool enabled[]={0};
-    vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
-    CheckStatus(vdp_st, __LINE__);
-    return;
-  }
-  VdpBool enabled[]={1};
-  vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
-  CheckStatus(vdp_st, __LINE__);
-  void* sh[] = { &g_settings.m_currentVideoSettings.m_Sharpness };
-  CLog::Log(LOGNOTICE,"Setting Sharpness to %f",g_settings.m_currentVideoSettings.m_Sharpness);
-  vdp_st = vdp_video_mixer_set_attribute_values(videoMixer, ARSIZE(attributes), attributes, sh);
-  CheckStatus(vdp_st, __LINE__);
-}
-
-void CVDPAU::SetHWUpscaling()
-{
-#ifdef VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
-  if(!Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1) || !upScale)
-    return;
-
-  VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 };
-  VdpStatus vdp_st;
-  VdpBool enabled[]={1};
-  vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
-  CheckStatus(vdp_st, __LINE__);
-#endif
-}
-
-void CVDPAU::SetDeinterlacing()
+EINTERLACEMETHOD CDecoder::AutoInterlaceMethod()
 {
-  VdpStatus vdp_st;
-  EDEINTERLACEMODE   mode = g_settings.m_currentVideoSettings.m_DeinterlaceMode;
-  EINTERLACEMETHOD method = g_settings.m_currentVideoSettings.m_InterlaceMethod;
-  if (method == VS_INTERLACEMETHOD_AUTO)
-    method = AutoInterlaceMethod();
-
-  VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL,
-                                     VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL,
-                                     VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE };
-  if (mode == VS_DEINTERLACEMODE_OFF)
-  {
-    VdpBool enabled[]={0,0,0};
-    vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
-  }
-  else
-  {
-    if (method == VS_INTERLACEMETHOD_AUTO_ION)
-    {
-      if (vid_height <= 576)
-      {
-        VdpBool enabled[]={1,1,0};
-        vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
-      }
-      else if (vid_height > 576)
-      {
-        VdpBool enabled[]={1,0,0};
-        vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
-      }
-    }
-    else if (method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL
-         ||  method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF)
-    {
-      VdpBool enabled[]={1,0,0};
-      vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
-    }
-    else if (method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL
-         ||  method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF)
-    {
-      VdpBool enabled[]={1,1,0};
-      vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
-    }
-    else if (method == VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE)
-    {
-      VdpBool enabled[]={1,0,1};
-      vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
-    }
-    else
-    {
-      VdpBool enabled[]={0,0,0};
-      vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
-    }
-  }
-
-  CheckStatus(vdp_st, __LINE__);
+  return VS_INTERLACEMETHOD_RENDER_BOB;
 }
 
-void CVDPAU::InitVDPAUProcs()
+void CDecoder::InitVDPAUProcs()
 {
   char* error;
 
@@ -736,151 +394,115 @@ void CVDPAU::InitVDPAUProcs()
   if (error)
   {
     CLog::Log(LOGERROR,"(VDPAU) - %s in %s",error,__FUNCTION__);
-    vdp_device = VDP_INVALID_HANDLE;
-
-    //g_application.m_guiDialogKaiToast.QueueNotification(CGUIDialogKaiToast::Error, "VDPAU", error, 10000);
-
+    m_vdpauConfig.vdpDevice = VDP_INVALID_HANDLE;
     return;
   }
 
   if (dl_vdp_device_create_x11)
   {
-    CSingleLock lock(g_graphicsContext);
-    m_Display = g_Windowing.GetDisplay();
-  }
-  else
-  {
-    CLog::Log(LOGERROR,"(VDPAU) - Unable to get dl_vdp_device_create_x11 in %s", __FUNCTION__);
-    vdp_device = VDP_INVALID_HANDLE;
-    return;
+    m_Display = XOpenDisplay(NULL);
   }
 
-  int mScreen = DefaultScreen(m_Display);
+  int mScreen = g_Windowing.GetCurrentScreen();
   VdpStatus vdp_st;
 
   // Create Device
-  // tested on 64bit Ubuntu 11.10 and it deadlocked without this
-  XLockDisplay(m_Display);
   vdp_st = dl_vdp_device_create_x11(m_Display, //x_display,
                                  mScreen, //x_screen,
-                                 &vdp_device,
-                                 &vdp_get_proc_address);
-  XUnlockDisplay(m_Display);
+                                 &m_vdpauConfig.vdpDevice,
+                                 &m_vdpauConfig.vdpProcs.vdp_get_proc_address);
 
-  CLog::Log(LOGNOTICE,"vdp_device = 0x%08x vdp_st = 0x%08x",vdp_device,vdp_st);
+  CLog::Log(LOGNOTICE,"vdp_device = 0x%08x vdp_st = 0x%08x",m_vdpauConfig.vdpDevice,vdp_st);
   if (vdp_st != VDP_STATUS_OK)
   {
     CLog::Log(LOGERROR,"(VDPAU) unable to init VDPAU - vdp_st = 0x%x.  Falling back.",vdp_st);
-    vdp_device = VDP_INVALID_HANDLE;
+    m_vdpauConfig.vdpDevice = VDP_INVALID_HANDLE;
     return;
   }
 
 #define VDP_PROC(id, proc) \
   do { \
-    vdp_st = vdp_get_proc_address(vdp_device, id, (void**)&proc); \
+    vdp_st = m_vdpauConfig.vdpProcs.vdp_get_proc_address(m_vdpauConfig.vdpDevice, id, (void**)&proc); \
     CheckStatus(vdp_st, __LINE__); \
   } while(0);
 
-  VDP_PROC(VDP_FUNC_ID_GET_ERROR_STRING                    , vdp_get_error_string);
-  VDP_PROC(VDP_FUNC_ID_DEVICE_DESTROY                      , vdp_device_destroy);
-  VDP_PROC(VDP_FUNC_ID_GENERATE_CSC_MATRIX                 , vdp_generate_csc_matrix);
-  VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_CREATE                , vdp_video_surface_create);
-  VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_DESTROY               , vdp_video_surface_destroy);
-  VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_PUT_BITS_Y_CB_CR      , vdp_video_surface_put_bits_y_cb_cr);
-  VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR      , vdp_video_surface_get_bits_y_cb_cr);
-  VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_Y_CB_CR     , vdp_output_surface_put_bits_y_cb_cr);
-  VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_NATIVE      , vdp_output_surface_put_bits_native);
-  VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_CREATE               , vdp_output_surface_create);
-  VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_DESTROY              , vdp_output_surface_destroy);
-  VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_GET_BITS_NATIVE      , vdp_output_surface_get_bits_native);
-  VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_OUTPUT_SURFACE, vdp_output_surface_render_output_surface);
-  VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_INDEXED     , vdp_output_surface_put_bits_indexed);  
-  VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_CREATE                  , vdp_video_mixer_create);
-  VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_SET_FEATURE_ENABLES     , vdp_video_mixer_set_feature_enables);
-  VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_DESTROY                 , vdp_video_mixer_destroy);
-  VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_RENDER                  , vdp_video_mixer_render);
-  VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_SET_ATTRIBUTE_VALUES    , vdp_video_mixer_set_attribute_values);
-  VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_QUERY_PARAMETER_SUPPORT , vdp_video_mixer_query_parameter_support);
-  VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_QUERY_FEATURE_SUPPORT   , vdp_video_mixer_query_feature_support);
-  VDP_PROC(VDP_FUNC_ID_DECODER_CREATE                      , vdp_decoder_create);
-  VDP_PROC(VDP_FUNC_ID_DECODER_DESTROY                     , vdp_decoder_destroy);
-  VDP_PROC(VDP_FUNC_ID_DECODER_RENDER                      , vdp_decoder_render);
-  VDP_PROC(VDP_FUNC_ID_DECODER_QUERY_CAPABILITIES          , vdp_decoder_query_caps);
-  VDP_PROC(VDP_FUNC_ID_PREEMPTION_CALLBACK_REGISTER        , vdp_preemption_callback_register);
-  VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_DESTROY          , vdp_presentation_queue_target_destroy);
-  VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_CREATE                  , vdp_presentation_queue_create);
-  VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_DESTROY                 , vdp_presentation_queue_destroy);
-  VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_DISPLAY                 , vdp_presentation_queue_display);
-  VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_BLOCK_UNTIL_SURFACE_IDLE, vdp_presentation_queue_block_until_surface_idle);
-  VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_CREATE_X11       , vdp_presentation_queue_target_create_x11);
-  VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_QUERY_SURFACE_STATUS    , vdp_presentation_queue_query_surface_status);
-  VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_GET_TIME                , vdp_presentation_queue_get_time);
-  
+  VDP_PROC(VDP_FUNC_ID_GET_ERROR_STRING                    , m_vdpauConfig.vdpProcs.vdp_get_error_string);
+  VDP_PROC(VDP_FUNC_ID_DEVICE_DESTROY                      , m_vdpauConfig.vdpProcs.vdp_device_destroy);
+  VDP_PROC(VDP_FUNC_ID_GENERATE_CSC_MATRIX                 , m_vdpauConfig.vdpProcs.vdp_generate_csc_matrix);
+  VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_CREATE                , m_vdpauConfig.vdpProcs.vdp_video_surface_create);
+  VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_DESTROY               , m_vdpauConfig.vdpProcs.vdp_video_surface_destroy);
+  VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_PUT_BITS_Y_CB_CR      , m_vdpauConfig.vdpProcs.vdp_video_surface_put_bits_y_cb_cr);
+  VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR      , m_vdpauConfig.vdpProcs.vdp_video_surface_get_bits_y_cb_cr);
+  VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_Y_CB_CR     , m_vdpauConfig.vdpProcs.vdp_output_surface_put_bits_y_cb_cr);
+  VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_NATIVE      , m_vdpauConfig.vdpProcs.vdp_output_surface_put_bits_native);
+  VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_CREATE               , m_vdpauConfig.vdpProcs.vdp_output_surface_create);
+  VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_DESTROY              , m_vdpauConfig.vdpProcs.vdp_output_surface_destroy);
+  VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_GET_BITS_NATIVE      , m_vdpauConfig.vdpProcs.vdp_output_surface_get_bits_native);
+  VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_OUTPUT_SURFACE, m_vdpauConfig.vdpProcs.vdp_output_surface_render_output_surface);
+  VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_INDEXED     , m_vdpauConfig.vdpProcs.vdp_output_surface_put_bits_indexed);
+  VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_CREATE                  , m_vdpauConfig.vdpProcs.vdp_video_mixer_create);
+  VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_SET_FEATURE_ENABLES     , m_vdpauConfig.vdpProcs.vdp_video_mixer_set_feature_enables);
+  VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_DESTROY                 , m_vdpauConfig.vdpProcs.vdp_video_mixer_destroy);
+  VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_RENDER                  , m_vdpauConfig.vdpProcs.vdp_video_mixer_render);
+  VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_SET_ATTRIBUTE_VALUES    , m_vdpauConfig.vdpProcs.vdp_video_mixer_set_attribute_values);
+  VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_QUERY_PARAMETER_SUPPORT , m_vdpauConfig.vdpProcs.vdp_video_mixer_query_parameter_support);
+  VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_QUERY_FEATURE_SUPPORT   , m_vdpauConfig.vdpProcs.vdp_video_mixer_query_feature_support);
+  VDP_PROC(VDP_FUNC_ID_DECODER_CREATE                      , m_vdpauConfig.vdpProcs.vdp_decoder_create);
+  VDP_PROC(VDP_FUNC_ID_DECODER_DESTROY                     , m_vdpauConfig.vdpProcs.vdp_decoder_destroy);
+  VDP_PROC(VDP_FUNC_ID_DECODER_RENDER                      , m_vdpauConfig.vdpProcs.vdp_decoder_render);
+  VDP_PROC(VDP_FUNC_ID_DECODER_QUERY_CAPABILITIES          , m_vdpauConfig.vdpProcs.vdp_decoder_query_caps);
+  VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_DESTROY          , m_vdpauConfig.vdpProcs.vdp_presentation_queue_target_destroy);
+  VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_CREATE                  , m_vdpauConfig.vdpProcs.vdp_presentation_queue_create);
+  VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_DESTROY                 , m_vdpauConfig.vdpProcs.vdp_presentation_queue_destroy);
+  VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_DISPLAY                 , m_vdpauConfig.vdpProcs.vdp_presentation_queue_display);
+  VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_BLOCK_UNTIL_SURFACE_IDLE, m_vdpauConfig.vdpProcs.vdp_presentation_queue_block_until_surface_idle);
+  VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_CREATE_X11       , m_vdpauConfig.vdpProcs.vdp_presentation_queue_target_create_x11);
+  VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_QUERY_SURFACE_STATUS    , m_vdpauConfig.vdpProcs.vdp_presentation_queue_query_surface_status);
+  VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_GET_TIME                , m_vdpauConfig.vdpProcs.vdp_presentation_queue_get_time);
+
 #undef VDP_PROC
 
   // set all vdpau resources to invalid
-  vdp_flip_target = VDP_INVALID_HANDLE;
-  vdp_flip_queue = VDP_INVALID_HANDLE;
-  videoMixer = VDP_INVALID_HANDLE;
-  totalAvailableOutputSurfaces = 0;
-  presentSurface = VDP_INVALID_HANDLE;
-  outputSurface = VDP_INVALID_HANDLE;
-  for (int i = 0; i < NUM_OUTPUT_SURFACES; i++)
-    outputSurfaces[i] = VDP_INVALID_HANDLE;
-
-  m_vdpauOutputMethod = OUTPUT_NONE;
-
-  CExclusiveLock lock(m_DisplaySection);
   m_DisplayState = VDPAU_OPEN;
-  vdpauConfigured = false;
+  m_vdpauConfigured = false;
 }
 
-void CVDPAU::FiniVDPAUProcs()
+void CDecoder::FiniVDPAUProcs()
 {
-  if (vdp_device == VDP_INVALID_HANDLE) return;
+  if (m_vdpauConfig.vdpDevice == VDP_INVALID_HANDLE) return;
 
   VdpStatus vdp_st;
-  vdp_st = vdp_device_destroy(vdp_device);
+  vdp_st = m_vdpauConfig.vdpProcs.vdp_device_destroy(m_vdpauConfig.vdpDevice);
   CheckStatus(vdp_st, __LINE__);
-  vdp_device = VDP_INVALID_HANDLE;
-  vdpauConfigured = false;
+  m_vdpauConfig.vdpDevice = VDP_INVALID_HANDLE;
 }
 
-void CVDPAU::InitCSCMatrix(int Height)
+void CDecoder::FiniVDPAUOutput()
 {
+  if (m_vdpauConfig.vdpDevice == VDP_INVALID_HANDLE || !m_vdpauConfigured) return;
+
+  CLog::Log(LOGNOTICE, " (VDPAU) %s", __FUNCTION__);
+
+  // uninit output
+  m_vdpauOutput.Dispose();
+  m_vdpauConfigured = false;
+
   VdpStatus vdp_st;
-  m_Procamp.struct_version = VDP_PROCAMP_VERSION;
-  m_Procamp.brightness     = 0.0;
-  m_Procamp.contrast       = 1.0;
-  m_Procamp.saturation     = 1.0;
-  m_Procamp.hue            = 0;
-  vdp_st = vdp_generate_csc_matrix(&m_Procamp,
-                                   (Height < 720)? VDP_COLOR_STANDARD_ITUR_BT_601 : VDP_COLOR_STANDARD_ITUR_BT_709,
-                                   &m_CSCMatrix);
-  CheckStatus(vdp_st, __LINE__);
-}
-
-void CVDPAU::FiniVDPAUOutput()
-{
-  FiniOutputMethod();
 
-  if (vdp_device == VDP_INVALID_HANDLE || !vdpauConfigured) return;
-
-  CLog::Log(LOGNOTICE, " (VDPAU) %s", __FUNCTION__);
-
-  VdpStatus vdp_st;
-
-  vdp_st = vdp_decoder_destroy(decoder);
+  vdp_st = m_vdpauConfig.vdpProcs.vdp_decoder_destroy(m_vdpauConfig.vdpDecoder);
   if (CheckStatus(vdp_st, __LINE__))
     return;
-  decoder = VDP_INVALID_HANDLE;
+  m_vdpauConfig.vdpDecoder = VDP_INVALID_HANDLE;
+
+  CSingleLock lock(m_videoSurfaceSec);
+  CLog::Log(LOGDEBUG, "CVDPAU::FiniVDPAUOutput destroying %d video surfaces", (int)m_videoSurfaces.size());
 
-  for (unsigned int i = 0; i < m_videoSurfaces.size(); ++i)
+  for(unsigned int i = 0; i < m_videoSurfaces.size(); ++i)
   {
     vdpau_render_state *render = m_videoSurfaces[i];
     if (render->surface != VDP_INVALID_HANDLE)
     {
-      vdp_st = vdp_video_surface_destroy(render->surface);
+      vdp_st = m_vdpauConfig.vdpProcs.vdp_video_surface_destroy(render->surface);
       render->surface = VDP_INVALID_HANDLE;
     }
     if (CheckStatus(vdp_st, __LINE__))
@@ -888,8 +510,7 @@ void CVDPAU::FiniVDPAUOutput()
   }
 }
 
-
-void CVDPAU::ReadFormatOf( PixelFormat fmt
+void CDecoder::ReadFormatOf( PixelFormat fmt
                          , VdpDecoderProfile &vdp_decoder_profile
                          , VdpChromaType     &vdp_chroma_type)
 {
@@ -916,9 +537,9 @@ void CVDPAU::ReadFormatOf( PixelFormat fmt
       vdp_chroma_type     = VDP_CHROMA_TYPE_420;
       break;
 #if (defined PIX_FMT_VDPAU_MPEG4_IN_AVUTIL) && \
-    (defined VDP_DECODER_PROFILE_MPEG4_PART2_ASP)
+    (defined VDP_DECODER_PROFILE_MP)
     case PIX_FMT_VDPAU_MPEG4:
-      vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG4_PART2_ASP;
+      vdp_decoder_profile = VDP_DECOPEG4_PART2_ASP;
       vdp_chroma_type     = VDP_CHROMA_TYPE_420;
       break;
 #endif
@@ -929,170 +550,78 @@ void CVDPAU::ReadFormatOf( PixelFormat fmt
   }
 }
 
-
-bool CVDPAU::ConfigVDPAU(AVCodecContext* avctx, int ref_frames)
+bool CDecoder::ConfigVDPAU(AVCodecContext* avctx, int ref_frames)
 {
   FiniVDPAUOutput();
 
   VdpStatus vdp_st;
   VdpDecoderProfile vdp_decoder_profile;
-  vid_width = avctx->width;
-  vid_height = avctx->height;
-  surface_width = avctx->coded_width;
-  surface_height = avctx->coded_height;
 
-  past[1] = past[0] = current = future = NULL;
-  CLog::Log(LOGNOTICE, " (VDPAU) screenWidth:%i vidWidth:%i surfaceWidth:%i",OutWidth,vid_width,surface_width);
-  CLog::Log(LOGNOTICE, " (VDPAU) screenHeight:%i vidHeight:%i surfaceHeight:%i",OutHeight,vid_height,surface_height);
-  ReadFormatOf(avctx->pix_fmt, vdp_decoder_profile, vdp_chroma_type);
+  m_vdpauConfig.vidWidth = avctx->width;
+  m_vdpauConfig.vidHeight = avctx->height;
+  m_vdpauConfig.surfaceWidth = avctx->coded_width;
+  m_vdpauConfig.surfaceHeight = avctx->coded_height;
+
+  SetWidthHeight(avctx->width,avctx->height);
+
+  CLog::Log(LOGNOTICE, " (VDPAU) screenWidth:%i vidWidth:%i surfaceWidth:%i",m_vdpauConfig.outWidth,m_vdpauConfig.vidWidth,m_vdpauConfig.surfaceWidth);
+  CLog::Log(LOGNOTICE, " (VDPAU) screenHeight:%i vidHeight:%i surfaceHeight:%i",m_vdpauConfig.outHeight,m_vdpauConfig.vidHeight,m_vdpauConfig.surfaceHeight);
+
+  ReadFormatOf(avctx->pix_fmt, vdp_decoder_profile, m_vdpauConfig.vdpChromaType);
 
   if(avctx->pix_fmt == PIX_FMT_VDPAU_H264)
   {
-     max_references = ref_frames;
-     if (max_references > 16) max_references = 16;
-     if (max_references < 5)  max_references = 5;
+    m_vdpauConfig.maxReferences = ref_frames;
+    if (m_vdpauConfig.maxReferences > 16) m_vdpauConfig.maxReferences = 16;
+    if (m_vdpauConfig.maxReferences < 5)  m_vdpauConfig.maxReferences = 5;
   }
   else
-    max_references = 2;
+    m_vdpauConfig.maxReferences = 2;
 
-  vdp_st = vdp_decoder_create(vdp_device,
+  vdp_st = m_vdpauConfig.vdpProcs.vdp_decoder_create(m_vdpauConfig.vdpDevice,
                               vdp_decoder_profile,
-                              surface_width,
-                              surface_height,
-                              max_references,
-                              &decoder);
-  if (CheckStatus(vdp_st, __LINE__))
-    return false;
-
-  m_vdpauOutputMethod = OUTPUT_NONE;
-
-  vdpauConfigured = true;
-  return true;
-}
-
-bool CVDPAU::ConfigOutputMethod(AVCodecContext *avctx, AVFrame *pFrame)
-{
-  VdpStatus vdp_st;
-
-  if (m_vdpauOutputMethod == OUTPUT_PIXMAP)
-    return true;
-
-  FiniOutputMethod();
-
-  MakePixmap(avctx->width,avctx->height);
-
-  vdp_st = vdp_presentation_queue_target_create_x11(vdp_device,
-                                                    m_Pixmap, //x_window,
-                                                    &vdp_flip_target);
-  if (CheckStatus(vdp_st, __LINE__))
-    return false;
-
-  vdp_st = vdp_presentation_queue_create(vdp_device,
-                                         vdp_flip_target,
-                                         &vdp_flip_queue);
+                              m_vdpauConfig.surfaceWidth,
+                              m_vdpauConfig.surfaceHeight,
+                              m_vdpauConfig.maxReferences,
+                              &m_vdpauConfig.vdpDecoder);
   if (CheckStatus(vdp_st, __LINE__))
     return false;
 
-  totalAvailableOutputSurfaces = 0;
-
-  int tmpMaxOutputSurfaces = NUM_OUTPUT_SURFACES;
-  if (vid_width == FULLHD_WIDTH)
-    tmpMaxOutputSurfaces = NUM_OUTPUT_SURFACES_FOR_FULLHD;
-
-  // Creation of outputSurfaces
-  for (int i = 0; i < NUM_OUTPUT_SURFACES && i < tmpMaxOutputSurfaces; i++)
-  {
-    vdp_st = vdp_output_surface_create(vdp_device,
-                                       VDP_RGBA_FORMAT_B8G8R8A8,
-                                       OutWidth,
-                                       OutHeight,
-                                       &outputSurfaces[i]);
-    if (CheckStatus(vdp_st, __LINE__))
+  // initialize output
+  CSingleLock lock(g_graphicsContext);
+  m_vdpauConfig.stats = &m_bufferStats;
+  m_vdpauConfig.vdpau = this;
+  m_bufferStats.Reset();
+  m_vdpauOutput.Start();
+  Message *reply;
+  if (m_vdpauOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::INIT,
+                                                 &reply,
+                                                 2000,
+                                                 &m_vdpauConfig,
+                                                 sizeof(m_vdpauConfig)))
+  {
+    bool success = reply->signal == COutputControlProtocol::ACC ? true : false;
+    reply->Release();
+    if (!success)
+    {
+      CLog::Log(LOGERROR, "VDPAU::%s - vdpau output returned error", __FUNCTION__);
+      m_vdpauOutput.Dispose();
       return false;
-    totalAvailableOutputSurfaces++;
-  }
-  CLog::Log(LOGNOTICE, " (VDPAU) Total Output Surfaces Available: %i of a max (tmp: %i const: %i)",
-                       totalAvailableOutputSurfaces,
-                       tmpMaxOutputSurfaces,
-                       NUM_OUTPUT_SURFACES);
-
-  // create 3 pitches of black lines needed for clipping top
-  // and bottom lines when de-interlacing
-  m_BlackBar = new uint32_t[3*OutWidth];
-  memset(m_BlackBar, 0, 3*OutWidth*sizeof(uint32_t));
-
-  surfaceNum = presentSurfaceNum = 0;
-  outputSurface = presentSurface = VDP_INVALID_HANDLE;
-  videoMixer = VDP_INVALID_HANDLE;
-
-  m_vdpauOutputMethod = OUTPUT_PIXMAP;
-
-  return true;
-}
-
-bool CVDPAU::FiniOutputMethod()
-{
-  VdpStatus vdp_st;
-
-  if (vdp_flip_queue != VDP_INVALID_HANDLE)
-  {
-    vdp_st = vdp_presentation_queue_destroy(vdp_flip_queue);
-    vdp_flip_queue = VDP_INVALID_HANDLE;
-    CheckStatus(vdp_st, __LINE__);
-  }
-
-  if (vdp_flip_target != VDP_INVALID_HANDLE)
-  {
-    vdp_st = vdp_presentation_queue_target_destroy(vdp_flip_target);
-    vdp_flip_target = VDP_INVALID_HANDLE;
-    CheckStatus(vdp_st, __LINE__);
-  }
-
-  if (m_glPixmap)
-  {
-    CLog::Log(LOGDEBUG, "GLX: Destroying glPixmap");
-    glXDestroyPixmap(m_Display, m_glPixmap);
-    m_glPixmap = None;
-  }
-
-  if (m_Pixmap)
-  {
-    CLog::Log(LOGDEBUG, "GLX: Destroying XPixmap");
-    XFreePixmap(m_Display, m_Pixmap);
-    m_Pixmap = None;
-  }
-
-  outputSurface = presentSurface = VDP_INVALID_HANDLE;
-
-  for (int i = 0; i < totalAvailableOutputSurfaces; i++)
-  {
-    if (outputSurfaces[i] == VDP_INVALID_HANDLE)
-       continue;
-    vdp_st = vdp_output_surface_destroy(outputSurfaces[i]);
-    outputSurfaces[i] = VDP_INVALID_HANDLE;
-    CheckStatus(vdp_st, __LINE__);
-  }
-
-  if (videoMixer != VDP_INVALID_HANDLE)
-  {
-    vdp_st = vdp_video_mixer_destroy(videoMixer);
-    videoMixer = VDP_INVALID_HANDLE;
-    CheckStatus(vdp_st, __LINE__);
+    }
   }
-
-  if (m_BlackBar)
+  else
   {
-    delete [] m_BlackBar;
-    m_BlackBar = NULL;
+    CLog::Log(LOGERROR, "VDPAU::%s - failed to init output", __FUNCTION__);
+    m_vdpauOutput.Dispose();
+    return false;
   }
 
-  while (!m_DVDVideoPics.empty())
-    m_DVDVideoPics.pop();
-
+  m_inMsgEvent.Reset();
+  m_vdpauConfigured = true;
   return true;
 }
 
-void CVDPAU::SpewHardwareAvailable()  //Copyright (c) 2008 Wladimir J. van der Laan  -- VDPInfo
+void CDecoder::SpewHardwareAvailable()  //CopyrighVDPAUt (c) 2008 Wladimir J. van der Laan  -- VDPInfo
 {
   VdpStatus rv;
   CLog::Log(LOGNOTICE,"VDPAU Decoder capabilities:");
@@ -1102,7 +631,7 @@ void CVDPAU::SpewHardwareAvailable()  //Copyright (c) 2008 Wladimir J. van der L
   {
     VdpBool is_supported = false;
     uint32_t max_level, max_macroblocks, max_width, max_height;
-    rv = vdp_decoder_query_caps(vdp_device, decoder_profiles[x].id,
+    rv = m_vdpauConfig.vdpProcs.vdp_decoder_query_caps(m_vdpauConfig.vdpDevice, decoder_profiles[x].id,
                                 &is_supported, &max_level, &max_macroblocks, &max_width, &max_height);
     if(rv == VDP_STATUS_OK && is_supported)
     {
@@ -1111,13 +640,13 @@ void CVDPAU::SpewHardwareAvailable()  //Copyright (c) 2008 Wladimir J. van der L
     }
   }
   CLog::Log(LOGNOTICE,"------------------------------------");
-  m_feature_count = 0;
+  m_vdpauConfig.featureCount = 0;
 #define CHECK_SUPPORT(feature)  \
   do { \
     VdpBool supported; \
-    if(vdp_video_mixer_query_feature_support(vdp_device, feature, &supported) == VDP_STATUS_OK && supported) { \
+    if(m_vdpauConfig.vdpProcs.vdp_video_mixer_query_feature_support(m_vdpauConfig.vdpDevice, feature, &supported) == VDP_STATUS_OK && supported) { \
       CLog::Log(LOGNOTICE, "Mixer feature: "#feature);  \
-      m_features[m_feature_count++] = feature; \
+      m_vdpauConfig.vdpFeatures[m_vdpauConfig.featureCount++] = feature; \
     } \
   } while(false)
 
@@ -1141,7 +670,7 @@ void CVDPAU::SpewHardwareAvailable()  //Copyright (c) 2008 Wladimir J. van der L
 
 }
 
-bool CVDPAU::IsSurfaceValid(vdpau_render_state *render)
+bool CDecoder::IsSurfaceValid(vdpau_render_state *render)
 {
   // find render state in queue
   bool found(false);
@@ -1168,34 +697,33 @@ bool CVDPAU::IsSurfaceValid(vdpau_render_state *render)
   return true;
 }
 
-int CVDPAU::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic)
+int CDecoder::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic)
 {
   //CLog::Log(LOGNOTICE,"%s",__FUNCTION__);
   CDVDVideoCodecFFmpeg* ctx        = (CDVDVideoCodecFFmpeg*)avctx->opaque;
-  CVDPAU*               vdp        = (CVDPAU*)ctx->GetHardware();
-  struct pictureAge*    pA         = &vdp->picAge;
+  CDecoder*             vdp        = (CDecoder*)ctx->GetHardware();
 
   // while we are waiting to recover we can't do anything
-  CSharedLock lock(vdp->m_DecoderSection);
+  CSingleLock lock(vdp->m_DecoderSection);
 
-  { CSharedLock dLock(vdp->m_DisplaySection);
-    if(vdp->m_DisplayState != VDPAU_OPEN)
-    {
-      CLog::Log(LOGWARNING, "CVDPAU::FFGetBuffer - returning due to awaiting recovery");
-      return -1;
-    }
+  if(vdp->m_DisplayState != VDPAU_OPEN)
+  {
+    CLog::Log(LOGWARNING, "CVDPAU::FFGetBuffer - returning due to awaiting recovery");
+    return -1;
   }
 
   vdpau_render_state * render = NULL;
 
   // find unused surface
-  for(unsigned int i = 0; i < vdp->m_videoSurfaces.size(); i++)
-  {
-    if(!(vdp->m_videoSurfaces[i]->state & (FF_VDPAU_STATE_USED_FOR_REFERENCE | FF_VDPAU_STATE_USED_FOR_RENDER)))
+  { CSingleLock lock(vdp->m_videoSurfaceSec);
+    for(unsigned int i = 0; i < vdp->m_videoSurfaces.size(); i++)
     {
-      render = vdp->m_videoSurfaces[i];
-      render->state = 0;
-      break;
+      if(!(vdp->m_videoSurfaces[i]->state & (FF_VDPAU_STATE_USED_FOR_REFERENCE | FF_VDPAU_STATE_USED_FOR_RENDER)))
+      {
+        render = vdp->m_videoSurfaces[i];
+        render->state = 0;
+        break;
+      }
     }
   }
 
@@ -1204,21 +732,22 @@ int CVDPAU::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic)
   {
     // create a new surface
     VdpDecoderProfile profile;
-    ReadFormatOf(avctx->pix_fmt, profile, vdp->vdp_chroma_type);
+    ReadFormatOf(avctx->pix_fmt, profile, vdp->m_vdpauConfig.vdpChromaType);
     render = (vdpau_render_state*)calloc(sizeof(vdpau_render_state), 1);
     if (render == NULL)
     {
       CLog::Log(LOGWARNING, "CVDPAU::FFGetBuffer - calloc failed");
       return -1;
     }
+    CSingleLock lock(vdp->m_videoSurfaceSec);
     render->surface = VDP_INVALID_HANDLE;
     vdp->m_videoSurfaces.push_back(render);
   }
 
   if (render->surface == VDP_INVALID_HANDLE)
   {
-    vdp_st = vdp->vdp_video_surface_create(vdp->vdp_device,
-                                         vdp->vdp_chroma_type,
+    vdp_st = vdp->m_vdpauConfig.vdpProcs.vdp_video_surface_create(vdp->m_vdpauConfig.vdpDevice,
+                                         vdp->m_vdpauConfig.vdpChromaType,
                                          avctx->coded_width,
                                          avctx->coded_height,
                                          &render->surface);
@@ -1239,18 +768,6 @@ int CVDPAU::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic)
 
   pic->linesize[0] = pic->linesize[1] =  pic->linesize[2] = 0;
 
-  if(pic->reference)
-  {
-    pA->ip_age[0]= pA->ip_age[1]+1;
-    pA->ip_age[1]= 1;
-    pA->b_age++;
-  }
-  else
-  {
-    pA->ip_age[0]++;
-    pA->ip_age[1]++;
-    pA->b_age = 1;
-  }
   pic->type= FF_BUFFER_TYPE_USER;
 
   render->state |= FF_VDPAU_STATE_USED_FOR_REFERENCE;
@@ -1258,15 +775,16 @@ int CVDPAU::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic)
   return 0;
 }
 
-void CVDPAU::FFReleaseBuffer(AVCodecContext *avctx, AVFrame *pic)
+void CDecoder::FFReleaseBuffer(AVCodecContext *avctx, AVFrame *pic)
 {
   //CLog::Log(LOGNOTICE,"%s",__FUNCTION__);
   CDVDVideoCodecFFmpeg* ctx        = (CDVDVideoCodecFFmpeg*)avctx->opaque;
-  CVDPAU*               vdp        = (CVDPAU*)ctx->GetHardware();
+  CDecoder*             vdp        = (CDecoder*)ctx->GetHardware();
+
   vdpau_render_state  * render;
   unsigned int i;
 
-  CSharedLock lock(vdp->m_DecoderSection);
+  CSingleLock lock(vdp->m_DecoderSection);
 
   render=(vdpau_render_state*)pic->data[0];
   if(!render)
@@ -1275,6 +793,8 @@ void CVDPAU::FFReleaseBuffer(AVCodecContext *avctx, AVFrame *pic)
     return;
   }
 
+  CSingleLock vLock(vdp->m_videoSurfaceSec);
+  render->state &= ~FF_VDPAU_STATE_USED_FOR_REFERENCE;
   for(i=0; i<4; i++)
     pic->data[i]= NULL;
 
@@ -1289,21 +809,18 @@ void CVDPAU::FFReleaseBuffer(AVCodecContext *avctx, AVFrame *pic)
 }
 
 
-void CVDPAU::FFDrawSlice(struct AVCodecContext *s,
+void CDecoder::FFDrawSlice(struct AVCodecContext *s,
                                            const AVFrame *src, int offset[4],
                                            int y, int type, int height)
 {
   CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)s->opaque;
-  CVDPAU*               vdp = (CVDPAU*)ctx->GetHardware();
+  CDecoder*               vdp = (CDecoder*)ctx->GetHardware();
 
   // while we are waiting to recover we can't do anything
-  CSharedLock lock(vdp->m_DecoderSection);
-
-  { CSharedLock dLock(vdp->m_DisplaySection);
-    if(vdp->m_DisplayState != VDPAU_OPEN)
-      return;
-  }
+  CSingleLock lock(vdp->m_DecoderSection);
 
+  if(vdp->m_DisplayState != VDPAU_OPEN)
+    return;
 
   if(src->linesize[0] || src->linesize[1] || src->linesize[2]
   || offset[0] || offset[1] || offset[2])
@@ -1333,59 +850,41 @@ void CVDPAU::FFDrawSlice(struct AVCodecContext *s,
   if(s->pix_fmt == PIX_FMT_VDPAU_H264)
     max_refs = render->info.h264.num_ref_frames;
 
-  if(vdp->decoder == VDP_INVALID_HANDLE
-  || vdp->vdpauConfigured == false
-  || vdp->max_references < max_refs)
+  if(vdp->m_vdpauConfig.vdpDecoder == VDP_INVALID_HANDLE
+  || vdp->m_vdpauConfigured == false
+  || vdp->m_vdpauConfig.maxReferences < max_refs)
   {
     if(!vdp->ConfigVDPAU(s, max_refs))
       return;
   }
 
-  vdp_st = vdp->vdp_decoder_render(vdp->decoder,
+  uint64_t startTime = CurrentHostCounter();
+  uint16_t decoded, processed, rend;
+  vdp->m_bufferStats.Get(decoded, processed, rend);
+  vdp_st = vdp->m_vdpauConfig.vdpProcs.vdp_decoder_render(vdp->m_vdpauConfig.vdpDecoder,
                                    render->surface,
                                    (VdpPictureInfo const *)&(render->info),
                                    render->bitstream_buffers_used,
                                    render->bitstream_buffers);
   vdp->CheckStatus(vdp_st, __LINE__);
+  uint64_t diff = CurrentHostCounter() - startTime;
+  if (diff*1000/CurrentHostFrequency() > 30)
+    CLog::Log(LOGWARNING,"CVDPAU::DrawSlice - VdpDecoderRender long decoding: %d ms, dec: %d, proc: %d, rend: %d", (int)((diff*1000)/CurrentHostFrequency()), decoded, processed, rend);
+
 }
 
-int CVDPAU::Decode(AVCodecContext *avctx, AVFrame *pFrame)
-{
-  //CLog::Log(LOGNOTICE,"%s",__FUNCTION__);
-  VdpStatus vdp_st;
-  VdpTime time;
 
+int CDecoder::Decode(AVCodecContext *avctx, AVFrame *pFrame)
+{
   int result = Check(avctx);
   if (result)
     return result;
 
-  CSharedLock lock(m_DecoderSection);
+  CSingleLock lock(m_DecoderSection);
 
-  if (!vdpauConfigured)
+  if (!m_vdpauConfigured)
     return VC_ERROR;
 
-  // configure vdpau output
-  if (!ConfigOutputMethod(avctx, pFrame))
-    return VC_FLUSHED;
-
-  outputSurface = outputSurfaces[surfaceNum];
-
-  CheckFeatures();
-
-  if (( (int)outRectVid.x1 != OutWidth ) ||
-      ( (int)outRectVid.y1 != OutHeight ))
-  {
-    outRectVid.x0 = 0;
-    outRectVid.y0 = 0;
-    outRectVid.x1 = OutWidth;
-    outRectVid.y1 = OutHeight;
-  }
-
-  EDEINTERLACEMODE   mode = g_settings.m_currentVideoSettings.m_DeinterlaceMode;
-  EINTERLACEMETHOD method = g_settings.m_currentVideoSettings.m_InterlaceMethod;
-  if (method == VS_INTERLACEMETHOD_AUTO)
-    method = AutoInterlaceMethod();
-
   if(pFrame)
   { // we have a new frame from decoder
 
@@ -1393,7 +892,10 @@ int CVDPAU::Decode(AVCodecContext *avctx, AVFrame *pFrame)
     if(!render) // old style ffmpeg gave data on plane 0
       render = (vdpau_render_state*)pFrame->data[0];
     if(!render)
+    {
+      CLog::Log(LOGERROR, "CVDPAU::Decode: no valid frame");
       return VC_ERROR;
+    }
 
     // ffmpeg vc-1 decoder does not flush, make sure the data buffer is still valid
     if (!IsSurfaceValid(render))
@@ -1402,258 +904,166 @@ int CVDPAU::Decode(AVCodecContext *avctx, AVFrame *pFrame)
       return VC_BUFFER;
     }
 
+    CSingleLock lock(m_videoSurfaceSec);
     render->state |= FF_VDPAU_STATE_USED_FOR_RENDER;
+    lock.Leave();
 
-    ClearUsedForRender(&past[0]);
-    past[0] = past[1];
-    past[1] = current;
-    current = future;
-    future = render;
+    // send frame to output for processing
+    CVdpauDecodedPicture pic;
+    memset(&pic.DVDPic, 0, sizeof(pic.DVDPic));
+    ((CDVDVideoCodecFFmpeg*)avctx->opaque)->GetPictureCommon(&pic.DVDPic);
+    pic.render = render;
+    m_bufferStats.IncDecoded();
+    m_vdpauOutput.m_dataPort.SendOutMessage(COutputDataProtocol::NEWFRAME, &pic, sizeof(pic));
 
-    DVDVideoPicture DVDPic;
-    memset(&DVDPic, 0, sizeof(DVDVideoPicture));
-    ((CDVDVideoCodecFFmpeg*)avctx->opaque)->GetPictureCommon(&DVDPic);
-    m_DVDVideoPics.push(DVDPic);
+    m_codecControl = pic.DVDPic.iFlags & (DVP_FLAG_DRAIN | DVP_FLAG_NO_POSTPROC);
+  }
 
-    int pics = m_DVDVideoPics.size();
-    if (pics < 2)
-        return VC_BUFFER;
-    else if (pics > 2)
+  int retval = 0;
+  uint16_t decoded, processed, render;
+  Message *msg;
+  while (m_vdpauOutput.m_controlPort.ReceiveInMessage(&msg))
+  {
+    if (msg->signal == COutputControlProtocol::ERROR)
     {
-      // this should not normally happen
-      CLog::Log(LOGERROR, "CVDPAU::Decode - invalid number of pictures in queue");
-      while (pics-- != 2)
-        m_DVDVideoPics.pop();
+      m_DisplayState = VDPAU_ERROR;
+      retval |= VC_ERROR;
     }
+    msg->Release();
+  }
 
-    if (mode == VS_DEINTERLACEMODE_FORCE
-    || (mode == VS_DEINTERLACEMODE_AUTO && m_DVDVideoPics.front().iFlags & DVP_FLAG_INTERLACED))
+  m_bufferStats.Get(decoded, processed, render);
+
+  uint64_t startTime = CurrentHostCounter();
+  while (!retval)
+  {
+    if (m_vdpauOutput.m_dataPort.ReceiveInMessage(&msg))
     {
-      if((method == VS_INTERLACEMETHOD_AUTO_ION
-      ||  method == VS_INTERLACEMETHOD_VDPAU_BOB
-      ||  method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL
-      ||  method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF
-      ||  method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL
-      ||  method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF
-      ||  method == VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE ))
+      if (msg->signal == COutputDataProtocol::PICTURE)
       {
-        if((method == VS_INTERLACEMETHOD_AUTO_ION && vid_height > 576)
-        || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF
-        || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF
-        || avctx->skip_frame == AVDISCARD_NONREF)
-          m_mixerstep = 0;
-        else
-          m_mixerstep = 1;
-
-        if(m_DVDVideoPics.front().iFlags & DVP_FLAG_TOP_FIELD_FIRST)
-          m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD;
-        else
-          m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD;
+        if (m_presentPicture)
+        {
+          m_presentPicture->ReturnUnused();
+          m_presentPicture = 0;
+        }
+
+        m_presentPicture = *(CVdpauRenderPicture**)msg->data;
+        m_presentPicture->vdpau = this;
+        m_bufferStats.DecRender();
+        m_bufferStats.Get(decoded, processed, render);
+        retval |= VC_PICTURE;
+        msg->Release();
+        break;
+      }
+      msg->Release();
+    }
+    else if (m_vdpauOutput.m_controlPort.ReceiveInMessage(&msg))
+    {
+      if (msg->signal == COutputControlProtocol::STATS)
+      {
+        m_bufferStats.Get(decoded, processed, render);
       }
       else
       {
-        m_mixerstep  = 0;
-        m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
+        m_DisplayState = VDPAU_ERROR;
+        retval |= VC_ERROR;
       }
+      msg->Release();
     }
-    else
+
+    if ((m_codecControl & DVP_FLAG_DRAIN))
     {
-      m_mixerstep  = 0;
-      m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
+      if (decoded + processed + render < 4)
+      {
+        retval |= VC_BUFFER;
+      }
     }
-
-  }
-  else if(m_mixerstep == 1)
-  { // no new frame given, output second field of old frame
-
-    if(avctx->skip_frame == AVDISCARD_NONREF)
+    else
     {
-      ClearUsedForRender(&past[1]);
-      m_DVDVideoPics.pop();
-      return VC_BUFFER;
+      if (decoded < 4 && (processed + render) < 3)
+      {
+        retval |= VC_BUFFER;
+      }
     }
 
-    m_mixerstep = 2;
-    if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD)
-      m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD;
-    else
-      m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD;
+    if (!retval && !m_inMsgEvent.WaitMSec(2000))
+      break;
   }
-  else
+  uint64_t diff = CurrentHostCounter() - startTime;
+  if (retval & VC_PICTURE)
   {
-    CLog::Log(LOGERROR, "CVDPAU::Decode - invalid mixer state reached");
-    return VC_BUFFER;
+    m_bufferStats.SetParams(diff, m_codecControl);
   }
+  if (diff*1000/CurrentHostFrequency() > 50)
+    CLog::Log(LOGDEBUG,"CVDPAU::Decode long wait: %d", (int)((diff*1000)/CurrentHostFrequency()));
 
-  VdpVideoSurface past_surfaces[2] = { VDP_INVALID_HANDLE, VDP_INVALID_HANDLE };
-  VdpVideoSurface futu_surfaces[1] = { VDP_INVALID_HANDLE };
-
-  if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME)
+  if (!retval)
   {
-    if (past[0])
-      past_surfaces[1] = past[0]->surface;
-    if (past[1])
-      past_surfaces[0] = past[1]->surface;
-    futu_surfaces[0] = future->surface;
+    CLog::Log(LOGERROR, "VDPAU::%s - timed out waiting for output message", __FUNCTION__);
+    m_DisplayState = VDPAU_ERROR;
+    retval |= VC_ERROR;
   }
-  else
-  {
-    if(m_mixerstep == 1)
-    { // first field
-      if (past[1])
-      {
-        past_surfaces[1] = past[1]->surface;
-        past_surfaces[0] = past[1]->surface;
-      }
-      futu_surfaces[0] = current->surface;
-    }
-    else
-    { // second field
-      if (past[1])
-        past_surfaces[1] = past[1]->surface;
-      past_surfaces[0] = current->surface;
-      futu_surfaces[0] = future->surface;
-    }
-  }
-
-  vdp_st = vdp_presentation_queue_block_until_surface_idle(vdp_flip_queue,outputSurface,&time);
-
-  VdpRect sourceRect = {0,0,vid_width, vid_height};
-
-  vdp_st = vdp_video_mixer_render(videoMixer,
-                                  VDP_INVALID_HANDLE,
-                                  0, 
-                                  m_mixerfield,
-                                  2,
-                                  past_surfaces,
-                                  current->surface,
-                                  1,
-                                  futu_surfaces,
-                                  &sourceRect,
-                                  outputSurface,
-                                  &(outRectVid),
-                                  &(outRectVid),
-                                  0,
-                                  NULL);
-  CheckStatus(vdp_st, __LINE__);
 
-  surfaceNum++;
-  if (surfaceNum >= totalAvailableOutputSurfaces) surfaceNum = 0;
+  return retval;
+}
 
-  if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME)
-  {
-    ClearUsedForRender(&past[0]);
-    return VC_BUFFER | VC_PICTURE;
-  }
-  else
-  {
-    // in order to clip top and bottom lines when de-interlacing
-    // we black those lines as a work around for not working
-    // background colour using the mixer
-    // pixel perfect is preferred over overscanning or zooming
+bool CDecoder::GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture)
+{
+  CSingleLock lock(m_DecoderSection);
 
-    VdpRect clipRect = outRectVid;
-    clipRect.y1 = clipRect.y0 + 2;
-    uint32_t *data[] = {m_BlackBar};
-    uint32_t pitches[] = {outRectVid.x1};
-    vdp_st = vdp_output_surface_put_bits_native(outputSurface,
-                                        (void**)data,
-                                        pitches,
-                                        &clipRect);
-    CheckStatus(vdp_st, __LINE__);
+  if (m_DisplayState != VDPAU_OPEN)
+    return false;
 
-    clipRect = outRectVid;
-    clipRect.y0 = clipRect.y1 - 2;
-    vdp_st = vdp_output_surface_put_bits_native(outputSurface,
-                                        (void**)data,
-                                        pitches,
-                                        &clipRect);
-    CheckStatus(vdp_st, __LINE__);
+  *picture = m_presentPicture->DVDPic;
+  picture->vdpau = m_presentPicture;
 
-    if(m_mixerstep == 1)
-      return VC_PICTURE;
-    else
-    {
-      ClearUsedForRender(&past[1]);
-      return VC_BUFFER | VC_PICTURE;
-    }
-  }
+  return true;
 }
 
-bool CVDPAU::GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture)
+void CDecoder::Reset()
 {
-  CSharedLock lock(m_DecoderSection);
-
-  { CSharedLock dLock(m_DisplaySection);
-    if (m_DisplayState != VDPAU_OPEN)
-      return false;
-  }
-
-  *picture = m_DVDVideoPics.front();
-  // if this is the first field of an interlaced frame, we'll need
-  // this same picture for the second field later
-  if (m_mixerstep != 1)
-    m_DVDVideoPics.pop();
+  CSingleLock lock(m_DecoderSection);
 
-  picture->format = RENDER_FMT_VDPAU;
-  picture->iFlags &= DVP_FLAG_DROPPED;
-  picture->iWidth = OutWidth;
-  picture->iHeight = OutHeight;
-  picture->vdpau = this;
+  if (!m_vdpauConfigured)
+    return;
 
-  if(m_mixerstep)
+  Message *reply;
+  if (m_vdpauOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::FLUSH,
+                                                 &reply,
+                                                 2000))
   {
-    picture->iRepeatPicture = -0.5;
-    if(m_mixerstep > 1)
+    bool success = reply->signal == COutputControlProtocol::ACC ? true : false;
+    reply->Release();
+    if (!success)
     {
-      picture->dts = DVD_NOPTS_VALUE;
-      picture->pts = DVD_NOPTS_VALUE;
+      CLog::Log(LOGERROR, "VDPAU::%s - flush returned error", __FUNCTION__);
+      m_DisplayState = VDPAU_ERROR;
     }
+    else
+      m_bufferStats.Reset();
+  }
+  else
+  {
+    CLog::Log(LOGERROR, "VDPAU::%s - flush timed out", __FUNCTION__);
+    m_DisplayState = VDPAU_ERROR;
   }
-  return true;
 }
 
-void CVDPAU::Reset()
+bool CDecoder::CanSkipDeint()
 {
-  // invalidate surfaces and picture queue when seeking
-  ClearUsedForRender(&past[0]);
-  ClearUsedForRender(&past[1]);
-  ClearUsedForRender(&current);
-  ClearUsedForRender(&future);
-
-  while (!m_DVDVideoPics.empty())
-    m_DVDVideoPics.pop();
+  return m_bufferStats.CanSkipDeint();
 }
 
-void CVDPAU::Present()
+void CDecoder::ReturnRenderPicture(CVdpauRenderPicture *renderPic)
 {
-  //CLog::Log(LOGNOTICE,"%s",__FUNCTION__);
-  VdpStatus vdp_st;
-
-  CSharedLock lock(m_DecoderSection);
-
-  { CSharedLock dLock(m_DisplaySection);
-    if (m_DisplayState != VDPAU_OPEN)
-      return;
-  }
-
-  presentSurface = outputSurface;
-
-  vdp_st = vdp_presentation_queue_display(vdp_flip_queue,
-                                          presentSurface,
-                                          0,
-                                          0,
-                                          0);
-  CheckStatus(vdp_st, __LINE__);
+  m_vdpauOutput.m_dataPort.SendOutMessage(COutputDataProtocol::RETURNPIC, &renderPic, sizeof(renderPic));
 }
 
-bool CVDPAU::CheckStatus(VdpStatus vdp_st, int line)
+bool CDecoder::CheckStatus(VdpStatus vdp_st, int line)
 {
   if (vdp_st != VDP_STATUS_OK)
   {
-    CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) at %s:%d\n", vdp_get_error_string(vdp_st), vdp_st, __FILE__, line);
-
-    CExclusiveLock lock(m_DisplaySection);
+    CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) at %s:%d\n", m_vdpauConfig.vdpProcs.vdp_get_error_string(vdp_st), vdp_st, __FILE__, line);
 
     if(m_DisplayState == VDPAU_OPEN)
     {
@@ -1671,4 +1081,2422 @@ bool CVDPAU::CheckStatus(VdpStatus vdp_st, int line)
   return false;
 }
 
+//-----------------------------------------------------------------------------
+// RenderPicture
+//-----------------------------------------------------------------------------
+
+CVdpauRenderPicture* CVdpauRenderPicture::Acquire()
+{
+  CSingleLock lock(*renderPicSection);
+
+  if (refCount == 0)
+    vdpau->Acquire();
+
+  refCount++;
+  return this;
+}
+
+long CVdpauRenderPicture::Release()
+{
+  CSingleLock lock(*renderPicSection);
+
+  refCount--;
+  if (refCount > 0)
+    return refCount;
+
+  lock.Leave();
+  vdpau->ReturnRenderPicture(this);
+  vdpau->ReleasePicReference();
+
+  return refCount;
+}
+
+void CVdpauRenderPicture::ReturnUnused()
+{
+  { CSingleLock lock(*renderPicSection);
+    if (refCount > 0)
+      return;
+  }
+  if (vdpau)
+    vdpau->ReturnRenderPicture(this);
+}
+//-----------------------------------------------------------------------------
+// Mixer
+//-----------------------------------------------------------------------------
+CMixer::CMixer(CEvent *inMsgEvent) :
+  CThread("Vdpau Mixer Thread"),
+  m_controlPort("ControlPort", inMsgEvent, &m_outMsgEvent),
+  m_dataPort("DataPort", inMsgEvent, &m_outMsgEvent)
+{
+  m_inMsgEvent = inMsgEvent;
+}
+
+CMixer::~CMixer()
+{
+  Dispose();
+}
+
+void CMixer::Start()
+{
+  Create();
+}
+
+void CMixer::Dispose()
+{
+  m_bStop = true;
+  m_outMsgEvent.Set();
+  StopThread();
+
+  m_controlPort.Purge();
+  m_dataPort.Purge();
+}
+
+void CMixer::OnStartup()
+{
+  CLog::Log(LOGNOTICE, "CMixer::OnStartup: Output Thread created");
+}
+
+void CMixer::OnExit()
+{
+  CLog::Log(LOGNOTICE, "CMixer::OnExit: Output Thread terminated");
+}
+
+enum MIXER_STATES
+{
+  M_TOP = 0,                      // 0
+  M_TOP_ERROR,                    // 1
+  M_TOP_UNCONFIGURED,             // 2
+  M_TOP_CONFIGURED,               // 3
+  M_TOP_CONFIGURED_WAIT1,         // 4
+  M_TOP_CONFIGURED_STEP1,         // 5
+  M_TOP_CONFIGURED_WAIT2,         // 6
+  M_TOP_CONFIGURED_STEP2,         // 7
+};
+
+int MIXER_parentStates[] = {
+    -1,
+    0, //TOP_ERROR
+    0, //TOP_UNCONFIGURED
+    0, //TOP_CONFIGURED
+    3, //TOP_CONFIGURED_WAIT1
+    3, //TOP_CONFIGURED_STEP1
+    3, //TOP_CONFIGURED_WAIT2
+    3, //TOP_CONFIGURED_STEP2
+};
+
+void CMixer::StateMachine(int signal, Protocol *port, Message *msg)
+{
+  for (int state = m_state; ; state = MIXER_parentStates[state])
+  {
+    switch (state)
+    {
+    case M_TOP: // TOP
+      if (port == &m_controlPort)
+      {
+        switch (signal)
+        {
+        case CMixerControlProtocol::FLUSH:
+          Flush();
+          msg->Reply(CMixerControlProtocol::ACC);
+          return;
+        default:
+          break;
+        }
+      }
+      {
+        std::string portName = port == NULL ? "timer" : port->portName;
+        CLog::Log(LOGWARNING, "CMixer::%s - signal: %d form port: %s not handled for state: %d", __FUNCTION__, signal, portName.c_str(), m_state);
+      }
+      return;
+
+    case M_TOP_ERROR: // TOP
+      break;
+
+    case M_TOP_UNCONFIGURED:
+      if (port == &m_controlPort)
+      {
+        switch (signal)
+        {
+        case CMixerControlProtocol::INIT:
+          CVdpauConfig *data;
+          data = (CVdpauConfig*)msg->data;
+          if (data)
+          {
+            m_config = *data;
+          }
+          Init();
+          if (!m_vdpError)
+          {
+            m_state = M_TOP_CONFIGURED_WAIT1;
+            msg->Reply(CMixerControlProtocol::ACC);
+          }
+          else
+          {
+            msg->Reply(CMixerControlProtocol::ERROR);
+          }
+          return;
+        default:
+          break;
+        }
+      }
+      break;
+
+    case M_TOP_CONFIGURED:
+      if (port == &m_dataPort)
+      {
+        switch (signal)
+        {
+        case CMixerDataProtocol::FRAME:
+          CVdpauDecodedPicture *frame;
+          frame = (CVdpauDecodedPicture*)msg->data;
+          if (frame)
+          {
+            m_decodedPics.push(*frame);
+          }
+          m_extTimeout = 0;
+          return;
+        case CMixerDataProtocol::BUFFER:
+          VdpOutputSurface *surf;
+          surf = (VdpOutputSurface*)msg->data;
+          if (surf)
+          {
+            m_outputSurfaces.push(*surf);
+          }
+          m_extTimeout = 0;
+          return;
+        default:
+          break;
+        }
+      }
+      break;
+
+    case M_TOP_CONFIGURED_WAIT1:
+      if (port == NULL) // timeout
+      {
+        switch (signal)
+        {
+        case CMixerControlProtocol::TIMEOUT:
+          if (!m_decodedPics.empty() && !m_outputSurfaces.empty())
+          {
+            m_state = M_TOP_CONFIGURED_STEP1;
+            m_bStateMachineSelfTrigger = true;
+          }
+          else
+          {
+//            if (m_extTimeout != 0)
+//            {
+//              SetPostProcFeatures(false);
+//              CLog::Log(LOGWARNING,"CVDPAU::Mixer timeout - decoded: %d, outputSurf: %d", (int)m_decodedPics.size(), (int)m_outputSurfaces.size());
+//            }
+            m_extTimeout = 100;
+          }
+          return;
+        default:
+          break;
+        }
+      }
+      break;
+
+    case M_TOP_CONFIGURED_STEP1:
+      if (port == NULL) // timeout
+      {
+        switch (signal)
+        {
+        case CMixerControlProtocol::TIMEOUT:
+          m_mixerInput.push_front(m_decodedPics.front());
+          m_decodedPics.pop();
+          if (m_mixerInput.size() < 2)
+          {
+            m_state = M_TOP_CONFIGURED_WAIT1;
+            m_extTimeout = 0;
+            return;
+          }
+          InitCycle();
+          ProcessPicture();
+          if (m_vdpError)
+          {
+            m_state = M_TOP_CONFIGURED_WAIT1;
+            m_extTimeout = 1000;
+            return;
+          }
+          if (m_processPicture.DVDPic.format != RENDER_FMT_VDPAU_420)
+            m_outputSurfaces.pop();
+          m_config.stats->IncProcessed();
+          m_config.stats->DecDecoded();
+          m_dataPort.SendInMessage(CMixerDataProtocol::PICTURE,&m_processPicture,sizeof(m_processPicture));
+          if (m_mixersteps > 1)
+          {
+            m_state = M_TOP_CONFIGURED_WAIT2;
+            m_extTimeout = 0;
+          }
+          else
+          {
+            FiniCycle();
+            m_state = M_TOP_CONFIGURED_WAIT1;
+            m_extTimeout = 0;
+          }
+          return;
+        default:
+          break;
+        }
+      }
+      break;
+
+    case M_TOP_CONFIGURED_WAIT2:
+      if (port == NULL) // timeout
+      {
+        switch (signal)
+        {
+        case CMixerControlProtocol::TIMEOUT:
+          if (!m_outputSurfaces.empty())
+          {
+            m_state = M_TOP_CONFIGURED_STEP2;
+            m_bStateMachineSelfTrigger = true;
+          }
+          else
+          {
+//            if (m_extTimeout != 0)
+//            {
+//              SetPostProcFeatures(false);
+//              CLog::Log(LOGNOTICE,"---mixer wait2 decoded: %d, outputSurf: %d", (int)m_decodedPics.size(), (int)m_outputSurfaces.size());
+//            }
+            m_extTimeout = 100;
+          }
+          return;
+        default:
+          break;
+        }
+      }
+      break;
+
+    case M_TOP_CONFIGURED_STEP2:
+       if (port == NULL) // timeout
+       {
+         switch (signal)
+         {
+         case CMixerControlProtocol::TIMEOUT:
+           m_processPicture.outputSurface = m_outputSurfaces.front();
+           m_mixerstep = 1;
+           ProcessPicture();
+           if (m_vdpError)
+           {
+             m_state = M_TOP_CONFIGURED_WAIT1;
+             m_extTimeout = 1000;
+             return;
+           }
+           if (m_processPicture.DVDPic.format != RENDER_FMT_VDPAU_420)
+             m_outputSurfaces.pop();
+           m_config.stats->IncProcessed();
+           m_dataPort.SendInMessage(CMixerDataProtocol::PICTURE,&m_processPicture,sizeof(m_processPicture));
+           FiniCycle();
+           m_state = M_TOP_CONFIGURED_WAIT1;
+           m_extTimeout = 0;
+           return;
+         default:
+           break;
+         }
+       }
+       break;
+
+    default: // we are in no state, should not happen
+      CLog::Log(LOGERROR, "CMixer::%s - no valid state: %d", __FUNCTION__, m_state);
+      return;
+    }
+  } // for
+}
+
+void CMixer::Process()
+{
+  Message *msg;
+  Protocol *port;
+  bool gotMsg;
+
+  m_state = M_TOP_UNCONFIGURED;
+  m_extTimeout = 1000;
+  m_bStateMachineSelfTrigger = false;
+
+  while (!m_bStop)
+  {
+    gotMsg = false;
+
+    if (m_bStateMachineSelfTrigger)
+    {
+      m_bStateMachineSelfTrigger = false;
+      // self trigger state machine
+      StateMachine(msg->signal, port, msg);
+      if (!m_bStateMachineSelfTrigger)
+      {
+        msg->Release();
+        msg = NULL;
+      }
+      continue;
+    }
+    // check control port
+    else if (m_controlPort.ReceiveOutMessage(&msg))
+    {
+      gotMsg = true;
+      port = &m_controlPort;
+    }
+    // check data port
+    else if (m_dataPort.ReceiveOutMessage(&msg))
+    {
+      gotMsg = true;
+      port = &m_dataPort;
+    }
+
+    if (gotMsg)
+    {
+      StateMachine(msg->signal, port, msg);
+      if (!m_bStateMachineSelfTrigger)
+      {
+        msg->Release();
+        msg = NULL;
+      }
+      continue;
+    }
+
+    // wait for message
+    else if (m_outMsgEvent.WaitMSec(m_extTimeout))
+    {
+      continue;
+    }
+    // time out
+    else
+    {
+      msg = m_controlPort.GetMessage();
+      msg->signal = CMixerControlProtocol::TIMEOUT;
+      port = 0;
+      // signal timeout to state machine
+      StateMachine(msg->signal, port, msg);
+      if (!m_bStateMachineSelfTrigger)
+      {
+        msg->Release();
+        msg = NULL;
+      }
+    }
+  }
+  Uninit();
+}
+
+void CMixer::CreateVdpauMixer()
+{
+  CLog::Log(LOGNOTICE, " (VDPAU) Creating the video mixer");
+
+  InitCSCMatrix(m_config.vidWidth);
+
+  VdpVideoMixerParameter parameters[] = {
+    VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH,
+    VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT,
+    VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE};
+
+  void const * parameter_values[] = {
+    &m_config.surfaceWidth,
+    &m_config.surfaceHeight,
+    &m_config.vdpChromaType};
+
+  VdpStatus vdp_st = VDP_STATUS_ERROR;
+  vdp_st = m_config.vdpProcs.vdp_video_mixer_create(m_config.vdpDevice,
+                                m_config.featureCount,
+                                m_config.vdpFeatures,
+                                ARSIZE(parameters),
+                                parameters,
+                                parameter_values,
+                                &m_videoMixer);
+  CheckStatus(vdp_st, __LINE__);
+
+  // create 3 pitches of black lines needed for clipping top
+  // and bottom lines when de-interlacing
+  m_BlackBar = new uint32_t[3*m_config.outWidth];
+  memset(m_BlackBar, 0, 3*m_config.outWidth*sizeof(uint32_t));
+
+}
+
+void CMixer::InitCSCMatrix(int Width)
+{
+  VdpStatus vdp_st;
+  m_Procamp.struct_version = VDP_PROCAMP_VERSION;
+  m_Procamp.brightness     = 0.0;
+  m_Procamp.contrast       = 1.0;
+  m_Procamp.saturation     = 1.0;
+  m_Procamp.hue            = 0;
+  vdp_st = m_config.vdpProcs.vdp_generate_csc_matrix(&m_Procamp,
+                                   (Width < 1000)? VDP_COLOR_STANDARD_ITUR_BT_601 : VDP_COLOR_STANDARD_ITUR_BT_709,
+                                   &m_CSCMatrix);
+  CheckStatus(vdp_st, __LINE__);
+}
+
+void CMixer::CheckFeatures()
+{
+  if (m_Upscale != m_config.upscale)
+  {
+    SetHWUpscaling();
+    m_Upscale = m_config.upscale;
+  }
+  if (m_Brightness != g_settings.m_currentVideoSettings.m_Brightness ||
+      m_Contrast   != g_settings.m_currentVideoSettings.m_Contrast)
+  {
+    SetColor();
+    m_Brightness = g_settings.m_currentVideoSettings.m_Brightness;
+    m_Contrast = g_settings.m_currentVideoSettings.m_Contrast;
+  }
+  if (m_NoiseReduction != g_settings.m_currentVideoSettings.m_NoiseReduction)
+  {
+    m_NoiseReduction = g_settings.m_currentVideoSettings.m_NoiseReduction;
+    SetNoiseReduction();
+  }
+  if (m_Sharpness != g_settings.m_currentVideoSettings.m_Sharpness)
+  {
+    m_Sharpness = g_settings.m_currentVideoSettings.m_Sharpness;
+    SetSharpness();
+  }
+  if (m_DeintMode != g_settings.m_currentVideoSettings.m_DeinterlaceMode ||
+      m_Deint     != g_settings.m_currentVideoSettings.m_InterlaceMethod)
+  {
+    m_DeintMode = g_settings.m_currentVideoSettings.m_DeinterlaceMode;
+    m_Deint     = g_settings.m_currentVideoSettings.m_InterlaceMethod;
+    SetDeinterlacing();
+  }
+}
+
+void CMixer::SetPostProcFeatures(bool postProcEnabled)
+{
+  if (m_PostProc != postProcEnabled)
+  {
+    if (postProcEnabled)
+    {
+      SetNoiseReduction();
+      SetSharpness();
+      SetDeinterlacing();
+      SetHWUpscaling();
+    }
+    else
+      PostProcOff();
+    m_PostProc = postProcEnabled;
+  }
+}
+
+void CMixer::PostProcOff()
+{
+  VdpStatus vdp_st;
+
+  if (m_videoMixer == VDP_INVALID_HANDLE)
+    return;
+
+  VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL,
+                                     VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL,
+                                     VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE};
+
+  VdpBool enabled[]={0,0,0};
+  vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
+  CheckStatus(vdp_st, __LINE__);
+
+  if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION))
+  {
+    VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION};
+
+    VdpBool enabled[]={0};
+    vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
+    CheckStatus(vdp_st, __LINE__);
+  }
+
+  if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_SHARPNESS))
+  {
+    VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_SHARPNESS};
+
+    VdpBool enabled[]={0};
+    vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
+    CheckStatus(vdp_st, __LINE__);
+  }
+
+  DisableHQScaling();
+}
+
+
+bool CMixer::GenerateStudioCSCMatrix(VdpColorStandard colorStandard, VdpCSCMatrix &studioCSCMatrix)
+{
+   // instead use studioCSCKCoeffs601[3], studioCSCKCoeffs709[3] to generate float[3][4] matrix (float studioCSC[3][4])
+   // m00 = mRY = red: luma factor (contrast factor) (1.0)
+   // m10 = mGY = green: luma factor (contrast factor) (1.0)
+   // m20 = mBY = blue: luma factor (contrast factor) (1.0)
+   //
+   // m01 = mRB = red: blue color diff coeff (0.0)
+   // m11 = mGB = green: blue color diff coeff (-2Kb(1-Kb)/(Kg))
+   // m21 = mBB = blue: blue color diff coeff ((1-Kb)/0.5)
+   //
+   // m02 = mRR = red: red color diff coeff ((1-Kr)/0.5)
+   // m12 = mGR = green: red color diff coeff (-2Kr(1-Kr)/(Kg))
+   // m22 = mBR = blue: red color diff coeff (0.0)
+   //
+   // m03 = mRC = red: colour zero offset (brightness factor) (-(1-Kr)/0.5 * (128/255))
+   // m13 = mGC = green: colour zero offset (brightness factor) ((256/255) * (Kb(1-Kb) + Kr(1-Kr)) / Kg)
+   // m23 = mBC = blue: colour zero offset (brightness factor) (-(1-Kb)/0.5 * (128/255))
+
+   // columns
+   int Y = 0;
+   int Cb = 1;
+   int Cr = 2;
+   int C = 3;
+   // rows
+   int R = 0;
+   int G = 1;
+   int B = 2;
+   // colour standard coefficients for red, geen, blue
+   double Kr, Kg, Kb;
+   // colour diff zero position (use standard 8-bit coding precision)
+   double CDZ = 128; //256*0.5
+   // range excursion (use standard 8-bit coding precision)
+   double EXC = 255; //256-1
+
+   if (colorStandard == VDP_COLOR_STANDARD_ITUR_BT_601)
+   {
+      Kr = studioCSCKCoeffs601[0];
+      Kg = studioCSCKCoeffs601[1];
+      Kb = studioCSCKCoeffs601[2];
+   }
+   else // assume VDP_COLOR_STANDARD_ITUR_BT_709
+   {
+      Kr = studioCSCKCoeffs709[0];
+      Kg = studioCSCKCoeffs709[1];
+      Kb = studioCSCKCoeffs709[2];
+   }
+   // we keep luma unscaled to retain the levels present in source so that 16-235 luma is converted to RGB 16-235
+   studioCSCMatrix[R][Y] = 1.0;
+   studioCSCMatrix[G][Y] = 1.0;
+   studioCSCMatrix[B][Y] = 1.0;
+
+   studioCSCMatrix[R][Cb] = 0.0;
+   studioCSCMatrix[G][Cb] = (double)-2 * Kb * (1 - Kb) / Kg;
+   studioCSCMatrix[B][Cb] = (double)(1 - Kb) / 0.5;
+
+   studioCSCMatrix[R][Cr] = (double)(1 - Kr) / 0.5;
+   studioCSCMatrix[G][Cr] = (double)-2 * Kr * (1 - Kr) / Kg;
+   studioCSCMatrix[B][Cr] = 0.0;
+
+   studioCSCMatrix[R][C] = (double)-1 * studioCSCMatrix[R][Cr] * CDZ/EXC;
+   studioCSCMatrix[G][C] = (double)-1 * (studioCSCMatrix[G][Cb] + studioCSCMatrix[G][Cr]) * CDZ/EXC;
+   studioCSCMatrix[B][C] = (double)-1 * studioCSCMatrix[B][Cb] * CDZ/EXC;
+
+   return true;
+}
+
+void CMixer::SetColor()
+{
+  VdpStatus vdp_st;
+
+  if (m_Brightness != g_settings.m_currentVideoSettings.m_Brightness)
+    m_Procamp.brightness = (float)((g_settings.m_currentVideoSettings.m_Brightness)-50) / 100;
+  if (m_Contrast != g_settings.m_currentVideoSettings.m_Contrast)
+    m_Procamp.contrast = (float)((g_settings.m_currentVideoSettings.m_Contrast)+50) / 100;
+
+  VdpColorStandard colorStandard;
+//  if(vid_height >= 600 || vid_width > 1024)
+  if(m_config.surfaceWidth > 1000)
+    colorStandard = VDP_COLOR_STANDARD_ITUR_BT_709;
+    //vdp_st = vdp_generate_csc_matrix(&m_Procamp, VDP_COLOR_STANDARD_ITUR_BT_709, &m_CSCMatrix);
+  else
+    colorStandard = VDP_COLOR_STANDARD_ITUR_BT_601;
+    //vdp_st = vdp_generate_csc_matrix(&m_Procamp, VDP_COLOR_STANDARD_ITUR_BT_601, &m_CSCMatrix);
+
+  VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX };
+  if (g_guiSettings.GetBool("videoplayer.vdpaustudiolevel"))
+  {
+    float studioCSC[3][4];
+    GenerateStudioCSCMatrix(colorStandard, studioCSC);
+    void const * pm_CSCMatix[] = { &studioCSC };
+    vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix);
+  }
+  else
+  {
+    vdp_st = m_config.vdpProcs.vdp_generate_csc_matrix(&m_Procamp, colorStandard, &m_CSCMatrix);
+    void const * pm_CSCMatix[] = { &m_CSCMatrix };
+    vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix);
+  }
+  CheckStatus(vdp_st, __LINE__);
+}
+
+void CMixer::SetNoiseReduction()
+{
+  if(!m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION))
+    return;
+
+  VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION };
+  VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL };
+  VdpStatus vdp_st;
+
+  if (!g_settings.m_currentVideoSettings.m_NoiseReduction)
+  {
+    VdpBool enabled[]= {0};
+    vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
+    CheckStatus(vdp_st, __LINE__);
+    return;
+  }
+  VdpBool enabled[]={1};
+  vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
+  CheckStatus(vdp_st, __LINE__);
+  void* nr[] = { &g_settings.m_currentVideoSettings.m_NoiseReduction };
+  CLog::Log(LOGNOTICE,"Setting Noise Reduction to %f",g_settings.m_currentVideoSettings.m_NoiseReduction);
+  vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, nr);
+  CheckStatus(vdp_st, __LINE__);
+}
+
+void CMixer::SetSharpness()
+{
+  if(!m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_SHARPNESS))
+    return;
+
+  VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_SHARPNESS };
+  VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL };
+  VdpStatus vdp_st;
+
+  if (!g_settings.m_currentVideoSettings.m_Sharpness)
+  {
+    VdpBool enabled[]={0};
+    vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
+    CheckStatus(vdp_st, __LINE__);
+    return;
+  }
+  VdpBool enabled[]={1};
+  vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
+  CheckStatus(vdp_st, __LINE__);
+  void* sh[] = { &g_settings.m_currentVideoSettings.m_Sharpness };
+  CLog::Log(LOGNOTICE,"Setting Sharpness to %f",g_settings.m_currentVideoSettings.m_Sharpness);
+  vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, sh);
+  CheckStatus(vdp_st, __LINE__);
+}
+
+EINTERLACEMETHOD CMixer::GetDeinterlacingMethod(bool log /* = false */)
+{
+  EINTERLACEMETHOD method = g_settings.m_currentVideoSettings.m_InterlaceMethod;
+  if (method == VS_INTERLACEMETHOD_AUTO)
+  {
+    int deint = -1;
+//    if (m_config.outHeight >= 720)
+//      deint = g_advancedSettings.m_videoVDPAUdeintHD;
+//    else
+//      deint = g_advancedSettings.m_videoVDPAUdeintSD;
+
+    if (deint != -1)
+    {
+      if (m_config.vdpau->Supports(EINTERLACEMETHOD(deint)))
+      {
+        method = EINTERLACEMETHOD(deint);
+        if (log)
+          CLog::Log(LOGNOTICE, "CVDPAU::GetDeinterlacingMethod: set de-interlacing to %d",  deint);
+      }
+      else
+      {
+        if (log)
+          CLog::Log(LOGWARNING, "CVDPAU::GetDeinterlacingMethod: method for de-interlacing (advanced settings) not supported");
+      }
+    }
+  }
+  return method;
+}
+
+void CMixer::SetDeinterlacing()
+{
+  VdpStatus vdp_st;
+
+  if (m_videoMixer == VDP_INVALID_HANDLE)
+    return;
+
+  EDEINTERLACEMODE   mode = g_settings.m_currentVideoSettings.m_DeinterlaceMode;
+  EINTERLACEMETHOD method = GetDeinterlacingMethod(true);
+
+  VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL,
+                                     VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL,
+                                     VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE };
+
+  if (mode == VS_DEINTERLACEMODE_OFF)
+  {
+    VdpBool enabled[] = {0,0,0};
+    vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
+  }
+  else
+  {
+    if (method == VS_INTERLACEMETHOD_AUTO)
+    {
+      VdpBool enabled[] = {1,0,0};
+      if (g_advancedSettings.m_videoVDPAUtelecine)
+        enabled[2] = 1;
+      vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
+    }
+    else if (method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL
+         ||  method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF)
+    {
+      VdpBool enabled[] = {1,0,0};
+      if (g_advancedSettings.m_videoVDPAUtelecine)
+        enabled[2] = 1;
+      vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
+    }
+    else if (method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL
+         ||  method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF)
+    {
+      VdpBool enabled[] = {1,1,0};
+      if (g_advancedSettings.m_videoVDPAUtelecine)
+        enabled[2] = 1;
+      vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
+    }
+    else
+    {
+      VdpBool enabled[]={0,0,0};
+      vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
+    }
+  }
+  CheckStatus(vdp_st, __LINE__);
+
+  SetDeintSkipChroma();
+
+  m_config.useInteropYuv = g_guiSettings.GetBool("videoplayer.usevdpauinteropyuv");
+}
+
+void CMixer::SetDeintSkipChroma()
+{
+  VdpVideoMixerAttribute attribute[] = { VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE};
+  VdpStatus vdp_st;
+
+  uint8_t val;
+  if (g_advancedSettings.m_videoVDPAUdeintSkipChromaHD && m_config.outHeight >= 720)
+    val = 1;
+  else
+    val = 0;
+
+  void const *values[]={&val};
+  vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attribute), attribute, values);
+
+  CheckStatus(vdp_st, __LINE__);
+}
+
+void CMixer::SetHWUpscaling()
+{
+#ifdef VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
+
+  VdpStatus vdp_st;
+  VdpBool enabled[]={1};
+  switch (m_config.upscale)
+  {
+    case 9:
+       if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9))
+       {
+          VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9 };
+          vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
+          break;
+       }
+    case 8:
+       if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8))
+       {
+          VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8 };
+          vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
+          break;
+       }
+    case 7:
+       if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7))
+       {
+          VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7 };
+          vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
+          break;
+       }
+    case 6:
+       if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6))
+       {
+          VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6 };
+          vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
+          break;
+       }
+    case 5:
+       if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5))
+       {
+          VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5 };
+          vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
+          break;
+       }
+    case 4:
+       if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4))
+       {
+          VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4 };
+          vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
+          break;
+       }
+    case 3:
+       if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3))
+       {
+          VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3 };
+          vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
+          break;
+       }
+    case 2:
+       if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2))
+       {
+          VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2 };
+          vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
+          break;
+       }
+    case 1:
+       if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1))
+       {
+          VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 };
+          vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
+          break;
+       }
+    default:
+       DisableHQScaling();
+       return;
+  }
+  CheckStatus(vdp_st, __LINE__);
+#endif
+}
+
+void CMixer::DisableHQScaling()
+{
+  VdpStatus vdp_st;
+
+  if (m_videoMixer == VDP_INVALID_HANDLE)
+    return;
+
+  if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1))
+  {
+    VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 };
+    VdpBool enabled[]={0};
+    vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
+    CheckStatus(vdp_st, __LINE__);
+  }
+
+  if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2))
+  {
+    VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2 };
+    VdpBool enabled[]={0};
+    vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
+    CheckStatus(vdp_st, __LINE__);
+  }
+
+  if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3))
+  {
+    VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3 };
+    VdpBool enabled[]={0};
+    vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
+    CheckStatus(vdp_st, __LINE__);
+  }
+
+  if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4))
+  {
+    VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4 };
+    VdpBool enabled[]={0};
+    vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
+    CheckStatus(vdp_st, __LINE__);
+  }
+
+  if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5))
+  {
+    VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5 };
+    VdpBool enabled[]={0};
+    vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
+    CheckStatus(vdp_st, __LINE__);
+  }
+
+  if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6))
+  {
+    VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6 };
+    VdpBool enabled[]={0};
+    vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
+    CheckStatus(vdp_st, __LINE__);
+  }
+
+  if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7))
+  {
+    VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7 };
+    VdpBool enabled[]={0};
+    vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
+    CheckStatus(vdp_st, __LINE__);
+  }
+
+  if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8))
+  {
+    VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8 };
+    VdpBool enabled[]={0};
+    vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
+    CheckStatus(vdp_st, __LINE__);
+  }
+
+  if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9))
+  {
+    VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9 };
+    VdpBool enabled[]={0};
+    vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
+    CheckStatus(vdp_st, __LINE__);
+  }
+}
+
+
+void CMixer::Init()
+{
+  m_Brightness = 0.0;
+  m_Contrast = 0.0;
+  m_NoiseReduction = 0.0;
+  m_Sharpness = 0.0;
+  m_DeintMode = 0;
+  m_Deint = 0;
+  m_PostProc = false;
+  m_vdpError = false;
+
+  m_config.upscale = g_advancedSettings.m_videoVDPAUScaling;
+  m_config.useInteropYuv = g_guiSettings.GetBool("videoplayer.usevdpauinteropyuv");
+
+  CreateVdpauMixer();
+}
+
+void CMixer::Uninit()
+{
+  Flush();
+  while (!m_outputSurfaces.empty())
+  {
+    m_outputSurfaces.pop();
+  }
+  m_config.vdpProcs.vdp_video_mixer_destroy(m_videoMixer);
+}
+
+void CMixer::Flush()
+{
+  while (!m_mixerInput.empty())
+  {
+    CVdpauDecodedPicture pic = m_mixerInput.back();
+    m_mixerInput.pop_back();
+    CSingleLock lock(*m_config.videoSurfaceSec);
+    if (pic.render)
+      pic.render->state &= ~FF_VDPAU_STATE_USED_FOR_RENDER;
+  }
+  while (!m_decodedPics.empty())
+  {
+    CVdpauDecodedPicture pic = m_decodedPics.front();
+    m_decodedPics.pop();
+    CSingleLock lock(*m_config.videoSurfaceSec);
+    if (pic.render)
+      pic.render->state &= ~FF_VDPAU_STATE_USED_FOR_RENDER;
+  }
+  Message *msg;
+  while (m_dataPort.ReceiveOutMessage(&msg))
+  {
+    if (msg->signal == CMixerDataProtocol::FRAME)
+    {
+      CVdpauDecodedPicture pic = *(CVdpauDecodedPicture*)msg->data;
+      CSingleLock lock(*m_config.videoSurfaceSec);
+      if (pic.render)
+        pic.render->state &= ~FF_VDPAU_STATE_USED_FOR_RENDER;
+    }
+    else if (msg->signal == CMixerDataProtocol::BUFFER)
+    {
+      VdpOutputSurface *surf;
+      surf = (VdpOutputSurface*)msg->data;
+      m_outputSurfaces.push(*surf);
+    }
+    msg->Release();
+  }
+}
+
+void CMixer::InitCycle()
+{
+  CheckFeatures();
+  uint64_t latency;
+  int flags;
+  m_config.stats->GetParams(latency, flags);
+  latency = (latency*1000)/CurrentHostFrequency();
+  if (flags & DVP_FLAG_NO_POSTPROC)
+    SetPostProcFeatures(false);
+  else
+    SetPostProcFeatures(true);
+
+  m_config.stats->SetCanSkipDeint(false);
+
+  EDEINTERLACEMODE   mode = g_settings.m_currentVideoSettings.m_DeinterlaceMode;
+  EINTERLACEMETHOD method = GetDeinterlacingMethod();
+  bool interlaced = m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_INTERLACED;
+
+  if (mode == VS_DEINTERLACEMODE_FORCE ||
+     (mode == VS_DEINTERLACEMODE_AUTO && interlaced))
+  {
+    if((method == VS_INTERLACEMETHOD_AUTO && interlaced)
+      ||  method == VS_INTERLACEMETHOD_VDPAU_BOB
+      ||  method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL
+      ||  method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF
+      ||  method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL
+      ||  method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF
+      ||  method == VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE )
+    {
+      if(method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF
+        || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF
+        || !g_graphicsContext.IsFullScreenVideo())
+        m_mixersteps = 1;
+      else
+      {
+        m_mixersteps = 2;
+        m_config.stats->SetCanSkipDeint(true);
+      }
+
+      if (m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_DROPDEINT)
+      {
+        m_mixersteps = 1;
+      }
+
+      if(m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_TOP_FIELD_FIRST)
+        m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD;
+      else
+        m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD;
+
+      m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU;
+      m_mixerInput[1].DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST |
+                                        DVP_FLAG_REPEAT_TOP_FIELD |
+                                        DVP_FLAG_INTERLACED);
+      m_config.useInteropYuv = false;
+    }
+    else if (method == VS_INTERLACEMETHOD_RENDER_BOB && m_config.useInteropYuv)
+    {
+      m_mixersteps = 1;
+      m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
+      m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU_420;
+    }
+    else
+    {
+      CLog::Log(LOGERROR, "CMixer::%s - interlace method not supported", __FUNCTION__);
+      m_mixersteps = 1;
+      m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
+      m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU;
+      m_mixerInput[1].DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST |
+                                        DVP_FLAG_REPEAT_TOP_FIELD |
+                                        DVP_FLAG_INTERLACED);
+    }
+  }
+  else
+  {
+    m_mixersteps = 1;
+    m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
+
+    if (m_config.useInteropYuv)
+      m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU_420;
+    else
+    {
+      m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU;
+      m_mixerInput[1].DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST |
+                                        DVP_FLAG_REPEAT_TOP_FIELD |
+                                        DVP_FLAG_INTERLACED);
+    }
+  }
+  m_mixerstep = 0;
+
+  if (m_mixerInput[1].DVDPic.format == RENDER_FMT_VDPAU)
+  {
+    m_processPicture.outputSurface = m_outputSurfaces.front();
+    m_mixerInput[1].DVDPic.iWidth = m_config.outWidth;
+    m_mixerInput[1].DVDPic.iHeight = m_config.outHeight;
+  }
+  else
+  {
+    m_mixerInput[1].DVDPic.iWidth = m_config.vidWidth;
+    m_mixerInput[1].DVDPic.iHeight = m_config.vidHeight;
+  }
+
+  m_processPicture.DVDPic = m_mixerInput[1].DVDPic;
+  m_processPicture.render = m_mixerInput[1].render;
+}
+
+void CMixer::FiniCycle()
+{
+  while (m_mixerInput.size() > 3)
+  {
+    CVdpauDecodedPicture &tmp = m_mixerInput.back();
+    if (tmp.render && m_processPicture.DVDPic.format != RENDER_FMT_VDPAU_420)
+    {
+      CSingleLock lock(*m_config.videoSurfaceSec);
+      tmp.render->state &= ~FF_VDPAU_STATE_USED_FOR_RENDER;
+    }
+    m_mixerInput.pop_back();
+//    m_config.stats->DecDecoded();
+  }
+}
+
+void CMixer::ProcessPicture()
+{
+  if (m_processPicture.DVDPic.format == RENDER_FMT_VDPAU_420)
+    return;
+
+  VdpStatus vdp_st;
+
+  if (m_mixerstep == 1)
+  {
+    if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD)
+      m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD;
+    else
+      m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD;
+  }
+
+  VdpVideoSurface past_surfaces[4] = { VDP_INVALID_HANDLE, VDP_INVALID_HANDLE, VDP_INVALID_HANDLE, VDP_INVALID_HANDLE };
+  VdpVideoSurface futu_surfaces[2] = { VDP_INVALID_HANDLE, VDP_INVALID_HANDLE };
+  uint32_t pastCount = 4;
+  uint32_t futuCount = 2;
+
+  if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME)
+  {
+    // use only 2 past 1 future for progressive/weave
+    // (only used for postproc anyway eg noise reduction)
+    if (m_mixerInput.size() > 3)
+      past_surfaces[1] = m_mixerInput[3].render->surface;
+    if (m_mixerInput.size() > 2)
+      past_surfaces[0] = m_mixerInput[2].render->surface;
+    futu_surfaces[0] = m_mixerInput[0].render->surface;
+    pastCount = 2;
+    futuCount = 1;
+  }
+  else
+  {
+    if(m_mixerstep == 0)
+    { // first field
+      if (m_mixerInput.size() > 3)
+      {
+        past_surfaces[3] = m_mixerInput[3].render->surface;
+        past_surfaces[2] = m_mixerInput[3].render->surface;
+      }
+      if (m_mixerInput.size() > 2)
+      {
+        past_surfaces[1] = m_mixerInput[2].render->surface;
+        past_surfaces[0] = m_mixerInput[2].render->surface;
+      }
+      futu_surfaces[0] = m_mixerInput[1].render->surface;
+      futu_surfaces[1] = m_mixerInput[0].render->surface;;
+    }
+    else
+    { // second field
+      if (m_mixerInput.size() > 3)
+      {
+        past_surfaces[3] = m_mixerInput[3].render->surface;
+      }
+      if (m_mixerInput.size() > 2)
+      {
+        past_surfaces[2] = m_mixerInput[2].render->surface;
+        past_surfaces[1] = m_mixerInput[2].render->surface;
+      }
+      past_surfaces[0] = m_mixerInput[1].render->surface;
+      futu_surfaces[0] = m_mixerInput[1].render->surface;
+      futu_surfaces[1] = m_mixerInput[1].render->surface;
+
+      m_processPicture.DVDPic.pts = DVD_NOPTS_VALUE;
+      m_processPicture.DVDPic.dts = DVD_NOPTS_VALUE;
+    }
+    m_processPicture.DVDPic.iRepeatPicture = 0.0;
+  } // interlaced
+
+  VdpRect sourceRect;
+  sourceRect.x0 = 0;
+  sourceRect.y0 = 0;
+  sourceRect.x1 = m_config.vidWidth;
+  sourceRect.y1 = m_config.vidHeight;
+
+  VdpRect destRect;
+  destRect.x0 = 0;
+  destRect.y0 = 0;
+  destRect.x1 = m_config.outWidth;
+  destRect.y1 = m_config.outHeight;
+
+  // start vdpau video mixer
+  vdp_st = m_config.vdpProcs.vdp_video_mixer_render(m_videoMixer,
+                                VDP_INVALID_HANDLE,
+                                0,
+                                m_mixerfield,
+                                pastCount,
+                                past_surfaces,
+                                m_mixerInput[1].render->surface,
+                                futuCount,
+                                futu_surfaces,
+                                &sourceRect,
+                                m_processPicture.outputSurface,
+                                &destRect,
+                                &destRect,
+                                0,
+                                NULL);
+  CheckStatus(vdp_st, __LINE__);
+
+  if (m_mixerfield != VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME)
+  {
+    // in order to clip top and bottom lines when de-interlacing
+    // we black those lines as a work around for not working
+    // background colour using the mixer
+    // pixel perfect is preferred over overscanning or zooming
+
+    VdpRect clipRect = destRect;
+    clipRect.y1 = clipRect.y0 + 2;
+    uint32_t *data[] = {m_BlackBar};
+    uint32_t pitches[] = {destRect.x1};
+    vdp_st = m_config.vdpProcs.vdp_output_surface_put_bits_native(m_processPicture.outputSurface,
+                                            (void**)data,
+                                            pitches,
+                                            &clipRect);
+    CheckStatus(vdp_st, __LINE__);
+
+    clipRect = destRect;
+    clipRect.y0 = clipRect.y1 - 2;
+    vdp_st = m_config.vdpProcs.vdp_output_surface_put_bits_native(m_processPicture.outputSurface,
+                                            (void**)data,
+                                            pitches,
+                                            &clipRect);
+    CheckStatus(vdp_st, __LINE__);
+  }
+}
+
+
+bool CMixer::CheckStatus(VdpStatus vdp_st, int line)
+{
+  if (vdp_st != VDP_STATUS_OK)
+  {
+    CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) at %s:%d\n", m_config.vdpProcs.vdp_get_error_string(vdp_st), vdp_st, __FILE__, line);
+    m_vdpError = true;
+    return true;
+  }
+  return false;
+}
+
+//-----------------------------------------------------------------------------
+// Output
+//-----------------------------------------------------------------------------
+COutput::COutput(CEvent *inMsgEvent) :
+  CThread("Vdpau Output Thread"),
+  m_controlPort("OutputControlPort", inMsgEvent, &m_outMsgEvent),
+  m_dataPort("OutputDataPort", inMsgEvent, &m_outMsgEvent),
+  m_mixer(&m_outMsgEvent)
+{
+  m_inMsgEvent = inMsgEvent;
+
+  CVdpauRenderPicture pic;
+  pic.renderPicSection = &m_bufferPool.renderPicSec;
+  pic.refCount = 0;
+  for (unsigned int i = 0; i < NUM_RENDER_PICS; i++)
+  {
+    m_bufferPool.allRenderPics.push_back(pic);
+  }
+  for (unsigned int i = 0; i < m_bufferPool.allRenderPics.size(); ++i)
+  {
+    m_bufferPool.freeRenderPics.push_back(&m_bufferPool.allRenderPics[i]);
+  }
+}
+
+void COutput::Start()
+{
+  Create();
+}
+
+COutput::~COutput()
+{
+  Dispose();
+
+  m_bufferPool.freeRenderPics.clear();
+  m_bufferPool.usedRenderPics.clear();
+  m_bufferPool.allRenderPics.clear();
+}
+
+void COutput::Dispose()
+{
+  CSingleLock lock(g_graphicsContext);
+  m_bStop = true;
+  m_outMsgEvent.Set();
+  StopThread();
+  m_controlPort.Purge();
+  m_dataPort.Purge();
+}
+
+void COutput::OnStartup()
+{
+  CLog::Log(LOGNOTICE, "COutput::OnStartup: Output Thread created");
+}
+
+void COutput::OnExit()
+{
+  CLog::Log(LOGNOTICE, "COutput::OnExit: Output Thread terminated");
+}
+
+enum OUTPUT_STATES
+{
+  O_TOP = 0,                      // 0
+  O_TOP_ERROR,                    // 1
+  O_TOP_UNCONFIGURED,             // 2
+  O_TOP_CONFIGURED,               // 3
+  O_TOP_CONFIGURED_IDLE,          // 4
+  O_TOP_CONFIGURED_WORK,          // 5
+};
+
+int VDPAU_OUTPUT_parentStates[] = {
+    -1,
+    0, //TOP_ERROR
+    0, //TOP_UNCONFIGURED
+    0, //TOP_CONFIGURED
+    3, //TOP_CONFIGURED_IDLE
+    3, //TOP_CONFIGURED_WORK
+};
+
+void COutput::StateMachine(int signal, Protocol *port, Message *msg)
+{
+  for (int state = m_state; ; state = VDPAU_OUTPUT_parentStates[state])
+  {
+    switch (state)
+    {
+    case O_TOP: // TOP
+      if (port == &m_controlPort)
+      {
+        switch (signal)
+        {
+        case COutputControlProtocol::FLUSH:
+          msg->Reply(COutputControlProtocol::ACC);
+          return;
+        case COutputControlProtocol::PRECLEANUP:
+          msg->Reply(COutputControlProtocol::ACC);
+          return;
+        default:
+          break;
+        }
+      }
+      else if (port == &m_dataPort)
+      {
+        switch (signal)
+        {
+        case COutputDataProtocol::RETURNPIC:
+          CVdpauRenderPicture *pic;
+          pic = *((CVdpauRenderPicture**)msg->data);
+          ProcessReturnPicture(pic);
+          return;
+        default:
+          break;
+        }
+      }
+      {
+        std::string portName = port == NULL ? "timer" : port->portName;
+        CLog::Log(LOGWARNING, "COutput::%s - signal: %d form port: %s not handled for state: %d", __FUNCTION__, signal, portName.c_str(), m_state);
+      }
+      return;
+
+    case O_TOP_ERROR:
+      break;
+
+    case O_TOP_UNCONFIGURED:
+      if (port == &m_controlPort)
+      {
+        switch (signal)
+        {
+        case COutputControlProtocol::INIT:
+          CVdpauConfig *data;
+          data = (CVdpauConfig*)msg->data;
+          if (data)
+          {
+            m_config = *data;
+          }
+          Init();
+          Message *reply;
+          if (m_mixer.m_controlPort.SendOutMessageSync(CMixerControlProtocol::INIT,
+                                     &reply, 1000, &m_config, sizeof(m_config)))
+          {
+            if (reply->signal != CMixerControlProtocol::ACC)
+              m_vdpError = true;
+            reply->Release();
+          }
+
+          // set initial number of
+          m_bufferPool.numOutputSurfaces = 4;
+          EnsureBufferPool();
+          if (!m_vdpError)
+          {
+            m_state = O_TOP_CONFIGURED_IDLE;
+            msg->Reply(COutputControlProtocol::ACC);
+          }
+          else
+          {
+            m_state = O_TOP_ERROR;
+            msg->Reply(COutputControlProtocol::ERROR);
+          }
+          return;
+        default:
+          break;
+        }
+      }
+      break;
+
+    case O_TOP_CONFIGURED:
+      if (port == &m_controlPort)
+      {
+        switch (signal)
+        {
+        case COutputControlProtocol::FLUSH:
+          Flush();
+          msg->Reply(COutputControlProtocol::ACC);
+          return;
+        case COutputControlProtocol::PRECLEANUP:
+          Flush();
+          msg->Reply(COutputControlProtocol::ACC);
+          return;
+        default:
+          break;
+        }
+      }
+      else if (port == &m_dataPort)
+      {
+        switch (signal)
+        {
+        case COutputDataProtocol::NEWFRAME:
+          CVdpauDecodedPicture *frame;
+          frame = (CVdpauDecodedPicture*)msg->data;
+          if (frame)
+          {
+            m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::FRAME,
+                                               frame,sizeof(CVdpauDecodedPicture));
+          }
+          return;
+        case COutputDataProtocol::RETURNPIC:
+          CVdpauRenderPicture *pic;
+          pic = *((CVdpauRenderPicture**)msg->data);
+          ProcessReturnPicture(pic);
+          m_controlPort.SendInMessage(COutputControlProtocol::STATS);
+          m_state = O_TOP_CONFIGURED_WORK;
+          m_extTimeout = 0;
+          return;
+        default:
+          break;
+        }
+      }
+      else if (port == &m_mixer.m_dataPort)
+      {
+        switch (signal)
+        {
+        case CMixerDataProtocol::PICTURE:
+          CVdpauProcessedPicture *pic;
+          pic = (CVdpauProcessedPicture*)msg->data;
+          m_bufferPool.processedPics.push(*pic);
+          m_state = O_TOP_CONFIGURED_WORK;
+          m_extTimeout = 0;
+          return;
+        default:
+          break;
+        }
+      }
+      break;
+
+    case O_TOP_CONFIGURED_IDLE:
+      if (port == NULL) // timeout
+      {
+        switch (signal)
+        {
+        case COutputControlProtocol::TIMEOUT:
+//          uint16_t decoded, processed, render;
+//          m_config.stats->Get(decoded, processed, render);
+//          CLog::Log(LOGDEBUG, "CVDPAU::COutput - timeout idle: decoded: %d, proc: %d, render: %d", decoded, processed, render);
+          return;
+        default:
+          break;
+        }
+      }
+      break;
+
+    case O_TOP_CONFIGURED_WORK:
+      if (port == NULL) // timeout
+      {
+        switch (signal)
+        {
+        case COutputControlProtocol::TIMEOUT:
+          if (HasWork())
+          {
+            CVdpauRenderPicture *pic;
+            pic = ProcessMixerPicture();
+            if (pic)
+            {
+              m_config.stats->DecProcessed();
+              m_config.stats->IncRender();
+              m_dataPort.SendInMessage(COutputDataProtocol::PICTURE, &pic, sizeof(pic));
+            }
+            m_extTimeout = 1;
+          }
+          else
+          {
+            m_state = O_TOP_CONFIGURED_IDLE;
+            m_extTimeout = 100;
+          }
+          return;
+        default:
+          break;
+        }
+      }
+      break;
+
+    default: // we are in no state, should not happen
+      CLog::Log(LOGERROR, "COutput::%s - no valid state: %d", __FUNCTION__, m_state);
+      return;
+    }
+  } // for
+}
+
+void COutput::Process()
+{
+  Message *msg;
+  Protocol *port;
+  bool gotMsg;
+
+  m_state = O_TOP_UNCONFIGURED;
+  m_extTimeout = 1000;
+  m_bStateMachineSelfTrigger = false;
+
+  while (!m_bStop)
+  {
+    gotMsg = false;
+
+    if (m_bStateMachineSelfTrigger)
+    {
+      m_bStateMachineSelfTrigger = false;
+      // self trigger state machine
+      StateMachine(msg->signal, port, msg);
+      if (!m_bStateMachineSelfTrigger)
+      {
+        msg->Release();
+        msg = NULL;
+      }
+      continue;
+    }
+    // check control port
+    else if (m_controlPort.ReceiveOutMessage(&msg))
+    {
+      gotMsg = true;
+      port = &m_controlPort;
+    }
+    // check data port
+    else if (m_dataPort.ReceiveOutMessage(&msg))
+    {
+      gotMsg = true;
+      port = &m_dataPort;
+    }
+    // check mixer data port
+    else if (m_mixer.m_dataPort.ReceiveInMessage(&msg))
+    {
+      gotMsg = true;
+      port = &m_mixer.m_dataPort;
+    }
+    if (gotMsg)
+    {
+      StateMachine(msg->signal, port, msg);
+      if (!m_bStateMachineSelfTrigger)
+      {
+        msg->Release();
+        msg = NULL;
+      }
+      continue;
+    }
+
+    // wait for message
+    else if (m_outMsgEvent.WaitMSec(m_extTimeout))
+    {
+      continue;
+    }
+    // time out
+    else
+    {
+      msg = m_controlPort.GetMessage();
+      msg->signal = COutputControlProtocol::TIMEOUT;
+      port = 0;
+      // signal timeout to state machine
+      StateMachine(msg->signal, port, msg);
+      if (!m_bStateMachineSelfTrigger)
+      {
+        msg->Release();
+        msg = NULL;
+      }
+    }
+  }
+  Flush();
+  Uninit();
+}
+
+bool COutput::Init()
+{
+  if (!CreateGlxContext())
+    return false;
+
+  if (!GLInit())
+    return false;
+
+  m_mixer.Start();
+  m_vdpError = false;
+
+  return true;
+}
+
+bool COutput::Uninit()
+{
+  m_mixer.Dispose();
+  GLUnmapSurfaces();
+  GLUnbindPixmaps();
+  ReleaseBufferPool();
+  DestroyGlxContext();
+  return true;
+}
+
+void COutput::Flush()
+{
+  Message *reply;
+  if (m_mixer.m_controlPort.SendOutMessageSync(CMixerControlProtocol::FLUSH,
+                                                 &reply,
+                                                 2000))
+  {
+    reply->Release();
+  }
+  else
+    CLog::Log(LOGERROR, "Coutput::%s - failed to flush mixer", __FUNCTION__);
+
+  Message *msg;
+  while (m_mixer.m_dataPort.ReceiveInMessage(&msg))
+  {
+    if (msg->signal == CMixerDataProtocol::PICTURE)
+    {
+      CVdpauProcessedPicture pic = *(CVdpauProcessedPicture*)msg->data;
+      if (pic.DVDPic.format == RENDER_FMT_VDPAU_420)
+      {
+        CSingleLock lock(*m_config.videoSurfaceSec);
+        if (pic.render)
+          pic.render->state &= ~FF_VDPAU_STATE_USED_FOR_RENDER;
+      }
+    }
+    msg->Release();
+  }
+
+  while (m_dataPort.ReceiveOutMessage(&msg))
+  {
+    if (msg->signal == COutputDataProtocol::NEWFRAME)
+    {
+      CVdpauDecodedPicture pic = *(CVdpauDecodedPicture*)msg->data;
+      CSingleLock lock(*m_config.videoSurfaceSec);
+      if (pic.render)
+        pic.render->state &= ~FF_VDPAU_STATE_USED_FOR_RENDER;
+    }
+    else if (msg->signal == COutputDataProtocol::RETURNPIC)
+    {
+      CVdpauRenderPicture *pic;
+      pic = *((CVdpauRenderPicture**)msg->data);
+      ProcessReturnPicture(pic);
+    }
+    msg->Release();
+  }
+
+  while (m_dataPort.ReceiveInMessage(&msg))
+  {
+    if (msg->signal == COutputDataProtocol::PICTURE)
+    {
+      CVdpauRenderPicture *pic;
+      pic = *((CVdpauRenderPicture**)msg->data);
+      ProcessReturnPicture(pic);
+    }
+  }
+
+  // reset used render flag which was cleared on mixer flush
+  std::deque<CVdpauRenderPicture*>::iterator it;
+  for (it = m_bufferPool.usedRenderPics.begin(); it != m_bufferPool.usedRenderPics.end(); ++it)
+  {
+    if ((*it)->DVDPic.format == RENDER_FMT_VDPAU_420)
+    {
+      std::map<VdpVideoSurface, VdpauBufferPool::GLVideoSurface>::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<CVdpauRenderPicture*>::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<VdpVideoSurface, VdpauBufferPool::GLVideoSurface>::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<VdpOutputSurface, VdpauBufferPool::GLVideoSurface>::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<void*>(m_config.vdpDevice), reinterpret_cast<void*>(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<void*>((*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.size(); i++)
+      {
+        glSurface.sourceRgb = m_bufferPool.outputSurfaces[i];
+        glGenTextures(1, glSurface.texture);
+        glSurface.glVdpauSurface = glVDPAURegisterOutputSurfaceNV(reinterpret_cast<void*>(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<VdpVideoSurface, VdpauBufferPool::GLVideoSurface>::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<VdpOutputSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
+  for (it = m_bufferPool.glOutputSurfaceMap.begin(); it != m_bufferPool.glOutputSurfaceMap.end(); ++it)
+  {
+    glVDPAUUnregisterSurfaceNV(it->second.glVdpauSurface);
+    glDeleteTextures(1, it->second.texture);
+  }
+  m_bufferPool.glOutputSurfaceMap.clear();
+
+  glVDPAUFiniNV();
+
+  CLog::Log(LOGNOTICE, "VDPAU::COutput: vdpau gl interop finished");
+
+#endif
+}
+
+void COutput::GLBindPixmaps()
+{
+  if (!m_config.usePixmaps)
+    return;
+
+  for (unsigned int i = 0; i < m_bufferPool.pixmaps.size(); i++)
+  {
+    // create texture
+    glGenTextures(1, &m_bufferPool.pixmaps[i].texture);
+
+    //bind texture
+    glBindTexture(GL_TEXTURE_2D, m_bufferPool.pixmaps[i].texture);
+
+    // bind pixmap
+    glXBindTexImageEXT(m_Display, m_bufferPool.pixmaps[i].glPixmap, GLX_FRONT_LEFT_EXT, NULL);
+
+    glBindTexture(GL_TEXTURE_2D, 0);
+  }
+
+  CLog::Log(LOGNOTICE, "VDPAU::COutput: bound pixmaps");
+}
+
+void COutput::GLUnbindPixmaps()
+{
+  if (!m_config.usePixmaps)
+    return;
+
+  for (unsigned int i = 0; i < m_bufferPool.pixmaps.size(); i++)
+  {
+    // create texture
+    if (!glIsTexture(m_bufferPool.pixmaps[i].texture))
+      continue;
+
+    //bind texture
+    glBindTexture(GL_TEXTURE_2D, m_bufferPool.pixmaps[i].texture);
+
+    // release pixmap
+    glXReleaseTexImageEXT(m_Display, m_bufferPool.pixmaps[i].glPixmap, GLX_FRONT_LEFT_EXT);
+
+    glBindTexture(GL_TEXTURE_2D, 0);
+
+    glDeleteTextures(1, &m_bufferPool.pixmaps[i].texture);
+  }
+  CLog::Log(LOGNOTICE, "VDPAU::COutput: unbound pixmaps");
+}
+
+bool COutput::CheckStatus(VdpStatus vdp_st, int line)
+{
+  if (vdp_st != VDP_STATUS_OK)
+  {
+    CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) at %s:%d\n", m_config.vdpProcs.vdp_get_error_string(vdp_st), vdp_st, __FILE__, line);
+    m_vdpError = true;
+    return true;
+  }
+  return false;
+}
+
+bool COutput::CreateGlxContext()
+{
+  GLXContext   glContext;
+  Window       window;
+
+  m_Display = g_Windowing.GetDisplay();
+  glContext = g_Windowing.GetGlxContext();
+  m_Window = g_Windowing.GetWindow();
+
+  // Get our window attribs.
+  XWindowAttributes wndattribs;
+  XGetWindowAttributes(m_Display, m_Window, &wndattribs);
+
+  // Get visual Info
+  XVisualInfo visInfo;
+  visInfo.visualid = wndattribs.visual->visualid;
+  int nvisuals = 0;
+  XVisualInfo* visuals = XGetVisualInfo(m_Display, VisualIDMask, &visInfo, &nvisuals);
+  if (nvisuals != 1)
+  {
+    CLog::Log(LOGERROR, "VDPAU::COutput::CreateGlxContext - could not find visual");
+    return false;
+  }
+  visInfo = visuals[0];
+  XFree(visuals);
+
+  m_pixmap = XCreatePixmap(m_Display,
+                           m_Window,
+                           192,
+                           108,
+                           visInfo.depth);
+  if (!m_pixmap)
+  {
+    CLog::Log(LOGERROR, "VDPAU::COutput::CreateGlxContext - Unable to create XPixmap");
+    return false;
+  }
+
+  // create gl pixmap
+  m_glPixmap = glXCreateGLXPixmap(m_Display, &visInfo, m_pixmap);
+
+  if (!m_glPixmap)
+  {
+    CLog::Log(LOGINFO, "VDPAU::COutput::CreateGlxContext - Could not create glPixmap");
+    return false;
+  }
+
+  m_glContext = glXCreateContext(m_Display, &visInfo, glContext, True);
+
+  if (!glXMakeCurrent(m_Display, m_glPixmap, m_glContext))
+  {
+    CLog::Log(LOGINFO, "VDPAU::COutput::CreateGlxContext - Could not make Pixmap current");
+    return false;
+  }
+
+  CLog::Log(LOGNOTICE, "VDPAU::COutput::CreateGlxContext - created context");
+  return true;
+}
+
+bool COutput::DestroyGlxContext()
+{
+  if (m_glContext)
+  {
+    glXMakeCurrent(m_Display, None, NULL);
+    glXDestroyContext(m_Display, m_glContext);
+  }
+  m_glContext = 0;
+
+  if (m_glPixmap)
+    glXDestroyPixmap(m_Display, m_glPixmap);
+  m_glPixmap = 0;
+
+  if (m_pixmap)
+    XFreePixmap(m_Display, m_pixmap);
+  m_pixmap = 0;
+
+  return true;
+}
+
 #endif
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h
index 2f53edf..4d1559c 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h
@@ -1,5 +1,3 @@
-
-#pragma once
 /*
  *      Copyright (C) 2005-2012 Team XBMC
  *      http://www.xbmc.org
@@ -20,9 +18,32 @@
  *
  */
 
+/**
+ * design goals:
+ * - improve performance
+ *   max out hw resources: e.g. make 1080p60 play on ION2
+ *   allow advanced de-interlacing on ION
+ *
+ * - add vdpau/opengl interop
+ *
+ * - remove tight dependency to render thread
+ *   prior design needed to hijack render thread in order to do
+ *   gl interop functions. In particular this was a problem for
+ *   init and clear down. Introduction of GL_NV_vdpau_interop
+ *   increased the need to be independent from render thread
+ *
+ * - move to an actor based design in order to reduce the number
+ *   of locks needed.
+ */
+
+#pragma once
+
 #include "system_gl.h"
 
-#include <queue>
+#include "DllAvUtil.h"
+#include "DVDVideoCodec.h"
+#include "DVDVideoCodecFFmpeg.h"
+#include "libavcodec/vdpau.h"
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
 #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<DVDVideoPicture> 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<vdpau_render_state*> *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<VdpOutputSurface> m_outputSurfaces;
+  std::queue<CVdpauDecodedPicture> m_decodedPics;
+  std::deque<CVdpauDecodedPicture> 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> pixmaps;
+  std::vector<VdpOutputSurface> outputSurfaces;
+  std::deque<Pixmaps*> notVisiblePixmaps;
+  std::vector<CVdpauRenderPicture> allRenderPics;
+  std::map<VdpVideoSurface, GLVideoSurface> glVideoSurfaceMap;
+  std::map<VdpOutputSurface, GLVideoSurface> glOutputSurfaceMap;
+  std::queue<CVdpauProcessedPicture> processedPics;
+  std::deque<CVdpauRenderPicture*> usedRenderPics;
+  std::deque<CVdpauRenderPicture*> 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<vdpau_render_state*> 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<vdpau_render_state*> m_videoSurfaces;
+  CCriticalSection m_videoSurfaceSec;
+
+  COutput       m_vdpauOutput;
+  CVdpauBufferStats m_bufferStats;
+  CEvent        m_inMsgEvent;
+  CVdpauRenderPicture *m_presentPicture;
+
+  int m_codecControl;
 };
+
+}
diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
index 10e2225..15a39fa 100644
--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
@@ -1141,6 +1141,9 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts)
       case RENDER_FMT_VDPAU:
         formatstr = "VDPAU";
         break;
+      case RENDER_FMT_VDPAU_420:
+        formatstr = "VDPAU_420";
+        break;
       case RENDER_FMT_DXVA:
         formatstr = "DXVA";
         break;
diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp
index f79fcc1..e988e1b 100644
--- a/xbmc/settings/AdvancedSettings.cpp
+++ b/xbmc/settings/AdvancedSettings.cpp
@@ -98,7 +98,7 @@ void CAdvancedSettings::Initialize()
   m_videoIgnoreSecondsAtStart = 3*60;
   m_videoIgnorePercentAtEnd   = 8.0f;
   m_videoPlayCountMinimumPercent = 90.0f;
-  m_videoVDPAUScaling = false;
+  m_videoVDPAUScaling = -1;
   m_videoNonLinStretchRatio = 0.5f;
   m_videoEnableHighQualityHwScalers = false;
   m_videoAutoScaleMaxFps = 30.0f;
@@ -106,6 +106,8 @@ void CAdvancedSettings::Initialize()
   m_videoAllowMpeg4VAAPI = false;  
   m_videoDisableBackgroundDeinterlace = false;
   m_videoCaptureUseOcclusionQuery = -1; //-1 is auto detect
+  m_videoVDPAUtelecine = false;
+  m_videoVDPAUdeintSkipChromaHD = false;
   m_DXVACheckCompatibility = false;
   m_DXVACheckCompatibilityPresent = false;
   m_DXVAForceProcessorRenderer = true;
@@ -490,7 +492,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);
@@ -498,6 +500,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 c262e4e..c0370e6 100644
--- a/xbmc/settings/AdvancedSettings.h
+++ b/xbmc/settings/AdvancedSettings.h
@@ -133,6 +133,8 @@ class CAdvancedSettings
     int m_videoPercentSeekBackwardBig;
     CStdString m_videoPPFFmpegDeint;
     CStdString m_videoPPFFmpegPostProc;
+    bool m_videoVDPAUtelecine;
+    bool m_videoVDPAUdeintSkipChromaHD;
     bool m_musicUseTimeSeeking;
     int m_musicTimeSeekForward;
     int m_musicTimeSeekBackward;
@@ -148,7 +150,7 @@ class CAdvancedSettings
     CStdString m_audioHost;
     bool m_audioApplyDrc;
 
-    bool  m_videoVDPAUScaling;
+    int   m_videoVDPAUScaling;
     float m_videoNonLinStretchRatio;
     bool  m_videoEnableHighQualityHwScalers;
     float m_videoAutoScaleMaxFps;
diff --git a/xbmc/settings/GUISettings.cpp b/xbmc/settings/GUISettings.cpp
index 4464abb..e9bc6f5 100644
--- a/xbmc/settings/GUISettings.cpp
+++ b/xbmc/settings/GUISettings.cpp
@@ -685,6 +685,8 @@ void CGUISettings::Initialize()
 
 #ifdef HAVE_LIBVDPAU
   AddBool(vp, "videoplayer.usevdpau", 13425, true);
+  AddBool(vp, "videoplayer.usevdpauinterop", 13435, true);
+  AddBool(vp, "videoplayer.usevdpauinteropyuv", 13436, false);
 #endif
 #ifdef HAVE_LIBVA
   AddBool(vp, "videoplayer.usevaapi", 13426, true);
diff --git a/xbmc/settings/GUIWindowSettingsCategory.cpp b/xbmc/settings/GUIWindowSettingsCategory.cpp
index 8b29c4f..785f24d 100644
--- a/xbmc/settings/GUIWindowSettingsCategory.cpp
+++ b/xbmc/settings/GUIWindowSettingsCategory.cpp
@@ -596,6 +596,40 @@ void CGUIWindowSettingsCategory::UpdateSettings()
         pControl->SetEnabled(true);
       }
     }
+    else if (strSetting.Equals("videoplayer.usevdpauinteropyuv"))
+    {
+      bool hasInterop = g_guiSettings.GetBool("videoplayer.usevdpauinterop");
+#ifndef GL_NV_vdpau_interop
+      hasInterop = false;
+#endif
+      CGUIControl *pControl = (CGUIControl *)GetControl(pSettingControl->GetID());
+      if (pControl && hasInterop && glewIsSupported("GL_NV_vdpau_interop"))
+      {
+        pControl->SetEnabled(true);
+      }
+      else
+      {
+        pControl->SetEnabled(false);
+        g_guiSettings.SetBool("videoplayer.usevdpauinteropyuv",false);
+      }
+    }
+    else if (strSetting.Equals("videoplayer.usevdpauinterop"))
+    {
+      bool hasInterop = g_guiSettings.GetBool("videoplayer.usevdpau");
+#ifndef GL_NV_vdpau_interop
+      hasInterop = false;
+#endif
+      CGUIControl *pControl = (CGUIControl *)GetControl(pSettingControl->GetID());
+      if (pControl && hasInterop && glewIsSupported("GL_NV_vdpau_interop"))
+      {
+        pControl->SetEnabled(true);
+      }
+      else
+      {
+        pControl->SetEnabled(false);
+        g_guiSettings.SetBool("videoplayer.usevdpauinterop",false);
+      }
+    }
     else
 #endif
     if (strSetting.Equals("videoscreen.resolution"))
diff --git a/xbmc/utils/ActorProtocol.cpp b/xbmc/utils/ActorProtocol.cpp
new file mode 100644
index 0000000..e0cfd0e
--- /dev/null
+++ b/xbmc/utils/ActorProtocol.cpp
@@ -0,0 +1,253 @@
+/*
+ *      Copyright (C) 2005-2012 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include "threads/Thread.h"
+#include "utils/log.h"
+#include <queue>
+#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<Message*> outMessages;
+  std::queue<Message*> inMessages;
+  std::queue<Message*> freeMessageQueue;
+  bool inDefered, outDefered;
+};
+
+}
diff --git a/xbmc/utils/Makefile b/xbmc/utils/Makefile
index d201884..7d1f9f0 100644
--- a/xbmc/utils/Makefile
+++ b/xbmc/utils/Makefile
@@ -70,6 +70,7 @@ SRCS=AlarmClock.cpp \
      Weather.cpp \
      XBMCTinyXML.cpp \
      XMLUtils.cpp \
+     ActorProtocol.cpp \
 
 LIB=utils.a
 
diff --git a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp
index ac5f007..f25d10d 100644
--- a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp
+++ b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp
@@ -103,7 +103,7 @@ void CGUIDialogVideoSettings::CreateSettings()
     entries.push_back(make_pair(VS_INTERLACEMETHOD_INVERSE_TELECINE     , 16314));
     entries.push_back(make_pair(VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL     , 16311));
     entries.push_back(make_pair(VS_INTERLACEMETHOD_VDPAU_TEMPORAL             , 16310));
-    entries.push_back(make_pair(VS_INTERLACEMETHOD_VDPAU_BOB                  , 16021));
+    entries.push_back(make_pair(VS_INTERLACEMETHOD_VDPAU_BOB                  , 16325));
     entries.push_back(make_pair(VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF, 16318));
     entries.push_back(make_pair(VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF        , 16317));
     entries.push_back(make_pair(VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE     , 16314));
diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h
index e7af3cb..2dd8a9f 100644
--- a/xbmc/windowing/X11/WinSystemX11.h
+++ b/xbmc/windowing/X11/WinSystemX11.h
@@ -63,6 +63,7 @@ class CWinSystemX11 : public CWinSystemBase
   // Local to WinSystemX11 only
   Display*  GetDisplay() { return m_dpy; }
   GLXWindow GetWindow() { return m_glWindow; }
+  GLXContext GetGlxContext() { return m_glContext; }
 
 protected:
   bool RefreshGlxContext();
-- 
1.7.10


From 40ce0dfbdd114dc86b1473392b76a8477b715d5b Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Tue, 25 Sep 2012 12:14:15 +0200
Subject: [PATCH 12/58] 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 685d5c3..752b0d1 100644
--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
@@ -1205,7 +1205,8 @@ void CLinuxRendererGL::Render(DWORD flags, int renderBuffer)
       break;
 
     case RQ_MULTIPASS:
-      RenderMultiPass(renderBuffer, m_currentField);
+      RenderToFBO(renderBuffer, m_currentField);
+      RenderFromFBO();
       VerifyGLState();
       break;
     }
@@ -1328,12 +1329,6 @@ void CLinuxRendererGL::RenderSinglePass(int index, int field)
   VerifyGLState();
 }
 
-void CLinuxRendererGL::RenderMultiPass(int index, int field)
-{
-  RenderToFBO(index, field);
-  RenderFromFBO();
-}
-
 void CLinuxRendererGL::RenderToFBO(int index, int field)
 {
   YUVPLANES &planes = m_buffers[index].fields[field];
diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.h b/xbmc/cores/VideoRenderers/LinuxRendererGL.h
index 3218cd5..afc78c2 100644
--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.h
+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.h
@@ -218,7 +218,6 @@ class CLinuxRendererGL : public CBaseRenderer
   void CalculateTextureSourceRects(int source, int num_planes);
 
   // renderers
-  void RenderMultiPass(int renderBuffer, int field);  // multi pass glsl renderer
   void RenderToFBO(int renderBuffer, int field);
   void RenderFromFBO();
   void RenderSinglePass(int renderBuffer, int field); // single pass glsl renderer
-- 
1.7.10


From 7474394537c4eea68e088cde78577978d46c8455 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Tue, 25 Sep 2012 13:20:47 +0200
Subject: [PATCH 13/58] 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 752b0d1..497fb32 100644
--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
@@ -689,18 +689,6 @@ void CLinuxRendererGL::RenderUpdate(bool clear, DWORD flags, DWORD alpha)
     glDisable(GL_POLYGON_STIPPLE);
 
   }
-  else if(m_format == RENDER_FMT_VDPAU_420
-      && !(flags & RENDER_FLAG_BOTH))
-  {
-    glDisable(GL_BLEND);
-    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
-    Render(flags | RENDER_FLAG_TOP, index);
-
-    glEnable(GL_BLEND);
-    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-    glColor4f(1.0f, 1.0f, 1.0f, 128 / 255.0f);
-    Render(flags | RENDER_FLAG_BOT , index);
-  }
   else
     Render(flags, index);
 
@@ -1200,13 +1188,21 @@ void CLinuxRendererGL::Render(DWORD flags, int renderBuffer)
     {
     case RQ_LOW:
     case RQ_SINGLEPASS:
-      RenderSinglePass(renderBuffer, m_currentField);
+      if (m_format == RENDER_FMT_VDPAU_420 && m_currentField == FIELD_FULL)
+        RenderProgressiveWeave(renderBuffer, m_currentField);
+      else
+        RenderSinglePass(renderBuffer, m_currentField);
       VerifyGLState();
       break;
 
     case RQ_MULTIPASS:
-      RenderToFBO(renderBuffer, m_currentField);
-      RenderFromFBO();
+      if (m_format == RENDER_FMT_VDPAU_420 && m_currentField == FIELD_FULL)
+        RenderProgressiveWeave(renderBuffer, m_currentField);
+      else
+      {
+        RenderToFBO(renderBuffer, m_currentField);
+        RenderFromFBO();
+      }
       VerifyGLState();
       break;
     }
@@ -1329,7 +1325,7 @@ void CLinuxRendererGL::RenderSinglePass(int index, int field)
   VerifyGLState();
 }
 
-void CLinuxRendererGL::RenderToFBO(int index, int field)
+void CLinuxRendererGL::RenderToFBO(int index, int field, bool weave /*= false*/)
 {
   YUVPLANES &planes = m_buffers[index].fields[field];
 
@@ -1431,6 +1427,8 @@ void CLinuxRendererGL::RenderToFBO(int index, int field)
   }
   m_fbo.width  *= planes[0].pixpertex_x;
   m_fbo.height *= planes[0].pixpertex_y;
+  if (weave)
+    m_fbo.height *= 2;
 
   // 1st Pass to video frame size
   glBegin(GL_QUADS);
@@ -1549,6 +1547,31 @@ void CLinuxRendererGL::RenderFromFBO()
   VerifyGLState();
 }
 
+void CLinuxRendererGL::RenderProgressiveWeave(int index, int field)
+{
+  bool scaleUp = (int)m_sourceHeight < g_graphicsContext.GetHeight() || (int)m_sourceWidth < g_graphicsContext.GetWidth();
+
+  if (m_fbo.fbo.IsSupported() && (scaleUp || m_renderQuality == RQ_MULTIPASS))
+  {
+    glEnable(GL_POLYGON_STIPPLE);
+    glPolygonStipple(stipple_weave);
+    RenderToFBO(index, FIELD_TOP, true);
+    glPolygonStipple(stipple_weave+4);
+    RenderToFBO(index, FIELD_BOT, true);
+    glDisable(GL_POLYGON_STIPPLE);
+    RenderFromFBO();
+  }
+  else
+  {
+    glEnable(GL_POLYGON_STIPPLE);
+    glPolygonStipple(stipple_weave);
+    RenderSinglePass(index, FIELD_TOP);
+    glPolygonStipple(stipple_weave+4);
+    RenderSinglePass(index, FIELD_BOT);
+    glDisable(GL_POLYGON_STIPPLE);
+  }
+}
+
 void CLinuxRendererGL::RenderVDPAU(int index, int field)
 {
 #ifdef HAVE_LIBVDPAU
diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.h b/xbmc/cores/VideoRenderers/LinuxRendererGL.h
index afc78c2..2fc34ae 100644
--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.h
+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.h
@@ -218,12 +218,12 @@ class CLinuxRendererGL : public CBaseRenderer
   void CalculateTextureSourceRects(int source, int num_planes);
 
   // renderers
-  void RenderToFBO(int renderBuffer, int field);
+  void RenderToFBO(int renderBuffer, int field, bool weave = false);
   void RenderFromFBO();
   void RenderSinglePass(int renderBuffer, int field); // single pass glsl renderer
   void RenderSoftware(int renderBuffer, int field);   // single pass s/w yuv2rgb renderer
   void RenderVDPAU(int renderBuffer, int field);      // render using vdpau hardware
-  void RenderVDPAUYV12(int renderBuffer, int field);      // render using vdpau hardware
+  void RenderProgressiveWeave(int renderBuffer, int field); // render using vdpau hardware
   void RenderVAAPI(int renderBuffer, int field);      // render using vdpau hardware
 
   struct
-- 
1.7.10


From e6f1e4673fcbdb4fad66cd78d6a96a2134b376bd Mon Sep 17 00:00:00 2001
From: FernetMenta <fernetmenta@online.de>
Date: Thu, 5 Jul 2012 15:22:05 +0200
Subject: [PATCH 14/58] 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 e9b9ba0..d2a0352 100644
--- a/xbmc/Application.cpp
+++ b/xbmc/Application.cpp
@@ -780,7 +780,7 @@ bool CApplication::CreateGUI()
 
   uint32_t sdlFlags = 0;
 
-#if defined(HAS_SDL_OPENGL) || (HAS_GLES == 2)
+#if (defined(HAS_SDL_OPENGL) || (HAS_GLES == 2)) && !defined(HAS_GLX)
   sdlFlags |= SDL_INIT_VIDEO;
 #endif
 
diff --git a/xbmc/system.h b/xbmc/system.h
index 4165c01..32584b1 100644
--- a/xbmc/system.h
+++ b/xbmc/system.h
@@ -162,16 +162,21 @@
 #define HAS_GL
 #ifdef HAVE_X11
 #define HAS_GLX
+#define HAS_X11_WIN_EVENTS
 #endif
 #ifdef HAVE_SDL
 #define HAS_SDL
 #ifndef HAS_SDL_OPENGL
 #define HAS_SDL_OPENGL
 #endif
+#ifndef HAVE_X11
 #define HAS_SDL_WIN_EVENTS
+#endif
 #else
+#ifndef HAVE_X11
 #define HAS_LINUX_EVENTS
 #endif
+#endif
 #define HAS_LINUX_NETWORK
 #define HAS_LIRC
 #ifdef HAVE_LIBPULSE
diff --git a/xbmc/windowing/Makefile b/xbmc/windowing/Makefile
index f109bec..f981642 100644
--- a/xbmc/windowing/Makefile
+++ b/xbmc/windowing/Makefile
@@ -1,6 +1,7 @@
 SRCS=WinEventsSDL.cpp \
      WinEventsLinux.cpp \
      WinSystem.cpp \
+     WinEventsX11.cpp \
      
 LIB=windowing.a
 
diff --git a/xbmc/windowing/WinEvents.h b/xbmc/windowing/WinEvents.h
index 6d322a9..5a671cc 100644
--- a/xbmc/windowing/WinEvents.h
+++ b/xbmc/windowing/WinEvents.h
@@ -58,6 +58,10 @@ class CWinEventsBase
 #include "WinEventsSDL.h"
 #define CWinEvents CWinEventsSDL
 
+#elif defined(TARGET_LINUX) && defined(HAS_X11_WIN_EVENTS)
+#include "WinEventsX11.h"
+#define CWinEvents CWinEventsX11
+
 #elif defined(TARGET_LINUX) && defined(HAS_LINUX_EVENTS)
 #include "WinEventsLinux.h"
 #define CWinEvents CWinEventsLinux
diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp
new file mode 100644
index 0000000..24477ae
--- /dev/null
+++ b/xbmc/windowing/WinEventsX11.cpp
@@ -0,0 +1,765 @@
+/*
+*      Copyright (C) 2005-2012 Team XBMC
+*      http://www.xbmc.org
+*
+*  This Program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2, or (at your option)
+*  any later version.
+*
+*  This Program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with XBMC; see the file COPYING.  If not, write to
+*  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+*  http://www.gnu.org/copyleft/gpl.html
+*
+*/
+
+#include "system.h"
+
+#ifdef HAS_X11_WIN_EVENTS
+
+#include "WinEvents.h"
+#include "WinEventsX11.h"
+#include "Application.h"
+#include "ApplicationMessenger.h"
+#include <X11/Xlib.h>
+#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<uint32_t, uint32_t>::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 <X11/Xlib.h>
+#include "threads/SystemClock.h"
+#include <map>
+
+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<uint32_t,uint32_t> m_symLookupTable;
+  int m_keymodState;
+  bool m_structureChanged;
+};
diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp
index a839709..76ef462 100644
--- a/xbmc/windowing/X11/WinSystemX11.cpp
+++ b/xbmc/windowing/X11/WinSystemX11.cpp
@@ -22,7 +22,6 @@
 
 #ifdef HAS_GLX
 
-#include <SDL/SDL_syswm.h>
 #include "WinSystemX11.h"
 #include "settings/Settings.h"
 #include "guilib/Texture.h"
@@ -31,27 +30,30 @@
 #include "XRandR.h"
 #include <vector>
 #include "threads/SingleLock.h"
-#include <X11/Xlib.h>
 #include "cores/VideoRenderers/RenderManager.h"
 #include "utils/TimeUtils.h"
+#include "settings/GUISettings.h"
 
 #if defined(HAS_XRANDR)
 #include <X11/extensions/Xrandr.h>
 #endif
 
+#include "../WinEvents.h"
+#include "input/MouseStat.h"
+
 using namespace std;
 
 CWinSystemX11::CWinSystemX11() : CWinSystemBase()
 {
   m_eWindowSystem = WINDOW_SYSTEM_X11;
   m_glContext = NULL;
-  m_SDLSurface = NULL;
   m_dpy = NULL;
   m_glWindow = 0;
-  m_wmWindow = 0;
   m_bWasFullScreenBeforeMinimize = false;
   m_minimized = false;
+  m_bIgnoreNextFocusMessage = false;
   m_dpyLostTime = 0;
+  m_invisibleCursor = 0;
 
   XSetErrorHandler(XErrorHandler);
 }
@@ -64,18 +66,6 @@ bool CWinSystemX11::InitWindowSystem()
 {
   if ((m_dpy = XOpenDisplay(NULL)))
   {
-
-    SDL_EnableUNICODE(1);
-    // set repeat to 10ms to ensure repeat time < frame time
-    // so that hold times can be reliably detected
-    SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, 10);
-
-    SDL_GL_SetAttribute(SDL_GL_RED_SIZE,   8);
-    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
-    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE,  8);
-    SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
-    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
-
     return CWinSystemBase::InitWindowSystem();
   }
   else
@@ -113,45 +103,37 @@ bool CWinSystemX11::DestroyWindowSystem()
 
 bool CWinSystemX11::CreateNewWindow(const CStdString& name, bool fullScreen, RESOLUTION_INFO& res, PHANDLE_EVENT_FUNC userFunction)
 {
-  RESOLUTION_INFO& desktop = g_settings.m_ResInfo[RES_DESKTOP];
-
-  if (fullScreen &&
-      (res.iWidth != desktop.iWidth || res.iHeight != desktop.iHeight ||
-       res.fRefreshRate != desktop.fRefreshRate || res.iScreen != desktop.iScreen))
-  {
-    //on the first call to SDL_SetVideoMode, SDL stores the current displaymode
-    //SDL restores the displaymode on SDL_QUIT(), if we change the displaymode
-    //before the first call to SDL_SetVideoMode, SDL changes the displaymode back
-    //to the wrong mode on exit
-
-    CLog::Log(LOGINFO, "CWinSystemX11::CreateNewWindow initializing to desktop resolution first");
-    if (!SetFullScreen(true, desktop, false))
-      return false;
-  }
-
   if(!SetFullScreen(fullScreen, res, false))
     return false;
 
-  CBaseTexture* iconTexture = CTexture::LoadFromFile("special://xbmc/media/icon.png");
-
-  if (iconTexture)
-    SDL_WM_SetIcon(SDL_CreateRGBSurfaceFrom(iconTexture->GetPixels(), iconTexture->GetWidth(), iconTexture->GetHeight(), 32, iconTexture->GetPitch(), 0xff0000, 0x00ff00, 0x0000ff, 0xff000000L), NULL);
-  SDL_WM_SetCaption("XBMC Media Center", NULL);
-  delete iconTexture;
-
-  // register XRandR Events
-#if defined(HAS_XRANDR)
-  int iReturn;
-  XRRQueryExtension(m_dpy, &m_RREventBase, &iReturn);
-  XRRSelectInput(m_dpy, m_wmWindow, RRScreenChangeNotifyMask);
-#endif
-
   m_bWindowCreated = true;
   return true;
 }
 
 bool CWinSystemX11::DestroyWindow()
 {
+  if (!m_glWindow)
+    return true;
+
+  if (m_glContext)
+    glXMakeCurrent(m_dpy, None, NULL);
+
+  if (m_invisibleCursor)
+  {
+    XUndefineCursor(m_dpy, m_glWindow);
+    XFreeCursor(m_dpy, m_invisibleCursor);
+    m_invisibleCursor = 0;
+  }
+
+  CWinEvents::Quit();
+
+  XUnmapWindow(m_dpy, m_glWindow);
+  XSync(m_dpy,TRUE);
+  XUngrabKeyboard(m_dpy, CurrentTime);
+  XUngrabPointer(m_dpy, CurrentTime);
+  XDestroyWindow(m_dpy, m_glWindow);
+  m_glWindow = 0;
+
   return true;
 }
 
@@ -161,65 +143,105 @@ bool CWinSystemX11::ResizeWindow(int newWidth, int newHeight, int newLeft, int n
   && m_nHeight == newHeight)
     return true;
 
+  if (!SetWindow(newWidth, newHeight, false))
+  {
+    return false;
+  }
+
+  RefreshGlxContext();
   m_nWidth  = newWidth;
   m_nHeight = newHeight;
+  m_bFullScreen = false;
 
-  int options = SDL_OPENGL;
-  if (m_bFullScreen)
-    options |= SDL_FULLSCREEN;
-  else
-    options |= SDL_RESIZABLE;
+  return false;
+}
+
+void CWinSystemX11::RefreshWindow()
+{
+  g_xrandr.Query(true);
+  XOutput out  = g_xrandr.GetCurrentOutput();
+  XMode   mode = g_xrandr.GetCurrentMode(out.name);
 
-  if ((m_SDLSurface = SDL_SetVideoMode(m_nWidth, m_nHeight, 0, options)))
+  // only overwrite desktop resolution, if we are not in fullscreen mode
+  if (!g_graphicsContext.IsFullScreenVideo())
   {
-    RefreshGlxContext();
-    return true;
+    CLog::Log(LOGDEBUG, "CWinSystemX11::RefreshWindow - store desktop resolution, width: %d, height: %d, hz: %2.2f", mode.w, mode.h, mode.hz);
+    UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.w, mode.h, mode.hz);
+    g_settings.m_ResInfo[RES_DESKTOP].strId     = mode.id;
+    g_settings.m_ResInfo[RES_DESKTOP].strOutput = out.name;
   }
 
-  return false;
+  RESOLUTION_INFO res;
+  unsigned int i;
+  bool found(false);
+  for (i = RES_DESKTOP; i < g_settings.m_ResInfo.size(); ++i)
+  {
+    if (g_settings.m_ResInfo[i].strId == mode.id)
+    {
+      found = true;
+      break;
+    }
+  }
+
+  if (!found)
+  {
+    CLog::Log(LOGERROR, "CWinSystemX11::RefreshWindow - could not find resolution");
+    return;
+  }
+
+  if (g_graphicsContext.IsFullScreenRoot())
+    g_graphicsContext.SetVideoResolution((RESOLUTION)i, true);
+  else
+    g_graphicsContext.SetVideoResolution(RES_WINDOW, true);
 }
 
 bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays)
 {
-  m_nWidth      = res.iWidth;
-  m_nHeight     = res.iHeight;
-  m_bFullScreen = fullScreen;
 
 #if defined(HAS_XRANDR)
   XOutput out;
   XMode mode;
-  out.name = res.strOutput;
-  mode.w   = res.iWidth;
-  mode.h   = res.iHeight;
-  mode.hz  = res.fRefreshRate;
-  mode.id  = res.strId;
+
+  if (fullScreen)
+  {
+    out.name = res.strOutput;
+    mode.w   = res.iWidth;
+    mode.h   = res.iHeight;
+    mode.hz  = res.fRefreshRate;
+    mode.id  = res.strId;
+  }
+  else
+  {
+    out.name = g_settings.m_ResInfo[RES_DESKTOP].strOutput;
+    mode.w   = g_settings.m_ResInfo[RES_DESKTOP].iWidth;
+    mode.h   = g_settings.m_ResInfo[RES_DESKTOP].iHeight;
+    mode.hz  = g_settings.m_ResInfo[RES_DESKTOP].fRefreshRate;
+    mode.id  = g_settings.m_ResInfo[RES_DESKTOP].strId;
+  }
  
-  if(m_bFullScreen)
+  XOutput currout  = g_xrandr.GetCurrentOutput();
+  XMode   currmode = g_xrandr.GetCurrentMode(currout.name);
+
+  // only call xrandr if mode changes
+  if (currout.name != out.name || currmode.w != mode.w || currmode.h != mode.h ||
+      currmode.hz != mode.hz || currmode.id != mode.id)
   {
+    CLog::Log(LOGNOTICE, "CWinSystemX11::SetFullScreen - calling xrandr");
     OnLostDevice();
     g_xrandr.SetMode(out, mode);
   }
-  else
-    g_xrandr.RestoreState();
 #endif
 
-  int options = SDL_OPENGL;
-  if (m_bFullScreen)
-    options |= SDL_FULLSCREEN;
-  else
-    options |= SDL_RESIZABLE;
-
-  if ((m_SDLSurface = SDL_SetVideoMode(m_nWidth, m_nHeight, 0, options)))
-  {
-    if ((m_SDLSurface->flags & SDL_OPENGL) != SDL_OPENGL)
-      CLog::Log(LOGERROR, "CWinSystemX11::SetFullScreen SDL_OPENGL not set, SDL_GetError:%s", SDL_GetError());
+  if (!SetWindow(res.iWidth, res.iHeight, fullScreen))
+    return false;
 
-    RefreshGlxContext();
+  RefreshGlxContext();
 
-    return true;
-  }
+  m_nWidth      = res.iWidth;
+  m_nHeight     = res.iHeight;
+  m_bFullScreen = fullScreen;
 
-  return false;
+  return true;
 }
 
 void CWinSystemX11::UpdateResolutions()
@@ -321,17 +343,10 @@ bool CWinSystemX11::IsSuitableVisual(XVisualInfo *vInfo)
 bool CWinSystemX11::RefreshGlxContext()
 {
   bool retVal = false;
-  SDL_SysWMinfo info;
-  SDL_VERSION(&info.version);
-  if (SDL_GetWMInfo(&info) <= 0)
-  {
-    CLog::Log(LOGERROR, "Failed to get window manager info from SDL");
-    return false;
-  }
 
-  if(m_glWindow == info.info.x11.window && m_glContext)
+  if (m_glContext)
   {
-    CLog::Log(LOGERROR, "GLX: Same window as before, refreshing context");
+    CLog::Log(LOGDEBUG, "CWinSystemX11::RefreshGlxContext: refreshing context");
     glXMakeCurrent(m_dpy, None, NULL);
     glXMakeCurrent(m_dpy, m_glWindow, m_glContext);
     return true;
@@ -343,8 +358,6 @@ bool CWinSystemX11::RefreshGlxContext()
   int availableVisuals    = 0;
   vMask.screen = DefaultScreen(m_dpy);
   XWindowAttributes winAttr;
-  m_glWindow = info.info.x11.window;
-  m_wmWindow = info.info.x11.wmwindow;
 
   /* Assume a depth of 24 in case the below calls to XGetWindowAttributes()
      or XGetVisualInfo() fail. That shouldn't happen unless something is
@@ -415,7 +428,10 @@ bool CWinSystemX11::RefreshGlxContext()
 
 void CWinSystemX11::ShowOSMouse(bool show)
 {
-  SDL_ShowCursor(show ? 1 : 0);
+  if (show)
+    XUndefineCursor(m_dpy,m_glWindow);
+  else if (m_invisibleCursor)
+    XDefineCursor(m_dpy,m_glWindow, m_invisibleCursor);
 }
 
 void CWinSystemX11::ResetOSScreensaver()
@@ -429,8 +445,6 @@ void CWinSystemX11::ResetOSScreensaver()
     {
       m_screensaverReset.StartZero();
       XResetScreenSaver(m_dpy);
-      //need to flush the output buffer, since we don't check for events on m_dpy
-      XFlush(m_dpy);
     }
   }
   else
@@ -446,13 +460,27 @@ void CWinSystemX11::NotifyAppActiveChange(bool bActivated)
 
   m_minimized = !bActivated;
 }
+
+void CWinSystemX11::NotifyAppFocusChange(bool bGaining)
+{
+  if (bGaining && m_bWasFullScreenBeforeMinimize && !m_bIgnoreNextFocusMessage &&
+      !g_graphicsContext.IsFullScreenRoot())
+    g_graphicsContext.ToggleFullScreenRoot();
+  if (!bGaining)
+    m_bIgnoreNextFocusMessage = false;
+}
+
 bool CWinSystemX11::Minimize()
 {
   m_bWasFullScreenBeforeMinimize = g_graphicsContext.IsFullScreenRoot();
   if (m_bWasFullScreenBeforeMinimize)
+  {
+    m_bIgnoreNextFocusMessage = true;
     g_graphicsContext.ToggleFullScreenRoot();
+  }
+
+  XIconifyWindow(m_dpy, m_glWindow, DefaultScreen(m_dpy));
 
-  SDL_WM_IconifyWindow();
   m_minimized = true;
   return true;
 }
@@ -462,13 +490,13 @@ bool CWinSystemX11::Restore()
 }
 bool CWinSystemX11::Hide()
 {
-  XUnmapWindow(m_dpy, m_wmWindow);
+  XUnmapWindow(m_dpy, m_glWindow);
   XSync(m_dpy, False);
   return true;
 }
 bool CWinSystemX11::Show(bool raise)
 {
-  XMapWindow(m_dpy, m_wmWindow);
+  XMapWindow(m_dpy, m_glWindow);
   XSync(m_dpy, False);
   m_minimized = false;
   return true;
@@ -500,6 +528,7 @@ void CWinSystemX11::CheckDisplayEvents()
   if (bGotEvent || bTimeout)
   {
     CLog::Log(LOGDEBUG, "%s - notify display reset event", __FUNCTION__);
+    RefreshWindow();
 
     CSingleLock lock(m_resourceSection);
 
@@ -558,4 +587,151 @@ bool CWinSystemX11::EnableFrameLimiter()
   return m_minimized;
 }
 
+bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen)
+{
+  bool changeWindow = false;
+  bool changeSize = false;
+  bool mouseActive = false;
+  float mouseX, mouseY;
+
+  if (m_glWindow && (m_bFullScreen != fullscreen))
+  {
+    mouseActive = g_Mouse.IsActive();
+    if (mouseActive)
+    {
+      Window root_return, child_return;
+      int root_x_return, root_y_return;
+      int win_x_return, win_y_return;
+      unsigned int mask_return;
+      bool isInWin = XQueryPointer(m_dpy, m_glWindow, &root_return, &child_return,
+                                   &root_x_return, &root_y_return,
+                                   &win_x_return, &win_y_return,
+                                   &mask_return);
+      if (isInWin)
+      {
+        mouseX = (float)win_x_return/m_nWidth;
+        mouseY = (float)win_y_return/m_nHeight;
+        g_Mouse.SetActive(false);
+      }
+      else
+        mouseActive = false;
+    }
+    DestroyWindow();
+  }
+
+  // create main window
+  if (!m_glWindow)
+  {
+    GLint att[] =
+    {
+      GLX_RGBA,
+      GLX_RED_SIZE, 8,
+      GLX_GREEN_SIZE, 8,
+      GLX_BLUE_SIZE, 8,
+      GLX_ALPHA_SIZE, 8,
+      GLX_DEPTH_SIZE, 24,
+      GLX_DOUBLEBUFFER,
+      None
+    };
+    Colormap cmap;
+    XSetWindowAttributes swa;
+    XVisualInfo *vi;
+
+    vi = glXChooseVisual(m_dpy, DefaultScreen(m_dpy), att);
+    cmap = XCreateColormap(m_dpy, RootWindow(m_dpy, vi->screen), vi->visual, AllocNone);
+
+    int def_vis = (vi->visual == DefaultVisual(m_dpy, vi->screen));
+    swa.override_redirect = fullscreen ? True : False;
+    swa.border_pixel = fullscreen ? 0 : 5;
+    swa.background_pixel = def_vis ? BlackPixel(m_dpy, vi->screen) : 0;
+    swa.colormap = cmap;
+    swa.background_pixel = def_vis ? BlackPixel(m_dpy, vi->screen) : 0;
+    swa.event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask |
+                     ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
+                     PropertyChangeMask | StructureNotifyMask | KeymapStateMask |
+                     EnterWindowMask | LeaveWindowMask | ExposureMask;
+    unsigned long mask = CWBackPixel | CWBorderPixel | CWColormap | CWOverrideRedirect | CWEventMask;
+
+    m_glWindow = XCreateWindow(m_dpy, RootWindow(m_dpy, vi->screen),
+                    0, 0, width, height, 0, vi->depth,
+                    InputOutput, vi->visual,
+                    mask, &swa);
+
+    // define invisible cursor
+    Pixmap bitmapNoData;
+    XColor black;
+    static char noData[] = { 0,0,0,0,0,0,0,0 };
+    black.red = black.green = black.blue = 0;
+
+    bitmapNoData = XCreateBitmapFromData(m_dpy, m_glWindow, noData, 8, 8);
+    m_invisibleCursor = XCreatePixmapCursor(m_dpy, bitmapNoData, bitmapNoData,
+                                            &black, &black, 0, 0);
+    XFreePixmap(m_dpy, bitmapNoData);
+    XDefineCursor(m_dpy,m_glWindow, m_invisibleCursor);
+
+    //init X11 events
+    CWinEvents::Init(m_dpy, m_glWindow);
+
+    changeWindow = true;
+    changeSize = true;
+  }
+
+  if (!CWinEvents::HasStructureChanged() && ((width != m_nWidth) || (height != m_nHeight)))
+  {
+    changeSize = true;
+  }
+
+  if (changeSize || changeWindow)
+  {
+    XResizeWindow(m_dpy, m_glWindow, width, height);
+  }
+
+  if (changeWindow)
+  {
+    if (!fullscreen)
+    {
+      XWMHints wm_hints;
+      XClassHint class_hints;
+      XTextProperty windowName, iconName;
+      std::string titleString = "XBMC Media Center";
+      char *title = (char*)titleString.c_str();
+
+      XStringListToTextProperty(&title, 1, &windowName);
+      XStringListToTextProperty(&title, 1, &iconName);
+      wm_hints.initial_state = NormalState;
+      wm_hints.input = True;
+      wm_hints.icon_pixmap = None;
+      wm_hints.flags = StateHint | IconPixmapHint | InputHint;
+
+      XSetWMProperties(m_dpy, m_glWindow, &windowName, &iconName,
+                            NULL, 0, NULL, &wm_hints,
+                            NULL);
+
+      // register interest in the delete window message
+      Atom wmDeleteMessage = XInternAtom(m_dpy, "WM_DELETE_WINDOW", False);
+      XSetWMProtocols(m_dpy, m_glWindow, &wmDeleteMessage, 1);
+    }
+    XMapRaised(m_dpy, m_glWindow);
+    XSync(m_dpy,TRUE);
+
+    if (changeWindow && mouseActive)
+    {
+      XWarpPointer(m_dpy, None, m_glWindow, 0, 0, 0, 0, mouseX*width, mouseY*height);
+    }
+
+    if (fullscreen)
+    {
+      int result = -1;
+      while (result != GrabSuccess)
+      {
+        result = XGrabPointer(m_dpy, m_glWindow, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, m_glWindow, None, CurrentTime);
+        XbmcThreads::ThreadSleep(100);
+      }
+      XGrabKeyboard(m_dpy, m_glWindow, True, GrabModeAsync, GrabModeAsync, CurrentTime);
+
+    }
+  }
+  return true;
+}
+
 #endif
diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h
index 2dd8a9f..9616d17 100644
--- a/xbmc/windowing/X11/WinSystemX11.h
+++ b/xbmc/windowing/X11/WinSystemX11.h
@@ -52,6 +52,7 @@ class CWinSystemX11 : public CWinSystemBase
   virtual bool EnableFrameLimiter();
 
   virtual void NotifyAppActiveChange(bool bActivated);
+  virtual void NotifyAppFocusChange(bool bGaining);
 
   virtual bool Minimize();
   virtual bool Restore() ;
@@ -64,19 +65,21 @@ class CWinSystemX11 : public CWinSystemBase
   Display*  GetDisplay() { return m_dpy; }
   GLXWindow GetWindow() { return m_glWindow; }
   GLXContext GetGlxContext() { return m_glContext; }
+  void RefreshWindow();
 
 protected:
   bool RefreshGlxContext();
   void CheckDisplayEvents();
   void OnLostDevice();
+  bool SetWindow(int width, int height, bool fullscreen);
 
-  SDL_Surface* m_SDLSurface;
+  Window       m_glWindow;
   GLXContext   m_glContext;
-  GLXWindow    m_glWindow;
-  Window       m_wmWindow;
   Display*     m_dpy;
+  Cursor       m_invisibleCursor;
   bool         m_bWasFullScreenBeforeMinimize;
   bool         m_minimized;
+  bool         m_bIgnoreNextFocusMessage;
   int          m_RREventBase;
   CCriticalSection             m_resourceSection;
   std::vector<IDispResource*>  m_resources;
-- 
1.7.10


From 69c6e04937b94309459d93fc9e72be60400b2764 Mon Sep 17 00:00:00 2001
From: FernetMenta <fernetmenta@online.de>
Date: Thu, 5 Jul 2012 15:24:22 +0200
Subject: [PATCH 15/58] X11: Add xbmc icon

---
 xbmc/windowing/X11/WinSystemX11.cpp |  126 ++++++++++++++++++++++++++++++++++-
 xbmc/windowing/X11/WinSystemX11.h   |    2 +
 2 files changed, 127 insertions(+), 1 deletion(-)

diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp
index 76ef462..c854598 100644
--- a/xbmc/windowing/X11/WinSystemX11.cpp
+++ b/xbmc/windowing/X11/WinSystemX11.cpp
@@ -134,6 +134,9 @@ bool CWinSystemX11::DestroyWindow()
   XDestroyWindow(m_dpy, m_glWindow);
   m_glWindow = 0;
 
+  if (m_icon)
+    XFreePixmap(m_dpy, m_icon);
+
   return true;
 }
 
@@ -688,8 +691,10 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen)
 
   if (changeWindow)
   {
+    m_icon = None;
     if (!fullscreen)
     {
+      CreateIconPixmap();
       XWMHints wm_hints;
       XClassHint class_hints;
       XTextProperty windowName, iconName;
@@ -700,7 +705,7 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen)
       XStringListToTextProperty(&title, 1, &iconName);
       wm_hints.initial_state = NormalState;
       wm_hints.input = True;
-      wm_hints.icon_pixmap = None;
+      wm_hints.icon_pixmap = m_icon;
       wm_hints.flags = StateHint | IconPixmapHint | InputHint;
 
       XSetWMProperties(m_dpy, m_glWindow, &windowName, &iconName,
@@ -734,4 +739,123 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen)
   return true;
 }
 
+bool CWinSystemX11::CreateIconPixmap()
+{
+  int depth;
+  XImage *img = NULL;
+  Visual *vis;
+  XWindowAttributes wndattribs;
+  XVisualInfo visInfo;
+  double rRatio;
+  double gRatio;
+  double bRatio;
+  int outIndex = 0;
+  int i,j;
+  int numBufBytes;
+  unsigned char *buf;
+  uint32_t *newBuf = 0;
+  size_t numNewBufBytes;
+
+  // Get visual Info
+  XGetWindowAttributes(m_dpy, m_glWindow, &wndattribs);
+  visInfo.visualid = wndattribs.visual->visualid;
+  int nvisuals = 0;
+  XVisualInfo* visuals = XGetVisualInfo(m_dpy, VisualIDMask, &visInfo, &nvisuals);
+  if (nvisuals != 1)
+  {
+    CLog::Log(LOGERROR, "CWinSystemX11::CreateIconPixmap - could not find visual");
+    return false;
+  }
+  visInfo = visuals[0];
+  XFree(visuals);
+
+  depth = visInfo.depth;
+  vis = visInfo.visual;
+
+  if (depth < 15)
+  {
+    CLog::Log(LOGERROR, "CWinSystemX11::CreateIconPixmap - no suitable depth");
+    return false;
+  }
+
+  rRatio = vis->red_mask / 255.0;
+  gRatio = vis->green_mask / 255.0;
+  bRatio = vis->blue_mask / 255.0;
+
+  CTexture iconTexture;
+  iconTexture.LoadFromFile("special://xbmc/media/icon.png");
+  buf = iconTexture.GetPixels();
+
+  numBufBytes = iconTexture.GetWidth() * iconTexture.GetHeight() * 4;
+
+  if (depth>=24)
+    numNewBufBytes = (4 * (iconTexture.GetWidth() * iconTexture.GetHeight()));
+  else
+    numNewBufBytes = (2 * (iconTexture.GetWidth() * iconTexture.GetHeight()));
+
+  newBuf = (uint32_t*)malloc(numNewBufBytes);
+  if (!newBuf)
+  {
+    CLog::Log(LOGERROR, "CWinSystemX11::CreateIconPixmap - malloc failed");
+    return false;
+  }
+
+  for (i=0; i<iconTexture.GetHeight();++i)
+  {
+    for (j=0; j<iconTexture.GetWidth();++j)
+    {
+      unsigned int pos = i*iconTexture.GetPitch()+j*4;
+      unsigned int r, g, b;
+      r = (buf[pos+2] * rRatio);
+      g = (buf[pos+1] * gRatio);
+      b = (buf[pos+0] * bRatio);
+      r &= vis->red_mask;
+      g &= vis->green_mask;
+      b &= vis->blue_mask;
+      newBuf[outIndex] = r | g | b;
+      ++outIndex;
+    }
+  }
+  img = XCreateImage(m_dpy, vis, depth,ZPixmap, 0, (char *)newBuf,
+                     iconTexture.GetWidth(), iconTexture.GetHeight(),
+                     (depth>=24)?32:16, 0);
+  if (!img)
+  {
+    CLog::Log(LOGERROR, "CWinSystemX11::CreateIconPixmap - could not create image");
+    free(newBuf);
+    return false;
+  }
+  if (!XInitImage(img))
+  {
+    CLog::Log(LOGERROR, "CWinSystemX11::CreateIconPixmap - init image failed");
+    XDestroyImage(img);
+    return false;
+  }
+
+  // set byte order
+  union
+  {
+    char c[sizeof(short)];
+    short s;
+  } order;
+  order.s = 1;
+  if ((1 == order.c[0]))
+  {
+    img->byte_order = LSBFirst;
+  }
+  else
+  {
+    img->byte_order = MSBFirst;
+  }
+
+  // create icon pixmap from image
+  m_icon = XCreatePixmap(m_dpy, m_glWindow, img->width, img->height, depth);
+  GC gc = XCreateGC(m_dpy, m_glWindow, 0, NULL);
+  XPutImage(m_dpy, m_icon, gc, img, 0, 0, 0, 0, img->width, img->height);
+  XFreeGC(m_dpy, gc);
+  XDestroyImage(img); // this also frees newBuf
+
+  return true;
+}
+
 #endif
diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h
index 9616d17..debf714 100644
--- a/xbmc/windowing/X11/WinSystemX11.h
+++ b/xbmc/windowing/X11/WinSystemX11.h
@@ -77,6 +77,7 @@ class CWinSystemX11 : public CWinSystemBase
   GLXContext   m_glContext;
   Display*     m_dpy;
   Cursor       m_invisibleCursor;
+  Pixmap       m_icon;
   bool         m_bWasFullScreenBeforeMinimize;
   bool         m_minimized;
   bool         m_bIgnoreNextFocusMessage;
@@ -88,6 +89,7 @@ class CWinSystemX11 : public CWinSystemBase
 private:
   bool IsSuitableVisual(XVisualInfo *vInfo);
   static int XErrorHandler(Display* dpy, XErrorEvent* error);
+  bool CreateIconPixmap();
 
   CStopWatch m_screensaverReset;
 };
-- 
1.7.10


From 377a09cf01961fff54a6e7b995a7b84cb26ea9e6 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Sun, 20 May 2012 14:11:26 +0200
Subject: [PATCH 16/58] X11: add SDL joystick until we have a better solution

---
 xbmc/windowing/WinEventsX11.cpp |   26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp
index 24477ae..2ec86a8 100644
--- a/xbmc/windowing/WinEventsX11.cpp
+++ b/xbmc/windowing/WinEventsX11.cpp
@@ -35,6 +35,10 @@
 #include "guilib/GUIWindowManager.h"
 #include "input/MouseStat.h"
 
+#ifdef HAS_SDL_JOYSTICK
+#include "input/SDLJoystick.h"
+#endif
+
 CWinEventsX11* CWinEventsX11::WinEvents = 0;
 
 static uint32_t SymMappingsX11[][2] =
@@ -547,6 +551,28 @@ bool CWinEventsX11::MessagePump()
 
   ret |= ProcessKeyRepeat();
 
+#ifdef HAS_SDL_JOYSTICK
+  SDL_Event event;
+  while (SDL_PollEvent(&event))
+  {
+    switch(event.type)
+    {
+      case SDL_JOYBUTTONUP:
+      case SDL_JOYBUTTONDOWN:
+      case SDL_JOYAXISMOTION:
+      case SDL_JOYBALLMOTION:
+      case SDL_JOYHATMOTION:
+        g_Joystick.Update(event);
+        ret = true;
+        break;
+
+      default:
+        break;
+    }
+    memset(&event, 0, sizeof(SDL_Event));
+  }
+#endif
+
   return ret;
 }
 
-- 
1.7.10


From f6f9d3688c745890331c040d231f34752ad4bd2d Mon Sep 17 00:00:00 2001
From: Joakim Plate <elupus@xbmc.org>
Date: Thu, 5 Jul 2012 12:35:55 +0200
Subject: [PATCH 17/58] X11: factor out code handling device reset
 notification

---
 xbmc/windowing/X11/WinSystemX11.cpp |   22 ++++++++++++++--------
 xbmc/windowing/X11/WinSystemX11.h   |    1 +
 2 files changed, 15 insertions(+), 8 deletions(-)

diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp
index c854598..70557d0 100644
--- a/xbmc/windowing/X11/WinSystemX11.cpp
+++ b/xbmc/windowing/X11/WinSystemX11.cpp
@@ -530,14 +530,7 @@ void CWinSystemX11::CheckDisplayEvents()
 
   if (bGotEvent || bTimeout)
   {
-    CLog::Log(LOGDEBUG, "%s - notify display reset event", __FUNCTION__);
-    RefreshWindow();
-
-    CSingleLock lock(m_resourceSection);
-
-    // tell any shared resources
-    for (vector<IDispResource *>::iterator i = m_resources.begin(); i != m_resources.end(); i++)
-      (*i)->OnResetDevice();
+    NotifyXRREvent();
 
     // reset fail safe timer
     m_dpyLostTime = 0;
@@ -545,6 +538,19 @@ void CWinSystemX11::CheckDisplayEvents()
 #endif
 }
 
+void CWinSystemX11::NotifyXRREvent()
+{
+  CLog::Log(LOGDEBUG, "%s - notify display reset event", __FUNCTION__);
+  RefreshWindow();
+
+  CSingleLock lock(m_resourceSection);
+
+  // tell any shared resources
+  for (vector<IDispResource *>::iterator i = m_resources.begin(); i != m_resources.end(); i++)
+    (*i)->OnResetDevice();
+
+}
+
 void CWinSystemX11::OnLostDevice()
 {
   CLog::Log(LOGDEBUG, "%s - notify display change event", __FUNCTION__);
diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h
index debf714..8c28e3f 100644
--- a/xbmc/windowing/X11/WinSystemX11.h
+++ b/xbmc/windowing/X11/WinSystemX11.h
@@ -66,6 +66,7 @@ class CWinSystemX11 : public CWinSystemBase
   GLXWindow GetWindow() { return m_glWindow; }
   GLXContext GetGlxContext() { return m_glContext; }
   void RefreshWindow();
+  void NotifyXRREvent();
 
 protected:
   bool RefreshGlxContext();
-- 
1.7.10


From 4ec04fa1d25596745b4499ae37503647bd212bd4 Mon Sep 17 00:00:00 2001
From: FernetMenta <fernetmenta@online.de>
Date: Thu, 5 Jul 2012 15:02:00 +0200
Subject: [PATCH 18/58] 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 <X11/extensions/Xrandr.h>
+#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<uint32_t,uint32_t> m_symLookupTable;
   int m_keymodState;
   bool m_structureChanged;
+  int m_RREventBase;
+  XbmcThreads::EndTime m_xrrFailSafeTimer;
+  bool m_xrrEventPending;
 };
diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp
index 70557d0..1cce843 100644
--- a/xbmc/windowing/X11/WinSystemX11.cpp
+++ b/xbmc/windowing/X11/WinSystemX11.cpp
@@ -507,7 +507,7 @@ bool CWinSystemX11::Show(bool raise)
 
 void CWinSystemX11::CheckDisplayEvents()
 {
-#if defined(HAS_XRANDR)
+#if defined(HAS_XRANDR) && defined(HAS_SDL_VIDEO_X11)
   bool bGotEvent(false);
   bool bTimeout(false);
   XEvent Event;
@@ -563,8 +563,12 @@ void CWinSystemX11::OnLostDevice()
       (*i)->OnLostDevice();
   }
 
+#if defined(HAS_SDL_VIDEO_X11)
   // fail safe timer
   m_dpyLostTime = CurrentHostCounter();
+#else
+  CWinEvents::SetXRRFailSafeTimer(3000);
+#endif
 }
 
 void CWinSystemX11::Register(IDispResource *resource)
-- 
1.7.10


From 1661885a13a500db73af817de5629538ee8bf65f Mon Sep 17 00:00:00 2001
From: FernetMenta <fernetmenta@online.de>
Date: Thu, 12 Apr 2012 15:43:56 +0200
Subject: [PATCH 19/58] xrandr: remove method RestoreState

---
 xbmc/windowing/X11/WinSystemX11.cpp |   13 +++++++++++--
 xbmc/windowing/X11/XRandR.cpp       |   19 -------------------
 xbmc/windowing/X11/XRandR.h         |    1 -
 3 files changed, 11 insertions(+), 22 deletions(-)

diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp
index 1cce843..e13ffa4 100644
--- a/xbmc/windowing/X11/WinSystemX11.cpp
+++ b/xbmc/windowing/X11/WinSystemX11.cpp
@@ -77,9 +77,18 @@ bool CWinSystemX11::InitWindowSystem()
 bool CWinSystemX11::DestroyWindowSystem()
 {
 #if defined(HAS_XRANDR)
-  //restore videomode on exit
+  //restore desktop resolution on exit
   if (m_bFullScreen)
-    g_xrandr.RestoreState();
+  {
+    XOutput out;
+    XMode mode;
+    out.name = g_settings.m_ResInfo[RES_DESKTOP].strOutput;
+    mode.w   = g_settings.m_ResInfo[RES_DESKTOP].iWidth;
+    mode.h   = g_settings.m_ResInfo[RES_DESKTOP].iHeight;
+    mode.hz  = g_settings.m_ResInfo[RES_DESKTOP].fRefreshRate;
+    mode.id  = g_settings.m_ResInfo[RES_DESKTOP].strId;
+    g_xrandr.SetMode(out, mode);
+  }
 #endif
 
   if (m_dpy)
diff --git a/xbmc/windowing/X11/XRandR.cpp b/xbmc/windowing/X11/XRandR.cpp
index d8e9161..59755a6 100644
--- a/xbmc/windowing/X11/XRandR.cpp
+++ b/xbmc/windowing/X11/XRandR.cpp
@@ -139,25 +139,6 @@ void CXRandR::SaveState()
   Query(true);
 }
 
-void CXRandR::RestoreState()
-{
-  vector<XOutput>::iterator outiter;
-  for (outiter=m_current.begin() ; outiter!=m_current.end() ; outiter++)
-  {
-    vector<XMode> modes = (*outiter).modes;
-    vector<XMode>::iterator modeiter;
-    for (modeiter=modes.begin() ; modeiter!=modes.end() ; modeiter++)
-    {
-      XMode mode = *modeiter;
-      if (mode.isCurrent)
-      {
-        SetMode(*outiter, mode);
-        return;
-      }
-    }
-  }
-}
-
 bool CXRandR::SetMode(XOutput output, XMode mode)
 {
   if ((output.name == m_currentOutput && mode.id == m_currentMode) || (output.name == "" && mode.id == ""))
diff --git a/xbmc/windowing/X11/XRandR.h b/xbmc/windowing/X11/XRandR.h
index 2a269d0..5b64633 100644
--- a/xbmc/windowing/X11/XRandR.h
+++ b/xbmc/windowing/X11/XRandR.h
@@ -99,7 +99,6 @@ class CXRandR
   bool SetMode(XOutput output, XMode mode);
   void LoadCustomModeLinesToAllOutputs(void);
   void SaveState();
-  void RestoreState();
   //bool Has1080i();
   //bool Has1080p();
   //bool Has720p();
-- 
1.7.10


From 01182003c79da8445e0d8cdf951cb7c6d3579c70 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Sun, 20 May 2012 13:17:10 +0200
Subject: [PATCH 20/58] xrandr: observe orientation

---
 xbmc/windowing/X11/WinSystemX11.cpp |   61 +++++++++++++++++++++++++++++++++--
 xbmc/windowing/X11/WinSystemX11.h   |    2 ++
 xbmc/windowing/X11/XRandR.cpp       |    7 ++++
 xbmc/windowing/X11/XRandR.h         |    1 +
 4 files changed, 68 insertions(+), 3 deletions(-)

diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp
index e13ffa4..6b0aa92 100644
--- a/xbmc/windowing/X11/WinSystemX11.cpp
+++ b/xbmc/windowing/X11/WinSystemX11.cpp
@@ -170,15 +170,24 @@ bool CWinSystemX11::ResizeWindow(int newWidth, int newHeight, int newLeft, int n
 
 void CWinSystemX11::RefreshWindow()
 {
-  g_xrandr.Query(true);
+  if (!g_xrandr.Query(true))
+  {
+    CLog::Log(LOGERROR, "WinSystemX11::RefreshWindow - failed to query xrandr");
+    return;
+  }
   XOutput out  = g_xrandr.GetCurrentOutput();
   XMode   mode = g_xrandr.GetCurrentMode(out.name);
 
+  RotateResolutions();
+
   // only overwrite desktop resolution, if we are not in fullscreen mode
   if (!g_graphicsContext.IsFullScreenVideo())
   {
     CLog::Log(LOGDEBUG, "CWinSystemX11::RefreshWindow - store desktop resolution, width: %d, height: %d, hz: %2.2f", mode.w, mode.h, mode.hz);
-    UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.w, mode.h, mode.hz);
+    if (!out.isRotated)
+      UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.w, mode.h, mode.hz);
+    else
+      UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.h, mode.w, mode.hz);
     g_settings.m_ResInfo[RES_DESKTOP].strId     = mode.id;
     g_settings.m_ResInfo[RES_DESKTOP].strOutput = out.name;
   }
@@ -234,6 +243,14 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl
   XOutput currout  = g_xrandr.GetCurrentOutput();
   XMode   currmode = g_xrandr.GetCurrentMode(currout.name);
 
+  // flip h/w when rotated
+  if (m_bIsRotated)
+  {
+    int w = mode.w;
+    mode.w = mode.h;
+    mode.h = w;
+  }
+
   // only call xrandr if mode changes
   if (currout.name != out.name || currmode.w != mode.w || currmode.h != mode.h ||
       currmode.hz != mode.hz || currmode.id != mode.id)
@@ -266,7 +283,11 @@ void CWinSystemX11::UpdateResolutions()
   {
     XOutput out  = g_xrandr.GetCurrentOutput();
     XMode   mode = g_xrandr.GetCurrentMode(out.name);
-    UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.w, mode.h, mode.hz);
+    m_bIsRotated = out.isRotated;
+    if (!m_bIsRotated)
+      UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.w, mode.h, mode.hz);
+    else
+      UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.h, mode.w, mode.hz);
     g_settings.m_ResInfo[RES_DESKTOP].strId     = mode.id;
     g_settings.m_ResInfo[RES_DESKTOP].strOutput = out.name;
   }
@@ -305,6 +326,16 @@ void CWinSystemX11::UpdateResolutions()
       res.iHeight = mode.h;
       res.iScreenWidth  = mode.w;
       res.iScreenHeight = mode.h;
+      if (!m_bIsRotated)
+      {
+        res.iWidth  = mode.w;
+        res.iHeight = mode.h;
+      }
+      else
+      {
+        res.iWidth  = mode.h;
+        res.iHeight = mode.w;
+      }
       if (mode.h>0 && mode.w>0 && out.hmm>0 && out.wmm>0)
         res.fPixelRatio = ((float)out.wmm/(float)mode.w) / (((float)out.hmm/(float)mode.h));
       else
@@ -332,6 +363,30 @@ void CWinSystemX11::UpdateResolutions()
 
 }
 
+void CWinSystemX11::RotateResolutions()
+{
+#if defined(HAS_XRANDR)
+  XOutput out  = g_xrandr.GetCurrentOutput();
+  if (out.isRotated == m_bIsRotated)
+    return;
+
+  for (unsigned int i = 0; i < g_settings.m_ResInfo.size(); ++i)
+  {
+    int width = g_settings.m_ResInfo[i].iWidth;
+    g_settings.m_ResInfo[i].iWidth = g_settings.m_ResInfo[i].iHeight;
+    g_settings.m_ResInfo[i].iHeight = width;
+  }
+  // update desktop resolution
+//  int h = g_settings.m_ResInfo[RES_DESKTOP].iHeight;
+//  int w = g_settings.m_ResInfo[RES_DESKTOP].iWidth;
+//  float hz = g_settings.m_ResInfo[RES_DESKTOP].fRefreshRate;
+//  UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, w, h, hz);
+
+  m_bIsRotated = out.isRotated;
+
+#endif
+}
+
 bool CWinSystemX11::IsSuitableVisual(XVisualInfo *vInfo)
 {
   int value;
diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h
index 8c28e3f..93cf5db 100644
--- a/xbmc/windowing/X11/WinSystemX11.h
+++ b/xbmc/windowing/X11/WinSystemX11.h
@@ -73,12 +73,14 @@ class CWinSystemX11 : public CWinSystemBase
   void CheckDisplayEvents();
   void OnLostDevice();
   bool SetWindow(int width, int height, bool fullscreen);
+  void RotateResolutions();
 
   Window       m_glWindow;
   GLXContext   m_glContext;
   Display*     m_dpy;
   Cursor       m_invisibleCursor;
   Pixmap       m_icon;
+  bool         m_bIsRotated;
   bool         m_bWasFullScreenBeforeMinimize;
   bool         m_minimized;
   bool         m_bIgnoreNextFocusMessage;
diff --git a/xbmc/windowing/X11/XRandR.cpp b/xbmc/windowing/X11/XRandR.cpp
index 59755a6..45aeb71 100644
--- a/xbmc/windowing/X11/XRandR.cpp
+++ b/xbmc/windowing/X11/XRandR.cpp
@@ -98,6 +98,13 @@ bool CXRandR::Query(bool force)
     xoutput.y = (output->Attribute("y") != NULL ? atoi(output->Attribute("y")) : 0);
     xoutput.wmm = (output->Attribute("wmm") != NULL ? atoi(output->Attribute("wmm")) : 0);
     xoutput.hmm = (output->Attribute("hmm") != NULL ? atoi(output->Attribute("hmm")) : 0);
+    if (output->Attribute("rotation") != NULL
+        && (strcasecmp(output->Attribute("rotation"), "left") == 0 || strcasecmp(output->Attribute("rotation"), "right") == 0))
+    {
+      xoutput.isRotated = true;
+    }
+    else
+      xoutput.isRotated = false;
 
     if (!xoutput.isConnected)
        continue;
diff --git a/xbmc/windowing/X11/XRandR.h b/xbmc/windowing/X11/XRandR.h
index 5b64633..618bd68 100644
--- a/xbmc/windowing/X11/XRandR.h
+++ b/xbmc/windowing/X11/XRandR.h
@@ -86,6 +86,7 @@ class XOutput
   int wmm;
   int hmm;
   std::vector<XMode> modes;
+  bool isRotated;
 };
 
 class CXRandR
-- 
1.7.10


From 2249ddc7458204c171fcf8ed29c39b66373a2de6 Mon Sep 17 00:00:00 2001
From: FernetMenta <fernetmenta@online.de>
Date: Thu, 5 Jul 2012 11:54:15 +0200
Subject: [PATCH 21/58] xrandr: allow getting info for multiple screen's

Refactored by: Joakim Plate <elupus@xbmc.org>
---
 xbmc/windowing/X11/XRandR.cpp |   65 ++++++++++++++++++++++++++++++++---------
 xbmc/windowing/X11/XRandR.h   |    8 +++--
 2 files changed, 57 insertions(+), 16 deletions(-)

diff --git a/xbmc/windowing/X11/XRandR.cpp b/xbmc/windowing/X11/XRandR.cpp
index 45aeb71..cc933b9 100644
--- a/xbmc/windowing/X11/XRandR.cpp
+++ b/xbmc/windowing/X11/XRandR.cpp
@@ -39,6 +39,7 @@
 CXRandR::CXRandR(bool query)
 {
   m_bInit = false;
+  m_numScreens = 1;
   if (query)
     Query();
 }
@@ -55,11 +56,21 @@ bool CXRandR::Query(bool force)
     return false;
 
   m_outputs.clear();
-  m_current.clear();
+  // query all screens
+  for(unsigned int screennum=0; screennum<m_numScreens; ++screennum)
+  {
+    if(!Query(force, screennum))
+      return false;
+  }
+  return true;
+}
 
+bool CXRandR::Query(bool force, int screennum)
+{
   CStdString cmd;
   cmd  = getenv("XBMC_BIN_HOME");
   cmd += "/xbmc-xrandr";
+  cmd.append("-q --screen %d", screennum);
 
   FILE* file = popen(cmd.c_str(),"r");
   if (!file)
@@ -79,7 +90,7 @@ bool CXRandR::Query(bool force)
   pclose(file);
 
   TiXmlElement *pRootElement = xmlDoc.RootElement();
-  if (strcasecmp(pRootElement->Value(), "screen") != 0)
+  if (strcasecmp(pRootElement->Value(), "screen") != screennum)
   {
     // TODO ERROR
     return false;
@@ -92,6 +103,7 @@ bool CXRandR::Query(bool force)
     xoutput.name.TrimLeft(" \n\r\t");
     xoutput.name.TrimRight(" \n\r\t");
     xoutput.isConnected = (strcasecmp(output->Attribute("connected"), "true") == 0);
+    xoutput.screen = screennum;
     xoutput.w = (output->Attribute("w") != NULL ? atoi(output->Attribute("w")) : 0);
     xoutput.h = (output->Attribute("h") != NULL ? atoi(output->Attribute("h")) : 0);
     xoutput.x = (output->Attribute("x") != NULL ? atoi(output->Attribute("x")) : 0);
@@ -123,7 +135,6 @@ bool CXRandR::Query(bool force)
       xoutput.modes.push_back(xmode);
       if (xmode.isCurrent)
       {
-        m_current.push_back(xoutput);
         hascurrent = true;
       }
     }
@@ -247,17 +258,6 @@ bool CXRandR::SetMode(XOutput output, XMode mode)
   return true;
 }
 
-XOutput CXRandR::GetCurrentOutput()
-{
-  Query();
-  for (unsigned int j = 0; j < m_outputs.size(); j++)
-  {
-    if(m_outputs[j].isConnected)
-      return m_outputs[j];
-  }
-  XOutput empty;
-  return empty;
-}
 XMode CXRandR::GetCurrentMode(CStdString outputName)
 {
   Query();
@@ -331,6 +331,43 @@ void CXRandR::LoadCustomModeLinesToAllOutputs(void)
   }
 }
 
+void CXRandR::SetNumScreens(unsigned int num)
+{
+  m_numScreens = num;
+  m_bInit = false;
+}
+
+bool CXRandR::IsOutputConnected(CStdString name)
+{
+  bool result = false;
+  Query();
+
+  for (unsigned int i = 0; i < m_outputs.size(); ++i)
+  {
+    if (m_outputs[i].name == name)
+    {
+      result = true;
+      break;
+    }
+  }
+  return result;
+}
+
+XOutput* CXRandR::GetOutput(CStdString outputName)
+{
+  XOutput *result = 0;
+  Query();
+  for (unsigned int i = 0; i < m_outputs.size(); ++i)
+  {
+    if (m_outputs[i].name == outputName)
+    {
+      result = &m_outputs[i];
+      break;
+    }
+  }
+  return result;
+}
+
 CXRandR g_xrandr;
 
 #endif // HAS_XRANDR
diff --git a/xbmc/windowing/X11/XRandR.h b/xbmc/windowing/X11/XRandR.h
index 618bd68..0824af5 100644
--- a/xbmc/windowing/X11/XRandR.h
+++ b/xbmc/windowing/X11/XRandR.h
@@ -79,6 +79,7 @@ class XOutput
     }
   CStdString name;
   bool isConnected;
+  int screen;
   int w;
   int h;
   int x;
@@ -94,12 +95,15 @@ class CXRandR
 public:
   CXRandR(bool query=false);
   bool Query(bool force=false);
+  bool Query(bool force, int screennum);
   std::vector<XOutput> 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<XOutput> m_current;
   std::vector<XOutput> m_outputs;
   CStdString m_currentOutput;
   CStdString m_currentMode;
+  unsigned int m_numScreens;
 };
 
 extern CXRandR g_xrandr;
-- 
1.7.10


From bd5aaf4fca228cb80d361262b9e28c7f2443fa0b Mon Sep 17 00:00:00 2001
From: FernetMenta <fernetmenta@online.de>
Date: Thu, 5 Jul 2012 11:44:00 +0200
Subject: [PATCH 22/58] X11: fix multi-head setups

---
 language/English/strings.po                 |    4 +-
 xbmc/rendering/gl/RenderSystemGL.h          |    1 +
 xbmc/settings/GUISettings.cpp               |    5 +
 xbmc/settings/GUIWindowSettingsCategory.cpp |   60 +++++-
 xbmc/settings/GUIWindowSettingsCategory.h   |    1 +
 xbmc/windowing/WinEventsX11.cpp             |    7 +
 xbmc/windowing/X11/WinSystemX11.cpp         |  262 ++++++++++++++++-----------
 xbmc/windowing/X11/WinSystemX11.h           |   10 +-
 8 files changed, 235 insertions(+), 115 deletions(-)

diff --git a/language/English/strings.po b/language/English/strings.po
index d046110..9887f19 100644
--- a/language/English/strings.po
+++ b/language/English/strings.po
@@ -895,7 +895,9 @@ msgctxt "#245"
 msgid "Sizing: (%i,%i)->(%i,%i) (Zoom x%2.2f) AR:%2.2f:1 (Pixels: %2.2f:1) (VShift: %2.2f)"
 msgstr ""
 
-#empty string with id 246
+msgctxt "#246"
+msgid "Monitor"
+msgstr ""
 
 msgctxt "#247"
 msgid "Scripts"
diff --git a/xbmc/rendering/gl/RenderSystemGL.h b/xbmc/rendering/gl/RenderSystemGL.h
index efe5493..85d780d 100644
--- a/xbmc/rendering/gl/RenderSystemGL.h
+++ b/xbmc/rendering/gl/RenderSystemGL.h
@@ -44,6 +44,7 @@ class CRenderSystemGL : public CRenderSystemBase
   virtual bool IsExtSupported(const char* extension);
 
   virtual void SetVSync(bool vsync);
+  virtual void ResetVSync() { m_bVsyncInit = false; }
 
   virtual void SetViewPort(CRect& viewPort);
   virtual void GetViewPort(CRect& viewPort);
diff --git a/xbmc/settings/GUISettings.cpp b/xbmc/settings/GUISettings.cpp
index e9bc6f5..abf5c01 100644
--- a/xbmc/settings/GUISettings.cpp
+++ b/xbmc/settings/GUISettings.cpp
@@ -392,11 +392,16 @@ void CGUISettings::Initialize()
   AddGroup(SETTINGS_SYSTEM, 13000);
   CSettingsCategory* vs = AddCategory(SETTINGS_SYSTEM, "videoscreen", 21373);
 
+#if defined(HAS_GLX)
+  AddString(vs, "videoscreen.monitor", 246, "", SPIN_CONTROL_TEXT);
+#endif
+
   // this setting would ideally not be saved, as its value is systematically derived from videoscreen.screenmode.
   // contains a DISPLAYMODE
 #if !defined(TARGET_DARWIN_IOS_ATV2) && !defined(TARGET_RASPBERRY_PI)
   AddInt(vs, "videoscreen.screen", 240, 0, -1, 1, 32, SPIN_CONTROL_TEXT);
 #endif
+
   // this setting would ideally not be saved, as its value is systematically derived from videoscreen.screenmode.
   // contains an index to the g_settings.m_ResInfo array. the only meaningful fields are iScreen, iWidth, iHeight.
 #if defined(TARGET_DARWIN)
diff --git a/xbmc/settings/GUIWindowSettingsCategory.cpp b/xbmc/settings/GUIWindowSettingsCategory.cpp
index 785f24d..89addf7 100644
--- a/xbmc/settings/GUIWindowSettingsCategory.cpp
+++ b/xbmc/settings/GUIWindowSettingsCategory.cpp
@@ -528,6 +528,12 @@ void CGUIWindowSettingsCategory::CreateSettings()
       FillInRefreshRates(strSetting, g_guiSettings.GetResolution(), false);
       continue;
     }
+    else if (strSetting.Equals("videoscreen.monitor"))
+    {
+      AddSetting(pSetting, group->GetWidth(), iControlID);
+      FillInMonitors(strSetting);
+      continue;
+    }
     else if (strSetting.Equals("lookandfeel.skintheme"))
     {
       AddSetting(pSetting, group->GetWidth(), iControlID);
@@ -1489,6 +1495,20 @@ void CGUIWindowSettingsCategory::OnSettingChanged(CBaseSettingControl *pSettingC
     // 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");
@@ -2418,11 +2438,15 @@ DisplayMode CGUIWindowSettingsCategory::FillInScreens(CStdString strSetting, RES
     if (g_advancedSettings.m_canWindowed)
       pControl->AddLabel(g_localizeStrings.Get(242), -1);
 
+#if !defined(HAS_GLX)
     for (int idx = 0; idx < g_Windowing.GetNumScreens(); idx++)
     {
       strScreen.Format(g_localizeStrings.Get(241), g_settings.m_ResInfo[RES_DESKTOP + idx].iScreen + 1);
       pControl->AddLabel(strScreen, g_settings.m_ResInfo[RES_DESKTOP + idx].iScreen);
     }
+#else
+    pControl->AddLabel(g_localizeStrings.Get(244), 0);
+#endif
     pControl->SetValue(mode);
     g_guiSettings.SetInt("videoscreen.screen", mode);
   }
@@ -2430,6 +2454,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<CStdString> monitors;
+    g_Windowing.GetConnectedOutputs(&monitors);
+
+    int currentMonitor = 0;
+    for (unsigned int i=0; i<monitors.size(); ++i)
+    {
+      if(g_settings.m_ResInfo[RES_DESKTOP].strOutput.Equals(monitors[i]))
+      {
+        currentMonitor = i;
+      }
+      pControl->AddLabel(monitors[i], i);
+    }
+
+    pControl->SetValue(currentMonitor);
+    g_guiSettings.SetString("videoscreen.monitor", g_settings.m_ResInfo[RES_DESKTOP].strOutput);
+  }
+}
+
+
 void CGUIWindowSettingsCategory::FillInResolutions(CStdString strSetting, DisplayMode mode, RESOLUTION res, bool UserChange)
 {
   CBaseSettingControl *control = GetSetting(strSetting);
@@ -2558,13 +2612,15 @@ void CGUIWindowSettingsCategory::OnRefreshRateChanged(RESOLUTION nextRes)
   RESOLUTION lastRes = g_graphicsContext.GetVideoResolution();
   bool cancelled = false;
 
+  bool outputChanged = !g_Windowing.IsCurrentOutput(g_guiSettings.GetString("videoscreen.monitor"));
+
   g_guiSettings.SetResolution(nextRes);
-  g_graphicsContext.SetVideoResolution(nextRes);
+  g_graphicsContext.SetVideoResolution(nextRes, outputChanged);
 
   if (!CGUIDialogYesNo::ShowAndGetInput(13110, 13111, 20022, 20022, -1, -1, cancelled, 10000))
   {
     g_guiSettings.SetResolution(lastRes);
-    g_graphicsContext.SetVideoResolution(lastRes);
+    g_graphicsContext.SetVideoResolution(lastRes, outputChanged);
 
     DisplayMode mode = FillInScreens("videoscreen.screen", lastRes);
     FillInResolutions("videoscreen.resolution", mode, lastRes, false);
diff --git a/xbmc/settings/GUIWindowSettingsCategory.h b/xbmc/settings/GUIWindowSettingsCategory.h
index 4a57322..82103cc 100644
--- a/xbmc/settings/GUIWindowSettingsCategory.h
+++ b/xbmc/settings/GUIWindowSettingsCategory.h
@@ -49,6 +49,7 @@ class CGUIWindowSettingsCategory :
   void FillInSoundSkins(CSetting *pSetting);
   void FillInLanguages(CSetting *pSetting, const std::vector<CStdString> &languages = std::vector<CStdString>(), const std::vector<CStdString> &languageKeys = std::vector<CStdString>());
   DisplayMode FillInScreens(CStdString strSetting, RESOLUTION res);
+  void FillInMonitors(CStdString strSetting);
   void FillInResolutions(CStdString strSetting, DisplayMode mode, RESOLUTION res, bool UserChange);
   void FillInRefreshRates(CStdString strSetting, RESOLUTION res, bool UserChange);
   void OnRefreshRateChanged(RESOLUTION resolution);
diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp
index 5946a33..6c22358 100644
--- a/xbmc/windowing/WinEventsX11.cpp
+++ b/xbmc/windowing/WinEventsX11.cpp
@@ -517,9 +517,16 @@ bool CWinEventsX11::MessagePump()
         break;
       }
 
+      case EnterNotify:
+      {
+        g_Windowing.NotifyMouseCoverage(true);
+        break;
+      }
+
       // lose mouse coverage
       case LeaveNotify:
       {
+        g_Windowing.NotifyMouseCoverage(false);
         g_Mouse.SetActive(false);
         break;
       }
diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp
index 6b0aa92..5f913f1 100644
--- a/xbmc/windowing/X11/WinSystemX11.cpp
+++ b/xbmc/windowing/X11/WinSystemX11.cpp
@@ -33,6 +33,7 @@
 #include "cores/VideoRenderers/RenderManager.h"
 #include "utils/TimeUtils.h"
 #include "settings/GUISettings.h"
+#include "windowing/WindowingFactory.h"
 
 #if defined(HAS_XRANDR)
 #include <X11/extensions/Xrandr.h>
@@ -54,6 +55,7 @@
   m_bIgnoreNextFocusMessage = false;
   m_dpyLostTime = 0;
   m_invisibleCursor = 0;
+  m_bIsInternalXrr = false;
 
   XSetErrorHandler(XErrorHandler);
 }
@@ -66,7 +68,8 @@ bool CWinSystemX11::InitWindowSystem()
 {
   if ((m_dpy = XOpenDisplay(NULL)))
   {
-    return CWinSystemBase::InitWindowSystem();
+    bool ret = CWinSystemBase::InitWindowSystem();
+    return ret;
   }
   else
     CLog::Log(LOGERROR, "GLX Error: No Display found");
@@ -103,6 +106,8 @@ bool CWinSystemX11::DestroyWindowSystem()
 
     //we don't call XCloseDisplay() here, since ati keeps a pointer to our m_dpy
     //so instead we just let m_dpy die on exit
+    // i have seen core dumps on ATI if the display is not closed here
+    XCloseDisplay(m_dpy);
   }
 
   // m_SDLSurface is free()'d by SDL_Quit().
@@ -125,7 +130,10 @@ bool CWinSystemX11::DestroyWindow()
     return true;
 
   if (m_glContext)
+  {
+    glFinish();
     glXMakeCurrent(m_dpy, None, NULL);
+  }
 
   if (m_invisibleCursor)
   {
@@ -155,7 +163,7 @@ bool CWinSystemX11::ResizeWindow(int newWidth, int newHeight, int newLeft, int n
   && m_nHeight == newHeight)
     return true;
 
-  if (!SetWindow(newWidth, newHeight, false))
+  if (!SetWindow(newWidth, newHeight, false, g_guiSettings.GetString("videoscreen.monitor")))
   {
     return false;
   }
@@ -164,58 +172,11 @@ bool CWinSystemX11::ResizeWindow(int newWidth, int newHeight, int newLeft, int n
   m_nWidth  = newWidth;
   m_nHeight = newHeight;
   m_bFullScreen = false;
+  m_currentOutput = g_guiSettings.GetString("videoscreen.monitor");
 
   return false;
 }
 
-void CWinSystemX11::RefreshWindow()
-{
-  if (!g_xrandr.Query(true))
-  {
-    CLog::Log(LOGERROR, "WinSystemX11::RefreshWindow - failed to query xrandr");
-    return;
-  }
-  XOutput out  = g_xrandr.GetCurrentOutput();
-  XMode   mode = g_xrandr.GetCurrentMode(out.name);
-
-  RotateResolutions();
-
-  // only overwrite desktop resolution, if we are not in fullscreen mode
-  if (!g_graphicsContext.IsFullScreenVideo())
-  {
-    CLog::Log(LOGDEBUG, "CWinSystemX11::RefreshWindow - store desktop resolution, width: %d, height: %d, hz: %2.2f", mode.w, mode.h, mode.hz);
-    if (!out.isRotated)
-      UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.w, mode.h, mode.hz);
-    else
-      UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.h, mode.w, mode.hz);
-    g_settings.m_ResInfo[RES_DESKTOP].strId     = mode.id;
-    g_settings.m_ResInfo[RES_DESKTOP].strOutput = out.name;
-  }
-
-  RESOLUTION_INFO res;
-  unsigned int i;
-  bool found(false);
-  for (i = RES_DESKTOP; i < g_settings.m_ResInfo.size(); ++i)
-  {
-    if (g_settings.m_ResInfo[i].strId == mode.id)
-    {
-      found = true;
-      break;
-    }
-  }
-
-  if (!found)
-  {
-    CLog::Log(LOGERROR, "CWinSystemX11::RefreshWindow - could not find resolution");
-    return;
-  }
-
-  if (g_graphicsContext.IsFullScreenRoot())
-    g_graphicsContext.SetVideoResolution((RESOLUTION)i, true);
-  else
-    g_graphicsContext.SetVideoResolution(RES_WINDOW, true);
-}
-
 bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays)
 {
 
@@ -240,8 +201,7 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl
     mode.id  = g_settings.m_ResInfo[RES_DESKTOP].strId;
   }
  
-  XOutput currout  = g_xrandr.GetCurrentOutput();
-  XMode   currmode = g_xrandr.GetCurrentMode(currout.name);
+  XMode   currmode = g_xrandr.GetCurrentMode(out.name);
 
   // flip h/w when rotated
   if (m_bIsRotated)
@@ -252,16 +212,17 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl
   }
 
   // only call xrandr if mode changes
-  if (currout.name != out.name || currmode.w != mode.w || currmode.h != mode.h ||
+  if (currmode.w != mode.w || currmode.h != mode.h ||
       currmode.hz != mode.hz || currmode.id != mode.id)
   {
     CLog::Log(LOGNOTICE, "CWinSystemX11::SetFullScreen - calling xrandr");
     OnLostDevice();
+    m_bIsInternalXrr = true;
     g_xrandr.SetMode(out, mode);
   }
 #endif
 
-  if (!SetWindow(res.iWidth, res.iHeight, fullScreen))
+  if (!SetWindow(res.iWidth, res.iHeight, fullScreen, g_guiSettings.GetString("videoscreen.monitor")))
     return false;
 
   RefreshGlxContext();
@@ -269,6 +230,7 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl
   m_nWidth      = res.iWidth;
   m_nHeight     = res.iHeight;
   m_bFullScreen = fullScreen;
+  m_currentOutput = g_guiSettings.GetString("videoscreen.monitor");
 
   return true;
 }
@@ -277,19 +239,30 @@ void CWinSystemX11::UpdateResolutions()
 {
   CWinSystemBase::UpdateResolutions();
 
-
 #if defined(HAS_XRANDR)
-  if(g_xrandr.Query())
-  {
-    XOutput out  = g_xrandr.GetCurrentOutput();
-    XMode   mode = g_xrandr.GetCurrentMode(out.name);
-    m_bIsRotated = out.isRotated;
+  CStdString currentMonitor;
+  int numScreens = XScreenCount(m_dpy);
+  g_xrandr.SetNumScreens(numScreens);
+  if(g_xrandr.Query(true))
+  {
+    currentMonitor = g_guiSettings.GetString("videoscreen.monitor");
+    // check if the monitor is connected
+    XOutput *out = g_xrandr.GetOutput(currentMonitor);
+    if (!out)
+    {
+      // choose first output
+      currentMonitor = g_xrandr.GetModes()[0].name;
+      out = g_xrandr.GetOutput(currentMonitor);
+      g_guiSettings.SetString("videoscreen.monitor", currentMonitor);
+    }
+    XMode mode = g_xrandr.GetCurrentMode(currentMonitor);
+    m_bIsRotated = out->isRotated;
     if (!m_bIsRotated)
-      UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.w, mode.h, mode.hz);
+      UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], out->screen, mode.w, mode.h, mode.hz);
     else
-      UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.h, mode.w, mode.hz);
+      UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], out->screen, mode.h, mode.w, mode.hz);
     g_settings.m_ResInfo[RES_DESKTOP].strId     = mode.id;
-    g_settings.m_ResInfo[RES_DESKTOP].strOutput = out.name;
+    g_settings.m_ResInfo[RES_DESKTOP].strOutput = currentMonitor;
   }
   else
 #endif
@@ -300,23 +273,26 @@ void CWinSystemX11::UpdateResolutions()
     UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, w, h, 0.0);
   }
 
-
 #if defined(HAS_XRANDR)
 
+  // erase previous stored modes
+  if (g_settings.m_ResInfo.size() > RES_CUSTOM)
+  {
+    std::vector<RESOLUTION_INFO>::iterator firstCustom = g_settings.m_ResInfo.begin()+RES_CUSTOM;
+    g_settings.m_ResInfo.erase(firstCustom, g_settings.m_ResInfo.end());
+  }
+
   CLog::Log(LOGINFO, "Available videomodes (xrandr):");
-  vector<XOutput>::iterator outiter;
-  vector<XOutput> 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<XMode>::iterator modeiter;
-    CLog::Log(LOGINFO, "Output '%s' has %"PRIdS" modes", out.name.c_str(), out.modes.size());
+    CLog::Log(LOGINFO, "Output '%s' has %"PRIdS" modes", out->name.c_str(), out->modes.size());
 
-    for (modeiter = out.modes.begin() ; modeiter!=out.modes.end() ; modeiter++)
+    for (modeiter = out->modes.begin() ; modeiter!=out->modes.end() ; modeiter++)
     {
       XMode mode = *modeiter;
       CLog::Log(LOGINFO, "ID:%s Name:%s Refresh:%f Width:%d Height:%d",
@@ -336,15 +312,15 @@ void CWinSystemX11::UpdateResolutions()
         res.iWidth  = mode.h;
         res.iHeight = mode.w;
       }
-      if (mode.h>0 && mode.w>0 && out.hmm>0 && out.wmm>0)
-        res.fPixelRatio = ((float)out.wmm/(float)mode.w) / (((float)out.hmm/(float)mode.h));
+      if (mode.h>0 && mode.w>0 && out->hmm>0 && out->wmm>0)
+        res.fPixelRatio = ((float)out->wmm/(float)mode.w) / (((float)out->hmm/(float)mode.h));
       else
         res.fPixelRatio = 1.0f;
 
       CLog::Log(LOGINFO, "Pixel Ratio: %f", res.fPixelRatio);
 
-      res.strMode.Format("%s: %s @ %.2fHz", out.name.c_str(), mode.name.c_str(), mode.hz);
-      res.strOutput    = out.name;
+      res.strMode.Format("%s: %s @ %.2fHz", out->name.c_str(), mode.name.c_str(), mode.hz);
+      res.strOutput    = out->name;
       res.strId        = mode.id;
       res.iSubtitles   = (int)(0.95*mode.h);
       res.fRefreshRate = mode.hz;
@@ -363,28 +339,19 @@ void CWinSystemX11::UpdateResolutions()
 
 }
 
-void CWinSystemX11::RotateResolutions()
+void CWinSystemX11::GetConnectedOutputs(std::vector<CStdString> *outputs)
 {
-#if defined(HAS_XRANDR)
-  XOutput out  = g_xrandr.GetCurrentOutput();
-  if (out.isRotated == m_bIsRotated)
-    return;
-
-  for (unsigned int i = 0; i < g_settings.m_ResInfo.size(); ++i)
+  vector<XOutput> outs;
+  outs = g_xrandr.GetModes();
+  for(unsigned int i=0; i<outs.size(); ++i)
   {
-    int width = g_settings.m_ResInfo[i].iWidth;
-    g_settings.m_ResInfo[i].iWidth = g_settings.m_ResInfo[i].iHeight;
-    g_settings.m_ResInfo[i].iHeight = width;
+    outputs->push_back(outs[i].name);
   }
-  // update desktop resolution
-//  int h = g_settings.m_ResInfo[RES_DESKTOP].iHeight;
-//  int w = g_settings.m_ResInfo[RES_DESKTOP].iWidth;
-//  float hz = g_settings.m_ResInfo[RES_DESKTOP].fRefreshRate;
-//  UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, w, h, hz);
-
-  m_bIsRotated = out.isRotated;
+}
 
-#endif
+bool CWinSystemX11::IsCurrentOutput(CStdString output)
+{
+  return m_currentOutput.Equals(output);
 }
 
 bool CWinSystemX11::IsSuitableVisual(XVisualInfo *vInfo)
@@ -414,8 +381,11 @@ bool CWinSystemX11::RefreshGlxContext()
   if (m_glContext)
   {
     CLog::Log(LOGDEBUG, "CWinSystemX11::RefreshGlxContext: refreshing context");
+    glFinish();
     glXMakeCurrent(m_dpy, None, NULL);
     glXMakeCurrent(m_dpy, m_glWindow, m_glContext);
+    XSync(m_dpy, FALSE);
+    g_Windowing.ResetVSync();
     return true;
   }
 
@@ -481,6 +451,8 @@ bool CWinSystemX11::RefreshGlxContext()
     {
       // make this context current
       glXMakeCurrent(m_dpy, m_glWindow, m_glContext);
+      g_Windowing.ResetVSync();
+      XSync(m_dpy, False);
       retVal = true;
     }
     else
@@ -522,24 +494,53 @@ void CWinSystemX11::ResetOSScreensaver()
 
 void CWinSystemX11::NotifyAppActiveChange(bool bActivated)
 {
-  if (bActivated && m_bWasFullScreenBeforeMinimize && !g_graphicsContext.IsFullScreenRoot())
+  if (bActivated && m_bWasFullScreenBeforeMinimize && !m_bFullScreen)
+  {
     g_graphicsContext.ToggleFullScreenRoot();
 
+    m_bWasFullScreenBeforeMinimize = false;
+  }
   m_minimized = !bActivated;
 }
 
 void CWinSystemX11::NotifyAppFocusChange(bool bGaining)
 {
   if (bGaining && m_bWasFullScreenBeforeMinimize && !m_bIgnoreNextFocusMessage &&
-      !g_graphicsContext.IsFullScreenRoot())
+      !m_bFullScreen)
+  {
+    m_bWasFullScreenBeforeMinimize = false;
     g_graphicsContext.ToggleFullScreenRoot();
+    m_minimized = false;
+  }
   if (!bGaining)
     m_bIgnoreNextFocusMessage = false;
 }
 
+void CWinSystemX11::NotifyMouseCoverage(bool covered)
+{
+  if (!m_bFullScreen)
+    return;
+
+  if (covered)
+  {
+    int result = -1;
+    while (result != GrabSuccess && result != AlreadyGrabbed)
+    {
+      result = XGrabPointer(m_dpy, m_glWindow, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
+      XbmcThreads::ThreadSleep(100);
+    }
+    XGrabKeyboard(m_dpy, m_glWindow, True, GrabModeAsync, GrabModeAsync, CurrentTime);
+  }
+  else
+  {
+    XUngrabKeyboard(m_dpy, CurrentTime);
+    XUngrabPointer(m_dpy, CurrentTime);
+  }
+}
+
 bool CWinSystemX11::Minimize()
 {
-  m_bWasFullScreenBeforeMinimize = g_graphicsContext.IsFullScreenRoot();
+  m_bWasFullScreenBeforeMinimize = m_bFullScreen;
   if (m_bWasFullScreenBeforeMinimize)
   {
     m_bIgnoreNextFocusMessage = true;
@@ -605,13 +606,46 @@ void CWinSystemX11::CheckDisplayEvents()
 void CWinSystemX11::NotifyXRREvent()
 {
   CLog::Log(LOGDEBUG, "%s - notify display reset event", __FUNCTION__);
-  RefreshWindow();
+  m_windowDirty = true;
 
-  CSingleLock lock(m_resourceSection);
+  // if external event update resolutions
+  if (!m_bIsInternalXrr)
+  {
+    UpdateResolutions();
+  }
+  else if (!g_xrandr.Query(true))
+  {
+    CLog::Log(LOGERROR, "WinSystemX11::RefreshWindow - failed to query xrandr");
+    return;
+  }
+  m_bIsInternalXrr = false;
 
-  // tell any shared resources
-  for (vector<IDispResource *>::iterator i = m_resources.begin(); i != m_resources.end(); i++)
-    (*i)->OnResetDevice();
+  CStdString currentOutput = g_guiSettings.GetString("videoscreen.monitor");
+  XOutput *out = g_xrandr.GetOutput(currentOutput);
+  XMode   mode = g_xrandr.GetCurrentMode(currentOutput);
+
+  RESOLUTION_INFO res;
+  unsigned int i;
+  bool found(false);
+  for (i = RES_DESKTOP; i < g_settings.m_ResInfo.size(); ++i)
+  {
+    if (g_settings.m_ResInfo[i].strId == mode.id)
+    {
+      found = true;
+      break;
+    }
+  }
+
+  if (!found)
+  {
+    CLog::Log(LOGERROR, "CWinSystemX11::RefreshWindow - could not find resolution");
+    i = RES_DESKTOP;
+  }
+
+  if (g_graphicsContext.IsFullScreenRoot())
+    g_graphicsContext.SetVideoResolution((RESOLUTION)i, true);
+  else
+    g_graphicsContext.SetVideoResolution(RES_WINDOW, true);
 
 }
 
@@ -664,14 +698,14 @@ bool CWinSystemX11::EnableFrameLimiter()
   return m_minimized;
 }
 
-bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen)
+bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStdString &output)
 {
   bool changeWindow = false;
   bool changeSize = false;
   bool mouseActive = false;
   float mouseX, mouseY;
 
-  if (m_glWindow && (m_bFullScreen != fullscreen))
+  if (m_glWindow && ((m_bFullScreen != fullscreen) || !m_currentOutput.Equals(output) || m_windowDirty))
   {
     mouseActive = g_Mouse.IsActive();
     if (mouseActive)
@@ -693,6 +727,7 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen)
       else
         mouseActive = false;
     }
+    OnLostDevice();
     DestroyWindow();
   }
 
@@ -714,7 +749,11 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen)
     XSetWindowAttributes swa;
     XVisualInfo *vi;
 
-    vi = glXChooseVisual(m_dpy, DefaultScreen(m_dpy), att);
+    XOutput *out = g_xrandr.GetOutput(output);
+    if (!out)
+      out = g_xrandr.GetOutput(m_currentOutput);
+    m_nScreen = out->screen;
+    vi = glXChooseVisual(m_dpy, m_nScreen, att);
     cmap = XCreateColormap(m_dpy, RootWindow(m_dpy, vi->screen), vi->visual, AllocNone);
 
     int def_vis = (vi->visual == DefaultVisual(m_dpy, vi->screen));
@@ -730,7 +769,7 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen)
     unsigned long mask = CWBackPixel | CWBorderPixel | CWColormap | CWOverrideRedirect | CWEventMask;
 
     m_glWindow = XCreateWindow(m_dpy, RootWindow(m_dpy, vi->screen),
-                    0, 0, width, height, 0, vi->depth,
+                    out->x, out->y, width, height, 0, vi->depth,
                     InputOutput, vi->visual,
                     mask, &swa);
 
@@ -801,14 +840,19 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen)
     if (fullscreen)
     {
       int result = -1;
-      while (result != GrabSuccess)
+      while (result != GrabSuccess && result != AlreadyGrabbed)
       {
-        result = XGrabPointer(m_dpy, m_glWindow, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, m_glWindow, None, CurrentTime);
+        result = XGrabPointer(m_dpy, m_glWindow, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
         XbmcThreads::ThreadSleep(100);
       }
       XGrabKeyboard(m_dpy, m_glWindow, True, GrabModeAsync, GrabModeAsync, CurrentTime);
-
     }
+    CSingleLock lock(m_resourceSection);
+    // tell any shared resources
+    for (vector<IDispResource *>::iterator i = m_resources.begin(); i != m_resources.end(); i++)
+      (*i)->OnResetDevice();
+
+    m_windowDirty = false;
   }
   return true;
 }
diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h
index 93cf5db..71034fc 100644
--- a/xbmc/windowing/X11/WinSystemX11.h
+++ b/xbmc/windowing/X11/WinSystemX11.h
@@ -65,15 +65,16 @@ class CWinSystemX11 : public CWinSystemBase
   Display*  GetDisplay() { return m_dpy; }
   GLXWindow GetWindow() { return m_glWindow; }
   GLXContext GetGlxContext() { return m_glContext; }
-  void RefreshWindow();
   void NotifyXRREvent();
+  void GetConnectedOutputs(std::vector<CStdString> *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<IDispResource*>  m_resources;
   uint64_t                     m_dpyLostTime;
+  CStdString                   m_currentOutput;
+  bool                         m_windowDirty;
+  bool                         m_bIsInternalXrr;
 
 private:
   bool IsSuitableVisual(XVisualInfo *vInfo);
-- 
1.7.10


From a172c0820920629f6bbfc5c93b855d1495e09ec8 Mon Sep 17 00:00:00 2001
From: FernetMenta <fernetmenta@online.de>
Date: Thu, 5 Jul 2012 11:36:32 +0200
Subject: [PATCH 23/58] X11: remove all DefaultScreen and RootWindow macros

---
 xbmc/windowing/X11/WinSystemX11.cpp   |    6 +++---
 xbmc/windowing/X11/WinSystemX11.h     |    1 +
 xbmc/windowing/X11/WinSystemX11GL.cpp |    2 +-
 3 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp
index 5f913f1..af1307c 100644
--- a/xbmc/windowing/X11/WinSystemX11.cpp
+++ b/xbmc/windowing/X11/WinSystemX11.cpp
@@ -267,7 +267,7 @@ void CWinSystemX11::UpdateResolutions()
   else
 #endif
   {
-    int x11screen = DefaultScreen(m_dpy);
+    int x11screen = m_nScreen;
     int w = DisplayWidth(m_dpy, x11screen);
     int h = DisplayHeight(m_dpy, x11screen);
     UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, w, h, 0.0);
@@ -393,7 +393,7 @@ bool CWinSystemX11::RefreshGlxContext()
   XVisualInfo *visuals;
   XVisualInfo *vInfo      = NULL;
   int availableVisuals    = 0;
-  vMask.screen = DefaultScreen(m_dpy);
+  vMask.screen = m_nScreen;
   XWindowAttributes winAttr;
 
   /* Assume a depth of 24 in case the below calls to XGetWindowAttributes()
@@ -547,7 +547,7 @@ bool CWinSystemX11::Minimize()
     g_graphicsContext.ToggleFullScreenRoot();
   }
 
-  XIconifyWindow(m_dpy, m_glWindow, DefaultScreen(m_dpy));
+  XIconifyWindow(m_dpy, m_glWindow, m_nScreen);
 
   m_minimized = true;
   return true;
diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h
index 71034fc..3bb4b8e 100644
--- a/xbmc/windowing/X11/WinSystemX11.h
+++ b/xbmc/windowing/X11/WinSystemX11.h
@@ -47,6 +47,7 @@ class CWinSystemX11 : public CWinSystemBase
   virtual bool SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays);
   virtual void UpdateResolutions();
   virtual int  GetNumScreens() { return 1; }
+  virtual int  GetCurrentScreen() { return m_nScreen; }
   virtual void ShowOSMouse(bool show);
   virtual void ResetOSScreensaver();
   virtual bool EnableFrameLimiter();
diff --git a/xbmc/windowing/X11/WinSystemX11GL.cpp b/xbmc/windowing/X11/WinSystemX11GL.cpp
index f858f88..d192697 100644
--- a/xbmc/windowing/X11/WinSystemX11GL.cpp
+++ b/xbmc/windowing/X11/WinSystemX11GL.cpp
@@ -203,7 +203,7 @@ bool CWinSystemX11GL::CreateNewWindow(const CStdString& name, bool fullScreen, R
     return false;
 
   m_glxext  = " ";
-  m_glxext += (const char*)glXQueryExtensionsString(m_dpy, DefaultScreen(m_dpy));
+  m_glxext += (const char*)glXQueryExtensionsString(m_dpy, m_nScreen);
   m_glxext += " ";
 
   CLog::Log(LOGDEBUG, "GLX_EXTENSIONS:%s", m_glxext.c_str());
-- 
1.7.10


From 6b513d66eeea6d266e3d447012445b8598e39c72 Mon Sep 17 00:00:00 2001
From: FernetMenta <fernetmenta@online.de>
Date: Thu, 5 Jul 2012 11:45:22 +0200
Subject: [PATCH 24/58] X11: remove all DefaultScreen and RootWindow macros
 (VideoRefClock)

Note this is on a separate display connection.
---
 xbmc/video/VideoReferenceClock.cpp |   15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/xbmc/video/VideoReferenceClock.cpp b/xbmc/video/VideoReferenceClock.cpp
index 9785fe7..0004e07 100644
--- a/xbmc/video/VideoReferenceClock.cpp
+++ b/xbmc/video/VideoReferenceClock.cpp
@@ -270,7 +270,7 @@ bool CVideoReferenceClock::SetupGLX()
   }
 
   bool          ExtensionFound = false;
-  istringstream Extensions(glXQueryExtensionsString(m_Dpy, DefaultScreen(m_Dpy)));
+  istringstream Extensions(glXQueryExtensionsString(m_Dpy, g_Windowing.GetCurrentScreen()));
   string        ExtensionStr;
 
   while (!ExtensionFound)
@@ -297,7 +297,7 @@ bool CVideoReferenceClock::SetupGLX()
     m_bIsATI = true;
   }
 
-  m_vInfo = glXChooseVisual(m_Dpy, DefaultScreen(m_Dpy), singleBufferAttributes);
+  m_vInfo = glXChooseVisual(m_Dpy, g_Windowing.GetCurrentScreen(), singleBufferAttributes);
   if (!m_vInfo)
   {
     CLog::Log(LOGDEBUG, "CVideoReferenceClock: glXChooseVisual returned NULL");
@@ -308,15 +308,16 @@ bool CVideoReferenceClock::SetupGLX()
   {
     Swa.border_pixel = 0;
     Swa.event_mask = StructureNotifyMask;
-    Swa.colormap = XCreateColormap(m_Dpy, RootWindow(m_Dpy, m_vInfo->screen), m_vInfo->visual, AllocNone );
+    Swa.colormap = XCreateColormap(m_Dpy, g_Windowing.GetWindow(), m_vInfo->visual, AllocNone );
     SwaMask = CWBorderPixel | CWColormap | CWEventMask;
 
-    m_Window = XCreateWindow(m_Dpy, RootWindow(m_Dpy, m_vInfo->screen), 0, 0, 256, 256, 0,
+    m_Window = XCreateWindow(m_Dpy, g_Windowing.GetWindow(), 0, 0, 256, 256, 0,
                            m_vInfo->depth, InputOutput, m_vInfo->visual, SwaMask, &Swa);
   }
   else
   {
-    m_pixmap = XCreatePixmap(m_Dpy, DefaultRootWindow(m_Dpy), 256, 256, m_vInfo->depth);
+    Window window = g_Windowing.GetWindow();
+    m_pixmap = XCreatePixmap(m_Dpy, window, 256, 256, m_vInfo->depth);
     if (!m_pixmap)
     {
       CLog::Log(LOGDEBUG, "CVideoReferenceClock: unable to create pixmap");
@@ -383,7 +384,7 @@ bool CVideoReferenceClock::SetupGLX()
 
   //set up receiving of RandR events, we'll get one when the refreshrate changes
   XRRQueryExtension(m_Dpy, &m_RREventBase, &ReturnV);
-  XRRSelectInput(m_Dpy, RootWindow(m_Dpy, m_vInfo->screen), RRScreenChangeNotifyMask);
+  XRRSelectInput(m_Dpy, g_Windowing.GetWindow(), RRScreenChangeNotifyMask);
 
   UpdateRefreshrate(true); //forced refreshrate update
   m_MissedVblanks = 0;
@@ -518,7 +519,7 @@ int CVideoReferenceClock::GetRandRRate()
   int RefreshRate;
   XRRScreenConfiguration *CurrInfo;
 
-  CurrInfo = XRRGetScreenInfo(m_Dpy, RootWindow(m_Dpy, m_vInfo->screen));
+  CurrInfo = XRRGetScreenInfo(m_Dpy, g_Windowing.GetWindow());
   RefreshRate = XRRConfigCurrentRate(CurrInfo);
   XRRFreeScreenConfigInfo(CurrInfo);
 
-- 
1.7.10


From 85e142c39ee955350da2dd1d690677ad84c810ec Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Wed, 20 Jun 2012 17:37:11 +0200
Subject: [PATCH 25/58] X11: recreate gl context after output has changed

---
 xbmc/windowing/X11/WinSystemX11.cpp   |   24 ++++++++++++++----------
 xbmc/windowing/X11/WinSystemX11.h     |    1 +
 xbmc/windowing/X11/WinSystemX11GL.cpp |    9 +++++++++
 3 files changed, 24 insertions(+), 10 deletions(-)

diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp
index af1307c..d3d15e2 100644
--- a/xbmc/windowing/X11/WinSystemX11.cpp
+++ b/xbmc/windowing/X11/WinSystemX11.cpp
@@ -168,7 +168,6 @@ bool CWinSystemX11::ResizeWindow(int newWidth, int newHeight, int newLeft, int n
     return false;
   }
 
-  RefreshGlxContext();
   m_nWidth  = newWidth;
   m_nHeight = newHeight;
   m_bFullScreen = false;
@@ -219,14 +218,13 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl
     OnLostDevice();
     m_bIsInternalXrr = true;
     g_xrandr.SetMode(out, mode);
+    return true;
   }
 #endif
 
   if (!SetWindow(res.iWidth, res.iHeight, fullScreen, g_guiSettings.GetString("videoscreen.monitor")))
     return false;
 
-  RefreshGlxContext();
-
   m_nWidth      = res.iWidth;
   m_nHeight     = res.iHeight;
   m_bFullScreen = fullScreen;
@@ -381,11 +379,8 @@ bool CWinSystemX11::RefreshGlxContext()
   if (m_glContext)
   {
     CLog::Log(LOGDEBUG, "CWinSystemX11::RefreshGlxContext: refreshing context");
-    glFinish();
     glXMakeCurrent(m_dpy, None, NULL);
     glXMakeCurrent(m_dpy, m_glWindow, m_glContext);
-    XSync(m_dpy, FALSE);
-    g_Windowing.ResetVSync();
     return true;
   }
 
@@ -445,14 +440,14 @@ bool CWinSystemX11::RefreshGlxContext()
     {
       glXMakeCurrent(m_dpy, None, NULL);
       glXDestroyContext(m_dpy, m_glContext);
+      XSync(m_dpy, FALSE);
+      m_newGlContext = true;
     }
 
     if ((m_glContext = glXCreateContext(m_dpy, vInfo, NULL, True)))
     {
       // make this context current
       glXMakeCurrent(m_dpy, m_glWindow, m_glContext);
-      g_Windowing.ResetVSync();
-      XSync(m_dpy, False);
       retVal = true;
     }
     else
@@ -729,6 +724,7 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd
     }
     OnLostDevice();
     DestroyWindow();
+    m_windowDirty = true;
   }
 
   // create main window
@@ -847,13 +843,21 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd
       }
       XGrabKeyboard(m_dpy, m_glWindow, True, GrabModeAsync, GrabModeAsync, CurrentTime);
     }
+
+    CDirtyRegionList dr;
+    RefreshGlxContext();
+    XSync(m_dpy, FALSE);
+    g_graphicsContext.Clear(0);
+    g_graphicsContext.Flip(dr);
+    g_Windowing.ResetVSync();
+    m_windowDirty = false;
+
     CSingleLock lock(m_resourceSection);
     // tell any shared resources
     for (vector<IDispResource *>::iterator i = m_resources.begin(); i != m_resources.end(); i++)
       (*i)->OnResetDevice();
-
-    m_windowDirty = false;
   }
+
   return true;
 }
 
diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h
index 3bb4b8e..cc28f56 100644
--- a/xbmc/windowing/X11/WinSystemX11.h
+++ b/xbmc/windowing/X11/WinSystemX11.h
@@ -93,6 +93,7 @@ class CWinSystemX11 : public CWinSystemBase
   CStdString                   m_currentOutput;
   bool                         m_windowDirty;
   bool                         m_bIsInternalXrr;
+  bool                         m_newGlContext;
 
 private:
   bool IsSuitableVisual(XVisualInfo *vInfo);
diff --git a/xbmc/windowing/X11/WinSystemX11GL.cpp b/xbmc/windowing/X11/WinSystemX11GL.cpp
index d192697..0f2d1d2 100644
--- a/xbmc/windowing/X11/WinSystemX11GL.cpp
+++ b/xbmc/windowing/X11/WinSystemX11GL.cpp
@@ -23,6 +23,7 @@
 
 #include "WinSystemX11GL.h"
 #include "utils/log.h"
+#include "Application.h"
 
 CWinSystemX11GL::CWinSystemX11GL()
 {
@@ -245,17 +246,25 @@ bool CWinSystemX11GL::CreateNewWindow(const CStdString& name, bool fullScreen, R
 
 bool CWinSystemX11GL::ResizeWindow(int newWidth, int newHeight, int newLeft, int newTop)
 {
+  m_newGlContext = false;
   CWinSystemX11::ResizeWindow(newWidth, newHeight, newLeft, newTop);
   CRenderSystemGL::ResetRenderSystem(newWidth, newHeight, false, 0);
 
+  if (m_newGlContext)
+    g_application.ReloadSkin();
+
   return true;
 }
 
 bool CWinSystemX11GL::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays)
 {
+  m_newGlContext = false;
   CWinSystemX11::SetFullScreen(fullScreen, res, blankOtherDisplays);
   CRenderSystemGL::ResetRenderSystem(res.iWidth, res.iHeight, fullScreen, res.fRefreshRate);
 
+  if (m_newGlContext)
+    g_application.ReloadSkin();
+
   return true;
 }
 
-- 
1.7.10


From e93c757a4f7a982af81f5e647e6e246d330fd5ec Mon Sep 17 00:00:00 2001
From: FernetMenta <fernetmenta@online.de>
Date: Thu, 5 Jul 2012 12:06:25 +0200
Subject: [PATCH 26/58] X11: hook video reference clock in windowing

---
 xbmc/video/VideoReferenceClock.cpp |   71 ++++++++++++++++++++++++++----------
 xbmc/video/VideoReferenceClock.h   |   13 ++++++-
 2 files changed, 63 insertions(+), 21 deletions(-)

diff --git a/xbmc/video/VideoReferenceClock.cpp b/xbmc/video/VideoReferenceClock.cpp
index 0004e07..fa8e35a 100644
--- a/xbmc/video/VideoReferenceClock.cpp
+++ b/xbmc/video/VideoReferenceClock.cpp
@@ -135,12 +135,23 @@
   m_Context = NULL;
   m_pixmap = None;
   m_glPixmap = None;
-  m_RREventBase = 0;
   m_UseNvSettings = true;
   m_bIsATI = false;
 #endif
 }
 
+CVideoReferenceClock::~CVideoReferenceClock()
+{
+#if defined(HAS_GLX)
+  // some ATI voodoo, if we don't close the display, we crash on exit
+  if (m_Dpy)
+  {
+    XCloseDisplay(m_Dpy);
+    m_Dpy = NULL;
+  }
+#endif
+}
+
 void CVideoReferenceClock::Process()
 {
   bool SetupSuccess = false;
@@ -151,6 +162,10 @@ void CVideoReferenceClock::Process()
   m_D3dCallback.Reset();
   g_Windowing.Register(&m_D3dCallback);
 #endif
+#if defined(HAS_GLX) && defined(HAS_XRANDR)
+  g_Windowing.Register(this);
+  m_xrrEvent = false;
+#endif
 
   while(!m_bStop)
   {
@@ -211,6 +226,16 @@ void CVideoReferenceClock::Process()
     //clean up the vblank clock
 #if defined(HAS_GLX) && defined(HAS_XRANDR)
     CleanupGLX();
+    if (m_xrrEvent)
+    {
+      m_releaseEvent.Set();
+      while (!m_bStop)
+      {
+        if (m_resetEvent.WaitMSec(100))
+          break;
+      }
+      m_xrrEvent = false;
+    }
 #elif defined(_WIN32) && defined(HAS_DX)
     CleanupD3D();
 #elif defined(TARGET_DARWIN)
@@ -222,6 +247,9 @@ void CVideoReferenceClock::Process()
 #if defined(_WIN32) && defined(HAS_DX)
   g_Windowing.Unregister(&m_D3dCallback);
 #endif
+#if defined(HAS_GLX)
+  g_Windowing.Unregister(this);
+#endif
 }
 
 bool CVideoReferenceClock::WaitStarted(int MSecs)
@@ -231,6 +259,24 @@ bool CVideoReferenceClock::WaitStarted(int MSecs)
 }
 
 #if defined(HAS_GLX) && defined(HAS_XRANDR)
+
+void CVideoReferenceClock::OnLostDevice()
+{
+  if (!m_xrrEvent)
+  {
+    m_releaseEvent.Reset();
+    m_resetEvent.Reset();
+    m_xrrEvent = true;
+    m_releaseEvent.Wait();
+  }
+}
+
+void CVideoReferenceClock::OnResetDevice()
+{
+  m_xrrEvent = false;
+  m_resetEvent.Set();
+}
+
 bool CVideoReferenceClock::SetupGLX()
 {
   int singleBufferAttributes[] = {
@@ -382,10 +428,6 @@ bool CVideoReferenceClock::SetupGLX()
     return false;
   }
 
-  //set up receiving of RandR events, we'll get one when the refreshrate changes
-  XRRQueryExtension(m_Dpy, &m_RREventBase, &ReturnV);
-  XRRSelectInput(m_Dpy, g_Windowing.GetWindow(), RRScreenChangeNotifyMask);
-
   UpdateRefreshrate(true); //forced refreshrate update
   m_MissedVblanks = 0;
 
@@ -586,6 +628,9 @@ void CVideoReferenceClock::RunGLX()
 
   while(!m_bStop)
   {
+    if (m_xrrEvent)
+      return;
+
     //wait for the next vblank
     if (!m_bIsATI)
     {
@@ -649,7 +694,6 @@ void CVideoReferenceClock::RunGLX()
       UpdateClock((int)(VblankCount - PrevVblankCount), true);
       SingleLock.Leave();
       SendVblankSignal();
-      UpdateRefreshrate();
       IsReset = false;
     }
     else if (!m_bStop)
@@ -1186,23 +1230,10 @@ bool CVideoReferenceClock::UpdateRefreshrate(bool Forced /*= false*/)
 
 #if defined(HAS_GLX) && defined(HAS_XRANDR)
 
-  //check for RandR events
-  bool   GotEvent = Forced || m_RefreshChanged == 2;
-  XEvent Event;
-  while (XCheckTypedEvent(m_Dpy, m_RREventBase + RRScreenChangeNotify, &Event))
-  {
-    if (Event.type == m_RREventBase + RRScreenChangeNotify)
-    {
-      CLog::Log(LOGDEBUG, "CVideoReferenceClock: Received RandR event %i", Event.type);
-      GotEvent = true;
-    }
-    XRRUpdateConfiguration(&Event);
-  }
-
   if (!Forced)
     m_RefreshChanged = 0;
 
-  if (!GotEvent) //refreshrate did not change
+  if (!Forced) //refreshrate did not change
     return false;
 
   //the refreshrate can be wrong on nvidia drivers, so read it from nvidia-settings when it's available
diff --git a/xbmc/video/VideoReferenceClock.h b/xbmc/video/VideoReferenceClock.h
index dcc4f09..7eb6317 100644
--- a/xbmc/video/VideoReferenceClock.h
+++ b/xbmc/video/VideoReferenceClock.h
@@ -30,6 +30,7 @@
   #include <X11/X.h>
   #include <X11/Xlib.h>
   #include <GL/glx.h>
+  #include "guilib/DispResource.h"
 #elif defined(_WIN32) && defined(HAS_DX)
   #include <d3d9.h>
   #include "guilib/D3DResource.h"
@@ -56,9 +57,13 @@ class CD3DCallback : public ID3DResource
 #endif
 
 class CVideoReferenceClock : public CThread
+#if defined(HAS_GLX) && defined(HAS_XRANDR)
+                            ,public IDispResource
+#endif
 {
   public:
     CVideoReferenceClock();
+    virtual ~CVideoReferenceClock();
 
     int64_t GetTime(bool interpolated = true);
     int64_t GetFrequency();
@@ -75,6 +80,11 @@ class CVideoReferenceClock : public CThread
     void VblankHandler(int64_t nowtime, double fps);
 #endif
 
+#if defined(HAS_GLX) && defined(HAS_XRANDR)
+    virtual void OnLostDevice();
+    virtual void OnResetDevice();
+#endif
+
   private:
     void    Process();
     bool    UpdateRefreshrate(bool Forced = false);
@@ -121,7 +131,8 @@ class CVideoReferenceClock : public CThread
     GLXContext   m_Context;
     Pixmap       m_pixmap;
     GLXPixmap    m_glPixmap;
-    int          m_RREventBase;
+    bool         m_xrrEvent;
+    CEvent       m_releaseEvent, m_resetEvent;
 
     bool         m_UseNvSettings;
     bool         m_bIsATI;
-- 
1.7.10


From 514b28d959f14ca495e76f1e8b2f0f5cd55082ce Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Thu, 21 Jun 2012 17:26:51 +0200
Subject: [PATCH 27/58] 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 cffa478..1f24d4f 100644
--- a/xbmc/settings/Settings.cpp
+++ b/xbmc/settings/Settings.cpp
@@ -55,6 +55,7 @@
 #include "filesystem/File.h"
 #include "filesystem/DirectoryCache.h"
 #include "DatabaseManager.h"
+#include "windowing/WindowingFactory.h"
 
 using namespace std;
 using namespace XFILE;
diff --git a/xbmc/windowing/WinSystem.h b/xbmc/windowing/WinSystem.h
index 05c5eda..852d085 100644
--- a/xbmc/windowing/WinSystem.h
+++ b/xbmc/windowing/WinSystem.h
@@ -100,6 +100,7 @@ class CWinSystemBase
   std::vector<RESOLUTION_WHR> ScreenResolutions(int screen);
   std::vector<REFRESHRATE> RefreshRates(int screen, int width, int height, uint32_t dwFlags);
   REFRESHRATE DefaultRefreshRate(int screen, std::vector<REFRESHRATE> rates);
+  virtual bool HasCalibration(const RESOLUTION_INFO &resInfo) { return true; };
 
 protected:
   void UpdateDesktopResolution(RESOLUTION_INFO& newRes, int screen, int width, int height, float refreshRate, uint32_t dwFlags = 0);
diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp
index d3d15e2..487b324 100644
--- a/xbmc/windowing/X11/WinSystemX11.cpp
+++ b/xbmc/windowing/X11/WinSystemX11.cpp
@@ -320,7 +320,7 @@ void CWinSystemX11::UpdateResolutions()
       res.strMode.Format("%s: %s @ %.2fHz", out->name.c_str(), mode.name.c_str(), mode.hz);
       res.strOutput    = out->name;
       res.strId        = mode.id;
-      res.iSubtitles   = (int)(0.95*mode.h);
+      res.iSubtitles   = (int)(0.965*mode.h);
       res.fRefreshRate = mode.hz;
       res.bFullScreen  = true;
 
@@ -333,8 +333,42 @@ void CWinSystemX11::UpdateResolutions()
       g_settings.m_ResInfo.push_back(res);
     }
   }
+  g_settings.ApplyCalibrations();
 #endif
+}
+
+bool CWinSystemX11::HasCalibration(const RESOLUTION_INFO &resInfo)
+{
+  XOutput *out = g_xrandr.GetOutput(m_currentOutput);
+
+  // keep calibrations done on a not connected output
+  if (!out->name.Equals(resInfo.strOutput))
+    return true;
+
+  // keep calibrations not updated with resolution data
+  if (resInfo.iWidth == 0)
+    return true;
+
+  float fPixRatio;
+  if (resInfo.iHeight>0 && resInfo.iWidth>0 && out->hmm>0 && out->wmm>0)
+    fPixRatio = ((float)out->wmm/(float)resInfo.iWidth) / (((float)out->hmm/(float)resInfo.iHeight));
+  else
+    fPixRatio = 1.0f;
 
+  if (resInfo.Overscan.left != 0)
+    return true;
+  if (resInfo.Overscan.top != 0)
+    return true;
+  if (resInfo.Overscan.right != resInfo.iWidth)
+    return true;
+  if (resInfo.Overscan.bottom != resInfo.iHeight)
+    return true;
+  if (resInfo.fPixelRatio != fPixRatio)
+    return true;
+  if (resInfo.iSubtitles != (int)(0.965*resInfo.iHeight))
+    return true;
+
+  return false;
 }
 
 void CWinSystemX11::GetConnectedOutputs(std::vector<CStdString> *outputs)
diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h
index cc28f56..c046c86 100644
--- a/xbmc/windowing/X11/WinSystemX11.h
+++ b/xbmc/windowing/X11/WinSystemX11.h
@@ -61,6 +61,7 @@ class CWinSystemX11 : public CWinSystemBase
   virtual bool Show(bool raise = true);
   virtual void Register(IDispResource *resource);
   virtual void Unregister(IDispResource *resource);
+  virtual bool HasCalibration(const RESOLUTION_INFO &resInfo);
 
   // Local to WinSystemX11 only
   Display*  GetDisplay() { return m_dpy; }
-- 
1.7.10


From a9c1e53503d51463f731763cb4eaa58a4dc7d83d Mon Sep 17 00:00:00 2001
From: FernetMenta <fernetmenta@online.de>
Date: Thu, 5 Jul 2012 12:00:26 +0200
Subject: [PATCH 28/58] X11: deactivate screen saver on startup

---
 xbmc/windowing/X11/WinSystemX11.cpp |   29 +++++++++++++++++++++++++++++
 xbmc/windowing/X11/WinSystemX11.h   |    1 +
 2 files changed, 30 insertions(+)

diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp
index 487b324..b3e7ab5 100644
--- a/xbmc/windowing/X11/WinSystemX11.cpp
+++ b/xbmc/windowing/X11/WinSystemX11.cpp
@@ -521,6 +521,33 @@ void CWinSystemX11::ResetOSScreensaver()
   }
 }
 
+void CWinSystemX11::EnableSystemScreenSaver(bool bEnable)
+{
+  if (!m_dpy)
+    return;
+
+  if (bEnable)
+    XForceScreenSaver(m_dpy, ScreenSaverActive);
+  else
+  {
+    Window root_return, child_return;
+    int root_x_return, root_y_return;
+    int win_x_return, win_y_return;
+    unsigned int mask_return;
+    bool isInWin = XQueryPointer(m_dpy, RootWindow(m_dpy, m_nScreen), &root_return, &child_return,
+                                 &root_x_return, &root_y_return,
+                                 &win_x_return, &win_y_return,
+                                 &mask_return);
+
+    XWarpPointer(m_dpy, None, RootWindow(m_dpy, m_nScreen), 0, 0, 0, 0, root_x_return+300, root_y_return+300);
+    XSync(m_dpy, FALSE);
+    XWarpPointer(m_dpy, None, RootWindow(m_dpy, m_nScreen), 0, 0, 0, 0, 0, 0);
+    XSync(m_dpy, FALSE);
+    XWarpPointer(m_dpy, None, RootWindow(m_dpy, m_nScreen), 0, 0, 0, 0, root_x_return, root_y_return);
+    XSync(m_dpy, FALSE);
+  }
+}
+
 void CWinSystemX11::NotifyAppActiveChange(bool bActivated)
 {
   if (bActivated && m_bWasFullScreenBeforeMinimize && !m_bFullScreen)
@@ -764,6 +791,8 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd
   // create main window
   if (!m_glWindow)
   {
+    EnableSystemScreenSaver(false);
+
     GLint att[] =
     {
       GLX_RGBA,
diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h
index c046c86..e953d2d 100644
--- a/xbmc/windowing/X11/WinSystemX11.h
+++ b/xbmc/windowing/X11/WinSystemX11.h
@@ -51,6 +51,7 @@ class CWinSystemX11 : public CWinSystemBase
   virtual void ShowOSMouse(bool show);
   virtual void ResetOSScreensaver();
   virtual bool EnableFrameLimiter();
+  virtual void EnableSystemScreenSaver(bool bEnable);
 
   virtual void NotifyAppActiveChange(bool bActivated);
   virtual void NotifyAppFocusChange(bool bGaining);
-- 
1.7.10


From a2f6f8c51f7a0bf58c9f42536b14880a5592a016 Mon Sep 17 00:00:00 2001
From: FernetMenta <fernetmenta@online.de>
Date: Thu, 5 Jul 2012 12:10:09 +0200
Subject: [PATCH 29/58] X11: change method of going full-screen

---
 xbmc/windowing/X11/WinSystemX11.cpp |    9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp
index b3e7ab5..91f92c1 100644
--- a/xbmc/windowing/X11/WinSystemX11.cpp
+++ b/xbmc/windowing/X11/WinSystemX11.cpp
@@ -34,6 +34,7 @@
 #include "utils/TimeUtils.h"
 #include "settings/GUISettings.h"
 #include "windowing/WindowingFactory.h"
+#include <X11/Xatom.h>
 
 #if defined(HAS_XRANDR)
 #include <X11/extensions/Xrandr.h>
@@ -816,7 +817,7 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd
     cmap = XCreateColormap(m_dpy, RootWindow(m_dpy, vi->screen), vi->visual, AllocNone);
 
     int def_vis = (vi->visual == DefaultVisual(m_dpy, vi->screen));
-    swa.override_redirect = fullscreen ? True : False;
+    swa.override_redirect = False;
     swa.border_pixel = fullscreen ? 0 : 5;
     swa.background_pixel = def_vis ? BlackPixel(m_dpy, vi->screen) : 0;
     swa.colormap = cmap;
@@ -832,6 +833,12 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd
                     InputOutput, vi->visual,
                     mask, &swa);
 
+    if (fullscreen)
+    {
+      Atom fs = XInternAtom(m_dpy, "_NET_WM_STATE_FULLSCREEN", True);
+      XChangeProperty(m_dpy, m_glWindow, XInternAtom(m_dpy, "_NET_WM_STATE", True), XA_ATOM, 32, PropModeReplace, (unsigned char *) &fs, 1);
+    }
+
     // define invisible cursor
     Pixmap bitmapNoData;
     XColor black;
-- 
1.7.10


From 32561409b440dec1ad2aa0542b32b3c687512045 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Thu, 28 Jun 2012 19:12:39 +0200
Subject: [PATCH 30/58] X11: reset key repeat and key modifier on focus lost
 and gain

---
 xbmc/windowing/WinEventsX11.cpp |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp
index 6c22358..d86205d 100644
--- a/xbmc/windowing/WinEventsX11.cpp
+++ b/xbmc/windowing/WinEventsX11.cpp
@@ -359,6 +359,8 @@ bool CWinEventsX11::MessagePump()
         if (WinEvents->m_xic)
           XSetICFocus(WinEvents->m_xic);
         g_application.m_AppFocused = true;
+        memset(&(WinEvents->m_lastKey), 0, sizeof(XBMC_Event));
+        WinEvents->m_keymodState = 0;
         if (serial == xevent.xfocus.serial)
           break;
         g_Windowing.NotifyAppFocusChange(g_application.m_AppFocused);
@@ -370,6 +372,7 @@ bool CWinEventsX11::MessagePump()
         if (WinEvents->m_xic)
           XUnsetICFocus(WinEvents->m_xic);
         g_application.m_AppFocused = false;
+        memset(&(WinEvents->m_lastKey), 0, sizeof(XBMC_Event));
         g_Windowing.NotifyAppFocusChange(g_application.m_AppFocused);
         serial = xevent.xfocus.serial;
         break;
-- 
1.7.10


From c89ca3e1e69fce896d866d1c92bc5626baae8406 Mon Sep 17 00:00:00 2001
From: Joakim Plate <elupus@xbmc.org>
Date: Thu, 5 Jul 2012 14:18:46 +0200
Subject: [PATCH 31/58] X11: replace custom utf8 to unicode with charset
 convertor (squash to x11 events)

---
 xbmc/windowing/WinEventsX11.cpp |  119 ++++-----------------------------------
 xbmc/windowing/WinEventsX11.h   |    2 -
 2 files changed, 11 insertions(+), 110 deletions(-)

diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp
index d86205d..76702e6 100644
--- a/xbmc/windowing/WinEventsX11.cpp
+++ b/xbmc/windowing/WinEventsX11.cpp
@@ -32,6 +32,7 @@
 #include "X11/keysymdef.h"
 #include "X11/XF86keysym.h"
 #include "utils/log.h"
+#include "utils/CharsetConverter.h"
 #include "guilib/GUIWindowManager.h"
 #include "input/MouseStat.h"
 
@@ -161,7 +162,6 @@
   m_display = 0;
   m_window = 0;
   m_keybuf = 0;
-  m_utf16buf = 0;
 }
 
 CWinEventsX11::~CWinEventsX11()
@@ -172,12 +172,6 @@
     m_keybuf = 0;
   }
 
-  if (m_utf16buf)
-  {
-    free(m_utf16buf);
-    m_utf16buf = 0;
-  }
-
   if (m_xic)
   {
     XUnsetICFocus(m_xic);
@@ -203,7 +197,6 @@ bool CWinEventsX11::Init(Display *dpy, Window win)
   WinEvents->m_display = dpy;
   WinEvents->m_window = win;
   WinEvents->m_keybuf = (char*)malloc(32*sizeof(char));
-  WinEvents->m_utf16buf = (uint16_t*)malloc(32*sizeof(uint16_t));
   WinEvents->m_keymodState = 0;
   WinEvents->m_wmDeleteMessage = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
   WinEvents->m_structureChanged = false;
@@ -433,8 +426,6 @@ bool CWinEventsX11::MessagePump()
         }
 
         Status status;
-        int utf16size;
-        int utf16length;
         int len;
         len = Xutf8LookupString(WinEvents->m_xic, &xevent.xkey,
                                 WinEvents->m_keybuf, sizeof(WinEvents->m_keybuf),
@@ -453,36 +444,29 @@ bool CWinEventsX11::MessagePump()
           case XLookupChars:
           case XLookupBoth:
           {
-            if (len == 0)
-              break;
-            utf16size = len * sizeof(uint16_t);
-            if (utf16size > sizeof(WinEvents->m_utf16buf))
-            {
-              WinEvents->m_utf16buf = (uint16_t *)realloc(WinEvents->m_utf16buf,utf16size);
-              if (WinEvents->m_utf16buf == NULL)
-              {
-                break;
-              }
-            }
-            utf16length = Utf8ToUnicode(WinEvents->m_keybuf, len, WinEvents->m_utf16buf, utf16size);
-            if (utf16length < 0)
+            CStdString   data(WinEvents->m_keybuf, len);
+            CStdStringW keys;
+            g_charsetConverter.utf8ToW(data, keys, false);
+
+            if (keys.length() == 0)
             {
               break;
             }
-            for (unsigned int i = 0; i < utf16length - 1; i++)
+
+            for (unsigned int i = 0; i < keys.length() - 1; i++)
             {
               newEvent.key.keysym.sym = XBMCK_UNKNOWN;
-              newEvent.key.keysym.unicode = WinEvents->m_utf16buf[i];
+              newEvent.key.keysym.unicode = keys[i];
               newEvent.key.state = xevent.xkey.state;
               newEvent.key.type = xevent.xkey.type;
               ret |= ProcessKey(newEvent, 500);
             }
-            if (utf16length > 0)
+            if (keys.length() > 0)
             {
               newEvent.key.keysym.scancode = xevent.xkey.keycode;
               xkeysym = XLookupKeysym(&xevent.xkey, 0);
               newEvent.key.keysym.sym = LookupXbmcKeySym(xkeysym);
-              newEvent.key.keysym.unicode = WinEvents->m_utf16buf[utf16length - 1];
+              newEvent.key.keysym.unicode = keys[keys.length() - 1];
               newEvent.key.state = xevent.xkey.state;
               newEvent.key.type = xevent.xkey.type;
 
@@ -743,87 +727,6 @@ bool CWinEventsX11::ProcessKeyRepeat()
   return false;
 }
 
-int CWinEventsX11::Utf8ToUnicode(const char *utf8, const int utf8Length, uint16_t *utf16, const int utf16MaxLength)
-{
-  // p moves over the output buffer.  max_ptr points to the next to the last slot of the buffer.
-  uint16_t *p = utf16;
-  uint16_t const *const maxPtr = utf16 + utf16MaxLength;
-
-  // end_of_input points to the last byte of input as opposed to the next to the last byte.
-  char const *const endOfInput = utf8 + utf8Length - 1;
-
-  while (utf8 <= endOfInput)
-  {
-    unsigned char const c = *utf8;
-    if (p >= maxPtr)
-    {
-      //No more output space.
-      return -1;
-    }
-    if (c < 0x80)
-    {
-      //One byte ASCII.
-      *p++ = c;
-      utf8 += 1;
-    }
-    else if (c < 0xC0)
-    {
-      // Follower byte without preceding leader bytes.
-      return -1;
-    }
-    // 11 bits
-    else if (c < 0xE0)
-    {
-      // Two byte sequence.  We need one follower byte.
-      if (endOfInput - utf8 < 1 || (((utf8[1] ^ 0x80)) & 0xC0))
-      {
-        return -1;
-      }
-      *p++ = (uint16_t)(((c & 0x1F) << 6) + (utf8[1] & 0x3F));
-      utf8 += 2;
-    }
-    // 16 bis
-    else if (c < 0xF0)
-    {
-      // Three byte sequence.  We need two follower byte.
-      if (endOfInput - utf8 < 2 || ((utf8[1] ^ 0x80) & 0xC0) || ((utf8[2] ^ 0x80) & 0xC0))
-      {
-        return -1;
-      }
-      *p++ = (uint16_t)(((c & 0xF) << 12) + ((utf8[1] & 0x3F) << 6) + (utf8[2] & 0x3F));
-      utf8 += 3;
-    }
-    // 21 bits
-    else if (c < 0xF8)
-    {
-      int plane;
-      // Four byte sequence.  We need three follower bytes.
-      if (endOfInput - utf8 < 3 || ((utf8[1] ^ 0x80) & 0xC0) ||
-          ((utf8[2] ^ 0x80) & 0xC0) || ((utf8[3] ^ 0x80) & 0xC0))
-      {
-        return -1;
-      }
-      uint32_t unicode = ((c & 0x7) << 18) + ((utf8[1] & 0x3F) << 12) +
-                          ((utf8[2] & 0x3F) << 6) + (utf8[3] & 0x3F);
-      utf8 += 4;
-      CLog::Log(LOGERROR, "CWinEventsX11::Utf8ToUnicode: 4 byte unicode not supported");
-    }
-    // 26 bits
-    else if (c < 0xFC)
-    {
-      CLog::Log(LOGERROR, "CWinEventsX11::Utf8ToUnicode: 4 byte unicode not supported");
-      utf8 += 5;
-    }
-    // 31 bit
-    else
-    {
-      CLog::Log(LOGERROR, "CWinEventsX11::Utf8ToUnicode: 4 byte unicode not supported");
-      utf8 += 6;
-    }
-  }
-  return p - utf16;
-}
-
 XBMCKey CWinEventsX11::LookupXbmcKeySym(KeySym keysym)
 {
   // try direct mapping first
diff --git a/xbmc/windowing/WinEventsX11.h b/xbmc/windowing/WinEventsX11.h
index 6100933..72955ad 100644
--- a/xbmc/windowing/WinEventsX11.h
+++ b/xbmc/windowing/WinEventsX11.h
@@ -38,7 +38,6 @@ class CWinEventsX11 : public CWinEventsBase
   static bool MessagePump();
 
 protected:
-  static int Utf8ToUnicode(const char *utf8, const int utf8Length, uint16_t *utf16, const int utf16MaxLength);
   static XBMCKey LookupXbmcKeySym(KeySym keysym);
   static bool ProcessKey(XBMC_Event &event, int repeatDelay);
   static bool ProcessKeyRepeat();
@@ -48,7 +47,6 @@ class CWinEventsX11 : public CWinEventsBase
   Window m_window;
   Atom m_wmDeleteMessage;
   char *m_keybuf;
-  uint16_t *m_utf16buf;
   XIM m_xim;
   XIC m_xic;
   XBMC_Event m_lastKey;
-- 
1.7.10


From f14ba6206ff8cdb5acd928528b78bfd0f3bcf9cd Mon Sep 17 00:00:00 2001
From: Joakim Plate <elupus@xbmc.org>
Date: Thu, 5 Jul 2012 14:23:54 +0200
Subject: [PATCH 32/58] X11: fixed invalid usage of sizeof() (squash into x11
 changes)

---
 xbmc/windowing/WinEventsX11.cpp |   11 +++++++----
 xbmc/windowing/WinEventsX11.h   |    1 +
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp
index 76702e6..c31877e 100644
--- a/xbmc/windowing/WinEventsX11.cpp
+++ b/xbmc/windowing/WinEventsX11.cpp
@@ -162,6 +162,7 @@
   m_display = 0;
   m_window = 0;
   m_keybuf = 0;
+  m_keybuf_len = 0;
 }
 
 CWinEventsX11::~CWinEventsX11()
@@ -196,7 +197,8 @@ bool CWinEventsX11::Init(Display *dpy, Window win)
   WinEvents = new CWinEventsX11();
   WinEvents->m_display = dpy;
   WinEvents->m_window = win;
-  WinEvents->m_keybuf = (char*)malloc(32*sizeof(char));
+  WinEvents->m_keybuf_len = 32*sizeof(char);
+  WinEvents->m_keybuf = (char*)malloc(WinEvents->m_keybuf_len);
   WinEvents->m_keymodState = 0;
   WinEvents->m_wmDeleteMessage = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
   WinEvents->m_structureChanged = false;
@@ -428,13 +430,14 @@ bool CWinEventsX11::MessagePump()
         Status status;
         int len;
         len = Xutf8LookupString(WinEvents->m_xic, &xevent.xkey,
-                                WinEvents->m_keybuf, sizeof(WinEvents->m_keybuf),
+                                WinEvents->m_keybuf, WinEvents->m_keybuf_len,
                                 &xkeysym, &status);
         if (status == XBufferOverflow)
         {
-          WinEvents->m_keybuf = (char*)realloc(WinEvents->m_keybuf, len*sizeof(char));
+          WinEvents->m_keybuf_len = len;
+          WinEvents->m_keybuf = (char*)realloc(WinEvents->m_keybuf, WinEvents->m_keybuf_len);
           len = Xutf8LookupString(WinEvents->m_xic, &xevent.xkey,
-                                  WinEvents->m_keybuf, sizeof(WinEvents->m_keybuf),
+                                  WinEvents->m_keybuf, WinEvents->m_keybuf_len,
                                   &xkeysym, &status);
         }
         switch (status)
diff --git a/xbmc/windowing/WinEventsX11.h b/xbmc/windowing/WinEventsX11.h
index 72955ad..102a076 100644
--- a/xbmc/windowing/WinEventsX11.h
+++ b/xbmc/windowing/WinEventsX11.h
@@ -47,6 +47,7 @@ class CWinEventsX11 : public CWinEventsBase
   Window m_window;
   Atom m_wmDeleteMessage;
   char *m_keybuf;
+  size_t m_keybuf_len;
   XIM m_xim;
   XIC m_xic;
   XBMC_Event m_lastKey;
-- 
1.7.10


From 70b39d59155703ea8f3f80b33e11298b5bbb8316 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Sat, 9 Jun 2012 18:23:53 +0200
Subject: [PATCH 33/58] 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 dbc28a7..0ab6e78 100644
--- a/xbmc/input/XBMC_keytable.cpp
+++ b/xbmc/input/XBMC_keytable.cpp
@@ -179,6 +179,8 @@
 , { XBMCK_LAUNCH_APP2,            0,    0, XBMCVK_LAUNCH_APP2,         "launch_app2_pc_icon" }
 , { XBMCK_LAUNCH_FILE_BROWSER,    0,    0, XBMCVK_LAUNCH_FILE_BROWSER, "launch_file_browser" }
 , { XBMCK_LAUNCH_MEDIA_CENTER,    0,    0, XBMCVK_LAUNCH_MEDIA_CENTER, "launch_media_center" }
+, { XBMCK_PLAY,                   0,    0, XBMCVK_MEDIA_PLAY_PAUSE,    "play_pause" }
+, { XBMCK_STOP,                   0,    0, XBMCVK_MEDIA_STOP,          "stop" }
 
 // Function keys
 , { XBMCK_F1,                     0,    0, XBMCVK_F1,            "f1"}
-- 
1.7.10


From 2cac8b3da3061ea9847e475aa50030a882f09e63 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Fri, 16 Mar 2012 15:57:51 +0100
Subject: [PATCH 34/58] videorefclock: temp deactivate of nv settings

---
 xbmc/video/VideoReferenceClock.cpp |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/xbmc/video/VideoReferenceClock.cpp b/xbmc/video/VideoReferenceClock.cpp
index fa8e35a..85e36c7 100644
--- a/xbmc/video/VideoReferenceClock.cpp
+++ b/xbmc/video/VideoReferenceClock.cpp
@@ -135,7 +135,7 @@
   m_Context = NULL;
   m_pixmap = None;
   m_glPixmap = None;
-  m_UseNvSettings = true;
+  m_UseNvSettings = false;
   m_bIsATI = false;
 #endif
 }
-- 
1.7.10


From 2541e950b628baf5cbee4e73a022c8d2d9b66481 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Mon, 20 Aug 2012 09:09:09 +0200
Subject: [PATCH 35/58] videorefclock: ask graphics context for refresh rate

---
 xbmc/video/VideoReferenceClock.cpp |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/xbmc/video/VideoReferenceClock.cpp b/xbmc/video/VideoReferenceClock.cpp
index 85e36c7..8209163 100644
--- a/xbmc/video/VideoReferenceClock.cpp
+++ b/xbmc/video/VideoReferenceClock.cpp
@@ -30,6 +30,7 @@
   #include <sstream>
   #include <X11/extensions/Xrandr.h>
   #include "windowing/WindowingFactory.h"
+  #include "guilib/GraphicContext.h"
   #define NVSETTINGSCMD "nvidia-settings -nt -q RefreshRate3"
 #elif defined(TARGET_DARWIN_OSX)
   #include <QuartzCore/CVDisplayLink.h>
@@ -1254,7 +1255,7 @@ bool CVideoReferenceClock::UpdateRefreshrate(bool Forced /*= false*/)
   }
 
   CSingleLock SingleLock(m_CritSection);
-  m_RefreshRate = GetRandRRate();
+  m_RefreshRate = MathUtils::round_int(g_graphicsContext.GetFPS());
 
   CLog::Log(LOGDEBUG, "CVideoReferenceClock: Detected refreshrate: %i hertz", (int)m_RefreshRate);
 
-- 
1.7.10


From d41b611cce7bbbdbe4e267ea773e0293b7339607 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Mon, 9 Jul 2012 14:00:18 +0200
Subject: [PATCH 36/58] X11: fix icon texture after
 cc5ed3c2474084ebc0373a3046410e6f766e03f4

---
 xbmc/windowing/X11/WinSystemX11.cpp |   43 +++++++++++++++++++++--------------
 1 file changed, 26 insertions(+), 17 deletions(-)

diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp
index 91f92c1..174ccef 100644
--- a/xbmc/windowing/X11/WinSystemX11.cpp
+++ b/xbmc/windowing/X11/WinSystemX11.cpp
@@ -874,22 +874,24 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd
     if (!fullscreen)
     {
       CreateIconPixmap();
-      XWMHints wm_hints;
-      XClassHint class_hints;
+      XWMHints *wm_hints;
       XTextProperty windowName, iconName;
       std::string titleString = "XBMC Media Center";
       char *title = (char*)titleString.c_str();
 
       XStringListToTextProperty(&title, 1, &windowName);
       XStringListToTextProperty(&title, 1, &iconName);
-      wm_hints.initial_state = NormalState;
-      wm_hints.input = True;
-      wm_hints.icon_pixmap = m_icon;
-      wm_hints.flags = StateHint | IconPixmapHint | InputHint;
 
+      wm_hints = XAllocWMHints();
+      wm_hints->initial_state = NormalState;
+      wm_hints->icon_pixmap = m_icon;
+      wm_hints->flags = StateHint | IconPixmapHint;
+
+      XSync(m_dpy,False);
       XSetWMProperties(m_dpy, m_glWindow, &windowName, &iconName,
-                            NULL, 0, NULL, &wm_hints,
+                            NULL, 0, NULL, wm_hints,
                             NULL);
+      XFree(wm_hints);
 
       // register interest in the delete window message
       Atom wmDeleteMessage = XInternAtom(m_dpy, "WM_DELETE_WINDOW", False);
@@ -974,16 +976,21 @@ bool CWinSystemX11::CreateIconPixmap()
   gRatio = vis->green_mask / 255.0;
   bRatio = vis->blue_mask / 255.0;
 
-  CTexture iconTexture;
-  iconTexture.LoadFromFile("special://xbmc/media/icon.png");
-  buf = iconTexture.GetPixels();
+  CBaseTexture *iconTexture = CBaseTexture::LoadFromFile("special://xbmc/media/icon.png");
+
+  if (!iconTexture)
+    return false;
 
-  numBufBytes = iconTexture.GetWidth() * iconTexture.GetHeight() * 4;
+  buf = iconTexture->GetPixels();
+
+  numBufBytes = iconTexture->GetWidth() * iconTexture->GetHeight() * 4;
+  int wid = iconTexture->GetWidth();
+  int hi = iconTexture->GetHeight();
 
   if (depth>=24)
-    numNewBufBytes = (4 * (iconTexture.GetWidth() * iconTexture.GetHeight()));
+    numNewBufBytes = (4 * (iconTexture->GetWidth() * iconTexture->GetHeight()));
   else
-    numNewBufBytes = (2 * (iconTexture.GetWidth() * iconTexture.GetHeight()));
+    numNewBufBytes = (2 * (iconTexture->GetWidth() * iconTexture->GetHeight()));
 
   newBuf = (uint32_t*)malloc(numNewBufBytes);
   if (!newBuf)
@@ -992,11 +999,11 @@ bool CWinSystemX11::CreateIconPixmap()
     return false;
   }
 
-  for (i=0; i<iconTexture.GetHeight();++i)
+  for (i=0; i<iconTexture->GetHeight();++i)
   {
-    for (j=0; j<iconTexture.GetWidth();++j)
+    for (j=0; j<iconTexture->GetWidth();++j)
     {
-      unsigned int pos = i*iconTexture.GetPitch()+j*4;
+      unsigned int pos = i*iconTexture->GetPitch()+j*4;
       unsigned int r, g, b;
       r = (buf[pos+2] * rRatio);
       g = (buf[pos+1] * gRatio);
@@ -1009,7 +1016,7 @@ bool CWinSystemX11::CreateIconPixmap()
     }
   }
   img = XCreateImage(m_dpy, vis, depth,ZPixmap, 0, (char *)newBuf,
-                     iconTexture.GetWidth(), iconTexture.GetHeight(),
+                     iconTexture->GetWidth(), iconTexture->GetHeight(),
                      (depth>=24)?32:16, 0);
   if (!img)
   {
@@ -1047,6 +1054,8 @@ bool CWinSystemX11::CreateIconPixmap()
   XFreeGC(m_dpy, gc);
   XDestroyImage(img); // this also frees newBuf
 
+  delete iconTexture;
+
   return true;
 }
 
-- 
1.7.10


From 9923666f9cf1f0fdabb4b2e0b104e30f0a9fab28 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Tue, 10 Jul 2012 11:14:12 +0200
Subject: [PATCH 37/58] X11: check for window manager

---
 xbmc/windowing/X11/WinSystemX11.cpp |   74 ++++++++++++++++++++++++++++++++++-
 xbmc/windowing/X11/WinSystemX11.h   |    1 +
 2 files changed, 73 insertions(+), 2 deletions(-)

diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp
index 174ccef..4f1ae26 100644
--- a/xbmc/windowing/X11/WinSystemX11.cpp
+++ b/xbmc/windowing/X11/WinSystemX11.cpp
@@ -816,8 +816,10 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd
     vi = glXChooseVisual(m_dpy, m_nScreen, att);
     cmap = XCreateColormap(m_dpy, RootWindow(m_dpy, vi->screen), vi->visual, AllocNone);
 
+    bool hasWM = HasWindowManager();
+
     int def_vis = (vi->visual == DefaultVisual(m_dpy, vi->screen));
-    swa.override_redirect = False;
+    swa.override_redirect = hasWM ? False : True;
     swa.border_pixel = fullscreen ? 0 : 5;
     swa.background_pixel = def_vis ? BlackPixel(m_dpy, vi->screen) : 0;
     swa.colormap = cmap;
@@ -833,7 +835,7 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd
                     InputOutput, vi->visual,
                     mask, &swa);
 
-    if (fullscreen)
+    if (fullscreen && hasWM)
     {
       Atom fs = XInternAtom(m_dpy, "_NET_WM_STATE_FULLSCREEN", True);
       XChangeProperty(m_dpy, m_glWindow, XInternAtom(m_dpy, "_NET_WM_STATE", True), XA_ATOM, 32, PropModeReplace, (unsigned char *) &fs, 1);
@@ -1059,4 +1061,72 @@ bool CWinSystemX11::CreateIconPixmap()
   return true;
 }
 
+bool CWinSystemX11::HasWindowManager()
+{
+  Window wm_check;
+  unsigned char *data;
+  int status, real_format;
+  Atom real_type, prop;
+  unsigned long items_read, items_left, i;
+  char req = 0;
+
+  prop = XInternAtom(m_dpy, "_NET_SUPPORTING_WM_CHECK", True);
+  if (prop == None)
+    return false;
+  status = XGetWindowProperty(m_dpy, DefaultRootWindow(m_dpy), prop,
+                      0L, 1L, False, XA_WINDOW, &real_type, &real_format,
+                      &items_read, &items_left, &data);
+  if(status != Success || ! items_read)
+  {
+    if(status == Success)
+      XFree(data);
+    return false;
+  }
+
+  wm_check = ((Window*)data)[0];
+  XFree(data);
+
+  status = XGetWindowProperty(m_dpy, wm_check, prop,
+                      0L, 1L, False, XA_WINDOW, &real_type, &real_format,
+                      &items_read, &items_left, &data);
+
+  if(status != Success || !items_read)
+  {
+    if(status == Success)
+      XFree(data);
+    return false;
+  }
+
+  if(wm_check != ((Window*)data)[0])
+  {
+    XFree(data);
+    return false;
+  }
+
+  XFree(data);
+
+  prop = XInternAtom(m_dpy, "_NET_WM_NAME", True);
+  if (prop == None)
+  {
+    CLog::Log(LOGDEBUG,"Window Manager Name: ");
+    return true;
+  }
+
+  status = XGetWindowProperty(m_dpy, wm_check, prop,
+                        0L, (~0L), False, AnyPropertyType, &real_type, &real_format,
+                        &items_read, &items_left, &data);
+
+  if(status == Success && items_read)
+  {
+    CLog::Log(LOGDEBUG,"Window Manager Name: %s", data);
+  }
+  else
+    CLog::Log(LOGDEBUG,"Window Manager Name: ");
+
+  if(status == Success)
+    XFree(data);
+
+  return true;
+}
+
 #endif
diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h
index e953d2d..0b7c10a 100644
--- a/xbmc/windowing/X11/WinSystemX11.h
+++ b/xbmc/windowing/X11/WinSystemX11.h
@@ -101,6 +101,7 @@ class CWinSystemX11 : public CWinSystemBase
   bool IsSuitableVisual(XVisualInfo *vInfo);
   static int XErrorHandler(Display* dpy, XErrorEvent* error);
   bool CreateIconPixmap();
+  bool HasWindowManager();
 
   CStopWatch m_screensaverReset;
 };
-- 
1.7.10


From 10cf8477872ce1e7f986c66dd2d187745653a9d1 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Thu, 12 Jul 2012 11:11:47 +0200
Subject: [PATCH 38/58] X11: dont set window on xrandr if no mode available

---
 xbmc/windowing/X11/WinSystemX11.cpp |   11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp
index 4f1ae26..c11ea89 100644
--- a/xbmc/windowing/X11/WinSystemX11.cpp
+++ b/xbmc/windowing/X11/WinSystemX11.cpp
@@ -665,16 +665,17 @@ void CWinSystemX11::NotifyXRREvent()
   CLog::Log(LOGDEBUG, "%s - notify display reset event", __FUNCTION__);
   m_windowDirty = true;
 
+  if (!g_xrandr.Query(true))
+  {
+    CLog::Log(LOGERROR, "WinSystemX11::RefreshWindow - failed to query xrandr");
+    return;
+  }
+
   // if external event update resolutions
   if (!m_bIsInternalXrr)
   {
     UpdateResolutions();
   }
-  else if (!g_xrandr.Query(true))
-  {
-    CLog::Log(LOGERROR, "WinSystemX11::RefreshWindow - failed to query xrandr");
-    return;
-  }
   m_bIsInternalXrr = false;
 
   CStdString currentOutput = g_guiSettings.GetString("videoscreen.monitor");
-- 
1.7.10


From 8eb784a2b8e9e949742645d94fabeff3194ac359 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Thu, 26 Jul 2012 09:34:28 +0200
Subject: [PATCH 39/58] X11: fix crash after a resolution change on startup

---
 xbmc/windowing/X11/WinSystemX11.cpp |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp
index c11ea89..0bd72d4 100644
--- a/xbmc/windowing/X11/WinSystemX11.cpp
+++ b/xbmc/windowing/X11/WinSystemX11.cpp
@@ -219,7 +219,8 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl
     OnLostDevice();
     m_bIsInternalXrr = true;
     g_xrandr.SetMode(out, mode);
-    return true;
+    if (m_glWindow)
+      return true;
   }
 #endif
 
-- 
1.7.10


From b727c8d69417726979856e6f1250fa04f1a57589 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Sat, 15 Sep 2012 18:27:29 +0200
Subject: [PATCH 40/58] X11: lock graphics context in NotifyXRREvent

---
 xbmc/windowing/X11/WinSystemX11.cpp |    2 ++
 1 file changed, 2 insertions(+)

diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp
index 0bd72d4..ef83133 100644
--- a/xbmc/windowing/X11/WinSystemX11.cpp
+++ b/xbmc/windowing/X11/WinSystemX11.cpp
@@ -666,6 +666,8 @@ void CWinSystemX11::NotifyXRREvent()
   CLog::Log(LOGDEBUG, "%s - notify display reset event", __FUNCTION__);
   m_windowDirty = true;
 
+  CSingleLock lock(g_graphicsContext);
+
   if (!g_xrandr.Query(true))
   {
     CLog::Log(LOGERROR, "WinSystemX11::RefreshWindow - failed to query xrandr");
-- 
1.7.10


From 7ed7ca37f86fb84ad867cf29e78e481bd8425c19 Mon Sep 17 00:00:00 2001
From: Rainer Hochecker <fernetmenta@online.de>
Date: Sat, 8 Oct 2011 16:45:13 +0200
Subject: [PATCH 41/58] ffmpeg: add xvba hwaccel

---
 lib/ffmpeg/configure                  |    8 ++
 lib/ffmpeg/libavcodec/Makefile        |    7 +-
 lib/ffmpeg/libavcodec/allcodecs.c     |    4 +
 lib/ffmpeg/libavcodec/h264.c          |    1 +
 lib/ffmpeg/libavcodec/mpegvideo.c     |    1 +
 lib/ffmpeg/libavcodec/xvba.c          |   66 ++++++++++++
 lib/ffmpeg/libavcodec/xvba.h          |   71 ++++++++++++
 lib/ffmpeg/libavcodec/xvba_h264.c     |  189 ++++++++++++++++++++++++++++++++
 lib/ffmpeg/libavcodec/xvba_internal.h |   24 +++++
 lib/ffmpeg/libavcodec/xvba_mpeg2.c    |   52 +++++++++
 lib/ffmpeg/libavcodec/xvba_vc1.c      |  190 +++++++++++++++++++++++++++++++++
 lib/ffmpeg/libavcodec/xvmc_internal.h |    4 +-
 lib/ffmpeg/libavutil/pixdesc.c        |    6 ++
 lib/ffmpeg/libavutil/pixfmt.h         |    1 +
 14 files changed, 622 insertions(+), 2 deletions(-)
 create mode 100644 lib/ffmpeg/libavcodec/xvba.c
 create mode 100644 lib/ffmpeg/libavcodec/xvba.h
 create mode 100644 lib/ffmpeg/libavcodec/xvba_h264.c
 create mode 100644 lib/ffmpeg/libavcodec/xvba_internal.h
 create mode 100644 lib/ffmpeg/libavcodec/xvba_mpeg2.c
 create mode 100644 lib/ffmpeg/libavcodec/xvba_vc1.c

diff --git a/lib/ffmpeg/configure b/lib/ffmpeg/configure
index c06005b..157cfd3 100755
--- a/lib/ffmpeg/configure
+++ b/lib/ffmpeg/configure
@@ -113,6 +113,7 @@ Configuration options:
   --enable-vdpau           enable VDPAU code [autodetect]
   --disable-dxva2          disable DXVA2 code
   --disable-vda            disable VDA code
+  --disable-xvba           disable XVBA code
   --enable-runtime-cpudetect detect cpu capabilities at runtime (bigger binary)
   --enable-hardcoded-tables use hardcoded tables instead of runtime generation
   --disable-safe-bitstream-reader
@@ -1084,6 +1085,7 @@ CONFIG_LIST="
     vaapi
     vda
     vdpau
+    xvba
     version3
     x11grab
     zlib
@@ -1423,6 +1425,7 @@ h264_dxva2_hwaccel_select="dxva2 h264_decoder"
 h264_vaapi_hwaccel_select="vaapi h264_decoder"
 h264_vda_hwaccel_deps="VideoDecodeAcceleration_VDADecoder_h pthreads"
 h264_vda_hwaccel_select="vda h264_decoder"
+h264_xvba_hwaccel_select="xvba h264_decoder"
 h264_vdpau_decoder_select="vdpau h264_decoder"
 imc_decoder_select="fft mdct sinewin"
 jpegls_decoder_select="golomb"
@@ -1459,6 +1462,7 @@ mpeg4_crystalhd_decoder_select="crystalhd"
 mpeg4_decoder_select="h263_decoder mpeg4video_parser"
 mpeg4_encoder_select="h263_encoder"
 mpeg4_vaapi_hwaccel_select="vaapi mpeg4_decoder"
+mpeg2_xvba_hwaccel_select="xvba mpeg2video_decoder"
 mpeg4_vdpau_decoder_select="vdpau mpeg4_decoder"
 msmpeg4_crystalhd_decoder_select="crystalhd"
 msmpeg4v1_decoder_select="h263_decoder"
@@ -1501,6 +1505,7 @@ vc1_decoder_select="h263_decoder h264chroma"
 vc1_dxva2_hwaccel_deps="dxva2api_h"
 vc1_dxva2_hwaccel_select="dxva2 vc1_decoder"
 vc1_vaapi_hwaccel_select="vaapi vc1_decoder"
+vc1_xvba_hwaccel_select="xvba vc1_decoder"
 vc1_vdpau_decoder_select="vdpau vc1_decoder"
 vc1image_decoder_select="vc1_decoder"
 vorbis_decoder_select="mdct"
@@ -1525,6 +1530,7 @@ wmv3_dxva2_hwaccel_select="vc1_dxva2_hwaccel"
 wmv3_vaapi_hwaccel_select="vc1_vaapi_hwaccel"
 wmv3_vdpau_decoder_select="vc1_vdpau_decoder"
 wmv3image_decoder_select="wmv3_decoder"
+wmv3_xvba_hwaccel_select="vc1_xvba_hwaccel"
 zlib_decoder_select="zlib"
 zlib_encoder_select="zlib"
 zmbv_decoder_select="zlib"
@@ -1533,6 +1539,7 @@ zmbv_encoder_select="zlib"
 crystalhd_deps="libcrystalhd_libcrystalhd_if_h"
 vaapi_deps="va_va_h"
 vda_deps="VideoDecodeAcceleration_VDADecoder_h pthreads"
+xvba_deps="amd_amdxvba_h"
 vdpau_deps="vdpau_vdpau_h vdpau_vdpau_x11_h"
 
 # parsers
@@ -3062,6 +3069,7 @@ check_header sys/select.h
 check_header termios.h
 check_header vdpau/vdpau.h
 check_header vdpau/vdpau_x11.h
+check_header amd/amdxvba.h
 check_cpp_condition vdpau/vdpau.h "defined(VDP_DECODER_PROFILE_MPEG4_PART2_SP)" && enable vdpau_mpeg4_support
 
 check_header X11/extensions/XvMClib.h
diff --git a/lib/ffmpeg/libavcodec/Makefile b/lib/ffmpeg/libavcodec/Makefile
index 972cc59..fc441bf 100644
--- a/lib/ffmpeg/libavcodec/Makefile
+++ b/lib/ffmpeg/libavcodec/Makefile
@@ -3,7 +3,7 @@ include $(SUBDIR)../config.mak
 NAME = avcodec
 FFLIBS = avutil
 
-HEADERS = avcodec.h avfft.h dxva2.h opt.h vaapi.h vda.h vdpau.h version.h xvmc.h
+HEADERS = avcodec.h avfft.h dxva2.h opt.h vaapi.h vda.h vdpau.h version.h xvmc.h xvba.h
 
 OBJS = allcodecs.o                                                      \
        audioconvert.o                                                   \
@@ -51,6 +51,7 @@ OBJS-$(CONFIG_SINEWIN)                 += sinewin.o
 OBJS-$(CONFIG_VAAPI)                   += vaapi.o
 OBJS-$(CONFIG_VDA)                     += vda.o
 OBJS-$(CONFIG_VDPAU)                   += vdpau.o
+OBJS-$(CONFIG_XVBA)                    += xvba.o
 
 # decoders/encoders/hardware accelerators
 OBJS-$(CONFIG_A64MULTI_ENCODER)        += a64multienc.o elbg.o
@@ -201,6 +202,7 @@ OBJS-$(CONFIG_H264_DECODER)            += h264.o                               \
 OBJS-$(CONFIG_H264_DXVA2_HWACCEL)      += dxva2_h264.o
 OBJS-$(CONFIG_H264_VAAPI_HWACCEL)      += vaapi_h264.o
 OBJS-$(CONFIG_H264_VDA_HWACCEL)        += vda_h264.o
+OBJS-$(CONFIG_H264_XVBA_HWACCEL)       += xvba_h264.o
 OBJS-$(CONFIG_HUFFYUV_DECODER)         += huffyuv.o
 OBJS-$(CONFIG_HUFFYUV_ENCODER)         += huffyuv.o
 OBJS-$(CONFIG_IDCIN_DECODER)           += idcinvideo.o
@@ -284,6 +286,7 @@ OBJS-$(CONFIG_MPEG1VIDEO_ENCODER)      += mpeg12enc.o mpegvideo_enc.o \
                                           mpegvideo.o error_resilience.o
 OBJS-$(CONFIG_MPEG2_DXVA2_HWACCEL)     += dxva2_mpeg2.o
 OBJS-$(CONFIG_MPEG2_VAAPI_HWACCEL)     += vaapi_mpeg2.o
+OBJS-$(CONFIG_MPEG2_XVBA_HWACCEL)      += xvba_mpeg2.o
 OBJS-$(CONFIG_MPEG2VIDEO_DECODER)      += mpeg12.o mpeg12data.o \
                                           mpegvideo.o error_resilience.o
 OBJS-$(CONFIG_MPEG2VIDEO_ENCODER)      += mpeg12enc.o mpegvideo_enc.o \
@@ -431,6 +434,7 @@ OBJS-$(CONFIG_VC1_DECODER)             += vc1dec.o vc1.o vc1data.o vc1dsp.o \
                                           intrax8.o intrax8dsp.o
 OBJS-$(CONFIG_VC1_DXVA2_HWACCEL)       += dxva2_vc1.o
 OBJS-$(CONFIG_VC1_VAAPI_HWACCEL)       += vaapi_vc1.o
+OBJS-$(CONFIG_VC1_XVBA_HWACCEL)        += xvba_vc1.o
 OBJS-$(CONFIG_VCR1_DECODER)            += vcr1.o
 OBJS-$(CONFIG_VCR1_ENCODER)            += vcr1.o
 OBJS-$(CONFIG_VMDAUDIO_DECODER)        += vmdav.o
@@ -732,6 +736,7 @@ SKIPHEADERS-$(CONFIG_LIBDIRAC)         += libdirac.h
 SKIPHEADERS-$(CONFIG_LIBSCHROEDINGER)  += libschroedinger.h
 SKIPHEADERS-$(CONFIG_VAAPI)            += vaapi_internal.h
 SKIPHEADERS-$(CONFIG_VDA)              += vda_internal.h
+SKIPHEADERS-$(CONFIG_XVBA)             += xvba_internal.h
 SKIPHEADERS-$(CONFIG_VDPAU)            += vdpau.h
 SKIPHEADERS-$(CONFIG_XVMC)             += xvmc.h
 SKIPHEADERS-$(HAVE_W32THREADS)         += w32pthreads.h
diff --git a/lib/ffmpeg/libavcodec/allcodecs.c b/lib/ffmpeg/libavcodec/allcodecs.c
index 32f3f52..0ff178e 100644
--- a/lib/ffmpeg/libavcodec/allcodecs.c
+++ b/lib/ffmpeg/libavcodec/allcodecs.c
@@ -59,14 +59,18 @@ void avcodec_register_all(void)
     REGISTER_HWACCEL (H264_VAAPI, h264_vaapi);
     REGISTER_HWACCEL (H264_VDA, h264_vda);
     REGISTER_HWACCEL (MPEG1_VDPAU, mpeg1_vdpau);
+    REGISTER_HWACCEL (H264_XVBA, h264_xvba);
     REGISTER_HWACCEL (MPEG2_DXVA2, mpeg2_dxva2);
     REGISTER_HWACCEL (MPEG2_VAAPI, mpeg2_vaapi);
     REGISTER_HWACCEL (MPEG2_VDPAU, mpeg2_vdpau);
     REGISTER_HWACCEL (MPEG4_VAAPI, mpeg4_vaapi);
+    REGISTER_HWACCEL (MPEG2_XVBA, mpeg2_xvba);
     REGISTER_HWACCEL (VC1_DXVA2, vc1_dxva2);
     REGISTER_HWACCEL (VC1_VAAPI, vc1_vaapi);
+    REGISTER_HWACCEL (VC1_XVBA, vc1_xvba);
     REGISTER_HWACCEL (WMV3_DXVA2, wmv3_dxva2);
     REGISTER_HWACCEL (WMV3_VAAPI, wmv3_vaapi);
+    REGISTER_HWACCEL (WMV3_XVBA, wmv3_xvba);
 
     /* video codecs */
     REGISTER_ENCODER (A64MULTI, a64multi);
diff --git a/lib/ffmpeg/libavcodec/h264.c b/lib/ffmpeg/libavcodec/h264.c
index c4785db..e9e7546 100644
--- a/lib/ffmpeg/libavcodec/h264.c
+++ b/lib/ffmpeg/libavcodec/h264.c
@@ -60,6 +60,7 @@
     PIX_FMT_DXVA2_VLD,
     PIX_FMT_VAAPI_VLD,
     PIX_FMT_VDA_VLD,
+    PIX_FMT_XVBA_VLD,
     PIX_FMT_YUVJ420P,
     PIX_FMT_NONE
 };
diff --git a/lib/ffmpeg/libavcodec/mpegvideo.c b/lib/ffmpeg/libavcodec/mpegvideo.c
index 04c149a..b22b631 100644
--- a/lib/ffmpeg/libavcodec/mpegvideo.c
+++ b/lib/ffmpeg/libavcodec/mpegvideo.c
@@ -136,6 +136,7 @@ static void dct_unquantize_h263_inter_c(MpegEncContext *s,
     PIX_FMT_DXVA2_VLD,
     PIX_FMT_VAAPI_VLD,
     PIX_FMT_VDA_VLD,
+    PIX_FMT_XVBA_VLD,
     PIX_FMT_YUV420P,
     PIX_FMT_NONE
 };
diff --git a/lib/ffmpeg/libavcodec/xvba.c b/lib/ffmpeg/libavcodec/xvba.c
new file mode 100644
index 0000000..be29e5d
--- /dev/null
+++ b/lib/ffmpeg/libavcodec/xvba.c
@@ -0,0 +1,66 @@
+/*
+ * HW decode acceleration for MPEG-2, H.264 and VC-1
+ *
+ * Copyright (C) 2005-2011 Team XBMC
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+/**
+ * \addtogroup XVBA_Decoding
+ *
+ * @{
+ */
+
+#include <stdint.h>
+#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 <stdint.h>
+#include <X11/Xlib.h>
+#include <amd/amdxvba.h>
+
+
+/**
+ * \defgroup XVBA_Decoding VA API Decoding
+ * \ingroup Decoder
+ * @{
+ */
+
+/** \brief The videoSurface is used for rendering. */
+#define FF_XVBA_STATE_USED_FOR_RENDER 1
+
+/**
+ * \brief The videoSurface is needed for reference/prediction.
+ * The codec manipulates this.
+ */
+#define FF_XVBA_STATE_USED_FOR_REFERENCE 2
+
+/**
+ * \brief The videoSurface holds a decoded frame.
+ * The codec manipulates this.
+ */
+#define FF_XVBA_STATE_DECODED 4
+
+/* @} */
+
+struct xvba_bitstream_buffers
+{
+  const void *buffer;
+  unsigned int size;
+};
+
+struct xvba_render_state {
+
+  int state; ///< Holds FF_XVBA_STATE_* values.
+  void *surface;
+  XVBAPictureDescriptor *picture_descriptor;
+  XVBAQuantMatrixAvc *iq_matrix;
+  unsigned int num_slices;
+  struct xvba_bitstream_buffers *buffers;
+  uint32_t buffers_alllocated;
+};
+
+#endif /* AVCODEC_XVBA_H */
diff --git a/lib/ffmpeg/libavcodec/xvba_h264.c b/lib/ffmpeg/libavcodec/xvba_h264.c
new file mode 100644
index 0000000..a077442
--- /dev/null
+++ b/lib/ffmpeg/libavcodec/xvba_h264.c
@@ -0,0 +1,189 @@
+/*
+ * H.264 HW decode acceleration through XVBA
+ *
+ * Copyright (C) 2005-2011 Team XBMC
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "xvba.h"
+#include "xvba_internal.h"
+#include "h264.h"
+#include <assert.h>
+
+/** @file
+ *  This file implements the glue code between FFmpeg's and XvBA API's
+ *  structures for H.264 decoding.
+ */
+
+
+/** Initialize and start decoding a frame with XVBA. */
+static int start_frame(AVCodecContext          *avctx,
+                       av_unused const uint8_t *buffer,
+                       av_unused uint32_t       size)
+{
+  H264Context * const h = avctx->priv_data;
+  MpegEncContext * const s = &h->s;
+  struct xvba_render_state *render;
+  XVBAPictureDescriptor *pic_descriptor;
+  int i;
+
+  render = (struct xvba_render_state *)s->current_picture_ptr->f.data[0];
+  assert(render);
+
+  if (render->picture_descriptor == 0)
+    return -1;
+
+  pic_descriptor = render->picture_descriptor;
+
+  for (i = 0; i < 2; ++i) {
+      int foc = s->current_picture_ptr->field_poc[i];
+      if (foc == INT_MAX)
+          foc = 0;
+      pic_descriptor->avc_curr_field_order_cnt_list[i] = foc;
+  }
+
+  pic_descriptor->avc_frame_num = h->frame_num;
+
+  render->num_slices = 0;
+
+  return 0;
+}
+
+/** End a hardware decoding based frame. */
+static int end_frame(AVCodecContext *avctx)
+{
+  H264Context * const h = avctx->priv_data;
+  MpegEncContext * const s = &h->s;
+  struct xvba_render_state *render;
+  XVBAPictureDescriptor *pic_descriptor;
+  XVBAQuantMatrixAvc *iq_matrix;
+
+  render = (struct xvba_render_state *)s->current_picture_ptr->f.data[0];
+  assert(render);
+
+  if (render->picture_descriptor == 0 || render->iq_matrix == 0)
+    return -1;
+
+  pic_descriptor = render->picture_descriptor;
+  iq_matrix = render->iq_matrix;
+
+  av_dlog(avctx, "end_frame()\n");
+
+  /* Fill in Picture Parameters*/
+  pic_descriptor->profile                                     = ff_xvba_translate_profile(avctx->profile);
+  pic_descriptor->level                                       = avctx->level;
+  pic_descriptor->width_in_mb                                 = s->mb_width;
+  pic_descriptor->height_in_mb                                = s->mb_height;
+  pic_descriptor->picture_structure                           = s->picture_structure;
+  pic_descriptor->chroma_format                               = s->chroma_format ? s->chroma_format : 1;
+  pic_descriptor->avc_intra_flag                              = (h->slice_type == AV_PICTURE_TYPE_I) ? 1 : 0;
+  pic_descriptor->avc_reference                               = (s->current_picture_ptr->f.reference & 3) ? 1 : 0;
+
+  pic_descriptor->avc_bit_depth_luma_minus8                   = h->sps.bit_depth_luma - 8;
+  pic_descriptor->avc_bit_depth_chroma_minus8                 = h->sps.bit_depth_chroma - 8;
+  pic_descriptor->avc_log2_max_frame_num_minus4               = h->sps.log2_max_frame_num -4;
+  pic_descriptor->avc_pic_order_cnt_type                      = h->sps.poc_type;
+  pic_descriptor->avc_log2_max_pic_order_cnt_lsb_minus4       = h->sps.log2_max_poc_lsb - 4;
+  pic_descriptor->avc_num_ref_frames                          = h->sps.ref_frame_count;
+  pic_descriptor->avc_reserved_8bit                           = 0;
+
+  /* Set correct level */
+  if (pic_descriptor->level == 41) {
+    const unsigned int mbw = pic_descriptor->width_in_mb;
+    const unsigned int mbh = pic_descriptor->height_in_mb;
+    const unsigned int max_ref_frames = 12288 * 1024 / (mbw * mbh * 384);
+    const unsigned int num_ref_frames = pic_descriptor->avc_num_ref_frames;
+    if (max_ref_frames < num_ref_frames)
+        pic_descriptor->level = 51;
+  }
+
+  pic_descriptor->avc_num_slice_groups_minus1                 = h->pps.slice_group_count - 1;
+  pic_descriptor->avc_num_ref_idx_l0_active_minus1            = h->pps.ref_count[0] - 1;
+  pic_descriptor->avc_num_ref_idx_l1_active_minus1            = h->pps.ref_count[1] - 1;
+
+  pic_descriptor->avc_pic_init_qp_minus26                     = h->pps.init_qp - 26;
+  pic_descriptor->avc_pic_init_qs_minus26                     = h->pps.init_qs - 26;
+  pic_descriptor->avc_chroma_qp_index_offset                  = h->pps.chroma_qp_index_offset[0];
+  pic_descriptor->avc_second_chroma_qp_index_offset           = h->pps.chroma_qp_index_offset[1];
+  pic_descriptor->avc_slice_group_change_rate_minus1          = 0; // not implemented in ffmpeg
+  pic_descriptor->avc_reserved_16bit                          = 0; // must be 0
+  memset(pic_descriptor->avc_field_order_cnt_list,0,sizeof(pic_descriptor->avc_field_order_cnt_list)); // must be 0
+  memset(pic_descriptor->avc_slice_group_map,0,sizeof(pic_descriptor->avc_slice_group_map)); // must be 0
+
+  // sps
+  pic_descriptor->sps_info.avc.delta_pic_always_zero_flag     = h->sps.delta_pic_order_always_zero_flag;
+  pic_descriptor->sps_info.avc.direct_8x8_inference_flag      = h->sps.direct_8x8_inference_flag;
+  pic_descriptor->sps_info.avc.frame_mbs_only_flag            = h->sps.frame_mbs_only_flag;
+  pic_descriptor->sps_info.avc.gaps_in_frame_num_value_allowed_flag = h->sps.gaps_in_frame_num_allowed_flag;
+  pic_descriptor->sps_info.avc.mb_adaptive_frame_field_flag   = h->sps.mb_aff;
+  pic_descriptor->sps_info.avc.residual_colour_transform_flag = h->sps.residual_color_transform_flag;
+  pic_descriptor->sps_info.avc.xvba_avc_sps_reserved          = 0;
+
+  // pps
+  pic_descriptor->pps_info.avc.entropy_coding_mode_flag       = h->pps.cabac;
+  pic_descriptor->pps_info.avc.pic_order_present_flag         = h->pps.pic_order_present;
+  pic_descriptor->pps_info.avc.weighted_pred_flag             = h->pps.weighted_pred;
+  pic_descriptor->pps_info.avc.weighted_bipred_idc            = h->pps.weighted_bipred_idc;
+  pic_descriptor->pps_info.avc.deblocking_filter_control_present_flag = h->pps.deblocking_filter_parameters_present;
+  pic_descriptor->pps_info.avc.constrained_intra_pred_flag    = h->pps.constrained_intra_pred;
+  pic_descriptor->pps_info.avc.redundant_pic_cnt_present_flag = h->pps.redundant_pic_cnt_present;
+  pic_descriptor->pps_info.avc.transform_8x8_mode_flag        = h->pps.transform_8x8_mode;
+  pic_descriptor->pps_info.avc.xvba_avc_pps_reserved          = 0; // must be 0
+
+  memcpy(iq_matrix->bScalingLists4x4, h->pps.scaling_matrix4, sizeof(iq_matrix->bScalingLists4x4));
+  memcpy(iq_matrix->bScalingLists8x8[0], h->pps.scaling_matrix8[0], sizeof(iq_matrix->bScalingLists8x8[0]));
+  memcpy(iq_matrix->bScalingLists8x8[1], h->pps.scaling_matrix8[3], sizeof(iq_matrix->bScalingLists8x8[0]));
+
+  // Wait for an I-frame before start decoding. Workaround for ATI UVD and UVD+ GPUs
+  if (!h->got_first_iframe) {
+      if (h->slice_type != AV_PICTURE_TYPE_I && h->slice_type != AV_PICTURE_TYPE_SI)
+          return -1;
+      h->got_first_iframe = 1;
+  }
+
+  ff_draw_horiz_band(s, 0, s->avctx->height);
+
+  return 0;
+}
+
+/** Decode the given H.264 slice with XVBA. */
+static int decode_slice(AVCodecContext *avctx,
+                        const uint8_t  *buffer,
+                        uint32_t        size)
+{
+  H264Context * const h = avctx->priv_data;
+  MpegEncContext * const s = &h->s;
+  struct xvba_render_state *render;
+
+  render = (struct xvba_render_state *)s->current_picture_ptr->f.data[0];
+  assert(render);
+
+  ff_xvba_add_slice_data(render, buffer, size);
+
+  return 0;
+}
+
+AVHWAccel ff_h264_xvba_hwaccel = {
+    .name           = "h264_xvba",
+    .type           = AVMEDIA_TYPE_VIDEO,
+    .id             = CODEC_ID_H264,
+    .pix_fmt        = PIX_FMT_XVBA_VLD,
+    .start_frame    = start_frame,
+    .end_frame      = end_frame,
+    .decode_slice   = decode_slice,
+};
diff --git a/lib/ffmpeg/libavcodec/xvba_internal.h b/lib/ffmpeg/libavcodec/xvba_internal.h
new file mode 100644
index 0000000..9653f85
--- /dev/null
+++ b/lib/ffmpeg/libavcodec/xvba_internal.h
@@ -0,0 +1,24 @@
+/*
+ * HW decode acceleration for MPEG-2, H.264 and VC-1
+ *
+ * Copyright (C) 2005-2011 Team XBMC
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+int ff_xvba_translate_profile(int profile);
+void ff_xvba_add_slice_data(struct xvba_render_state *render, const uint8_t *buffer, uint32_t size);
diff --git a/lib/ffmpeg/libavcodec/xvba_mpeg2.c b/lib/ffmpeg/libavcodec/xvba_mpeg2.c
new file mode 100644
index 0000000..552ef95
--- /dev/null
+++ b/lib/ffmpeg/libavcodec/xvba_mpeg2.c
@@ -0,0 +1,52 @@
+/*
+ * MPEG-2 HW decode acceleration through XVBA
+ *
+ * Copyright (C) 2005-2011 Team XBMC
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "dsputil.h"
+
+static int start_frame(AVCodecContext *avctx, av_unused const uint8_t *buffer, av_unused uint32_t size)
+{
+    struct MpegEncContext * const s = avctx->priv_data;
+    return 0;
+}
+
+static int end_frame(AVCodecContext *avctx)
+{
+    return 0;
+}
+
+static int decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size)
+{
+    struct MpegEncContext * const s = avctx->priv_data;
+    return 0;
+}
+
+AVHWAccel ff_mpeg2_xvba_hwaccel = {
+    .name           = "mpeg2_xvba",
+    .type           = AVMEDIA_TYPE_VIDEO,
+    .id             = CODEC_ID_MPEG2VIDEO,
+    .pix_fmt        = PIX_FMT_XVBA_VLD,
+    .capabilities   = 0,
+    .start_frame    = start_frame,
+    .end_frame      = end_frame,
+    .decode_slice   = decode_slice,
+    .priv_data_size = 0,
+};
diff --git a/lib/ffmpeg/libavcodec/xvba_vc1.c b/lib/ffmpeg/libavcodec/xvba_vc1.c
new file mode 100644
index 0000000..7315b62
--- /dev/null
+++ b/lib/ffmpeg/libavcodec/xvba_vc1.c
@@ -0,0 +1,190 @@
+/*
+ * VC-1 HW decode acceleration through XVBA
+ *
+ * Copyright (C) 2005-2011 Team XBMC
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "xvba.h"
+#include "xvba_internal.h"
+#include "vc1.h"
+#include "vc1data.h"
+#include <assert.h>
+
+
+/** @file
+ * Implement structures of ffmpeg <-> XvBA
+ */
+
+/* Initialize and start decoding a frame with XvBA */
+static int start_frame(AVCodecContext *avctx,
+				av_unused const uint8_t *buffer, 
+				av_unused uint32_t size)
+{
+    VC1Context * const v = avctx->priv_data;
+    MpegEncContext * const s = &v->s;
+    struct xvba_render_state *render;
+
+    render = (struct xvba_render_state *)s->current_picture_ptr->f.data[0];
+    assert(render);
+    
+    render->num_slices = 0;
+    return 0;
+}
+
+/* End a hardware decoding based frame */
+static int end_frame(AVCodecContext *avctx)
+{
+    VC1Context* const v = avctx->priv_data;
+    MpegEncContext* const s = &v->s;
+    struct xvba_render_state *render, *last, *next;
+    XVBAPictureDescriptor *pic_descriptor;
+
+    render = (struct xvba_render_state *)s->current_picture_ptr->f.data[0];
+    assert(render);
+
+    if (render->picture_descriptor == 0)
+      return -1;
+
+    pic_descriptor = render->picture_descriptor;
+    
+    av_dlog(avctx, "xvba_vc1_end_frame()\n");
+    
+    memset(pic_descriptor, 0, sizeof(*pic_descriptor));
+
+    /* Fill in Parameters - for reference see AMD sdk documentation */
+    pic_descriptor->profile                                 = ff_xvba_translate_profile(v->profile);
+    pic_descriptor->level                                   = v->level;
+    //done like in va-driver and vaapi
+    if (v->profile == PROFILE_ADVANCED) {
+      pic_descriptor->width_in_mb                           = s->avctx->coded_width;
+      pic_descriptor->height_in_mb                          = s->avctx->coded_height;
+    } else {
+      pic_descriptor->width_in_mb                           = s->mb_width;
+      pic_descriptor->height_in_mb                          = s->mb_height;
+    }
+    pic_descriptor->picture_structure                       = s->picture_structure;
+    // xvba-video set this to 1 only 4:2:0 supported
+    // doc says: if not set, choose 1 - we try this
+    pic_descriptor->chroma_format                           = 1;
+    pic_descriptor->avc_intra_flag                          = s->pict_type == AV_PICTURE_TYPE_I || v->bi_type == 1;
+    pic_descriptor->avc_reference                           = (s->current_picture_ptr->f.reference & 3) ? 1 : 0;
+    
+    // VC-1 explicit parameters see page 30 of sdk
+    // sps_info
+    pic_descriptor->sps_info.vc1.postprocflag               = v->postprocflag;
+    
+    // done as in vaapi
+    pic_descriptor->sps_info.vc1.pulldown                   = v->broadcast;
+    pic_descriptor->sps_info.vc1.interlace                  = v->interlace;
+    pic_descriptor->sps_info.vc1.tfcntrflag                 = v->tfcntrflag;
+    pic_descriptor->sps_info.vc1.finterpflag                = v->finterpflag;
+    pic_descriptor->sps_info.vc1.reserved                   = 1;
+    // eventually check if this makes sense together with interlace
+    pic_descriptor->sps_info.vc1.psf                        = v->psf;
+    // what about if it is a frame (page 31)
+    // looked at xvba-driver
+    pic_descriptor->sps_info.vc1.second_field               = !s->first_field;
+    pic_descriptor->sps_info.vc1.xvba_vc1_sps_reserved      = 0;
+    
+    // VC-1 explicit parameters see page 30 of sdk
+    // pps_info
+    pic_descriptor->pps_info.vc1.panscan_flag               = v->panscanflag;
+    pic_descriptor->pps_info.vc1.refdist_flag               = v->refdist_flag;
+    pic_descriptor->pps_info.vc1.loopfilter                 = s->loop_filter;
+    pic_descriptor->pps_info.vc1.fastuvmc                   = v->fastuvmc;
+    pic_descriptor->pps_info.vc1.extended_mv                = v->extended_mv;
+    pic_descriptor->pps_info.vc1.dquant                     = v->dquant;
+    pic_descriptor->pps_info.vc1.vstransform                = v->vstransform;
+    pic_descriptor->pps_info.vc1.overlap                    = v->overlap;
+    pic_descriptor->pps_info.vc1.quantizer                  = v->quantizer_mode;
+    pic_descriptor->pps_info.vc1.extended_dmv               = v->extended_dmv;   
+    pic_descriptor->pps_info.vc1.maxbframes                 = s->avctx->max_b_frames;
+    pic_descriptor->pps_info.vc1.rangered                   = (pic_descriptor->profile == PROFILE_SIMPLE) ? 0 : v->rangered;   
+    pic_descriptor->pps_info.vc1.syncmarker                 = (pic_descriptor->profile == PROFILE_SIMPLE) ? 0 : s->resync_marker;
+    pic_descriptor->pps_info.vc1.multires                   = v->multires;
+    pic_descriptor->pps_info.vc1.reserved                   = 1;
+    pic_descriptor->pps_info.vc1.range_mapy_flag            = v->range_mapy_flag;
+    pic_descriptor->pps_info.vc1.range_mapy                 = v->range_mapy;
+    pic_descriptor->pps_info.vc1.range_mapuv_flag           = v->range_mapuv_flag;
+    pic_descriptor->pps_info.vc1.range_mapuv                = v->range_mapuv;
+    pic_descriptor->pps_info.vc1.xvba_vc1_pps_reserved      = 0;
+    
+    pic_descriptor->past_surface                            = 0;
+    pic_descriptor->future_surface                          = 0;
+    switch (s->pict_type) {
+    case AV_PICTURE_TYPE_B:
+        next = (struct xvba_render_state *)s->next_picture.f.data[0];
+        assert(next);
+        if (next)
+          pic_descriptor->past_surface = next->surface;
+        // fall-through
+    case AV_PICTURE_TYPE_P:
+        last = (struct xvba_render_state *)s->last_picture.f.data[0];
+        assert(last);
+        if (last)
+          pic_descriptor->future_surface = last->surface;
+        break;
+    }
+
+    ff_draw_horiz_band(s, 0, s->avctx->height);
+
+    return 0;
+}
+
+static int decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size)
+{
+  VC1Context* const v = avctx->priv_data;
+  MpegEncContext* const s = &v->s;
+  struct xvba_render_state *render;
+
+  render = (struct xvba_render_state *)s->current_picture_ptr->f.data[0];
+  assert(render);
+
+  if (avctx->codec_id == CODEC_ID_VC1 &&
+      size >= 4 && IS_MARKER(AV_RB32(buffer))) {
+      buffer += 4;
+      size   -= 4;
+  }
+
+  ff_xvba_add_slice_data(render, buffer, size);
+
+  return 0;
+}
+
+#if CONFIG_WMV3_XVBA_HWACCEL
+AVHWAccel ff_wmv3_xvba_hwaccel = {
+    .name           = "wmv3_xvba",
+    .type           = AVMEDIA_TYPE_VIDEO,
+    .id             = CODEC_ID_WMV3,
+    .pix_fmt        = PIX_FMT_XVBA_VLD,
+    .start_frame    = start_frame,
+    .end_frame      = end_frame,
+    .decode_slice   = decode_slice,
+};
+#endif
+
+AVHWAccel ff_vc1_xvba_hwaccel = {
+    .name           = "vc1_xvba",
+    .type           = AVMEDIA_TYPE_VIDEO,
+    .id             = CODEC_ID_VC1,
+    .pix_fmt        = PIX_FMT_XVBA_VLD,
+    .start_frame    = start_frame,
+    .end_frame      = end_frame,
+    .decode_slice   = decode_slice,
+};
diff --git a/lib/ffmpeg/libavcodec/xvmc_internal.h b/lib/ffmpeg/libavcodec/xvmc_internal.h
index 04197ce..d925eb1 100644
--- a/lib/ffmpeg/libavcodec/xvmc_internal.h
+++ b/lib/ffmpeg/libavcodec/xvmc_internal.h
@@ -1,5 +1,7 @@
 /*
- * XVideo Motion Compensation internal functions
+ * HW decode acceleration for MPEG-2, H.264 and VC-1
+ *
+ * Copyright (C) 2005-2011 Team XBMC
  *
  * This file is part of FFmpeg.
  *
diff --git a/lib/ffmpeg/libavutil/pixdesc.c b/lib/ffmpeg/libavutil/pixdesc.c
index e73fbfe..5abbd14 100644
--- a/lib/ffmpeg/libavutil/pixdesc.c
+++ b/lib/ffmpeg/libavutil/pixdesc.c
@@ -874,6 +874,12 @@ void av_write_image_line(const uint16_t *src, uint8_t *data[4], const int linesi
         .log2_chroma_h = 1,
         .flags = PIX_FMT_HWACCEL,
     },
+    [PIX_FMT_XVBA_VLD] = {
+        .name = "xvba_vld",
+        .log2_chroma_w = 1,
+        .log2_chroma_h = 1,
+        .flags = PIX_FMT_HWACCEL,
+    },
     [PIX_FMT_YUV420P9LE] = {
         .name = "yuv420p9le",
         .nb_components = 3,
diff --git a/lib/ffmpeg/libavutil/pixfmt.h b/lib/ffmpeg/libavutil/pixfmt.h
index f0d9c01..0f8cf7b 100644
--- a/lib/ffmpeg/libavutil/pixfmt.h
+++ b/lib/ffmpeg/libavutil/pixfmt.h
@@ -129,6 +129,7 @@ enum PixelFormat {
     PIX_FMT_YUV444P16BE,  ///< planar YUV 4:4:4, 48bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian
     PIX_FMT_VDPAU_MPEG4,  ///< MPEG4 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers
     PIX_FMT_DXVA2_VLD,    ///< HW decoding through DXVA2, Picture.data[3] contains a LPDIRECT3DSURFACE9 pointer
+    PIX_FMT_XVBA_VLD,     ///< HW decoding through DXVA2, Picture.data[3] contains a vaapi_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers
 
     PIX_FMT_RGB444LE,  ///< packed RGB 4:4:4, 16bpp, (msb)4A 4R 4G 4B(lsb), little-endian, most significant bits to 0
     PIX_FMT_RGB444BE,  ///< packed RGB 4:4:4, 16bpp, (msb)4A 4R 4G 4B(lsb), big-endian, most significant bits to 0
-- 
1.7.10


From ba3ff34f25538a4214d3734b12b938b032396a1f Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Thu, 12 Apr 2012 12:09:31 +0200
Subject: [PATCH 42/58] xvba: add decoder

---
 configure.in                                       |   48 +
 language/English/strings.po                        |   12 +-
 xbmc/cores/VideoRenderers/LinuxRendererGL.cpp      |  218 +-
 xbmc/cores/VideoRenderers/LinuxRendererGL.h        |   15 +-
 xbmc/cores/VideoRenderers/RenderFormats.h          |    1 +
 xbmc/cores/VideoRenderers/RenderManager.cpp        |    9 +-
 .../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h      |    4 +
 .../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp        |   16 +
 xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in   |    4 +
 xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp      | 2354 ++++++++++++++++++++
 xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.h        |  382 ++++
 xbmc/cores/dvdplayer/DVDPlayerVideo.cpp            |    3 +
 xbmc/settings/GUISettings.cpp                      |    3 +
 xbmc/settings/VideoSettings.h                      |    2 +
 xbmc/video/dialogs/GUIDialogVideoSettings.cpp      |    1 +
 15 files changed, 3064 insertions(+), 8 deletions(-)
 create mode 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp
 create mode 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.h

diff --git a/configure.in b/configure.in
index 82f457a..c328f0f 100644
--- a/configure.in
+++ b/configure.in
@@ -124,6 +124,8 @@ vaapi_not_found="== Could not find libva. VAAPI support disabled. =="
 vaapi_disabled="== VAAPI support manually disabled. =="
 crystalhd_not_found="== Could not find libcrystalhd. CrystalHD support disabled. =="
 crystalhd_disabled="== CrystalHD support manually disabled. =="
+xvba_not_found="== Could not find amdxvba.h. XVBA support disabled. =="
+xvba_disabled="== XVBA support manually disabled. =="
 vdadecoder_enabled="== VDADecoder support enabled. =="
 vdadecoder_disabled="== VDADecoder support manually disabled. =="
 vtbdecoder_enabled="== VTBDecoder support enabled. =="
@@ -247,6 +249,12 @@ AC_ARG_ENABLE([crystalhd],
   [enable CrystalHD decoding (default is auto)])],
   [use_crystalhd=$enableval],
   [use_crystalhd=auto])
+  
+AC_ARG_ENABLE([xvba],
+  [AS_HELP_STRING([--enable-xvba],
+  [enable XVBA decoding (default is auto)])],
+  [use_xvba=$enableval],
+  [use_xvba=auto])  
 
 AC_ARG_ENABLE([vdadecoder],
   [AS_HELP_STRING([--enable-vdadecoder],
@@ -1760,6 +1768,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 <X11/Xlib.h>])
+
+    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
@@ -1971,6 +2011,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
@@ -2444,6 +2490,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)
@@ -2627,6 +2674,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 9887f19..c616348 100644
--- a/language/English/strings.po
+++ b/language/English/strings.po
@@ -5124,7 +5124,11 @@ msgctxt "#13436"
 msgid "Allow Vdpau OpenGL interop YUV"
 msgstr ""
 
-#empty strings from id 13437 to 13499
+msgctxt "#13437"
+msgid "Allow hardware acceleration (XVBA)"
+msgstr ""
+
+#empty strings from id 13438 to 13499
 
 msgctxt "#13500"
 msgid "A/V sync method"
@@ -6346,7 +6350,11 @@ msgctxt "#16325"
 msgid "VDPAU - Bob"
 msgstr ""
 
-#empty strings from id 16326 to 16399
+msgctxt "#16326"
+msgid "XVBA"
+msgstr ""
+
+#empty strings from id 16327 to 16399
 
 msgctxt "#16400"
 msgid "Post-processing"
diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
index 497fb32..723ab34 100644
--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
@@ -63,6 +63,9 @@
        VA_MICRO_VERSION == 0 && VA_SDS_VERSION < 5)))
 
 #endif
+#ifdef HAVE_LIBXVBA
+#include "cores/dvdplayer/DVDCodecs/Video/XVBA.h"
+#endif
 
 #ifdef TARGET_DARWIN
   #include "osx/CocoaInterface.h"
@@ -129,6 +132,9 @@
 #ifdef HAVE_LIBVDPAU
   vdpau = NULL;
 #endif
+#ifdef HAVE_LIBXVBA
+  xvba = NULL;
+#endif
 }
 
 CLinuxRendererGL::YUVBUFFER::~YUVBUFFER()
@@ -604,6 +610,9 @@ void CLinuxRendererGL::ReleaseBuffer(int idx)
 #ifdef HAVE_LIBVDPAU
   SAFE_RELEASE(buf.vdpau);
 #endif
+#ifdef HAVE_LIBXVBA
+  SAFE_RELEASE(buf.xvba);
+#endif
 #ifdef HAVE_LIBVA
   buf.vaapi.surface.reset();
 #endif
@@ -879,7 +888,7 @@ void CLinuxRendererGL::UpdateVideoFilter()
   case VS_SCALINGMETHOD_LINEAR:
     SetTextureFilter(m_scalingMethod == VS_SCALINGMETHOD_NEAREST ? GL_NEAREST : GL_LINEAR);
     m_renderQuality = RQ_SINGLEPASS;
-    if (((m_renderMethod & RENDER_VDPAU) || (m_renderMethod & RENDER_VAAPI)) && m_nonLinStretch)
+    if (((m_renderMethod & RENDER_VDPAU) || (m_renderMethod & RENDER_VAAPI) || (m_renderMethod & RENDER_XVBA)) && m_nonLinStretch)
     {
       m_pVideoFilterShader = new StretchFilterShader();
       if (!m_pVideoFilterShader->CompileAndLink())
@@ -965,6 +974,11 @@ void CLinuxRendererGL::LoadShaders(int field)
     CLog::Log(LOGNOTICE, "GL: Using CVBREF render method");
     m_renderMethod = RENDER_CVREF;
   }
+  else if (m_format == RENDER_FMT_XVBA)
+  {
+    CLog::Log(LOGNOTICE, "GL: Using XVBA render method");
+    m_renderMethod = RENDER_XVBA;
+  }
   else
   {
     int requestedMethod = g_guiSettings.GetInt("videoplayer.rendermethod");
@@ -1113,6 +1127,12 @@ void CLinuxRendererGL::LoadShaders(int field)
     m_textureCreate = &CLinuxRendererGL::CreateCVRefTexture;
     m_textureDelete = &CLinuxRendererGL::DeleteCVRefTexture;
   }
+  else if (m_format == RENDER_FMT_XVBA)
+  {
+    m_textureUpload = &CLinuxRendererGL::UploadXVBATexture;
+    m_textureCreate = &CLinuxRendererGL::CreateXVBATexture;
+    m_textureDelete = &CLinuxRendererGL::DeleteXVBATexture;
+  }
   else
   {
     // setup default YV12 texture handlers
@@ -1225,6 +1245,13 @@ void CLinuxRendererGL::Render(DWORD flags, int renderBuffer)
     RenderVAAPI(renderBuffer, m_currentField);
   }
 #endif
+#ifdef HAVE_LIBXVBA
+  else if (m_renderMethod & RENDER_XVBA)
+  {
+    UpdateVideoFilter();
+    RenderXVBA(renderBuffer, m_currentField);
+  }
+#endif
   else
   {
     // RENDER_CVREF uses the same render as the default case
@@ -1732,6 +1759,77 @@ void CLinuxRendererGL::RenderVAAPI(int index, int field)
 #endif
 }
 
+void CLinuxRendererGL::RenderXVBA(int index, int field)
+{
+#ifdef HAVE_LIBXVBA
+  YUVPLANE &plane = m_buffers[index].fields[0][1];
+
+  glEnable(m_textureTarget);
+  glActiveTextureARB(GL_TEXTURE0);
+
+  glBindTexture(m_textureTarget, plane.id);
+
+  // Try some clamping or wrapping
+  glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+  glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+  if (m_pVideoFilterShader)
+  {
+    GLint filter;
+    if (!m_pVideoFilterShader->GetTextureFilter(filter))
+      filter = m_scalingMethod == VS_SCALINGMETHOD_NEAREST ? GL_NEAREST : GL_LINEAR;
+
+    glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, filter);
+    glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, filter);
+    m_pVideoFilterShader->SetSourceTexture(0);
+    m_pVideoFilterShader->SetWidth(m_sourceWidth);
+    m_pVideoFilterShader->SetHeight(m_sourceHeight);
+
+    //disable non-linear stretch when a dvd menu is shown, parts of the menu are rendered through the overlay renderer
+    //having non-linear stretch on breaks the alignment
+    if (g_application.m_pPlayer && g_application.m_pPlayer->IsInMenu())
+      m_pVideoFilterShader->SetNonLinStretch(1.0);
+    else
+      m_pVideoFilterShader->SetNonLinStretch(pow(g_settings.m_fPixelRatio, g_advancedSettings.m_videoNonLinStretchRatio));
+
+    m_pVideoFilterShader->Enable();
+  }
+  else
+  {
+    GLint filter = m_scalingMethod == VS_SCALINGMETHOD_NEAREST ? GL_NEAREST : GL_LINEAR;
+    glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, filter);
+    glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, filter);
+  }
+
+  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+  VerifyGLState();
+
+  glBegin(GL_QUADS);
+  if (m_textureTarget==GL_TEXTURE_2D)
+  {
+    glTexCoord2f(plane.rect.x1, plane.rect.y1); glVertex2f(m_destRect.x1, m_destRect.y1);
+    glTexCoord2f(plane.rect.x2, plane.rect.y1); glVertex2f(m_destRect.x2, m_destRect.y1);
+    glTexCoord2f(plane.rect.x2, plane.rect.y2); glVertex2f(m_destRect.x2, m_destRect.y2);
+    glTexCoord2f(plane.rect.x1, plane.rect.y2); glVertex2f(m_destRect.x1, m_destRect.y2);
+  }
+  else
+  {
+    glTexCoord2f(m_destRect.x1, m_destRect.y1); glVertex4f(m_destRect.x1, m_destRect.y1, 0.0f, 0.0f);
+    glTexCoord2f(m_destRect.x2, m_destRect.y1); glVertex4f(m_destRect.x2, m_destRect.y1, 1.0f, 0.0f);
+    glTexCoord2f(m_destRect.x2, m_destRect.y2); glVertex4f(m_destRect.x2, m_destRect.y2, 1.0f, 1.0f);
+    glTexCoord2f(m_destRect.x1, m_destRect.y2); glVertex4f(m_destRect.x1, m_destRect.y2, 0.0f, 1.0f);
+  }
+  glEnd();
+  VerifyGLState();
+
+  if (m_pVideoFilterShader)
+    m_pVideoFilterShader->Disable();
+
+  glBindTexture (m_textureTarget, 0);
+  glDisable(m_textureTarget);
+#endif
+}
+
 void CLinuxRendererGL::RenderSoftware(int index, int field)
 {
   // used for textues uploaded from rgba or CVPixelBuffers.
@@ -2788,6 +2886,93 @@ bool CLinuxRendererGL::CreateCVRefTexture(int index)
   return true;
 }
 
+void CLinuxRendererGL::DeleteXVBATexture(int index)
+{
+#ifdef HAVE_LIBXVBA
+  YUVPLANE &plane = m_buffers[index].fields[0][0];
+  YUVFIELDS &fields = m_buffers[index].fields;
+
+  SAFE_RELEASE(m_buffers[index].xvba);
+
+  if(plane.id && glIsTexture(plane.id))
+    glDeleteTextures(1, &plane.id);
+  plane.id = 0;
+  fields[0][1].id = 0;
+#endif
+}
+
+bool CLinuxRendererGL::CreateXVBATexture(int index)
+{
+#ifdef HAVE_LIBXVBA
+  YV12Image &im = m_buffers[index].image;
+  YUVFIELDS &fields = m_buffers[index].fields;
+  YUVPLANE &plane = fields[0][0];
+
+  DeleteXVBATexture(index);
+
+  memset(&im , 0, sizeof(im));
+  memset(&fields, 0, sizeof(fields));
+
+  glGenTextures(1, &plane.id);
+
+  m_eventTexturesDone[index]->Set();
+#endif
+  return true;
+}
+
+void CLinuxRendererGL::UploadXVBATexture(int index)
+{
+#ifdef HAVE_LIBXVBA
+  XVBA::CXvbaRenderPicture *xvba = m_buffers[index].xvba;
+  YV12Image &im = m_buffers[index].image;
+
+  YUVFIELDS &fields = m_buffers[index].fields;
+  YUVPLANE &plane = fields[0][1];
+
+  if (!xvba)
+  {
+    fields[0][1].id = fields[0][0].id;
+    m_eventTexturesDone[index]->Set();
+    CLog::Log(LOGWARNING,"CLinuxRendererGL::UploadXVBATexture no xvba texture, index: %d", index);
+    return;
+  }
+//  xvba->Transfer();
+
+  fields[0][1].id = xvba->texture;
+
+  im.height = xvba->texHeight;
+  im.width  = xvba->texWidth;
+
+  plane.texwidth  = xvba->texWidth;
+  plane.texheight = xvba->texHeight;
+  plane.pixpertex_x = 1;
+  plane.pixpertex_y = 1;
+
+  plane.rect = m_sourceRect;
+  plane.width  = im.width;
+  plane.height = im.height;
+
+  plane.height  /= plane.pixpertex_y;
+  plane.rect.y1 /= plane.pixpertex_y;
+  plane.rect.y2 /= plane.pixpertex_y;
+  plane.width   /= plane.pixpertex_x;
+  plane.rect.x1 /= plane.pixpertex_x;
+  plane.rect.x2 /= plane.pixpertex_x;
+
+  if (m_textureTarget == GL_TEXTURE_2D)
+  {
+    plane.height  /= plane.texheight;
+    plane.rect.y1 /= plane.texheight;
+    plane.rect.y2 /= plane.texheight;
+    plane.width   /= plane.texwidth;
+    plane.rect.x1 /= plane.texwidth;
+    plane.rect.x2 /= plane.texwidth;
+  }
+
+  m_eventTexturesDone[index]->Set();
+#endif
+}
+
 void CLinuxRendererGL::UploadYUV422PackedTexture(int source)
 {
   YUVBUFFER& buf    =  m_buffers[source];
@@ -3373,6 +3558,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);
@@ -3386,6 +3574,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);
@@ -3409,7 +3600,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;
   }
 
@@ -3481,6 +3673,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.
@@ -3523,7 +3725,7 @@ bool CLinuxRendererGL::Supports(ESCALINGMETHOD method)
   || method == VS_SCALINGMETHOD_LANCZOS3)
   {
     if ((glewIsSupported("GL_EXT_framebuffer_object") && (m_renderMethod & RENDER_GLSL)) ||
-        (m_renderMethod & RENDER_VDPAU) || (m_renderMethod & RENDER_VAAPI))
+        (m_renderMethod & RENDER_VDPAU) || (m_renderMethod & RENDER_VAAPI) || (m_renderMethod & RENDER_XVBA))
     {
       // spline36 and lanczos3 are only allowed through advancedsettings.xml
       if(method != VS_SCALINGMETHOD_SPLINE36
@@ -3615,4 +3817,14 @@ void CLinuxRendererGL::AddProcessor(struct __CVBuffer *cvBufferRef, int index)
 }
 #endif
 
+#ifdef HAVE_LIBXVBA
+void CLinuxRendererGL::AddProcessor(XVBA::CXvbaRenderPicture* xvba, int index)
+{
+  YUVBUFFER &buf = m_buffers[index];
+  XVBA::CXvbaRenderPicture *pic = xvba->Acquire();
+  SAFE_RELEASE(buf.xvba);
+  buf.xvba = pic;
+}
+#endif
+
 #endif
diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.h b/xbmc/cores/VideoRenderers/LinuxRendererGL.h
index 2fc34ae..e76624b 100644
--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.h
+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.h
@@ -43,6 +43,8 @@
 namespace Shaders { class BaseVideoFilterShader; }
 namespace VAAPI   { struct CHolder; }
 namespace VDPAU   { class CVdpauRenderPicture; }
+namespace XVBA    { class CXvbaRenderPicture; }
+
 
 #define NUM_BUFFERS 10
 
@@ -90,6 +92,7 @@ enum RenderMethod
   RENDER_POT=0x10,
   RENDER_VAAPI=0x20,
   RENDER_CVREF = 0x40,
+  RENDER_XVBA=0x80,
 };
 
 enum RenderQuality
@@ -151,7 +154,9 @@ class CLinuxRendererGL : public CBaseRenderer
 #ifdef TARGET_DARWIN
   virtual void         AddProcessor(struct __CVBuffer *cvBufferRef, int index);
 #endif
-
+#ifdef HAVE_LIBXVBA
+  virtual void         AddProcessor(XVBA::CXvbaRenderPicture* xvba, int index);
+#endif
   virtual void RenderUpdate(bool clear, DWORD flags = 0, DWORD alpha = 255);
 
   // Feature support
@@ -210,6 +215,10 @@ class CLinuxRendererGL : public CBaseRenderer
   void DeleteYUV422PackedTexture(int index);
   bool CreateYUV422PackedTexture(int index);
 
+  void UploadXVBATexture(int index);
+  void DeleteXVBATexture(int index);
+  bool CreateXVBATexture(int index);
+
   void UploadRGBTexture(int index);
   void ToRGBFrame(YV12Image* im, unsigned flipIndexPlane, unsigned flipIndexBuf);
   void ToRGBFields(YV12Image* im, unsigned flipIndexPlaneTop, unsigned flipIndexPlaneBot, unsigned flipIndexBuf);
@@ -225,6 +234,7 @@ class CLinuxRendererGL : public CBaseRenderer
   void RenderVDPAU(int renderBuffer, int field);      // render using vdpau hardware
   void RenderProgressiveWeave(int renderBuffer, int field); // render using vdpau hardware
   void RenderVAAPI(int renderBuffer, int field);      // render using vdpau hardware
+  void RenderXVBA(int renderBuffer, int field);      // render using xvba hardware
 
   struct
   {
@@ -292,6 +302,9 @@ class CLinuxRendererGL : public CBaseRenderer
 #ifdef TARGET_DARWIN_OSX
     struct __CVBuffer *cvBufferRef;
 #endif
+#ifdef HAVE_LIBXVBA
+    XVBA::CXvbaRenderPicture *xvba;
+#endif
   };
 
   typedef YUVBUFFER          YUVBUFFERS[NUM_BUFFERS];
diff --git a/xbmc/cores/VideoRenderers/RenderFormats.h b/xbmc/cores/VideoRenderers/RenderFormats.h
index 0262c60..a727d94 100644
--- a/xbmc/cores/VideoRenderers/RenderFormats.h
+++ b/xbmc/cores/VideoRenderers/RenderFormats.h
@@ -35,6 +35,7 @@ enum ERenderFormat {
   RENDER_FMT_OMXEGL,
   RENDER_FMT_CVBREF,
   RENDER_FMT_BYPASS,
+  RENDER_FMT_XVBA,
 };
 
 #endif
diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp
index a521680..0506823 100644
--- a/xbmc/cores/VideoRenderers/RenderManager.cpp
+++ b/xbmc/cores/VideoRenderers/RenderManager.cpp
@@ -250,8 +250,9 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi
 
   // check if decoder supports buffering
   m_bCodecSupportsBuffering = false;
-  if (format == RENDER_FMT_VDPAU ||
-      format == RENDER_FMT_VDPAU_420)
+  if (format == RENDER_FMT_VDPAU
+     || format == RENDER_FMT_VDPAU_420
+     || format == RENDER_FMT_XVBA)
     m_bCodecSupportsBuffering = true;
 
   bool result = m_pRenderer->Configure(width, height, d_width, d_height, fps, flags, format, extended_format, orientation);
@@ -873,6 +874,10 @@ int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic)
   else if(pic.format == RENDER_FMT_VAAPI)
     m_pRenderer->AddProcessor(*pic.vaapi, index);
 #endif
+#ifdef HAVE_LIBXVBA
+  else if(pic.format == RENDER_FMT_XVBA)
+    m_pRenderer->AddProcessor(pic.xvba, index);
+#endif
   m_pRenderer->ReleaseImage(index, false);
 
   return index;
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
index 98d8f89..76d3575 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
@@ -35,6 +35,7 @@
 namespace DXVA { class CSurfaceContext; }
 namespace VAAPI { struct CHolder; }
 namespace VDPAU { class CVdpauRenderPicture; }
+namespace XVBA { class CXvbaRenderPicture; }
 class COpenMax;
 class COpenMaxVideo;
 struct OpenMaxVideoBuffer;
@@ -60,6 +61,9 @@ struct DVDVideoPicture
     struct {
       VAAPI::CHolder* vaapi;
     };
+    struct {
+      XVBA::CXvbaRenderPicture* xvba;
+    };
 
     struct {
       COpenMax *openMax;
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
index a6e42e5..b3252ec 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
@@ -56,6 +56,9 @@
 #ifdef HAVE_LIBVA
 #include "VAAPI.h"
 #endif
+#ifdef HAVE_LIBXVBA
+#include "XVBA.h"
+#endif
 
 using namespace boost;
 
@@ -100,6 +103,19 @@ enum PixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx
       dec->Release();
   }
 #endif
+#ifdef HAVE_LIBXVBA
+    if(*cur == PIX_FMT_XVBA_VLD && g_guiSettings.GetBool("videoplayer.usexvba"))
+    {
+      XVBA::CDecoder* dec = new XVBA::CDecoder();
+      if(dec->Open(avctx, *cur, ctx->m_uSurfacesCount))
+      {
+        ctx->SetHardware(dec);
+        return *cur;
+      }
+      else
+        dec->Release();
+    }
+#endif
 #ifdef HAVE_LIBVA
     // mpeg4 vaapi decoding is disabled
     if(*cur == PIX_FMT_VAAPI_VLD && g_guiSettings.GetBool("videoplayer.usevaapi") 
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in b/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in
index 176ceff..c58422b 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in
@@ -14,6 +14,10 @@ ifeq (@USE_CRYSTALHD@,1)
 SRCS += CrystalHD.cpp
 SRCS += DVDVideoCodecCrystalHD.cpp
 endif
+ifeq (@USE_XVBA@,1)
+SRCS+=  XVBA.cpp \
+
+endif
 ifeq (@USE_VDA@,1)
 SRCS += DVDVideoCodecVDA.cpp
 endif
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp
new file mode 100644
index 0000000..e8e376a
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp
@@ -0,0 +1,2354 @@
+/*
+ *      Copyright (C) 2005-2011 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "system.h"
+#ifdef HAVE_LIBXVBA
+
+#include "system_gl.h"
+#include <dlfcn.h>
+#include <string>
+#include "XVBA.h"
+#include "windowing/WindowingFactory.h"
+#include "guilib/GraphicContext.h"
+#include "settings/GUISettings.h"
+#include "settings/Settings.h"
+#include "utils/TimeUtils.h"
+#include "cores/dvdplayer/DVDClock.h"
+
+using namespace XVBA;
+
+// XVBA interface
+
+#define XVBA_LIBRARY    "libXvBAW.so.1"
+
+typedef Bool        (*XVBAQueryExtensionProc)       (Display *dpy, int *vers);
+typedef Status      (*XVBACreateContextProc)        (void *input, void *output);
+typedef Status      (*XVBADestroyContextProc)       (void *context);
+typedef Bool        (*XVBAGetSessionInfoProc)       (void *input, void *output);
+typedef Status      (*XVBACreateSurfaceProc)        (void *input, void *output);
+typedef Status      (*XVBACreateGLSharedSurfaceProc)(void *input, void *output);
+typedef Status      (*XVBADestroySurfaceProc)       (void *surface);
+typedef Status      (*XVBACreateDecodeBuffersProc)  (void *input, void *output);
+typedef Status      (*XVBADestroyDecodeBuffersProc) (void *input);
+typedef Status      (*XVBAGetCapDecodeProc)         (void *input, void *output);
+typedef Status      (*XVBACreateDecodeProc)         (void *input, void *output);
+typedef Status      (*XVBADestroyDecodeProc)        (void *session);
+typedef Status      (*XVBAStartDecodePictureProc)   (void *input);
+typedef Status      (*XVBADecodePictureProc)        (void *input);
+typedef Status      (*XVBAEndDecodePictureProc)     (void *input);
+typedef Status      (*XVBASyncSurfaceProc)          (void *input, void *output);
+typedef Status      (*XVBAGetSurfaceProc)           (void *input);
+typedef Status      (*XVBATransferSurfaceProc)      (void *input);
+
+static struct
+{
+  XVBAQueryExtensionProc              QueryExtension;
+  XVBACreateContextProc               CreateContext;
+  XVBADestroyContextProc              DestroyContext;
+  XVBAGetSessionInfoProc              GetSessionInfo;
+  XVBACreateSurfaceProc               CreateSurface;
+  XVBACreateGLSharedSurfaceProc       CreateGLSharedSurface;
+  XVBADestroySurfaceProc              DestroySurface;
+  XVBACreateDecodeBuffersProc         CreateDecodeBuffers;
+  XVBADestroyDecodeBuffersProc        DestroyDecodeBuffers;
+  XVBAGetCapDecodeProc                GetCapDecode;
+  XVBACreateDecodeProc                CreateDecode;
+  XVBADestroyDecodeProc               DestroyDecode;
+  XVBAStartDecodePictureProc          StartDecodePicture;
+  XVBADecodePictureProc               DecodePicture;
+  XVBAEndDecodePictureProc            EndDecodePicture;
+  XVBASyncSurfaceProc                 SyncSurface;
+  XVBAGetSurfaceProc                  GetSurface;
+  XVBATransferSurfaceProc             TransferSurface;
+}g_XVBA_vtable;
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+
+CXVBAContext *CXVBAContext::m_context = 0;
+CCriticalSection CXVBAContext::m_section;
+Display *CXVBAContext::m_display = 0;
+void *CXVBAContext::m_dlHandle = 0;
+
+CXVBAContext::CXVBAContext()
+{
+  m_context = 0;
+//  m_dlHandle = 0;
+  m_xvbaContext = 0;
+  m_refCount = 0;
+}
+
+void CXVBAContext::Release()
+{
+  CSingleLock lock(m_section);
+
+  m_refCount--;
+  if (m_refCount <= 0)
+  {
+    Close();
+    delete this;
+    m_context = 0;
+  }
+}
+
+void CXVBAContext::Close()
+{
+  CLog::Log(LOGNOTICE, "XVBA::Close - closing decoder context");
+
+  DestroyContext();
+//  if (m_dlHandle)
+//  {
+//    dlclose(m_dlHandle);
+//    m_dlHandle = 0;
+//  }
+}
+
+bool CXVBAContext::EnsureContext(CXVBAContext **ctx)
+{
+  CSingleLock lock(m_section);
+
+  if (m_context)
+  {
+    m_context->m_refCount++;
+    *ctx = m_context;
+    return true;
+  }
+
+  m_context = new CXVBAContext();
+  *ctx = m_context;
+  {
+    CSingleLock gLock(g_graphicsContext);
+    if (!m_context->LoadSymbols() || !m_context->CreateContext())
+    {
+      delete m_context;
+      m_context = 0;
+      return false;
+    }
+  }
+
+  m_context->m_refCount++;
+
+  *ctx = m_context;
+  return true;
+}
+
+bool CXVBAContext::LoadSymbols()
+{
+  if (!m_dlHandle)
+  {
+    m_dlHandle  = dlopen(XVBA_LIBRARY, RTLD_LAZY);
+    if (!m_dlHandle)
+    {
+      const char* error = dlerror();
+      if (!error)
+        error = "dlerror() returned NULL";
+
+      CLog::Log(LOGERROR,"XVBA::LoadSymbols: Unable to get handle to lib: %s", error);
+      return false;
+    }
+  }
+  else
+    return true;
+
+#define INIT_PROC(PREFIX, PROC) do {                            \
+        g_##PREFIX##_vtable.PROC = (PREFIX##PROC##Proc)         \
+            dlsym(m_dlHandle, #PREFIX #PROC);                   \
+    } while (0)
+
+#define INIT_PROC_CHECK(PREFIX, PROC) do {                      \
+        dlerror();                                              \
+        INIT_PROC(PREFIX, PROC);                                \
+        if (dlerror()) {                                        \
+            dlclose(m_dlHandle);                                \
+            m_dlHandle = NULL;                                  \
+            return false;                                       \
+        }                                                       \
+    } while (0)
+
+#define XVBA_INIT_PROC(PROC) INIT_PROC_CHECK(XVBA, PROC)
+
+  XVBA_INIT_PROC(QueryExtension);
+  XVBA_INIT_PROC(CreateContext);
+  XVBA_INIT_PROC(DestroyContext);
+  XVBA_INIT_PROC(GetSessionInfo);
+  XVBA_INIT_PROC(CreateSurface);
+  XVBA_INIT_PROC(CreateGLSharedSurface);
+  XVBA_INIT_PROC(DestroySurface);
+  XVBA_INIT_PROC(CreateDecodeBuffers);
+  XVBA_INIT_PROC(DestroyDecodeBuffers);
+  XVBA_INIT_PROC(GetCapDecode);
+  XVBA_INIT_PROC(CreateDecode);
+  XVBA_INIT_PROC(DestroyDecode);
+  XVBA_INIT_PROC(StartDecodePicture);
+  XVBA_INIT_PROC(DecodePicture);
+  XVBA_INIT_PROC(EndDecodePicture);
+  XVBA_INIT_PROC(SyncSurface);
+  XVBA_INIT_PROC(GetSurface);
+  XVBA_INIT_PROC(TransferSurface);
+
+#undef XVBA_INIT_PROC
+#undef INIT_PROC
+
+  return true;
+}
+
+bool CXVBAContext::CreateContext()
+{
+  if (m_xvbaContext)
+    return true;
+
+  CLog::Log(LOGNOTICE,"XVBA::CreateContext - creating decoder context");
+
+  Drawable window;
+  { CSingleLock lock(g_graphicsContext);
+    if (!m_display)
+      m_display = XOpenDisplay(NULL);
+    window = 0;
+  }
+
+  int version;
+  if (!g_XVBA_vtable.QueryExtension(m_display, &version))
+    return false;
+  CLog::Log(LOGNOTICE,"XVBA::CreateContext - opening xvba version: %i", version);
+
+  // create XVBA Context
+  XVBA_Create_Context_Input contextInput;
+  XVBA_Create_Context_Output contextOutput;
+  contextInput.size = sizeof(contextInput);
+  contextInput.display = m_display;
+  contextInput.draw = window;
+  contextOutput.size = sizeof(contextOutput);
+  if(Success != g_XVBA_vtable.CreateContext(&contextInput, &contextOutput))
+  {
+    CLog::Log(LOGERROR,"XVBA::CreateContext - failed to create context");
+    return false;
+  }
+  m_xvbaContext = contextOutput.context;
+
+  return true;
+}
+
+void CXVBAContext::DestroyContext()
+{
+  if (!m_xvbaContext)
+    return;
+
+  g_XVBA_vtable.DestroyContext(m_xvbaContext);
+  m_xvbaContext = 0;
+//  XCloseDisplay(m_display);
+}
+
+void *CXVBAContext::GetContext()
+{
+  return m_xvbaContext;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+
+static unsigned int decoderId = 0;
+
+CDecoder::CDecoder() : m_xvbaOutput(&m_inMsgEvent)
+{
+  m_xvbaConfig.context = 0;
+  m_xvbaConfig.xvbaSession = 0;
+  m_xvbaConfig.videoSurfaces = &m_videoSurfaces;
+  m_xvbaConfig.videoSurfaceSec = &m_videoSurfaceSec;
+  m_xvbaConfig.apiSec = &m_apiSec;
+
+  m_displayState = XVBA_OPEN;
+}
+
+CDecoder::~CDecoder()
+{
+  Close();
+}
+
+typedef struct {
+    unsigned int  size;
+    unsigned int  num_of_decodecaps;
+    XVBADecodeCap decode_caps_list[];
+} XVBA_GetCapDecode_Output_Base;
+
+void CDecoder::OnLostDevice()
+{
+  CLog::Log(LOGNOTICE,"XVBA::OnLostDevice event");
+
+  CSingleLock lock(m_decoderSection);
+  DestroySession();
+  if (m_xvbaConfig.context)
+    m_xvbaConfig.context->Release();
+  m_xvbaConfig.context = 0;
+
+  m_displayState = XVBA_LOST;
+  m_displayEvent.Reset();
+}
+
+void CDecoder::OnResetDevice()
+{
+  CLog::Log(LOGNOTICE,"XVBA::OnResetDevice event");
+
+  CSingleLock lock(m_decoderSection);
+  if (m_displayState == XVBA_LOST)
+  {
+    m_displayState = XVBA_RESET;
+    lock.Leave();
+    m_displayEvent.Set();
+  }
+}
+
+bool CDecoder::Open(AVCodecContext* avctx, const enum PixelFormat fmt, unsigned int surfaces)
+{
+  std::string Vendor = g_Windowing.GetRenderVendor();
+  std::transform(Vendor.begin(), Vendor.end(), Vendor.begin(), ::tolower);
+  if (Vendor.compare(0, 3, "ati") != 0)
+  {
+    return false;
+  }
+
+  m_decoderId = decoderId++;
+
+  CLog::Log(LOGNOTICE,"(XVBA::Open) opening xvba decoder, id: %d", m_decoderId);
+
+  if(avctx->coded_width  == 0
+  || avctx->coded_height == 0)
+  {
+    CLog::Log(LOGWARNING,"(XVBA) no width/height available, can't init");
+    return false;
+  }
+
+  if (!m_dllAvUtil.Load())
+    return false;
+
+  if (!CXVBAContext::EnsureContext(&m_xvbaConfig.context))
+    return false;
+
+  // xvba get session info
+  XVBA_GetSessionInfo_Input sessionInput;
+  XVBA_GetSessionInfo_Output sessionOutput;
+  sessionInput.size = sizeof(sessionInput);
+  sessionInput.context = m_xvbaConfig.context->GetContext();
+  sessionOutput.size = sizeof(sessionOutput);
+  if (Success != g_XVBA_vtable.GetSessionInfo(&sessionInput, &sessionOutput))
+  {
+    CLog::Log(LOGERROR,"(XVBA) can't get session info");
+    return false;
+  }
+  if (sessionOutput.getcapdecode_output_size == 0)
+  {
+    CLog::Log(LOGERROR,"(XVBA) session decode not supported");
+    return false;
+  }
+
+  // get decoder capabilities
+  XVBA_GetCapDecode_Input capInput;
+  XVBA_GetCapDecode_Output *capOutput;
+  capInput.size = sizeof(capInput);
+  capInput.context = m_xvbaConfig.context->GetContext();
+  capOutput = (XVBA_GetCapDecode_Output *)calloc(sessionOutput.getcapdecode_output_size, 1);
+  capOutput->size = sessionOutput.getcapdecode_output_size;
+  if (Success != g_XVBA_vtable.GetCapDecode(&capInput, capOutput))
+  {
+    CLog::Log(LOGERROR,"(XVBA) can't get decode capabilities");
+    return false;
+  }
+
+  int match = -1;
+  if (avctx->codec_id == CODEC_ID_H264)
+  {
+    // search for profile high
+    for (unsigned int i = 0; i < capOutput->num_of_decodecaps; ++i)
+    {
+      if (capOutput->decode_caps_list[i].capability_id == XVBA_H264 &&
+          capOutput->decode_caps_list[i].flags == XVBA_H264_HIGH)
+      {
+        match = (int) i;
+        break;
+      }
+    }
+    if (match < 0)
+    {
+      CLog::Log(LOGNOTICE, "(XVBA::Open) - profile XVBA_H264_HIGH not found");
+    }
+  }
+  else if (avctx->codec_id == CODEC_ID_VC1)
+  {
+    // search for profile advanced
+    for (unsigned int i = 0; i < capOutput->num_of_decodecaps; ++i)
+    {
+      if (capOutput->decode_caps_list[i].capability_id == XVBA_VC1 &&
+          capOutput->decode_caps_list[i].flags == XVBA_VC1_ADVANCED)
+      {
+        match = (int) i;
+        break;
+      }
+    }
+    if (match < 0)
+    {
+      CLog::Log(LOGNOTICE, "(XVBA::Open) - profile XVBA_VC1_ADVANCED not found");
+    }
+  }
+  else if (avctx->codec_id == CODEC_ID_MPEG2VIDEO)
+  {
+    // search for profile high
+    for (unsigned int i = 0; i < capOutput->num_of_decodecaps; ++i)
+    {
+      if (capOutput->decode_caps_list[i].capability_id == XVBA_MPEG2_VLD)
+      {
+        // XXX: uncomment when implemented
+        // match = (int) i;
+        // break;
+      }
+    }
+    if (match < 0)
+    {
+      CLog::Log(LOGNOTICE, "(XVBA::Open) - profile XVBA_MPEG2_VLD not found");
+    }
+  }
+  else if (avctx->codec_id == CODEC_ID_WMV3)
+  {
+    // search for profile high
+    for (unsigned int i = 0; i < capOutput->num_of_decodecaps; ++i)
+    {
+      if (capOutput->decode_caps_list[i].capability_id == XVBA_VC1 &&
+          capOutput->decode_caps_list[i].flags == XVBA_VC1_MAIN)
+      {
+        match = (int) i;
+        break;
+      }
+    }
+    if (match < 0)
+    {
+      CLog::Log(LOGNOTICE, "(XVBA::Open) - profile XVBA_VC1_MAIN not found");
+    }
+  }
+
+  if (match < 0)
+  {
+    free(capOutput);
+    return false;
+  }
+
+  CLog::Log(LOGNOTICE,"(XVBA) using decoder capability id: %i flags: %i",
+                          capOutput->decode_caps_list[match].capability_id,
+                          capOutput->decode_caps_list[match].flags);
+  CLog::Log(LOGNOTICE,"(XVBA) using surface type: %x",
+                          capOutput->decode_caps_list[match].surface_type);
+
+  m_xvbaConfig.decoderCap = capOutput->decode_caps_list[match];
+
+  free(capOutput);
+
+  // set some varables
+  m_xvbaConfig.xvbaSession = 0;
+  m_xvbaBufferPool.data_buffer = 0;
+  m_xvbaBufferPool.iq_matrix_buffer = 0;
+  m_xvbaBufferPool.picture_descriptor_buffer = 0;
+  m_presentPicture = 0;
+  m_xvbaConfig.numRenderBuffers = surfaces;
+  m_decoderThread = CThread::GetCurrentThreadId();
+  m_speed = DVD_PLAYSPEED_NORMAL;
+
+  if (1) //g_guiSettings.GetBool("videoplayer.usexvbasharedsurface"))
+    m_xvbaConfig.useSharedSurfaces = true;
+  else
+    m_xvbaConfig.useSharedSurfaces = false;
+
+  m_displayState = XVBA_OPEN;
+
+  // setup ffmpeg
+  avctx->thread_count    = 1;
+  avctx->get_buffer      = CDecoder::FFGetBuffer;
+  avctx->release_buffer  = CDecoder::FFReleaseBuffer;
+  avctx->draw_horiz_band = CDecoder::FFDrawSlice;
+  avctx->slice_flags     = SLICE_FLAG_CODED_ORDER|SLICE_FLAG_ALLOW_FIELD;
+
+  g_Windowing.Register(this);
+  return true;
+}
+
+void CDecoder::Close()
+{
+  CLog::Log(LOGNOTICE, "XVBA::Close - closing decoder, id: %d", m_decoderId);
+
+  if (!m_xvbaConfig.context)
+    return;
+
+  DestroySession();
+  if (m_xvbaConfig.context)
+    m_xvbaConfig.context->Release();
+  m_xvbaConfig.context = 0;
+
+  while (!m_videoSurfaces.empty())
+  {
+    xvba_render_state *render = m_videoSurfaces.back();
+    if(render->buffers_alllocated > 0)
+      m_dllAvUtil.av_free(render->buffers);
+    m_videoSurfaces.pop_back();
+    free(render);
+  }
+
+  g_Windowing.Unregister(this);
+  m_dllAvUtil.Unload();
+}
+
+long CDecoder::Release()
+{
+  // check if we should do some pre-cleanup here
+  // a second decoder might need resources
+  if (m_xvbaConfig.xvbaSession)
+  {
+    CSingleLock lock(m_decoderSection);
+    CLog::Log(LOGNOTICE,"XVBA::Release pre-cleanup");
+    DestroySession(true);
+  }
+  return IHardwareDecoder::Release();
+}
+
+long CDecoder::ReleasePicReference()
+{
+  return IHardwareDecoder::Release();
+}
+
+bool CDecoder::Supports(EINTERLACEMETHOD method)
+{
+  if(method == VS_INTERLACEMETHOD_AUTO)
+    return true;
+
+  if (1) //g_guiSettings.GetBool("videoplayer.usexvbasharedsurface"))
+  {
+    if (method == VS_INTERLACEMETHOD_XVBA)
+      return true;
+  }
+
+  return false;
+}
+
+void CDecoder::ResetState()
+{
+  m_displayState = XVBA_OPEN;
+}
+
+int CDecoder::Check(AVCodecContext* avctx)
+{
+  EDisplayState state;
+
+  { CSingleLock lock(m_decoderSection);
+    state = m_displayState;
+  }
+
+  if (state == XVBA_LOST)
+  {
+    CLog::Log(LOGNOTICE,"XVBA::Check waiting for display reset event");
+    if (!m_displayEvent.WaitMSec(2000))
+    {
+      CLog::Log(LOGERROR, "XVBA::Check - device didn't reset in reasonable time");
+      state = XVBA_RESET;;
+    }
+    else
+    { CSingleLock lock(m_decoderSection);
+      state = m_displayState;
+    }
+  }
+  if (state == XVBA_RESET || state == XVBA_ERROR)
+  {
+    CLog::Log(LOGNOTICE,"XVBA::Check - Attempting recovery");
+
+    CSingleLock gLock(g_graphicsContext);
+    CSingleLock lock(m_decoderSection);
+
+    DestroySession();
+    ResetState();
+    CXVBAContext::EnsureContext(&m_xvbaConfig.context);
+
+    if (state == XVBA_RESET)
+      return VC_FLUSHED;
+    else
+      return VC_ERROR;
+  }
+  return 0;
+}
+
+void CDecoder::SetError(const char* function, const char* msg, int line)
+{
+  CLog::Log(LOGERROR, "XVBA::%s - %s, line %d", function, msg, line);
+  CSingleLock lock(m_decoderSection);
+  m_displayState = XVBA_ERROR;
+}
+
+bool CDecoder::CreateSession(AVCodecContext* avctx)
+{
+  m_xvbaConfig.surfaceWidth = (avctx->coded_width+15) & ~15;
+  m_xvbaConfig.surfaceHeight = (avctx->coded_height+15) & ~15;
+
+  m_xvbaConfig.vidWidth = avctx->width;
+  m_xvbaConfig.vidHeight = avctx->height;
+
+  XVBA_Create_Decode_Session_Input sessionInput;
+  XVBA_Create_Decode_Session_Output sessionOutput;
+
+  sessionInput.size = sizeof(sessionInput);
+  sessionInput.width = m_xvbaConfig.surfaceWidth;
+  sessionInput.height = m_xvbaConfig.surfaceHeight;
+  sessionInput.context = m_xvbaConfig.context->GetContext();
+  sessionInput.decode_cap = &m_xvbaConfig.decoderCap;
+  sessionOutput.size = sizeof(sessionOutput);
+
+  if (Success != g_XVBA_vtable.CreateDecode(&sessionInput, &sessionOutput))
+  {
+    SetError(__FUNCTION__, "failed to create decoder session", __LINE__);
+    CLog::Log(LOGERROR, "Decoder failed with following stats: m_surfaceWidth %u, m_surfaceHeight %u,"
+                        " m_vidWidth %u, m_vidHeight %u, coded_width %d, coded_height %d",
+                        m_xvbaConfig.surfaceWidth,
+                        m_xvbaConfig.surfaceHeight,
+                        m_xvbaConfig.vidWidth,
+                        m_xvbaConfig.vidHeight,
+                        avctx->coded_width,
+                        avctx->coded_height);
+    return false;
+  }
+  m_xvbaConfig.xvbaSession = sessionOutput.session;
+
+  // create decode buffers
+  XVBA_Create_DecodeBuff_Input bufferInput;
+  XVBA_Create_DecodeBuff_Output bufferOutput;
+
+  bufferInput.size = sizeof(bufferInput);
+  bufferInput.session = m_xvbaConfig.xvbaSession;
+  bufferInput.buffer_type = XVBA_PICTURE_DESCRIPTION_BUFFER;
+  bufferInput.num_of_buffers = 1;
+  bufferOutput.size = sizeof(bufferOutput);
+  if (Success != g_XVBA_vtable.CreateDecodeBuffers(&bufferInput, &bufferOutput)
+      || bufferOutput.num_of_buffers_in_list != 1)
+  {
+    SetError(__FUNCTION__, "failed to create picture buffer", __LINE__);
+    return false;
+  }
+  m_xvbaBufferPool.picture_descriptor_buffer = bufferOutput.buffer_list;
+
+  // data buffer
+  bufferInput.buffer_type = XVBA_DATA_BUFFER;
+  if (Success != g_XVBA_vtable.CreateDecodeBuffers(&bufferInput, &bufferOutput)
+      || bufferOutput.num_of_buffers_in_list != 1)
+  {
+    SetError(__FUNCTION__, "failed to create data buffer", __LINE__);
+    return false;
+  }
+  m_xvbaBufferPool.data_buffer = bufferOutput.buffer_list;
+
+  // QO Buffer
+  bufferInput.buffer_type = XVBA_QM_BUFFER;
+  if (Success != g_XVBA_vtable.CreateDecodeBuffers(&bufferInput, &bufferOutput)
+      || bufferOutput.num_of_buffers_in_list != 1)
+  {
+    SetError(__FUNCTION__, "failed to create qm buffer", __LINE__);
+    return false;
+  }
+  m_xvbaBufferPool.iq_matrix_buffer = bufferOutput.buffer_list;
+
+
+  // initialize output
+  CSingleLock lock(g_graphicsContext);
+  m_xvbaConfig.stats = &m_bufferStats;
+  m_bufferStats.Reset();
+  m_xvbaOutput.Start();
+  Message *reply;
+  if (m_xvbaOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::INIT,
+                                                 &reply,
+                                                 2000,
+                                                 &m_xvbaConfig,
+                                                 sizeof(m_xvbaConfig)))
+  {
+    bool success = reply->signal == COutputControlProtocol::ACC ? true : false;
+    reply->Release();
+    if (!success)
+    {
+      CLog::Log(LOGERROR, "XVBA::%s - vdpau output returned error", __FUNCTION__);
+      m_xvbaOutput.Dispose();
+      return false;
+    }
+  }
+  else
+  {
+    CLog::Log(LOGERROR, "XVBA::%s - failed to init output", __FUNCTION__);
+    m_xvbaOutput.Dispose();
+    return false;
+  }
+  m_inMsgEvent.Reset();
+
+  return true;
+}
+
+void CDecoder::DestroySession(bool precleanup /*= false*/)
+{
+  // wait for unfinished decoding jobs
+  XbmcThreads::EndTime timer;
+  if (m_xvbaConfig.xvbaSession)
+  {
+    for (unsigned int i = 0; i < m_videoSurfaces.size(); ++i)
+    {
+      xvba_render_state *render = m_videoSurfaces[i];
+      if (render->surface)
+      {
+        XVBA_Surface_Sync_Input syncInput;
+        XVBA_Surface_Sync_Output syncOutput;
+        syncInput.size = sizeof(syncInput);
+        syncInput.session = m_xvbaConfig.xvbaSession;
+        syncInput.surface = render->surface;
+        syncInput.query_status = XVBA_GET_SURFACE_STATUS;
+        syncOutput.size = sizeof(syncOutput);
+        timer.Set(1000);
+        while(!timer.IsTimePast())
+        {
+          if (Success != g_XVBA_vtable.SyncSurface(&syncInput, &syncOutput))
+          {
+            CLog::Log(LOGERROR,"XVBA::DestroySession - failed sync surface");
+            break;
+          }
+          if (!(syncOutput.status_flags & XVBA_STILL_PENDING))
+            break;
+          Sleep(10);
+        }
+        if (timer.IsTimePast())
+          CLog::Log(LOGERROR,"XVBA::DestroySession - unfinished decoding job");
+      }
+    }
+  }
+
+  if (precleanup)
+  {
+    Message *reply;
+    if (m_xvbaOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::PRECLEANUP,
+                                                   &reply,
+                                                   2000))
+    {
+      bool success = reply->signal == COutputControlProtocol::ACC ? true : false;
+      reply->Release();
+      if (!success)
+      {
+        CLog::Log(LOGERROR, "XVBA::%s - pre-cleanup returned error", __FUNCTION__);
+        m_displayState = XVBA_ERROR;
+      }
+    }
+    else
+    {
+      CLog::Log(LOGERROR, "XVBA::%s - pre-cleanup timed out", __FUNCTION__);
+      m_displayState = XVBA_ERROR;
+    }
+  }
+  else
+    m_xvbaOutput.Dispose();
+
+  XVBA_Destroy_Decode_Buffers_Input bufInput;
+  bufInput.size = sizeof(bufInput);
+  bufInput.num_of_buffers_in_list = 1;
+  bufInput.session = m_xvbaConfig.xvbaSession;
+
+  for (unsigned int i=0; i<m_xvbaBufferPool.data_control_buffers.size() ; ++i)
+  {
+    bufInput.buffer_list = m_xvbaBufferPool.data_control_buffers[i];
+    g_XVBA_vtable.DestroyDecodeBuffers(&bufInput);
+  }
+  m_xvbaBufferPool.data_control_buffers.clear();
+
+  if (m_xvbaConfig.xvbaSession && m_xvbaBufferPool.data_buffer)
+  {
+    bufInput.buffer_list = m_xvbaBufferPool.data_buffer;
+    g_XVBA_vtable.DestroyDecodeBuffers(&bufInput);
+  }
+  m_xvbaBufferPool.data_buffer = 0;
+
+  if (m_xvbaConfig.xvbaSession && m_xvbaBufferPool.picture_descriptor_buffer)
+  {
+    bufInput.buffer_list = m_xvbaBufferPool.picture_descriptor_buffer;
+    g_XVBA_vtable.DestroyDecodeBuffers(&bufInput);
+  }
+  m_xvbaBufferPool.picture_descriptor_buffer = 0;
+
+  if (m_xvbaConfig.xvbaSession && m_xvbaBufferPool.iq_matrix_buffer)
+  {
+    bufInput.buffer_list = m_xvbaBufferPool.iq_matrix_buffer;
+    g_XVBA_vtable.DestroyDecodeBuffers(&bufInput);
+  }
+  m_xvbaBufferPool.iq_matrix_buffer = 0;
+
+  for (unsigned int i = 0; i < m_videoSurfaces.size(); ++i)
+  {
+    xvba_render_state *render = m_videoSurfaces[i];
+    if (m_xvbaConfig.xvbaSession && render->surface)
+    {
+      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; i<missing; ++i)
+  {
+    { CSingleLock lock(m_apiSec);
+      if (Success != g_XVBA_vtable.CreateDecodeBuffers(&bufferInput, &bufferOutput)
+          || bufferOutput.num_of_buffers_in_list != 1)
+      {
+        SetError(__FUNCTION__, "failed to create data control buffer", __LINE__);
+        return false;
+      }
+    }
+    m_xvbaBufferPool.data_control_buffers.push_back(bufferOutput.buffer_list);
+  }
+
+  return true;
+}
+
+void CDecoder::FFReleaseBuffer(AVCodecContext *avctx, AVFrame *pic)
+{
+  CDVDVideoCodecFFmpeg* ctx   = (CDVDVideoCodecFFmpeg*)avctx->opaque;
+  CDecoder*             xvba  = (CDecoder*)ctx->GetHardware();
+  unsigned int i;
+
+  CSingleLock lock(xvba->m_decoderSection);
+
+  xvba_render_state * render = NULL;
+  render = (xvba_render_state*)pic->data[0];
+  if(!render)
+  {
+    CLog::Log(LOGERROR, "XVBA::FFReleaseBuffer - invalid context handle provided");
+    return;
+  }
+
+  for(i=0; i<4; i++)
+    pic->data[i]= NULL;
+
+  // find render state in queue
+  if (!xvba->IsSurfaceValid(render))
+  {
+    CLog::Log(LOGDEBUG, "XVBA::FFReleaseBuffer - ignoring invalid buffer");
+    return;
+  }
+
+  render->state &= ~FF_XVBA_STATE_USED_FOR_REFERENCE;
+}
+
+void CDecoder::FFDrawSlice(struct AVCodecContext *avctx,
+                             const AVFrame *src, int offset[4],
+                             int y, int type, int height)
+{
+  CDVDVideoCodecFFmpeg* ctx   = (CDVDVideoCodecFFmpeg*)avctx->opaque;
+  CDecoder*             xvba  = (CDecoder*)ctx->GetHardware();
+
+  CSingleLock lock(xvba->m_decoderSection);
+
+  if(xvba->m_displayState != XVBA_OPEN)
+    return;
+
+  if(src->linesize[0] || src->linesize[1] || src->linesize[2]
+    || offset[0] || offset[1] || offset[2])
+  {
+    CLog::Log(LOGERROR, "XVBA::FFDrawSlice - invalid linesizes or offsets provided");
+    return;
+  }
+
+  xvba_render_state * render;
+
+  render = (xvba_render_state*)src->data[0];
+  if(!render)
+  {
+    CLog::Log(LOGERROR, "XVBA::FFDrawSlice - invalid context handle provided");
+    return;
+  }
+
+  // ffmpeg vc-1 decoder does not flush, make sure the data buffer is still valid
+  if (!xvba->IsSurfaceValid(render))
+  {
+    CLog::Log(LOGWARNING, "XVBA::FFDrawSlice - ignoring invalid buffer");
+    return;
+  }
+
+  // decoding
+  XVBA_Decode_Picture_Start_Input startInput;
+  startInput.size = sizeof(startInput);
+  startInput.session = xvba->m_xvbaConfig.xvbaSession;
+  startInput.target_surface = render->surface;
+  { CSingleLock lock(xvba->m_apiSec);
+    if (Success != g_XVBA_vtable.StartDecodePicture(&startInput))
+    {
+      xvba->SetError(__FUNCTION__, "failed to start decoding", __LINE__);
+      return;
+    }
+  }
+
+  XVBA_Decode_Picture_Input picInput;
+  picInput.size = sizeof(picInput);
+  picInput.session = xvba->m_xvbaConfig.xvbaSession;
+  XVBABufferDescriptor *list[2];
+  picInput.buffer_list = list;
+  list[0] = xvba->m_xvbaBufferPool.picture_descriptor_buffer;
+  picInput.num_of_buffers_in_list = 1;
+  if (avctx->codec_id == CODEC_ID_H264)
+  {
+    list[1] = xvba->m_xvbaBufferPool.iq_matrix_buffer;
+    picInput.num_of_buffers_in_list = 2;
+  }
+
+  { CSingleLock lock(xvba->m_apiSec);
+    if (Success != g_XVBA_vtable.DecodePicture(&picInput))
+    {
+      xvba->SetError(__FUNCTION__, "failed to decode picture 1", __LINE__);
+      return;
+    }
+  }
+
+  if (!xvba->EnsureDataControlBuffers(render->num_slices))
+    return;
+
+  XVBADataCtrl *dataControl;
+  int location = 0;
+  xvba->m_xvbaBufferPool.data_buffer->data_size_in_buffer = 0;
+  for (unsigned int j = 0; j < render->num_slices; ++j)
+  {
+    int startCodeSize = 0;
+    uint8_t startCode[] = {0x00,0x00,0x01};
+    if (avctx->codec_id == CODEC_ID_H264)
+    {
+      startCodeSize = 3;
+      memcpy((uint8_t*)xvba->m_xvbaBufferPool.data_buffer->bufferXVBA+location,
+          startCode, 3);
+    }
+    else if (avctx->codec_id == CODEC_ID_VC1 &&
+        (memcmp(render->buffers[j].buffer, startCode, 3) != 0))
+    {
+      startCodeSize = 4;
+      uint8_t sdf = 0x0d;
+      memcpy((uint8_t*)xvba->m_xvbaBufferPool.data_buffer->bufferXVBA+location,
+          startCode, 3);
+      memcpy((uint8_t*)xvba->m_xvbaBufferPool.data_buffer->bufferXVBA+location+3,
+          &sdf, 1);
+    }
+    // check for potential buffer overwrite
+    unsigned int bytesToCopy = render->buffers[j].size;
+    unsigned int freeBufferSize = xvba->m_xvbaBufferPool.data_buffer->buffer_size -
+        xvba->m_xvbaBufferPool.data_buffer->data_size_in_buffer;
+    if (bytesToCopy >= freeBufferSize)
+    {
+      xvba->SetError(__FUNCTION__, "bitstream buffer too large, maybe corrupted packet", __LINE__);
+      return;
+    }
+    memcpy((uint8_t*)xvba->m_xvbaBufferPool.data_buffer->bufferXVBA+location+startCodeSize,
+        render->buffers[j].buffer,
+        render->buffers[j].size);
+    dataControl = (XVBADataCtrl*)xvba->m_xvbaBufferPool.data_control_buffers[j]->bufferXVBA;
+    dataControl->SliceDataLocation = location;
+    dataControl->SliceBytesInBuffer = render->buffers[j].size+startCodeSize;
+    dataControl->SliceBitsInBuffer = dataControl->SliceBytesInBuffer * 8;
+    xvba->m_xvbaBufferPool.data_buffer->data_size_in_buffer += dataControl->SliceBytesInBuffer;
+    location += dataControl->SliceBytesInBuffer;
+  }
+
+  int bufSize = xvba->m_xvbaBufferPool.data_buffer->data_size_in_buffer;
+  int padding = bufSize % 128;
+  if (padding)
+  {
+    padding = 128 - padding;
+    xvba->m_xvbaBufferPool.data_buffer->data_size_in_buffer += padding;
+    memset((uint8_t*)xvba->m_xvbaBufferPool.data_buffer->bufferXVBA+bufSize,0,padding);
+  }
+
+  picInput.num_of_buffers_in_list = 2;
+  for (unsigned int i = 0; i < render->num_slices; ++i)
+  {
+    list[0] = xvba->m_xvbaBufferPool.data_buffer;
+    list[0]->data_offset = 0;
+    list[1] = xvba->m_xvbaBufferPool.data_control_buffers[i];
+    list[1]->data_size_in_buffer = sizeof(*dataControl);
+    { CSingleLock lock(xvba->m_apiSec);
+      if (Success != g_XVBA_vtable.DecodePicture(&picInput))
+      {
+        xvba->SetError(__FUNCTION__, "failed to decode picture 2", __LINE__);
+        return;
+      }
+    }
+  }
+  XVBA_Decode_Picture_End_Input endInput;
+  endInput.size = sizeof(endInput);
+  endInput.session = xvba->m_xvbaConfig.xvbaSession;
+  { CSingleLock lock(xvba->m_apiSec);
+    if (Success != g_XVBA_vtable.EndDecodePicture(&endInput))
+    {
+      xvba->SetError(__FUNCTION__, "failed to decode picture 3", __LINE__);
+      return;
+    }
+  }
+
+  // decode sync and error
+  XVBA_Surface_Sync_Input syncInput;
+  XVBA_Surface_Sync_Output syncOutput;
+  syncInput.size = sizeof(syncInput);
+  syncInput.session = xvba->m_xvbaConfig.xvbaSession;
+  syncInput.surface = render->surface;
+  syncInput.query_status = XVBA_GET_SURFACE_STATUS;
+  syncOutput.size = sizeof(syncOutput);
+  int64_t start = CurrentHostCounter();
+  while (1)
+  {
+    { CSingleLock lock(xvba->m_apiSec);
+      if (Success != g_XVBA_vtable.SyncSurface(&syncInput, &syncOutput))
+      {
+        xvba->SetError(__FUNCTION__, "failed sync surface 1", __LINE__);
+        return;
+      }
+    }
+    if (!(syncOutput.status_flags & XVBA_STILL_PENDING))
+      break;
+    if (CurrentHostCounter() - start > CurrentHostFrequency())
+    {
+      xvba->SetError(__FUNCTION__, "timed out waiting for surface", __LINE__);
+      break;
+    }
+    usleep(100);
+  }
+  render->state |= FF_XVBA_STATE_DECODED;
+}
+
+int CDecoder::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic)
+{
+  CDVDVideoCodecFFmpeg* ctx   = (CDVDVideoCodecFFmpeg*)avctx->opaque;
+  CDecoder*             xvba  = (CDecoder*)ctx->GetHardware();
+
+  pic->data[0] =
+  pic->data[1] =
+  pic->data[2] =
+  pic->data[3] = 0;
+
+  pic->linesize[0] =
+  pic->linesize[1] =
+  pic->linesize[2] =
+  pic->linesize[3] = 0;
+
+  CSingleLock lock(xvba->m_decoderSection);
+
+  if(xvba->m_displayState != XVBA_OPEN)
+    return -1;
+
+  if (xvba->m_xvbaConfig.xvbaSession == 0)
+  {
+    if (!xvba->CreateSession(avctx))
+      return -1;
+  }
+
+  xvba_render_state * render = NULL;
+  // find unused surface
+  { CSingleLock lock(xvba->m_videoSurfaceSec);
+    for(unsigned int i = 0; i < xvba->m_videoSurfaces.size(); ++i)
+    {
+      if(!(xvba->m_videoSurfaces[i]->state & (FF_XVBA_STATE_USED_FOR_REFERENCE | FF_XVBA_STATE_USED_FOR_RENDER)))
+      {
+        render = xvba->m_videoSurfaces[i];
+        render->state = 0;
+        break;
+      }
+    }
+  }
+
+  // create a new render state
+  if (render == NULL)
+  {
+    render = (xvba_render_state*)calloc(sizeof(xvba_render_state), 1);
+    if (render == NULL)
+    {
+      CLog::Log(LOGERROR, "XVBA::FFGetBuffer - calloc failed");
+      return -1;
+    }
+    render->surface = 0;
+    render->buffers_alllocated = 0;
+    CSingleLock lock(xvba->m_videoSurfaceSec);
+    xvba->m_videoSurfaces.push_back(render);
+  }
+
+  // create a new surface
+  if (render->surface == 0)
+  {
+    XVBA_Create_Surface_Input surfaceInput;
+    XVBA_Create_Surface_Output surfaceOutput;
+    surfaceInput.size = sizeof(surfaceInput);
+    surfaceInput.surface_type = xvba->m_xvbaConfig.decoderCap.surface_type;
+    surfaceInput.width = xvba->m_xvbaConfig.surfaceWidth;
+    surfaceInput.height = xvba->m_xvbaConfig.surfaceHeight;
+    surfaceInput.session = xvba->m_xvbaConfig.xvbaSession;
+    surfaceOutput.size = sizeof(surfaceOutput);
+    { CSingleLock lock(xvba->m_apiSec);
+      if (Success != g_XVBA_vtable.CreateSurface(&surfaceInput, &surfaceOutput))
+      {
+        xvba->SetError(__FUNCTION__, "failed to create video surface", __LINE__);
+        return -1;
+      }
+    }
+    render->surface = surfaceOutput.surface;
+    render->picture_descriptor = (XVBAPictureDescriptor *)xvba->m_xvbaBufferPool.picture_descriptor_buffer->bufferXVBA;
+    render->iq_matrix = (XVBAQuantMatrixAvc *)xvba->m_xvbaBufferPool.iq_matrix_buffer->bufferXVBA;
+    CLog::Log(LOGDEBUG, "XVBA::FFGetBuffer - created video surface");
+  }
+
+  if (render == NULL)
+    return -1;
+
+  pic->data[0] = (uint8_t*)render;
+
+  pic->type= FF_BUFFER_TYPE_USER;
+
+  render->state |= FF_XVBA_STATE_USED_FOR_REFERENCE;
+  render->state &= ~FF_XVBA_STATE_DECODED;
+  pic->reordered_opaque= avctx->reordered_opaque;
+
+  return 0;
+}
+
+int CDecoder::Decode(AVCodecContext* avctx, AVFrame* frame)
+{
+  int result = Check(avctx);
+  if (result)
+    return result;
+
+  CSingleLock lock(m_decoderSection);
+
+  if(frame)
+  { // we have a new frame from decoder
+
+    xvba_render_state * render = (xvba_render_state*)frame->data[0];
+    if(!render)
+    {
+      CLog::Log(LOGERROR, "XVBA::Decode - no render buffer");
+      return VC_ERROR;
+    }
+
+    // ffmpeg vc-1 decoder does not flush, make sure the data buffer is still valid
+    if (!IsSurfaceValid(render))
+    {
+      CLog::Log(LOGWARNING, "XVBA::Decode - ignoring invalid buffer");
+      return VC_BUFFER;
+    }
+    if (!(render->state & FF_XVBA_STATE_DECODED))
+    {
+      CLog::Log(LOGDEBUG, "XVBA::Decode - ffmpeg failed");
+      return VC_BUFFER;
+    }
+
+    CSingleLock lock(m_videoSurfaceSec);
+    render->state |= FF_XVBA_STATE_USED_FOR_RENDER;
+    lock.Leave();
+
+    // send frame to output for processing
+    CXvbaDecodedPicture pic;
+    memset(&pic.DVDPic, 0, sizeof(pic.DVDPic));
+    ((CDVDVideoCodecFFmpeg*)avctx->opaque)->GetPictureCommon(&pic.DVDPic);
+    pic.render = render;
+    m_bufferStats.IncDecoded();
+    m_xvbaOutput.m_dataPort.SendOutMessage(COutputDataProtocol::NEWFRAME, &pic, sizeof(pic));
+
+    m_codecControl = pic.DVDPic.iFlags & (DVP_FLAG_DRAIN | DVP_FLAG_NO_POSTPROC);
+  }
+
+  int retval = 0;
+  uint16_t decoded, processed, render;
+  Message *msg;
+  while (m_xvbaOutput.m_controlPort.ReceiveInMessage(&msg))
+  {
+    if (msg->signal == COutputControlProtocol::ERROR)
+    {
+      m_displayState = XVBA_ERROR;
+      retval |= VC_ERROR;
+    }
+    msg->Release();
+  }
+
+  m_bufferStats.Get(decoded, processed, render);
+
+  uint64_t startTime = CurrentHostCounter();
+  while (!retval)
+  {
+    if (m_xvbaOutput.m_dataPort.ReceiveInMessage(&msg))
+    {
+      if (msg->signal == COutputDataProtocol::PICTURE)
+      {
+        if (m_presentPicture)
+        {
+          m_presentPicture->ReturnUnused();
+          m_presentPicture = 0;
+        }
+
+        m_presentPicture = *(CXvbaRenderPicture**)msg->data;
+        m_presentPicture->xvba = this;
+        m_bufferStats.DecRender();
+        m_bufferStats.Get(decoded, processed, render);
+        retval |= VC_PICTURE;
+      }
+      msg->Release();
+    }
+    else if (m_xvbaOutput.m_controlPort.ReceiveInMessage(&msg))
+    {
+      if (msg->signal == COutputControlProtocol::STATS)
+      {
+        m_bufferStats.Get(decoded, processed, render);
+      }
+      else
+      {
+        m_displayState = XVBA_ERROR;
+        retval |= VC_ERROR;
+      }
+      msg->Release();
+    }
+
+    if ((m_codecControl & DVP_FLAG_DRAIN))
+    {
+      if (decoded + processed + render < 2)
+      {
+        retval |= VC_BUFFER;
+      }
+    }
+    else
+    {
+      if (decoded + processed + render < 4)
+      {
+        retval |= VC_BUFFER;
+      }
+    }
+
+    if (!retval && !m_inMsgEvent.WaitMSec(2000))
+      break;
+  }
+  uint64_t diff = CurrentHostCounter() - startTime;
+  if (retval & VC_PICTURE)
+  {
+    m_bufferStats.SetParams(diff, m_speed);
+    if (diff*1000/CurrentHostFrequency() > 50)
+      CLog::Log(LOGDEBUG,"XVBA::Decode long wait: %d", (int)((diff*1000)/CurrentHostFrequency()));
+  }
+
+  if (!retval)
+  {
+    CLog::Log(LOGERROR, "XVBA::%s - timed out waiting for output message", __FUNCTION__);
+    m_displayState = XVBA_ERROR;
+    retval |= VC_ERROR;
+  }
+
+  return retval;
+
+}
+
+bool CDecoder::GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture)
+{
+  CSingleLock lock(m_decoderSection);
+
+  if (m_displayState != XVBA_OPEN)
+    return false;
+
+  *picture = m_presentPicture->DVDPic;
+  picture->xvba = m_presentPicture;
+
+  return true;
+}
+
+void CDecoder::ReturnRenderPicture(CXvbaRenderPicture *renderPic)
+{
+  m_xvbaOutput.m_dataPort.SendOutMessage(COutputDataProtocol::RETURNPIC, &renderPic, sizeof(renderPic));
+}
+
+
+//void CDecoder::CopyYV12(int index, uint8_t *dest)
+//{
+//  CSharedLock lock(m_decoderSection);
+//
+//  { CSharedLock dLock(m_displaySection);
+//    if(m_displayState != XVBA_OPEN)
+//      return;
+//  }
+//
+//  if (!m_flipBuffer[index].outPic)
+//  {
+//    CLog::Log(LOGWARNING, "XVBA::Present: present picture is NULL");
+//    return;
+//  }
+//
+//  XVBA_GetSurface_Target target;
+//  target.size = sizeof(target);
+//  target.surfaceType = XVBA_YV12;
+//  target.flag = XVBA_FRAME;
+//
+//  XVBA_Get_Surface_Input input;
+//  input.size = sizeof(input);
+//  input.session = m_xvbaSession;
+//  input.src_surface = m_flipBuffer[index].outPic->render->surface;
+//  input.target_buffer = dest;
+//  input.target_pitch = m_surfaceWidth;
+//  input.target_width = m_surfaceWidth;
+//  input.target_height = m_surfaceHeight;
+//  input.target_parameter = target;
+//  { CSingleLock lock(m_apiSec);
+//    if (Success != g_XVBA_vtable.GetSurface(&input))
+//    {
+//      CLog::Log(LOGERROR,"(XVBA::CopyYV12) failed to get  surface");
+//    }
+//  }
+//}
+
+void CDecoder::Reset()
+{
+  CSingleLock lock(m_decoderSection);
+
+  if (!m_xvbaConfig.xvbaSession)
+    return;
+
+  Message *reply;
+  if (m_xvbaOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::FLUSH,
+                                                 &reply,
+                                                 2000))
+  {
+    bool success = reply->signal == COutputControlProtocol::ACC ? true : false;
+    reply->Release();
+    if (!success)
+    {
+      CLog::Log(LOGERROR, "XVBA::%s - flush returned error", __FUNCTION__);
+      m_displayState = XVBA_ERROR;
+    }
+    else
+      m_bufferStats.Reset();
+  }
+  else
+  {
+    CLog::Log(LOGERROR, "XVBA::%s - flush timed out", __FUNCTION__);
+    m_displayState = XVBA_ERROR;
+  }
+}
+
+bool CDecoder::CanSkipDeint()
+{
+  return m_bufferStats.CanSkipDeint();
+}
+
+void CDecoder::SetSpeed(int speed)
+{
+  m_speed = speed;
+}
+
+//-----------------------------------------------------------------------------
+// RenderPicture
+//-----------------------------------------------------------------------------
+
+CXvbaRenderPicture* CXvbaRenderPicture::Acquire()
+{
+  CSingleLock lock(*renderPicSection);
+
+  if (refCount == 0)
+    xvba->Acquire();
+
+  refCount++;
+  return this;
+}
+
+long CXvbaRenderPicture::Release()
+{
+  CSingleLock lock(*renderPicSection);
+
+  refCount--;
+  if (refCount > 0)
+    return refCount;
+
+  lock.Leave();
+  xvba->ReturnRenderPicture(this);
+  xvba->ReleasePicReference();
+
+  return refCount;
+}
+
+void CXvbaRenderPicture::ReturnUnused()
+{
+  { CSingleLock lock(*renderPicSection);
+    if (refCount > 0)
+      return;
+  }
+  if (xvba)
+    xvba->ReturnRenderPicture(this);
+}
+
+//-----------------------------------------------------------------------------
+// Output
+//-----------------------------------------------------------------------------
+COutput::COutput(CEvent *inMsgEvent) :
+  CThread("XVBA Output Thread"),
+  m_controlPort("OutputControlPort", inMsgEvent, &m_outMsgEvent),
+  m_dataPort("OutputDataPort", inMsgEvent, &m_outMsgEvent)
+{
+  m_inMsgEvent = inMsgEvent;
+
+  CXvbaRenderPicture pic;
+  pic.renderPicSection = &m_bufferPool.renderPicSec;
+  pic.refCount = 0;
+  for (unsigned int i = 0; i < NUM_RENDER_PICS; i++)
+  {
+    m_bufferPool.allRenderPics.push_back(pic);
+  }
+  for (unsigned int i = 0; i < m_bufferPool.allRenderPics.size(); ++i)
+  {
+    m_bufferPool.freeRenderPics.push_back(&m_bufferPool.allRenderPics[i]);
+  }
+}
+
+void COutput::Start()
+{
+  Create();
+}
+
+COutput::~COutput()
+{
+  Dispose();
+
+  m_bufferPool.freeRenderPics.clear();
+  m_bufferPool.usedRenderPics.clear();
+  m_bufferPool.allRenderPics.clear();
+}
+
+void COutput::Dispose()
+{
+  CSingleLock lock(g_graphicsContext);
+  m_bStop = true;
+  m_outMsgEvent.Set();
+  StopThread();
+  m_controlPort.Purge();
+  m_dataPort.Purge();
+}
+
+void COutput::OnStartup()
+{
+  CLog::Log(LOGNOTICE, "COutput::OnStartup: Output Thread created");
+}
+
+void COutput::OnExit()
+{
+  CLog::Log(LOGNOTICE, "COutput::OnExit: Output Thread terminated");
+}
+
+enum OUTPUT_STATES
+{
+  O_TOP = 0,                      // 0
+  O_TOP_ERROR,                    // 1
+  O_TOP_UNCONFIGURED,             // 2
+  O_TOP_CONFIGURED,               // 3
+  O_TOP_CONFIGURED_WAIT_RES1,     // 4
+  O_TOP_CONFIGURED_WAIT_DEC,      // 5
+  O_TOP_CONFIGURED_STEP1,         // 6
+  O_TOP_CONFIGURED_WAIT_RES2,     // 7
+  O_TOP_CONFIGURED_STEP2,         // 8
+};
+
+int OUTPUT_parentStates[] = {
+    -1,
+    0, //TOP_ERROR
+    0, //TOP_UNCONFIGURED
+    0, //TOP_CONFIGURED
+    3, //TOP_CONFIGURED_WAIT_RES1
+    3, //TOP_CONFIGURED_WAIT_DEC
+    3, //TOP_CONFIGURED_STEP1
+    3, //TOP_CONFIGURED_WAIT_RES2
+    3, //TOP_CONFIGURED_STEP2
+};
+
+void COutput::StateMachine(int signal, Protocol *port, Message *msg)
+{
+  for (int state = m_state; ; state = OUTPUT_parentStates[state])
+  {
+    switch (state)
+    {
+    case O_TOP: // TOP
+      if (port == &m_controlPort)
+      {
+        switch (signal)
+        {
+        case COutputControlProtocol::FLUSH:
+          msg->Reply(COutputControlProtocol::ACC);
+          return;
+        case COutputControlProtocol::PRECLEANUP:
+          msg->Reply(COutputControlProtocol::ACC);
+          return;
+        default:
+          break;
+        }
+      }
+      else if (port == &m_dataPort)
+      {
+        switch (signal)
+        {
+        case COutputDataProtocol::RETURNPIC:
+          CXvbaRenderPicture *pic;
+          pic = *((CXvbaRenderPicture**)msg->data);
+          ProcessReturnPicture(pic);
+          return;
+        default:
+          break;
+        }
+      }
+      {
+        std::string portName = port == NULL ? "timer" : port->portName;
+        CLog::Log(LOGWARNING, "COutput::%s - signal: %d form port: %s not handled for state: %d", __FUNCTION__, signal, portName.c_str(), m_state);
+      }
+      return;
+
+    case O_TOP_ERROR:
+      m_extTimeout = 1000;
+      break;
+
+    case O_TOP_UNCONFIGURED:
+      if (port == &m_controlPort)
+      {
+        switch (signal)
+        {
+        case COutputControlProtocol::INIT:
+          CXvbaConfig *data;
+          data = (CXvbaConfig*)msg->data;
+          if (data)
+          {
+            m_config = *data;
+          }
+          Init();
+          EnsureBufferPool();
+          if (!m_xvbaError)
+          {
+            m_state = O_TOP_CONFIGURED_WAIT_RES1;
+            msg->Reply(COutputControlProtocol::ACC);
+          }
+          else
+          {
+            m_state = O_TOP_ERROR;
+            msg->Reply(COutputControlProtocol::ERROR);
+          }
+          return;
+        default:
+          break;
+        }
+      }
+      break;
+
+    case O_TOP_CONFIGURED:
+      if (port == &m_controlPort)
+      {
+        switch (signal)
+        {
+        case COutputControlProtocol::FLUSH:
+          m_state = O_TOP_CONFIGURED_WAIT_RES1;
+          Flush();
+          msg->Reply(COutputControlProtocol::ACC);
+          return;
+        case COutputControlProtocol::PRECLEANUP:
+          m_state = O_TOP_UNCONFIGURED;
+          m_extTimeout = 10000;
+          Flush();
+          ReleaseBufferPool(true);
+          msg->Reply(COutputControlProtocol::ACC);
+          return;
+        default:
+          break;
+        }
+      }
+      else if (port == &m_dataPort)
+      {
+        switch (signal)
+        {
+        case COutputDataProtocol::NEWFRAME:
+          CXvbaDecodedPicture *frame;
+          frame = (CXvbaDecodedPicture*)msg->data;
+          if (frame)
+          {
+            m_decodedPics.push(*frame);
+            m_extTimeout = 0;
+          }
+          return;
+        case COutputDataProtocol::RETURNPIC:
+          CXvbaRenderPicture *pic;
+          pic = *((CXvbaRenderPicture**)msg->data);
+          ProcessReturnPicture(pic);
+          m_controlPort.SendInMessage(COutputControlProtocol::STATS);
+          m_extTimeout = 0;
+          return;
+        default:
+          break;
+        }
+      }
+      break;
+
+    case O_TOP_CONFIGURED_WAIT_RES1:
+      if (port == NULL) // timeout
+      {
+        switch (signal)
+        {
+        case COutputControlProtocol::TIMEOUT:
+          if (!m_decodedPics.empty() && FindFreeSurface() >= 0 && !m_bufferPool.freeRenderPics.empty())
+          {
+            m_state = O_TOP_CONFIGURED_WAIT_DEC;
+            m_bStateMachineSelfTrigger = true;
+          }
+          else
+          {
+            if (m_extTimeout != 0)
+            {
+              uint16_t decoded, processed, render;
+              m_config.stats->Get(decoded, processed, render);
+//              CLog::Log(LOGDEBUG, "CVDPAU::COutput - timeout idle: decoded: %d, proc: %d, render: %d", decoded, processed, render);
+            }
+            m_extTimeout = 100;
+          }
+          return;
+        default:
+          break;
+        }
+      }
+      break;
+
+    case O_TOP_CONFIGURED_WAIT_DEC:
+       if (port == NULL) // timeout
+       {
+         switch (signal)
+         {
+         case COutputControlProtocol::TIMEOUT:
+           if (IsDecodingFinished())
+           {
+             m_state = O_TOP_CONFIGURED_STEP1;
+             m_bStateMachineSelfTrigger = true;
+           }
+           else
+           {
+             m_extTimeout = 1;
+           }
+           return;
+         default:
+           break;
+         }
+       }
+       break;
+
+    case O_TOP_CONFIGURED_STEP1:
+      if (port == NULL) // timeout
+      {
+        switch (signal)
+        {
+        case COutputControlProtocol::TIMEOUT:
+          m_processPicture = m_decodedPics.front();
+          m_decodedPics.pop();
+          InitCycle();
+          CXvbaRenderPicture *pic;
+          pic = ProcessPicture();
+          if (pic)
+          {
+            m_config.stats->IncRender();
+            m_dataPort.SendInMessage(COutputDataProtocol::PICTURE, &pic, sizeof(pic));
+          }
+          if (m_xvbaError)
+          {
+            m_state = O_TOP_ERROR;
+            return;
+          }
+          if (m_deinterlacing && !m_deintSkip)
+          {
+            m_state = O_TOP_CONFIGURED_WAIT_RES2;
+            m_extTimeout = 0;
+          }
+          else
+          {
+            FiniCycle();
+            m_state = O_TOP_CONFIGURED_WAIT_RES1;
+            m_extTimeout = 0;
+          }
+          return;
+        default:
+          break;
+        }
+      }
+      break;
+
+    case O_TOP_CONFIGURED_WAIT_RES2:
+      if (port == NULL) // timeout
+      {
+        switch (signal)
+        {
+        case COutputControlProtocol::TIMEOUT:
+          if (FindFreeSurface() >= 0 && !m_bufferPool.freeRenderPics.empty())
+          {
+            m_state = O_TOP_CONFIGURED_STEP2;
+            m_bStateMachineSelfTrigger = true;
+          }
+          else
+          {
+            if (m_extTimeout != 0)
+            {
+              uint16_t decoded, processed, render;
+              m_config.stats->Get(decoded, processed, render);
+              CLog::Log(LOGDEBUG, "CVDPAU::COutput - timeout idle: decoded: %d, proc: %d, render: %d", decoded, processed, render);
+            }
+            m_extTimeout = 100;
+          }
+          return;
+        default:
+          break;
+        }
+      }
+      break;
+
+    case O_TOP_CONFIGURED_STEP2:
+      if (port == NULL) // timeout
+      {
+        switch (signal)
+        {
+        case COutputControlProtocol::TIMEOUT:
+          CXvbaRenderPicture *pic;
+          m_deintStep = 1;
+          pic = ProcessPicture();
+          if (pic)
+          {
+            m_config.stats->IncRender();
+            m_dataPort.SendInMessage(COutputDataProtocol::PICTURE, &pic, sizeof(pic));
+          }
+          if (m_xvbaError)
+          {
+            m_state = O_TOP_ERROR;
+            return;
+          }
+          FiniCycle();
+          m_state = O_TOP_CONFIGURED_WAIT_RES1;
+          m_extTimeout = 0;
+          return;
+        default:
+          break;
+        }
+      }
+      break;
+
+    default: // we are in no state, should not happen
+      CLog::Log(LOGERROR, "COutput::%s - no valid state: %d", __FUNCTION__, m_state);
+      return;
+    }
+  } // for
+}
+
+void COutput::Process()
+{
+  Message *msg;
+  Protocol *port;
+  bool gotMsg;
+
+  m_state = O_TOP_UNCONFIGURED;
+  m_extTimeout = 1000;
+  m_bStateMachineSelfTrigger = false;
+
+  while (!m_bStop)
+  {
+    gotMsg = false;
+
+    if (m_bStateMachineSelfTrigger)
+    {
+      m_bStateMachineSelfTrigger = false;
+      // self trigger state machine
+      StateMachine(msg->signal, port, msg);
+      if (!m_bStateMachineSelfTrigger)
+      {
+        msg->Release();
+        msg = NULL;
+      }
+      continue;
+    }
+    // check control port
+    else if (m_controlPort.ReceiveOutMessage(&msg))
+    {
+      gotMsg = true;
+      port = &m_controlPort;
+    }
+    // check data port
+    else if (m_dataPort.ReceiveOutMessage(&msg))
+    {
+      gotMsg = true;
+      port = &m_dataPort;
+    }
+    if (gotMsg)
+    {
+      StateMachine(msg->signal, port, msg);
+      if (!m_bStateMachineSelfTrigger)
+      {
+        msg->Release();
+        msg = NULL;
+      }
+      continue;
+    }
+
+    // wait for message
+    else if (m_outMsgEvent.WaitMSec(m_extTimeout))
+    {
+      continue;
+    }
+    // time out
+    else
+    {
+      msg = m_controlPort.GetMessage();
+      msg->signal = COutputControlProtocol::TIMEOUT;
+      port = 0;
+      // signal timeout to state machine
+      StateMachine(msg->signal, port, msg);
+      if (!m_bStateMachineSelfTrigger)
+      {
+        msg->Release();
+        msg = NULL;
+      }
+    }
+  }
+  Flush();
+  Uninit();
+}
+
+bool COutput::Init()
+{
+  if (!CreateGlxContext())
+    return false;
+
+  m_xvbaError = false;
+  m_processPicture.render = 0;
+  m_fence = None;
+
+  return true;
+}
+
+bool COutput::Uninit()
+{
+  ReleaseBufferPool();
+  DestroyGlxContext();
+  return true;
+}
+
+void COutput::Flush()
+{
+  while (!m_decodedPics.empty())
+  {
+    CXvbaDecodedPicture pic = m_decodedPics.front();
+    m_decodedPics.pop();
+    CSingleLock lock(*m_config.videoSurfaceSec);
+    if (pic.render)
+      pic.render->state &= ~(FF_XVBA_STATE_USED_FOR_RENDER | FF_XVBA_STATE_DECODED);
+  }
+
+  if (m_processPicture.render)
+  {
+    CSingleLock lock(*m_config.videoSurfaceSec);
+    m_processPicture.render->state &= ~(FF_XVBA_STATE_USED_FOR_RENDER | FF_XVBA_STATE_DECODED);
+    m_processPicture.render = 0;
+  }
+
+  Message *msg;
+  while (m_dataPort.ReceiveOutMessage(&msg))
+  {
+    if (msg->signal == COutputDataProtocol::NEWFRAME)
+    {
+      CXvbaDecodedPicture pic = *(CXvbaDecodedPicture*)msg->data;
+      CSingleLock lock(*m_config.videoSurfaceSec);
+      if (pic.render)
+        pic.render->state &= ~(FF_XVBA_STATE_USED_FOR_RENDER | FF_XVBA_STATE_DECODED);
+    }
+    else if (msg->signal == COutputDataProtocol::RETURNPIC)
+    {
+      CXvbaRenderPicture *pic;
+      pic = *((CXvbaRenderPicture**)msg->data);
+      ProcessReturnPicture(pic);
+    }
+    msg->Release();
+  }
+
+  while (m_dataPort.ReceiveInMessage(&msg))
+  {
+    if (msg->signal == COutputDataProtocol::PICTURE)
+    {
+      CXvbaRenderPicture *pic;
+      pic = *((CXvbaRenderPicture**)msg->data);
+      ProcessReturnPicture(pic);
+    }
+  }
+}
+
+bool COutput::IsDecodingFinished()
+{
+  return true;
+
+  // check for decoding to be finished
+  CXvbaDecodedPicture decodedPic = m_decodedPics.front();
+
+  XVBA_Surface_Sync_Input syncInput;
+  XVBA_Surface_Sync_Output syncOutput;
+  syncInput.size = sizeof(syncInput);
+  syncInput.session = m_config.xvbaSession;
+  syncInput.surface = decodedPic.render->surface;
+  syncInput.query_status = XVBA_GET_SURFACE_STATUS;
+  syncOutput.size = sizeof(syncOutput);
+  { CSingleLock lock(*(m_config.apiSec));
+    if (Success != g_XVBA_vtable.SyncSurface(&syncInput, &syncOutput))
+    {
+      CLog::Log(LOGERROR,"XVBA - failed sync surface");
+      m_xvbaError = true;
+      return false;
+    }
+  }
+  if (!(syncOutput.status_flags & XVBA_STILL_PENDING))
+    return true;
+
+  return false;
+}
+
+CXvbaRenderPicture* COutput::ProcessPicture()
+{
+  CXvbaRenderPicture *retPic = 0;
+
+  if (m_deintStep == 1)
+  {
+    if(m_field == XVBA_TOP_FIELD)
+      m_field = XVBA_BOTTOM_FIELD;
+    else
+      m_field = XVBA_TOP_FIELD;
+  }
+
+  // find unused shared surface
+  unsigned int idx = FindFreeSurface();
+  XvbaBufferPool::GLVideoSurface *glSurface = &m_bufferPool.glSurfaces[idx];
+  glSurface->used = true;
+  glSurface->field = m_field;
+  glSurface->render = m_processPicture.render;
+  glSurface->transferred = false;
+
+  int cmd = 0;
+  m_config.stats->GetCmd(cmd);
+
+//  if (m_fence)
+//    glDeleteSync(m_fence);
+//  m_fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+
+  // transfer surface
+  XVBA_Transfer_Surface_Input transInput;
+  transInput.size = sizeof(transInput);
+  transInput.session = m_config.xvbaSession;
+  transInput.src_surface = m_processPicture.render->surface;
+  transInput.target_surface = glSurface->glSurface;
+  transInput.flag = m_field;
+  { CSingleLock lock(*(m_config.apiSec));
+    if (Success != g_XVBA_vtable.TransferSurface(&transInput))
+    {
+      CLog::Log(LOGERROR,"(XVBA) failed to transfer surface");
+      m_xvbaError = true;
+      return retPic;
+    }
+  }
+
+  // prepare render pic
+  retPic = m_bufferPool.freeRenderPics.front();
+  m_bufferPool.freeRenderPics.pop_front();
+  m_bufferPool.usedRenderPics.push_back(retPic);
+  retPic->sourceIdx = glSurface->id;
+  retPic->DVDPic = m_processPicture.DVDPic;
+  retPic->valid = true;
+  retPic->texture = glSurface->texture;
+  retPic->crop = CRect(0,0,0,0);
+  retPic->texWidth = m_config.surfaceWidth;
+  retPic->texHeight = m_config.surfaceHeight;
+  retPic->xvbaOutput = this;
+
+  // set repeat pic for de-interlacing
+  if (m_deinterlacing)
+  {
+    if (m_deintStep == 1)
+    {
+      retPic->DVDPic.pts = DVD_NOPTS_VALUE;
+      retPic->DVDPic.dts = DVD_NOPTS_VALUE;
+    }
+    retPic->DVDPic.iRepeatPicture = 0.0;
+  }
+
+  return retPic;
+}
+
+void COutput::ProcessReturnPicture(CXvbaRenderPicture *pic)
+{
+  std::deque<CXvbaRenderPicture*>::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; i<m_bufferPool.glSurfaces.size();++i)
+    {
+      if (i == pic->sourceIdx)
+        continue;
+      if (m_bufferPool.glSurfaces[i].render == render)
+      {
+        referenced = true;
+        break;
+      }
+    }
+    if (m_processPicture.render == render)
+      referenced = true;
+
+    // release video surface
+    if (!referenced)
+    {
+      CSingleLock lock(*m_config.videoSurfaceSec);
+      render->state &= ~(FF_XVBA_STATE_USED_FOR_RENDER | FF_XVBA_STATE_DECODED);
+    }
+
+    // unreference video surface
+    m_bufferPool.glSurfaces[pic->sourceIdx].render = 0;
+
+    m_bufferPool.glSurfaces[pic->sourceIdx].used = false;
+    return;
+  }
+}
+
+int COutput::FindFreeSurface()
+{
+  // find free shared surface
+  unsigned int i;
+  for (i = 0; i < m_bufferPool.glSurfaces.size(); ++i)
+  {
+    if (!m_bufferPool.glSurfaces[i].used)
+      break;
+  }
+  if (i == m_bufferPool.glSurfaces.size())
+    return -1;
+  else
+    return i;
+}
+
+void COutput::InitCycle()
+{
+  uint64_t latency;
+  int speed;
+  m_config.stats->GetParams(latency, speed);
+  latency = (latency*1000)/CurrentHostFrequency();
+
+  m_config.stats->SetCanSkipDeint(false);
+
+  EDEINTERLACEMODE   mode = g_settings.m_currentVideoSettings.m_DeinterlaceMode;
+  EINTERLACEMETHOD method = g_settings.m_currentVideoSettings.m_InterlaceMethod;
+  bool interlaced = m_processPicture.DVDPic.iFlags & DVP_FLAG_INTERLACED;
+
+  if (mode == VS_DEINTERLACEMODE_FORCE ||
+     (mode == VS_DEINTERLACEMODE_AUTO && interlaced))
+  {
+    if((method == VS_INTERLACEMETHOD_AUTO && interlaced)
+      ||  method == VS_INTERLACEMETHOD_XVBA)
+    {
+      m_deinterlacing = true;
+      m_deintSkip = false;
+      m_config.stats->SetCanSkipDeint(true);
+
+      if (m_processPicture.DVDPic.iFlags & DVP_FLAG_DROPDEINT)
+      {
+        m_deintSkip = true;
+      }
+
+      // do only half deinterlacing
+      if (speed != DVD_PLAYSPEED_NORMAL || !g_graphicsContext.IsFullScreenVideo())
+      {
+        m_config.stats->SetCanSkipDeint(false);
+        m_deintSkip = true;
+      }
+
+      if(m_processPicture.DVDPic.iFlags & DVP_FLAG_TOP_FIELD_FIRST)
+        m_field = XVBA_TOP_FIELD;
+      else
+        m_field = XVBA_BOTTOM_FIELD;
+    }
+  }
+  else
+  {
+    m_deinterlacing = false;
+    m_field = XVBA_FRAME;
+  }
+
+  m_processPicture.DVDPic.format = RENDER_FMT_XVBA;
+  m_processPicture.DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST |
+                                    DVP_FLAG_REPEAT_TOP_FIELD |
+                                    DVP_FLAG_INTERLACED);
+  m_processPicture.DVDPic.iWidth = m_config.vidWidth;
+  m_processPicture.DVDPic.iHeight = m_config.vidHeight;
+
+  m_deintStep = 0;
+}
+
+void COutput::FiniCycle()
+{
+//  { CSingleLock lock(*m_config.videoSurfaceSec);
+//    m_processPicture.render->state &= ~FF_XVBA_STATE_USED_FOR_RENDER;
+//  }
+  m_processPicture.render = 0;
+  m_config.stats->DecDecoded();
+}
+
+bool COutput::EnsureBufferPool()
+{
+  if (m_config.useSharedSurfaces && m_bufferPool.glSurfaces.empty())
+  {
+    GLenum textureTarget;
+    if (!glewIsSupported("GL_ARB_texture_non_power_of_two") && glewIsSupported("GL_ARB_texture_rectangle"))
+    {
+      textureTarget = GL_TEXTURE_RECTANGLE_ARB;
+    }
+    else
+      textureTarget = GL_TEXTURE_2D;
+
+    // create shared surfaces
+    XvbaBufferPool::GLVideoSurface surface;
+    for (unsigned int i = 0; i < NUM_RENDER_PICS; ++i)
+    {
+      glEnable(textureTarget);
+      glGenTextures(1, &surface.texture);
+      glBindTexture(textureTarget, surface.texture);
+      glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+      glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+      glTexParameteri(textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+      glTexParameteri(textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+      glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+      glTexImage2D(textureTarget, 0, GL_RGBA, m_config.surfaceWidth, m_config.surfaceHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
+
+      XVBA_Create_GLShared_Surface_Input surfInput;
+      XVBA_Create_GLShared_Surface_Output surfOutput;
+      surfInput.size = sizeof(surfInput);
+      surfInput.session = m_config.xvbaSession;
+      surfInput.gltexture = surface.texture;
+      surfInput.glcontext = m_glContext;
+      surfOutput.size = sizeof(surfOutput);
+      surfOutput.surface = 0;
+      if (Success != g_XVBA_vtable.CreateGLSharedSurface(&surfInput, &surfOutput))
+      {
+        CLog::Log(LOGERROR,"(XVBA) failed to create shared surface");
+        m_xvbaError = true;
+        break;
+      }
+      CLog::Log(LOGDEBUG, "XVBA::GetTexture - created shared surface");
+
+      surface.glSurface = surfOutput.surface;
+      surface.id = i;
+      surface.used = false;
+      surface.render = 0;
+      m_bufferPool.glSurfaces.push_back(surface);
+    }
+    glDisable(textureTarget);
+  }
+
+  return true;
+}
+
+void COutput::ReleaseBufferPool(bool precleanup /*= false*/)
+{
+//  if (m_fence)
+//  {
+//    uint64_t maxTimeout = 1000000000LL;
+//    glClientWaitSync(m_fence, GL_SYNC_FLUSH_COMMANDS_BIT, maxTimeout);
+//    glDeleteSync(m_fence);
+//    m_fence = None;
+//  }
+
+  CSingleLock lock(m_bufferPool.renderPicSec);
+
+  for (unsigned int i = 0; i < m_bufferPool.glSurfaces.size(); ++i)
+  {
+    if (m_bufferPool.glSurfaces[i].glSurface)
+    {
+      g_XVBA_vtable.DestroySurface(m_bufferPool.glSurfaces[i].glSurface);
+      m_bufferPool.glSurfaces[i].glSurface = 0;
+    }
+    if (m_bufferPool.glSurfaces[i].texture && !precleanup)
+    {
+      glDeleteTextures(1, &m_bufferPool.glSurfaces[i].texture);
+      m_bufferPool.glSurfaces[i].texture = 0;
+    }
+    m_bufferPool.glSurfaces[i].render = 0;
+    m_bufferPool.glSurfaces[i].used = true;
+  }
+
+  if (!precleanup)
+  {
+    m_bufferPool.glSurfaces.clear();
+
+    // invalidate all used render pictures
+    for (unsigned int i = 0; i < m_bufferPool.usedRenderPics.size(); ++i)
+    {
+      m_bufferPool.usedRenderPics[i]->valid = false;
+    }
+  }
+}
+
+void COutput::PreReleaseBufferPool()
+{
+  CSingleLock lock(m_bufferPool.renderPicSec);
+
+  if (m_config.useSharedSurfaces)
+  {
+    for (unsigned int i = 0; i < m_bufferPool.glSurfaces.size(); ++i)
+    {
+      if (!m_bufferPool.glSurfaces[i].used)
+      {
+        g_XVBA_vtable.DestroySurface(m_bufferPool.glSurfaces[i].glSurface);
+        glDeleteTextures(1, &m_bufferPool.glSurfaces[i].texture);
+        m_bufferPool.glSurfaces[i].glSurface = 0;
+        m_bufferPool.glSurfaces[i].used = true;
+      }
+    }
+  }
+}
+
+bool COutput::CreateGlxContext()
+{
+  GLXContext   glContext;
+
+  m_Display = g_Windowing.GetDisplay();
+  glContext = g_Windowing.GetGlxContext();
+  m_Window = g_Windowing.GetWindow();
+
+  // Get our window attribs.
+  XWindowAttributes wndattribs;
+  XGetWindowAttributes(m_Display, m_Window, &wndattribs);
+
+  // Get visual Info
+  XVisualInfo visInfo;
+  visInfo.visualid = wndattribs.visual->visualid;
+  int nvisuals = 0;
+  XVisualInfo* visuals = XGetVisualInfo(m_Display, VisualIDMask, &visInfo, &nvisuals);
+  if (nvisuals != 1)
+  {
+    CLog::Log(LOGERROR, "XVBA::COutput::CreateGlxContext - could not find visual");
+    return false;
+  }
+  visInfo = visuals[0];
+  XFree(visuals);
+
+  m_pixmap = XCreatePixmap(m_Display,
+                           m_Window,
+                           192,
+                           108,
+                           visInfo.depth);
+  if (!m_pixmap)
+  {
+    CLog::Log(LOGERROR, "XVBA::COutput::CreateGlxContext - Unable to create XPixmap");
+    return false;
+  }
+
+  // create gl pixmap
+  m_glPixmap = glXCreateGLXPixmap(m_Display, &visInfo, m_pixmap);
+
+  if (!m_glPixmap)
+  {
+    CLog::Log(LOGINFO, "XVBA::COutput::CreateGlxContext - Could not create glPixmap");
+    return false;
+  }
+
+  m_glContext = glXCreateContext(m_Display, &visInfo, glContext, True);
+
+  if (!glXMakeCurrent(m_Display, m_glPixmap, m_glContext))
+  {
+    CLog::Log(LOGINFO, "XVBA::COutput::CreateGlxContext - Could not make Pixmap current");
+    return false;
+  }
+
+  CLog::Log(LOGNOTICE, "XVBA::COutput::CreateGlxContext - created context");
+  return true;
+}
+
+bool COutput::DestroyGlxContext()
+{
+  if (m_glContext)
+  {
+    glXMakeCurrent(m_Display, None, NULL);
+    glXDestroyContext(m_Display, m_glContext);
+  }
+  m_glContext = 0;
+
+  if (m_glPixmap)
+    glXDestroyPixmap(m_Display, m_glPixmap);
+  m_glPixmap = 0;
+
+  if (m_pixmap)
+    XFreePixmap(m_Display, m_pixmap);
+  m_pixmap = 0;
+
+  return true;
+}
+
+#endif
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.h
new file mode 100644
index 0000000..f38444c
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.h
@@ -0,0 +1,382 @@
+/*
+ *      Copyright (C) 2005-2011 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+#pragma once
+
+#include "X11/Xlib.h"
+#include "amd/amdxvba.h"
+#include "DllAvCodec.h"
+#include "DVDCodecs/Video/DVDVideoCodecFFmpeg.h"
+#include "threads/Thread.h"
+#include "threads/CriticalSection.h"
+#include "threads/SharedSection.h"
+#include "threads/Event.h"
+#include "guilib/DispResource.h"
+#include "guilib/Geometry.h"
+#include "libavcodec/xvba.h"
+#include "utils/ActorProtocol.h"
+#include "settings/VideoSettings.h"
+#include <GL/glx.h>
+#include <vector>
+#include <deque>
+
+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<xvba_render_state*> *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<GLVideoSurface> glSurfaces;
+  std::vector<CXvbaRenderPicture> allRenderPics;
+  std::deque<CXvbaRenderPicture*> usedRenderPics;
+  std::deque<CXvbaRenderPicture*> 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<CXvbaDecodedPicture> 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<xvba_render_state*> 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<XVBABufferDescriptor*> data_control_buffers;
+  };
+  XVBABufferPool m_xvbaBufferPool;
+
+  COutput       m_xvbaOutput;
+  CXvbaBufferStats m_bufferStats;
+  CEvent        m_inMsgEvent;
+  CXvbaRenderPicture *m_presentPicture;
+
+  int m_speed;
+  int m_codecControl;
+};
+
+}
diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
index 15a39fa..e5e71f3 100644
--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
@@ -1162,6 +1162,9 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts)
       case RENDER_FMT_NONE:
         formatstr = "NONE";
         break;
+      case RENDER_FMT_XVBA:
+        formatstr = "XVBA";
+        break;
     }
 
     if(m_bAllowFullscreen)
diff --git a/xbmc/settings/GUISettings.cpp b/xbmc/settings/GUISettings.cpp
index abf5c01..ee0c789 100644
--- a/xbmc/settings/GUISettings.cpp
+++ b/xbmc/settings/GUISettings.cpp
@@ -696,6 +696,9 @@ void CGUISettings::Initialize()
 #ifdef HAVE_LIBVA
   AddBool(vp, "videoplayer.usevaapi", 13426, true);
 #endif
+#ifdef HAVE_LIBXVBA
+  AddBool(vp, "videoplayer.usexvba", 13437, true);
+#endif
 #ifdef HAS_DX
   AddBool(g_sysinfo.IsVistaOrHigher() ? vp: NULL, "videoplayer.usedxva2", 13427, g_sysinfo.IsVistaOrHigher() ? true : false);
 #endif
diff --git a/xbmc/settings/VideoSettings.h b/xbmc/settings/VideoSettings.h
index f8093b2..f54a837 100644
--- a/xbmc/settings/VideoSettings.h
+++ b/xbmc/settings/VideoSettings.h
@@ -65,6 +65,8 @@ enum EINTERLACEMETHOD
   VS_INTERLACEMETHOD_SW_BLEND = 20,
   VS_INTERLACEMETHOD_AUTO_ION = 21,
 
+  VS_INTERLACEMETHOD_XVBA = 22,
+
   VS_INTERLACEMETHOD_MAX // do not use and keep as last enum value.
 };
 
diff --git a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp
index f25d10d..f6b1ea4 100644
--- a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp
+++ b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp
@@ -110,6 +110,7 @@ void CGUIDialogVideoSettings::CreateSettings()
     entries.push_back(make_pair(VS_INTERLACEMETHOD_DXVA_BOB                   , 16320));
     entries.push_back(make_pair(VS_INTERLACEMETHOD_DXVA_BEST                  , 16321));
     entries.push_back(make_pair(VS_INTERLACEMETHOD_AUTO_ION                   , 16325));
+    entries.push_back(make_pair(VS_INTERLACEMETHOD_XVBA                       , 16326));
 
     /* remove unsupported methods */
     for(vector<pair<int, int> >::iterator it = entries.begin(); it != entries.end();)
-- 
1.7.10


From f14ba2a7b0bb2dc3b3335572e3578c39c44d68ce Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Thu, 23 Aug 2012 19:39:49 +0200
Subject: [PATCH 43/58] ffmpeg: add av_find_default_stream_index to interface

---
 lib/DllAvFormat.h |    4 ++++
 1 file changed, 4 insertions(+)

diff --git a/lib/DllAvFormat.h b/lib/DllAvFormat.h
index 9bda3f3..bf31fcb 100644
--- a/lib/DllAvFormat.h
+++ b/lib/DllAvFormat.h
@@ -98,6 +98,7 @@ class DllAvFormatInterface
   virtual int avformat_write_header (AVFormatContext *s, AVDictionary **options)=0;
   virtual int av_write_trailer(AVFormatContext *s)=0;
   virtual int av_write_frame  (AVFormatContext *s, AVPacket *pkt)=0;
+  virtual int av_find_default_stream_index(AVFormatContext *s)=0;
 };
 
 #if (defined USE_EXTERNAL_FFMPEG) || (defined TARGET_DARWIN) 
@@ -153,6 +154,7 @@ class DllAvFormat : public DllDynamic, DllAvFormatInterface
   virtual int avformat_write_header (AVFormatContext *s, AVDictionary **options) { return ::avformat_write_header (s, options); }
   virtual int av_write_trailer(AVFormatContext *s) { return ::av_write_trailer(s); }
   virtual int av_write_frame  (AVFormatContext *s, AVPacket *pkt) { return ::av_write_frame(s, pkt); }
+  virtual int av_find_default_stream_index(AVFormatContext *s) { return ::av_find_default_stream_index(s); }
 
   // DLL faking.
   virtual bool ResolveExports() { return true; }
@@ -209,6 +211,7 @@ class DllAvFormat : public DllDynamic, DllAvFormatInterface
   DEFINE_METHOD2(int, avformat_write_header , (AVFormatContext *p1, AVDictionary **p2))
   DEFINE_METHOD1(int, av_write_trailer, (AVFormatContext *p1))
   DEFINE_METHOD2(int, av_write_frame  , (AVFormatContext *p1, AVPacket *p2))
+  DEFINE_METHOD1(int, av_find_default_stream_index, (AVFormatContext *p1))
   BEGIN_METHOD_RESOLVE()
     RESOLVE_METHOD_RENAME(av_register_all, av_register_all_dont_call)
     RESOLVE_METHOD(av_find_input_format)
@@ -243,6 +246,7 @@ class DllAvFormat : public DllDynamic, DllAvFormatInterface
     RESOLVE_METHOD(avformat_write_header)
     RESOLVE_METHOD(av_write_trailer)
     RESOLVE_METHOD(av_write_frame)
+    RESOLVE_METHOD(av_find_default_stream_index)
   END_METHOD_RESOLVE()
 
   /* dependencies of libavformat */
-- 
1.7.10


From 04c4aec1667a07fc2270a1f5ca5ae4d06833db23 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Mon, 20 Aug 2012 16:06:39 +0200
Subject: [PATCH 44/58] dvdplayer: observe pts counter overflow

---
 .../cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp |  198 +++++++++++++++++++-
 xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h  |    4 +
 2 files changed, 201 insertions(+), 1 deletion(-)

diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
index 7c0ab03..f91be3c 100644
--- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
@@ -18,13 +18,13 @@
  *
  */
 
-#include "system.h"
 #ifndef __STDC_CONSTANT_MACROS
 #define __STDC_CONSTANT_MACROS
 #endif
 #ifndef __STDC_LIMIT_MACROS
 #define __STDC_LIMIT_MACROS
 #endif
+#include "system.h"
 #ifdef _LINUX
 #include "stdint.h"
 #endif
@@ -495,6 +495,9 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput)
       AddStream(i);
   }
 
+  m_bPtsWrapChecked = false;
+  m_bPtsWrap = false;
+
   return true;
 }
 
@@ -605,6 +608,12 @@ double CDVDDemuxFFmpeg::ConvertTimestamp(int64_t pts, int den, int num)
   if (pts == (int64_t)AV_NOPTS_VALUE)
     return DVD_NOPTS_VALUE;
 
+  if (m_bPtsWrap)
+  {
+    if (pts < m_iStartTime && pts < m_iEndTime)
+      pts += m_iMaxTime;
+  }
+
   // do calculations in floats as they can easily overflow otherwise
   // we don't care for having a completly exact timestamp anyway
   double timestamp = (double)pts * num  / den;
@@ -729,6 +738,24 @@ DemuxPacket* CDVDDemuxFFmpeg::Read()
           pkt.pts = AV_NOPTS_VALUE;
         }
 
+        if (!m_bPtsWrapChecked && m_pFormatContext->iformat->flags & AVFMT_TS_DISCONT)
+        {
+          int defaultStream = m_dllAvFormat.av_find_default_stream_index(m_pFormatContext);
+          int64_t duration = m_pFormatContext->streams[defaultStream]->duration * 1.5;
+          m_iMaxTime = 1LL<<m_pFormatContext->streams[defaultStream]->pts_wrap_bits;
+          m_iStartTime = m_pFormatContext->streams[defaultStream]->start_time;
+          if (m_iStartTime != DVD_NOPTS_VALUE)
+          {
+            m_iEndTime = (m_iStartTime + duration) & ~m_iMaxTime;
+            if (m_iEndTime < m_iStartTime)
+            {
+              CLog::Log(LOGNOTICE,"CDVDDemuxFFmpeg::Read - file contains pts overflow");
+              m_bPtsWrap = true;
+            }
+          }
+          m_bPtsWrapChecked = true;
+        }
+
         // copy contents into our own packet
         pPacket->iSize = pkt.size;
 
@@ -845,10 +872,20 @@ bool CDVDDemuxFFmpeg::SeekTime(int time, bool backwords, double *startpts)
   int ret;
   {
     CSingleLock lock(m_critSection);
+
     ret = m_dllAvFormat.av_seek_frame(m_pFormatContext, -1, seek_pts, backwords ? AVSEEK_FLAG_BACKWARD : 0);
 
     if(ret >= 0)
+    {
       UpdateCurrentPTS();
+
+      // seek may fail silently on streams which allow discontinuity
+      // if current timestamp is way off asume a pts overflow and try bisect seek
+      if (m_bPtsWrap && fabs(time - m_iCurrentPts/1000) > 10000)
+      {
+        ret = SeekTimeDiscont(seek_pts, backwords) ? 1 : -1;
+      }
+    }
   }
 
   if(m_iCurrentPts == DVD_NOPTS_VALUE)
@@ -867,6 +904,165 @@ bool CDVDDemuxFFmpeg::SeekTime(int time, bool backwords, double *startpts)
   return (ret >= 0);
 }
 
+bool CDVDDemuxFFmpeg::SeekTimeDiscont(int64_t pts, bool backwards)
+{
+  // this code is taken from ffmpeg function ff_gen_search
+  // it is modified to assume a pts overflow if timestamp < start_time
+  if (!m_pFormatContext->iformat->read_timestamp)
+    return false;
+
+  int defaultStream = m_dllAvFormat.av_find_default_stream_index(m_pFormatContext);
+
+  if (defaultStream < 0)
+  {
+    return false;
+  }
+
+  // timestamp for default must be expressed in AV_TIME_BASE units
+  pts = m_dllAvUtil.av_rescale_rnd(pts, m_pFormatContext->streams[defaultStream]->time_base.den,
+                      AV_TIME_BASE * (int64_t)m_pFormatContext->streams[defaultStream]->time_base.num,
+                      AV_ROUND_NEAR_INF);
+
+  int64_t pos, pos_min, pos_max, pos_limit, ts, ts_min, ts_max;
+  int64_t start_pos, filesize;
+  int no_change;
+
+  pos_min = m_pFormatContext->data_offset;
+  ts_min = m_pFormatContext->iformat->read_timestamp(m_pFormatContext, defaultStream,
+                                                     &pos_min, INT64_MAX);
+  if (ts_min == AV_NOPTS_VALUE)
+    return false;
+
+  if(ts_min >= pts)
+  {
+    pos = pos_min;
+    return true;
+  }
+
+  int step= 1024;
+  filesize = m_pInput->GetLength();
+  pos_max = filesize - 1;
+  do
+  {
+    pos_max -= step;
+    ts_max = m_pFormatContext->iformat->read_timestamp(m_pFormatContext, defaultStream,
+                                                       &pos_max, pos_max + step);
+    step += step;
+  }while (ts_max == AV_NOPTS_VALUE && pos_max >= step);
+
+  if (ts_max == AV_NOPTS_VALUE)
+    return false;
+
+  if (ts_max < m_iStartTime && ts_max < m_iEndTime)
+    ts_max += m_iMaxTime;
+
+  for(;;)
+  {
+    int64_t tmp_pos = pos_max + 1;
+    int64_t tmp_ts = m_pFormatContext->iformat->read_timestamp(m_pFormatContext, defaultStream,
+                                                               &tmp_pos, INT64_MAX);
+    if(tmp_ts == AV_NOPTS_VALUE)
+      break;
+
+    if (tmp_ts < m_iStartTime && tmp_ts < m_iEndTime)
+      tmp_ts += m_iMaxTime;
+
+    ts_max = tmp_ts;
+    pos_max = tmp_pos;
+    if (tmp_pos >= filesize)
+      break;
+  }
+  pos_limit = pos_max;
+
+  if(ts_max <= pts)
+  {
+    bool ret = SeekByte(pos_max);
+    if (ret)
+    {
+      m_iCurrentPts = ConvertTimestamp(ts_max, m_pFormatContext->streams[defaultStream]->time_base.den,
+                                       m_pFormatContext->streams[defaultStream]->time_base.num);
+    }
+    return ret;
+  }
+
+  if(ts_min > ts_max)
+  {
+    return false;
+  }
+  else if (ts_min == ts_max)
+  {
+    pos_limit = pos_min;
+  }
+
+  no_change=0;
+  while (pos_min < pos_limit)
+  {
+    if (no_change == 0)
+    {
+      int64_t approximate_keyframe_distance= pos_max - pos_limit;
+      // interpolate position (better than dichotomy)
+      pos = m_dllAvUtil.av_rescale_rnd(pts - ts_min, pos_max - pos_min,
+                                       ts_max - ts_min, AV_ROUND_NEAR_INF)
+          + pos_min - approximate_keyframe_distance;
+    }
+    else if (no_change == 1)
+    {
+      // bisection, if interpolation failed to change min or max pos last time
+      pos = (pos_min + pos_limit) >> 1;
+    }
+    else
+    {
+      /* linear search if bisection failed, can only happen if there
+         are very few or no keyframes between min/max */
+      pos = pos_min;
+    }
+    if (pos <= pos_min)
+      pos= pos_min + 1;
+    else if (pos > pos_limit)
+      pos= pos_limit;
+    start_pos = pos;
+
+    ts = m_pFormatContext->iformat->read_timestamp(m_pFormatContext, defaultStream,
+                                                   &pos, INT64_MAX);
+    if (pos == pos_max)
+      no_change++;
+    else
+      no_change=0;
+
+    if (ts == AV_NOPTS_VALUE)
+    {
+      return false;
+    }
+
+    if (ts < m_iStartTime && ts < m_iEndTime)
+      ts += m_iMaxTime;
+
+    if (pts <= ts)
+    {
+      pos_limit = start_pos - 1;
+      pos_max = pos;
+      ts_max = ts;
+    }
+    if (pts >= ts)
+    {
+      pos_min = pos;
+      ts_min = ts;
+    }
+  }
+
+  pos = (backwards) ? pos_min : pos_max;
+  ts  = (backwards) ?  ts_min :  ts_max;
+
+  bool ret = SeekByte(pos);
+  if (ret)
+  {
+    m_iCurrentPts = ConvertTimestamp(ts, m_pFormatContext->streams[defaultStream]->time_base.den,
+                                     m_pFormatContext->streams[defaultStream]->time_base.num);
+  }
+
+  return ret;
+}
+
 bool CDVDDemuxFFmpeg::SeekByte(int64_t pos)
 {
   g_demuxer.set(this);
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h
index 2b5f2e8..e0acf29 100644
--- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h
@@ -97,6 +97,7 @@ class CDVDDemuxFFmpeg : public CDVDDemux
   DemuxPacket* Read();
 
   bool SeekTime(int time, bool backwords = false, double* startpts = NULL);
+  bool SeekTimeDiscont(int64_t pts, bool backwards);
   bool SeekByte(int64_t pos);
   int GetStreamLength();
   CDemuxStream* GetStream(int iStreamId);
@@ -141,5 +142,8 @@ class CDVDDemuxFFmpeg : public CDVDDemux
   XbmcThreads::EndTime  m_timeout;
 
   CDVDInputStream* m_pInput;
+
+  bool m_bPtsWrap, m_bPtsWrapChecked;
+  int64_t m_iStartTime, m_iMaxTime, m_iEndTime;
 };
 
-- 
1.7.10


From 8154babe8b8862701468ccb33d22798e3fab8c4d Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Tue, 2 Oct 2012 13:02:10 +0200
Subject: [PATCH 45/58] dvdplayer: avoid short screen flicker caused by
 unnecessary reconfigure of renderer

---
 xbmc/cores/dvdplayer/DVDPlayerVideo.cpp |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
index e5e71f3..8b02d81 100644
--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
@@ -1033,7 +1033,7 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts)
    || m_output.height != pPicture->iHeight
    || m_output.dwidth != pPicture->iDisplayWidth
    || m_output.dheight != pPicture->iDisplayHeight
-   || m_output.framerate != config_framerate
+   || (!m_bFpsInvalid && fmod(m_output.framerate, config_framerate) != 0.0 )
    || m_output.color_format != (unsigned int)pPicture->format
    || m_output.extended_format != pPicture->extended_format
    || ( m_output.color_matrix != pPicture->color_matrix && pPicture->color_matrix != 0 ) // don't reconfigure on unspecified
@@ -1184,7 +1184,7 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts)
     m_output.height = pPicture->iHeight;
     m_output.dwidth = pPicture->iDisplayWidth;
     m_output.dheight = pPicture->iDisplayHeight;
-    m_output.framerate = config_framerate;
+    m_output.framerate = config_framerate == 0.0 ? g_graphicsContext.GetFPS() : config_framerate;
     m_output.color_format = pPicture->format;
     m_output.extended_format = pPicture->extended_format;
     m_output.color_matrix = pPicture->color_matrix;
-- 
1.7.10


From 5151698a925c539654a90a19d1d3df11d38e7938 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Sat, 16 Jun 2012 12:46:30 +0200
Subject: [PATCH 46/58] xvba: do not use vaapi if xvba is present

---
 xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp |    9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp
index a2b9195..43a05b3 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp
@@ -261,6 +261,15 @@ void CDecoder::Close()
 
 bool CDecoder::Open(AVCodecContext *avctx, enum PixelFormat fmt, unsigned int surfaces)
 {
+#ifdef HAVE_LIBXVBA
+  std::string Vendor = g_Windowing.GetRenderVendor();
+  std::transform(Vendor.begin(), Vendor.end(), Vendor.begin(), ::tolower);
+  if (Vendor.compare(0, 3, "ati") == 0)
+  {
+    return false;
+  }
+#endif
+
   VAEntrypoint entrypoint = VAEntrypointVLD;
   VAProfile    profile;
 
-- 
1.7.10


From 4501236a67eefb4b6def816b57be86f71b19297f Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Thu, 11 Oct 2012 12:05:50 +0200
Subject: [PATCH 47/58] vdpau: advanced settings for auto deinterlacing

---
 xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp |    8 ++++----
 xbmc/settings/AdvancedSettings.cpp             |    4 ++++
 xbmc/settings/AdvancedSettings.h               |    2 ++
 3 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp
index 235f565..d95797b 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp
@@ -1770,10 +1770,10 @@ EINTERLACEMETHOD CMixer::GetDeinterlacingMethod(bool log /* = false */)
   if (method == VS_INTERLACEMETHOD_AUTO)
   {
     int deint = -1;
-//    if (m_config.outHeight >= 720)
-//      deint = g_advancedSettings.m_videoVDPAUdeintHD;
-//    else
-//      deint = g_advancedSettings.m_videoVDPAUdeintSD;
+    if (m_config.outHeight >= 720)
+      deint = g_advancedSettings.m_videoVDPAUdeintHD;
+    else
+      deint = g_advancedSettings.m_videoVDPAUdeintSD;
 
     if (deint != -1)
     {
diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp
index e988e1b..710e85e 100644
--- a/xbmc/settings/AdvancedSettings.cpp
+++ b/xbmc/settings/AdvancedSettings.cpp
@@ -106,6 +106,8 @@ void CAdvancedSettings::Initialize()
   m_videoAllowMpeg4VAAPI = false;  
   m_videoDisableBackgroundDeinterlace = false;
   m_videoCaptureUseOcclusionQuery = -1; //-1 is auto detect
+  m_videoVDPAUdeintHD = -1;
+  m_videoVDPAUdeintSD = -1;
   m_videoVDPAUtelecine = false;
   m_videoVDPAUdeintSkipChromaHD = false;
   m_DXVACheckCompatibility = false;
@@ -500,6 +502,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 c0370e6..737fda6 100644
--- a/xbmc/settings/AdvancedSettings.h
+++ b/xbmc/settings/AdvancedSettings.h
@@ -133,6 +133,8 @@ class CAdvancedSettings
     int m_videoPercentSeekBackwardBig;
     CStdString m_videoPPFFmpegDeint;
     CStdString m_videoPPFFmpegPostProc;
+    int m_videoVDPAUdeintHD;
+    int m_videoVDPAUdeintSD;
     bool m_videoVDPAUtelecine;
     bool m_videoVDPAUdeintSkipChromaHD;
     bool m_musicUseTimeSeeking;
-- 
1.7.10


From 09c3552c12928c65853920f85c91b02933666c4b Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Thu, 11 Oct 2012 13:01:08 +0200
Subject: [PATCH 48/58] dvdplayer: correct determination if video is playing

---
 xbmc/cores/dvdplayer/DVDPlayer.cpp |   11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp
index bd84086..b09ed01 100644
--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp
@@ -2389,9 +2389,16 @@ bool CDVDPlayer::IsPaused() const
 
 bool CDVDPlayer::HasVideo() const
 {
-  if (m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD)) return true;
+  bool hasVideo(false);
 
-  return m_SelectionStreams.Count(STREAM_VIDEO) > 0 ? true : false;
+  if (m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD))
+    hasVideo = true;
+  else if (m_SelectionStreams.Count(STREAM_VIDEO) > 0)
+    hasVideo = true;
+  else if (g_renderManager.IsConfigured())
+    hasVideo = true;
+
+  return hasVideo;
 }
 
 bool CDVDPlayer::HasAudio() const
-- 
1.7.10


From 388d82b9394c452affb1379fe74b10066ae01839 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Sun, 14 Oct 2012 13:46:54 +0200
Subject: [PATCH 49/58] rendermanager: fix stuttering in non full-screen mode,
 squash to add buffering

---
 xbmc/cores/VideoRenderers/RenderManager.cpp |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp
index 0506823..b141c80 100644
--- a/xbmc/cores/VideoRenderers/RenderManager.cpp
+++ b/xbmc/cores/VideoRenderers/RenderManager.cpp
@@ -1057,8 +1057,9 @@ void CXBMCRenderManager::PrepareNextRender()
     presenttime = clocktime + MAXPRESENTDELAY;
 
   m_sleeptime = presenttime - clocktime;
+  double frametime = 1 / g_graphicsContext.GetFPS();
 
-  if (g_graphicsContext.IsFullScreenVideo() || presenttime <= clocktime+0.01)
+  if (g_graphicsContext.IsFullScreenVideo() || presenttime <= clocktime + frametime)
   {
     m_presentPts = m_renderBuffers[idx].pts;
     m_presenttime = presenttime;
-- 
1.7.10


From d025c444708f859b397a3cb110be55c73057c92c Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Sun, 14 Oct 2012 17:54:02 +0200
Subject: [PATCH 50/58] rendermanager: forgot to set flip event if buffering
 is not used

---
 xbmc/cores/VideoRenderers/RenderManager.cpp |   20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp
index b141c80..9290f80 100644
--- a/xbmc/cores/VideoRenderers/RenderManager.cpp
+++ b/xbmc/cores/VideoRenderers/RenderManager.cpp
@@ -1096,17 +1096,17 @@ void CXBMCRenderManager::NotifyDisplayFlip()
   if (!m_pRenderer)
     return;
 
-  if (m_iNumRenderBuffers < 3)
-    return;
-
-  int last = m_iDisplayedRenderBuffer;
-  m_iDisplayedRenderBuffer = (m_iCurrentRenderBuffer + m_iNumRenderBuffers - 1) % m_iNumRenderBuffers;
-
-  if (last != m_iDisplayedRenderBuffer
-      && m_iDisplayedRenderBuffer != m_iCurrentRenderBuffer)
+  if (m_iNumRenderBuffers >= 3)
   {
-    m_pRenderer->ReleaseBuffer(m_iDisplayedRenderBuffer);
-    m_overlays.ReleaseBuffer(m_iDisplayedRenderBuffer);
+    int last = m_iDisplayedRenderBuffer;
+    m_iDisplayedRenderBuffer = (m_iCurrentRenderBuffer + m_iNumRenderBuffers - 1) % m_iNumRenderBuffers;
+
+    if (last != m_iDisplayedRenderBuffer
+        && m_iDisplayedRenderBuffer != m_iCurrentRenderBuffer)
+    {
+      m_pRenderer->ReleaseBuffer(m_iDisplayedRenderBuffer);
+      m_overlays.ReleaseBuffer(m_iDisplayedRenderBuffer);
+    }
   }
 
   lock.Leave();
-- 
1.7.10


From 4f19b85dd90f9eea8bf29e6f208e4fdb1da4d160 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Fri, 26 Oct 2012 15:30:22 +0200
Subject: [PATCH 51/58] vdpau: fix small mem leak

---
 xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp |    2 ++
 1 file changed, 2 insertions(+)

diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp
index d95797b..fec4b88 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp
@@ -2052,6 +2052,8 @@ void CMixer::Uninit()
     m_outputSurfaces.pop();
   }
   m_config.vdpProcs.vdp_video_mixer_destroy(m_videoMixer);
+
+  delete [] m_BlackBar;
 }
 
 void CMixer::Flush()
-- 
1.7.10


From 2fdfb80c70f030a51391f93aa57234cc73191e51 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Mon, 29 Oct 2012 18:25:56 +0100
Subject: [PATCH 52/58] xvba: do not render if there is no valid texture

---
 xbmc/cores/VideoRenderers/LinuxRendererGL.cpp |    8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
index 723ab34..4a6ab25 100644
--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
@@ -2929,16 +2929,14 @@ void CLinuxRendererGL::UploadXVBATexture(int index)
   YUVFIELDS &fields = m_buffers[index].fields;
   YUVPLANE &plane = fields[0][1];
 
-  if (!xvba)
+  if (!xvba || !xvba->valid)
   {
-    fields[0][1].id = fields[0][0].id;
     m_eventTexturesDone[index]->Set();
-    CLog::Log(LOGWARNING,"CLinuxRendererGL::UploadXVBATexture no xvba texture, index: %d", index);
+    m_skipRender = true;
     return;
   }
-//  xvba->Transfer();
 
-  fields[0][1].id = xvba->texture;
+  plane.id = xvba->texture;
 
   im.height = xvba->texHeight;
   im.width  = xvba->texWidth;
-- 
1.7.10


From 6cc9cd9c48f4ee86e0f35544284ba65ec6c1b99f Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Fri, 2 Nov 2012 13:20:03 +0100
Subject: [PATCH 53/58] player: fix rewind

---
 xbmc/cores/dvdplayer/DVDMessage.h       |    5 ++++-
 xbmc/cores/dvdplayer/DVDPlayer.cpp      |   33 ++++++++++++++++++++-----------
 xbmc/cores/dvdplayer/DVDPlayer.h        |    7 ++++---
 xbmc/cores/dvdplayer/DVDPlayerVideo.cpp |   10 ++++++----
 xbmc/cores/dvdplayer/DVDPlayerVideo.h   |    1 +
 5 files changed, 36 insertions(+), 20 deletions(-)

diff --git a/xbmc/cores/dvdplayer/DVDMessage.h b/xbmc/cores/dvdplayer/DVDMessage.h
index 30b2f5c..b9831d4 100644
--- a/xbmc/cores/dvdplayer/DVDMessage.h
+++ b/xbmc/cores/dvdplayer/DVDMessage.h
@@ -218,7 +218,7 @@ class CDVDMsgPlayerSetState : public CDVDMsg
 class CDVDMsgPlayerSeek : public CDVDMsg
 {
 public:
-  CDVDMsgPlayerSeek(int time, bool backward, bool flush = true, bool accurate = true, bool restore = true, bool trickplay = false)
+  CDVDMsgPlayerSeek(int time, bool backward, bool flush = true, bool accurate = true, bool restore = true, bool trickplay = false, bool sync = true)
     : CDVDMsg(PLAYER_SEEK)
     , m_time(time)
     , m_backward(backward)
@@ -226,6 +226,7 @@ class CDVDMsgPlayerSeek : public CDVDMsg
     , m_accurate(accurate)
     , m_restore(restore)
     , m_trickplay(trickplay)
+    , m_sync(sync)
   {}
   int  GetTime()              { return m_time; }
   bool GetBackward()          { return m_backward; }
@@ -233,6 +234,7 @@ class CDVDMsgPlayerSeek : public CDVDMsg
   bool GetAccurate()          { return m_accurate; }
   bool GetRestore()           { return m_restore; }
   bool GetTrickPlay()         { return m_trickplay; }
+  bool GetSync()              { return m_sync; }
 private:
   int  m_time;
   bool m_backward;
@@ -240,6 +242,7 @@ class CDVDMsgPlayerSeek : public CDVDMsg
   bool m_accurate;
   bool m_restore; // whether to restore any EDL cut time
   bool m_trickplay;
+  bool m_sync;
 };
 
 class CDVDMsgPlayerSeekChapter : public CDVDMsg
diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp
index b09ed01..da9058d 100644
--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp
@@ -1555,11 +1555,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
@@ -1578,7 +1580,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));
       }
     }
   }
@@ -2037,7 +2039,7 @@ void CDVDPlayer::HandleMessages()
             if(!m_pSubtitleDemuxer->SeekTime(time, msg.GetBackward()))
               CLog::Log(LOGDEBUG, "failed to seek subtitle demuxer: %d, success", time);
           }
-          FlushBuffers(!msg.GetFlush(), start, msg.GetAccurate());
+          FlushBuffers(!msg.GetFlush(), start, msg.GetAccurate(), msg.GetSync());
         }
         else
           CLog::Log(LOGWARNING, "error while seeking");
@@ -2175,9 +2177,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();
         }
 
@@ -2193,7 +2196,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
@@ -2774,10 +2778,11 @@ int64_t CDVDPlayer::GetTime()
   {
     offset  = CDVDClock::GetAbsoluteClock() - m_State.timestamp;
     offset *= m_playSpeed / DVD_PLAYSPEED_NORMAL;
+    offset  = DVD_TIME_TO_MSEC(offset);
     if(offset >  1000) offset =  1000;
     if(offset < -1000) offset = -1000;
   }
-  return llrint(m_State.time + DVD_TIME_TO_MSEC(offset));
+  return llrint(m_State.time + offset);
 }
 
 // return length in msec
@@ -3136,7 +3141,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)
@@ -3148,19 +3153,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;
 
@@ -3204,7 +3213,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 9438a9b..2bbb031 100644
--- a/xbmc/cores/dvdplayer/DVDPlayer.h
+++ b/xbmc/cores/dvdplayer/DVDPlayer.h
@@ -310,7 +310,7 @@ class CDVDPlayer : public IPlayer, public CThread, public IDVDPlayer
   bool GetCachingTimes(double& play_left, double& cache_left, double& file_offset);
 
 
-  void FlushBuffers(bool queued, double pts = DVD_NOPTS_VALUE, bool accurate = true);
+  void FlushBuffers(bool queued, double pts = DVD_NOPTS_VALUE, bool accurate = true, bool sync = true);
 
   void HandleMessages();
   void HandlePlaySpeed();
@@ -359,8 +359,9 @@ class CDVDPlayer : public IPlayer, public CThread, public IDVDPlayer
   int m_playSpeed;
   struct SSpeedState
   {
-    double lastpts;  // holds last display pts during ff/rw operations
-    double lasttime;
+    double  lastpts;  // holds last display pts during ff/rw operations
+    int64_t lasttime;
+    double  lastabstime;
   } m_SpeedState;
 
   int m_errorCount;
diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
index 8b02d81..d26ab9c 100644
--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
@@ -1268,13 +1268,13 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts)
 
   if( m_speed < 0 )
   {
-    double decoderPts = m_droppingStats.m_lastDecoderPts;
+    double inputPts = m_droppingStats.m_lastPts;
     double renderPts = m_droppingStats.m_lastRenderPts;
     if (pts > renderPts)
     {
-      if (decoderPts >= renderPts)
+      if (inputPts >= renderPts)
       {
-        Sleep(200);
+        Sleep(50);
       }
       return result | EOS_DROPPED;
     }
@@ -1571,7 +1571,7 @@ double CDVDPlayerVideo::GetCurrentPts()
 
   if( m_stalled )
     iRenderPts = DVD_NOPTS_VALUE;
-  else
+  else if ( m_speed == DVD_PLAYSPEED_NORMAL)
     iRenderPts = iRenderPts - max(0.0, iSleepTime);
 
   return iRenderPts;
@@ -1671,6 +1671,8 @@ int CDVDPlayerVideo::CalcDropRequirement(double pts)
   int    iSkippedDeint = 0;
   int    iBufferLevel;
 
+  m_droppingStats.m_lastPts = pts;
+
   // get decoder stats
   if (!m_pVideoCodec->GetPts(iDecoderPts, iSkippedDeint, interlaced))
     iDecoderPts = pts;
diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.h b/xbmc/cores/dvdplayer/DVDPlayerVideo.h
index 509d5f7..7cddda7 100644
--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.h
+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.h
@@ -51,6 +51,7 @@ class CDroppingStats
   double m_totalGain;
   double m_lastDecoderPts;
   double m_lastRenderPts;
+  double m_lastPts;
   unsigned int m_lateFrames;
   unsigned int m_dropRequests;
   bool m_requestOutputDrop;
-- 
1.7.10


From 3ca0b89c8009e1e61da27d7bc616b8cb03435bd5 Mon Sep 17 00:00:00 2001
From: fritsch <peter.fruehberger@gmail.com>
Date: Fri, 2 Nov 2012 17:56:12 +0100
Subject: [PATCH 54/58] xvba: do not create decoder for surfaces larger than
 width 2048 or height 1536

---
 xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp |   15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp
index e8e376a..b73c48a 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp
@@ -335,6 +335,21 @@ bool CDecoder::Open(AVCodecContext* avctx, const enum PixelFormat fmt, unsigned
     return false;
   }
 
+  // Fixme: Revisit with new SDK
+  // Workaround for 0.74.01-AES-2 that does not signal if surfaces are too large
+  // it seems that xvba does not support anything > 2k
+  // return false, for files that are larger
+  // if you are unlucky, this would kill your decoder
+  // we limit to 2048x1536(+8) now - as this was tested working
+  int surfaceWidth = (avctx->coded_width+15) & ~15;
+  int surfaceHeight = (avctx->coded_height+15) & ~15;
+  if(surfaceHeight > 1544 || surfaceWidth > 2048)
+  {
+    CLog::Log(LOGERROR, "Surface too large, decoder skipped: surfaceWidth %u, surfaceHeight %u",
+                        surfaceWidth, surfaceHeight);
+    return false;
+  }
+
   if (!m_dllAvUtil.Load())
     return false;
 
-- 
1.7.10


From 7716a8fd17116103cc43c573de398038a614c79e Mon Sep 17 00:00:00 2001
From: fritsch <peter.fruehberger@gmail.com>
Date: Sun, 4 Nov 2012 16:24:10 +0100
Subject: [PATCH 55/58] xvba: add string for available decoders - we are
 important so make sure we are there

---
 xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp |    5 +++++
 1 file changed, 5 insertions(+)

diff --git a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
index 0cea7a9..6fb74b7 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
@@ -169,6 +169,11 @@ CDVDVideoCodec* CDVDFactoryCodec::CreateVideoCodec(CDVDStreamInfo &hint, unsigne
 #elif defined(_LINUX) && !defined(TARGET_DARWIN)
   hwSupport += "VAAPI:no ";
 #endif
+#if defined(HAVE_LIBXVBA) && defined(TARGET_LINUX)
+  hwSupport += "XVBA:yes ";
+#elif defined(TARGET_LINUX)
+  hwSupport += "XVBA:no ";
+#endif
 
   CLog::Log(LOGDEBUG, "CDVDFactoryCodec: compiled in hardware support: %s", hwSupport.c_str());
 
-- 
1.7.10


From a8a42001b07528e79758bfc79717c95f3282dc58 Mon Sep 17 00:00:00 2001
From: fritsch <Peter.Fruehberger@gmail.com>
Date: Thu, 22 Nov 2012 21:32:21 +0100
Subject: [PATCH 56/58] xvba: revisit Artefacts. There are more broken video
 files out there

---
 lib/ffmpeg/libavcodec/xvba_h264.c |   10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/lib/ffmpeg/libavcodec/xvba_h264.c b/lib/ffmpeg/libavcodec/xvba_h264.c
index a077442..87af687 100644
--- a/lib/ffmpeg/libavcodec/xvba_h264.c
+++ b/lib/ffmpeg/libavcodec/xvba_h264.c
@@ -102,10 +102,16 @@ static int end_frame(AVCodecContext *avctx)
   pic_descriptor->avc_num_ref_frames                          = h->sps.ref_frame_count;
   pic_descriptor->avc_reserved_8bit                           = 0;
 
-  /* Set correct level */
-  if (pic_descriptor->level == 41) {
+  /* Set a level that can decode stuff in every case without a lookup table 
+     xvba seems to have problems only when the number of Reframes goes beyond
+     the max support number of Level4.1@High. So in praxis decoding a Level 3.0
+     file that in deed has level4.1@High specs does not matter. We use this fact
+     and check if the ref_frames stay in the range Level4.1@high can decode if
+     not, we set Level5.1 */
+  if (pic_descriptor->avc_num_ref_frames > 4) {
     const unsigned int mbw = pic_descriptor->width_in_mb;
     const unsigned int mbh = pic_descriptor->height_in_mb;
+    // this matches Level4.1@High stats to differ between <= 4.1 and 5.1
     const unsigned int max_ref_frames = 12288 * 1024 / (mbw * mbh * 384);
     const unsigned int num_ref_frames = pic_descriptor->avc_num_ref_frames;
     if (max_ref_frames < num_ref_frames)
-- 
1.7.10


From 5bad32f250578a0ff23a1424039f6acfd43e7f08 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Fri, 23 Nov 2012 09:42:02 +0100
Subject: [PATCH 57/58] xvba: reactivate accidently disabled
 IsDecodingFinished

---
 xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp |    2 --
 1 file changed, 2 deletions(-)

diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp
index b73c48a..47ff25f 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp
@@ -1949,8 +1949,6 @@ void COutput::Flush()
 
 bool COutput::IsDecodingFinished()
 {
-  return true;
-
   // check for decoding to be finished
   CXvbaDecodedPicture decodedPic = m_decodedPics.front();
 
-- 
1.7.10


From 77888a23dd4c76d67481e7e964b0c862403b52c5 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Fri, 23 Nov 2012 17:41:12 +0100
Subject: [PATCH 58/58] xrandr: fix query for multiple screens

---
 xbmc/windowing/X11/XRandR.cpp |   10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/xbmc/windowing/X11/XRandR.cpp b/xbmc/windowing/X11/XRandR.cpp
index cc933b9..533e03d 100644
--- a/xbmc/windowing/X11/XRandR.cpp
+++ b/xbmc/windowing/X11/XRandR.cpp
@@ -57,12 +57,14 @@ bool CXRandR::Query(bool force)
 
   m_outputs.clear();
   // query all screens
+  // we are happy if at least one screen returns results
+  bool success = false;
   for(unsigned int screennum=0; screennum<m_numScreens; ++screennum)
   {
-    if(!Query(force, screennum))
-      return false;
+    if(Query(force, screennum))
+      success = true;
   }
-  return true;
+  return success;
 }
 
 bool CXRandR::Query(bool force, int screennum)
@@ -70,7 +72,7 @@ bool CXRandR::Query(bool force, int screennum)
   CStdString cmd;
   cmd  = getenv("XBMC_BIN_HOME");
   cmd += "/xbmc-xrandr";
-  cmd.append("-q --screen %d", screennum);
+  cmd.AppendFormat(" -q --screen %d", screennum);
 
   FILE* file = popen(cmd.c_str(),"r");
   if (!file)
-- 
1.7.10

