[vlc-devel] [PATCH] DXVA2: output an opaque pixel format with D3D9 surfaces internally (v2)

Steve Lhomme robux4 at videolabs.io
Mon Apr 20 17:39:46 CEST 2015


Add a filter to convert these surfaces to I420,YV12 & NV12 planes
D3D9 uses the same surface for its display picure_t
--
D3D9 creates a DXVA/D3D9 picture pool of the right size when used in DXVA
The D3D9 device/handle is shared between the decoder and the vout so surfaces are compatible and all is done in the GPU
The win32 DXVA hack is not needed anymore. DXVA is now thread safe and compatible with multithreaded frame decoding.

v1 was missing dxva2.h and using mulitple surface pixel formats
---
 include/vlc_fourcc.h                 |   3 +
 modules/codec/Makefile.am            |   2 +-
 modules/codec/avcodec/dxva2.c        | 438 +++++++++++++++++++++++++++--------
 modules/codec/avcodec/dxva2.h        |  69 ++++++
 modules/codec/avcodec/video.c        |  15 --
 modules/video_output/msw/direct3d9.c | 291 +++++++++++++----------
 src/misc/fourcc.c                    |   3 +
 7 files changed, 581 insertions(+), 240 deletions(-)
 create mode 100644 modules/codec/avcodec/dxva2.h

diff --git a/include/vlc_fourcc.h b/include/vlc_fourcc.h
index 5d30ece..df82f6f 100644
--- a/include/vlc_fourcc.h
+++ b/include/vlc_fourcc.h
@@ -332,6 +332,9 @@
 /* Broadcom MMAL opaque buffer type */
 #define VLC_CODEC_MMAL_OPAQUE     VLC_FOURCC('M','M','A','L')
 
+/* DXVA2 opaque video surface for use with D3D9 */
+#define VLC_CODEC_D3D9_OPAQUE     VLC_FOURCC('D','X','A','9')
+
 /* Image codec (video) */
 #define VLC_CODEC_PNG             VLC_FOURCC('p','n','g',' ')
 #define VLC_CODEC_PPM             VLC_FOURCC('p','p','m',' ')
diff --git a/modules/codec/Makefile.am b/modules/codec/Makefile.am
index 9c31230..0426b66 100644
--- a/modules/codec/Makefile.am
+++ b/modules/codec/Makefile.am
@@ -342,7 +342,7 @@ endif
 
 libdxva2_plugin_la_SOURCES = \
 	video_chroma/copy.c video_chroma/copy.h \
-	codec/avcodec/dxva2.c
+	codec/avcodec/dxva2.c codec/avcodec/dxva2.h
 libdxva2_plugin_la_LIBADD = -lole32 -lshlwapi -luuid
 if HAVE_AVCODEC_DXVA2
 codec_LTLIBRARIES += libdxva2_plugin.la
diff --git a/modules/codec/avcodec/dxva2.c b/modules/codec/avcodec/dxva2.c
index 23f575a..6acfb92 100644
--- a/modules/codec/avcodec/dxva2.c
+++ b/modules/codec/avcodec/dxva2.c
@@ -41,7 +41,8 @@
 #include <vlc_fourcc.h>
 #include <vlc_cpu.h>
 #include <vlc_plugin.h>
-#include <vlc_codecs.h>
+#include <vlc_codec.h>
+#include <vlc_filter.h>
 
 #include <libavcodec/avcodec.h>
 #    define DXVA2API_USE_BITFIELDS
@@ -51,16 +52,25 @@
 #include "avcodec.h"
 #include "va.h"
 #include "../../video_chroma/copy.h"
+#include "../../demux/asf/libasf_guid.h"
+#include "dxva2.h"
 
 static int Open(vlc_va_t *, AVCodecContext *, const es_format_t *);
 static void Close(vlc_va_t *, AVCodecContext *);
 
+static int  OpenConverter( vlc_object_t * );
+static void CloseConverter( vlc_object_t * );
+
 vlc_module_begin()
     set_description(N_("DirectX Video Acceleration (DXVA) 2.0"))
     set_capability("hw decoder", 0)
     set_category(CAT_INPUT)
     set_subcategory(SUBCAT_INPUT_VCODEC)
     set_callbacks(Open, Close)
+    add_submodule()
+        set_description( N_("DXA9 to I420,YV12,NV12") )
+        set_capability( "video filter2", 10 )
+        set_callbacks( OpenConverter, CloseConverter )
 vlc_module_end()
 
 #include <windows.h>
@@ -271,8 +281,8 @@ static const dxva2_mode_t *Dxva2FindMode(const GUID *guid)
 /* */
 typedef struct {
     const char   *name;
-    D3DFORMAT    format;
-    vlc_fourcc_t codec;
+    D3DFORMAT    format;    /* D3D format */
+    vlc_fourcc_t fourcc;    /* VLC fourcc */
 } d3d_format_t;
 /* XXX Prefered format must come first */
 static const d3d_format_t d3d_formats[] = {
@@ -292,14 +302,6 @@ static const d3d_format_t *D3dFindFormat(D3DFORMAT format)
     return NULL;
 }
 
-/* */
-typedef struct {
-    LPDIRECT3DSURFACE9 d3d;
-    int                refcount;
-    unsigned int       order;
-    vlc_mutex_t        *p_lock;
-} vlc_va_surface_t;
-
 #define VA_DXVA2_MAX_SURFACE_COUNT (64)
 struct vlc_va_sys_t
 {
@@ -329,7 +331,7 @@ struct vlc_va_sys_t
     /* Video service */
     IDirectXVideoDecoderService  *vs;
     GUID                         input;
-    D3DFORMAT                    render;
+    const d3d_format_t           *p_render;
 
     /* Video decoder */
     DXVA2_ConfigPictureDecode    cfg;
@@ -337,7 +339,6 @@ struct vlc_va_sys_t
 
     /* Option conversion */
     D3DFORMAT                    output;
-    copy_cache_t                 surface_cache;
 
     /* */
     struct dxva_context hw;
@@ -351,8 +352,13 @@ struct vlc_va_sys_t
 
     int          thread_count;
 
-    vlc_va_surface_t surface[VA_DXVA2_MAX_SURFACE_COUNT];
+    vlc_va_t          *va;
+
+    /* surfaces in the GPU user space */
+    picture_sys_t surface[VA_DXVA2_MAX_SURFACE_COUNT];
     LPDIRECT3DSURFACE9 hw_surface[VA_DXVA2_MAX_SURFACE_COUNT];
+
+    picture_pool_setup_sys_t pool_cookie;
 };
 
 /* */
@@ -365,15 +371,135 @@ static void D3dDestroyDeviceManager(vlc_va_sys_t *);
 
 static int DxCreateVideoService(vlc_va_t *);
 static void DxDestroyVideoService(vlc_va_sys_t *);
-static int DxFindVideoServiceConversion(vlc_va_t *, GUID *input, D3DFORMAT *output);
+static int DxFindVideoServiceConversion(vlc_va_t *, GUID *input, const d3d_format_t **output);
 
 static int DxCreateVideoDecoder(vlc_va_t *,
                                 int codec_id, const video_format_t *, bool);
 static void DxDestroyVideoDecoder(vlc_va_sys_t *);
 static int DxResetVideoDecoder(vlc_va_t *);
 
