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

Steve Lhomme robux4 at videolabs.io
Mon Apr 20 16:15:19 CEST 2015


Discard this patch, it's missing dxva2.h

On Mon, Apr 20, 2015 at 3:56 PM, Steve Lhomme <robux4 at videolabs.io> wrote:
> 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.
> ---
>  include/vlc_fourcc.h                 |   5 +
>  modules/codec/Makefile.am            |   2 +-
>  modules/codec/avcodec/dxva2.c        | 533 ++++++++++++++++++++++++++---------
>  modules/codec/avcodec/video.c        |  15 -
>  modules/video_output/msw/direct3d9.c | 296 +++++++++++--------
>  src/misc/fourcc.c                    |   3 +
>  6 files changed, 589 insertions(+), 265 deletions(-)
>
> diff --git a/include/vlc_fourcc.h b/include/vlc_fourcc.h
> index 5d30ece..8eecd9e 100644
> --- a/include/vlc_fourcc.h
> +++ b/include/vlc_fourcc.h
> @@ -332,6 +332,11 @@
>  /* 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_DXVA_N_OPAQUE  VLC_FOURCC('D','X','A','9')
> +#define VLC_CODEC_DXVA_Y_OPAQUE  VLC_FOURCC('D','X','Y','9')
> +#define VLC_CODEC_DXVA_I_OPAQUE  VLC_FOURCC('D','X','I','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..6df29c8 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,78 +533,76 @@ 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'):
> +        *chroma = VLC_CODEC_DXVA_N_OPAQUE;
> +        break;
> +    case MAKEFOURCC('Y','V','1','2'):
> +        *chroma = VLC_CODEC_DXVA_Y_OPAQUE;
> +        break;
> +    case MAKEFOURCC('I','M','C','3'):
> +        *chroma = VLC_CODEC_DXVA_I_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;
>  }
>
> +struct dxva_opaque
> +{
> +    picture_sys_t *p_dxva_surface;
> +    vlc_va_sys_t  *p_sys;
> +};
> +
>  static int Extract(vlc_va_t *va, picture_t *picture, void *opaque,
>                     uint8_t *data)
>  {
> -    vlc_va_sys_t *sys = va->sys;
> -    LPDIRECT3DSURFACE9 d3d = (LPDIRECT3DSURFACE9)(uintptr_t)data;
> +    struct dxva_opaque *p_output = opaque;
>
> -    if (!sys->surface_cache.buffer)
> -        return VLC_EGENERIC;
> +    vlc_va_sys_t *sys = va->sys;
> +    LPDIRECT3DSURFACE9 source = (LPDIRECT3DSURFACE9)(uintptr_t)data;
>
> -    /* */
> -    assert(sys->output == MAKEFOURCC('Y','V','1','2'));
> +    LPDIRECT3DSURFACE9 output = picture->p_sys->surface;
>
> -    /* */
> -    D3DLOCKED_RECT lock;
> -    if (FAILED(IDirect3DSurface9_LockRect(d3d, &lock, NULL, D3DLOCK_READONLY))) {
> -        msg_Err(va, "Failed to lock surface");
> -        return VLC_EGENERIC;
> -    }
> +    assert(source == p_output->p_dxva_surface->surface);
>
> -    if (sys->render == MAKEFOURCC('Y','V','1','2') ||
> -        sys->render == MAKEFOURCC('I','M','C','3')) {
> -        bool imc3 = sys->render == MAKEFOURCC('I','M','C','3');
> -        size_t chroma_pitch = imc3 ? lock.Pitch : (lock.Pitch / 2);
> +    picture->pf_copy_private = CopySurface;
>
> -        size_t pitch[3] = {
> -            lock.Pitch,
> -            chroma_pitch,
> -            chroma_pitch,
> -        };
> -
> -        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,
> -        };
> +    /* */
> +    if ( picture->p_sys->p_lock )
> +        vlc_mutex_lock( picture->p_sys->p_lock );
>
> -        if (imc3) {
> -            uint8_t *V = plane[1];
> -            plane[1] = plane[2];
> -            plane[2] = V;
> -        }
> -        CopyFromYv12(picture, plane, pitch, sys->width, sys->height,
> -                     &sys->surface_cache);
> -    } else {
> -        assert(sys->render == MAKEFOURCC('N','V','1','2'));
> -        uint8_t *plane[2] = {
> -            lock.pBits,
> -            (uint8_t*)lock.pBits + lock.Pitch * sys->surface_height
> -        };
> -        size_t  pitch[2] = {
> -            lock.Pitch,
> -            lock.Pitch,
> -        };
> -        CopyFromNv12(picture, plane, pitch, sys->width, sys->height,
> -                     &sys->surface_cache);
> +    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 );
>      }
>
>      /* */
> -    IDirect3DSurface9_UnlockRect(d3d);
> -    (void) opaque;
> +    if ( picture->p_sys->p_lock )
> +        vlc_mutex_unlock( picture->p_sys->p_lock );
> +
>      return VLC_SUCCESS;
>  }
>
> @@ -498,30 +621,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 +655,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 );
> +
> +    struct dxva_opaque *p_output = opaque;
> +    if ( p_output->p_dxva_surface->p_lock )
> +        vlc_mutex_lock( p_output->p_dxva_surface->p_lock );
>
> -    surface->refcount--;
> -    (void) data;
> +    p_output->p_dxva_surface->refcount--;
> +    p_output->p_dxva_surface->order = p_output->p_sys->surface_order++;
>
> -    if ( surface->p_lock )
> -        vlc_mutex_unlock( surface->p_lock );
> +    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 +694,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 +739,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 +793,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 +831,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 +999,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 +1112,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 +1179,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 +1190,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 +1208,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 +1303,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 +1313,138 @@ static int DxResetVideoDecoder(vlc_va_t *va)
>      return VLC_EGENERIC;
>  }
>
> -static void DxCreateVideoConversion(vlc_va_sys_t *va)
> +static void NV12_I420 (filter_t *p_filter, picture_t *src, picture_t *dst)
>  {
> -    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;
> +    copy_cache_t *p_copy_cache = (copy_cache_t*) p_filter->p_sys;
> +
> +    LPDIRECT3DSURFACE9 d3d = src->p_sys->surface;
> +
> +    /* */
> +    D3DLOCKED_RECT lock;
> +    if (FAILED(IDirect3DSurface9_LockRect(d3d, &lock, NULL, D3DLOCK_READONLY))) {
> +        msg_Err(p_filter, "Failed to lock surface");
> +        return;
>      }
> -    CopyInitCache(&va->surface_cache, va->surface_width);
> +
> +    uint8_t *plane[2] = {
> +        lock.pBits,
> +        (uint8_t*)lock.pBits + lock.Pitch * src->format.i_height
> +    };
> +    size_t  pitch[2] = {
> +        lock.Pitch,
> +        lock.Pitch,
> +    };
> +    CopyFromNv12(dst, plane, pitch, src->format.i_width, src->format.i_visible_height,
> +                 p_copy_cache);
> +
> +    /* */
> +    IDirect3DSurface9_UnlockRect(d3d);
> +}
> +
> +static void YV12_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;
> +
> +    /* */
> +    D3DLOCKED_RECT lock;
> +    if (FAILED(IDirect3DSurface9_LockRect(d3d, &lock, NULL, D3DLOCK_READONLY))) {
> +        msg_Err(p_filter, "Failed to lock surface");
> +        return;
> +    }
> +
> +    size_t pitch[3] = {
> +        lock.Pitch,
> +        lock.Pitch / 2,
> +        lock.Pitch / 2,
> +    };
> +
> +    uint8_t *plane[3] = {
> +        (uint8_t*)lock.pBits,
> +        (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,
> +    };
> +
> +    CopyFromYv12(dst, plane, pitch, src->format.i_width, src->format.i_visible_height,
> +                 p_copy_cache);
> +
> +    /* */
> +    IDirect3DSurface9_UnlockRect(d3d);
> +}
> +
> +static void IMC3_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;
> +
> +    /* */
> +    D3DLOCKED_RECT lock;
> +    if (FAILED(IDirect3DSurface9_LockRect(d3d, &lock, NULL, D3DLOCK_READONLY))) {
> +        msg_Err(p_filter, "Failed to lock surface");
> +        return;
> +    }
> +
> +    size_t pitch[3] = {
> +        lock.Pitch,
> +        lock.Pitch,
> +        lock.Pitch,
> +    };
> +
> +    uint8_t *plane[3] = {
> +        (uint8_t*)lock.pBits,
> +        (uint8_t*)lock.pBits + pitch[0] * src->format.i_height
> +                             + pitch[1] * src->format.i_height / 2,
> +        (uint8_t*)lock.pBits + pitch[0] * src->format.i_height,
> +    };
> +
> +    CopyFromYv12(dst, plane, pitch, src->format.i_width, src->format.i_visible_height,
> +                 p_copy_cache);
> +
> +    /* */
> +    IDirect3DSurface9_UnlockRect(d3d);
> +}
> +
> +
> +VIDEO_FILTER_WRAPPER (NV12_I420)
> +VIDEO_FILTER_WRAPPER (YV12_I420)
> +VIDEO_FILTER_WRAPPER (IMC3_I420)
> +
> +static int OpenConverter( vlc_object_t *obj )
> +{
> +    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_DXVA_N_OPAQUE )
> +        p_filter->pf_video_filter = NV12_I420_Filter;
> +    else if ( p_filter->fmt_in.video.i_chroma == VLC_CODEC_DXVA_Y_OPAQUE )
> +        p_filter->pf_video_filter = YV12_I420_Filter;
> +    else if ( p_filter->fmt_in.video.i_chroma == VLC_CODEC_DXVA_I_OPAQUE )
> +        p_filter->pf_video_filter = IMC3_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/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..db6a1ed 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);
> @@ -153,6 +148,9 @@ static void Direct3D9RenderScene(vout_display_t *vd, d3d_region_t *, int, d3d_re
>  /* */
>  static int DesktopCallback(vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void *);
>
> +#define format_is_DXVA(fmt) (fmt == VLC_CODEC_DXVA_N_OPAQUE \
> +    || fmt == VLC_CODEC_DXVA_Y_OPAQUE || fmt == VLC_CODEC_DXVA_I_OPAQUE)
> +
>  /**
>   * It creates a Direct3D vout display.
>   */
> @@ -202,10 +200,10 @@ static int Open(vlc_object_t *object)
>
>      /* */
>      vout_display_info_t info = vd->info;
> -    info.is_slow = true;
> +    info.is_slow = !format_is_DXVA( fmt.i_chroma );
>      info.has_double_click = true;
>      info.has_hide_mouse = false;
> -    info.has_pictures_invalid = true;
> +    info.has_pictures_invalid = !format_is_DXVA( fmt.i_chroma );
>      info.has_event_thread = true;
>      if (var_InheritBool(vd, "direct3d9-hw-blending") &&
>          sys->d3dregion_format != D3DFMT_UNKNOWN &&
> @@ -274,7 +272,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 +292,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 ( !format_is_DXVA( picture->format.i_chroma ) )
> +        Direct3D9UnlockSurface(picture);
>
>      /* check if device is still available */
>      HRESULT hr = IDirect3DDevice9_TestCooperativeLevel(sys->d3ddev);
> @@ -335,6 +341,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 +357,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 ( !format_is_DXVA( picture->format.i_chroma ) )
> +        Direct3D9LockSurface(picture);
>      picture_Release(picture);
> -#endif
>      if (subpicture)
>          subpicture_Delete(subpicture);
>
> @@ -534,21 +538,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 ( format_is_DXVA( vd->fmt.i_chroma ) &&
> +         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 +574,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 +673,58 @@ static int Direct3D9Open(vout_display_t *vd, video_format_t *fmt)
>      if (Direct3D9FillPresentationParameters(vd))
>          return VLC_EGENERIC;
>
> -    // Create the D3DDevice
> -    LPDIRECT3DDEVICE9 d3ddev;
> +    if ( format_is_DXVA( vd->fmt.i_chroma ) &&
> +         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 +889,9 @@ 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_DXVA_N_OPAQUE,  0,0,0 },
> +    { "DXVAYV12",   MAKEFOURCC('Y','V','1','2'),    VLC_CODEC_DXVA_Y_OPAQUE,  0,0,0 },
> +    { "DXVAIMC3",   MAKEFOURCC('I','M','C','3'),    VLC_CODEC_DXVA_I_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 +911,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 && format_is_DXVA( chroma ))
> +            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 +1003,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 ( format_is_DXVA( fmt->i_chroma ) &&
> +         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 (!format_is_DXVA( fmt->i_chroma ))
> +        {
> +            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 +1085,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..330d40c 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_DXVA_N_OPAQUE, VLC_CODEC_DXVA_Y_OPAQUE, VLC_CODEC_DXVA_I_OPAQUE, },
> +                                                FAKE_FMT() },
> +
>      { { 0 },                                   FAKE_FMT() }
>  };
>
> --
> 2.3.0
>
>
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel
>



More information about the vlc-devel mailing list