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

Jean-Baptiste Kempf jb at videolan.org
Tue Apr 21 18:36:03 CEST 2015


On 20 Apr, Steve Lhomme wrote :
>  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 +

Please split this patch in 3: core, decoder, video output.

The core part looks OK.

> 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"

You should not need this, but vlc_codecs.h

> +static int  OpenConverter( vlc_object_t * );
> +static void CloseConverter( vlc_object_t * );

Converter is usually a bad name, if I may say.

> +    add_submodule()
> +        set_description( N_("DXA9 to I420,YV12,NV12") )

This is hard to translate (aka, impossible).

>  typedef struct {
>      const char   *name;
> -    D3DFORMAT    format;
> -    vlc_fourcc_t codec;
> +    D3DFORMAT    format;    /* D3D format */
> +    vlc_fourcc_t fourcc;    /* VLC fourcc */
>  } d3d_format_t;

Usually, I'd prefer that you split renames in a different patch. :)

> @@ -329,7 +331,7 @@ struct vlc_va_sys_t
>      /* Video service */
>      IDirectXVideoDecoderService  *vs;
>      GUID                         input;
> -    D3DFORMAT                    render;
> +    const d3d_format_t           *p_render;

By curiosity, what was missing in D3DFORMAT ?
This is a change important in the patch, and I am too stupid to see the
reason.

> -    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;

What is this pool_cookie?

> +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 );
> +    }
> +}

What is this function actually doing?
I'd love some comments/documentation on that.

> +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];

VLA? beurk.

> +    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;
> +};

What is this dxva_opaque ?

> -    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));

Unchecked calloc :)

> +    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;
> +};

They are stored in the picture_pool_sys, and not in the picture_sys?

Or are they the same (d3ddev)?

> +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;
> +};

> 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

I do not think this is in the right patch.

> 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

Please split this :)

With my kindest regards,

-- 
Jean-Baptiste Kempf
http://www.jbkempf.com/ - +33 672 704 734
Sent from my Electronic Device



More information about the vlc-devel mailing list