-static void DxCreateVideoConversion(vlc_va_sys_t *);
-static void DxDestroyVideoConversion(vlc_va_sys_t *);
+static void CopySurface( picture_t *p_dst, picture_t *p_src )
+{
+    picture_sys_t *p_src_sys = p_src->p_sys;
+    picture_sys_t *p_dst_sys = p_dst->p_sys;
+
+    if (!p_dst_sys)
+        return;
+
+    LPDIRECT3DSURFACE9 source = p_src_sys->surface;
+    LPDIRECT3DSURFACE9 output = p_dst_sys->surface;
+
+    HRESULT hr = IDirect3DDevice9_StretchRect( p_src_sys->surface_device, source, NULL, output, NULL, D3DTEXF_NONE);
+    if (FAILED(hr)) {
+        //msg_Err( p_src_sys->p_va, "Failed to copy the hw surface to the decoder surface (hr=0x%0lx)", hr );
+    }
+}
+
+void DestroySurface(picture_t *p_pic)
+{
+    picture_sys_t *p_pic_sys = p_pic->p_sys;
+    IDirect3DSurface9_Release( p_pic_sys->surface );
+    free( p_pic_sys );
+    p_pic->p_sys = NULL;
+}
+
+static int LockOutputSurface(picture_t *p_pic)
+{
+    IDirect3DSurface9_AddRef( p_pic->p_sys->surface );
+    return VLC_SUCCESS;
+}
+
+static void UnlockOutputSurface(picture_t *p_pic)
+{
+    IDirect3DSurface9_Release( p_pic->p_sys->surface );
+}
+
+static void DestroySurfacePool(void *p_pool_gc_sys)
+{
+    picture_pool_configuration_t *p_pool = p_pool_gc_sys;
+    free( p_pool );
+}
+
+static picture_pool_configuration_t *CreateSurfacePoolConfig(picture_pool_setup_sys_t *p_sys, const video_format_t *fmt, unsigned count)
+{
+    vlc_va_sys_t *sys = p_sys->p_va_sys;
+    LPDIRECT3DSURFACE9 hw_surfaces[count];
+    picture_sys_t *p_sys_pictures[count];
+    picture_pool_configuration_t *p_pool = NULL;
+    picture_t **pictures = NULL;
+
+    memset(p_sys_pictures, 0, count * sizeof(picture_sys_t *));
+
+    p_pool = calloc(1, sizeof(picture_pool_configuration_t));
+    if ( p_pool == NULL )
+        goto error;
+
+    pictures = calloc(count, sizeof(picture_t*));
+    if ( pictures == NULL )
+        goto error;
+
+    if (FAILED(IDirectXVideoDecoderService_CreateSurface(sys->vs,
+                                                         sys->surface_width,
+                                                         sys->surface_height,
+                                                         count - 1,
+                                                         sys->p_render->format,
+                                                         D3DPOOL_DEFAULT,
+                                                         0,
+                                                         DXVA2_VideoDecoderRenderTarget,
+                                                         hw_surfaces,
+                                                         NULL))) {
+        msg_Err(sys->va, "IDirectXVideoAccelerationService_CreateSurface display failed");
+        goto error;
+    }
+    p_pool->picture_count = count;
+
+    for (unsigned i = 0; i < count; ++i)
+    {
+        p_sys_pictures[i] = calloc(1, sizeof(picture_sys_t));
+        if ( p_sys_pictures[i] == NULL )
+            goto error;
+        p_sys_pictures[i]->surface = hw_surfaces[i];
+        p_sys_pictures[i]->surface_device = sys->d3ddev;
+        p_sys_pictures[i]->index = i;
+        if ( sys->b_thread_safe )
+            p_sys_pictures[i]->p_lock = &sys->surface_lock;
+
+        picture_resource_t pic_resource = {
+            .p_sys = p_sys_pictures[i],
+            .pf_destroy = DestroySurface,
+        };
+        pictures[i] = picture_NewFromResource( fmt, &pic_resource );
+        if ( pictures[i] == NULL)
+            goto error;
+    }
+
+    p_pool->picture = pictures;
+    p_pool->lock = LockOutputSurface;
+    p_pool->unlock = UnlockOutputSurface;
+    p_pool->gc.pf_destroy = DestroySurfacePool;
+    p_pool->gc.p_sys = p_pool;
+
+    return p_pool;
+
+error:
+    for (unsigned i = 0; i < p_pool->picture_count; ++i)
+    {
+        IDirect3DSurface9_Release( hw_surfaces[i] );
+    }
+    for (unsigned i = 0; i < count; ++i)
+    {
+        if (p_sys_pictures != NULL && p_sys_pictures[i] != NULL)
+            free( p_sys_pictures[i] );
+        if (pictures != NULL && pictures[i] != NULL)
+            picture_Release( pictures[i] );
+    }
+    if ( pictures != NULL )
+        free( pictures );
+    if ( p_pool != NULL )
+        free( p_pool );
+
+    return NULL;
+}
 
 /* */
 static int Setup(vlc_va_t *va, AVCodecContext *avctx, vlc_fourcc_t *chroma, picture_pool_setup_t *output_init)
