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

Steve Lhomme robux4 at videolabs.io
Wed Apr 22 10:16:43 CEST 2015


Yes, this is a big patch :)

I can at least split the addition VLC_CODEC_D3D9_OPAQUE into a
separate patch. It's just moving the surface to planes into a filter
rather than doing it internally. That will make the changes related to
the direct rendering more obvious.

On Tue, Apr 21, 2015 at 6:36 PM, Jean-Baptiste Kempf <jb at videolan.org> wrote:
> 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.

When I was using 3 different chroma depending on the surface type, it
was necessary to know which variant was used. It may not be needed
anymore.

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

A pointer to this structure is passed in the picture_pool_setup_t
callback. It contains all the data needed to create the pool of D3D9
surfaces properly. The pointer is valid as long as the va decoder is
alive.

>> +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.

I'll have to check if it's still needed. When the decoder gets
picture_t it does a picture_Copy and push that copy in the vout FIFO.
That's where we copy the pixels from the decoder surface (internal to
avcodec/dxva2) to the decoder pool allocated by vout_wrapper.

>> +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 :)

Oops

>> +    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)?

They are the same.

>> +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.

After this patch is (not going to be) applied, this hack is not needed
anymore. So I suppose it's related but I can split it submit it once
we have a working solution in master.

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

ok



More information about the vlc-devel mailing list