aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCrystalP <CrystalP@xbmc.org>2011-02-06 21:16:15 -0500
committerCrystalP <CrystalP@xbmc.org>2011-02-06 21:16:15 -0500
commited71ae3bcd60088623ce8adb12be1507606f9c43 (patch)
tree05090a375aa888efc3d13c680aacccc205f672fa
parent6e2c48f4f4677ed7ae22aa2a8b0edaade9a80fee (diff)
parent40bdfa138fc76cd30f4eb7ba0a66da6493412252 (diff)
Merge Windows renderer support for the NV12 and UVYV formats used natively by the CrystalHD cards.
-rw-r--r--system/shaders/yuv2rgb_d3d.fx54
-rw-r--r--xbmc/cores/VideoRenderers/VideoShaders/WinVideoFilter.cpp95
-rw-r--r--xbmc/cores/VideoRenderers/VideoShaders/WinVideoFilter.h5
-rw-r--r--xbmc/cores/VideoRenderers/WinRenderer.cpp142
-rw-r--r--xbmc/cores/VideoRenderers/WinRenderer.h15
-rw-r--r--xbmc/guilib/D3DResource.h4
6 files changed, 244 insertions, 71 deletions
diff --git a/system/shaders/yuv2rgb_d3d.fx b/system/shaders/yuv2rgb_d3d.fx
index 833bbadd43..610e12bd92 100644
--- a/system/shaders/yuv2rgb_d3d.fx
+++ b/system/shaders/yuv2rgb_d3d.fx
@@ -23,10 +23,7 @@ texture g_YTexture;
texture g_UTexture;
texture g_VTexture;
float4x4 g_ColorMatrix;
-
-#ifdef SINGLEPASS
-
-// Color conversion + bilinear resize in one pass
+float2 g_StepXY;
sampler YSampler =
sampler_state {
@@ -37,21 +34,6 @@ sampler YSampler =
MagFilter = LINEAR;
};
-#else
-
-// Color conversion only
-
-sampler YSampler =
- sampler_state {
- Texture = <g_YTexture>;
- AddressU = CLAMP;
- AddressV = CLAMP;
- MinFilter = POINT;
- MagFilter = POINT;
- };
-
-#endif
-
sampler USampler =
sampler_state {
Texture = <g_UTexture>;
@@ -87,10 +69,44 @@ struct PS_OUTPUT
PS_OUTPUT YUV2RGB( VS_OUTPUT In)
{
PS_OUTPUT OUT;
+#if defined(XBMC_YV12)
float4 YUV = float4(tex2D (YSampler, In.TextureY).x
, tex2D (USampler, In.TextureU).x
, tex2D (VSampler, In.TextureV).x
, 1.0);
+#elif defined(XBMC_NV12)
+ float4 YUV = float4(tex2D (YSampler, In.TextureY).x
+ , tex2D (USampler, In.TextureU).ra
+ , 1.0);
+#elif defined(XBMC_YUY2) || defined(XBMC_UYVY)
+ // The HLSL compiler is smart enough to optimize away these redundant assignments.
+ // That way the code is almost identical to the OGL shader.
+ float2 stepxy = g_StepXY;
+ float2 pos = In.TextureY;
+ pos = float2(pos.x - (stepxy.x * 0.25), pos.y);
+ float2 f = frac(pos / stepxy);
+
+ //y axis will be correctly interpolated by opengl
+ //x axis will not, so we grab two pixels at the center of two columns and interpolate ourselves
+ float4 c1 = tex2D(YSampler, float2(pos.x + ((0.5 - f.x) * stepxy.x), pos.y));
+ float4 c2 = tex2D(YSampler, float2(pos.x + ((1.5 - f.x) * stepxy.x), pos.y));
+
+ /* each pixel has two Y subpixels and one UV subpixel
+ YUV Y YUV
+ check if we're left or right of the middle Y subpixel and interpolate accordingly*/
+ #if defined(XBMC_YUY2) // BGRA = YUYV
+ float leftY = lerp(c1.b, c1.r, f.x * 2.0);
+ float rightY = lerp(c1.r, c2.b, f.x * 2.0 - 1.0);
+ float2 outUV = lerp(c1.ga, c2.ga, f.x);
+ #elif defined(XBMC_UYVY) // BGRA = UYVY
+ float leftY = lerp(c1.g, c1.a, f.x * 2.0);
+ float rightY = lerp(c1.a, c2.g, f.x * 2.0 - 1.0);
+ float2 outUV = lerp(c1.br, c2.br, f.x);
+ #endif
+ float outY = lerp(leftY, rightY, step(0.5, f.x));
+ float4 YUV = float4(outY, outUV, 1.0);
+#endif
+
OUT.RGBColor = mul(YUV, g_ColorMatrix);
OUT.RGBColor.a = 1.0;
return OUT;
diff --git a/xbmc/cores/VideoRenderers/VideoShaders/WinVideoFilter.cpp b/xbmc/cores/VideoRenderers/VideoShaders/WinVideoFilter.cpp
index 5a29583e55..f5542fa42a 100644
--- a/xbmc/cores/VideoRenderers/VideoShaders/WinVideoFilter.cpp
+++ b/xbmc/cores/VideoRenderers/VideoShaders/WinVideoFilter.cpp
@@ -192,32 +192,77 @@ bool CWinShader::Execute()
//==================================================================================
-bool CYUV2RGBShader::Create(bool singlepass, unsigned int sourceWidth, unsigned int sourceHeight)
+bool CYUV2RGBShader::Create(unsigned int sourceWidth, unsigned int sourceHeight, BufferFormat fmt)
{
ReleaseInternal();
CWinShader::CreateVertexBuffer(D3DFVF_XYZRHW | D3DFVF_TEX3, 4, sizeof(CUSTOMVERTEX), 2);
+ m_sourceWidth = sourceWidth;
+ m_sourceHeight = sourceHeight;
+
+ unsigned int texWidth;
+
DefinesMap defines;
- if (singlepass)
- defines["SINGLEPASS"] = "";
- CStdString effectString = "special://xbmc/system/shaders/yuv2rgb_d3d.fx";
+ if (fmt == YV12)
+ {
+ defines["XBMC_YV12"] = "";
+ texWidth = sourceWidth;
- if(!LoadEffect(effectString, &defines))
+ if(!m_YUVPlanes[0].Create(texWidth , m_sourceHeight , 1, 0, D3DFMT_L8, D3DPOOL_DEFAULT)
+ || !m_YUVPlanes[1].Create(texWidth / 2, m_sourceHeight / 2, 1, 0, D3DFMT_L8, D3DPOOL_DEFAULT)
+ || !m_YUVPlanes[2].Create(texWidth / 2, m_sourceHeight / 2, 1, 0, D3DFMT_L8, D3DPOOL_DEFAULT))
+ {
+ CLog::Log(LOGERROR, __FUNCTION__": Failed to create YV12 planes.");
+ return false;
+ }
+ }
+ else if (fmt == NV12)
{
- CLog::Log(LOGERROR, __FUNCTION__": Failed to load shader %s.", effectString.c_str());
- return false;
+ defines["XBMC_NV12"] = "";
+ texWidth = sourceWidth;
+
+ if(!m_YUVPlanes[0].Create(texWidth , m_sourceHeight , 1, 0, D3DFMT_L8, D3DPOOL_DEFAULT)
+ || !m_YUVPlanes[1].Create(texWidth / 2, m_sourceHeight / 2, 1, 0, D3DFMT_A8L8, D3DPOOL_DEFAULT))
+ {
+ CLog::Log(LOGERROR, __FUNCTION__": Failed to create NV12 planes.");
+ return false;
+ }
}
+ else if (fmt == YUY2)
+ {
+ defines["XBMC_YUY2"] = "";
+ texWidth = sourceWidth >> 1;
- m_sourceWidth = sourceWidth;
- m_sourceHeight = sourceHeight;
+ if(!m_YUVPlanes[0].Create(texWidth , m_sourceHeight , 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT))
+ {
+ CLog::Log(LOGERROR, __FUNCTION__": Failed to create YUY2 planes.");
+ return false;
+ }
+ }
+ else if (fmt == UYVY)
+ {
+ defines["XBMC_UYVY"] = "";
+ texWidth = sourceWidth >> 1;
+
+ if(!m_YUVPlanes[0].Create(texWidth , m_sourceHeight , 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT))
+ {
+ CLog::Log(LOGERROR, __FUNCTION__": Failed to create UYVY planes.");
+ return false;
+ }
+ }
+ else
+ return false;
+
+ m_texSteps[0] = 1.0f/(float)texWidth;
+ m_texSteps[1] = 1.0f/(float)sourceHeight;
- if(!m_YUVPlanes[0].Create(m_sourceWidth , m_sourceHeight , 1, 0, D3DFMT_L8, D3DPOOL_DEFAULT)
- || !m_YUVPlanes[1].Create(m_sourceWidth / 2, m_sourceHeight / 2, 1, 0, D3DFMT_L8, D3DPOOL_DEFAULT)
- || !m_YUVPlanes[2].Create(m_sourceWidth / 2, m_sourceHeight / 2, 1, 0, D3DFMT_L8, D3DPOOL_DEFAULT))
+ CStdString effectString = "special://xbmc/system/shaders/yuv2rgb_d3d.fx";
+
+ if(!LoadEffect(effectString, &defines))
{
- CLog::Log(LOGERROR, __FUNCTION__": Failed to create YUV planes.");
+ CLog::Log(LOGERROR, __FUNCTION__": Failed to load shader %s.", effectString.c_str());
return false;
}
@@ -233,7 +278,7 @@ void CYUV2RGBShader::Render(CRect sourceRect, CRect destRect,
PrepareParameters(sourceRect, destRect,
contrast, brightness, flags);
UploadToGPU(YUVbuf);
- SetShaderParameters();
+ SetShaderParameters(YUVbuf);
Execute();
}
@@ -299,13 +344,16 @@ void CYUV2RGBShader::PrepareParameters(CRect sourceRect,
flags);
}
-void CYUV2RGBShader::SetShaderParameters()
+void CYUV2RGBShader::SetShaderParameters(YUVBuffer* YUVbuf)
{
- m_effect.SetMatrix( "g_ColorMatrix", m_matrix.Matrix());
- m_effect.SetTechnique( "YUV2RGB_T" );
- m_effect.SetTexture( "g_YTexture", m_YUVPlanes[0] ) ;
- m_effect.SetTexture( "g_UTexture", m_YUVPlanes[1] ) ;
- m_effect.SetTexture( "g_VTexture", m_YUVPlanes[2] ) ;
+ m_effect.SetMatrix("g_ColorMatrix", m_matrix.Matrix());
+ m_effect.SetTechnique("YUV2RGB_T");
+ m_effect.SetTexture("g_YTexture", m_YUVPlanes[0]);
+ if (YUVbuf->GetActivePlanes() > 1)
+ m_effect.SetTexture("g_UTexture", m_YUVPlanes[1]);
+ if (YUVbuf->GetActivePlanes() > 2)
+ m_effect.SetTexture("g_VTexture", m_YUVPlanes[2]);
+ m_effect.SetFloatArray("g_StepXY", m_texSteps, sizeof(m_texSteps)/sizeof(m_texSteps[0]));
}
void CYUV2RGBShader::ReleaseInternal()
@@ -319,19 +367,18 @@ void CYUV2RGBShader::ReleaseInternal()
bool CYUV2RGBShader::UploadToGPU(YUVBuffer* YUVbuf)
{
- const RECT rect = { 0, 0, m_sourceWidth, m_sourceHeight };
- const RECT recthalf = { 0, 0, m_sourceWidth / 2, m_sourceHeight / 2};
const POINT point = { 0, 0 };
- for (int i = 0; i<3; i++)
+ for (unsigned int i = 0; i<YUVbuf->GetActivePlanes(); i++)
{
+ const RECT rect = { 0, 0, YUVbuf->planes[i].texture.GetWidth(), YUVbuf->planes[i].texture.GetHeight() };
IDirect3DSurface9 *src, *dest;
if(FAILED(YUVbuf->planes[i].texture.Get()->GetSurfaceLevel(0, &src)))
CLog::Log(LOGERROR, __FUNCTION__": Failed to retrieve level 0 surface for source YUV plane %d", i);
if (FAILED(m_YUVPlanes[i].Get()->GetSurfaceLevel(0, &dest)))
CLog::Log(LOGERROR, __FUNCTION__": Failed to retrieve level 0 surface for destination YUV plane %d", i);
- if (FAILED(g_Windowing.Get3DDevice()->UpdateSurface(src, i == 0 ? &rect : &recthalf, dest, &point)))
+ if (FAILED(g_Windowing.Get3DDevice()->UpdateSurface(src, &rect, dest, &point)))
{
CLog::Log(LOGERROR, __FUNCTION__": Failed to copy plane %d from sysmem to vidmem.", i);
src->Release();
diff --git a/xbmc/cores/VideoRenderers/VideoShaders/WinVideoFilter.h b/xbmc/cores/VideoRenderers/VideoShaders/WinVideoFilter.h
index d74fad4bbb..046acba481 100644
--- a/xbmc/cores/VideoRenderers/VideoShaders/WinVideoFilter.h
+++ b/xbmc/cores/VideoRenderers/VideoShaders/WinVideoFilter.h
@@ -76,7 +76,7 @@ private:
class CYUV2RGBShader : public CWinShader
{
public:
- virtual bool Create(bool singlepass, unsigned int sourceWidth, unsigned int sourceHeight);
+ virtual bool Create(unsigned int sourceWidth, unsigned int sourceHeight, BufferFormat fmt);
virtual void Render(CRect sourceRect,
CRect destRect,
float contrast,
@@ -90,7 +90,7 @@ protected:
float contrast,
float brightness,
unsigned int flags);
- virtual void SetShaderParameters();
+ virtual void SetShaderParameters(YUVBuffer* YUVbuf);
virtual void ReleaseInternal();
virtual bool UploadToGPU(YUVBuffer* YUVbuf);
@@ -99,6 +99,7 @@ private:
unsigned int m_sourceWidth, m_sourceHeight;
CRect m_sourceRect, m_destRect;
CD3DTexture m_YUVPlanes[3];
+ float m_texSteps[2];
struct CUSTOMVERTEX {
FLOAT x, y, z;
diff --git a/xbmc/cores/VideoRenderers/WinRenderer.cpp b/xbmc/cores/VideoRenderers/WinRenderer.cpp
index 104d283437..356ac4b668 100644
--- a/xbmc/cores/VideoRenderers/WinRenderer.cpp
+++ b/xbmc/cores/VideoRenderers/WinRenderer.cpp
@@ -87,6 +87,24 @@ CWinRenderer::~CWinRenderer()
UnInit();
}
+static BufferFormat BufferFormatFromFlags(unsigned int flags)
+{
+ if (CONF_FLAGS_FORMAT_MASK(flags) == CONF_FLAGS_FORMAT_YV12) return YV12;
+ else if (CONF_FLAGS_FORMAT_MASK(flags) == CONF_FLAGS_FORMAT_NV12) return NV12;
+ else if (CONF_FLAGS_FORMAT_MASK(flags) == CONF_FLAGS_FORMAT_YUY2) return YUY2;
+ else if (CONF_FLAGS_FORMAT_MASK(flags) == CONF_FLAGS_FORMAT_UYVY) return UYVY;
+ else return Invalid;
+}
+
+static enum PixelFormat PixelFormatFromFlags(unsigned int flags)
+{
+ if (CONF_FLAGS_FORMAT_MASK(flags) == CONF_FLAGS_FORMAT_YV12) return PIX_FMT_YUV420P;
+ else if (CONF_FLAGS_FORMAT_MASK(flags) == CONF_FLAGS_FORMAT_NV12) return PIX_FMT_NV12;
+ else if (CONF_FLAGS_FORMAT_MASK(flags) == CONF_FLAGS_FORMAT_UYVY) return PIX_FMT_UYVY422;
+ else if (CONF_FLAGS_FORMAT_MASK(flags) == CONF_FLAGS_FORMAT_YUY2) return PIX_FMT_YUYV422;
+ else return PIX_FMT_NONE;
+}
+
void CWinRenderer::ManageTextures()
{
int neededbuffers = 2;
@@ -549,11 +567,14 @@ void CWinRenderer::UpdatePSVideoFilter()
SAFE_RELEASE(m_colorShader)
+ BufferFormat format = BufferFormatFromFlags(m_flags);
+
if (m_bUseHQScaler)
{
m_colorShader = new CYUV2RGBShader();
- if (!m_colorShader->Create(false, m_sourceWidth, m_sourceHeight))
+ if (!m_colorShader->Create(m_sourceWidth, m_sourceHeight, format))
{
+ // Try again after disabling the HQ scaler and freeing its resources
m_IntermediateTarget.Release();
SAFE_RELEASE(m_scalerShader)
SAFE_RELEASE(m_colorShader);
@@ -564,7 +585,7 @@ void CWinRenderer::UpdatePSVideoFilter()
if (!m_bUseHQScaler) //fallback from HQ scalers and multipass creation above
{
m_colorShader = new CYUV2RGBShader();
- if (!m_colorShader->Create(true, m_sourceWidth, m_sourceHeight))
+ if (!m_colorShader->Create(m_sourceWidth, m_sourceHeight, format))
SAFE_RELEASE(m_colorShader);
// we're in big trouble - should fallback on D3D accelerated or sw method
}
@@ -674,35 +695,43 @@ void CWinRenderer::Render(DWORD flags)
void CWinRenderer::RenderSW()
{
+ enum PixelFormat format = PixelFormatFromFlags(m_flags);
+
// 1. convert yuv to rgb
m_sw_scale_ctx = m_dllSwScale->sws_getCachedContext(m_sw_scale_ctx,
- m_sourceWidth, m_sourceHeight, PIX_FMT_YUV420P,
+ m_sourceWidth, m_sourceHeight, format,
m_sourceWidth, m_sourceHeight, PIX_FMT_BGRA,
SWS_FAST_BILINEAR | SwScaleCPUFlags(), NULL, NULL, NULL);
YUVBuffer* buf = (YUVBuffer*)m_VideoBuffers[m_iYV12RenderBuffer];
- D3DLOCKED_RECT srclr[3];
- if(!(buf->planes[0].texture.LockRect(0, &srclr[0], NULL, D3DLOCK_READONLY))
- || !(buf->planes[1].texture.LockRect(0, &srclr[1], NULL, D3DLOCK_READONLY))
- || !(buf->planes[2].texture.LockRect(0, &srclr[2], NULL, D3DLOCK_READONLY)))
- CLog::Log(LOGERROR, __FUNCTION__" - failed to lock yuv textures into memory");
+ D3DLOCKED_RECT srclr[MAX_PLANES];
+ uint8_t *src[MAX_PLANES];
+ int srcStride[MAX_PLANES];
+
+ for (unsigned int idx = 0; idx < buf->GetActivePlanes(); idx++)
+ {
+ if(!(buf->planes[idx].texture.LockRect(0, &srclr[idx], NULL, D3DLOCK_READONLY)))
+ CLog::Log(LOGERROR, __FUNCTION__" - failed to lock yuv textures into memory");
+ else
+ {
+ src[idx] = (uint8_t*)srclr[idx].pBits;
+ srcStride[idx] = srclr[idx].Pitch;
+ }
+ }
D3DLOCKED_RECT destlr = {0,0};
if (!m_SWTarget.LockRect(0, &destlr, NULL, D3DLOCK_DISCARD))
CLog::Log(LOGERROR, __FUNCTION__" - failed to lock swtarget texture into memory");
- uint8_t *src[] = { (uint8_t*)srclr[0].pBits, (uint8_t*)srclr[1].pBits, (uint8_t*)srclr[2].pBits, 0 };
- int srcStride[] = { srclr[0].Pitch, srclr[1].Pitch, srclr[2].Pitch, 0 };
uint8_t *dst[] = { (uint8_t*) destlr.pBits, 0, 0, 0 };
int dstStride[] = { destlr.Pitch, 0, 0, 0 };
m_dllSwScale->sws_scale(m_sw_scale_ctx, src, srcStride, 0, m_sourceHeight, dst, dstStride);
- if(!(buf->planes[0].texture.UnlockRect(0))
- || !(buf->planes[1].texture.UnlockRect(0))
- || !(buf->planes[2].texture.UnlockRect(0)))
- CLog::Log(LOGERROR, __FUNCTION__" - failed to unlock yuv textures");
+ for (unsigned int idx = 0; idx < buf->GetActivePlanes(); idx++)
+ if(!(buf->planes[idx].texture.UnlockRect(0)))
+ CLog::Log(LOGERROR, __FUNCTION__" - failed to unlock yuv textures");
if (!m_SWTarget.UnlockRect(0))
CLog::Log(LOGERROR, __FUNCTION__" - failed to unlock swtarget texture");
@@ -990,7 +1019,9 @@ bool CWinRenderer::CreateYV12Texture(int index)
{
YUVBuffer *buf = new YUVBuffer();
- if (!buf->Create(m_sourceWidth, m_sourceHeight))
+ BufferFormat format = BufferFormatFromFlags(m_flags);
+
+ if (!buf->Create(format, m_sourceWidth, m_sourceHeight))
{
CLog::Log(LOGERROR, __FUNCTION__" - Unable to create YV12 video texture %i", index);
return false;
@@ -1085,8 +1116,9 @@ YUVBuffer::~YUVBuffer()
Release();
}
-bool YUVBuffer::Create(unsigned int width, unsigned int height)
+bool YUVBuffer::Create(BufferFormat format, unsigned int width, unsigned int height)
{
+ m_format = format;
m_width = width;
m_height = height;
@@ -1095,17 +1127,50 @@ bool YUVBuffer::Create(unsigned int width, unsigned int height)
// - Dynamic + D3DPOOL_DEFAULT caused trouble for Intel i3 and some IGP. Bad sync/locking in the driver I suppose
// and Present failed every second time for the second video played.
// - this is what D3D9 does behind the scenes anyway
- if ( !planes[PLANE_Y].texture.Create(m_width , m_height , 1, 0, D3DFMT_L8, D3DPOOL_SYSTEMMEM)
- || !planes[PLANE_U].texture.Create(m_width / 2, m_height / 2, 1, 0, D3DFMT_L8, D3DPOOL_SYSTEMMEM)
- || !planes[PLANE_V].texture.Create(m_width / 2, m_height / 2, 1, 0, D3DFMT_L8, D3DPOOL_SYSTEMMEM))
+ switch(m_format)
+ {
+ case YV12:
+ {
+ if ( !planes[PLANE_Y].texture.Create(m_width , m_height , 1, 0, D3DFMT_L8, D3DPOOL_SYSTEMMEM)
+ || !planes[PLANE_U].texture.Create(m_width / 2, m_height / 2, 1, 0, D3DFMT_L8, D3DPOOL_SYSTEMMEM)
+ || !planes[PLANE_V].texture.Create(m_width / 2, m_height / 2, 1, 0, D3DFMT_L8, D3DPOOL_SYSTEMMEM))
+ return false;
+ m_activeplanes = 3;
+ break;
+ }
+ case NV12:
+ {
+ if ( !planes[PLANE_Y].texture.Create(m_width , m_height , 1, 0, D3DFMT_L8, D3DPOOL_SYSTEMMEM)
+ || !planes[PLANE_UV].texture.Create(m_width / 2, m_height / 2, 1, 0, D3DFMT_A8L8, D3DPOOL_SYSTEMMEM))
+ return false;
+ m_activeplanes = 2;
+ break;
+ }
+ case YUY2:
+ {
+ if ( !planes[PLANE_Y].texture.Create(m_width >> 1 , m_height , 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM))
+ return false;
+ m_activeplanes = 1;
+ break;
+ }
+ case UYVY:
+ {
+ if ( !planes[PLANE_Y].texture.Create(m_width >> 1 , m_height , 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM))
+ return false;
+ m_activeplanes = 1;
+ break;
+ }
+ default:
+ m_activeplanes = 0;
return false;
+ }
return true;
}
void YUVBuffer::Release()
{
- for(unsigned i = 0; i < MAX_PLANES; i++)
+ for(unsigned i = 0; i < m_activeplanes; i++)
{
planes[i].texture.Release();
memset(&planes[i].rect, 0, sizeof(planes[i].rect));
@@ -1114,7 +1179,7 @@ void YUVBuffer::Release()
void YUVBuffer::StartRender()
{
- for(unsigned i = 0; i < MAX_PLANES; i++)
+ for(unsigned i = 0; i < m_activeplanes; i++)
{
if(planes[i].texture.Get() && planes[i].rect.pBits)
if (!planes[i].texture.UnlockRect(0))
@@ -1125,7 +1190,7 @@ void YUVBuffer::StartRender()
void YUVBuffer::StartDecode()
{
- for(unsigned i = 0; i < MAX_PLANES; i++)
+ for(unsigned i = 0; i < m_activeplanes; i++)
{
if(planes[i].texture.Get()
&& planes[i].texture.LockRect(0, &planes[i].rect, NULL, D3DLOCK_DISCARD) == false)
@@ -1138,9 +1203,36 @@ void YUVBuffer::StartDecode()
void YUVBuffer::Clear()
{
- memset(planes[PLANE_Y].rect.pBits, 0, planes[PLANE_Y].rect.Pitch * m_height);
- memset(planes[PLANE_U].rect.pBits, 128, planes[PLANE_U].rect.Pitch * (m_height/2));
- memset(planes[PLANE_V].rect.pBits, 128, planes[PLANE_V].rect.Pitch * (m_height/2));
+ // Set Y to 0 and U,V to 128 (RGB 0,0,0) to avoid visual artifacts at the start of playback
+
+ switch(m_format)
+ {
+ case YV12:
+ {
+ memset(planes[PLANE_Y].rect.pBits, 0, planes[PLANE_Y].rect.Pitch * m_height);
+ memset(planes[PLANE_U].rect.pBits, 128, planes[PLANE_U].rect.Pitch * (m_height/2));
+ memset(planes[PLANE_V].rect.pBits, 128, planes[PLANE_V].rect.Pitch * (m_height/2));
+ break;
+ }
+ case NV12:
+ {
+ memset(planes[PLANE_Y].rect.pBits, 0, planes[PLANE_Y].rect.Pitch * m_height);
+ memset(planes[PLANE_UV].rect.pBits, 128, planes[PLANE_U].rect.Pitch * (m_height/2));
+ break;
+ }
+ // YUY2, UYVY: wmemset to set a 16bit pattern, byte-swapped because x86 is LE
+ case YUY2:
+ {
+ wmemset((wchar_t*)planes[PLANE_Y].rect.pBits, 0x8000, planes[PLANE_Y].rect.Pitch / 2 * m_height);
+ break;
+ }
+ case UYVY:
+ {
+ wmemset((wchar_t*)planes[PLANE_Y].rect.pBits, 0x0080, planes[PLANE_Y].rect.Pitch / 2 * m_height);
+ break;
+ }
+
+ }
}
//==================================
diff --git a/xbmc/cores/VideoRenderers/WinRenderer.h b/xbmc/cores/VideoRenderers/WinRenderer.h
index 28c2f15a1d..7ea068e2f5 100644
--- a/xbmc/cores/VideoRenderers/WinRenderer.h
+++ b/xbmc/cores/VideoRenderers/WinRenderer.h
@@ -115,11 +115,21 @@ enum RenderMethod
#define PLANE_Y 0
#define PLANE_U 1
#define PLANE_V 2
+#define PLANE_UV 1
#define FIELD_FULL 0
#define FIELD_TOP 1
#define FIELD_BOT 2
+enum BufferFormat
+{
+ Invalid,
+ YV12,
+ NV12,
+ YUY2,
+ UYVY
+};
+
struct SVideoBuffer
{
virtual ~SVideoBuffer() {}
@@ -139,17 +149,20 @@ struct SVideoPlane
struct YUVBuffer : SVideoBuffer
{
~YUVBuffer();
- bool Create(unsigned int width, unsigned int height);
+ bool Create(BufferFormat format, unsigned int width, unsigned int height);
virtual void Release();
virtual void StartDecode();
virtual void StartRender();
virtual void Clear();
+ unsigned int GetActivePlanes() { return m_activeplanes; }
SVideoPlane planes[MAX_PLANES];
private:
unsigned int m_width;
unsigned int m_height;
+ BufferFormat m_format;
+ unsigned int m_activeplanes;
};
struct DXVABuffer : SVideoBuffer
diff --git a/xbmc/guilib/D3DResource.h b/xbmc/guilib/D3DResource.h
index 7da5287c48..828f45eda9 100644
--- a/xbmc/guilib/D3DResource.h
+++ b/xbmc/guilib/D3DResource.h
@@ -49,13 +49,17 @@ public:
bool GetLevelDesc(UINT level, D3DSURFACE_DESC *desc);
bool GetSurfaceLevel(UINT level, LPDIRECT3DSURFACE9 *surface);
+ // Accessors
LPDIRECT3DTEXTURE9 Get() const { return m_texture; };
+ UINT GetWidth() { return m_width; }
+ UINT GetHeight() { return m_height; }
virtual void OnDestroyDevice();
virtual void OnCreateDevice();
virtual void OnLostDevice();
virtual void OnResetDevice();
+
private:
unsigned int GetMemoryUsage(unsigned int pitch) const;