@@ -385,7 +511,6 @@ static int Setup(vlc_va_t *va, AVCodecContext *avctx, vlc_fourcc_t *chroma, pict
         goto ok;
 
     /* */
-    DxDestroyVideoConversion(sys);
     DxDestroyVideoDecoder(sys);
 
     avctx->hwaccel_context = NULL;
@@ -408,39 +533,57 @@ static int Setup(vlc_va_t *va, AVCodecContext *avctx, vlc_fourcc_t *chroma, pict
     sys->hw.surface = sys->hw_surface;
 
     /* */
-    DxCreateVideoConversion(sys);
+    sys->output = sys->p_render->format;
 
     /* */
 ok:
+    switch(sys->p_render->format)
+    {
+    case MAKEFOURCC('N','V','1','2'):
+    case MAKEFOURCC('Y','V','1','2'):
+    case MAKEFOURCC('I','M','C','3'):
+        *chroma = VLC_CODEC_D3D9_OPAQUE;
+        break;
+    default:
+        return VLC_EGENERIC;
+    }
     avctx->hwaccel_context = &sys->hw;
-    const d3d_format_t *output = D3dFindFormat(sys->output);
-    *chroma = output->codec;
+    output_init->pf_create_config = CreateSurfacePoolConfig;
+    sys->pool_cookie.p_va_sys = sys;
+    sys->pool_cookie.d3ddev = sys->d3ddev;
+    sys->pool_cookie.d3dobj = sys->d3dobj;
+    sys->pool_cookie.d3dpp = sys->d3dpp;
+    output_init->p_sys = &sys->pool_cookie;
 
     return VLC_SUCCESS;
 }
 
-static int Extract(vlc_va_t *va, picture_t *picture, void *opaque,
-                   uint8_t *data)
+struct dxva_opaque
 {
-    vlc_va_sys_t *sys = va->sys;
-    LPDIRECT3DSURFACE9 d3d = (LPDIRECT3DSURFACE9)(uintptr_t)data;
+    picture_sys_t *p_dxva_surface;
+    vlc_va_sys_t  *p_sys;
+};
 
-    if (!sys->surface_cache.buffer)
-        return VLC_EGENERIC;
 
-    /* */
-    assert(sys->output == MAKEFOURCC('Y','V','1','2'));
+static void DXA9_I420 (filter_t *p_filter, picture_t *src, picture_t *dst)
+{
+    copy_cache_t *p_copy_cache = (copy_cache_t*) p_filter->p_sys;
+
+    LPDIRECT3DSURFACE9 d3d = src->p_sys->surface;
+    D3DSURFACE_DESC desc;
+    if (FAILED( IDirect3DSurface9_GetDesc(d3d, &desc) ))
+        return;
 
     /* */
     D3DLOCKED_RECT lock;
     if (FAILED(IDirect3DSurface9_LockRect(d3d, &lock, NULL, D3DLOCK_READONLY))) {
-        msg_Err(va, "Failed to lock surface");
-        return VLC_EGENERIC;
+        msg_Err(p_filter, "Failed to lock surface");
+        return;
     }
 
-    if (sys->render == MAKEFOURCC('Y','V','1','2') ||
-        sys->render == MAKEFOURCC('I','M','C','3')) {
-        bool imc3 = sys->render == MAKEFOURCC('I','M','C','3');
+    if (desc.Format == MAKEFOURCC('Y','V','1','2') ||
+        desc.Format == MAKEFOURCC('I','M','C','3')) {
+        bool imc3 = desc.Format == MAKEFOURCC('I','M','C','3');
         size_t chroma_pitch = imc3 ? lock.Pitch : (lock.Pitch / 2);
 
         size_t pitch[3] = {
@@ -451,9 +594,9 @@ static int Extract(vlc_va_t *va, picture_t *picture, void *opaque,
 
         uint8_t *plane[3] = {
             (uint8_t*)lock.pBits,
-            (uint8_t*)lock.pBits + pitch[0] * sys->surface_height,
-            (uint8_t*)lock.pBits + pitch[0] * sys->surface_height
-                                 + pitch[1] * sys->surface_height / 2,
+            (uint8_t*)lock.pBits + pitch[0] * src->format.i_height,
+            (uint8_t*)lock.pBits + pitch[0] * src->format.i_height
+                                 + pitch[1] * src->format.i_height / 2,
         };
 
         if (imc3) {
@@ -461,25 +604,61 @@ static int Extract(vlc_va_t *va, picture_t *picture, void *opaque,
             plane[1] = plane[2];
             plane[2] = V;
         }
-        CopyFromYv12(picture, plane, pitch, sys->width, sys->height,
-                     &sys->surface_cache);
+        CopyFromYv12(dst, plane, pitch, src->format.i_width, src->format.i_visible_height,
+                     p_copy_cache);
     } else {
-        assert(sys->render == MAKEFOURCC('N','V','1','2'));
+        assert(desc.Format == MAKEFOURCC('N','V','1','2'));
         uint8_t *plane[2] = {
             lock.pBits,
-            (uint8_t*)lock.pBits + lock.Pitch * sys->surface_height
+            (uint8_t*)lock.pBits + lock.Pitch * src->format.i_height
         };
         size_t  pitch[2] = {
             lock.Pitch,
             lock.Pitch,
         };
-        CopyFromNv12(picture, plane, pitch, sys->width, sys->height,
-                     &sys->surface_cache);
+        CopyFromNv12(dst, plane, pitch, src->format.i_width, src->format.i_visible_height,
+                     p_copy_cache);
     }
 
     /* */
     IDirect3DSurface9_UnlockRect(d3d);
-    (void) opaque;
+}
+
+static int Extract(vlc_va_t *va, picture_t *picture, void *opaque,
+                   uint8_t *data)
+{
+    struct dxva_opaque *p_output = opaque;
+
+    vlc_va_sys_t *sys = va->sys;
+    LPDIRECT3DSURFACE9 source = (LPDIRECT3DSURFACE9)(uintptr_t)data;
+
+    LPDIRECT3DSURFACE9 output = picture->p_sys->surface;
+
+    assert(source == p_output->p_dxva_surface->surface);
+
+    picture->pf_copy_private = CopySurface;
+
+    /* */
+    if ( picture->p_sys->p_lock )
+        vlc_mutex_lock( picture->p_sys->p_lock );
+
+    HRESULT hr;
+#if 0
+    RECT outputRect;
+    outputRect.top = 0;
+    outputRect.left = 0;
+    outputRect.right = picture->format.i_visible_width;
+    outputRect.bottom = picture->format.i_visible_height;
+#endif
+    hr = IDirect3DDevice9_StretchRect( sys->d3ddev, source, NULL, output, NULL, D3DTEXF_NONE);
+    if (FAILED(hr)) {
+        msg_Err(va, "Failed to copy the hw surface to the decoder surface (hr=0x%0lx)", hr );
+    }
+
+    /* */
+    if ( picture->p_sys->p_lock )
+        vlc_mutex_unlock( picture->p_sys->p_lock );
+
     return VLC_SUCCESS;
 }
 
@@ -498,30 +677,31 @@ static int Get(vlc_va_t *va, void **opaque, uint8_t **data)
         return VLC_EGENERIC;
     }
 
+    struct dxva_opaque *p_output = malloc(sizeof(*p_output));
+    *opaque = p_output;
+    p_output->p_sys = sys;
+
     if ( sys->b_thread_safe )
         vlc_mutex_lock( &sys->surface_lock );
 
     /* Grab an unused surface, in case none are, try the oldest
      * XXX using the oldest is a workaround in case a problem happens with libavcodec */
-    unsigned i, old;
-    for (i = 0, old = 0; i < sys->surface_count; i++) {
-        vlc_va_surface_t *surface = &sys->surface[i];
-
-        if (!surface->refcount)
-            break;
-
-        if (surface->order < sys->surface[old].order)
-            old = i;
+    unsigned i;
+    picture_sys_t *oldest = NULL;
+    for (i = 0; i < sys->surface_count; i++) {
+        picture_sys_t *surface = &sys->surface[i];
+        if (!surface->refcount && (!oldest || surface->order < oldest->order))
+           oldest = surface;
     }
-    if (i >= sys->surface_count)
-        i = old;
-
-    vlc_va_surface_t *surface = &sys->surface[i];
-
-    surface->refcount = 1;
-    surface->order = sys->surface_order++;
-    *data = (void *)surface->d3d;
-    *opaque = surface;
+    if ( oldest == NULL )
+    {
+        msg_Warn(va, "%lx could not find an unused surface, use oldest index", GetCurrentThreadId());
+        oldest = &sys->surface[0];
+    }
+    *data = (void *)oldest->surface;
+    p_output->p_dxva_surface = oldest;
+    p_output->p_dxva_surface->refcount++;
+    assert( p_output->p_dxva_surface->refcount == 1 );
 
     if ( sys->b_thread_safe )
         vlc_mutex_unlock( &sys->surface_lock );
@@ -531,23 +711,27 @@ static int Get(vlc_va_t *va, void **opaque, uint8_t **data)
 
 static void Release(void *opaque, uint8_t *data)
 {
-    vlc_va_surface_t *surface = opaque;
-    if ( surface->p_lock )
-        vlc_mutex_lock( surface->p_lock );
+    VLC_UNUSED( data );
 
-    surface->refcount--;
-    (void) data;
+    struct dxva_opaque *p_output = opaque;
+    if ( p_output->p_dxva_surface->p_lock )
+        vlc_mutex_lock( p_output->p_dxva_surface->p_lock );
 
-    if ( surface->p_lock )
-        vlc_mutex_unlock( surface->p_lock );
+    p_output->p_dxva_surface->refcount--;
+    p_output->p_dxva_surface->order = p_output->p_sys->surface_order++;
+
+    if ( p_output->p_dxva_surface->p_lock )
+        vlc_mutex_unlock( p_output->p_dxva_surface->p_lock );
+
+    free( p_output );
 }
 
 static void Close(vlc_va_t *va, AVCodecContext *ctx)
 {
+    VLC_UNUSED( ctx );
+
     vlc_va_sys_t *sys = va->sys;
 
-    (void) ctx;
-    DxDestroyVideoConversion(sys);
     DxDestroyVideoDecoder(sys);
     DxDestroyVideoService(sys);
     D3dDestroyDeviceManager(sys);
@@ -566,6 +750,8 @@ static void Close(vlc_va_t *va, AVCodecContext *ctx)
 
 static int Open(vlc_va_t *va, AVCodecContext *ctx, const es_format_t *fmt)
 {
+    VLC_UNUSED( fmt );
+
     vlc_va_sys_t *sys = calloc(1, sizeof (*sys));
     if (unlikely(sys == NULL))
         return VLC_ENOMEM;
@@ -609,7 +795,7 @@ static int Open(vlc_va_t *va, AVCodecContext *ctx, const es_format_t *fmt)
     }
 
     /* */
-    if (DxFindVideoServiceConversion(va, &sys->input, &sys->render)) {
+    if (DxFindVideoServiceConversion(va, &sys->input, &sys->p_render)) {
         msg_Err(va, "DxFindVideoServiceConversion failed");
         goto error;
     }
@@ -663,6 +849,35 @@ static int D3dCreateDevice(vlc_va_t *va)
         ZeroMemory(d3dai, sizeof(*d3dai));
     }
 
+    /*
+    ** Get the current desktop display mode, so we can set up a back
+    ** buffer of the same format
+    */
+    D3DDISPLAYMODE d3ddm;
+    HRESULT hr = IDirect3D9_GetAdapterDisplayMode(sys->d3dobj,
+                                                  D3DADAPTER_DEFAULT, &d3ddm);
+    if (FAILED(hr)) {
+       msg_Err(va, "Could not read adapter display mode. (hr=0x%0lx)", hr);
+       return VLC_EGENERIC;
+    }
+
+    UINT AdapterToUse = D3DADAPTER_DEFAULT;
+    D3DDEVTYPE DeviceType = D3DDEVTYPE_HAL;
+
+#ifndef NDEBUG
+    // Look for 'NVIDIA PerfHUD' adapter
+    // If it is present, override default settings
+    for (UINT Adapter=0; Adapter< IDirect3D9_GetAdapterCount(d3dobj); ++Adapter) {
+        D3DADAPTER_IDENTIFIER9 Identifier;
+        HRESULT Res = IDirect3D9_GetAdapterIdentifier(d3dobj,Adapter,0,&Identifier);
+        if (SUCCEEDED(Res) && strstr(Identifier.Description,"PerfHUD") != 0) {
+            AdapterToUse = Adapter;
+            DeviceType = D3DDEVTYPE_REF;
+            break;
+        }
+    }
+#endif
+
     /* */
     D3DPRESENT_PARAMETERS *d3dpp = &sys->d3dpp;
     ZeroMemory(d3dpp, sizeof(*d3dpp));
@@ -672,18 +887,20 @@ static int D3dCreateDevice(vlc_va_t *va)
     d3dpp->SwapEffect             = D3DSWAPEFFECT_DISCARD;
     d3dpp->MultiSampleType        = D3DMULTISAMPLE_NONE;
     d3dpp->PresentationInterval   = D3DPRESENT_INTERVAL_DEFAULT;
-    d3dpp->BackBufferCount        = 0;                  /* FIXME what to put here */
-    d3dpp->BackBufferFormat       = D3DFMT_X8R8G8B8;    /* FIXME what to put here */
-    d3dpp->BackBufferWidth        = 0;
-    d3dpp->BackBufferHeight       = 0;
+    d3dpp->BackBufferCount        = 1;
+    d3dpp->BackBufferFormat       = d3ddm.Format;
+    d3dpp->BackBufferWidth        = __MAX((unsigned int)GetSystemMetrics(SM_CXVIRTUALSCREEN),
+                                          d3ddm.Width);
+    d3dpp->BackBufferHeight       = __MAX((unsigned int)GetSystemMetrics(SM_CYVIRTUALSCREEN),
+                                          d3ddm.Height);
     d3dpp->EnableAutoDepthStencil = FALSE;
 
     /* Direct3D needs a HWND to create a device, even without using ::Present
     this HWND is used to alert Direct3D when there's a change of focus window.
     For now, use GetDesktopWindow, as it looks harmless */
     LPDIRECT3DDEVICE9 d3ddev;
-    if (FAILED(IDirect3D9_CreateDevice(d3dobj, D3DADAPTER_DEFAULT,
-                                       D3DDEVTYPE_HAL, GetDesktopWindow(),
+    if (FAILED(IDirect3D9_CreateDevice(d3dobj, AdapterToUse,
+                                       DeviceType, d3dpp->hDeviceWindow,
                                        D3DCREATE_SOFTWARE_VERTEXPROCESSING |
                                        D3DCREATE_MULTITHREADED,
                                        d3dpp, &d3ddev))) {
@@ -838,7 +1055,7 @@ static void DxDestroyVideoService(vlc_va_sys_t *va)
 /**
  * Find the best suited decoder mode GUID and render format.
  */
-static int DxFindVideoServiceConversion(vlc_va_t *va, GUID *input, D3DFORMAT *output)
+static int DxFindVideoServiceConversion(vlc_va_t *va, GUID *input, const d3d_format_t **output)
 {
     vlc_va_sys_t *sys = va->sys;
 
@@ -951,7 +1168,7 @@ static int DxFindVideoServiceConversion(vlc_va_t *va, GUID *input, D3DFORMAT *ou
             /* We have our solution */
             msg_Dbg(va, "Using '%s' to decode to '%s'", mode->name, format->name);
             *input  = *mode->guid;
-            *output = format->format;
+            *output = format;
             CoTaskMemFree(output_list);
             CoTaskMemFree(input_list);
             return VLC_SUCCESS;
@@ -1018,7 +1235,7 @@ static int DxCreateVideoDecoder(vlc_va_t *va, int codec_id,
                                                          sys->surface_width,
                                                          sys->surface_height,
                                                          sys->surface_count - 1,
-                                                         sys->render,
+                                                         sys->p_render->format,
                                                          D3DPOOL_DEFAULT,
                                                          0,
                                                          DXVA2_VideoDecoderRenderTarget,
@@ -1029,13 +1246,16 @@ static int DxCreateVideoDecoder(vlc_va_t *va, int codec_id,
         return VLC_EGENERIC;
     }
     for (unsigned i = 0; i < sys->surface_count; i++) {
-        vlc_va_surface_t *surface = &sys->surface[i];
-        surface->d3d = sys->hw_surface[i];
-        surface->refcount = 0;
-        surface->order = 0;
+        picture_sys_t *p_picture = &sys->surface[i];
+        p_picture->surface = sys->hw_surface[i];
+        p_picture->surface_device = sys->d3ddev;
+        p_picture->refcount = 0;
+        p_picture->index = i;
+        p_picture->order = i;
         if ( sys->b_thread_safe )
-            surface->p_lock = &sys->surface_lock;
+            p_picture->p_lock = &sys->surface_lock;
     }
+    sys->surface_order = sys->surface_count;
     msg_Dbg(va, "IDirectXVideoAccelerationService_CreateSurface succeed with %d surfaces (%dx%d)",
             sys->surface_count, fmt->i_width, fmt->i_height);
 
@@ -1044,7 +1264,7 @@ static int DxCreateVideoDecoder(vlc_va_t *va, int codec_id,
     ZeroMemory(&dsc, sizeof(dsc));
     dsc.SampleWidth     = fmt->i_width;
     dsc.SampleHeight    = fmt->i_height;
-    dsc.Format          = sys->render;
+    dsc.Format          = sys->p_render->format;
     if (fmt->i_frame_rate > 0 && fmt->i_frame_rate_base > 0) {
         dsc.InputSampleFreq.Numerator   = fmt->i_frame_rate;
         dsc.InputSampleFreq.Denominator = fmt->i_frame_rate_base;
@@ -1139,7 +1359,7 @@ static void DxDestroyVideoDecoder(vlc_va_sys_t *va)
     va->decoder = NULL;
 
     for (unsigned i = 0; i < va->surface_count; i++)
-        IDirect3DSurface9_Release(va->surface[i].d3d);
+        IDirect3DSurface9_Release( va->hw_surface[i] );
     va->surface_count = 0;
 }
 
@@ -1149,21 +1369,37 @@ static int DxResetVideoDecoder(vlc_va_t *va)
     return VLC_EGENERIC;
 }
 
-static void DxCreateVideoConversion(vlc_va_sys_t *va)
+VIDEO_FILTER_WRAPPER (DXA9_I420)
+
+static int OpenConverter( vlc_object_t *obj )
 {
-    switch (va->render) {
-    case MAKEFOURCC('N','V','1','2'):
-    case MAKEFOURCC('I','M','C','3'):
-        va->output = MAKEFOURCC('Y','V','1','2');
-        break;
-    default:
-        va->output = va->render;
-        break;
-    }
-    CopyInitCache(&va->surface_cache, va->surface_width);
+    filter_t *p_filter = (filter_t *)obj;
+    if ( p_filter->fmt_in.video.i_height != p_filter->fmt_out.video.i_height
+         || p_filter->fmt_in.video.i_width != p_filter->fmt_out.video.i_width )
+        return VLC_EGENERIC;
+
+    if ( p_filter->fmt_out.video.i_chroma != VLC_CODEC_I420
+         && p_filter->fmt_out.video.i_chroma != VLC_CODEC_YV12
+         && p_filter->fmt_out.video.i_chroma != VLC_CODEC_NV12 )
+        return VLC_EGENERIC;
+
+    if ( p_filter->fmt_in.video.i_chroma == VLC_CODEC_D3D9_OPAQUE )
+        p_filter->pf_video_filter = DXA9_I420_Filter;
+    else
+        return VLC_EGENERIC;
+
+    copy_cache_t *p_copy_cache = calloc(1, sizeof(*p_copy_cache));
+    CopyInitCache(p_copy_cache, p_filter->fmt_in.video.i_width );
+    p_filter->p_sys = (filter_sys_t*) p_copy_cache;
+
+    return VLC_SUCCESS;
 }
 
-static void DxDestroyVideoConversion(vlc_va_sys_t *va)
+static void CloseConverter( vlc_object_t *obj )
 {
-    CopyCleanCache(&va->surface_cache);
+    filter_t *p_filter = (filter_t *)obj;
+    copy_cache_t *p_copy_cache = (copy_cache_t*) p_filter->p_sys;
+    CopyCleanCache(p_copy_cache);
+    free( p_copy_cache );
+    p_filter->p_sys = NULL;
 }
diff --git a/modules/codec/avcodec/dxva2.h b/modules/codec/avcodec/dxva2.h
new file mode 100644
index 0000000..b4fd0ff
--- /dev/null
+++ b/modules/codec/avcodec/dxva2.h
@@ -0,0 +1,69 @@
+/*****************************************************************************
+ * dxva2.c: Video Acceleration helpers
+ *****************************************************************************
+ * Copyright (C) 2009 Geoffroy Couprie
+ * Copyright (C) 2009 Laurent Aimar
+ * $Id$
+ *
+ * Authors: Geoffroy Couprie <geal at videolan.org>
+ *          Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
+ *
+ * This program 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.
+ *
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifndef AVCODEC_DXVA2_H_
+#define AVCODEC_DXVA2_H_
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+# if _WIN32_WINNT < 0x600
+/* dxva2 needs Vista support */
+#  undef _WIN32_WINNT
+#  define _WIN32_WINNT 0x600
+# endif
+
+#include <vlc_common.h>
+#include <vlc_picture.h>
+
+#include "va.h"
+
+#include <d3d9.h>
+
+struct picture_pool_setup_sys_t {
+    vlc_va_sys_t           *p_va_sys;
+    /* shared objects between the decoder and the d3d9 vout */
+    LPDIRECT3D9            d3dobj;
+    LPDIRECT3DDEVICE9      d3ddev;
+    D3DPRESENT_PARAMETERS  d3dpp;
+};
+
+struct picture_sys_t
+{
+    LPDIRECT3DSURFACE9 surface;
+    LPDIRECT3DDEVICE9  surface_device;
+
+    /* D3D9 vout stuff */
+    picture_t          *fallback;
+
+    /* DXVA2 decoder stuff */
+    int                refcount;
+    unsigned int       order;
+    unsigned int       index;
+    vlc_mutex_t        *p_lock;
+};
+
+#endif /* AVCODEC_DXVA2_H_ */
diff --git a/modules/codec/avcodec/video.c b/modules/codec/avcodec/video.c
index fbbd719..1790587 100644
--- a/modules/codec/avcodec/video.c
+++ b/modules/codec/avcodec/video.c
@@ -396,21 +396,6 @@ int InitVideoDec( decoder_t *p_dec, AVCodecContext *p_context,
             break;
     }
 
-    /* Workaround: frame multithreading is not compatible with
-     * DXVA2. When a frame is being copied to host memory, the frame
-     * is locked and cannot be used as a reference frame
-     * simultaneously and thus decoding fails for some frames. This
-     * causes major image corruption. */
-# if defined(_WIN32)
-    char *avcodec_hw = var_InheritString( p_dec, "avcodec-hw" );
-    if( avcodec_hw == NULL || strcasecmp( avcodec_hw, "none" ) )
-    {
-        msg_Warn( p_dec, "threaded frame decoding is not compatible with DXVA2, disabled" );
-        p_context->thread_type &= ~FF_THREAD_FRAME;
-    }
-    free( avcodec_hw );
-# endif
-
     if( p_context->thread_type & FF_THREAD_FRAME )
         p_dec->i_extra_picture_buffers = 2 * p_context->thread_count;
 #endif
diff --git a/modules/video_output/msw/direct3d9.c b/modules/video_output/msw/direct3d9.c
index db96275..20943b9 100644
--- a/modules/video_output/msw/direct3d9.c
+++ b/modules/video_output/msw/direct3d9.c
@@ -50,6 +50,7 @@
 
 #include "common.h"
 #include "builtin_shaders.h"
+#include "../../codec/avcodec/dxva2.h"
 
 /*****************************************************************************
  * Module descriptor
@@ -104,12 +105,6 @@ static const vlc_fourcc_t d3d_subpicture_chromas[] = {
     0
 };
 
-struct picture_sys_t
-{
-    LPDIRECT3DSURFACE9 surface;
-    picture_t          *fallback;
-};
-
 static int  Open(vlc_object_t *);
 
 static picture_pool_t *Pool  (vout_display_t *, unsigned);
@@ -202,10 +197,10 @@ static int Open(vlc_object_t *object)
 
     /* */
     vout_display_info_t info = vd->info;
-    info.is_slow = true;
+    info.is_slow = fmt.i_chroma != VLC_CODEC_D3D9_OPAQUE;
     info.has_double_click = true;
     info.has_hide_mouse = false;
-    info.has_pictures_invalid = true;
+    info.has_pictures_invalid = fmt.i_chroma != VLC_CODEC_D3D9_OPAQUE;
     info.has_event_thread = true;
     if (var_InheritBool(vd, "direct3d9-hw-blending") &&
         sys->d3dregion_format != D3DFMT_UNKNOWN &&
@@ -274,7 +269,18 @@ static void Close(vlc_object_t *object)
 /* */
 static picture_pool_t *Pool(vout_display_t *vd, unsigned count)
 {
-    VLC_UNUSED(count);
+    if ( vd->sys->pool == NULL )
+    {
+        const picture_pool_configuration_t *conf = NULL;
+        if ( vd->sys->pool == NULL && vd->cfg->p_pool_setup->pf_create_config)
+            conf = vd->cfg->p_pool_setup->pf_create_config( vd->cfg->p_pool_setup->p_sys, &vd->fmt, count);
+
+        if ( conf != NULL )
+            vd->sys->pool = picture_pool_NewExtended( conf );
+        else
+            vd->sys->pool = picture_pool_NewFromFormat( &vd->fmt, count);
+    }
+
     return vd->sys->pool;
 }
 
@@ -283,21 +289,18 @@ static void Direct3D9UnlockSurface(picture_t *);
 
 static void Prepare(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture)
 {
+    VLC_UNUSED(subpicture);
+
     vout_display_sys_t *sys = vd->sys;
     LPDIRECT3DSURFACE9 surface = picture->p_sys->surface;
-#if 0
-    picture_Release(picture);
-    VLC_UNUSED(subpicture);
-#else
+
     /* FIXME it is a bit ugly, we need the surface to be unlocked for
      * rendering.
      *  The clean way would be to release the picture (and ensure that
      * the vout doesn't keep a reference). But because of the vout
      * wrapper, we can't */
-
-    Direct3D9UnlockSurface(picture);
-    VLC_UNUSED(subpicture);
-#endif
+    if ( picture->format.i_chroma != VLC_CODEC_D3D9_OPAQUE )
+        Direct3D9UnlockSurface(picture);
 
     /* check if device is still available */
     HRESULT hr = IDirect3DDevice9_TestCooperativeLevel(sys->d3ddev);
@@ -335,6 +338,8 @@ static void Prepare(vout_display_t *vd, picture_t *picture, subpicture_t *subpic
 
 static void Display(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture)
 {
+    VLC_UNUSED(subpicture);
+
     vout_display_sys_t *sys = vd->sys;
     LPDIRECT3DDEVICE9 d3ddev = sys->d3ddev;
 
@@ -349,19 +354,15 @@ static void Display(vout_display_t *vd, picture_t *picture, subpicture_t *subpic
     // No stretching should happen here !
     const RECT src = sys->rect_dest_clipped;
     const RECT dst = sys->rect_dest_clipped;
-    HRESULT hr = IDirect3DDevice9_Present(d3ddev, &src, &dst, NULL, NULL);
+    HRESULT hr = IDirect3DDevice9_Present(d3ddev, &src, &dst, sys->hvideownd, NULL);
     if (FAILED(hr)) {
         msg_Dbg(vd, "Failed IDirect3DDevice9_Present: 0x%0lx", hr);
     }
 
-#if 0
-    VLC_UNUSED(picture);
-    VLC_UNUSED(subpicture);
-#else
     /* XXX See Prepare() */
-    Direct3D9LockSurface(picture);
+    if ( picture->format.i_chroma != VLC_CODEC_D3D9_OPAQUE )
+        Direct3D9LockSurface(picture);
     picture_Release(picture);
-#endif
     if (subpicture)
         subpicture_Delete(subpicture);
 
@@ -534,21 +535,33 @@ static int Direct3D9Create(vout_display_t *vd)
         return VLC_EGENERIC;
     }
 
-    LPDIRECT3D9 (WINAPI *OurDirect3DCreate9)(UINT SDKVersion);
-    OurDirect3DCreate9 =
-        (void *)GetProcAddress(sys->hd3d9_dll, "Direct3DCreate9");
-    if (!OurDirect3DCreate9) {
-        msg_Err(vd, "Cannot locate reference to Direct3DCreate9 ABI in DLL");
-        return VLC_EGENERIC;
+    if ( vd->fmt.i_chroma == VLC_CODEC_D3D9_OPAQUE &&
+         vd->cfg->p_pool_setup != NULL &&
+         vd->cfg->p_pool_setup->p_sys != NULL )
+    {
+        sys->d3dobj = vd->cfg->p_pool_setup->p_sys->d3dobj;
     }
 
-    /* Create the D3D object. */
-    LPDIRECT3D9 d3dobj = OurDirect3DCreate9(D3D_SDK_VERSION);
-    if (!d3dobj) {
-       msg_Err(vd, "Could not create Direct3D9 instance.");
-       return VLC_EGENERIC;
+    if ( sys->d3dobj == NULL )
+    {
+        LPDIRECT3D9 (WINAPI *OurDirect3DCreate9)(UINT SDKVersion);
+        OurDirect3DCreate9 =
+            (void *)GetProcAddress(sys->hd3d9_dll, "Direct3DCreate9");
+        if (!OurDirect3DCreate9) {
+            msg_Err(vd, "Cannot locate reference to Direct3DCreate9 ABI in DLL");
+            return VLC_EGENERIC;
+        }
+
+        /* Create the D3D object. */
+        LPDIRECT3D9 d3dobj = OurDirect3DCreate9(D3D_SDK_VERSION);
+        if (!d3dobj) {
+           msg_Err(vd, "Could not create Direct3D9 instance.");
+           return VLC_EGENERIC;
+        }
+        sys->d3dobj = d3dobj;
+    } else {
+        IDirect3D9_AddRef( sys->d3dobj );
     }
-    sys->d3dobj = d3dobj;
 
     sys->hd3d9x_dll = Direct3D9LoadShaderLibrary();
     if (!sys->hd3d9x_dll)
@@ -558,7 +571,7 @@ static int Direct3D9Create(vout_display_t *vd)
     ** Get device capabilities
     */
     ZeroMemory(&sys->d3dcaps, sizeof(sys->d3dcaps));
-    HRESULT hr = IDirect3D9_GetDeviceCaps(d3dobj, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &sys->d3dcaps);
+    HRESULT hr = IDirect3D9_GetDeviceCaps(sys->d3dobj, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &sys->d3dcaps);
     if (FAILED(hr)) {
        msg_Err(vd, "Could not read adapter capabilities. (hr=0x%0lx)", hr);
        return VLC_EGENERIC;
@@ -657,45 +670,58 @@ static int Direct3D9Open(vout_display_t *vd, video_format_t *fmt)
     if (Direct3D9FillPresentationParameters(vd))
         return VLC_EGENERIC;
 
-    // Create the D3DDevice
-    LPDIRECT3DDEVICE9 d3ddev;
+    if ( vd->fmt.i_chroma == VLC_CODEC_D3D9_OPAQUE &&
+         vd->cfg->p_pool_setup != NULL &&
+         vd->cfg->p_pool_setup->p_sys != NULL )
+    {
+        sys->d3ddev = vd->cfg->p_pool_setup->p_sys->d3ddev;
+        sys->d3dpp  = vd->cfg->p_pool_setup->p_sys->d3dpp;
+    }
+
+    if ( sys->d3ddev == NULL )
+    {
+        // Create the D3DDevice
+        LPDIRECT3DDEVICE9 d3ddev;
 
-    UINT AdapterToUse = D3DADAPTER_DEFAULT;
-    D3DDEVTYPE DeviceType = D3DDEVTYPE_HAL;
+        UINT AdapterToUse = D3DADAPTER_DEFAULT;
+        D3DDEVTYPE DeviceType = D3DDEVTYPE_HAL;
 
 #ifndef NDEBUG
-    // Look for 'NVIDIA PerfHUD' adapter
-    // If it is present, override default settings
-    for (UINT Adapter=0; Adapter< IDirect3D9_GetAdapterCount(d3dobj); ++Adapter) {
-        D3DADAPTER_IDENTIFIER9 Identifier;
-        HRESULT Res = IDirect3D9_GetAdapterIdentifier(d3dobj,Adapter,0,&Identifier);
-        if (SUCCEEDED(Res) && strstr(Identifier.Description,"PerfHUD") != 0) {
-            AdapterToUse = Adapter;
-            DeviceType = D3DDEVTYPE_REF;
-            break;
+        // Look for 'NVIDIA PerfHUD' adapter
+        // If it is present, override default settings
+        for (UINT Adapter=0; Adapter< IDirect3D9_GetAdapterCount(d3dobj); ++Adapter) {
+            D3DADAPTER_IDENTIFIER9 Identifier;
+            HRESULT Res = IDirect3D9_GetAdapterIdentifier(d3dobj,Adapter,0,&Identifier);
+            if (SUCCEEDED(Res) && strstr(Identifier.Description,"PerfHUD") != 0) {
+                AdapterToUse = Adapter;
+                DeviceType = D3DDEVTYPE_REF;
+                break;
+            }
         }
-    }
 #endif
 
-    /* */
-    D3DADAPTER_IDENTIFIER9 d3dai;
-    if (FAILED(IDirect3D9_GetAdapterIdentifier(d3dobj,AdapterToUse,0, &d3dai))) {
-        msg_Warn(vd, "IDirect3D9_GetAdapterIdentifier failed");
-    } else {
-        msg_Dbg(vd, "Direct3d9 Device: %s %lu %lu %lu", d3dai.Description,
-                d3dai.VendorId, d3dai.DeviceId, d3dai.Revision );
-    }
+        /* */
+        D3DADAPTER_IDENTIFIER9 d3dai;
+        if (FAILED(IDirect3D9_GetAdapterIdentifier(d3dobj,AdapterToUse,0, &d3dai))) {
+            msg_Warn(vd, "IDirect3D9_GetAdapterIdentifier failed");
+        } else {
+            msg_Dbg(vd, "Direct3d9 Device: %s %lu %lu %lu", d3dai.Description,
+                    d3dai.VendorId, d3dai.DeviceId, d3dai.Revision );
+        }
 
-    HRESULT hr = IDirect3D9_CreateDevice(d3dobj, AdapterToUse,
-                                         DeviceType, sys->hvideownd,
-                                         D3DCREATE_SOFTWARE_VERTEXPROCESSING|
-                                         D3DCREATE_MULTITHREADED,
-                                         &sys->d3dpp, &d3ddev);
-    if (FAILED(hr)) {
-       msg_Err(vd, "Could not create the D3D9 device! (hr=0x%0lx)", hr);
-       return VLC_EGENERIC;
+        HRESULT hr = IDirect3D9_CreateDevice(d3dobj, AdapterToUse,
+                                             DeviceType, sys->hvideownd,
+                                             D3DCREATE_SOFTWARE_VERTEXPROCESSING|
+                                             D3DCREATE_MULTITHREADED,
+                                             &sys->d3dpp, &d3ddev);
+        if (FAILED(hr)) {
+           msg_Err(vd, "Could not create the D3D9 device! (hr=0x%0lx)", hr);
+           return VLC_EGENERIC;
+        }
+        sys->d3ddev = d3ddev;
+    } else {
+        IDirect3DDevice9_AddRef( sys->d3ddev );
     }
-    sys->d3ddev = d3ddev;
 
     UpdateRects(vd, NULL, NULL, true);
 
@@ -860,6 +886,7 @@ static const d3d_format_t d3d_formats[] = {
     { "YV12",       MAKEFOURCC('Y','V','1','2'),    VLC_CODEC_I420,  0,0,0 },
     { "YV12",       MAKEFOURCC('Y','V','1','2'),    VLC_CODEC_J420,  0,0,0 },
     { "NV12",       MAKEFOURCC('N','V','1','2'),    VLC_CODEC_NV12,  0,0,0 },
+    { "DXVANV12",   MAKEFOURCC('N','V','1','2'),    VLC_CODEC_D3D9_OPAQUE,  0,0,0 },
     { "UYVY",       D3DFMT_UYVY,    VLC_CODEC_UYVY,  0,0,0 },
     { "YUY2",       D3DFMT_YUY2,    VLC_CODEC_YUYV,  0,0,0 },
     { "X8R8G8B8",   D3DFMT_X8R8G8B8,VLC_CODEC_RGB32, 0xff0000, 0x00ff00, 0x0000ff },
@@ -879,8 +906,11 @@ static const d3d_format_t *Direct3DFindFormat(vout_display_t *vd, vlc_fourcc_t c
 
     for (unsigned pass = 0; pass < 2; pass++) {
         const vlc_fourcc_t *list;
+        const vlc_fourcc_t dxva_chroma[] = {chroma, 0};
 
-        if (pass == 0 && sys->allow_hw_yuv && vlc_fourcc_IsYUV(chroma))
+        if (pass == 0 && chroma == VLC_CODEC_D3D9_OPAQUE)
+            list = dxva_chroma;
+        else if (pass == 0 && sys->allow_hw_yuv && vlc_fourcc_IsYUV(chroma))
             list = vlc_fourcc_GetYUVFallback(chroma);
         else if (pass == 1)
             list = vlc_fourcc_GetRGBFallback(chroma);
@@ -968,64 +998,76 @@ static int Direct3D9CreatePool(vout_display_t *vd, video_format_t *fmt)
 
     /* We create one picture.
      * It is useless to create more as we can't be used for direct rendering */
-
-    /* Create a surface */
-    LPDIRECT3DSURFACE9 surface;
-    HRESULT hr = IDirect3DDevice9_CreateOffscreenPlainSurface(d3ddev,
-                                                              fmt->i_visible_width,
-                                                              fmt->i_visible_height,
-                                                              d3dfmt->format,
-                                                              D3DPOOL_DEFAULT,
-                                                              &surface,
-                                                              NULL);
-    if (FAILED(hr)) {
-        msg_Err(vd, "Failed to create picture surface. (hr=0x%lx)", hr);
-        return VLC_EGENERIC;
+    if ( fmt->i_chroma == VLC_CODEC_D3D9_OPAQUE &&
+         vd->cfg->p_pool_setup != NULL &&
+         vd->cfg->p_pool_setup->p_sys != NULL &&
+         vd->cfg->p_pool_setup->p_sys->p_va_sys != NULL )
+    {
+        sys->pool = NULL;
     }
+    else
+    {
+        /* Create a surface */
+        LPDIRECT3DSURFACE9 surface;
+        HRESULT hr = IDirect3DDevice9_CreateOffscreenPlainSurface(d3ddev,
+                                                                  fmt->i_visible_width,
+                                                                  fmt->i_visible_height,
+                                                                  d3dfmt->format,
+                                                                  D3DPOOL_DEFAULT,
+                                                                  &surface,
+                                                                  NULL);
+        if (FAILED(hr)) {
+            msg_Err(vd, "Failed to create picture surface. (hr=0x%lx)", hr);
+            return VLC_EGENERIC;
+        }
 
 #ifndef NDEBUG
-    msg_Dbg(vd, "Direct3D created offscreen surface: %ix%i",
-                fmt->i_visible_width, fmt->i_visible_height);
+        msg_Dbg(vd, "Direct3D created offscreen surface: %ix%i",
+                    fmt->i_visible_width, fmt->i_visible_height);
 #endif
 
-    /* fill surface with black color */
-    IDirect3DDevice9_ColorFill(d3ddev, surface, NULL, D3DCOLOR_ARGB(0xFF, 0, 0, 0));
+        /* fill surface with black color */
+        IDirect3DDevice9_ColorFill(d3ddev, surface, NULL, D3DCOLOR_ARGB(0xFF, 0, 0, 0));
 
-    /* Create the associated picture */
-    picture_sys_t *picsys = malloc(sizeof(*picsys));
-    if (unlikely(picsys == NULL)) {
-        IDirect3DSurface9_Release(surface);
-        return VLC_ENOMEM;
-    }
-    picsys->surface = surface;
-    picsys->fallback = NULL;
-
-    picture_resource_t resource = { .p_sys = picsys };
-    for (int i = 0; i < PICTURE_PLANE_MAX; i++)
-        resource.p[i].i_lines = fmt->i_visible_height / (i > 0 ? 2 : 1);
-
-    picture_t *picture = picture_NewFromResource(fmt, &resource);
-    if (!picture) {
-        msg_Err(vd, "Failed to create a picture from resources.");
-        IDirect3DSurface9_Release(surface);
-        free(picsys);
-        return VLC_ENOMEM;
-    }
-    sys->picsys = picsys;
-
-    /* Wrap it into a picture pool */
-    picture_pool_configuration_t pool_cfg;
-    memset(&pool_cfg, 0, sizeof(pool_cfg));
-    pool_cfg.picture_count = 1;
-    pool_cfg.picture       = &picture;
-    pool_cfg.lock          = Direct3D9LockSurface;
-    pool_cfg.unlock        = Direct3D9UnlockSurface;
+        /* Create the associated picture */
+        picture_sys_t *picsys = calloc(1, sizeof(*picsys));
+        if (unlikely(picsys == NULL)) {
+            IDirect3DSurface9_Release(surface);
+            return VLC_ENOMEM;
+        }
+        picsys->surface = surface;
+        picsys->surface_device = d3ddev;
+
+        picture_resource_t resource = { .p_sys = picsys };
+        for (int i = 0; i < PICTURE_PLANE_MAX; i++)
+            resource.p[i].i_lines = fmt->i_visible_height / (i > 0 ? 2 : 1);
+
+        picture_t *picture = picture_NewFromResource(fmt, &resource);
+        if (!picture) {
+            msg_Err(vd, "Failed to create a picture from resources.");
+            IDirect3DSurface9_Release(surface);
+            free(picsys);
+            return VLC_ENOMEM;
+        }
+        sys->picsys = picsys;
+
+        /* Wrap it into a picture pool */
+        picture_pool_configuration_t pool_cfg;
+        memset(&pool_cfg, 0, sizeof(pool_cfg));
+        pool_cfg.picture_count = 1;
+        pool_cfg.picture       = &picture;
+        if (fmt->i_chroma != VLC_CODEC_D3D9_OPAQUE)
+        {
+            pool_cfg.lock      = Direct3D9LockSurface;
+            pool_cfg.unlock    = Direct3D9UnlockSurface;
+        }
 
-    sys->pool = picture_pool_NewExtended(&pool_cfg);
-    if (!sys->pool) {
-        picture_Release(picture);
-        IDirect3DSurface9_Release(surface);
-        return VLC_ENOMEM;
+        sys->pool = picture_pool_NewExtended(&pool_cfg);
+        if (!sys->pool) {
+            picture_Release(picture);
+            IDirect3DSurface9_Release(surface);
+            return VLC_ENOMEM;
+        }
     }
     return VLC_SUCCESS;
 }
@@ -1038,9 +1080,12 @@ static void Direct3D9DestroyPool(vout_display_t *vd)
 
     if (sys->pool) {
         picture_sys_t *picsys = sys->picsys;
-        IDirect3DSurface9_Release(picsys->surface);
-        if (picsys->fallback)
-            picture_Release(picsys->fallback);
+        if ( picsys != NULL )
+        {
+            IDirect3DSurface9_Release(picsys->surface);
+            if (picsys->fallback)
+                picture_Release(picsys->fallback);
+        }
         picture_pool_Release(sys->pool);
     }
     sys->pool = NULL;
diff --git a/src/misc/fourcc.c b/src/misc/fourcc.c
index 3b5c9b3..032a12c 100644
--- a/src/misc/fourcc.c
+++ b/src/misc/fourcc.c
@@ -2193,6 +2193,9 @@ static const struct
     { { VLC_CODEC_ANDROID_OPAQUE, VLC_CODEC_MMAL_OPAQUE, },
                                                FAKE_FMT() },
 
+    { { VLC_CODEC_D3D9_OPAQUE, },
+                                               FAKE_FMT() },
+
     { { 0 },                                   FAKE_FMT() }
 };
 
-- 
2.3.0





More information about the vlc-devel mailing list