Files
LibreELEC.tv/packages/mediacenter/xbmc/patches.x86/xbmc-801-xvba_support-ae08a23.patch
Stephan Raue 321041a8ba xbmc: update XVBA/VDPAU patches
Signed-off-by: Stephan Raue <stephan@openelec.tv>
2013-01-29 10:22:37 +01:00

19238 lines
621 KiB
Diff

From bfd49543c49747236d401df4351767d584f756ac Mon Sep 17 00:00:00 2001
From: wsnipex <wsnipex@a1.net>
Date: Sun, 4 Nov 2012 14:05:52 +0100
Subject: [PATCH 01/72] configure: add --enable-pvraddons-with-dependencies
switch for intree building of PVR Addons
---
configure.in | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/configure.in b/configure.in
index 4769315..350d960 100644
--- a/configure.in
+++ b/configure.in
@@ -521,6 +521,14 @@ AC_ARG_ENABLE([external-ffmpeg],
[use_external_ffmpeg=$use_external_libraries])
### End of external library options
+### PVR addons specific
+AC_ARG_ENABLE([pvraddons-with-dependencies],
+ [AS_HELP_STRING([--enable-pvraddons-with-dependencies],
+ [enable build of pvr addons with dependencies (default is no) 'Linux only'])],
+ [use_pvraddons_with_deps=$enableval],
+ [use_pvraddons_with_deps=no])
+
+### End PVR addons specific
if test "x$host_vendor" != "xapple"; then
DEFAULT_COMPILE_FLAGS="-fPIC -DPIC -D_REENTRANT"
@@ -2770,12 +2778,16 @@ XB_CONFIG_MODULE([pvr-addons], [
if test "$USE_EXTERNAL_FFMPEG" = 1; then
PVR_EXT_FFMPEG="--enable-external-ffmpeg"
fi
+ if test "$use_pvraddons_with_deps" = "yes"; then
+ ADDONS_WITH_DEPS="--enable-addons-with-dependencies"
+ fi
./configure \
--prefix="${prefix}" \
--host=$host_alias \
--build=$build_alias \
--target=$target_alias \
$PVR_EXT_FFMPEG \
+ $ADDONS_WITH_DEPS \
CC="$CC" \
CXX="$CXX" \
CFLAGS="$CFLAGS" \
--
1.7.10
From dc83e2351e8bf8e904102782ea489d2c8caa2802 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Mon, 28 May 2012 10:03:31 +0200
Subject: [PATCH 02/72] VideoRenerers: add buffering
---
xbmc/Application.cpp | 3 +
xbmc/cores/VideoRenderers/BaseRenderer.h | 5 +-
xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 41 ++--
xbmc/cores/VideoRenderers/LinuxRendererGL.h | 13 +-
xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 8 +-
xbmc/cores/VideoRenderers/LinuxRendererGLES.h | 4 +-
xbmc/cores/VideoRenderers/OverlayRenderer.cpp | 19 +-
xbmc/cores/VideoRenderers/OverlayRenderer.h | 6 +-
xbmc/cores/VideoRenderers/RenderManager.cpp | 296 +++++++++++++++++++----
xbmc/cores/VideoRenderers/RenderManager.h | 48 +++-
xbmc/cores/VideoRenderers/WinRenderer.cpp | 8 +-
xbmc/cores/VideoRenderers/WinRenderer.h | 2 +-
xbmc/cores/dvdplayer/DVDPlayer.cpp | 2 +-
xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 18 +-
14 files changed, 380 insertions(+), 93 deletions(-)
diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp
index c6f0a14..18e6310 100644
--- a/xbmc/Application.cpp
+++ b/xbmc/Application.cpp
@@ -2367,7 +2367,10 @@ void CApplication::Render()
m_lastFrameTime = XbmcThreads::SystemClockMillis();
if (flip)
+ {
g_graphicsContext.Flip(dirtyRegions);
+ g_renderManager.NotifyDisplayFlip();
+ }
CTimeUtils::UpdateFrameTime(flip);
g_TextureManager.FreeUnusedTextures();
diff --git a/xbmc/cores/VideoRenderers/BaseRenderer.h b/xbmc/cores/VideoRenderers/BaseRenderer.h
index 81d21d8..b02d536 100644
--- a/xbmc/cores/VideoRenderers/BaseRenderer.h
+++ b/xbmc/cores/VideoRenderers/BaseRenderer.h
@@ -80,10 +80,13 @@ class CBaseRenderer
void GetVideoRect(CRect &source, CRect &dest);
float GetAspectRatio() const;
- virtual bool AddVideoPicture(DVDVideoPicture* picture) { return false; }
+ virtual bool AddVideoPicture(DVDVideoPicture* picture, int index) { return false; }
virtual void Flush() {};
virtual unsigned int GetProcessorSize() { return 0; }
+ virtual unsigned int GetMaxProcessorSize() { return 0; }
+ virtual void SetProcessorSize(int numBuffers) { }
+ virtual void ReleaseBuffer(int idx) { }
virtual bool Supports(ERENDERFEATURE feature) { return false; }
diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
index 1cf52d3..b32a7ea 100644
--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
@@ -235,14 +235,6 @@ bool CLinuxRendererGL::ValidateRenderer()
return true;
}
-
-void CLinuxRendererGL::ManageTextures()
-{
- m_NumYV12Buffers = 2;
- //m_iYV12RenderBuffer = 0;
- return;
-}
-
bool CLinuxRendererGL::ValidateRenderTarget()
{
if (!m_bValidated)
@@ -603,13 +595,28 @@ void CLinuxRendererGL::Flush()
glFinish();
m_bValidated = false;
m_fbo.fbo.Cleanup();
+ m_iYV12RenderBuffer = 0;
+}
+
+void CLinuxRendererGL::ReleaseBuffer(int idx)
+{
+ YUVBUFFER &buf = m_buffers[idx];
+#ifdef HAVE_LIBVDPAU
+ SAFE_RELEASE(buf.vdpau);
+#endif
+#ifdef HAVE_LIBVA
+ buf.vaapi.surface.reset();
+#endif
+#ifdef TARGET_DARWIN
+ if (buf.cvBufferRef)
+ CVBufferRelease(buf.cvBufferRef);
+#endif
}
void CLinuxRendererGL::Update(bool bPauseDrawing)
{
if (!m_bConfigured) return;
ManageDisplay();
- ManageTextures();
}
void CLinuxRendererGL::RenderUpdate(bool clear, DWORD flags, DWORD alpha)
@@ -625,7 +632,6 @@ void CLinuxRendererGL::RenderUpdate(bool clear, DWORD flags, DWORD alpha)
}
ManageDisplay();
- ManageTextures();
g_graphicsContext.BeginPaint();
@@ -782,7 +788,6 @@ unsigned int CLinuxRendererGL::PreInit()
m_resolution = RES_DESKTOP;
m_iYV12RenderBuffer = 0;
- m_NumYV12Buffers = 2;
m_formats.push_back(RENDER_FMT_YUV420P);
GLint size;
@@ -2465,7 +2470,7 @@ void CLinuxRendererGL::UploadVAAPITexture(int index)
|| status == VA_STATUS_ERROR_INVALID_DISPLAY)
{
va.display->lost(true);
- for(int i = 0; i < NUM_BUFFERS; i++)
+ for(int i = 0; i < m_NumYV12Buffers; i++)
{
m_buffers[i].vaapi.display.reset();
m_buffers[i].vaapi.surface.reset();
@@ -3412,26 +3417,26 @@ void CLinuxRendererGL::UnBindPbo(YUVBUFFER& buff)
}
#ifdef HAVE_LIBVDPAU
-void CLinuxRendererGL::AddProcessor(CVDPAU* vdpau)
+void CLinuxRendererGL::AddProcessor(CVDPAU* vdpau, int index)
{
- YUVBUFFER &buf = m_buffers[NextYV12Texture()];
+ YUVBUFFER &buf = m_buffers[index];
SAFE_RELEASE(buf.vdpau);
buf.vdpau = (CVDPAU*)vdpau->Acquire();
}
#endif
#ifdef HAVE_LIBVA
-void CLinuxRendererGL::AddProcessor(VAAPI::CHolder& holder)
+void CLinuxRendererGL::AddProcessor(VAAPI::CHolder& holder, int index)
{
- YUVBUFFER &buf = m_buffers[NextYV12Texture()];
+ YUVBUFFER &buf = m_buffers[index];
buf.vaapi.surface = holder.surface;
}
#endif
#ifdef TARGET_DARWIN
-void CLinuxRendererGL::AddProcessor(struct __CVBuffer *cvBufferRef)
+void CLinuxRendererGL::AddProcessor(struct __CVBuffer *cvBufferRef, int index)
{
- YUVBUFFER &buf = m_buffers[NextYV12Texture()];
+ YUVBUFFER &buf = m_buffers[index];
if (buf.cvBufferRef)
CVBufferRelease(buf.cvBufferRef);
buf.cvBufferRef = cvBufferRef;
diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.h b/xbmc/cores/VideoRenderers/LinuxRendererGL.h
index acebfe0..9f55fcb 100644
--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.h
+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.h
@@ -44,7 +44,7 @@
namespace Shaders { class BaseVideoFilterShader; }
namespace VAAPI { struct CHolder; }
-#define NUM_BUFFERS 3
+#define NUM_BUFFERS 10
#undef ALIGN
@@ -138,15 +138,19 @@ class CLinuxRendererGL : public CBaseRenderer
virtual void UnInit();
virtual void Reset(); /* resets renderer after seek for example */
virtual void Flush();
+ virtual void ReleaseBuffer(int idx);
+ virtual void SetProcessorSize(int numBuffers) { m_NumYV12Buffers = numBuffers; }
+ virtual unsigned int GetMaxProcessorSize() { return NUM_BUFFERS; }
+ virtual unsigned int GetProcessorSize() { return m_NumYV12Buffers; }
#ifdef HAVE_LIBVDPAU
- virtual void AddProcessor(CVDPAU* vdpau);
+ virtual void AddProcessor(CVDPAU* vdpau, int index);
#endif
#ifdef HAVE_LIBVA
- virtual void AddProcessor(VAAPI::CHolder& holder);
+ virtual void AddProcessor(VAAPI::CHolder& holder, int index);
#endif
#ifdef TARGET_DARWIN
- virtual void AddProcessor(struct __CVBuffer *cvBufferRef);
+ virtual void AddProcessor(struct __CVBuffer *cvBufferRef, int index);
#endif
virtual void RenderUpdate(bool clear, DWORD flags = 0, DWORD alpha = 255);
@@ -168,7 +172,6 @@ class CLinuxRendererGL : public CBaseRenderer
void DrawBlackBars();
bool ValidateRenderer();
- virtual void ManageTextures();
int NextYV12Texture();
virtual bool ValidateRenderTarget();
virtual void LoadShaders(int field=FIELD_FULL);
diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
index cb0939f..2a59e2b 100644
--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
+++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
@@ -1982,16 +1982,16 @@ EINTERLACEMETHOD CLinuxRendererGLES::AutoInterlaceMethod()
}
#ifdef HAVE_LIBOPENMAX
-void CLinuxRendererGLES::AddProcessor(COpenMax* openMax, DVDVideoPicture *picture)
+void CLinuxRendererGLES::AddProcessor(COpenMax* openMax, DVDVideoPicture *picture, int index)
{
- YUVBUFFER &buf = m_buffers[NextYV12Texture()];
+ YUVBUFFER &buf = m_buffers[index];
buf.openMaxBuffer = picture->openMaxBuffer;
}
#endif
#ifdef HAVE_VIDEOTOOLBOXDECODER
-void CLinuxRendererGLES::AddProcessor(struct __CVBuffer *cvBufferRef)
+void CLinuxRendererGLES::AddProcessor(struct __CVBuffer *cvBufferRef, int index)
{
- YUVBUFFER &buf = m_buffers[NextYV12Texture()];
+ YUVBUFFER &buf = m_buffers[index];
if (buf.cvBufferRef)
CVBufferRelease(buf.cvBufferRef);
buf.cvBufferRef = cvBufferRef;
diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h
index 76b5437..c6b69db 100644
--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h
+++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h
@@ -153,10 +153,10 @@ class CLinuxRendererGLES : public CBaseRenderer
virtual std::vector<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 0cd2510..315d64a 100644
--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp
@@ -463,7 +463,7 @@ bool CDVDPlayer::OpenFile(const CFileItem& file, const CPlayerOptions &options)
m_ready.Reset();
#if defined(HAS_VIDEO_PLAYBACK)
- g_renderManager.PreInit();
+ g_renderManager.PreInit(&m_clock);
#endif
Create();
diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
index 3008c25..a4bb1ba 100644
--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
@@ -261,6 +261,7 @@ void CDVDPlayerVideo::OpenStream(CDVDStreamInfo &hint, CDVDVideoCodec* codec)
m_stalled = m_messageQueue.GetPacketCount(CDVDMsg::DEMUXER_PACKET) == 0;
m_started = false;
m_codecname = m_pVideoCodec->GetName();
+ g_renderManager.EnableBuffering(false);
}
void CDVDPlayerVideo::CloseStream(bool bWaitForBuffers)
@@ -436,6 +437,7 @@ void CDVDPlayerVideo::Process()
picture.iFlags &= ~DVP_FLAG_ALLOCATED;
m_packets.clear();
m_started = false;
+ g_renderManager.EnableBuffering(false);
}
else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) // private message sent by (CDVDPlayerVideo::Flush())
{
@@ -448,6 +450,7 @@ void CDVDPlayerVideo::Process()
//we need to recalculate the framerate
//TODO: this needs to be set on a streamchange instead
ResetFrameRateCalc();
+ g_renderManager.EnableBuffering(false);
m_stalled = true;
m_started = false;
@@ -586,6 +589,8 @@ void CDVDPlayerVideo::Process()
m_pVideoCodec->Reset();
m_packets.clear();
+ picture.iFlags &= ~DVP_FLAG_ALLOCATED;
+ g_renderManager.DiscardBuffer();
break;
}
@@ -700,6 +705,7 @@ void CDVDPlayerVideo::Process()
m_codecname = m_pVideoCodec->GetName();
m_started = true;
m_messageParent.Put(new CDVDMsgInt(CDVDMsg::PLAYER_STARTED, DVDPLAYER_VIDEO));
+ g_renderManager.EnableBuffering(true);
}
// guess next frame pts. iDuration is always valid
@@ -1317,6 +1323,16 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts)
mDisplayField = FS_BOT;
}
+ int buffer = g_renderManager.WaitForBuffer(m_bStop);
+ while (buffer < 0 && !CThread::m_bStop &&
+ CDVDClock::GetAbsoluteClock(false) < iCurrentClock + iSleepTime + DVD_MSEC_TO_TIME(500) )
+ {
+ Sleep(1);
+ buffer = g_renderManager.WaitForBuffer(m_bStop);
+ }
+ if (buffer < 0)
+ return EOS_DROPPED;
+
ProcessOverlays(pPicture, pts);
AutoCrop(pPicture);
@@ -1333,7 +1349,7 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts)
if (index < 0)
return EOS_DROPPED;
- g_renderManager.FlipPage(CThread::m_bStop, (iCurrentClock + iSleepTime) / DVD_TIME_BASE, -1, mDisplayField);
+ g_renderManager.FlipPage(CThread::m_bStop, pts, -1, mDisplayField, m_speed);
return result;
#else
--
1.7.10
From dacc0167c993efa6ac884fd3c439fc5f0c823934 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Tue, 2 Oct 2012 10:49:09 +0200
Subject: [PATCH 03/72] linuxrenderer: delete all textures on reconfigure
---
xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
index b32a7ea..a2dc2be 100644
--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
@@ -251,7 +251,7 @@ bool CLinuxRendererGL::ValidateRenderTarget()
// function pointer for texture might change in
// call to LoadShaders
glFinish();
- for (int i = 0 ; i < m_NumYV12Buffers ; i++)
+ for (int i = 0 ; i < NUM_BUFFERS ; i++)
(this->*m_textureDelete)(i);
// trigger update of video filters
--
1.7.10
From 226539d21ba940ea8add89417df7102302c7ba79 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Mon, 28 May 2012 10:17:33 +0200
Subject: [PATCH 04/72] drop frame counter in application, ask render manager
instead
---
xbmc/Application.cpp | 50 +++++----------------------
xbmc/Application.h | 6 ++--
xbmc/cores/VideoRenderers/RenderManager.cpp | 11 ++++++
xbmc/cores/VideoRenderers/RenderManager.h | 1 +
4 files changed, 23 insertions(+), 45 deletions(-)
diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp
index 18e6310..9a7b900 100644
--- a/xbmc/Application.cpp
+++ b/xbmc/Application.cpp
@@ -415,8 +415,6 @@
#endif
m_currentStack = new CFileItemList;
- m_frameCount = 0;
-
m_bPresentFrame = false;
m_bPlatformDirectories = true;
@@ -2227,28 +2225,18 @@ float CApplication::GetDimScreenSaverLevel() const
bool CApplication::WaitFrame(unsigned int timeout)
{
- bool done = false;
-
// Wait for all other frames to be presented
- CSingleLock lock(m_frameMutex);
- //wait until event is set, but modify remaining time
+ m_frameEvent.Reset();
- TightConditionVariable<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()
@@ -2268,7 +2256,6 @@ void CApplication::Render()
int vsync_mode = g_guiSettings.GetInt("videoscreen.vsync");
- bool decrement = false;
bool hasRendered = false;
bool limitFrames = false;
unsigned int singleFrameTime = 10; // default limit 100 fps
@@ -2282,13 +2269,10 @@ void CApplication::Render()
m_bPresentFrame = false;
if (!extPlayerActive && g_graphicsContext.IsFullScreenVideo() && !IsPaused())
{
- CSingleLock lock(m_frameMutex);
-
- TightConditionVariable<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
@@ -2312,8 +2296,6 @@ void CApplication::Render()
else if (lowfps)
singleFrameTime = 200; // 5 fps, <=200 ms latency to wake up
}
-
- decrement = true;
}
}
@@ -2377,13 +2359,6 @@ void CApplication::Render()
g_renderManager.UpdateResolution();
g_renderManager.ManageCaptures();
-
- {
- CSingleLock lock(m_frameMutex);
- if(m_frameCount > 0 && decrement)
- m_frameCount--;
- }
- m_frameCond.notifyAll();
}
void CApplication::SetStandAlone(bool value)
@@ -5638,12 +5613,6 @@ bool CApplication::SwitchToFullScreen()
// See if we're playing a video, and are in GUI mode
if ( IsPlayingVideo() && g_windowManager.GetActiveWindow() != WINDOW_FULLSCREEN_VIDEO)
{
- // Reset frame count so that timing is FPS will be correct.
- {
- CSingleLock lock(m_frameMutex);
- m_frameCount = 0;
- }
-
// then switch to fullscreen mode
g_windowManager.ActivateWindow(WINDOW_FULLSCREEN_VIDEO);
return true;
@@ -5876,7 +5845,6 @@ bool CApplication::IsCurrentThread() const
bool CApplication::IsPresentFrame()
{
- CSingleLock lock(m_frameMutex);
bool ret = m_bPresentFrame;
return ret;
diff --git a/xbmc/Application.h b/xbmc/Application.h
index 69609fa..6764a60 100644
--- a/xbmc/Application.h
+++ b/xbmc/Application.h
@@ -422,10 +422,8 @@ class CApplication : public CXBApplicationEx, public IPlayerCallback, public IMs
bool m_bEnableLegacyRes;
bool m_bTestMode;
bool m_bSystemScreenSaverEnable;
-
- int m_frameCount;
- CCriticalSection m_frameMutex;
- XbmcThreads::ConditionVariable m_frameCond;
+
+ CEvent m_frameEvent;
VIDEO::CVideoInfoScanner *m_videoInfoScanner;
MUSIC_INFO::CMusicInfoScanner *m_musicInfoScanner;
diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp
index eeb6c6f..4b897da 100644
--- a/xbmc/cores/VideoRenderers/RenderManager.cpp
+++ b/xbmc/cores/VideoRenderers/RenderManager.cpp
@@ -1104,3 +1104,14 @@ void CXBMCRenderManager::NotifyDisplayFlip()
lock.Leave();
m_flipEvent.Set();
}
+
+bool CXBMCRenderManager::HasFrame()
+{
+ CSharedLock lock(m_sharedSection);
+ if (m_presentstep == PRESENT_IDLE &&
+ GetNextRenderBufferIndex() < 0 &&
+ m_speed > 0)
+ return false;
+ else
+ return true;
+}
diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h
index 34ff8d0..288175e 100644
--- a/xbmc/cores/VideoRenderers/RenderManager.h
+++ b/xbmc/cores/VideoRenderers/RenderManager.h
@@ -134,6 +134,7 @@ class CXBMCRenderManager
void RegisterRenderUpdateCallBack(const void *ctx, RenderUpdateCallBackFn fn);
int WaitForBuffer(volatile bool& bStop);
void NotifyDisplayFlip();
+ bool HasFrame();
void EnableBuffering(bool enable);
void DiscardBuffer();
--
1.7.10
From 0f81843cb7279f3b99607551967354ff30e15e4d Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Mon, 28 May 2012 10:34:39 +0200
Subject: [PATCH 05/72] 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 4bc6ff77b121468020578f9d393e8aaae1a419f6 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Mon, 28 May 2012 10:41:31 +0200
Subject: [PATCH 06/72] videoplayer: update frametime, it might change due to
fps detection
---
xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 2 ++
1 file changed, 2 insertions(+)
diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
index 93908a7..4675556 100644
--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
@@ -721,6 +721,8 @@ void CDVDPlayerVideo::Process()
CDVDCodecUtils::FreePicture(pTempYUVPackedPicture);
#endif
+ frametime = (double)DVD_TIME_BASE/m_fFrameRate;
+
if(m_started == false)
{
m_codecname = m_pVideoCodec->GetName();
--
1.7.10
From 723a731d68b9360f9804e8711255afa62c4ce34d Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Mon, 28 May 2012 10:43:06 +0200
Subject: [PATCH 07/72] videoplayer: give streams with invalid fps a chance
for fps detection
---
xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
index 4675556..2ef6358 100644
--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
@@ -1595,7 +1595,7 @@ void CDVDPlayerVideo::CalcFrameRate()
double frameduration = m_pullupCorrection.GetFrameDuration();
if (frameduration == DVD_NOPTS_VALUE ||
- (g_advancedSettings.m_videoFpsDetect == 1 && m_pullupCorrection.GetPatternLength() > 1))
+ (g_advancedSettings.m_videoFpsDetect == 1 && (m_pullupCorrection.GetPatternLength() > 1 && !m_bFpsInvalid)))
{
//reset the stored framerates if no good framerate was detected
m_fStableFrameRate = 0.0;
--
1.7.10
From 60c955c30cdfcf361396e47fc92a1e1883b085fe Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Mon, 28 May 2012 10:49:05 +0200
Subject: [PATCH 08/72] dvdplayer: allow rewinding at end of stream, do a seek
after rewind
---
xbmc/cores/dvdplayer/DVDPlayer.cpp | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp
index 315d64a..6fcb6b3 100644
--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp
@@ -1542,7 +1542,7 @@ void CDVDPlayer::HandlePlaySpeed()
}
else if (m_CurrentVideo.id >= 0
- && m_CurrentVideo.inited == true
+ && (m_CurrentVideo.inited == true || GetPlaySpeed() < 0) // allow rewind at end of file
&& m_SpeedState.lastpts != m_dvdPlayerVideo.GetCurrentPts()
&& m_SpeedState.lasttime != GetTime())
{
@@ -2183,6 +2183,12 @@ void CDVDPlayer::HandleMessages()
pvrinputstream->Pause( speed == 0 );
}
+ // do a seek after rewind, clock is not in sync with current pts
+ if (m_playSpeed < 0 && speed >= 0)
+ {
+ m_messenger.Put(new CDVDMsgPlayerSeek(GetTime(), true, true, true));
+ }
+
// if playspeed is different then DVD_PLAYSPEED_NORMAL or DVD_PLAYSPEED_PAUSE
// audioplayer, stops outputing audio to audiorendere, but still tries to
// sleep an correct amount for each packet
--
1.7.10
From 8d237cf023501560fc394679819463034a209413 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Sun, 2 Sep 2012 16:05:21 +0200
Subject: [PATCH 09/72] video player: present correct pts to user for a/v sync
(after buffering in renderer)
---
xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 41 +++++++++++++++++++------------
xbmc/cores/dvdplayer/DVDPlayerVideo.h | 2 +-
2 files changed, 26 insertions(+), 17 deletions(-)
diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
index 2ef6358..10e2225 100644
--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
@@ -1251,22 +1251,6 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts)
else
iSleepTime = iFrameSleep + (iClockSleep - iFrameSleep) / m_autosync;
-#ifdef PROFILE /* during profiling, try to play as fast as possible */
- iSleepTime = 0;
-#endif
-
- // present the current pts of this frame to user, and include the actual
- // presentation delay, to allow him to adjust for it
- if( m_stalled )
- m_iCurrentPts = DVD_NOPTS_VALUE;
- else
- m_iCurrentPts = pts - max(0.0, iSleepTime);
-
- // timestamp when we think next picture should be displayed based on current duration
- m_FlipTimeStamp = iCurrentClock;
- m_FlipTimeStamp += max(0.0, iSleepTime);
- m_FlipTimeStamp += iFrameDuration;
-
if ((m_droppingStats.m_requestOutputDrop && !(pPicture->iFlags & DVP_FLAG_NOSKIP))
|| (pPicture->iFlags & DVP_FLAG_DROPPED))
{
@@ -1571,6 +1555,22 @@ void CDVDPlayerVideo::ResetFrameRateCalc()
g_advancedSettings.m_videoFpsDetect == 0;
}
+double CDVDPlayerVideo::GetCurrentPts()
+{
+ double iSleepTime, iRenderPts;
+ int iBufferLevel;
+
+ // get render stats
+ g_renderManager.GetStats(iSleepTime, iRenderPts, iBufferLevel);
+
+ if( m_stalled )
+ iRenderPts = DVD_NOPTS_VALUE;
+ else
+ iRenderPts = iRenderPts - max(0.0, iSleepTime);
+
+ return iRenderPts;
+}
+
#define MAXFRAMERATEDIFF 0.01
#define MAXFRAMESERR 1000
@@ -1689,6 +1689,15 @@ int CDVDPlayerVideo::CalcDropRequirement(double pts)
else
iInterval = 1/m_fFrameRate*(double)DVD_TIME_BASE;
+
+ m_FlipTimeStamp = m_pClock->GetAbsoluteClock() + max(0.0, iSleepTime) + iInterval;
+
+ if( m_stalled )
+ m_iCurrentPts = DVD_NOPTS_VALUE;
+ else
+ m_iCurrentPts = iRenderPts - max(0.0, iSleepTime);
+
+
if (m_droppingStats.m_lastDecoderPts > 0
&& bNewFrame
&& m_bAllowDrop
diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.h b/xbmc/cores/dvdplayer/DVDPlayerVideo.h
index 4913712..509d5f7 100644
--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.h
+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.h
@@ -108,7 +108,7 @@ class CDVDPlayerVideo : public CThread
bool InitializedOutputDevice();
- double GetCurrentPts() { return m_iCurrentPts; }
+ double GetCurrentPts();
int GetPullupCorrection() { return m_pullupCorrection.GetPatternLength(); }
double GetOutputDelay(); /* returns the expected delay, from that a packet is put in queue */
--
1.7.10
From 04a6a8b4ca29c17da6bbb9591685922b2f6f1442 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Mon, 28 May 2012 11:02:29 +0200
Subject: [PATCH 10/72] 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 4d237410264bbff9c4ac373de498f80ecb15f7a3 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Sat, 7 Apr 2012 09:19:00 +0200
Subject: [PATCH 11/72] vdpau: redesign
---
language/English/strings.po | 12 +-
system/shaders/yuv2rgb_basic.glsl | 12 +
xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 203 +-
xbmc/cores/VideoRenderers/LinuxRendererGL.h | 13 +-
xbmc/cores/VideoRenderers/RenderFormats.h | 1 +
xbmc/cores/VideoRenderers/RenderManager.cpp | 8 +-
xbmc/cores/VideoRenderers/RenderManager.h | 2 +-
.../VideoRenderers/VideoShaders/YUV2RGBShader.cpp | 2 +
.../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h | 4 +-
.../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 23 +-
.../DVDCodecs/Video/DVDVideoCodecFFmpeg.h | 1 -
xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 3798 +++++++++++++++-----
xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h | 662 +++-
xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 3 +
xbmc/settings/AdvancedSettings.cpp | 8 +-
xbmc/settings/AdvancedSettings.h | 4 +-
xbmc/settings/GUISettings.cpp | 2 +
xbmc/settings/GUIWindowSettingsCategory.cpp | 34 +
xbmc/utils/ActorProtocol.cpp | 253 ++
xbmc/utils/ActorProtocol.h | 87 +
xbmc/utils/Makefile | 1 +
xbmc/video/dialogs/GUIDialogVideoSettings.cpp | 2 +-
xbmc/windowing/X11/WinSystemX11.h | 1 +
23 files changed, 3942 insertions(+), 1194 deletions(-)
create mode 100644 xbmc/utils/ActorProtocol.cpp
create mode 100644 xbmc/utils/ActorProtocol.h
diff --git a/language/English/strings.po b/language/English/strings.po
index dff2978..88292d3 100644
--- a/language/English/strings.po
+++ b/language/English/strings.po
@@ -5114,7 +5114,15 @@ msgctxt "#13434"
msgid "Play only this"
msgstr ""
-#empty strings from id 13435 to 13499
+msgctxt "#13435"
+msgid "Allow Vdpau OpenGL interop"
+msgstr ""
+
+msgctxt "#13436"
+msgid "Allow Vdpau OpenGL interop YUV"
+msgstr ""
+
+#empty strings from id 13437 to 13499
msgctxt "#13500"
msgid "A/V sync method"
@@ -6333,7 +6341,7 @@ msgid "Software Blend"
msgstr ""
msgctxt "#16325"
-msgid "Auto - ION Optimized"
+msgid "VDPAU - Bob"
msgstr ""
#empty strings from id 16326 to 16399
diff --git a/system/shaders/yuv2rgb_basic.glsl b/system/shaders/yuv2rgb_basic.glsl
index 88c33b2..aa26174 100644
--- a/system/shaders/yuv2rgb_basic.glsl
+++ b/system/shaders/yuv2rgb_basic.glsl
@@ -70,6 +70,18 @@ void main()
rgb.a = gl_Color.a;
gl_FragColor = rgb;
+#elif defined(XBMC_VDPAU_NV12)
+
+ vec4 yuv, rgb;
+ yuv.rgba = vec4( texture2D(m_sampY, stretch(m_cordY)).r
+ , texture2D(m_sampU, stretch(m_cordU)).r
+ , texture2D(m_sampV, stretch(m_cordV)).g
+ , 1.0 );
+
+ rgb = m_yuvmat * yuv;
+ rgb.a = gl_Color.a;
+ gl_FragColor = rgb;
+
#elif defined(XBMC_YUY2) || defined(XBMC_UYVY)
#if(XBMC_texture_rectangle)
diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
index a2dc2be..4ee50c1 100644
--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
@@ -689,6 +689,18 @@ void CLinuxRendererGL::RenderUpdate(bool clear, DWORD flags, DWORD alpha)
glDisable(GL_POLYGON_STIPPLE);
}
+ else if(m_format == RENDER_FMT_VDPAU_420
+ && !(flags & RENDER_FLAG_BOTH))
+ {
+ glDisable(GL_BLEND);
+ glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+ Render(flags | RENDER_FLAG_TOP, index);
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glColor4f(1.0f, 1.0f, 1.0f, 128 / 255.0f);
+ Render(flags | RENDER_FLAG_BOT , index);
+ }
else
Render(flags, index);
@@ -769,11 +781,6 @@ void CLinuxRendererGL::FlipPage(int source)
m_buffers[m_iYV12RenderBuffer].flipindex = ++m_flipindex;
-#ifdef HAVE_LIBVDPAU
- if((m_renderMethod & RENDER_VDPAU) && m_buffers[m_iYV12RenderBuffer].vdpau)
- m_buffers[m_iYV12RenderBuffer].vdpau->Present();
-#endif
-
return;
}
@@ -1100,6 +1107,12 @@ void CLinuxRendererGL::LoadShaders(int field)
m_textureCreate = &CLinuxRendererGL::CreateVDPAUTexture;
m_textureDelete = &CLinuxRendererGL::DeleteVDPAUTexture;
}
+ else if (m_format == RENDER_FMT_VDPAU_420)
+ {
+ m_textureUpload = &CLinuxRendererGL::UploadVDPAUTexture420;
+ m_textureCreate = &CLinuxRendererGL::CreateVDPAUTexture420;
+ m_textureDelete = &CLinuxRendererGL::DeleteVDPAUTexture420;
+ }
else if (m_format == RENDER_FMT_VAAPI)
{
m_textureUpload = &CLinuxRendererGL::UploadVAAPITexture;
@@ -1175,7 +1188,10 @@ void CLinuxRendererGL::Render(DWORD flags, int renderBuffer)
m_currentField = FIELD_FULL;
// call texture load function
+ m_skipRender = false;
(this->*m_textureUpload)(renderBuffer);
+ if (m_skipRender)
+ return;
if (m_renderMethod & RENDER_GLSL)
{
@@ -1541,17 +1557,12 @@ void CLinuxRendererGL::RenderFromFBO()
void CLinuxRendererGL::RenderVDPAU(int index, int field)
{
#ifdef HAVE_LIBVDPAU
- YUVPLANE &plane = m_buffers[index].fields[field][0];
- CVDPAU *vdpau = m_buffers[m_iYV12RenderBuffer].vdpau;
-
- if (!vdpau)
- return;
+ YUVPLANE &plane = m_buffers[index].fields[0][1];
glEnable(m_textureTarget);
glActiveTextureARB(GL_TEXTURE0);
- glBindTexture(m_textureTarget, plane.id);
- vdpau->BindPixmap();
+ glBindTexture(m_textureTarget, plane.id);
// Try some clamping or wrapping
glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@@ -1609,8 +1620,6 @@ void CLinuxRendererGL::RenderVDPAU(int index, int field)
if (m_pVideoFilterShader)
m_pVideoFilterShader->Disable();
- vdpau->ReleasePixmap();
-
glBindTexture (m_textureTarget, 0);
glDisable(m_textureTarget);
#endif
@@ -2295,12 +2304,14 @@ void CLinuxRendererGL::DeleteVDPAUTexture(int index)
{
#ifdef HAVE_LIBVDPAU
YUVPLANE &plane = m_buffers[index].fields[0][0];
+ YUVFIELDS &fields = m_buffers[index].fields;
SAFE_RELEASE(m_buffers[index].vdpau);
if(plane.id && glIsTexture(plane.id))
glDeleteTextures(1, &plane.id);
plane.id = 0;
+ fields[0][1].id = 0;
#endif
}
@@ -2334,11 +2345,152 @@ bool CLinuxRendererGL::CreateVDPAUTexture(int index)
void CLinuxRendererGL::UploadVDPAUTexture(int index)
{
#ifdef HAVE_LIBVDPAU
+ VDPAU::CVdpauRenderPicture *vdpau = m_buffers[index].vdpau;
+
+ unsigned int flipindex = m_buffers[index].flipindex;
+ YUVFIELDS &fields = m_buffers[index].fields;
+ YUVPLANE &plane = fields[0][0];
+
+ if (!vdpau || !vdpau->valid)
+ {
+ m_eventTexturesDone[index]->Set();
+ m_skipRender = true;
+ return;
+ }
+
+ fields[0][1].id = vdpau->texture[0];
+
+ m_eventTexturesDone[index]->Set();
+#endif
+}
+
+void CLinuxRendererGL::DeleteVDPAUTexture420(int index)
+{
+#ifdef HAVE_LIBVDPAU
+ YUVPLANE &plane = m_buffers[index].fields[0][0];
+ YUVFIELDS &fields = m_buffers[index].fields;
+
+ SAFE_RELEASE(m_buffers[index].vdpau);
+
+ if(plane.id && glIsTexture(plane.id))
+ glDeleteTextures(1, &plane.id);
+ plane.id = 0;
+ fields[1][0].id = 0;
+ fields[1][1].id = 0;
+ fields[2][0].id = 0;
+ fields[2][1].id = 0;
+
+#endif
+}
+
+bool CLinuxRendererGL::CreateVDPAUTexture420(int index)
+{
+#ifdef HAVE_LIBVDPAU
+ YV12Image &im = m_buffers[index].image;
+ YUVFIELDS &fields = m_buffers[index].fields;
+ YUVPLANE &plane = fields[0][0];
+ GLuint *pbo = m_buffers[index].pbo;
+
+ DeleteVDPAUTexture420(index);
+
+ memset(&im , 0, sizeof(im));
+ memset(&fields, 0, sizeof(fields));
+
+ im.cshift_x = 1;
+ im.cshift_y = 1;
+
+ im.plane[0] = NULL;
+ im.plane[1] = NULL;
+ im.plane[2] = NULL;
+
+ for(int p = 0;p<3;p++)
+ {
+ pbo[p] = None;
+ }
+
+ glEnable(m_textureTarget);
+ glGenTextures(1, &plane.id);
+ glDisable(m_textureTarget);
+
m_eventTexturesDone[index]->Set();
- glPixelStorei(GL_UNPACK_ALIGNMENT,1); //what's this for?
#endif
+ return true;
}
+void CLinuxRendererGL::UploadVDPAUTexture420(int index)
+{
+#ifdef HAVE_LIBVDPAU
+ VDPAU::CVdpauRenderPicture *vdpau = m_buffers[index].vdpau;
+ YV12Image &im = m_buffers[index].image;
+
+ unsigned int flipindex = m_buffers[index].flipindex;
+ YUVFIELDS &fields = m_buffers[index].fields;
+ YUVPLANE &plane = fields[0][0];
+
+ if (!vdpau || !vdpau->valid)
+ {
+ m_eventTexturesDone[index]->Set();
+ m_skipRender = true;
+ return;
+ }
+
+ im.height = vdpau->texHeight;
+ im.width = vdpau->texWidth;
+
+ // YUV
+ for (int f = FIELD_FULL; f<=FIELD_BOT ; f++)
+ {
+ int fieldshift = (f==FIELD_FULL) ? 0 : 1;
+ YUVPLANES &planes = fields[f];
+
+ planes[0].texwidth = im.width;
+ planes[0].texheight = im.height >> fieldshift;
+
+ planes[1].texwidth = planes[0].texwidth >> im.cshift_x;
+ planes[1].texheight = planes[0].texheight >> im.cshift_y;
+ planes[2].texwidth = planes[1].texwidth;
+ planes[2].texheight = planes[1].texheight;
+
+ for (int p = 0; p < 3; p++)
+ {
+ planes[p].pixpertex_x = 1;
+ planes[p].pixpertex_y = 1;
+ }
+ }
+ // crop
+// m_sourceRect.x1 += vdpau->crop.x1;
+// m_sourceRect.x2 -= vdpau->crop.x2;
+// m_sourceRect.y1 += vdpau->crop.y1;
+// m_sourceRect.y2 -= vdpau->crop.y2;
+
+ // set textures
+ fields[1][0].id = vdpau->texture[0];
+ fields[1][1].id = vdpau->texture[2];
+ fields[2][0].id = vdpau->texture[1];
+ fields[2][1].id = vdpau->texture[3];
+
+ glEnable(m_textureTarget);
+ for (int f = 1; f < 3; f++)
+ {
+ for (int p=0;p<2;p++)
+ {
+ glBindTexture(m_textureTarget,fields[f][p].id);
+ glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glBindTexture(m_textureTarget,0);
+ VerifyGLState();
+ }
+ fields[f][2].id = fields[f][1].id;
+ }
+ CalculateTextureSourceRects(index, 3);
+ glDisable(m_textureTarget);
+
+ m_eventTexturesDone[index]->Set();
+#endif
+}
void CLinuxRendererGL::DeleteVAAPITexture(int index)
{
@@ -3276,12 +3428,13 @@ bool CLinuxRendererGL::Supports(EINTERLACEMETHOD method)
if(method == VS_INTERLACEMETHOD_AUTO)
return true;
- if(m_renderMethod & RENDER_VDPAU)
+ if(m_renderMethod & RENDER_VDPAU ||
+ m_format == RENDER_FMT_VDPAU_420)
{
#ifdef HAVE_LIBVDPAU
- CVDPAU *vdpau = m_buffers[m_iYV12RenderBuffer].vdpau;
- if(vdpau)
- return vdpau->Supports(method);
+ VDPAU::CVdpauRenderPicture *vdpauPic = m_buffers[m_iYV12RenderBuffer].vdpau;
+ if(vdpauPic && vdpauPic->vdpau)
+ return vdpauPic->vdpau->Supports(method);
#endif
return false;
}
@@ -3367,14 +3520,7 @@ EINTERLACEMETHOD CLinuxRendererGL::AutoInterlaceMethod()
return VS_INTERLACEMETHOD_NONE;
if(m_renderMethod & RENDER_VDPAU)
- {
-#ifdef HAVE_LIBVDPAU
- CVDPAU *vdpau = m_buffers[m_iYV12RenderBuffer].vdpau;
- if(vdpau)
- return vdpau->AutoInterlaceMethod();
-#endif
return VS_INTERLACEMETHOD_NONE;
- }
if(Supports(VS_INTERLACEMETHOD_RENDER_BOB))
return VS_INTERLACEMETHOD_RENDER_BOB;
@@ -3417,11 +3563,12 @@ void CLinuxRendererGL::UnBindPbo(YUVBUFFER& buff)
}
#ifdef HAVE_LIBVDPAU
-void CLinuxRendererGL::AddProcessor(CVDPAU* vdpau, int index)
+void CLinuxRendererGL::AddProcessor(VDPAU::CVdpauRenderPicture *vdpau, int index)
{
YUVBUFFER &buf = m_buffers[index];
+ VDPAU::CVdpauRenderPicture *pic = vdpau->Acquire();
SAFE_RELEASE(buf.vdpau);
- buf.vdpau = (CVDPAU*)vdpau->Acquire();
+ buf.vdpau = pic;
}
#endif
diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.h b/xbmc/cores/VideoRenderers/LinuxRendererGL.h
index 9f55fcb..3218cd5 100644
--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.h
+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.h
@@ -38,15 +38,14 @@
class CRenderCapture;
-class CVDPAU;
class CBaseTexture;
namespace Shaders { class BaseYUV2RGBShader; }
namespace Shaders { class BaseVideoFilterShader; }
namespace VAAPI { struct CHolder; }
+namespace VDPAU { class CVdpauRenderPicture; }
#define NUM_BUFFERS 10
-
#undef ALIGN
#define ALIGN(value, alignment) (((value)+((alignment)-1))&~((alignment)-1))
#define CLAMP(a, min, max) ((a) > (max) ? (max) : ( (a) < (min) ? (min) : a ))
@@ -144,7 +143,7 @@ class CLinuxRendererGL : public CBaseRenderer
virtual unsigned int GetProcessorSize() { return m_NumYV12Buffers; }
#ifdef HAVE_LIBVDPAU
- virtual void AddProcessor(CVDPAU* vdpau, int index);
+ virtual void AddProcessor(VDPAU::CVdpauRenderPicture* vdpau, int index);
#endif
#ifdef HAVE_LIBVA
virtual void AddProcessor(VAAPI::CHolder& holder, int index);
@@ -195,6 +194,10 @@ class CLinuxRendererGL : public CBaseRenderer
void DeleteVDPAUTexture(int index);
bool CreateVDPAUTexture(int index);
+ void UploadVDPAUTexture420(int index);
+ void DeleteVDPAUTexture420(int index);
+ bool CreateVDPAUTexture420(int index);
+
void UploadVAAPITexture(int index);
void DeleteVAAPITexture(int index);
bool CreateVAAPITexture(int index);
@@ -221,6 +224,7 @@ class CLinuxRendererGL : public CBaseRenderer
void RenderSinglePass(int renderBuffer, int field); // single pass glsl renderer
void RenderSoftware(int renderBuffer, int field); // single pass s/w yuv2rgb renderer
void RenderVDPAU(int renderBuffer, int field); // render using vdpau hardware
+ void RenderVDPAUYV12(int renderBuffer, int field); // render using vdpau hardware
void RenderVAAPI(int renderBuffer, int field); // render using vdpau hardware
struct
@@ -281,7 +285,7 @@ class CLinuxRendererGL : public CBaseRenderer
GLuint pbo[MAX_PLANES];
#ifdef HAVE_LIBVDPAU
- CVDPAU* vdpau;
+ VDPAU::CVdpauRenderPicture *vdpau;
#endif
#ifdef HAVE_LIBVA
VAAPI::CHolder& vaapi;
@@ -327,6 +331,7 @@ class CLinuxRendererGL : public CBaseRenderer
bool m_nonLinStretch;
bool m_nonLinStretchGui;
float m_pixelRatio;
+ bool m_skipRender;
};
diff --git a/xbmc/cores/VideoRenderers/RenderFormats.h b/xbmc/cores/VideoRenderers/RenderFormats.h
index 09f8f5d..0262c60 100644
--- a/xbmc/cores/VideoRenderers/RenderFormats.h
+++ b/xbmc/cores/VideoRenderers/RenderFormats.h
@@ -26,6 +26,7 @@ enum ERenderFormat {
RENDER_FMT_YUV420P10,
RENDER_FMT_YUV420P16,
RENDER_FMT_VDPAU,
+ RENDER_FMT_VDPAU_420,
RENDER_FMT_NV12,
RENDER_FMT_UYVY422,
RENDER_FMT_YUYV422,
diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp
index f19797c..a521680 100644
--- a/xbmc/cores/VideoRenderers/RenderManager.cpp
+++ b/xbmc/cores/VideoRenderers/RenderManager.cpp
@@ -250,8 +250,9 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi
// check if decoder supports buffering
m_bCodecSupportsBuffering = false;
-// if (format == RENDER_FMT_VDPAU)
-// m_bCodecSupportsBuffering = true;
+ if (format == RENDER_FMT_VDPAU ||
+ format == RENDER_FMT_VDPAU_420)
+ m_bCodecSupportsBuffering = true;
bool result = m_pRenderer->Configure(width, height, d_width, d_height, fps, flags, format, extended_format, orientation);
if(result)
@@ -856,7 +857,8 @@ int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic)
CDVDCodecUtils::CopyDXVA2Picture(&image, &pic);
}
#ifdef HAVE_LIBVDPAU
- else if(pic.format == RENDER_FMT_VDPAU)
+ else if(pic.format == RENDER_FMT_VDPAU
+ || pic.format == RENDER_FMT_VDPAU_420)
m_pRenderer->AddProcessor(pic.vdpau, index);
#endif
#ifdef HAVE_LIBOPENMAX
diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h
index 9342586..6746957 100644
--- a/xbmc/cores/VideoRenderers/RenderManager.h
+++ b/xbmc/cores/VideoRenderers/RenderManager.h
@@ -35,7 +35,7 @@
namespace DXVA { class CProcessor; }
namespace VAAPI { class CSurfaceHolder; }
-class CVDPAU;
+namespace VDPAU { class CVdpauRenderPicture; }
struct DVDVideoPicture;
#define ERRORBUFFSIZE 30
diff --git a/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp b/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp
index 58f26b0..50606eb 100644
--- a/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp
+++ b/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp
@@ -201,6 +201,8 @@ static void CalculateYUVMatrixGL(GLfloat res[4][4]
m_defines += "#define XBMC_YUY2\n";
else if (m_format == RENDER_FMT_UYVY422)
m_defines += "#define XBMC_UYVY\n";
+ else if (RENDER_FMT_VDPAU_420)
+ m_defines += "#define XBMC_VDPAU_NV12\n";
else
CLog::Log(LOGERROR, "GL: BaseYUV2RGBGLSLShader - unsupported format %d", m_format);
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
index 5001aac..98d8f89 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
@@ -34,7 +34,7 @@
namespace DXVA { class CSurfaceContext; }
namespace VAAPI { struct CHolder; }
-class CVDPAU;
+namespace VDPAU { class CVdpauRenderPicture; }
class COpenMax;
class COpenMaxVideo;
struct OpenMaxVideoBuffer;
@@ -55,7 +55,7 @@ struct DVDVideoPicture
DXVA::CSurfaceContext* context;
};
struct {
- CVDPAU* vdpau;
+ VDPAU::CVdpauRenderPicture* vdpau;
};
struct {
VAAPI::CHolder* vaapi;
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
index dae3b8e..a6e42e5 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
@@ -71,14 +71,14 @@ enum PixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx
while(*cur != PIX_FMT_NONE)
{
#ifdef HAVE_LIBVDPAU
- if(CVDPAU::IsVDPAUFormat(*cur) && g_guiSettings.GetBool("videoplayer.usevdpau"))
+ if(VDPAU::CDecoder::IsVDPAUFormat(*cur) && g_guiSettings.GetBool("videoplayer.usevdpau"))
{
if(ctx->GetHardware())
return *cur;
CLog::Log(LOGNOTICE,"CDVDVideoCodecFFmpeg::GetFormat - Creating VDPAU(%ix%i)", avctx->width, avctx->height);
- CVDPAU* vdp = new CVDPAU();
- if(vdp->Open(avctx, *cur))
+ VDPAU::CDecoder* vdp = new VDPAU::CDecoder();
+ if(vdp->Open(avctx, *cur, ctx->m_uSurfacesCount))
{
ctx->SetHardware(vdp);
return *cur;
@@ -205,14 +205,27 @@ bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options
continue;
CLog::Log(LOGNOTICE,"CDVDVideoCodecFFmpeg::Open() Creating VDPAU(%ix%i, %d)",hints.width, hints.height, hints.codec);
- CVDPAU* vdp = new CVDPAU();
+
+ VDPAU::CDecoder* vdp = new VDPAU::CDecoder();
m_pCodecContext = m_dllAvCodec.avcodec_alloc_context3(pCodec);
m_pCodecContext->codec_id = hints.codec;
m_pCodecContext->width = hints.width;
m_pCodecContext->height = hints.height;
m_pCodecContext->coded_width = hints.width;
m_pCodecContext->coded_height = hints.height;
- if(vdp->Open(m_pCodecContext, pCodec->pix_fmts ? pCodec->pix_fmts[0] : PIX_FMT_NONE))
+
+ // check number of surfaces used in renderer
+ unsigned int surfaces = 0;
+ for(std::vector<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 16800b7..844f8e8 100644
--- a/xbmc/settings/AdvancedSettings.cpp
+++ b/xbmc/settings/AdvancedSettings.cpp
@@ -98,7 +98,7 @@ void CAdvancedSettings::Initialize()
m_videoIgnoreSecondsAtStart = 3*60;
m_videoIgnorePercentAtEnd = 8.0f;
m_videoPlayCountMinimumPercent = 90.0f;
- m_videoVDPAUScaling = false;
+ m_videoVDPAUScaling = -1;
m_videoNonLinStretchRatio = 0.5f;
m_videoEnableHighQualityHwScalers = false;
m_videoAutoScaleMaxFps = 30.0f;
@@ -106,6 +106,8 @@ void CAdvancedSettings::Initialize()
m_videoAllowMpeg4VAAPI = false;
m_videoDisableBackgroundDeinterlace = false;
m_videoCaptureUseOcclusionQuery = -1; //-1 is auto detect
+ m_videoVDPAUtelecine = false;
+ m_videoVDPAUdeintSkipChromaHD = false;
m_DXVACheckCompatibility = false;
m_DXVACheckCompatibilityPresent = false;
m_DXVAForceProcessorRenderer = true;
@@ -493,7 +495,7 @@ void CAdvancedSettings::ParseSettingsFile(const CStdString &file)
XMLUtils::GetString(pElement,"cleandatetime", m_videoCleanDateTimeRegExp);
XMLUtils::GetString(pElement,"ppffmpegdeinterlacing",m_videoPPFFmpegDeint);
XMLUtils::GetString(pElement,"ppffmpegpostprocessing",m_videoPPFFmpegPostProc);
- XMLUtils::GetBoolean(pElement,"vdpauscaling",m_videoVDPAUScaling);
+ XMLUtils::GetInt(pElement,"vdpauscaling",m_videoVDPAUScaling);
XMLUtils::GetFloat(pElement, "nonlinearstretchratio", m_videoNonLinStretchRatio, 0.01f, 1.0f);
XMLUtils::GetBoolean(pElement,"enablehighqualityhwscalers", m_videoEnableHighQualityHwScalers);
XMLUtils::GetFloat(pElement,"autoscalemaxfps",m_videoAutoScaleMaxFps, 0.0f, 1000.0f);
@@ -501,6 +503,8 @@ void CAdvancedSettings::ParseSettingsFile(const CStdString &file)
XMLUtils::GetBoolean(pElement,"allowmpeg4vaapi",m_videoAllowMpeg4VAAPI);
XMLUtils::GetBoolean(pElement, "disablebackgrounddeinterlace", m_videoDisableBackgroundDeinterlace);
XMLUtils::GetInt(pElement, "useocclusionquery", m_videoCaptureUseOcclusionQuery, -1, 1);
+ XMLUtils::GetBoolean(pElement,"vdpauInvTelecine",m_videoVDPAUtelecine);
+ XMLUtils::GetBoolean(pElement,"vdpauHDdeintSkipChroma",m_videoVDPAUdeintSkipChromaHD);
TiXmlElement* pAdjustRefreshrate = pElement->FirstChildElement("adjustrefreshrate");
if (pAdjustRefreshrate)
diff --git a/xbmc/settings/AdvancedSettings.h b/xbmc/settings/AdvancedSettings.h
index 27887d4..72718e5 100644
--- a/xbmc/settings/AdvancedSettings.h
+++ b/xbmc/settings/AdvancedSettings.h
@@ -133,6 +133,8 @@ class CAdvancedSettings
int m_videoPercentSeekBackwardBig;
CStdString m_videoPPFFmpegDeint;
CStdString m_videoPPFFmpegPostProc;
+ bool m_videoVDPAUtelecine;
+ bool m_videoVDPAUdeintSkipChromaHD;
bool m_musicUseTimeSeeking;
int m_musicTimeSeekForward;
int m_musicTimeSeekBackward;
@@ -148,7 +150,7 @@ class CAdvancedSettings
CStdString m_audioHost;
bool m_audioApplyDrc;
- bool m_videoVDPAUScaling;
+ int m_videoVDPAUScaling;
float m_videoNonLinStretchRatio;
bool m_videoEnableHighQualityHwScalers;
float m_videoAutoScaleMaxFps;
diff --git a/xbmc/settings/GUISettings.cpp b/xbmc/settings/GUISettings.cpp
index 76ec0cc..4cdb093 100644
--- a/xbmc/settings/GUISettings.cpp
+++ b/xbmc/settings/GUISettings.cpp
@@ -685,6 +685,8 @@ void CGUISettings::Initialize()
#ifdef HAVE_LIBVDPAU
AddBool(vp, "videoplayer.usevdpau", 13425, true);
+ AddBool(vp, "videoplayer.usevdpauinterop", 13435, true);
+ AddBool(vp, "videoplayer.usevdpauinteropyuv", 13436, false);
#endif
#ifdef HAVE_LIBVA
AddBool(vp, "videoplayer.usevaapi", 13426, true);
diff --git a/xbmc/settings/GUIWindowSettingsCategory.cpp b/xbmc/settings/GUIWindowSettingsCategory.cpp
index 4ac2663..d988598 100644
--- a/xbmc/settings/GUIWindowSettingsCategory.cpp
+++ b/xbmc/settings/GUIWindowSettingsCategory.cpp
@@ -596,6 +596,40 @@ void CGUIWindowSettingsCategory::UpdateSettings()
pControl->SetEnabled(true);
}
}
+ else if (strSetting.Equals("videoplayer.usevdpauinteropyuv"))
+ {
+ bool hasInterop = g_guiSettings.GetBool("videoplayer.usevdpauinterop");
+#ifndef GL_NV_vdpau_interop
+ hasInterop = false;
+#endif
+ CGUIControl *pControl = (CGUIControl *)GetControl(pSettingControl->GetID());
+ if (pControl && hasInterop && glewIsSupported("GL_NV_vdpau_interop"))
+ {
+ pControl->SetEnabled(true);
+ }
+ else
+ {
+ pControl->SetEnabled(false);
+ g_guiSettings.SetBool("videoplayer.usevdpauinteropyuv",false);
+ }
+ }
+ else if (strSetting.Equals("videoplayer.usevdpauinterop"))
+ {
+ bool hasInterop = g_guiSettings.GetBool("videoplayer.usevdpau");
+#ifndef GL_NV_vdpau_interop
+ hasInterop = false;
+#endif
+ CGUIControl *pControl = (CGUIControl *)GetControl(pSettingControl->GetID());
+ if (pControl && hasInterop && glewIsSupported("GL_NV_vdpau_interop"))
+ {
+ pControl->SetEnabled(true);
+ }
+ else
+ {
+ pControl->SetEnabled(false);
+ g_guiSettings.SetBool("videoplayer.usevdpauinterop",false);
+ }
+ }
else
#endif
if (strSetting.Equals("videoscreen.resolution"))
diff --git a/xbmc/utils/ActorProtocol.cpp b/xbmc/utils/ActorProtocol.cpp
new file mode 100644
index 0000000..e0cfd0e
--- /dev/null
+++ b/xbmc/utils/ActorProtocol.cpp
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2005-2012 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <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 c088467d9d0955051a510dadbddb270ddc3e3c20 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Tue, 25 Sep 2012 12:14:15 +0200
Subject: [PATCH 12/72] linuxrenderer: drop method RenderMultiPass
---
xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 9 ++-------
xbmc/cores/VideoRenderers/LinuxRendererGL.h | 1 -
2 files changed, 2 insertions(+), 8 deletions(-)
diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
index 4ee50c1..ea58c85 100644
--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
@@ -1205,7 +1205,8 @@ void CLinuxRendererGL::Render(DWORD flags, int renderBuffer)
break;
case RQ_MULTIPASS:
- RenderMultiPass(renderBuffer, m_currentField);
+ RenderToFBO(renderBuffer, m_currentField);
+ RenderFromFBO();
VerifyGLState();
break;
}
@@ -1328,12 +1329,6 @@ void CLinuxRendererGL::RenderSinglePass(int index, int field)
VerifyGLState();
}
-void CLinuxRendererGL::RenderMultiPass(int index, int field)
-{
- RenderToFBO(index, field);
- RenderFromFBO();
-}
-
void CLinuxRendererGL::RenderToFBO(int index, int field)
{
YUVPLANES &planes = m_buffers[index].fields[field];
diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.h b/xbmc/cores/VideoRenderers/LinuxRendererGL.h
index 3218cd5..afc78c2 100644
--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.h
+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.h
@@ -218,7 +218,6 @@ class CLinuxRendererGL : public CBaseRenderer
void CalculateTextureSourceRects(int source, int num_planes);
// renderers
- void RenderMultiPass(int renderBuffer, int field); // multi pass glsl renderer
void RenderToFBO(int renderBuffer, int field);
void RenderFromFBO();
void RenderSinglePass(int renderBuffer, int field); // single pass glsl renderer
--
1.7.10
From 0de3939247a63509e6bfab2e77c298eaa28aa29c Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Tue, 25 Sep 2012 13:20:47 +0200
Subject: [PATCH 13/72] linuxrenderer: implement progressive weave for vdpau
---
xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 55 ++++++++++++++++++-------
xbmc/cores/VideoRenderers/LinuxRendererGL.h | 4 +-
2 files changed, 41 insertions(+), 18 deletions(-)
diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
index ea58c85..b281ca7 100644
--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
@@ -689,18 +689,6 @@ void CLinuxRendererGL::RenderUpdate(bool clear, DWORD flags, DWORD alpha)
glDisable(GL_POLYGON_STIPPLE);
}
- else if(m_format == RENDER_FMT_VDPAU_420
- && !(flags & RENDER_FLAG_BOTH))
- {
- glDisable(GL_BLEND);
- glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
- Render(flags | RENDER_FLAG_TOP, index);
-
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glColor4f(1.0f, 1.0f, 1.0f, 128 / 255.0f);
- Render(flags | RENDER_FLAG_BOT , index);
- }
else
Render(flags, index);
@@ -1200,13 +1188,21 @@ void CLinuxRendererGL::Render(DWORD flags, int renderBuffer)
{
case RQ_LOW:
case RQ_SINGLEPASS:
- RenderSinglePass(renderBuffer, m_currentField);
+ if (m_format == RENDER_FMT_VDPAU_420 && m_currentField == FIELD_FULL)
+ RenderProgressiveWeave(renderBuffer, m_currentField);
+ else
+ RenderSinglePass(renderBuffer, m_currentField);
VerifyGLState();
break;
case RQ_MULTIPASS:
- RenderToFBO(renderBuffer, m_currentField);
- RenderFromFBO();
+ if (m_format == RENDER_FMT_VDPAU_420 && m_currentField == FIELD_FULL)
+ RenderProgressiveWeave(renderBuffer, m_currentField);
+ else
+ {
+ RenderToFBO(renderBuffer, m_currentField);
+ RenderFromFBO();
+ }
VerifyGLState();
break;
}
@@ -1329,7 +1325,7 @@ void CLinuxRendererGL::RenderSinglePass(int index, int field)
VerifyGLState();
}
-void CLinuxRendererGL::RenderToFBO(int index, int field)
+void CLinuxRendererGL::RenderToFBO(int index, int field, bool weave /*= false*/)
{
YUVPLANES &planes = m_buffers[index].fields[field];
@@ -1431,6 +1427,8 @@ void CLinuxRendererGL::RenderToFBO(int index, int field)
}
m_fbo.width *= planes[0].pixpertex_x;
m_fbo.height *= planes[0].pixpertex_y;
+ if (weave)
+ m_fbo.height *= 2;
// 1st Pass to video frame size
glBegin(GL_QUADS);
@@ -1549,6 +1547,31 @@ void CLinuxRendererGL::RenderFromFBO()
VerifyGLState();
}
+void CLinuxRendererGL::RenderProgressiveWeave(int index, int field)
+{
+ bool scaleUp = (int)m_sourceHeight < g_graphicsContext.GetHeight() || (int)m_sourceWidth < g_graphicsContext.GetWidth();
+
+ if (m_fbo.fbo.IsSupported() && (scaleUp || m_renderQuality == RQ_MULTIPASS))
+ {
+ glEnable(GL_POLYGON_STIPPLE);
+ glPolygonStipple(stipple_weave);
+ RenderToFBO(index, FIELD_TOP, true);
+ glPolygonStipple(stipple_weave+4);
+ RenderToFBO(index, FIELD_BOT, true);
+ glDisable(GL_POLYGON_STIPPLE);
+ RenderFromFBO();
+ }
+ else
+ {
+ glEnable(GL_POLYGON_STIPPLE);
+ glPolygonStipple(stipple_weave);
+ RenderSinglePass(index, FIELD_TOP);
+ glPolygonStipple(stipple_weave+4);
+ RenderSinglePass(index, FIELD_BOT);
+ glDisable(GL_POLYGON_STIPPLE);
+ }
+}
+
void CLinuxRendererGL::RenderVDPAU(int index, int field)
{
#ifdef HAVE_LIBVDPAU
diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.h b/xbmc/cores/VideoRenderers/LinuxRendererGL.h
index afc78c2..2fc34ae 100644
--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.h
+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.h
@@ -218,12 +218,12 @@ class CLinuxRendererGL : public CBaseRenderer
void CalculateTextureSourceRects(int source, int num_planes);
// renderers
- void RenderToFBO(int renderBuffer, int field);
+ void RenderToFBO(int renderBuffer, int field, bool weave = false);
void RenderFromFBO();
void RenderSinglePass(int renderBuffer, int field); // single pass glsl renderer
void RenderSoftware(int renderBuffer, int field); // single pass s/w yuv2rgb renderer
void RenderVDPAU(int renderBuffer, int field); // render using vdpau hardware
- void RenderVDPAUYV12(int renderBuffer, int field); // render using vdpau hardware
+ void RenderProgressiveWeave(int renderBuffer, int field); // render using vdpau hardware
void RenderVAAPI(int renderBuffer, int field); // render using vdpau hardware
struct
--
1.7.10
From c12380f4b9c9c2671bfd1ebd3e29ba7cd83ac95e Mon Sep 17 00:00:00 2001
From: FernetMenta <fernetmenta@online.de>
Date: Thu, 5 Jul 2012 15:22:05 +0200
Subject: [PATCH 14/72] X11: ditch SDL for video and window events
---
xbmc/Application.cpp | 2 +-
xbmc/system.h | 5 +
xbmc/windowing/Makefile | 1 +
xbmc/windowing/WinEvents.h | 4 +
xbmc/windowing/WinEventsX11.cpp | 765 +++++++++++++++++++++++++++++++++++
xbmc/windowing/WinEventsX11.h | 57 +++
xbmc/windowing/X11/WinSystemX11.cpp | 370 ++++++++++++-----
xbmc/windowing/X11/WinSystemX11.h | 9 +-
8 files changed, 1112 insertions(+), 101 deletions(-)
create mode 100644 xbmc/windowing/WinEventsX11.cpp
create mode 100644 xbmc/windowing/WinEventsX11.h
diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp
index 9a7b900..fc8e721 100644
--- a/xbmc/Application.cpp
+++ b/xbmc/Application.cpp
@@ -790,7 +790,7 @@ bool CApplication::CreateGUI()
uint32_t sdlFlags = 0;
-#if defined(HAS_SDL_OPENGL) || (HAS_GLES == 2)
+#if (defined(HAS_SDL_OPENGL) || (HAS_GLES == 2)) && !defined(HAS_GLX)
sdlFlags |= SDL_INIT_VIDEO;
#endif
diff --git a/xbmc/system.h b/xbmc/system.h
index 4165c01..32584b1 100644
--- a/xbmc/system.h
+++ b/xbmc/system.h
@@ -162,16 +162,21 @@
#define HAS_GL
#ifdef HAVE_X11
#define HAS_GLX
+#define HAS_X11_WIN_EVENTS
#endif
#ifdef HAVE_SDL
#define HAS_SDL
#ifndef HAS_SDL_OPENGL
#define HAS_SDL_OPENGL
#endif
+#ifndef HAVE_X11
#define HAS_SDL_WIN_EVENTS
+#endif
#else
+#ifndef HAVE_X11
#define HAS_LINUX_EVENTS
#endif
+#endif
#define HAS_LINUX_NETWORK
#define HAS_LIRC
#ifdef HAVE_LIBPULSE
diff --git a/xbmc/windowing/Makefile b/xbmc/windowing/Makefile
index f109bec..f981642 100644
--- a/xbmc/windowing/Makefile
+++ b/xbmc/windowing/Makefile
@@ -1,6 +1,7 @@
SRCS=WinEventsSDL.cpp \
WinEventsLinux.cpp \
WinSystem.cpp \
+ WinEventsX11.cpp \
LIB=windowing.a
diff --git a/xbmc/windowing/WinEvents.h b/xbmc/windowing/WinEvents.h
index 6d322a9..5a671cc 100644
--- a/xbmc/windowing/WinEvents.h
+++ b/xbmc/windowing/WinEvents.h
@@ -58,6 +58,10 @@ class CWinEventsBase
#include "WinEventsSDL.h"
#define CWinEvents CWinEventsSDL
+#elif defined(TARGET_LINUX) && defined(HAS_X11_WIN_EVENTS)
+#include "WinEventsX11.h"
+#define CWinEvents CWinEventsX11
+
#elif defined(TARGET_LINUX) && defined(HAS_LINUX_EVENTS)
#include "WinEventsLinux.h"
#define CWinEvents CWinEventsLinux
diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp
new file mode 100644
index 0000000..24477ae
--- /dev/null
+++ b/xbmc/windowing/WinEventsX11.cpp
@@ -0,0 +1,765 @@
+/*
+* Copyright (C) 2005-2012 Team XBMC
+* http://www.xbmc.org
+*
+* This Program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2, or (at your option)
+* any later version.
+*
+* This Program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with XBMC; see the file COPYING. If not, write to
+* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+* http://www.gnu.org/copyleft/gpl.html
+*
+*/
+
+#include "system.h"
+
+#ifdef HAS_X11_WIN_EVENTS
+
+#include "WinEvents.h"
+#include "WinEventsX11.h"
+#include "Application.h"
+#include "ApplicationMessenger.h"
+#include <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 58fa894afaffbc990ee1ab87ff55db30e36ab2c2 Mon Sep 17 00:00:00 2001
From: FernetMenta <fernetmenta@online.de>
Date: Thu, 5 Jul 2012 15:24:22 +0200
Subject: [PATCH 15/72] 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 cad2ac7f357906f10f100a038ff28e83a69c68e8 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Sun, 20 May 2012 14:11:26 +0200
Subject: [PATCH 16/72] X11: add SDL joystick until we have a better solution
---
xbmc/windowing/WinEventsX11.cpp | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp
index 24477ae..2ec86a8 100644
--- a/xbmc/windowing/WinEventsX11.cpp
+++ b/xbmc/windowing/WinEventsX11.cpp
@@ -35,6 +35,10 @@
#include "guilib/GUIWindowManager.h"
#include "input/MouseStat.h"
+#ifdef HAS_SDL_JOYSTICK
+#include "input/SDLJoystick.h"
+#endif
+
CWinEventsX11* CWinEventsX11::WinEvents = 0;
static uint32_t SymMappingsX11[][2] =
@@ -547,6 +551,28 @@ bool CWinEventsX11::MessagePump()
ret |= ProcessKeyRepeat();
+#ifdef HAS_SDL_JOYSTICK
+ SDL_Event event;
+ while (SDL_PollEvent(&event))
+ {
+ switch(event.type)
+ {
+ case SDL_JOYBUTTONUP:
+ case SDL_JOYBUTTONDOWN:
+ case SDL_JOYAXISMOTION:
+ case SDL_JOYBALLMOTION:
+ case SDL_JOYHATMOTION:
+ g_Joystick.Update(event);
+ ret = true;
+ break;
+
+ default:
+ break;
+ }
+ memset(&event, 0, sizeof(SDL_Event));
+ }
+#endif
+
return ret;
}
--
1.7.10
From fdefd4cf296518f31ad1165268fccd651e08dd3c Mon Sep 17 00:00:00 2001
From: Joakim Plate <elupus@xbmc.org>
Date: Thu, 5 Jul 2012 12:35:55 +0200
Subject: [PATCH 17/72] 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 9a409794d1eb8ee0c4b0b1124dea7dd30af32c06 Mon Sep 17 00:00:00 2001
From: FernetMenta <fernetmenta@online.de>
Date: Thu, 5 Jul 2012 15:02:00 +0200
Subject: [PATCH 18/72] 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 1dc579a2d5c608cfd4f799971759d18cbd2957e5 Mon Sep 17 00:00:00 2001
From: FernetMenta <fernetmenta@online.de>
Date: Thu, 12 Apr 2012 15:43:56 +0200
Subject: [PATCH 19/72] 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 4a6f0e986fc27b356041a4b1bb989e0e594c8aa7 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Sun, 20 May 2012 13:17:10 +0200
Subject: [PATCH 20/72] 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 97e5811e05a4ecde7249b2f76283729ff300fda9 Mon Sep 17 00:00:00 2001
From: FernetMenta <fernetmenta@online.de>
Date: Thu, 5 Jul 2012 11:54:15 +0200
Subject: [PATCH 21/72] 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 2b379b9ce21b6d61b44b647b79ef3587dbbcf0ec Mon Sep 17 00:00:00 2001
From: FernetMenta <fernetmenta@online.de>
Date: Thu, 5 Jul 2012 11:44:00 +0200
Subject: [PATCH 22/72] X11: fix multi-head setups
---
language/English/strings.po | 4 +-
xbmc/rendering/gl/RenderSystemGL.h | 1 +
xbmc/settings/GUISettings.cpp | 5 +
xbmc/settings/GUIWindowSettingsCategory.cpp | 60 +++++-
xbmc/settings/GUIWindowSettingsCategory.h | 1 +
xbmc/windowing/WinEventsX11.cpp | 7 +
xbmc/windowing/X11/WinSystemX11.cpp | 262 ++++++++++++++++-----------
xbmc/windowing/X11/WinSystemX11.h | 10 +-
8 files changed, 235 insertions(+), 115 deletions(-)
diff --git a/language/English/strings.po b/language/English/strings.po
index 88292d3..bba7284 100644
--- a/language/English/strings.po
+++ b/language/English/strings.po
@@ -895,7 +895,9 @@ msgctxt "#245"
msgid "Sizing: (%i,%i)->(%i,%i) (Zoom x%2.2f) AR:%2.2f:1 (Pixels: %2.2f:1) (VShift: %2.2f)"
msgstr ""
-#empty string with id 246
+msgctxt "#246"
+msgid "Monitor"
+msgstr ""
msgctxt "#247"
msgid "Scripts"
diff --git a/xbmc/rendering/gl/RenderSystemGL.h b/xbmc/rendering/gl/RenderSystemGL.h
index efe5493..85d780d 100644
--- a/xbmc/rendering/gl/RenderSystemGL.h
+++ b/xbmc/rendering/gl/RenderSystemGL.h
@@ -44,6 +44,7 @@ class CRenderSystemGL : public CRenderSystemBase
virtual bool IsExtSupported(const char* extension);
virtual void SetVSync(bool vsync);
+ virtual void ResetVSync() { m_bVsyncInit = false; }
virtual void SetViewPort(CRect& viewPort);
virtual void GetViewPort(CRect& viewPort);
diff --git a/xbmc/settings/GUISettings.cpp b/xbmc/settings/GUISettings.cpp
index 4cdb093..0e320e1 100644
--- a/xbmc/settings/GUISettings.cpp
+++ b/xbmc/settings/GUISettings.cpp
@@ -392,11 +392,16 @@ void CGUISettings::Initialize()
AddGroup(SETTINGS_SYSTEM, 13000);
CSettingsCategory* vs = AddCategory(SETTINGS_SYSTEM, "videoscreen", 21373);
+#if defined(HAS_GLX)
+ AddString(vs, "videoscreen.monitor", 246, "", SPIN_CONTROL_TEXT);
+#endif
+
// this setting would ideally not be saved, as its value is systematically derived from videoscreen.screenmode.
// contains a DISPLAYMODE
#if !defined(TARGET_DARWIN_IOS_ATV2) && !defined(TARGET_RASPBERRY_PI)
AddInt(vs, "videoscreen.screen", 240, 0, -1, 1, 32, SPIN_CONTROL_TEXT);
#endif
+
// this setting would ideally not be saved, as its value is systematically derived from videoscreen.screenmode.
// contains an index to the g_settings.m_ResInfo array. the only meaningful fields are iScreen, iWidth, iHeight.
#if defined(TARGET_DARWIN)
diff --git a/xbmc/settings/GUIWindowSettingsCategory.cpp b/xbmc/settings/GUIWindowSettingsCategory.cpp
index d988598..3c19a06 100644
--- a/xbmc/settings/GUIWindowSettingsCategory.cpp
+++ b/xbmc/settings/GUIWindowSettingsCategory.cpp
@@ -528,6 +528,12 @@ void CGUIWindowSettingsCategory::CreateSettings()
FillInRefreshRates(strSetting, g_guiSettings.GetResolution(), false);
continue;
}
+ else if (strSetting.Equals("videoscreen.monitor"))
+ {
+ AddSetting(pSetting, group->GetWidth(), iControlID);
+ FillInMonitors(strSetting);
+ continue;
+ }
else if (strSetting.Equals("lookandfeel.skintheme"))
{
AddSetting(pSetting, group->GetWidth(), iControlID);
@@ -1494,6 +1500,20 @@ void CGUIWindowSettingsCategory::OnSettingChanged(BaseSettingControlPtr pSetting
// Cascade
FillInResolutions("videoscreen.resolution", mode, RES_DESKTOP, true);
}
+ else if (strSetting.Equals("videoscreen.monitor"))
+ {
+ CSettingString *pSettingString = (CSettingString *)pSettingControl->GetSetting();
+ CGUISpinControlEx *pControl = (CGUISpinControlEx *)GetControl(pSettingControl->GetID());
+ CStdString currentMonitor = pControl->GetCurrentLabel();
+ if (!g_Windowing.IsCurrentOutput(currentMonitor))
+ {
+ g_guiSettings.SetString("videoscreen.monitor", currentMonitor);
+ g_Windowing.UpdateResolutions();
+ DisplayMode mode = g_guiSettings.GetInt("videoscreen.screen");
+ // Cascade
+ FillInResolutions("videoscreen.resolution", mode, RES_DESKTOP, true);
+ }
+ }
else if (strSetting.Equals("videoscreen.resolution"))
{
RESOLUTION nextRes = (RESOLUTION) g_guiSettings.GetInt("videoscreen.resolution");
@@ -2430,11 +2450,15 @@ DisplayMode CGUIWindowSettingsCategory::FillInScreens(CStdString strSetting, RES
if (g_advancedSettings.m_canWindowed)
pControl->AddLabel(g_localizeStrings.Get(242), -1);
+#if !defined(HAS_GLX)
for (int idx = 0; idx < g_Windowing.GetNumScreens(); idx++)
{
strScreen.Format(g_localizeStrings.Get(241), g_settings.m_ResInfo[RES_DESKTOP + idx].iScreen + 1);
pControl->AddLabel(strScreen, g_settings.m_ResInfo[RES_DESKTOP + idx].iScreen);
}
+#else
+ pControl->AddLabel(g_localizeStrings.Get(244), 0);
+#endif
pControl->SetValue(mode);
g_guiSettings.SetInt("videoscreen.screen", mode);
}
@@ -2442,6 +2466,36 @@ DisplayMode CGUIWindowSettingsCategory::FillInScreens(CStdString strSetting, RES
return mode;
}
+void CGUIWindowSettingsCategory::FillInMonitors(CStdString strSetting)
+{
+ // we expect "videoscreen.monitor" but it might be hidden on some platforms,
+ // so check that we actually have a visable control.
+ CBaseSettingControl *control = GetSetting(strSetting);
+ if (control)
+ {
+ control->SetDelayed();
+ CGUISpinControlEx *pControl = (CGUISpinControlEx *)GetControl(control->GetID());
+ pControl->Clear();
+
+ std::vector<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)
{
BaseSettingControlPtr control = GetSetting(strSetting);
@@ -2570,13 +2624,15 @@ void CGUIWindowSettingsCategory::OnRefreshRateChanged(RESOLUTION nextRes)
RESOLUTION lastRes = g_graphicsContext.GetVideoResolution();
bool cancelled = false;
+ bool outputChanged = !g_Windowing.IsCurrentOutput(g_guiSettings.GetString("videoscreen.monitor"));
+
g_guiSettings.SetResolution(nextRes);
- g_graphicsContext.SetVideoResolution(nextRes);
+ g_graphicsContext.SetVideoResolution(nextRes, outputChanged);
if (!CGUIDialogYesNo::ShowAndGetInput(13110, 13111, 20022, 20022, -1, -1, cancelled, 10000))
{
g_guiSettings.SetResolution(lastRes);
- g_graphicsContext.SetVideoResolution(lastRes);
+ g_graphicsContext.SetVideoResolution(lastRes, outputChanged);
DisplayMode mode = FillInScreens("videoscreen.screen", lastRes);
FillInResolutions("videoscreen.resolution", mode, lastRes, false);
diff --git a/xbmc/settings/GUIWindowSettingsCategory.h b/xbmc/settings/GUIWindowSettingsCategory.h
index 5142c6e..0d4649d 100644
--- a/xbmc/settings/GUIWindowSettingsCategory.h
+++ b/xbmc/settings/GUIWindowSettingsCategory.h
@@ -51,6 +51,7 @@ class CGUIWindowSettingsCategory :
void FillInSoundSkins(CSetting *pSetting);
void FillInLanguages(CSetting *pSetting, const std::vector<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 2a747f13a0a50dea0883d0d3c701ef290235a99b Mon Sep 17 00:00:00 2001
From: FernetMenta <fernetmenta@online.de>
Date: Thu, 5 Jul 2012 11:36:32 +0200
Subject: [PATCH 23/72] X11: remove all DefaultScreen and RootWindow macros
---
xbmc/windowing/X11/WinSystemX11.cpp | 6 +++---
xbmc/windowing/X11/WinSystemX11.h | 1 +
xbmc/windowing/X11/WinSystemX11GL.cpp | 2 +-
3 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp
index 5f913f1..af1307c 100644
--- a/xbmc/windowing/X11/WinSystemX11.cpp
+++ b/xbmc/windowing/X11/WinSystemX11.cpp
@@ -267,7 +267,7 @@ void CWinSystemX11::UpdateResolutions()
else
#endif
{
- int x11screen = DefaultScreen(m_dpy);
+ int x11screen = m_nScreen;
int w = DisplayWidth(m_dpy, x11screen);
int h = DisplayHeight(m_dpy, x11screen);
UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, w, h, 0.0);
@@ -393,7 +393,7 @@ bool CWinSystemX11::RefreshGlxContext()
XVisualInfo *visuals;
XVisualInfo *vInfo = NULL;
int availableVisuals = 0;
- vMask.screen = DefaultScreen(m_dpy);
+ vMask.screen = m_nScreen;
XWindowAttributes winAttr;
/* Assume a depth of 24 in case the below calls to XGetWindowAttributes()
@@ -547,7 +547,7 @@ bool CWinSystemX11::Minimize()
g_graphicsContext.ToggleFullScreenRoot();
}
- XIconifyWindow(m_dpy, m_glWindow, DefaultScreen(m_dpy));
+ XIconifyWindow(m_dpy, m_glWindow, m_nScreen);
m_minimized = true;
return true;
diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h
index 71034fc..3bb4b8e 100644
--- a/xbmc/windowing/X11/WinSystemX11.h
+++ b/xbmc/windowing/X11/WinSystemX11.h
@@ -47,6 +47,7 @@ class CWinSystemX11 : public CWinSystemBase
virtual bool SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays);
virtual void UpdateResolutions();
virtual int GetNumScreens() { return 1; }
+ virtual int GetCurrentScreen() { return m_nScreen; }
virtual void ShowOSMouse(bool show);
virtual void ResetOSScreensaver();
virtual bool EnableFrameLimiter();
diff --git a/xbmc/windowing/X11/WinSystemX11GL.cpp b/xbmc/windowing/X11/WinSystemX11GL.cpp
index f858f88..d192697 100644
--- a/xbmc/windowing/X11/WinSystemX11GL.cpp
+++ b/xbmc/windowing/X11/WinSystemX11GL.cpp
@@ -203,7 +203,7 @@ bool CWinSystemX11GL::CreateNewWindow(const CStdString& name, bool fullScreen, R
return false;
m_glxext = " ";
- m_glxext += (const char*)glXQueryExtensionsString(m_dpy, DefaultScreen(m_dpy));
+ m_glxext += (const char*)glXQueryExtensionsString(m_dpy, m_nScreen);
m_glxext += " ";
CLog::Log(LOGDEBUG, "GLX_EXTENSIONS:%s", m_glxext.c_str());
--
1.7.10
From cf018ebbf1eae8f5ae2914ef347aac5f963c0d71 Mon Sep 17 00:00:00 2001
From: FernetMenta <fernetmenta@online.de>
Date: Thu, 5 Jul 2012 11:45:22 +0200
Subject: [PATCH 24/72] X11: remove all DefaultScreen and RootWindow macros
(VideoRefClock)
Note this is on a separate display connection.
---
xbmc/video/VideoReferenceClock.cpp | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/xbmc/video/VideoReferenceClock.cpp b/xbmc/video/VideoReferenceClock.cpp
index 9785fe7..0004e07 100644
--- a/xbmc/video/VideoReferenceClock.cpp
+++ b/xbmc/video/VideoReferenceClock.cpp
@@ -270,7 +270,7 @@ bool CVideoReferenceClock::SetupGLX()
}
bool ExtensionFound = false;
- istringstream Extensions(glXQueryExtensionsString(m_Dpy, DefaultScreen(m_Dpy)));
+ istringstream Extensions(glXQueryExtensionsString(m_Dpy, g_Windowing.GetCurrentScreen()));
string ExtensionStr;
while (!ExtensionFound)
@@ -297,7 +297,7 @@ bool CVideoReferenceClock::SetupGLX()
m_bIsATI = true;
}
- m_vInfo = glXChooseVisual(m_Dpy, DefaultScreen(m_Dpy), singleBufferAttributes);
+ m_vInfo = glXChooseVisual(m_Dpy, g_Windowing.GetCurrentScreen(), singleBufferAttributes);
if (!m_vInfo)
{
CLog::Log(LOGDEBUG, "CVideoReferenceClock: glXChooseVisual returned NULL");
@@ -308,15 +308,16 @@ bool CVideoReferenceClock::SetupGLX()
{
Swa.border_pixel = 0;
Swa.event_mask = StructureNotifyMask;
- Swa.colormap = XCreateColormap(m_Dpy, RootWindow(m_Dpy, m_vInfo->screen), m_vInfo->visual, AllocNone );
+ Swa.colormap = XCreateColormap(m_Dpy, g_Windowing.GetWindow(), m_vInfo->visual, AllocNone );
SwaMask = CWBorderPixel | CWColormap | CWEventMask;
- m_Window = XCreateWindow(m_Dpy, RootWindow(m_Dpy, m_vInfo->screen), 0, 0, 256, 256, 0,
+ m_Window = XCreateWindow(m_Dpy, g_Windowing.GetWindow(), 0, 0, 256, 256, 0,
m_vInfo->depth, InputOutput, m_vInfo->visual, SwaMask, &Swa);
}
else
{
- m_pixmap = XCreatePixmap(m_Dpy, DefaultRootWindow(m_Dpy), 256, 256, m_vInfo->depth);
+ Window window = g_Windowing.GetWindow();
+ m_pixmap = XCreatePixmap(m_Dpy, window, 256, 256, m_vInfo->depth);
if (!m_pixmap)
{
CLog::Log(LOGDEBUG, "CVideoReferenceClock: unable to create pixmap");
@@ -383,7 +384,7 @@ bool CVideoReferenceClock::SetupGLX()
//set up receiving of RandR events, we'll get one when the refreshrate changes
XRRQueryExtension(m_Dpy, &m_RREventBase, &ReturnV);
- XRRSelectInput(m_Dpy, RootWindow(m_Dpy, m_vInfo->screen), RRScreenChangeNotifyMask);
+ XRRSelectInput(m_Dpy, g_Windowing.GetWindow(), RRScreenChangeNotifyMask);
UpdateRefreshrate(true); //forced refreshrate update
m_MissedVblanks = 0;
@@ -518,7 +519,7 @@ int CVideoReferenceClock::GetRandRRate()
int RefreshRate;
XRRScreenConfiguration *CurrInfo;
- CurrInfo = XRRGetScreenInfo(m_Dpy, RootWindow(m_Dpy, m_vInfo->screen));
+ CurrInfo = XRRGetScreenInfo(m_Dpy, g_Windowing.GetWindow());
RefreshRate = XRRConfigCurrentRate(CurrInfo);
XRRFreeScreenConfigInfo(CurrInfo);
--
1.7.10
From 5d8bfcd52e5a189515629c15c73434ef6c6bcc88 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Wed, 20 Jun 2012 17:37:11 +0200
Subject: [PATCH 25/72] 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 bd9a29b7661c75152174959f9f269f32c13a658b Mon Sep 17 00:00:00 2001
From: FernetMenta <fernetmenta@online.de>
Date: Thu, 5 Jul 2012 12:06:25 +0200
Subject: [PATCH 26/72] 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 702f79eab647ec68030c99d6113976f3c602e87c Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Thu, 21 Jun 2012 17:26:51 +0200
Subject: [PATCH 27/72] X11: fix video calibrations
---
xbmc/settings/Settings.cpp | 1 +
xbmc/windowing/WinSystem.h | 1 +
xbmc/windowing/X11/WinSystemX11.cpp | 36 ++++++++++++++++++++++++++++++++++-
xbmc/windowing/X11/WinSystemX11.h | 1 +
4 files changed, 38 insertions(+), 1 deletion(-)
diff --git a/xbmc/settings/Settings.cpp b/xbmc/settings/Settings.cpp
index 8a430ad..fde6e4e 100644
--- a/xbmc/settings/Settings.cpp
+++ b/xbmc/settings/Settings.cpp
@@ -55,6 +55,7 @@
#include "filesystem/File.h"
#include "filesystem/DirectoryCache.h"
#include "DatabaseManager.h"
+#include "windowing/WindowingFactory.h"
using namespace std;
using namespace XFILE;
diff --git a/xbmc/windowing/WinSystem.h b/xbmc/windowing/WinSystem.h
index 05c5eda..852d085 100644
--- a/xbmc/windowing/WinSystem.h
+++ b/xbmc/windowing/WinSystem.h
@@ -100,6 +100,7 @@ class CWinSystemBase
std::vector<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 07920e322c9770ebb99becd104ebce0789c502fa Mon Sep 17 00:00:00 2001
From: FernetMenta <fernetmenta@online.de>
Date: Thu, 5 Jul 2012 12:00:26 +0200
Subject: [PATCH 28/72] X11: deactivate screen saver on startup
---
xbmc/windowing/X11/WinSystemX11.cpp | 29 +++++++++++++++++++++++++++++
xbmc/windowing/X11/WinSystemX11.h | 1 +
2 files changed, 30 insertions(+)
diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp
index 487b324..b3e7ab5 100644
--- a/xbmc/windowing/X11/WinSystemX11.cpp
+++ b/xbmc/windowing/X11/WinSystemX11.cpp
@@ -521,6 +521,33 @@ void CWinSystemX11::ResetOSScreensaver()
}
}
+void CWinSystemX11::EnableSystemScreenSaver(bool bEnable)
+{
+ if (!m_dpy)
+ return;
+
+ if (bEnable)
+ XForceScreenSaver(m_dpy, ScreenSaverActive);
+ else
+ {
+ Window root_return, child_return;
+ int root_x_return, root_y_return;
+ int win_x_return, win_y_return;
+ unsigned int mask_return;
+ bool isInWin = XQueryPointer(m_dpy, RootWindow(m_dpy, m_nScreen), &root_return, &child_return,
+ &root_x_return, &root_y_return,
+ &win_x_return, &win_y_return,
+ &mask_return);
+
+ XWarpPointer(m_dpy, None, RootWindow(m_dpy, m_nScreen), 0, 0, 0, 0, root_x_return+300, root_y_return+300);
+ XSync(m_dpy, FALSE);
+ XWarpPointer(m_dpy, None, RootWindow(m_dpy, m_nScreen), 0, 0, 0, 0, 0, 0);
+ XSync(m_dpy, FALSE);
+ XWarpPointer(m_dpy, None, RootWindow(m_dpy, m_nScreen), 0, 0, 0, 0, root_x_return, root_y_return);
+ XSync(m_dpy, FALSE);
+ }
+}
+
void CWinSystemX11::NotifyAppActiveChange(bool bActivated)
{
if (bActivated && m_bWasFullScreenBeforeMinimize && !m_bFullScreen)
@@ -764,6 +791,8 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd
// create main window
if (!m_glWindow)
{
+ EnableSystemScreenSaver(false);
+
GLint att[] =
{
GLX_RGBA,
diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h
index c046c86..e953d2d 100644
--- a/xbmc/windowing/X11/WinSystemX11.h
+++ b/xbmc/windowing/X11/WinSystemX11.h
@@ -51,6 +51,7 @@ class CWinSystemX11 : public CWinSystemBase
virtual void ShowOSMouse(bool show);
virtual void ResetOSScreensaver();
virtual bool EnableFrameLimiter();
+ virtual void EnableSystemScreenSaver(bool bEnable);
virtual void NotifyAppActiveChange(bool bActivated);
virtual void NotifyAppFocusChange(bool bGaining);
--
1.7.10
From 835bcc9c7fd477012492ffc4cad2bdd9ce506064 Mon Sep 17 00:00:00 2001
From: FernetMenta <fernetmenta@online.de>
Date: Thu, 5 Jul 2012 12:10:09 +0200
Subject: [PATCH 29/72] 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 e2442797ff82b3ed8053f1a6422863ffce9cbe5f Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Thu, 28 Jun 2012 19:12:39 +0200
Subject: [PATCH 30/72] X11: reset key repeat and key modifier on focus lost
and gain
---
xbmc/windowing/WinEventsX11.cpp | 3 +++
1 file changed, 3 insertions(+)
diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp
index 6c22358..d86205d 100644
--- a/xbmc/windowing/WinEventsX11.cpp
+++ b/xbmc/windowing/WinEventsX11.cpp
@@ -359,6 +359,8 @@ bool CWinEventsX11::MessagePump()
if (WinEvents->m_xic)
XSetICFocus(WinEvents->m_xic);
g_application.m_AppFocused = true;
+ memset(&(WinEvents->m_lastKey), 0, sizeof(XBMC_Event));
+ WinEvents->m_keymodState = 0;
if (serial == xevent.xfocus.serial)
break;
g_Windowing.NotifyAppFocusChange(g_application.m_AppFocused);
@@ -370,6 +372,7 @@ bool CWinEventsX11::MessagePump()
if (WinEvents->m_xic)
XUnsetICFocus(WinEvents->m_xic);
g_application.m_AppFocused = false;
+ memset(&(WinEvents->m_lastKey), 0, sizeof(XBMC_Event));
g_Windowing.NotifyAppFocusChange(g_application.m_AppFocused);
serial = xevent.xfocus.serial;
break;
--
1.7.10
From 77a22163a7f611e9183b7cd0b817fc51a42d45de Mon Sep 17 00:00:00 2001
From: Joakim Plate <elupus@xbmc.org>
Date: Thu, 5 Jul 2012 14:18:46 +0200
Subject: [PATCH 31/72] X11: replace custom utf8 to unicode with charset
convertor (squash to x11 events)
---
xbmc/windowing/WinEventsX11.cpp | 119 ++++-----------------------------------
xbmc/windowing/WinEventsX11.h | 2 -
2 files changed, 11 insertions(+), 110 deletions(-)
diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp
index d86205d..76702e6 100644
--- a/xbmc/windowing/WinEventsX11.cpp
+++ b/xbmc/windowing/WinEventsX11.cpp
@@ -32,6 +32,7 @@
#include "X11/keysymdef.h"
#include "X11/XF86keysym.h"
#include "utils/log.h"
+#include "utils/CharsetConverter.h"
#include "guilib/GUIWindowManager.h"
#include "input/MouseStat.h"
@@ -161,7 +162,6 @@
m_display = 0;
m_window = 0;
m_keybuf = 0;
- m_utf16buf = 0;
}
CWinEventsX11::~CWinEventsX11()
@@ -172,12 +172,6 @@
m_keybuf = 0;
}
- if (m_utf16buf)
- {
- free(m_utf16buf);
- m_utf16buf = 0;
- }
-
if (m_xic)
{
XUnsetICFocus(m_xic);
@@ -203,7 +197,6 @@ bool CWinEventsX11::Init(Display *dpy, Window win)
WinEvents->m_display = dpy;
WinEvents->m_window = win;
WinEvents->m_keybuf = (char*)malloc(32*sizeof(char));
- WinEvents->m_utf16buf = (uint16_t*)malloc(32*sizeof(uint16_t));
WinEvents->m_keymodState = 0;
WinEvents->m_wmDeleteMessage = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
WinEvents->m_structureChanged = false;
@@ -433,8 +426,6 @@ bool CWinEventsX11::MessagePump()
}
Status status;
- int utf16size;
- int utf16length;
int len;
len = Xutf8LookupString(WinEvents->m_xic, &xevent.xkey,
WinEvents->m_keybuf, sizeof(WinEvents->m_keybuf),
@@ -453,36 +444,29 @@ bool CWinEventsX11::MessagePump()
case XLookupChars:
case XLookupBoth:
{
- if (len == 0)
- break;
- utf16size = len * sizeof(uint16_t);
- if (utf16size > sizeof(WinEvents->m_utf16buf))
- {
- WinEvents->m_utf16buf = (uint16_t *)realloc(WinEvents->m_utf16buf,utf16size);
- if (WinEvents->m_utf16buf == NULL)
- {
- break;
- }
- }
- utf16length = Utf8ToUnicode(WinEvents->m_keybuf, len, WinEvents->m_utf16buf, utf16size);
- if (utf16length < 0)
+ CStdString data(WinEvents->m_keybuf, len);
+ CStdStringW keys;
+ g_charsetConverter.utf8ToW(data, keys, false);
+
+ if (keys.length() == 0)
{
break;
}
- for (unsigned int i = 0; i < utf16length - 1; i++)
+
+ for (unsigned int i = 0; i < keys.length() - 1; i++)
{
newEvent.key.keysym.sym = XBMCK_UNKNOWN;
- newEvent.key.keysym.unicode = WinEvents->m_utf16buf[i];
+ newEvent.key.keysym.unicode = keys[i];
newEvent.key.state = xevent.xkey.state;
newEvent.key.type = xevent.xkey.type;
ret |= ProcessKey(newEvent, 500);
}
- if (utf16length > 0)
+ if (keys.length() > 0)
{
newEvent.key.keysym.scancode = xevent.xkey.keycode;
xkeysym = XLookupKeysym(&xevent.xkey, 0);
newEvent.key.keysym.sym = LookupXbmcKeySym(xkeysym);
- newEvent.key.keysym.unicode = WinEvents->m_utf16buf[utf16length - 1];
+ newEvent.key.keysym.unicode = keys[keys.length() - 1];
newEvent.key.state = xevent.xkey.state;
newEvent.key.type = xevent.xkey.type;
@@ -743,87 +727,6 @@ bool CWinEventsX11::ProcessKeyRepeat()
return false;
}
-int CWinEventsX11::Utf8ToUnicode(const char *utf8, const int utf8Length, uint16_t *utf16, const int utf16MaxLength)
-{
- // p moves over the output buffer. max_ptr points to the next to the last slot of the buffer.
- uint16_t *p = utf16;
- uint16_t const *const maxPtr = utf16 + utf16MaxLength;
-
- // end_of_input points to the last byte of input as opposed to the next to the last byte.
- char const *const endOfInput = utf8 + utf8Length - 1;
-
- while (utf8 <= endOfInput)
- {
- unsigned char const c = *utf8;
- if (p >= maxPtr)
- {
- //No more output space.
- return -1;
- }
- if (c < 0x80)
- {
- //One byte ASCII.
- *p++ = c;
- utf8 += 1;
- }
- else if (c < 0xC0)
- {
- // Follower byte without preceding leader bytes.
- return -1;
- }
- // 11 bits
- else if (c < 0xE0)
- {
- // Two byte sequence. We need one follower byte.
- if (endOfInput - utf8 < 1 || (((utf8[1] ^ 0x80)) & 0xC0))
- {
- return -1;
- }
- *p++ = (uint16_t)(((c & 0x1F) << 6) + (utf8[1] & 0x3F));
- utf8 += 2;
- }
- // 16 bis
- else if (c < 0xF0)
- {
- // Three byte sequence. We need two follower byte.
- if (endOfInput - utf8 < 2 || ((utf8[1] ^ 0x80) & 0xC0) || ((utf8[2] ^ 0x80) & 0xC0))
- {
- return -1;
- }
- *p++ = (uint16_t)(((c & 0xF) << 12) + ((utf8[1] & 0x3F) << 6) + (utf8[2] & 0x3F));
- utf8 += 3;
- }
- // 21 bits
- else if (c < 0xF8)
- {
- int plane;
- // Four byte sequence. We need three follower bytes.
- if (endOfInput - utf8 < 3 || ((utf8[1] ^ 0x80) & 0xC0) ||
- ((utf8[2] ^ 0x80) & 0xC0) || ((utf8[3] ^ 0x80) & 0xC0))
- {
- return -1;
- }
- uint32_t unicode = ((c & 0x7) << 18) + ((utf8[1] & 0x3F) << 12) +
- ((utf8[2] & 0x3F) << 6) + (utf8[3] & 0x3F);
- utf8 += 4;
- CLog::Log(LOGERROR, "CWinEventsX11::Utf8ToUnicode: 4 byte unicode not supported");
- }
- // 26 bits
- else if (c < 0xFC)
- {
- CLog::Log(LOGERROR, "CWinEventsX11::Utf8ToUnicode: 4 byte unicode not supported");
- utf8 += 5;
- }
- // 31 bit
- else
- {
- CLog::Log(LOGERROR, "CWinEventsX11::Utf8ToUnicode: 4 byte unicode not supported");
- utf8 += 6;
- }
- }
- return p - utf16;
-}
-
XBMCKey CWinEventsX11::LookupXbmcKeySym(KeySym keysym)
{
// try direct mapping first
diff --git a/xbmc/windowing/WinEventsX11.h b/xbmc/windowing/WinEventsX11.h
index 6100933..72955ad 100644
--- a/xbmc/windowing/WinEventsX11.h
+++ b/xbmc/windowing/WinEventsX11.h
@@ -38,7 +38,6 @@ class CWinEventsX11 : public CWinEventsBase
static bool MessagePump();
protected:
- static int Utf8ToUnicode(const char *utf8, const int utf8Length, uint16_t *utf16, const int utf16MaxLength);
static XBMCKey LookupXbmcKeySym(KeySym keysym);
static bool ProcessKey(XBMC_Event &event, int repeatDelay);
static bool ProcessKeyRepeat();
@@ -48,7 +47,6 @@ class CWinEventsX11 : public CWinEventsBase
Window m_window;
Atom m_wmDeleteMessage;
char *m_keybuf;
- uint16_t *m_utf16buf;
XIM m_xim;
XIC m_xic;
XBMC_Event m_lastKey;
--
1.7.10
From e060b3197bbac54b79b604bbbf9a8e86257980f5 Mon Sep 17 00:00:00 2001
From: Joakim Plate <elupus@xbmc.org>
Date: Thu, 5 Jul 2012 14:23:54 +0200
Subject: [PATCH 32/72] X11: fixed invalid usage of sizeof() (squash into x11
changes)
---
xbmc/windowing/WinEventsX11.cpp | 11 +++++++----
xbmc/windowing/WinEventsX11.h | 1 +
2 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp
index 76702e6..c31877e 100644
--- a/xbmc/windowing/WinEventsX11.cpp
+++ b/xbmc/windowing/WinEventsX11.cpp
@@ -162,6 +162,7 @@
m_display = 0;
m_window = 0;
m_keybuf = 0;
+ m_keybuf_len = 0;
}
CWinEventsX11::~CWinEventsX11()
@@ -196,7 +197,8 @@ bool CWinEventsX11::Init(Display *dpy, Window win)
WinEvents = new CWinEventsX11();
WinEvents->m_display = dpy;
WinEvents->m_window = win;
- WinEvents->m_keybuf = (char*)malloc(32*sizeof(char));
+ WinEvents->m_keybuf_len = 32*sizeof(char);
+ WinEvents->m_keybuf = (char*)malloc(WinEvents->m_keybuf_len);
WinEvents->m_keymodState = 0;
WinEvents->m_wmDeleteMessage = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
WinEvents->m_structureChanged = false;
@@ -428,13 +430,14 @@ bool CWinEventsX11::MessagePump()
Status status;
int len;
len = Xutf8LookupString(WinEvents->m_xic, &xevent.xkey,
- WinEvents->m_keybuf, sizeof(WinEvents->m_keybuf),
+ WinEvents->m_keybuf, WinEvents->m_keybuf_len,
&xkeysym, &status);
if (status == XBufferOverflow)
{
- WinEvents->m_keybuf = (char*)realloc(WinEvents->m_keybuf, len*sizeof(char));
+ WinEvents->m_keybuf_len = len;
+ WinEvents->m_keybuf = (char*)realloc(WinEvents->m_keybuf, WinEvents->m_keybuf_len);
len = Xutf8LookupString(WinEvents->m_xic, &xevent.xkey,
- WinEvents->m_keybuf, sizeof(WinEvents->m_keybuf),
+ WinEvents->m_keybuf, WinEvents->m_keybuf_len,
&xkeysym, &status);
}
switch (status)
diff --git a/xbmc/windowing/WinEventsX11.h b/xbmc/windowing/WinEventsX11.h
index 72955ad..102a076 100644
--- a/xbmc/windowing/WinEventsX11.h
+++ b/xbmc/windowing/WinEventsX11.h
@@ -47,6 +47,7 @@ class CWinEventsX11 : public CWinEventsBase
Window m_window;
Atom m_wmDeleteMessage;
char *m_keybuf;
+ size_t m_keybuf_len;
XIM m_xim;
XIC m_xic;
XBMC_Event m_lastKey;
--
1.7.10
From c52af3ba68292f08331cbbbc940dfcea838a2f44 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Sat, 9 Jun 2012 18:23:53 +0200
Subject: [PATCH 33/72] add missing keys to xbmc keytable
---
xbmc/input/XBMC_keytable.cpp | 2 ++
1 file changed, 2 insertions(+)
diff --git a/xbmc/input/XBMC_keytable.cpp b/xbmc/input/XBMC_keytable.cpp
index aaf65ba..9d7922f 100644
--- a/xbmc/input/XBMC_keytable.cpp
+++ b/xbmc/input/XBMC_keytable.cpp
@@ -179,6 +179,8 @@
, { XBMCK_LAUNCH_APP2, 0, 0, XBMCVK_LAUNCH_APP2, "launch_app2_pc_icon" }
, { XBMCK_LAUNCH_FILE_BROWSER, 0, 0, XBMCVK_LAUNCH_FILE_BROWSER, "launch_file_browser" }
, { XBMCK_LAUNCH_MEDIA_CENTER, 0, 0, XBMCVK_LAUNCH_MEDIA_CENTER, "launch_media_center" }
+, { XBMCK_PLAY, 0, 0, XBMCVK_MEDIA_PLAY_PAUSE, "play_pause" }
+, { XBMCK_STOP, 0, 0, XBMCVK_MEDIA_STOP, "stop" }
// Function keys
, { XBMCK_F1, 0, 0, XBMCVK_F1, "f1"}
--
1.7.10
From 25587ee807eca2fc9dde4528e3fc930b337e38b0 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Fri, 16 Mar 2012 15:57:51 +0100
Subject: [PATCH 34/72] videorefclock: temp deactivate of nv settings
---
xbmc/video/VideoReferenceClock.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/xbmc/video/VideoReferenceClock.cpp b/xbmc/video/VideoReferenceClock.cpp
index fa8e35a..85e36c7 100644
--- a/xbmc/video/VideoReferenceClock.cpp
+++ b/xbmc/video/VideoReferenceClock.cpp
@@ -135,7 +135,7 @@
m_Context = NULL;
m_pixmap = None;
m_glPixmap = None;
- m_UseNvSettings = true;
+ m_UseNvSettings = false;
m_bIsATI = false;
#endif
}
--
1.7.10
From 4f8a95de09408321e2df3da891536c314fe3b4d2 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Mon, 20 Aug 2012 09:09:09 +0200
Subject: [PATCH 35/72] 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 85d81f0c933cb0a75c2c21de86b4065e3db86002 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Mon, 9 Jul 2012 14:00:18 +0200
Subject: [PATCH 36/72] 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 111c2f8fd0f6b698fbff0fda6dc6c17ce3644626 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Tue, 10 Jul 2012 11:14:12 +0200
Subject: [PATCH 37/72] X11: check for window manager
---
xbmc/windowing/X11/WinSystemX11.cpp | 74 ++++++++++++++++++++++++++++++++++-
xbmc/windowing/X11/WinSystemX11.h | 1 +
2 files changed, 73 insertions(+), 2 deletions(-)
diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp
index 174ccef..4f1ae26 100644
--- a/xbmc/windowing/X11/WinSystemX11.cpp
+++ b/xbmc/windowing/X11/WinSystemX11.cpp
@@ -816,8 +816,10 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd
vi = glXChooseVisual(m_dpy, m_nScreen, att);
cmap = XCreateColormap(m_dpy, RootWindow(m_dpy, vi->screen), vi->visual, AllocNone);
+ bool hasWM = HasWindowManager();
+
int def_vis = (vi->visual == DefaultVisual(m_dpy, vi->screen));
- swa.override_redirect = False;
+ swa.override_redirect = hasWM ? False : True;
swa.border_pixel = fullscreen ? 0 : 5;
swa.background_pixel = def_vis ? BlackPixel(m_dpy, vi->screen) : 0;
swa.colormap = cmap;
@@ -833,7 +835,7 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd
InputOutput, vi->visual,
mask, &swa);
- if (fullscreen)
+ if (fullscreen && hasWM)
{
Atom fs = XInternAtom(m_dpy, "_NET_WM_STATE_FULLSCREEN", True);
XChangeProperty(m_dpy, m_glWindow, XInternAtom(m_dpy, "_NET_WM_STATE", True), XA_ATOM, 32, PropModeReplace, (unsigned char *) &fs, 1);
@@ -1059,4 +1061,72 @@ bool CWinSystemX11::CreateIconPixmap()
return true;
}
+bool CWinSystemX11::HasWindowManager()
+{
+ Window wm_check;
+ unsigned char *data;
+ int status, real_format;
+ Atom real_type, prop;
+ unsigned long items_read, items_left, i;
+ char req = 0;
+
+ prop = XInternAtom(m_dpy, "_NET_SUPPORTING_WM_CHECK", True);
+ if (prop == None)
+ return false;
+ status = XGetWindowProperty(m_dpy, DefaultRootWindow(m_dpy), prop,
+ 0L, 1L, False, XA_WINDOW, &real_type, &real_format,
+ &items_read, &items_left, &data);
+ if(status != Success || ! items_read)
+ {
+ if(status == Success)
+ XFree(data);
+ return false;
+ }
+
+ wm_check = ((Window*)data)[0];
+ XFree(data);
+
+ status = XGetWindowProperty(m_dpy, wm_check, prop,
+ 0L, 1L, False, XA_WINDOW, &real_type, &real_format,
+ &items_read, &items_left, &data);
+
+ if(status != Success || !items_read)
+ {
+ if(status == Success)
+ XFree(data);
+ return false;
+ }
+
+ if(wm_check != ((Window*)data)[0])
+ {
+ XFree(data);
+ return false;
+ }
+
+ XFree(data);
+
+ prop = XInternAtom(m_dpy, "_NET_WM_NAME", True);
+ if (prop == None)
+ {
+ CLog::Log(LOGDEBUG,"Window Manager Name: ");
+ return true;
+ }
+
+ status = XGetWindowProperty(m_dpy, wm_check, prop,
+ 0L, (~0L), False, AnyPropertyType, &real_type, &real_format,
+ &items_read, &items_left, &data);
+
+ if(status == Success && items_read)
+ {
+ CLog::Log(LOGDEBUG,"Window Manager Name: %s", data);
+ }
+ else
+ CLog::Log(LOGDEBUG,"Window Manager Name: ");
+
+ if(status == Success)
+ XFree(data);
+
+ return true;
+}
+
#endif
diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h
index e953d2d..0b7c10a 100644
--- a/xbmc/windowing/X11/WinSystemX11.h
+++ b/xbmc/windowing/X11/WinSystemX11.h
@@ -101,6 +101,7 @@ class CWinSystemX11 : public CWinSystemBase
bool IsSuitableVisual(XVisualInfo *vInfo);
static int XErrorHandler(Display* dpy, XErrorEvent* error);
bool CreateIconPixmap();
+ bool HasWindowManager();
CStopWatch m_screensaverReset;
};
--
1.7.10
From f1051e1991e5ef5d83ce428b841ac365082042ec Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Thu, 12 Jul 2012 11:11:47 +0200
Subject: [PATCH 38/72] X11: dont set window on xrandr if no mode available
---
xbmc/windowing/X11/WinSystemX11.cpp | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp
index 4f1ae26..c11ea89 100644
--- a/xbmc/windowing/X11/WinSystemX11.cpp
+++ b/xbmc/windowing/X11/WinSystemX11.cpp
@@ -665,16 +665,17 @@ void CWinSystemX11::NotifyXRREvent()
CLog::Log(LOGDEBUG, "%s - notify display reset event", __FUNCTION__);
m_windowDirty = true;
+ if (!g_xrandr.Query(true))
+ {
+ CLog::Log(LOGERROR, "WinSystemX11::RefreshWindow - failed to query xrandr");
+ return;
+ }
+
// if external event update resolutions
if (!m_bIsInternalXrr)
{
UpdateResolutions();
}
- else if (!g_xrandr.Query(true))
- {
- CLog::Log(LOGERROR, "WinSystemX11::RefreshWindow - failed to query xrandr");
- return;
- }
m_bIsInternalXrr = false;
CStdString currentOutput = g_guiSettings.GetString("videoscreen.monitor");
--
1.7.10
From 83b9c33e88077d957884ee22316c218e570dc3d5 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Thu, 26 Jul 2012 09:34:28 +0200
Subject: [PATCH 39/72] X11: fix crash after a resolution change on startup
---
xbmc/windowing/X11/WinSystemX11.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp
index c11ea89..0bd72d4 100644
--- a/xbmc/windowing/X11/WinSystemX11.cpp
+++ b/xbmc/windowing/X11/WinSystemX11.cpp
@@ -219,7 +219,8 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl
OnLostDevice();
m_bIsInternalXrr = true;
g_xrandr.SetMode(out, mode);
- return true;
+ if (m_glWindow)
+ return true;
}
#endif
--
1.7.10
From b8956ed57f1b683ae79d7306c7461a31c894e9a9 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Sat, 15 Sep 2012 18:27:29 +0200
Subject: [PATCH 40/72] X11: lock graphics context in NotifyXRREvent
---
xbmc/windowing/X11/WinSystemX11.cpp | 2 ++
1 file changed, 2 insertions(+)
diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp
index 0bd72d4..ef83133 100644
--- a/xbmc/windowing/X11/WinSystemX11.cpp
+++ b/xbmc/windowing/X11/WinSystemX11.cpp
@@ -666,6 +666,8 @@ void CWinSystemX11::NotifyXRREvent()
CLog::Log(LOGDEBUG, "%s - notify display reset event", __FUNCTION__);
m_windowDirty = true;
+ CSingleLock lock(g_graphicsContext);
+
if (!g_xrandr.Query(true))
{
CLog::Log(LOGERROR, "WinSystemX11::RefreshWindow - failed to query xrandr");
--
1.7.10
From aed5d244b81b1a0b171b7fea3b332decafc96c56 Mon Sep 17 00:00:00 2001
From: Rainer Hochecker <fernetmenta@online.de>
Date: Sat, 8 Oct 2011 16:45:13 +0200
Subject: [PATCH 41/72] 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 922cada27e255bc3f685b700c2ffa4a146f87624 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Thu, 12 Apr 2012 12:09:31 +0200
Subject: [PATCH 42/72] xvba: add decoder
---
configure.in | 48 +
language/English/strings.po | 12 +-
xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 218 +-
xbmc/cores/VideoRenderers/LinuxRendererGL.h | 15 +-
xbmc/cores/VideoRenderers/RenderFormats.h | 1 +
xbmc/cores/VideoRenderers/RenderManager.cpp | 9 +-
.../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h | 4 +
.../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 16 +
xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in | 4 +
xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp | 2354 ++++++++++++++++++++
xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.h | 382 ++++
xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 3 +
xbmc/settings/GUISettings.cpp | 3 +
xbmc/settings/VideoSettings.h | 2 +
xbmc/video/dialogs/GUIDialogVideoSettings.cpp | 1 +
15 files changed, 3064 insertions(+), 8 deletions(-)
create mode 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp
create mode 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.h
diff --git a/configure.in b/configure.in
index 350d960..3660fa4 100644
--- a/configure.in
+++ b/configure.in
@@ -124,6 +124,8 @@ vaapi_not_found="== Could not find libva. VAAPI support disabled. =="
vaapi_disabled="== VAAPI support manually disabled. =="
crystalhd_not_found="== Could not find libcrystalhd. CrystalHD support disabled. =="
crystalhd_disabled="== CrystalHD support manually disabled. =="
+xvba_not_found="== Could not find amdxvba.h. XVBA support disabled. =="
+xvba_disabled="== XVBA support manually disabled. =="
vdadecoder_enabled="== VDADecoder support enabled. =="
vdadecoder_disabled="== VDADecoder support manually disabled. =="
vtbdecoder_enabled="== VTBDecoder support enabled. =="
@@ -247,6 +249,12 @@ AC_ARG_ENABLE([crystalhd],
[enable CrystalHD decoding (default is auto)])],
[use_crystalhd=$enableval],
[use_crystalhd=auto])
+
+AC_ARG_ENABLE([xvba],
+ [AS_HELP_STRING([--enable-xvba],
+ [enable XVBA decoding (default is auto)])],
+ [use_xvba=$enableval],
+ [use_xvba=auto])
AC_ARG_ENABLE([vdadecoder],
[AS_HELP_STRING([--enable-vdadecoder],
@@ -1759,6 +1767,38 @@ else
USE_CRYSTALHD=0
fi
+# XVBA
+if test "x$use_xvba" != "xno"; then
+ if test "$host_vendor" = "apple" ; then
+ if test "x$use_xvba" = "xyes"; then
+ AC_MSG_ERROR([XVBA not supported on this platform])
+ else
+ use_xvba="no"
+ AC_MSG_NOTICE($xvba_disabled)
+ fi
+ USE_XVBA=0
+ else
+ initial_val=$use_xvba
+ AC_CHECK_HEADER([amd/amdxvba.h],, use_xvba=no, [#include <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
@@ -1970,6 +2010,12 @@ else
final_message="$final_message\n CrystalHD:\tNo"
fi
+if test "x$use_xvba" != "xno"; then
+ final_message="$final_message\n XVBA:\t\tYes"
+else
+ final_message="$final_message\n XVBA:\t\tNo"
+fi
+
if test "x$use_vdadecoder" != "xno"; then
final_message="$final_message\n VDADecoder:\tYes"
else
@@ -2443,6 +2489,7 @@ AC_SUBST(USE_OPENGLES)
AC_SUBST(USE_VDPAU)
AC_SUBST(USE_VAAPI)
AC_SUBST(USE_CRYSTALHD)
+AC_SUBST(USE_XVBA)
AC_SUBST(USE_LIBSMBCLIENT)
AC_SUBST(USE_LIBNFS)
AC_SUBST(USE_LIBAFPCLIENT)
@@ -2626,6 +2673,7 @@ XB_CONFIG_MODULE([lib/ffmpeg], [
`if test "x$use_vdpau" != "xno"; then echo --enable-vdpau; else echo --disable-vdpau; fi` \
`if test "x$use_vaapi" != "xno"; then echo --enable-vaapi; else echo --disable-vaapi; fi` \
`if test "$use_optimizations" != "no"; then echo --enable-optimizations; else echo --disable-optimizations; fi` \
+ `if test "x$use_xvba" != "xno"; then echo --enable-xvba; else echo --disable-xvba; fi` \
--enable-protocol=http \
--enable-pthreads \
--enable-runtime-cpudetect \
diff --git a/language/English/strings.po b/language/English/strings.po
index bba7284..ede18b3 100644
--- a/language/English/strings.po
+++ b/language/English/strings.po
@@ -5124,7 +5124,11 @@ msgctxt "#13436"
msgid "Allow Vdpau OpenGL interop YUV"
msgstr ""
-#empty strings from id 13437 to 13499
+msgctxt "#13437"
+msgid "Allow hardware acceleration (XVBA)"
+msgstr ""
+
+#empty strings from id 13438 to 13499
msgctxt "#13500"
msgid "A/V sync method"
@@ -6346,7 +6350,11 @@ msgctxt "#16325"
msgid "VDPAU - Bob"
msgstr ""
-#empty strings from id 16326 to 16399
+msgctxt "#16326"
+msgid "XVBA"
+msgstr ""
+
+#empty strings from id 16327 to 16399
msgctxt "#16400"
msgid "Post-processing"
diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
index b281ca7..ec3606a 100644
--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
@@ -63,6 +63,9 @@
VA_MICRO_VERSION == 0 && VA_SDS_VERSION < 5)))
#endif
+#ifdef HAVE_LIBXVBA
+#include "cores/dvdplayer/DVDCodecs/Video/XVBA.h"
+#endif
#ifdef TARGET_DARWIN
#include "osx/CocoaInterface.h"
@@ -129,6 +132,9 @@
#ifdef HAVE_LIBVDPAU
vdpau = NULL;
#endif
+#ifdef HAVE_LIBXVBA
+ xvba = NULL;
+#endif
}
CLinuxRendererGL::YUVBUFFER::~YUVBUFFER()
@@ -604,6 +610,9 @@ void CLinuxRendererGL::ReleaseBuffer(int idx)
#ifdef HAVE_LIBVDPAU
SAFE_RELEASE(buf.vdpau);
#endif
+#ifdef HAVE_LIBXVBA
+ SAFE_RELEASE(buf.xvba);
+#endif
#ifdef HAVE_LIBVA
buf.vaapi.surface.reset();
#endif
@@ -879,7 +888,7 @@ void CLinuxRendererGL::UpdateVideoFilter()
case VS_SCALINGMETHOD_LINEAR:
SetTextureFilter(m_scalingMethod == VS_SCALINGMETHOD_NEAREST ? GL_NEAREST : GL_LINEAR);
m_renderQuality = RQ_SINGLEPASS;
- if (((m_renderMethod & RENDER_VDPAU) || (m_renderMethod & RENDER_VAAPI)) && m_nonLinStretch)
+ if (((m_renderMethod & RENDER_VDPAU) || (m_renderMethod & RENDER_VAAPI) || (m_renderMethod & RENDER_XVBA)) && m_nonLinStretch)
{
m_pVideoFilterShader = new StretchFilterShader();
if (!m_pVideoFilterShader->CompileAndLink())
@@ -965,6 +974,11 @@ void CLinuxRendererGL::LoadShaders(int field)
CLog::Log(LOGNOTICE, "GL: Using CVBREF render method");
m_renderMethod = RENDER_CVREF;
}
+ else if (m_format == RENDER_FMT_XVBA)
+ {
+ CLog::Log(LOGNOTICE, "GL: Using XVBA render method");
+ m_renderMethod = RENDER_XVBA;
+ }
else
{
int requestedMethod = g_guiSettings.GetInt("videoplayer.rendermethod");
@@ -1113,6 +1127,12 @@ void CLinuxRendererGL::LoadShaders(int field)
m_textureCreate = &CLinuxRendererGL::CreateCVRefTexture;
m_textureDelete = &CLinuxRendererGL::DeleteCVRefTexture;
}
+ else if (m_format == RENDER_FMT_XVBA)
+ {
+ m_textureUpload = &CLinuxRendererGL::UploadXVBATexture;
+ m_textureCreate = &CLinuxRendererGL::CreateXVBATexture;
+ m_textureDelete = &CLinuxRendererGL::DeleteXVBATexture;
+ }
else
{
// setup default YV12 texture handlers
@@ -1225,6 +1245,13 @@ void CLinuxRendererGL::Render(DWORD flags, int renderBuffer)
RenderVAAPI(renderBuffer, m_currentField);
}
#endif
+#ifdef HAVE_LIBXVBA
+ else if (m_renderMethod & RENDER_XVBA)
+ {
+ UpdateVideoFilter();
+ RenderXVBA(renderBuffer, m_currentField);
+ }
+#endif
else
{
// RENDER_CVREF uses the same render as the default case
@@ -1732,6 +1759,77 @@ void CLinuxRendererGL::RenderVAAPI(int index, int field)
#endif
}
+void CLinuxRendererGL::RenderXVBA(int index, int field)
+{
+#ifdef HAVE_LIBXVBA
+ YUVPLANE &plane = m_buffers[index].fields[0][1];
+
+ glEnable(m_textureTarget);
+ glActiveTextureARB(GL_TEXTURE0);
+
+ glBindTexture(m_textureTarget, plane.id);
+
+ // Try some clamping or wrapping
+ glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ if (m_pVideoFilterShader)
+ {
+ GLint filter;
+ if (!m_pVideoFilterShader->GetTextureFilter(filter))
+ filter = m_scalingMethod == VS_SCALINGMETHOD_NEAREST ? GL_NEAREST : GL_LINEAR;
+
+ glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, filter);
+ glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, filter);
+ m_pVideoFilterShader->SetSourceTexture(0);
+ m_pVideoFilterShader->SetWidth(m_sourceWidth);
+ m_pVideoFilterShader->SetHeight(m_sourceHeight);
+
+ //disable non-linear stretch when a dvd menu is shown, parts of the menu are rendered through the overlay renderer
+ //having non-linear stretch on breaks the alignment
+ if (g_application.m_pPlayer && g_application.m_pPlayer->IsInMenu())
+ m_pVideoFilterShader->SetNonLinStretch(1.0);
+ else
+ m_pVideoFilterShader->SetNonLinStretch(pow(g_settings.m_fPixelRatio, g_advancedSettings.m_videoNonLinStretchRatio));
+
+ m_pVideoFilterShader->Enable();
+ }
+ else
+ {
+ GLint filter = m_scalingMethod == VS_SCALINGMETHOD_NEAREST ? GL_NEAREST : GL_LINEAR;
+ glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, filter);
+ glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, filter);
+ }
+
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ VerifyGLState();
+
+ glBegin(GL_QUADS);
+ if (m_textureTarget==GL_TEXTURE_2D)
+ {
+ glTexCoord2f(plane.rect.x1, plane.rect.y1); glVertex2f(m_destRect.x1, m_destRect.y1);
+ glTexCoord2f(plane.rect.x2, plane.rect.y1); glVertex2f(m_destRect.x2, m_destRect.y1);
+ glTexCoord2f(plane.rect.x2, plane.rect.y2); glVertex2f(m_destRect.x2, m_destRect.y2);
+ glTexCoord2f(plane.rect.x1, plane.rect.y2); glVertex2f(m_destRect.x1, m_destRect.y2);
+ }
+ else
+ {
+ glTexCoord2f(m_destRect.x1, m_destRect.y1); glVertex4f(m_destRect.x1, m_destRect.y1, 0.0f, 0.0f);
+ glTexCoord2f(m_destRect.x2, m_destRect.y1); glVertex4f(m_destRect.x2, m_destRect.y1, 1.0f, 0.0f);
+ glTexCoord2f(m_destRect.x2, m_destRect.y2); glVertex4f(m_destRect.x2, m_destRect.y2, 1.0f, 1.0f);
+ glTexCoord2f(m_destRect.x1, m_destRect.y2); glVertex4f(m_destRect.x1, m_destRect.y2, 0.0f, 1.0f);
+ }
+ glEnd();
+ VerifyGLState();
+
+ if (m_pVideoFilterShader)
+ m_pVideoFilterShader->Disable();
+
+ glBindTexture (m_textureTarget, 0);
+ glDisable(m_textureTarget);
+#endif
+}
+
void CLinuxRendererGL::RenderSoftware(int index, int field)
{
// used for textues uploaded from rgba or CVPixelBuffers.
@@ -2783,6 +2881,93 @@ bool CLinuxRendererGL::CreateCVRefTexture(int index)
return true;
}
+void CLinuxRendererGL::DeleteXVBATexture(int index)
+{
+#ifdef HAVE_LIBXVBA
+ YUVPLANE &plane = m_buffers[index].fields[0][0];
+ YUVFIELDS &fields = m_buffers[index].fields;
+
+ SAFE_RELEASE(m_buffers[index].xvba);
+
+ if(plane.id && glIsTexture(plane.id))
+ glDeleteTextures(1, &plane.id);
+ plane.id = 0;
+ fields[0][1].id = 0;
+#endif
+}
+
+bool CLinuxRendererGL::CreateXVBATexture(int index)
+{
+#ifdef HAVE_LIBXVBA
+ YV12Image &im = m_buffers[index].image;
+ YUVFIELDS &fields = m_buffers[index].fields;
+ YUVPLANE &plane = fields[0][0];
+
+ DeleteXVBATexture(index);
+
+ memset(&im , 0, sizeof(im));
+ memset(&fields, 0, sizeof(fields));
+
+ glGenTextures(1, &plane.id);
+
+ m_eventTexturesDone[index]->Set();
+#endif
+ return true;
+}
+
+void CLinuxRendererGL::UploadXVBATexture(int index)
+{
+#ifdef HAVE_LIBXVBA
+ XVBA::CXvbaRenderPicture *xvba = m_buffers[index].xvba;
+ YV12Image &im = m_buffers[index].image;
+
+ YUVFIELDS &fields = m_buffers[index].fields;
+ YUVPLANE &plane = fields[0][1];
+
+ if (!xvba)
+ {
+ fields[0][1].id = fields[0][0].id;
+ m_eventTexturesDone[index]->Set();
+ CLog::Log(LOGWARNING,"CLinuxRendererGL::UploadXVBATexture no xvba texture, index: %d", index);
+ return;
+ }
+// xvba->Transfer();
+
+ fields[0][1].id = xvba->texture;
+
+ im.height = xvba->texHeight;
+ im.width = xvba->texWidth;
+
+ plane.texwidth = xvba->texWidth;
+ plane.texheight = xvba->texHeight;
+ plane.pixpertex_x = 1;
+ plane.pixpertex_y = 1;
+
+ plane.rect = m_sourceRect;
+ plane.width = im.width;
+ plane.height = im.height;
+
+ plane.height /= plane.pixpertex_y;
+ plane.rect.y1 /= plane.pixpertex_y;
+ plane.rect.y2 /= plane.pixpertex_y;
+ plane.width /= plane.pixpertex_x;
+ plane.rect.x1 /= plane.pixpertex_x;
+ plane.rect.x2 /= plane.pixpertex_x;
+
+ if (m_textureTarget == GL_TEXTURE_2D)
+ {
+ plane.height /= plane.texheight;
+ plane.rect.y1 /= plane.texheight;
+ plane.rect.y2 /= plane.texheight;
+ plane.width /= plane.texwidth;
+ plane.rect.x1 /= plane.texwidth;
+ plane.rect.x2 /= plane.texwidth;
+ }
+
+ m_eventTexturesDone[index]->Set();
+#endif
+}
+
void CLinuxRendererGL::UploadYUV422PackedTexture(int source)
{
YUVBUFFER& buf = m_buffers[source];
@@ -3368,6 +3553,9 @@ bool CLinuxRendererGL::Supports(ERENDERFEATURE feature)
if (m_renderMethod & RENDER_VAAPI)
return false;
+ if (m_renderMethod & RENDER_XVBA)
+ return false;
+
return (m_renderMethod & RENDER_GLSL)
|| (m_renderMethod & RENDER_ARB)
|| ((m_renderMethod & RENDER_SW) && glewIsSupported("GL_ARB_imaging") == GL_TRUE);
@@ -3381,6 +3569,9 @@ bool CLinuxRendererGL::Supports(ERENDERFEATURE feature)
if (m_renderMethod & RENDER_VAAPI)
return false;
+ if (m_renderMethod & RENDER_XVBA)
+ return false;
+
return (m_renderMethod & RENDER_GLSL)
|| (m_renderMethod & RENDER_ARB)
|| ((m_renderMethod & RENDER_SW) && glewIsSupported("GL_ARB_imaging") == GL_TRUE);
@@ -3404,7 +3595,8 @@ bool CLinuxRendererGL::Supports(ERENDERFEATURE feature)
if (feature == RENDERFEATURE_NONLINSTRETCH)
{
if (((m_renderMethod & RENDER_GLSL) && !(m_renderMethod & RENDER_POT)) ||
- (m_renderMethod & RENDER_VDPAU) || (m_renderMethod & RENDER_VAAPI))
+ (m_renderMethod & RENDER_VDPAU) || (m_renderMethod & RENDER_VAAPI) ||
+ (m_renderMethod & RENDER_XVBA))
return true;
}
@@ -3476,6 +3668,16 @@ bool CLinuxRendererGL::Supports(EINTERLACEMETHOD method)
return false;
}
+ if(m_renderMethod & RENDER_XVBA)
+ {
+#ifdef HAVE_LIBXVBA
+ XVBA::CXvbaRenderPicture *xvba = m_buffers[m_iYV12RenderBuffer].xvba;
+ if(xvba)
+ return xvba->xvba->Supports(method);
+#endif
+ return false;
+ }
+
#ifdef TARGET_DARWIN
// YADIF too slow for HD but we have no methods to fall back
// to something that works so just turn it off.
@@ -3518,7 +3720,7 @@ bool CLinuxRendererGL::Supports(ESCALINGMETHOD method)
|| method == VS_SCALINGMETHOD_LANCZOS3)
{
if ((glewIsSupported("GL_EXT_framebuffer_object") && (m_renderMethod & RENDER_GLSL)) ||
- (m_renderMethod & RENDER_VDPAU) || (m_renderMethod & RENDER_VAAPI))
+ (m_renderMethod & RENDER_VDPAU) || (m_renderMethod & RENDER_VAAPI) || (m_renderMethod & RENDER_XVBA))
{
// spline36 and lanczos3 are only allowed through advancedsettings.xml
if(method != VS_SCALINGMETHOD_SPLINE36
@@ -3610,4 +3812,14 @@ void CLinuxRendererGL::AddProcessor(struct __CVBuffer *cvBufferRef, int index)
}
#endif
+#ifdef HAVE_LIBXVBA
+void CLinuxRendererGL::AddProcessor(XVBA::CXvbaRenderPicture* xvba, int index)
+{
+ YUVBUFFER &buf = m_buffers[index];
+ XVBA::CXvbaRenderPicture *pic = xvba->Acquire();
+ SAFE_RELEASE(buf.xvba);
+ buf.xvba = pic;
+}
+#endif
+
#endif
diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.h b/xbmc/cores/VideoRenderers/LinuxRendererGL.h
index 2fc34ae..e76624b 100644
--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.h
+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.h
@@ -43,6 +43,8 @@
namespace Shaders { class BaseVideoFilterShader; }
namespace VAAPI { struct CHolder; }
namespace VDPAU { class CVdpauRenderPicture; }
+namespace XVBA { class CXvbaRenderPicture; }
+
#define NUM_BUFFERS 10
@@ -90,6 +92,7 @@ enum RenderMethod
RENDER_POT=0x10,
RENDER_VAAPI=0x20,
RENDER_CVREF = 0x40,
+ RENDER_XVBA=0x80,
};
enum RenderQuality
@@ -151,7 +154,9 @@ class CLinuxRendererGL : public CBaseRenderer
#ifdef TARGET_DARWIN
virtual void AddProcessor(struct __CVBuffer *cvBufferRef, int index);
#endif
-
+#ifdef HAVE_LIBXVBA
+ virtual void AddProcessor(XVBA::CXvbaRenderPicture* xvba, int index);
+#endif
virtual void RenderUpdate(bool clear, DWORD flags = 0, DWORD alpha = 255);
// Feature support
@@ -210,6 +215,10 @@ class CLinuxRendererGL : public CBaseRenderer
void DeleteYUV422PackedTexture(int index);
bool CreateYUV422PackedTexture(int index);
+ void UploadXVBATexture(int index);
+ void DeleteXVBATexture(int index);
+ bool CreateXVBATexture(int index);
+
void UploadRGBTexture(int index);
void ToRGBFrame(YV12Image* im, unsigned flipIndexPlane, unsigned flipIndexBuf);
void ToRGBFields(YV12Image* im, unsigned flipIndexPlaneTop, unsigned flipIndexPlaneBot, unsigned flipIndexBuf);
@@ -225,6 +234,7 @@ class CLinuxRendererGL : public CBaseRenderer
void RenderVDPAU(int renderBuffer, int field); // render using vdpau hardware
void RenderProgressiveWeave(int renderBuffer, int field); // render using vdpau hardware
void RenderVAAPI(int renderBuffer, int field); // render using vdpau hardware
+ void RenderXVBA(int renderBuffer, int field); // render using xvba hardware
struct
{
@@ -292,6 +302,9 @@ class CLinuxRendererGL : public CBaseRenderer
#ifdef TARGET_DARWIN_OSX
struct __CVBuffer *cvBufferRef;
#endif
+#ifdef HAVE_LIBXVBA
+ XVBA::CXvbaRenderPicture *xvba;
+#endif
};
typedef YUVBUFFER YUVBUFFERS[NUM_BUFFERS];
diff --git a/xbmc/cores/VideoRenderers/RenderFormats.h b/xbmc/cores/VideoRenderers/RenderFormats.h
index 0262c60..a727d94 100644
--- a/xbmc/cores/VideoRenderers/RenderFormats.h
+++ b/xbmc/cores/VideoRenderers/RenderFormats.h
@@ -35,6 +35,7 @@ enum ERenderFormat {
RENDER_FMT_OMXEGL,
RENDER_FMT_CVBREF,
RENDER_FMT_BYPASS,
+ RENDER_FMT_XVBA,
};
#endif
diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp
index a521680..0506823 100644
--- a/xbmc/cores/VideoRenderers/RenderManager.cpp
+++ b/xbmc/cores/VideoRenderers/RenderManager.cpp
@@ -250,8 +250,9 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi
// check if decoder supports buffering
m_bCodecSupportsBuffering = false;
- if (format == RENDER_FMT_VDPAU ||
- format == RENDER_FMT_VDPAU_420)
+ if (format == RENDER_FMT_VDPAU
+ || format == RENDER_FMT_VDPAU_420
+ || format == RENDER_FMT_XVBA)
m_bCodecSupportsBuffering = true;
bool result = m_pRenderer->Configure(width, height, d_width, d_height, fps, flags, format, extended_format, orientation);
@@ -873,6 +874,10 @@ int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic)
else if(pic.format == RENDER_FMT_VAAPI)
m_pRenderer->AddProcessor(*pic.vaapi, index);
#endif
+#ifdef HAVE_LIBXVBA
+ else if(pic.format == RENDER_FMT_XVBA)
+ m_pRenderer->AddProcessor(pic.xvba, index);
+#endif
m_pRenderer->ReleaseImage(index, false);
return index;
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
index 98d8f89..76d3575 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
@@ -35,6 +35,7 @@
namespace DXVA { class CSurfaceContext; }
namespace VAAPI { struct CHolder; }
namespace VDPAU { class CVdpauRenderPicture; }
+namespace XVBA { class CXvbaRenderPicture; }
class COpenMax;
class COpenMaxVideo;
struct OpenMaxVideoBuffer;
@@ -60,6 +61,9 @@ struct DVDVideoPicture
struct {
VAAPI::CHolder* vaapi;
};
+ struct {
+ XVBA::CXvbaRenderPicture* xvba;
+ };
struct {
COpenMax *openMax;
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
index a6e42e5..b3252ec 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
@@ -56,6 +56,9 @@
#ifdef HAVE_LIBVA
#include "VAAPI.h"
#endif
+#ifdef HAVE_LIBXVBA
+#include "XVBA.h"
+#endif
using namespace boost;
@@ -100,6 +103,19 @@ enum PixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx
dec->Release();
}
#endif
+#ifdef HAVE_LIBXVBA
+ if(*cur == PIX_FMT_XVBA_VLD && g_guiSettings.GetBool("videoplayer.usexvba"))
+ {
+ XVBA::CDecoder* dec = new XVBA::CDecoder();
+ if(dec->Open(avctx, *cur, ctx->m_uSurfacesCount))
+ {
+ ctx->SetHardware(dec);
+ return *cur;
+ }
+ else
+ dec->Release();
+ }
+#endif
#ifdef HAVE_LIBVA
// mpeg4 vaapi decoding is disabled
if(*cur == PIX_FMT_VAAPI_VLD && g_guiSettings.GetBool("videoplayer.usevaapi")
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in b/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in
index 176ceff..c58422b 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in
@@ -14,6 +14,10 @@ ifeq (@USE_CRYSTALHD@,1)
SRCS += CrystalHD.cpp
SRCS += DVDVideoCodecCrystalHD.cpp
endif
+ifeq (@USE_XVBA@,1)
+SRCS+= XVBA.cpp \
+
+endif
ifeq (@USE_VDA@,1)
SRCS += DVDVideoCodecVDA.cpp
endif
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp
new file mode 100644
index 0000000..e8e376a
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp
@@ -0,0 +1,2354 @@
+/*
+ * Copyright (C) 2005-2011 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "system.h"
+#ifdef HAVE_LIBXVBA
+
+#include "system_gl.h"
+#include <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 0e320e1..10ef779 100644
--- a/xbmc/settings/GUISettings.cpp
+++ b/xbmc/settings/GUISettings.cpp
@@ -696,6 +696,9 @@ void CGUISettings::Initialize()
#ifdef HAVE_LIBVA
AddBool(vp, "videoplayer.usevaapi", 13426, true);
#endif
+#ifdef HAVE_LIBXVBA
+ AddBool(vp, "videoplayer.usexvba", 13437, true);
+#endif
#ifdef HAS_DX
AddBool(g_sysinfo.IsVistaOrHigher() ? vp: NULL, "videoplayer.usedxva2", 13427, g_sysinfo.IsVistaOrHigher() ? true : false);
#endif
diff --git a/xbmc/settings/VideoSettings.h b/xbmc/settings/VideoSettings.h
index f8093b2..f54a837 100644
--- a/xbmc/settings/VideoSettings.h
+++ b/xbmc/settings/VideoSettings.h
@@ -65,6 +65,8 @@ enum EINTERLACEMETHOD
VS_INTERLACEMETHOD_SW_BLEND = 20,
VS_INTERLACEMETHOD_AUTO_ION = 21,
+ VS_INTERLACEMETHOD_XVBA = 22,
+
VS_INTERLACEMETHOD_MAX // do not use and keep as last enum value.
};
diff --git a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp
index f25d10d..f6b1ea4 100644
--- a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp
+++ b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp
@@ -110,6 +110,7 @@ void CGUIDialogVideoSettings::CreateSettings()
entries.push_back(make_pair(VS_INTERLACEMETHOD_DXVA_BOB , 16320));
entries.push_back(make_pair(VS_INTERLACEMETHOD_DXVA_BEST , 16321));
entries.push_back(make_pair(VS_INTERLACEMETHOD_AUTO_ION , 16325));
+ entries.push_back(make_pair(VS_INTERLACEMETHOD_XVBA , 16326));
/* remove unsupported methods */
for(vector<pair<int, int> >::iterator it = entries.begin(); it != entries.end();)
--
1.7.10
From 517eda0bf58a6376a82839ab92e51b97c143edf1 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Thu, 23 Aug 2012 19:39:49 +0200
Subject: [PATCH 43/72] ffmpeg: add av_find_default_stream_index to interface
---
lib/DllAvFormat.h | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/lib/DllAvFormat.h b/lib/DllAvFormat.h
index 9bda3f3..bf31fcb 100644
--- a/lib/DllAvFormat.h
+++ b/lib/DllAvFormat.h
@@ -98,6 +98,7 @@ class DllAvFormatInterface
virtual int avformat_write_header (AVFormatContext *s, AVDictionary **options)=0;
virtual int av_write_trailer(AVFormatContext *s)=0;
virtual int av_write_frame (AVFormatContext *s, AVPacket *pkt)=0;
+ virtual int av_find_default_stream_index(AVFormatContext *s)=0;
};
#if (defined USE_EXTERNAL_FFMPEG) || (defined TARGET_DARWIN)
@@ -153,6 +154,7 @@ class DllAvFormat : public DllDynamic, DllAvFormatInterface
virtual int avformat_write_header (AVFormatContext *s, AVDictionary **options) { return ::avformat_write_header (s, options); }
virtual int av_write_trailer(AVFormatContext *s) { return ::av_write_trailer(s); }
virtual int av_write_frame (AVFormatContext *s, AVPacket *pkt) { return ::av_write_frame(s, pkt); }
+ virtual int av_find_default_stream_index(AVFormatContext *s) { return ::av_find_default_stream_index(s); }
// DLL faking.
virtual bool ResolveExports() { return true; }
@@ -209,6 +211,7 @@ class DllAvFormat : public DllDynamic, DllAvFormatInterface
DEFINE_METHOD2(int, avformat_write_header , (AVFormatContext *p1, AVDictionary **p2))
DEFINE_METHOD1(int, av_write_trailer, (AVFormatContext *p1))
DEFINE_METHOD2(int, av_write_frame , (AVFormatContext *p1, AVPacket *p2))
+ DEFINE_METHOD1(int, av_find_default_stream_index, (AVFormatContext *p1))
BEGIN_METHOD_RESOLVE()
RESOLVE_METHOD_RENAME(av_register_all, av_register_all_dont_call)
RESOLVE_METHOD(av_find_input_format)
@@ -243,6 +246,7 @@ class DllAvFormat : public DllDynamic, DllAvFormatInterface
RESOLVE_METHOD(avformat_write_header)
RESOLVE_METHOD(av_write_trailer)
RESOLVE_METHOD(av_write_frame)
+ RESOLVE_METHOD(av_find_default_stream_index)
END_METHOD_RESOLVE()
/* dependencies of libavformat */
--
1.7.10
From 23be471842ae9ea7bd62c18261a5e96a11045d04 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Mon, 20 Aug 2012 16:06:39 +0200
Subject: [PATCH 44/72] 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 66382788a903f99ba317e972ba0445fc68320750 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Tue, 2 Oct 2012 13:02:10 +0200
Subject: [PATCH 45/72] dvdplayer: avoid short screen flicker caused by
unnecessary reconfigure of renderer
---
xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
index e5e71f3..8b02d81 100644
--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
@@ -1033,7 +1033,7 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts)
|| m_output.height != pPicture->iHeight
|| m_output.dwidth != pPicture->iDisplayWidth
|| m_output.dheight != pPicture->iDisplayHeight
- || m_output.framerate != config_framerate
+ || (!m_bFpsInvalid && fmod(m_output.framerate, config_framerate) != 0.0 )
|| m_output.color_format != (unsigned int)pPicture->format
|| m_output.extended_format != pPicture->extended_format
|| ( m_output.color_matrix != pPicture->color_matrix && pPicture->color_matrix != 0 ) // don't reconfigure on unspecified
@@ -1184,7 +1184,7 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts)
m_output.height = pPicture->iHeight;
m_output.dwidth = pPicture->iDisplayWidth;
m_output.dheight = pPicture->iDisplayHeight;
- m_output.framerate = config_framerate;
+ m_output.framerate = config_framerate == 0.0 ? g_graphicsContext.GetFPS() : config_framerate;
m_output.color_format = pPicture->format;
m_output.extended_format = pPicture->extended_format;
m_output.color_matrix = pPicture->color_matrix;
--
1.7.10
From 04f4521c1938a7ac17acd59f3bd6be59c7ba8184 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Sat, 16 Jun 2012 12:46:30 +0200
Subject: [PATCH 46/72] xvba: do not use vaapi if xvba is present
---
xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp
index a2b9195..43a05b3 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp
@@ -261,6 +261,15 @@ void CDecoder::Close()
bool CDecoder::Open(AVCodecContext *avctx, enum PixelFormat fmt, unsigned int surfaces)
{
+#ifdef HAVE_LIBXVBA
+ std::string Vendor = g_Windowing.GetRenderVendor();
+ std::transform(Vendor.begin(), Vendor.end(), Vendor.begin(), ::tolower);
+ if (Vendor.compare(0, 3, "ati") == 0)
+ {
+ return false;
+ }
+#endif
+
VAEntrypoint entrypoint = VAEntrypointVLD;
VAProfile profile;
--
1.7.10
From a133b7fa119e859ec50b9f05a33de984105234f3 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Thu, 11 Oct 2012 12:05:50 +0200
Subject: [PATCH 47/72] vdpau: advanced settings for auto deinterlacing
---
xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 8 ++++----
xbmc/settings/AdvancedSettings.cpp | 4 ++++
xbmc/settings/AdvancedSettings.h | 2 ++
3 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp
index 235f565..d95797b 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp
@@ -1770,10 +1770,10 @@ EINTERLACEMETHOD CMixer::GetDeinterlacingMethod(bool log /* = false */)
if (method == VS_INTERLACEMETHOD_AUTO)
{
int deint = -1;
-// if (m_config.outHeight >= 720)
-// deint = g_advancedSettings.m_videoVDPAUdeintHD;
-// else
-// deint = g_advancedSettings.m_videoVDPAUdeintSD;
+ if (m_config.outHeight >= 720)
+ deint = g_advancedSettings.m_videoVDPAUdeintHD;
+ else
+ deint = g_advancedSettings.m_videoVDPAUdeintSD;
if (deint != -1)
{
diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp
index 844f8e8..d913924 100644
--- a/xbmc/settings/AdvancedSettings.cpp
+++ b/xbmc/settings/AdvancedSettings.cpp
@@ -106,6 +106,8 @@ void CAdvancedSettings::Initialize()
m_videoAllowMpeg4VAAPI = false;
m_videoDisableBackgroundDeinterlace = false;
m_videoCaptureUseOcclusionQuery = -1; //-1 is auto detect
+ m_videoVDPAUdeintHD = -1;
+ m_videoVDPAUdeintSD = -1;
m_videoVDPAUtelecine = false;
m_videoVDPAUdeintSkipChromaHD = false;
m_DXVACheckCompatibility = false;
@@ -503,6 +505,8 @@ void CAdvancedSettings::ParseSettingsFile(const CStdString &file)
XMLUtils::GetBoolean(pElement,"allowmpeg4vaapi",m_videoAllowMpeg4VAAPI);
XMLUtils::GetBoolean(pElement, "disablebackgrounddeinterlace", m_videoDisableBackgroundDeinterlace);
XMLUtils::GetInt(pElement, "useocclusionquery", m_videoCaptureUseOcclusionQuery, -1, 1);
+ XMLUtils::GetInt(pElement,"vdpauHDdeint",m_videoVDPAUdeintHD);
+ XMLUtils::GetInt(pElement,"vdpauSDdeint",m_videoVDPAUdeintSD);
XMLUtils::GetBoolean(pElement,"vdpauInvTelecine",m_videoVDPAUtelecine);
XMLUtils::GetBoolean(pElement,"vdpauHDdeintSkipChroma",m_videoVDPAUdeintSkipChromaHD);
diff --git a/xbmc/settings/AdvancedSettings.h b/xbmc/settings/AdvancedSettings.h
index 72718e5..aaa4702 100644
--- a/xbmc/settings/AdvancedSettings.h
+++ b/xbmc/settings/AdvancedSettings.h
@@ -133,6 +133,8 @@ class CAdvancedSettings
int m_videoPercentSeekBackwardBig;
CStdString m_videoPPFFmpegDeint;
CStdString m_videoPPFFmpegPostProc;
+ int m_videoVDPAUdeintHD;
+ int m_videoVDPAUdeintSD;
bool m_videoVDPAUtelecine;
bool m_videoVDPAUdeintSkipChromaHD;
bool m_musicUseTimeSeeking;
--
1.7.10
From 62540aeaa356823bd34e9367ac39eef23a6e4ce4 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Thu, 11 Oct 2012 13:01:08 +0200
Subject: [PATCH 48/72] dvdplayer: correct determination if video is playing
---
xbmc/cores/dvdplayer/DVDPlayer.cpp | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp
index 6fcb6b3..f76691d 100644
--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp
@@ -2382,9 +2382,16 @@ bool CDVDPlayer::IsPaused() const
bool CDVDPlayer::HasVideo() const
{
- if (m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD)) return true;
+ bool hasVideo(false);
- return m_SelectionStreams.Count(STREAM_VIDEO) > 0 ? true : false;
+ if (m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD))
+ hasVideo = true;
+ else if (m_SelectionStreams.Count(STREAM_VIDEO) > 0)
+ hasVideo = true;
+ else if (g_renderManager.IsConfigured())
+ hasVideo = true;
+
+ return hasVideo;
}
bool CDVDPlayer::HasAudio() const
--
1.7.10
From 5a093bbd60d1ca47ed7c5e4639f28dafc1b565c1 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Sun, 14 Oct 2012 13:46:54 +0200
Subject: [PATCH 49/72] rendermanager: fix stuttering in non full-screen mode,
squash to add buffering
---
xbmc/cores/VideoRenderers/RenderManager.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp
index 0506823..b141c80 100644
--- a/xbmc/cores/VideoRenderers/RenderManager.cpp
+++ b/xbmc/cores/VideoRenderers/RenderManager.cpp
@@ -1057,8 +1057,9 @@ void CXBMCRenderManager::PrepareNextRender()
presenttime = clocktime + MAXPRESENTDELAY;
m_sleeptime = presenttime - clocktime;
+ double frametime = 1 / g_graphicsContext.GetFPS();
- if (g_graphicsContext.IsFullScreenVideo() || presenttime <= clocktime+0.01)
+ if (g_graphicsContext.IsFullScreenVideo() || presenttime <= clocktime + frametime)
{
m_presentPts = m_renderBuffers[idx].pts;
m_presenttime = presenttime;
--
1.7.10
From d0597caa2c922575efdf081d719d5665c626ffec Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Sun, 14 Oct 2012 17:54:02 +0200
Subject: [PATCH 50/72] rendermanager: forgot to set flip event if buffering
is not used
---
xbmc/cores/VideoRenderers/RenderManager.cpp | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp
index b141c80..9290f80 100644
--- a/xbmc/cores/VideoRenderers/RenderManager.cpp
+++ b/xbmc/cores/VideoRenderers/RenderManager.cpp
@@ -1096,17 +1096,17 @@ void CXBMCRenderManager::NotifyDisplayFlip()
if (!m_pRenderer)
return;
- if (m_iNumRenderBuffers < 3)
- return;
-
- int last = m_iDisplayedRenderBuffer;
- m_iDisplayedRenderBuffer = (m_iCurrentRenderBuffer + m_iNumRenderBuffers - 1) % m_iNumRenderBuffers;
-
- if (last != m_iDisplayedRenderBuffer
- && m_iDisplayedRenderBuffer != m_iCurrentRenderBuffer)
+ if (m_iNumRenderBuffers >= 3)
{
- m_pRenderer->ReleaseBuffer(m_iDisplayedRenderBuffer);
- m_overlays.ReleaseBuffer(m_iDisplayedRenderBuffer);
+ int last = m_iDisplayedRenderBuffer;
+ m_iDisplayedRenderBuffer = (m_iCurrentRenderBuffer + m_iNumRenderBuffers - 1) % m_iNumRenderBuffers;
+
+ if (last != m_iDisplayedRenderBuffer
+ && m_iDisplayedRenderBuffer != m_iCurrentRenderBuffer)
+ {
+ m_pRenderer->ReleaseBuffer(m_iDisplayedRenderBuffer);
+ m_overlays.ReleaseBuffer(m_iDisplayedRenderBuffer);
+ }
}
lock.Leave();
--
1.7.10
From c485392afa608bfbcf903fa53a9dd824258c96dd Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Fri, 26 Oct 2012 15:30:22 +0200
Subject: [PATCH 51/72] vdpau: fix small mem leak
---
xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 2 ++
1 file changed, 2 insertions(+)
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp
index d95797b..fec4b88 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp
@@ -2052,6 +2052,8 @@ void CMixer::Uninit()
m_outputSurfaces.pop();
}
m_config.vdpProcs.vdp_video_mixer_destroy(m_videoMixer);
+
+ delete [] m_BlackBar;
}
void CMixer::Flush()
--
1.7.10
From 9d7228a84013e409149d7b05d34545d1bdf06e27 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Mon, 29 Oct 2012 18:25:56 +0100
Subject: [PATCH 52/72] xvba: do not render if there is no valid texture
---
xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
index ec3606a..7c3adcb 100644
--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
@@ -2924,16 +2924,14 @@ void CLinuxRendererGL::UploadXVBATexture(int index)
YUVFIELDS &fields = m_buffers[index].fields;
YUVPLANE &plane = fields[0][1];
- if (!xvba)
+ if (!xvba || !xvba->valid)
{
- fields[0][1].id = fields[0][0].id;
m_eventTexturesDone[index]->Set();
- CLog::Log(LOGWARNING,"CLinuxRendererGL::UploadXVBATexture no xvba texture, index: %d", index);
+ m_skipRender = true;
return;
}
-// xvba->Transfer();
- fields[0][1].id = xvba->texture;
+ plane.id = xvba->texture;
im.height = xvba->texHeight;
im.width = xvba->texWidth;
--
1.7.10
From 85be082db41b27cdd3824b8360dc021e17a84c22 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Fri, 2 Nov 2012 13:20:03 +0100
Subject: [PATCH 53/72] player: fix rewind
---
xbmc/cores/dvdplayer/DVDMessage.h | 5 ++++-
xbmc/cores/dvdplayer/DVDPlayer.cpp | 33 ++++++++++++++++++++-----------
xbmc/cores/dvdplayer/DVDPlayer.h | 7 ++++---
xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 10 ++++++----
xbmc/cores/dvdplayer/DVDPlayerVideo.h | 1 +
5 files changed, 36 insertions(+), 20 deletions(-)
diff --git a/xbmc/cores/dvdplayer/DVDMessage.h b/xbmc/cores/dvdplayer/DVDMessage.h
index 30b2f5c..b9831d4 100644
--- a/xbmc/cores/dvdplayer/DVDMessage.h
+++ b/xbmc/cores/dvdplayer/DVDMessage.h
@@ -218,7 +218,7 @@ class CDVDMsgPlayerSetState : public CDVDMsg
class CDVDMsgPlayerSeek : public CDVDMsg
{
public:
- CDVDMsgPlayerSeek(int time, bool backward, bool flush = true, bool accurate = true, bool restore = true, bool trickplay = false)
+ CDVDMsgPlayerSeek(int time, bool backward, bool flush = true, bool accurate = true, bool restore = true, bool trickplay = false, bool sync = true)
: CDVDMsg(PLAYER_SEEK)
, m_time(time)
, m_backward(backward)
@@ -226,6 +226,7 @@ class CDVDMsgPlayerSeek : public CDVDMsg
, m_accurate(accurate)
, m_restore(restore)
, m_trickplay(trickplay)
+ , m_sync(sync)
{}
int GetTime() { return m_time; }
bool GetBackward() { return m_backward; }
@@ -233,6 +234,7 @@ class CDVDMsgPlayerSeek : public CDVDMsg
bool GetAccurate() { return m_accurate; }
bool GetRestore() { return m_restore; }
bool GetTrickPlay() { return m_trickplay; }
+ bool GetSync() { return m_sync; }
private:
int m_time;
bool m_backward;
@@ -240,6 +242,7 @@ class CDVDMsgPlayerSeek : public CDVDMsg
bool m_accurate;
bool m_restore; // whether to restore any EDL cut time
bool m_trickplay;
+ bool m_sync;
};
class CDVDMsgPlayerSeekChapter : public CDVDMsg
diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp
index f76691d..07df0d8 100644
--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp
@@ -1543,11 +1543,13 @@ void CDVDPlayer::HandlePlaySpeed()
}
else if (m_CurrentVideo.id >= 0
&& (m_CurrentVideo.inited == true || GetPlaySpeed() < 0) // allow rewind at end of file
- && m_SpeedState.lastpts != m_dvdPlayerVideo.GetCurrentPts()
+ && (m_SpeedState.lastpts != m_dvdPlayerVideo.GetCurrentPts() || fabs(m_SpeedState.lastabstime - CDVDClock::GetAbsoluteClock()) > DVD_MSEC_TO_TIME(200))
+ && (m_dvdPlayerVideo.GetCurrentPts() != DVD_NOPTS_VALUE)
&& m_SpeedState.lasttime != GetTime())
{
m_SpeedState.lastpts = m_dvdPlayerVideo.GetCurrentPts();
m_SpeedState.lasttime = GetTime();
+ m_SpeedState.lastabstime = CDVDClock::GetAbsoluteClock();
// check how much off clock video is when ff/rw:ing
// a problem here is that seeking isn't very accurate
// and since the clock will be resynced after seek
@@ -1566,7 +1568,7 @@ void CDVDPlayer::HandlePlaySpeed()
{
CLog::Log(LOGDEBUG, "CDVDPlayer::Process - Seeking to catch up");
int64_t iTime = (int64_t)DVD_TIME_TO_MSEC(m_clock.GetClock() + m_State.time_offset + 500000.0 * m_playSpeed / DVD_PLAYSPEED_NORMAL);
- m_messenger.Put(new CDVDMsgPlayerSeek(iTime, (GetPlaySpeed() < 0), true, false, false, true));
+ m_messenger.Put(new CDVDMsgPlayerSeek(iTime, (GetPlaySpeed() < 0), true, false, false, true, false));
}
}
}
@@ -2030,7 +2032,7 @@ void CDVDPlayer::HandleMessages()
if(!m_pSubtitleDemuxer->SeekTime(time, msg.GetBackward()))
CLog::Log(LOGDEBUG, "failed to seek subtitle demuxer: %d, success", time);
}
- FlushBuffers(!msg.GetFlush(), start, msg.GetAccurate());
+ FlushBuffers(!msg.GetFlush(), start, msg.GetAccurate(), msg.GetSync());
}
else
CLog::Log(LOGWARNING, "error while seeking");
@@ -2168,9 +2170,10 @@ void CDVDPlayer::HandleMessages()
double offset;
offset = CDVDClock::GetAbsoluteClock() - m_State.timestamp;
offset *= m_playSpeed / DVD_PLAYSPEED_NORMAL;
+ offset = DVD_TIME_TO_MSEC(offset);
if(offset > 1000) offset = 1000;
if(offset < -1000) offset = -1000;
- m_State.time += DVD_TIME_TO_MSEC(offset);
+ m_State.time += offset;
m_State.timestamp = CDVDClock::GetAbsoluteClock();
}
@@ -2186,7 +2189,8 @@ void CDVDPlayer::HandleMessages()
// do a seek after rewind, clock is not in sync with current pts
if (m_playSpeed < 0 && speed >= 0)
{
- m_messenger.Put(new CDVDMsgPlayerSeek(GetTime(), true, true, true));
+ int64_t iTime = (int64_t)DVD_TIME_TO_MSEC(m_clock.GetClock() + m_State.time_offset);
+ m_messenger.Put(new CDVDMsgPlayerSeek(iTime, true, true, false, false, true));
}
// if playspeed is different then DVD_PLAYSPEED_NORMAL or DVD_PLAYSPEED_PAUSE
@@ -2767,10 +2771,11 @@ int64_t CDVDPlayer::GetTime()
{
offset = CDVDClock::GetAbsoluteClock() - m_State.timestamp;
offset *= m_playSpeed / DVD_PLAYSPEED_NORMAL;
+ offset = DVD_TIME_TO_MSEC(offset);
if(offset > 1000) offset = 1000;
if(offset < -1000) offset = -1000;
}
- return llrint(m_State.time + DVD_TIME_TO_MSEC(offset));
+ return llrint(m_State.time + offset);
}
// return length in msec
@@ -3140,7 +3145,7 @@ bool CDVDPlayer::CloseTeletextStream(bool bWaitForBuffers)
return true;
}
-void CDVDPlayer::FlushBuffers(bool queued, double pts, bool accurate)
+void CDVDPlayer::FlushBuffers(bool queued, double pts, bool accurate, bool sync)
{
double startpts;
if(accurate)
@@ -3152,19 +3157,23 @@ void CDVDPlayer::FlushBuffers(bool queued, double pts, bool accurate)
if(startpts != DVD_NOPTS_VALUE)
startpts -= m_offset_pts;
- m_CurrentAudio.inited = false;
+ if (sync)
+ {
+ m_CurrentAudio.inited = false;
+ m_CurrentVideo.inited = false;
+ m_CurrentSubtitle.inited = false;
+ m_CurrentTeletext.inited = false;
+ }
+
m_CurrentAudio.dts = DVD_NOPTS_VALUE;
m_CurrentAudio.startpts = startpts;
- m_CurrentVideo.inited = false;
m_CurrentVideo.dts = DVD_NOPTS_VALUE;
m_CurrentVideo.startpts = startpts;
- m_CurrentSubtitle.inited = false;
m_CurrentSubtitle.dts = DVD_NOPTS_VALUE;
m_CurrentSubtitle.startpts = startpts;
- m_CurrentTeletext.inited = false;
m_CurrentTeletext.dts = DVD_NOPTS_VALUE;
m_CurrentTeletext.startpts = startpts;
@@ -3208,7 +3217,7 @@ void CDVDPlayer::FlushBuffers(bool queued, double pts, bool accurate)
m_CurrentTeletext.started = false;
}
- if(pts != DVD_NOPTS_VALUE)
+ if(pts != DVD_NOPTS_VALUE && sync)
m_clock.Discontinuity(pts);
UpdatePlayState(0);
}
diff --git a/xbmc/cores/dvdplayer/DVDPlayer.h b/xbmc/cores/dvdplayer/DVDPlayer.h
index d3c201e..70ecea9 100644
--- a/xbmc/cores/dvdplayer/DVDPlayer.h
+++ b/xbmc/cores/dvdplayer/DVDPlayer.h
@@ -310,7 +310,7 @@ class CDVDPlayer : public IPlayer, public CThread, public IDVDPlayer
bool GetCachingTimes(double& play_left, double& cache_left, double& file_offset);
- void FlushBuffers(bool queued, double pts = DVD_NOPTS_VALUE, bool accurate = true);
+ void FlushBuffers(bool queued, double pts = DVD_NOPTS_VALUE, bool accurate = true, bool sync = true);
void HandleMessages();
void HandlePlaySpeed();
@@ -359,8 +359,9 @@ class CDVDPlayer : public IPlayer, public CThread, public IDVDPlayer
int m_playSpeed;
struct SSpeedState
{
- double lastpts; // holds last display pts during ff/rw operations
- double lasttime;
+ double lastpts; // holds last display pts during ff/rw operations
+ int64_t lasttime;
+ double lastabstime;
} m_SpeedState;
int m_errorCount;
diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
index 8b02d81..d26ab9c 100644
--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
@@ -1268,13 +1268,13 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts)
if( m_speed < 0 )
{
- double decoderPts = m_droppingStats.m_lastDecoderPts;
+ double inputPts = m_droppingStats.m_lastPts;
double renderPts = m_droppingStats.m_lastRenderPts;
if (pts > renderPts)
{
- if (decoderPts >= renderPts)
+ if (inputPts >= renderPts)
{
- Sleep(200);
+ Sleep(50);
}
return result | EOS_DROPPED;
}
@@ -1571,7 +1571,7 @@ double CDVDPlayerVideo::GetCurrentPts()
if( m_stalled )
iRenderPts = DVD_NOPTS_VALUE;
- else
+ else if ( m_speed == DVD_PLAYSPEED_NORMAL)
iRenderPts = iRenderPts - max(0.0, iSleepTime);
return iRenderPts;
@@ -1671,6 +1671,8 @@ int CDVDPlayerVideo::CalcDropRequirement(double pts)
int iSkippedDeint = 0;
int iBufferLevel;
+ m_droppingStats.m_lastPts = pts;
+
// get decoder stats
if (!m_pVideoCodec->GetPts(iDecoderPts, iSkippedDeint, interlaced))
iDecoderPts = pts;
diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.h b/xbmc/cores/dvdplayer/DVDPlayerVideo.h
index 509d5f7..7cddda7 100644
--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.h
+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.h
@@ -51,6 +51,7 @@ class CDroppingStats
double m_totalGain;
double m_lastDecoderPts;
double m_lastRenderPts;
+ double m_lastPts;
unsigned int m_lateFrames;
unsigned int m_dropRequests;
bool m_requestOutputDrop;
--
1.7.10
From 024ecda241754f02ad985fab9116e33b06b8d174 Mon Sep 17 00:00:00 2001
From: fritsch <peter.fruehberger@gmail.com>
Date: Fri, 2 Nov 2012 17:56:12 +0100
Subject: [PATCH 54/72] xvba: do not create decoder for surfaces larger than
width 2048 or height 1536
---
xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp
index e8e376a..b73c48a 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp
@@ -335,6 +335,21 @@ bool CDecoder::Open(AVCodecContext* avctx, const enum PixelFormat fmt, unsigned
return false;
}
+ // Fixme: Revisit with new SDK
+ // Workaround for 0.74.01-AES-2 that does not signal if surfaces are too large
+ // it seems that xvba does not support anything > 2k
+ // return false, for files that are larger
+ // if you are unlucky, this would kill your decoder
+ // we limit to 2048x1536(+8) now - as this was tested working
+ int surfaceWidth = (avctx->coded_width+15) & ~15;
+ int surfaceHeight = (avctx->coded_height+15) & ~15;
+ if(surfaceHeight > 1544 || surfaceWidth > 2048)
+ {
+ CLog::Log(LOGERROR, "Surface too large, decoder skipped: surfaceWidth %u, surfaceHeight %u",
+ surfaceWidth, surfaceHeight);
+ return false;
+ }
+
if (!m_dllAvUtil.Load())
return false;
--
1.7.10
From 98ebb0d0232cf4a7ea2082f9f16e210a39e983e8 Mon Sep 17 00:00:00 2001
From: fritsch <peter.fruehberger@gmail.com>
Date: Sun, 4 Nov 2012 16:24:10 +0100
Subject: [PATCH 55/72] xvba: add string for available decoders - we are
important so make sure we are there
---
xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
index 0cea7a9..6fb74b7 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
@@ -169,6 +169,11 @@ CDVDVideoCodec* CDVDFactoryCodec::CreateVideoCodec(CDVDStreamInfo &hint, unsigne
#elif defined(_LINUX) && !defined(TARGET_DARWIN)
hwSupport += "VAAPI:no ";
#endif
+#if defined(HAVE_LIBXVBA) && defined(TARGET_LINUX)
+ hwSupport += "XVBA:yes ";
+#elif defined(TARGET_LINUX)
+ hwSupport += "XVBA:no ";
+#endif
CLog::Log(LOGDEBUG, "CDVDFactoryCodec: compiled in hardware support: %s", hwSupport.c_str());
--
1.7.10
From 84e701f7db6603a2942611d5c74ba645c625ec0d Mon Sep 17 00:00:00 2001
From: fritsch <Peter.Fruehberger@gmail.com>
Date: Thu, 22 Nov 2012 21:32:21 +0100
Subject: [PATCH 56/72] xvba: revisit Artefacts. There are more broken video
files out there
---
lib/ffmpeg/libavcodec/xvba_h264.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/lib/ffmpeg/libavcodec/xvba_h264.c b/lib/ffmpeg/libavcodec/xvba_h264.c
index a077442..87af687 100644
--- a/lib/ffmpeg/libavcodec/xvba_h264.c
+++ b/lib/ffmpeg/libavcodec/xvba_h264.c
@@ -102,10 +102,16 @@ static int end_frame(AVCodecContext *avctx)
pic_descriptor->avc_num_ref_frames = h->sps.ref_frame_count;
pic_descriptor->avc_reserved_8bit = 0;
- /* Set correct level */
- if (pic_descriptor->level == 41) {
+ /* Set a level that can decode stuff in every case without a lookup table
+ xvba seems to have problems only when the number of Reframes goes beyond
+ the max support number of Level4.1@High. So in praxis decoding a Level 3.0
+ file that in deed has level4.1@High specs does not matter. We use this fact
+ and check if the ref_frames stay in the range Level4.1@high can decode if
+ not, we set Level5.1 */
+ if (pic_descriptor->avc_num_ref_frames > 4) {
const unsigned int mbw = pic_descriptor->width_in_mb;
const unsigned int mbh = pic_descriptor->height_in_mb;
+ // this matches Level4.1@High stats to differ between <= 4.1 and 5.1
const unsigned int max_ref_frames = 12288 * 1024 / (mbw * mbh * 384);
const unsigned int num_ref_frames = pic_descriptor->avc_num_ref_frames;
if (max_ref_frames < num_ref_frames)
--
1.7.10
From afd776e3e90a1787ce4c3392266d70368de4e164 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Fri, 23 Nov 2012 09:42:02 +0100
Subject: [PATCH 57/72] xvba: reactivate accidently disabled
IsDecodingFinished
---
xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp | 2 --
1 file changed, 2 deletions(-)
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp
index b73c48a..47ff25f 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp
@@ -1949,8 +1949,6 @@ void COutput::Flush()
bool COutput::IsDecodingFinished()
{
- return true;
-
// check for decoding to be finished
CXvbaDecodedPicture decodedPic = m_decodedPics.front();
--
1.7.10
From 37576c15f9e3a0c2dce593e9d9cb5a7863845de7 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Fri, 23 Nov 2012 17:41:12 +0100
Subject: [PATCH 58/72] 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
From bd5d572c69ee254beedb5e9339831652943ea8b4 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Sun, 2 Dec 2012 15:46:55 +0100
Subject: [PATCH 59/72] X11: add debug log to print out refresh after xrr
event
---
xbmc/windowing/X11/WinSystemX11.cpp | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp
index ef83133..76c6362 100644
--- a/xbmc/windowing/X11/WinSystemX11.cpp
+++ b/xbmc/windowing/X11/WinSystemX11.cpp
@@ -685,6 +685,12 @@ void CWinSystemX11::NotifyXRREvent()
XOutput *out = g_xrandr.GetOutput(currentOutput);
XMode mode = g_xrandr.GetCurrentMode(currentOutput);
+ if (out)
+ CLog::Log(LOGDEBUG, "%s - current output: %s, mode: %s, refresh: %.3f", __FUNCTION__
+ , out->name.c_str(), mode.id.c_str(), mode.hz);
+ else
+ CLog::Log(LOGWARNING, "%s - output name not set", __FUNCTION__);
+
RESOLUTION_INFO res;
unsigned int i;
bool found(false);
--
1.7.10
From d418ae1053a3842eb3e6a3bbd84666a5ee3defe2 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Tue, 11 Dec 2012 11:08:13 +0100
Subject: [PATCH 60/72] X11: dont call XCloseDisplay on shutdown, it crashes
when powered doen by cec on ATI
---
xbmc/windowing/X11/WinSystemX11.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp
index 76c6362..e4e25b2 100644
--- a/xbmc/windowing/X11/WinSystemX11.cpp
+++ b/xbmc/windowing/X11/WinSystemX11.cpp
@@ -108,7 +108,8 @@ bool CWinSystemX11::DestroyWindowSystem()
//we don't call XCloseDisplay() here, since ati keeps a pointer to our m_dpy
//so instead we just let m_dpy die on exit
// i have seen core dumps on ATI if the display is not closed here
- XCloseDisplay(m_dpy);
+ // crashes when shutting down via cec
+// XCloseDisplay(m_dpy);
}
// m_SDLSurface is free()'d by SDL_Quit().
--
1.7.10
From 3b700401e9aace50b5ce6c5d7ba2a2e33bb5217f Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Wed, 12 Dec 2012 09:52:17 +0100
Subject: [PATCH 61/72] vdpau: make interop gl default and remove setting,
rename and intvert interop yuv
---
language/English/strings.po | 2 +-
xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 17 ++++++++++-------
xbmc/settings/GUISettings.cpp | 3 +--
xbmc/settings/GUIWindowSettingsCategory.cpp | 23 +++--------------------
4 files changed, 15 insertions(+), 30 deletions(-)
diff --git a/language/English/strings.po b/language/English/strings.po
index ede18b3..281a8a1 100644
--- a/language/English/strings.po
+++ b/language/English/strings.po
@@ -5121,7 +5121,7 @@ msgid "Allow Vdpau OpenGL interop"
msgstr ""
msgctxt "#13436"
-msgid "Allow Vdpau OpenGL interop YUV"
+msgid "Prefer VDPAU Video Mixer"
msgstr ""
msgctxt "#13437"
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp
index fec4b88..ad140fb 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp
@@ -365,12 +365,15 @@ bool CDecoder::Supports(EINTERLACEMETHOD method)
|| method == VS_INTERLACEMETHOD_AUTO)
return true;
- if (g_guiSettings.GetBool("videoplayer.usevdpauinteropyuv"))
+ if (!m_vdpauConfig.usePixmaps)
{
if (method == VS_INTERLACEMETHOD_RENDER_BOB)
return true;
}
+ if (method == VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE)
+ return false;
+
for(SInterlaceMapping* p = g_interlace_mapping; p->method != VS_INTERLACEMETHOD_NONE; p++)
{
if(p->method == method)
@@ -1847,7 +1850,7 @@ void CMixer::SetDeinterlacing()
SetDeintSkipChroma();
- m_config.useInteropYuv = g_guiSettings.GetBool("videoplayer.usevdpauinteropyuv");
+ m_config.useInteropYuv = !g_guiSettings.GetBool("videoplayer.usevdpaumixer");
}
void CMixer::SetDeintSkipChroma()
@@ -2039,7 +2042,7 @@ void CMixer::Init()
m_vdpError = false;
m_config.upscale = g_advancedSettings.m_videoVDPAUScaling;
- m_config.useInteropYuv = g_guiSettings.GetBool("videoplayer.usevdpauinteropyuv");
+ m_config.useInteropYuv = !g_guiSettings.GetBool("videoplayer.usevdpaumixer");
CreateVdpauMixer();
}
@@ -2149,11 +2152,12 @@ void CMixer::InitCycle()
DVP_FLAG_INTERLACED);
m_config.useInteropYuv = false;
}
- else if (method == VS_INTERLACEMETHOD_RENDER_BOB && m_config.useInteropYuv)
+ else if (method == VS_INTERLACEMETHOD_RENDER_BOB)
{
m_mixersteps = 1;
m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU_420;
+ m_config.useInteropYuv = true;
}
else
{
@@ -3185,7 +3189,7 @@ bool COutput::GLInit()
glVDPAUGetSurfaceivNV = NULL;
#endif
- m_config.usePixmaps = !g_guiSettings.GetBool("videoplayer.usevdpauinterop");
+ m_config.usePixmaps = false;
#ifdef GL_NV_vdpau_interop
if (glewIsSupported("GL_NV_vdpau_interop"))
@@ -3217,8 +3221,7 @@ bool COutput::GLInit()
#endif
{
m_config.usePixmaps = true;
- g_guiSettings.SetBool("videoplayer.usevdpauinterop",false);
- g_guiSettings.SetBool("videoplayer.usevdpauinteropyuv",false);
+ g_guiSettings.SetBool("videoplayer.usevdpaumixer",true);
}
if (!glXBindTexImageEXT)
glXBindTexImageEXT = (PFNGLXBINDTEXIMAGEEXTPROC)glXGetProcAddress((GLubyte *) "glXBindTexImageEXT");
diff --git a/xbmc/settings/GUISettings.cpp b/xbmc/settings/GUISettings.cpp
index 10ef779..a4bd524 100644
--- a/xbmc/settings/GUISettings.cpp
+++ b/xbmc/settings/GUISettings.cpp
@@ -690,8 +690,7 @@ void CGUISettings::Initialize()
#ifdef HAVE_LIBVDPAU
AddBool(vp, "videoplayer.usevdpau", 13425, true);
- AddBool(vp, "videoplayer.usevdpauinterop", 13435, true);
- AddBool(vp, "videoplayer.usevdpauinteropyuv", 13436, false);
+ AddBool(vp, "videoplayer.usevdpaumixer", 13436, true);
#endif
#ifdef HAVE_LIBVA
AddBool(vp, "videoplayer.usevaapi", 13426, true);
diff --git a/xbmc/settings/GUIWindowSettingsCategory.cpp b/xbmc/settings/GUIWindowSettingsCategory.cpp
index 3c19a06..b9f18e4 100644
--- a/xbmc/settings/GUIWindowSettingsCategory.cpp
+++ b/xbmc/settings/GUIWindowSettingsCategory.cpp
@@ -602,9 +602,9 @@ void CGUIWindowSettingsCategory::UpdateSettings()
pControl->SetEnabled(true);
}
}
- else if (strSetting.Equals("videoplayer.usevdpauinteropyuv"))
+ else if (strSetting.Equals("videoplayer.usevdpaumixer"))
{
- bool hasInterop = g_guiSettings.GetBool("videoplayer.usevdpauinterop");
+ bool hasInterop = true;
#ifndef GL_NV_vdpau_interop
hasInterop = false;
#endif
@@ -616,24 +616,7 @@ void CGUIWindowSettingsCategory::UpdateSettings()
else
{
pControl->SetEnabled(false);
- g_guiSettings.SetBool("videoplayer.usevdpauinteropyuv",false);
- }
- }
- else if (strSetting.Equals("videoplayer.usevdpauinterop"))
- {
- bool hasInterop = g_guiSettings.GetBool("videoplayer.usevdpau");
-#ifndef GL_NV_vdpau_interop
- hasInterop = false;
-#endif
- CGUIControl *pControl = (CGUIControl *)GetControl(pSettingControl->GetID());
- if (pControl && hasInterop && glewIsSupported("GL_NV_vdpau_interop"))
- {
- pControl->SetEnabled(true);
- }
- else
- {
- pControl->SetEnabled(false);
- g_guiSettings.SetBool("videoplayer.usevdpauinterop",false);
+ g_guiSettings.SetBool("videoplayer.usevdpaumixer",true);
}
}
else
--
1.7.10
From a060312a4e236858bf3c9a97d663c5643796b649 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Wed, 12 Dec 2012 18:34:47 +0100
Subject: [PATCH 62/72] vdpau: drop studio level conversion
---
language/English/strings.po | 6 +-
xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 4 +-
xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 94 +-----------------------
xbmc/settings/GUISettings.cpp | 1 -
4 files changed, 7 insertions(+), 98 deletions(-)
diff --git a/language/English/strings.po b/language/English/strings.po
index 281a8a1..fc896b3 100644
--- a/language/English/strings.po
+++ b/language/English/strings.po
@@ -4371,11 +4371,7 @@ msgctxt "#13121"
msgid "VDPAU HQ Upscaling level"
msgstr ""
-msgctxt "#13122"
-msgid "VDPAU Studio level color conversion"
-msgstr ""
-
-#empty strings from id 13123 to 13129
+#empty strings from id 13122 to 13129
msgctxt "#13130"
msgid "Blank other displays"
diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
index 7c3adcb..0bb924b 100644
--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
@@ -3545,7 +3545,7 @@ bool CLinuxRendererGL::Supports(ERENDERFEATURE feature)
{
if(feature == RENDERFEATURE_BRIGHTNESS)
{
- if ((m_renderMethod & RENDER_VDPAU) && !g_guiSettings.GetBool("videoplayer.vdpaustudiolevel"))
+ if (m_renderMethod & RENDER_VDPAU)
return true;
if (m_renderMethod & RENDER_VAAPI)
@@ -3561,7 +3561,7 @@ bool CLinuxRendererGL::Supports(ERENDERFEATURE feature)
if(feature == RENDERFEATURE_CONTRAST)
{
- if ((m_renderMethod & RENDER_VDPAU) && !g_guiSettings.GetBool("videoplayer.vdpaustudiolevel"))
+ if (m_renderMethod & RENDER_VDPAU)
return true;
if (m_renderMethod & RENDER_VAAPI)
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp
index ad140fb..5851e1a 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp
@@ -57,15 +57,6 @@
};
const size_t decoder_profile_count = sizeof(decoder_profiles)/sizeof(CDecoder::Desc);
-//static float studioCSC[3][4] =
-//{
-// { 1.0f, 0.0f, 1.57480000f,-0.78740000f},
-// { 1.0f,-0.18737736f,-0.46813736f, 0.32775736f},
-// { 1.0f, 1.85556000f, 0.0f,-0.92780000f}
-//};
-static float studioCSCKCoeffs601[3] = {0.299, 0.587, 0.114}; //BT601 {Kr, Kg, Kb}
-static float studioCSCKCoeffs709[3] = {0.2126, 0.7152, 0.0722}; //BT709 {Kr, Kg, Kb}
-
static struct SInterlaceMapping
{
const EINTERLACEMETHOD method;
@@ -1614,74 +1605,6 @@ void CMixer::PostProcOff()
DisableHQScaling();
}
-
-bool CMixer::GenerateStudioCSCMatrix(VdpColorStandard colorStandard, VdpCSCMatrix &studioCSCMatrix)
-{
- // instead use studioCSCKCoeffs601[3], studioCSCKCoeffs709[3] to generate float[3][4] matrix (float studioCSC[3][4])
- // m00 = mRY = red: luma factor (contrast factor) (1.0)
- // m10 = mGY = green: luma factor (contrast factor) (1.0)
- // m20 = mBY = blue: luma factor (contrast factor) (1.0)
- //
- // m01 = mRB = red: blue color diff coeff (0.0)
- // m11 = mGB = green: blue color diff coeff (-2Kb(1-Kb)/(Kg))
- // m21 = mBB = blue: blue color diff coeff ((1-Kb)/0.5)
- //
- // m02 = mRR = red: red color diff coeff ((1-Kr)/0.5)
- // m12 = mGR = green: red color diff coeff (-2Kr(1-Kr)/(Kg))
- // m22 = mBR = blue: red color diff coeff (0.0)
- //
- // m03 = mRC = red: colour zero offset (brightness factor) (-(1-Kr)/0.5 * (128/255))
- // m13 = mGC = green: colour zero offset (brightness factor) ((256/255) * (Kb(1-Kb) + Kr(1-Kr)) / Kg)
- // m23 = mBC = blue: colour zero offset (brightness factor) (-(1-Kb)/0.5 * (128/255))
-
- // columns
- int Y = 0;
- int Cb = 1;
- int Cr = 2;
- int C = 3;
- // rows
- int R = 0;
- int G = 1;
- int B = 2;
- // colour standard coefficients for red, geen, blue
- double Kr, Kg, Kb;
- // colour diff zero position (use standard 8-bit coding precision)
- double CDZ = 128; //256*0.5
- // range excursion (use standard 8-bit coding precision)
- double EXC = 255; //256-1
-
- if (colorStandard == VDP_COLOR_STANDARD_ITUR_BT_601)
- {
- Kr = studioCSCKCoeffs601[0];
- Kg = studioCSCKCoeffs601[1];
- Kb = studioCSCKCoeffs601[2];
- }
- else // assume VDP_COLOR_STANDARD_ITUR_BT_709
- {
- Kr = studioCSCKCoeffs709[0];
- Kg = studioCSCKCoeffs709[1];
- Kb = studioCSCKCoeffs709[2];
- }
- // we keep luma unscaled to retain the levels present in source so that 16-235 luma is converted to RGB 16-235
- studioCSCMatrix[R][Y] = 1.0;
- studioCSCMatrix[G][Y] = 1.0;
- studioCSCMatrix[B][Y] = 1.0;
-
- studioCSCMatrix[R][Cb] = 0.0;
- studioCSCMatrix[G][Cb] = (double)-2 * Kb * (1 - Kb) / Kg;
- studioCSCMatrix[B][Cb] = (double)(1 - Kb) / 0.5;
-
- studioCSCMatrix[R][Cr] = (double)(1 - Kr) / 0.5;
- studioCSCMatrix[G][Cr] = (double)-2 * Kr * (1 - Kr) / Kg;
- studioCSCMatrix[B][Cr] = 0.0;
-
- studioCSCMatrix[R][C] = (double)-1 * studioCSCMatrix[R][Cr] * CDZ/EXC;
- studioCSCMatrix[G][C] = (double)-1 * (studioCSCMatrix[G][Cb] + studioCSCMatrix[G][Cr]) * CDZ/EXC;
- studioCSCMatrix[B][C] = (double)-1 * studioCSCMatrix[B][Cb] * CDZ/EXC;
-
- return true;
-}
-
void CMixer::SetColor()
{
VdpStatus vdp_st;
@@ -1701,19 +1624,10 @@ void CMixer::SetColor()
//vdp_st = vdp_generate_csc_matrix(&m_Procamp, VDP_COLOR_STANDARD_ITUR_BT_601, &m_CSCMatrix);
VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX };
- if (g_guiSettings.GetBool("videoplayer.vdpaustudiolevel"))
- {
- float studioCSC[3][4];
- GenerateStudioCSCMatrix(colorStandard, studioCSC);
- void const * pm_CSCMatix[] = { &studioCSC };
- vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix);
- }
- else
- {
- vdp_st = m_config.vdpProcs.vdp_generate_csc_matrix(&m_Procamp, colorStandard, &m_CSCMatrix);
- void const * pm_CSCMatix[] = { &m_CSCMatrix };
- vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix);
- }
+ vdp_st = m_config.vdpProcs.vdp_generate_csc_matrix(&m_Procamp, colorStandard, &m_CSCMatrix);
+ void const * pm_CSCMatix[] = { &m_CSCMatrix };
+ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix);
+
CheckStatus(vdp_st, __LINE__);
}
diff --git a/xbmc/settings/GUISettings.cpp b/xbmc/settings/GUISettings.cpp
index a4bd524..67aeec9 100644
--- a/xbmc/settings/GUISettings.cpp
+++ b/xbmc/settings/GUISettings.cpp
@@ -772,7 +772,6 @@ void CGUISettings::Initialize()
AddSeparator(vp, "videoplayer.sep1.5");
#ifdef HAVE_LIBVDPAU
AddBool(NULL, "videoplayer.vdpauUpscalingLevel", 13121, false);
- AddBool(vp, "videoplayer.vdpaustudiolevel", 13122, false);
#endif
#endif
AddSeparator(vp, "videoplayer.sep5");
--
1.7.10
From 6d03704ce1cbc7d09d684da1ced478b2b59c0b35 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Gr=C3=A9gory=20Coutant?= <gregory.coutant@gmail.com>
Date: Wed, 12 Dec 2012 19:49:47 +0100
Subject: [PATCH 63/72] x11: support for multiple x screens
---
xbmc/windowing/X11/XRandR.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/xbmc/windowing/X11/XRandR.cpp b/xbmc/windowing/X11/XRandR.cpp
index 533e03d..7a16488 100644
--- a/xbmc/windowing/X11/XRandR.cpp
+++ b/xbmc/windowing/X11/XRandR.cpp
@@ -92,7 +92,7 @@ bool CXRandR::Query(bool force, int screennum)
pclose(file);
TiXmlElement *pRootElement = xmlDoc.RootElement();
- if (strcasecmp(pRootElement->Value(), "screen") != screennum)
+ if (atoi(pRootElement->Attribute("id")) != screennum)
{
// TODO ERROR
return false;
--
1.7.10
From 597c8449084e1e5ebfebfb31db570f7826d06517 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Wed, 12 Dec 2012 20:28:49 +0100
Subject: [PATCH 64/72] vdpau: observe ffmpeg tags for color space
---
xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 38 ++++++++++++++++--------
xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h | 1 +
2 files changed, 27 insertions(+), 12 deletions(-)
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp
index 5851e1a..8858614 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp
@@ -907,6 +907,7 @@ int CDecoder::Decode(AVCodecContext *avctx, AVFrame *pFrame)
memset(&pic.DVDPic, 0, sizeof(pic.DVDPic));
((CDVDVideoCodecFFmpeg*)avctx->opaque)->GetPictureCommon(&pic.DVDPic);
pic.render = render;
+ pic.DVDPic.color_matrix = avctx->colorspace;
m_bufferStats.IncDecoded();
m_vdpauOutput.m_dataPort.SendOutMessage(COutputDataProtocol::NEWFRAME, &pic, sizeof(pic));
@@ -1513,10 +1514,6 @@ void CMixer::InitCSCMatrix(int Width)
m_Procamp.contrast = 1.0;
m_Procamp.saturation = 1.0;
m_Procamp.hue = 0;
- vdp_st = m_config.vdpProcs.vdp_generate_csc_matrix(&m_Procamp,
- (Width < 1000)? VDP_COLOR_STANDARD_ITUR_BT_601 : VDP_COLOR_STANDARD_ITUR_BT_709,
- &m_CSCMatrix);
- CheckStatus(vdp_st, __LINE__);
}
void CMixer::CheckFeatures()
@@ -1527,11 +1524,13 @@ void CMixer::CheckFeatures()
m_Upscale = m_config.upscale;
}
if (m_Brightness != g_settings.m_currentVideoSettings.m_Brightness ||
- m_Contrast != g_settings.m_currentVideoSettings.m_Contrast)
+ m_Contrast != g_settings.m_currentVideoSettings.m_Contrast ||
+ m_ColorMatrix != m_mixerInput[1].DVDPic.color_matrix)
{
SetColor();
m_Brightness = g_settings.m_currentVideoSettings.m_Brightness;
m_Contrast = g_settings.m_currentVideoSettings.m_Contrast;
+ m_ColorMatrix = m_mixerInput[1].DVDPic.color_matrix;
}
if (m_NoiseReduction != g_settings.m_currentVideoSettings.m_NoiseReduction)
{
@@ -1615,13 +1614,27 @@ void CMixer::SetColor()
m_Procamp.contrast = (float)((g_settings.m_currentVideoSettings.m_Contrast)+50) / 100;
VdpColorStandard colorStandard;
-// if(vid_height >= 600 || vid_width > 1024)
- if(m_config.surfaceWidth > 1000)
- colorStandard = VDP_COLOR_STANDARD_ITUR_BT_709;
- //vdp_st = vdp_generate_csc_matrix(&m_Procamp, VDP_COLOR_STANDARD_ITUR_BT_709, &m_CSCMatrix);
- else
- colorStandard = VDP_COLOR_STANDARD_ITUR_BT_601;
- //vdp_st = vdp_generate_csc_matrix(&m_Procamp, VDP_COLOR_STANDARD_ITUR_BT_601, &m_CSCMatrix);
+ switch(m_mixerInput[1].DVDPic.color_matrix)
+ {
+ case AVCOL_SPC_BT709:
+ colorStandard = VDP_COLOR_STANDARD_ITUR_BT_709;
+ break;
+ case AVCOL_SPC_BT470BG:
+ case AVCOL_SPC_SMPTE170M:
+ colorStandard = VDP_COLOR_STANDARD_ITUR_BT_601;
+ break;
+ case AVCOL_SPC_SMPTE240M:
+ colorStandard = VDP_COLOR_STANDARD_SMPTE_240M;
+ break;
+ case AVCOL_SPC_FCC:
+ case AVCOL_SPC_UNSPECIFIED:
+ case AVCOL_SPC_RGB:
+ default:
+ if(m_config.surfaceWidth > 1000)
+ colorStandard = VDP_COLOR_STANDARD_ITUR_BT_709;
+ else
+ colorStandard = VDP_COLOR_STANDARD_ITUR_BT_601;
+ }
VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX };
vdp_st = m_config.vdpProcs.vdp_generate_csc_matrix(&m_Procamp, colorStandard, &m_CSCMatrix);
@@ -1952,6 +1965,7 @@ void CMixer::Init()
m_Sharpness = 0.0;
m_DeintMode = 0;
m_Deint = 0;
+ m_ColorMatrix = 0;
m_PostProc = false;
m_vdpError = false;
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h
index 4d1559c..471ad68 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h
@@ -334,6 +334,7 @@ class CMixer : private CThread
int m_DeintMode;
int m_Deint;
int m_Upscale;
+ unsigned int m_ColorMatrix : 4;
uint32_t *m_BlackBar;
VdpVideoMixerPictureStructure m_mixerfield;
int m_mixerstep;
--
1.7.10
From 3f9308d76025ef1e31923fa9a06587f75c00f870 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Thu, 20 Dec 2012 19:35:38 +0100
Subject: [PATCH 65/72] fix compile error after recent change
---
xbmc/settings/GUIWindowSettingsCategory.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/xbmc/settings/GUIWindowSettingsCategory.cpp b/xbmc/settings/GUIWindowSettingsCategory.cpp
index b9f18e4..cacb32a 100644
--- a/xbmc/settings/GUIWindowSettingsCategory.cpp
+++ b/xbmc/settings/GUIWindowSettingsCategory.cpp
@@ -2453,7 +2453,7 @@ void CGUIWindowSettingsCategory::FillInMonitors(CStdString strSetting)
{
// we expect "videoscreen.monitor" but it might be hidden on some platforms,
// so check that we actually have a visable control.
- CBaseSettingControl *control = GetSetting(strSetting);
+ BaseSettingControlPtr control = GetSetting(strSetting);
if (control)
{
control->SetDelayed();
--
1.7.10
From 213792b2678760d42740d581a1ee71e186a31c4d Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Mon, 24 Dec 2012 16:02:42 +0100
Subject: [PATCH 66/72] pvr: increase changes counter of stream on stream
change, cosmetics after
dd307930d39d92f145a01a16600cd00e01ec39be
---
xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp
index 8c984f6..034e545 100644
--- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp
@@ -348,9 +348,7 @@ void CDVDDemuxPVRClient::RequestStreams()
if (stm)
{
st = dynamic_cast<CDemuxStreamAudioPVRClient*>(stm);
- if (!st
- || (st->codec != (CodecID)props.stream[i].iCodecId)
- || (st->iChannels != props.stream[i].iChannels))
+ if (!st || (st->codec != (CodecID)props.stream[i].iCodecId))
DisposeStream(i);
}
if (!m_streams[i])
@@ -367,6 +365,7 @@ void CDVDDemuxPVRClient::RequestStreams()
st->iBitsPerSample = props.stream[i].iBitsPerSample;
m_streams[i] = st;
st->m_parser_split = true;
+ st->changes++;
}
else if (props.stream[i].iCodecType == AVMEDIA_TYPE_VIDEO)
{
--
1.7.10
From e810d3bd68e89e800fba217e88184c2df0fe4040 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Thu, 17 Jan 2013 16:03:22 +0100
Subject: [PATCH 67/72] X11: add keymapping for XF86XK_Sleep
---
xbmc/windowing/WinEventsX11.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp
index c31877e..ed31c04 100644
--- a/xbmc/windowing/WinEventsX11.cpp
+++ b/xbmc/windowing/WinEventsX11.cpp
@@ -143,6 +143,7 @@
, {XK_Break, XBMCK_BREAK}
, {XK_Menu, XBMCK_MENU}
, {XF86XK_PowerOff, XBMCK_POWER}
+, {XF86XK_Sleep, XBMCK_SLEEP}
, {XK_EcuSign, XBMCK_EURO}
, {XK_Undo, XBMCK_UNDO}
/* Media keys */
--
1.7.10
From 2cb807b2f801f06723cde1bdd636550c08fc08ab Mon Sep 17 00:00:00 2001
From: fritsch <peter.fruehberger@gmail.com>
Date: Sat, 12 Jan 2013 13:03:50 +0100
Subject: [PATCH 68/72] dvdplayer: Allow multithread decoding for hi10p
content by default
This allows decoding of some hi10p material on e.g. AMD Fusion with
both cores at the max. This introduces a new advancedsetting named
disablehi10pmultithreading to disable hi10p decoded multithreaded.
---
.../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 18 ++++++++++++++++--
.../dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h | 1 +
xbmc/settings/AdvancedSettings.cpp | 2 ++
xbmc/settings/AdvancedSettings.h | 1 +
4 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
index b3252ec..3f8a6e8 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
@@ -154,6 +154,7 @@ enum PixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx
m_iScreenHeight = 0;
m_iOrientation = 0;
m_bSoftware = false;
+ m_isHi10p = false;
m_pHardware = NULL;
m_iLastKeyframe = 0;
m_dts = DVD_NOPTS_VALUE;
@@ -204,7 +205,10 @@ bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options
case FF_PROFILE_H264_HIGH_444_PREDICTIVE:
case FF_PROFILE_H264_HIGH_444_INTRA:
case FF_PROFILE_H264_CAVLC_444:
+ // this is needed to not open the decoders
m_bSoftware = true;
+ // this we need to enable multithreading for hi10p via advancedsettings
+ m_isHi10p = true;
break;
}
}
@@ -277,8 +281,18 @@ bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options
m_pCodecContext->codec_tag = hints.codec_tag;
/* Only allow slice threading, since frame threading is more
* sensitive to changes in frame sizes, and it causes crashes
- * during HW accell */
- m_pCodecContext->thread_type = FF_THREAD_SLICE;
+ * during HW accell - so we unset it in this case.
+ *
+ * When we detect Hi10p and user did not disable hi10pmultithreading
+ * via advancedsettings.xml we keep the ffmpeg default thread type.
+ * */
+ if(m_isHi10p && !g_advancedSettings.m_videoDisableHi10pMultithreading)
+ {
+ CLog::Log(LOGDEBUG,"CDVDVideoCodecFFmpeg::Open() Keep default threading for Hi10p: %d",
+ m_pCodecContext->thread_type);
+ }
+ else
+ m_pCodecContext->thread_type = FF_THREAD_SLICE;
#if defined(TARGET_DARWIN_IOS)
// ffmpeg with enabled neon will crash and burn if this is enabled
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h
index bf4367c..db1d2b2 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h
@@ -116,6 +116,7 @@ class CDVDVideoCodecFFmpeg : public CDVDVideoCodec
std::string m_name;
bool m_bSoftware;
+ bool m_isHi10p;
IHardwareDecoder *m_pHardware;
int m_iLastKeyframe;
double m_dts;
diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp
index d913924..6a48309 100644
--- a/xbmc/settings/AdvancedSettings.cpp
+++ b/xbmc/settings/AdvancedSettings.cpp
@@ -116,6 +116,7 @@ void CAdvancedSettings::Initialize()
m_DXVANoDeintProcForProgressive = false;
m_videoFpsDetect = 1;
m_videoDefaultLatency = 0.0;
+ m_videoDisableHi10pMultithreading = false;
m_musicUseTimeSeeking = true;
m_musicTimeSeekForward = 10;
@@ -502,6 +503,7 @@ void CAdvancedSettings::ParseSettingsFile(const CStdString &file)
XMLUtils::GetBoolean(pElement,"enablehighqualityhwscalers", m_videoEnableHighQualityHwScalers);
XMLUtils::GetFloat(pElement,"autoscalemaxfps",m_videoAutoScaleMaxFps, 0.0f, 1000.0f);
XMLUtils::GetBoolean(pElement,"allowmpeg4vdpau",m_videoAllowMpeg4VDPAU);
+ XMLUtils::GetBoolean(pElement,"disablehi10pmultithreading",m_videoDisableHi10pMultithreading);
XMLUtils::GetBoolean(pElement,"allowmpeg4vaapi",m_videoAllowMpeg4VAAPI);
XMLUtils::GetBoolean(pElement, "disablebackgrounddeinterlace", m_videoDisableBackgroundDeinterlace);
XMLUtils::GetInt(pElement, "useocclusionquery", m_videoCaptureUseOcclusionQuery, -1, 1);
diff --git a/xbmc/settings/AdvancedSettings.h b/xbmc/settings/AdvancedSettings.h
index aaa4702..863e4f3 100644
--- a/xbmc/settings/AdvancedSettings.h
+++ b/xbmc/settings/AdvancedSettings.h
@@ -168,6 +168,7 @@ class CAdvancedSettings
bool m_DXVAForceProcessorRenderer;
bool m_DXVANoDeintProcForProgressive;
int m_videoFpsDetect;
+ bool m_videoDisableHi10pMultithreading;
CStdString m_videoDefaultPlayer;
CStdString m_videoDefaultDVDPlayer;
--
1.7.10
From 5e52fa15742e1300ac394738ead4ca2792c4812c Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Mon, 21 Jan 2013 09:00:19 +0100
Subject: [PATCH 69/72] X11: remove toggle full screen after resume
---
xbmc/powermanagement/PowerManager.cpp | 5 -----
1 file changed, 5 deletions(-)
diff --git a/xbmc/powermanagement/PowerManager.cpp b/xbmc/powermanagement/PowerManager.cpp
index a5534c9..7e2ddc6 100644
--- a/xbmc/powermanagement/PowerManager.cpp
+++ b/xbmc/powermanagement/PowerManager.cpp
@@ -223,11 +223,6 @@ void CPowerManager::OnWake()
#if defined(_WIN32)
ShowWindow(g_hWnd,SW_RESTORE);
SetForegroundWindow(g_hWnd);
-#elif !defined(TARGET_DARWIN_OSX)
- // Hack to reclaim focus, thus rehiding system mouse pointer.
- // Surely there's a better way?
- g_graphicsContext.ToggleFullScreenRoot();
- g_graphicsContext.ToggleFullScreenRoot();
#endif
}
g_application.ResetScreenSaver();
--
1.7.10
From e8f3e20dfb3bde4434e2aea69b34e22ba1859a31 Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Wed, 23 Jan 2013 17:03:02 +0100
Subject: [PATCH 70/72] xrandr: set screen on mode change command
---
xbmc/windowing/X11/XRandR.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/xbmc/windowing/X11/XRandR.cpp b/xbmc/windowing/X11/XRandR.cpp
index 7a16488..6531ba3 100644
--- a/xbmc/windowing/X11/XRandR.cpp
+++ b/xbmc/windowing/X11/XRandR.cpp
@@ -246,7 +246,7 @@ bool CXRandR::SetMode(XOutput output, XMode mode)
m_currentMode = modeFound.id;
char cmd[255];
if (getenv("XBMC_BIN_HOME"))
- snprintf(cmd, sizeof(cmd), "%s/xbmc-xrandr --output %s --mode %s", getenv("XBMC_BIN_HOME"), outputFound.name.c_str(), modeFound.id.c_str());
+ snprintf(cmd, sizeof(cmd), "%s/xbmc-xrandr --screen %d --output %s --mode %s", getenv("XBMC_BIN_HOME"), outputFound.screen, outputFound.name.c_str(), modeFound.id.c_str());
else
return false;
CLog::Log(LOGINFO, "XRANDR: %s", cmd);
--
1.7.10
From f229dba603070e1f0528d395c9d5d63f9044ae6e Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Wed, 23 Jan 2013 17:03:39 +0100
Subject: [PATCH 71/72] X11: recreate glx context when output changes
---
xbmc/windowing/X11/WinSystemX11.cpp | 6 +++---
xbmc/windowing/X11/WinSystemX11.h | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp
index e4e25b2..b87e264 100644
--- a/xbmc/windowing/X11/WinSystemX11.cpp
+++ b/xbmc/windowing/X11/WinSystemX11.cpp
@@ -409,11 +409,11 @@ bool CWinSystemX11::IsSuitableVisual(XVisualInfo *vInfo)
return true;
}
-bool CWinSystemX11::RefreshGlxContext()
+bool CWinSystemX11::RefreshGlxContext(bool force)
{
bool retVal = false;
- if (m_glContext)
+ if (m_glContext && !force)
{
CLog::Log(LOGDEBUG, "CWinSystemX11::RefreshGlxContext: refreshing context");
glXMakeCurrent(m_dpy, None, NULL);
@@ -930,7 +930,7 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd
}
CDirtyRegionList dr;
- RefreshGlxContext();
+ RefreshGlxContext(!m_currentOutput.Equals(output));
XSync(m_dpy, FALSE);
g_graphicsContext.Clear(0);
g_graphicsContext.Flip(dr);
diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h
index 0b7c10a..33b1739 100644
--- a/xbmc/windowing/X11/WinSystemX11.h
+++ b/xbmc/windowing/X11/WinSystemX11.h
@@ -74,7 +74,7 @@ class CWinSystemX11 : public CWinSystemBase
void NotifyMouseCoverage(bool covered);
protected:
- bool RefreshGlxContext();
+ bool RefreshGlxContext(bool force);
void CheckDisplayEvents();
void OnLostDevice();
bool SetWindow(int width, int height, bool fullscreen, const CStdString &output);
--
1.7.10
From ae08a23a2f4fd78139e2ebca8a4a87ab619feb0b Mon Sep 17 00:00:00 2001
From: xbmc <fernetmenta@online.de>
Date: Sun, 27 Jan 2013 12:10:19 +0100
Subject: [PATCH 72/72] vdpau: switch off de-interlacing on ff
---
xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp
index 8858614..3e21d9d 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp
@@ -2043,8 +2043,9 @@ void CMixer::InitCycle()
EINTERLACEMETHOD method = GetDeinterlacingMethod();
bool interlaced = m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_INTERLACED;
- if (mode == VS_DEINTERLACEMODE_FORCE ||
- (mode == VS_DEINTERLACEMODE_AUTO && interlaced))
+ if (!(flags & DVP_FLAG_NO_POSTPROC) &&
+ (mode == VS_DEINTERLACEMODE_FORCE ||
+ (mode == VS_DEINTERLACEMODE_AUTO && interlaced)))
{
if((method == VS_INTERLACEMETHOD_AUTO && interlaced)
|| method == VS_INTERLACEMETHOD_VDPAU_BOB
--
1.7.10