[vlc-devel] [PATCH] [RFC] always output an opaque D3D9 surface from DXVA

Steve Lhomme robux4 at videolabs.io
Mon Apr 27 11:24:52 CEST 2015


On Thu, Apr 23, 2015 at 5:51 PM, Rémi Denis-Courmont <remi at remlab.net> wrote:
> Le jeudi 23 avril 2015, 17:11:19 Steve Lhomme a écrit :
>> This is a test code to show how DXVA direct rendering could be done.
>>
>> When avcodec asks for an AVFrame, the vout and its decoder pool is already
>> created. So we use the D3D9 device from the picture_t coming from that pool
>> to recreate the DXVA2 decoder surface.
>>
>> This is working fine for normal playback, seeking, opening files of
>> same/different dimensions.
>>
>> The decoder of D3D9 surface is created in the vout wrapper (like all the
>> others) but with a dirty hack for now.
>>
>> This code also works with direct rendering to D3D9, not included in this
>> patch.
>>
>> The changes to the other va->Setup callback are not done and it's a
>> temporary test code. ---
>>  include/vlc_fourcc.h            |   3 +
>>  modules/codec/avcodec/dxva2.c   | 173 ++++++++++++++++++++++------
>>  modules/codec/avcodec/va.h      |   6 +-
>>  modules/codec/avcodec/video.c   |  19 +--
>>  modules/video_chroma/copy.c     |  40 +++++--
>>  src/Makefile.am                 |   2 +
>>  src/misc/fourcc.c               |   3 +
>>  src/video_output/vout_wrapper.c |  17 ++-
>>  src/win32/direct3d9_pool.c      | 248
>> ++++++++++++++++++++++++++++++++++++++++ src/win32/direct3d9_pool.h      |
>> 39 +++++++
>>  10 files changed, 491 insertions(+), 59 deletions(-)
>>  create mode 100644 src/win32/direct3d9_pool.c
>>  create mode 100644 src/win32/direct3d9_pool.h
>>
>> diff --git a/include/vlc_fourcc.h b/include/vlc_fourcc.h
>> index 5d30ece..df82f6f 100644
>> --- a/include/vlc_fourcc.h
>> +++ b/include/vlc_fourcc.h
>> @@ -332,6 +332,9 @@
>>  /* Broadcom MMAL opaque buffer type */
>>  #define VLC_CODEC_MMAL_OPAQUE     VLC_FOURCC('M','M','A','L')
>>
>> +/* DXVA2 opaque video surface for use with D3D9 */
>> +#define VLC_CODEC_D3D9_OPAQUE     VLC_FOURCC('D','X','A','9')
>> +
>>  /* Image codec (video) */
>>  #define VLC_CODEC_PNG             VLC_FOURCC('p','n','g',' ')
>>  #define VLC_CODEC_PPM             VLC_FOURCC('p','p','m',' ')
>> diff --git a/modules/codec/avcodec/dxva2.c b/modules/codec/avcodec/dxva2.c
>> index db9820f..4382e24 100644
>> --- a/modules/codec/avcodec/dxva2.c
>> +++ b/modules/codec/avcodec/dxva2.c
>> @@ -42,6 +42,7 @@
>>  #include <vlc_cpu.h>
>>  #include <vlc_plugin.h>
>>  #include <vlc_codecs.h>
>> +#include <vlc_filter.h>
>>
>>  #include <libavcodec/avcodec.h>
>>  #    define DXVA2API_USE_BITFIELDS
>> @@ -55,12 +56,19 @@
>>  static int Open(vlc_va_t *, AVCodecContext *, const es_format_t *);
>>  static void Close(vlc_va_t *, AVCodecContext *);
>>
>> +static int  OpenFilter( vlc_object_t * );
>> +static void CloseFilter( 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_("DXVA2 surface to planes") )
>> +        set_capability( "video filter2", 10 )
>> +        set_callbacks( OpenFilter, CloseFilter )
>>  vlc_module_end()
>>
>>  #include <windows.h>
>> @@ -348,6 +356,11 @@ struct vlc_va_sys_t
>>      LPDIRECT3DSURFACE9 hw_surface[VA_DXVA2_MAX_SURFACE_COUNT];
>>  };
>>
>> +struct picture_sys_t
>> +{
>> +    LPDIRECT3DSURFACE9 surface;
>> +};
>
> You don't need a structure to store a single pointer (assuming you won't be
> adding more stuff).

That means I'd have to cast LPDIRECT3DSURFACE9 to/from picture_sys_t everytime.

>> +
>>  /* */
>>  static int D3dCreateDevice(vlc_va_t *);
>>  static void D3dDestroyDevice(vlc_va_sys_t *);
>> @@ -369,9 +382,49 @@ static void DxCreateVideoConversion(vlc_va_sys_t *);
>>  static void DxDestroyVideoConversion(vlc_va_sys_t *);
>>
>>  /* */
>> -static int Setup(vlc_va_t *va, AVCodecContext *avctx, vlc_fourcc_t *chroma)
>> +static int Setup(vlc_va_t *va, AVCodecContext *avctx, vlc_fourcc_t
>> *chroma, picture_t *p_test_output) {
>>      vlc_va_sys_t *sys = va->sys;
>> +    LPDIRECT3DDEVICE9 picd3ddev = NULL;
>> +    if (p_test_output!=NULL && p_test_output->p_sys)
>> +        IDirect3DSurface9_GetDevice(p_test_output->p_sys->surface,
>> &picd3ddev);
>> +
>> +    if ( picd3ddev != NULL && picd3ddev != sys->d3ddev )
>> +    {
>> +        /* restart the dxva decoder with the appropriate D3D9 device */
>> +        DxDestroyVideoDecoder(sys);
>> +        DxDestroyVideoService(sys);
>> +        D3dDestroyDeviceManager(sys);
>> +        D3dDestroyDevice(sys);
>> +
>> +        if (FAILED(IDirect3DDevice9_GetDirect3D(picd3ddev, &sys->d3dobj)))
>> { +            msg_Err(va, "Can't retrieve the D3D from the device"); +
>>        goto error;
>> +        }
>> +        IDirect3D9_AddRef(sys->d3dobj);
>> +        IDirect3DDevice9_AddRef(picd3ddev);
>> +        sys->d3ddev = picd3ddev;
>> +        msg_Dbg(va, "D3dCreateDevice succeed");
>> +
>> +        if (D3dCreateDeviceManager(va)) {
>> +            msg_Err(va, "D3dCreateDeviceManager failed");
>> +            goto error;
>> +        }
>> +
>> +        if (DxCreateVideoService(va)) {
>> +            msg_Err(va, "DxCreateVideoService failed");
>> +            goto error;
>> +        }
>> +
>> +        /* */
>> +        es_format_t fake_fmt;
>> +        memset(&fake_fmt, 0, sizeof(fake_fmt));
>> +        fake_fmt.i_profile = avctx->profile;
>> +        if (DxFindVideoServiceConversion(va, &sys->input, &sys->render,
>> &fake_fmt)) { +            msg_Err(va, "DxFindVideoServiceConversion
>> failed");
>> +            goto error;
>> +        }
>> +    }
>>
>>      if (sys->width == avctx->coded_width && sys->height ==
>> avctx->coded_height && sys->decoder != NULL)
>> @@ -406,33 +459,40 @@ static int Setup(vlc_va_t *va, AVCodecContext *avctx,
>> vlc_fourcc_t *chroma) /* */
>>  ok:
>>      avctx->hwaccel_context = &sys->hw;
>> -    const d3d_format_t *output = D3dFindFormat(sys->output);
>> -    *chroma = output->codec;
>> +    *chroma = VLC_CODEC_D3D9_OPAQUE;
>>
>>      return VLC_SUCCESS;
>> +
>> +error:
>> +    DxDestroyVideoDecoder(sys);
>> +    DxDestroyVideoService(sys);
>> +    D3dDestroyDeviceManager(sys);
>> +    D3dDestroyDevice(sys);
>> +    return VLC_EGENERIC;
>>  }
>>
>> -static int Extract(vlc_va_t *va, picture_t *picture, uint8_t *data)
>> +static void DXA9_I420 (filter_t *p_filter, picture_t *src, picture_t *dst)
>>  {
>> -    vlc_va_sys_t *sys = va->sys;
>> -    LPDIRECT3DSURFACE9 d3d = (LPDIRECT3DSURFACE9)(uintptr_t)data;
>> +    copy_cache_t *p_copy_cache = (copy_cache_t*) p_filter->p_sys;
>>
>>      if (!sys->surface_cache.buffer)
>>          return VLC_EGENERIC;
>>
>> -    /* */
>> -    assert(sys->output == MAKEFOURCC('Y','V','1','2'));
>> +    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] = {
>> @@ -443,9 +503,9 @@ static int Extract(vlc_va_t *va, picture_t *picture,
>> uint8_t *data)
>>
>>          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) {
>> @@ -453,24 +513,49 @@ static int Extract(vlc_va_t *va, picture_t *picture,
>> uint8_t *data) 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'));
>> +        CopyFromYv12(dst, plane, pitch, src->format.i_width,
>> src->format.i_visible_height, +                     p_copy_cache);
>> +    } else if (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);
>> +    } else {
>> +        msg_Err(p_filter, "Unsupported DXA9 conversion to 0x%08X",
>> desc.Format); }
>>
>>      /* */
>>      IDirect3DSurface9_UnlockRect(d3d);
>> +}
>> +
>> +static int Extract(vlc_va_t *va, picture_t *picture, uint8_t *data)
>> +{
>> +    vlc_va_sys_t *sys = va->sys;
>> +    LPDIRECT3DSURFACE9 d3d = (LPDIRECT3DSURFACE9)(uintptr_t)data;
>> +    picture_sys_t *p_sys = picture->p_sys;
>> +    LPDIRECT3DSURFACE9 output = p_sys->surface;
>> +
>> +    assert(d3d != output);
>> +#ifndef NDEBUG
>> +    LPDIRECT3DDEVICE9 srcDevice, dstDevice;
>> +    IDirect3DSurface9_GetDevice(d3d, &srcDevice);
>> +    IDirect3DSurface9_GetDevice(output, &dstDevice);
>> +    assert(srcDevice == dstDevice);
>> +#endif
>> +
>> +    HRESULT hr;
>> +    hr = IDirect3DDevice9_StretchRect( sys->d3ddev, d3d, 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 );
>> +        return VLC_EGENERIC;
>> +    }
>> +
>
> OK but I would expect Extract to be unnecessary when doing direct rendering
> (the one in VDPAU is pretty much doing nothing).

Yes, we need to copy pixels between the surfaces like we were copying
pixels from the surface to the planes. The target is from the
"decoder" pool (the one from the vout wrapper), not the internal DXVA
one. These picture_t end up in the display FIFO. So they need a
different reference counting that the one used for the dxva2 surfaces.

>>      return VLC_SUCCESS;
>>  }
>>
>> @@ -1078,21 +1163,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 OpenFilter( vlc_object_t *obj )
>>  {
>> -    switch (va->render) {
>> -    case MAKEFOURCC('N','V','1','2'):
>> -    case MAKEFOURCC('I','M','C','3'):
>> -        va->output = MAKEFOURCC('Y','V','1','2');
>> -        break;
>> -    default:
>> -        va->output = va->render;
>> -        break;
>> -    }
>> -    CopyInitCache(&va->surface_cache, va->surface_width);
>> +    filter_t *p_filter = (filter_t *)obj;
>> +    if ( p_filter->fmt_in.video.i_height !=
>> p_filter->fmt_out.video.i_height +         ||
>> p_filter->fmt_in.video.i_width != p_filter->fmt_out.video.i_width ) +
>>  return VLC_EGENERIC;
>> +
>> +    if ( p_filter->fmt_out.video.i_chroma != VLC_CODEC_I420
>> +         && p_filter->fmt_out.video.i_chroma != VLC_CODEC_YV12
>> +         && p_filter->fmt_out.video.i_chroma != VLC_CODEC_NV12 )
>> +        return VLC_EGENERIC;
>> +
>> +    if ( p_filter->fmt_in.video.i_chroma == VLC_CODEC_D3D9_OPAQUE )
>> +        p_filter->pf_video_filter = DXA9_I420_Filter;
>> +    else
>> +        return VLC_EGENERIC;
>> +
>> +    copy_cache_t *p_copy_cache = calloc(1, sizeof(*p_copy_cache));
>> +    CopyInitCache(p_copy_cache, p_filter->fmt_in.video.i_width );
>> +    p_filter->p_sys = (filter_sys_t*) p_copy_cache;
>> +
>> +    return VLC_SUCCESS;
>>  }
>>
>> -static void DxDestroyVideoConversion(vlc_va_sys_t *va)
>> +static void CloseFilter( 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/va.h b/modules/codec/avcodec/va.h
>> index a5ffeae..cbf43e9 100644
>> --- a/modules/codec/avcodec/va.h
>> +++ b/modules/codec/avcodec/va.h
>> @@ -37,7 +37,7 @@ struct vlc_va_t {
>>      const char *description;
>>      int pix_fmt;
>>
>> -    int  (*setup)(vlc_va_t *, AVCodecContext *, vlc_fourcc_t *output);
>> +    int  (*setup)(vlc_va_t *, AVCodecContext *, vlc_fourcc_t *output,
>> picture_t *p_test_output);
>> int  (*get)(vlc_va_t *, picture_t *pic, uint8_t
>> **data);
>>      void (*release)(void *pic, uint8_t *surface);
>>      int  (*extract)(vlc_va_t *, picture_t *pic, uint8_t *data);
>> @@ -58,9 +58,9 @@ vlc_va_t *vlc_va_New(vlc_object_t *obj, AVCodecContext *,
>> const es_format_t *fmt * @return VLC_SUCCESS on success, otherwise an error
>> code.
>>   */
>>  static inline int vlc_va_Setup(vlc_va_t *va, AVCodecContext *avctx,
>> -                               vlc_fourcc_t *output)
>> +                               vlc_fourcc_t *output, picture_t
>> *p_test_output) {
>> -    return va->setup(va, avctx, output);
>> +    return va->setup(va, avctx, output, p_test_output);
>>  }
>>
>>  /**
>> diff --git a/modules/codec/avcodec/video.c b/modules/codec/avcodec/video.c
>> index 71f8fbf..30fd185 100644
>> --- a/modules/codec/avcodec/video.c
>> +++ b/modules/codec/avcodec/video.c
>> @@ -1063,10 +1063,19 @@ static int lavc_GetFrame(struct AVCodecContext *ctx,
>> AVFrame *frame, int flags) frame->opaque = NULL;
>>
>>      wait_mt(sys);
>> +    /* The semaphore protects updates to fmt_out */
>> +    pic = ffmpeg_NewPictBuf(dec, ctx);
>
> You need to set i_chroma first.

I suppose that's done now with d331a8535763147143aa0e66991997308404bda5 ?
"test for decoder hardware output support before decoding"

>> +    if (pic == NULL)
>> +    {
>> +        post_mt(sys);
>> +        return -1;
>> +    }
>> +
>>      if (sys->p_va != NULL)
>>      {   /* TODO: Move this to get_format(). We are screwed if it fails
>> here. */
>> -        if (vlc_va_Setup(sys->p_va, ctx,
>> &dec->fmt_out.video.i_chroma))
>> +        if (vlc_va_Setup(sys->p_va, ctx,
>> &dec->fmt_out.video.i_chroma, pic)) {
>
> And you can't change i_chroma after you've allocated a picture.

We can remove the chroma parameter from setup(), given the changes
above. The va provides the output pixel format earlier and it won't be
regonatiated for that instance.

>> +            picture_Release(pic);
>>              post_mt(sys);
>>              msg_Err(dec, "hardware acceleration setup failed");
>>              return -1;
>> @@ -1074,15 +1083,11 @@ static int lavc_GetFrame(struct AVCodecContext *ctx,
>> AVFrame *frame, int flags) }
>>      else if (!sys->b_direct_rendering)
>>      {
>> +        picture_Release(pic);
>>          post_mt(sys);
>>          return avcodec_default_get_buffer2(ctx, frame, flags);
>>      }
>> -
>> -    /* The semaphore protects updates to fmt_out */
>> -    pic = ffmpeg_NewPictBuf(dec, ctx);
>>      post_mt(sys);
>> -    if (pic == NULL)
>> -        return -1;
>>
>>      if (sys->p_va != NULL)
>>          return lavc_va_GetFrame(ctx, frame, pic);
>> @@ -1142,7 +1147,7 @@ static enum PixelFormat ffmpeg_GetFormat(
>> AVCodecContext *p_context, /* We try to call vlc_va_Setup when possible to
>> detect errors when * possible (later is too late) */
>>          if( p_context->width > 0 && p_context->height > 0
>> -         && vlc_va_Setup( p_va, p_context, &p_dec->fmt_out.video.i_chroma )
>> ) +         && vlc_va_Setup( p_va, p_context,
>> &p_dec->fmt_out.video.i_chroma, NULL ) ) {
>>              msg_Err( p_dec, "acceleration setup failure" );
>>              break;
>> diff --git a/modules/video_chroma/copy.c b/modules/video_chroma/copy.c
>> index cc98c92..2ddf9ef 100644
>> --- a/modules/video_chroma/copy.c
>> +++ b/modules/video_chroma/copy.c
>> @@ -326,11 +326,23 @@ static void SSE_CopyFromNv12(picture_t *dst,
>>                    src[0], src_pitch[0],
>>                    cache->buffer, cache->size,
>>                    width, height, cpu);
>> -    SSE_SplitPlanes(dst->p[2].p_pixels, dst->p[2].i_pitch,
>> -                    dst->p[1].p_pixels, dst->p[1].i_pitch,
>> -                    src[1], src_pitch[1],
>> -                    cache->buffer, cache->size,
>> -                    (width+1)/2, (height+1)/2, cpu);
>> +    if( dst->format.i_chroma == VLC_CODEC_YV12 )
>> +        SSE_SplitPlanes(dst->p[2].p_pixels, dst->p[2].i_pitch,
>> +                        dst->p[1].p_pixels, dst->p[1].i_pitch,
>> +                        src[1], src_pitch[1],
>> +                        cache->buffer, cache->size,
>> +                        (width+1)/2, (height+1)/2, cpu);
>> +    else if( dst->format.i_chroma == VLC_CODEC_I420 )
>> +        SSE_SplitPlanes(dst->p[1].p_pixels, dst->p[1].i_pitch,
>> +                        dst->p[2].p_pixels, dst->p[2].i_pitch,
>> +                        src[1], src_pitch[1],
>> +                        cache->buffer, cache->size,
>> +                        (width+1)/2, (height+1)/2, cpu);
>> +    else if( dst->format.i_chroma == VLC_CODEC_NV12 )
>> +        SSE_CopyPlane(dst->p[1].p_pixels, dst->p[1].i_pitch,
>> +                      src[1], src_pitch[1],
>> +                      cache->buffer, cache->size,
>> +                      width, height/2, cpu);
>>      asm volatile ("emms");
>>  }
>>
>> @@ -394,10 +406,20 @@ void CopyFromNv12(picture_t *dst, uint8_t *src[2],
>> size_t src_pitch[2], CopyPlane(dst->p[0].p_pixels, dst->p[0].i_pitch,
>>                src[0], src_pitch[0],
>>                width, height);
>> -    SplitPlanes(dst->p[2].p_pixels, dst->p[2].i_pitch,
>> -                dst->p[1].p_pixels, dst->p[1].i_pitch,
>> -                src[1], src_pitch[1],
>> -                width/2, height/2);
>> +    if( dst->format.i_chroma == VLC_CODEC_YV12 )
>> +        SplitPlanes(dst->p[2].p_pixels, dst->p[2].i_pitch,
>> +                    dst->p[1].p_pixels, dst->p[1].i_pitch,
>> +                    src[1], src_pitch[1],
>> +                    width/2, height/2);
>> +    else if( dst->format.i_chroma = VLC_CODEC_I420 )
>> +        SplitPlanes(dst->p[1].p_pixels, dst->p[1].i_pitch,
>> +                    dst->p[2].p_pixels, dst->p[2].i_pitch,
>> +                    src[1], src_pitch[1],
>> +                    width/2, height/2);
>> +    else if( dst->format.i_chroma == VLC_CODEC_NV12 )
>> +        CopyPlane(dst->p[1].p_pixels, dst->p[1].i_pitch,
>> +                      src[1], src_pitch[1],
>> +                      width, height/2);
>>  }
>>
>>  void CopyFromYv12(picture_t *dst, uint8_t *src[3], size_t src_pitch[3],
>> diff --git a/src/Makefile.am b/src/Makefile.am
>> index 1f02494..a2489ab 100644
>> --- a/src/Makefile.am
>> +++ b/src/Makefile.am
>> @@ -290,6 +290,8 @@ SOURCES_libvlc_linux = \
>>       $(NULL)
>>
>>  SOURCES_libvlc_win32 = \
>> +     win32/direct3d9_pool.c \
>> +     win32/direct3d9_pool.h \
>>       win32/dirs.c \
>>       win32/error.c \
>>       win32/filesystem.c \
>> diff --git a/src/misc/fourcc.c b/src/misc/fourcc.c
>> index 3b5c9b3..032a12c 100644
>> --- a/src/misc/fourcc.c
>> +++ b/src/misc/fourcc.c
>> @@ -2193,6 +2193,9 @@ static const struct
>>      { { VLC_CODEC_ANDROID_OPAQUE, VLC_CODEC_MMAL_OPAQUE, },
>>                                                 FAKE_FMT() },
>>
>> +    { { VLC_CODEC_D3D9_OPAQUE, },
>> +                                               FAKE_FMT() },
>> +
>>      { { 0 },                                   FAKE_FMT() }
>>  };
>>
>> diff --git a/src/video_output/vout_wrapper.c
>> b/src/video_output/vout_wrapper.c index d172bcc..3442bd0 100644
>> --- a/src/video_output/vout_wrapper.c
>> +++ b/src/video_output/vout_wrapper.c
>> @@ -35,6 +35,9 @@
>>  #include <assert.h>
>>  #include "vout_internal.h"
>>  #include "display.h"
>> +#if defined(_WIN32)
>> +#include "../win32/direct3d9_pool.h"
>> +#endif
>>
>>  /**************************************************************************
>> *** * Local prototypes
>> @@ -139,10 +142,16 @@ int vout_InitWrapper(vout_thread_t *vout)
>>          sys->decoder_pool = display_pool;
>>          sys->display_pool = display_pool;
>>      } else if (!sys->decoder_pool) {
>> -        sys->decoder_pool =
>> -            picture_pool_NewFromFormat(&source,
>> -                                       __MAX(VOUT_MAX_PICTURES,
>> -                                             reserved_picture +
>> decoder_picture - DISPLAY_PICTURE_COUNT)); +        const unsigned
>> decoder_pool_size = __MAX(VOUT_MAX_PICTURES, +
>>                    reserved_picture + decoder_picture -
>> DISPLAY_PICTURE_COUNT); +#if defined(_WIN32)
>> +        if (source.i_chroma == VLC_CODEC_D3D9_OPAQUE)
>> +            /* FIXME dirty hack for now */
>> +            sys->decoder_pool = AllocPoolD3D9( VLC_OBJECT(vout), &source,
>> decoder_pool_size ); +        else
>> +#endif
>> +            sys->decoder_pool = picture_pool_NewFromFormat( &source,
>> decoder_pool_size ); +
>>          if (!sys->decoder_pool)
>>              return VLC_EGENERIC;
>>          if (allow_dr) {
>> diff --git a/src/win32/direct3d9_pool.c b/src/win32/direct3d9_pool.c
>> new file mode 100644
>> index 0000000..fd40a0a
>> --- /dev/null
>> +++ b/src/win32/direct3d9_pool.c
>> @@ -0,0 +1,248 @@
>> +/**************************************************************************
>> *** + * direct3d9_pool.c: Windows Direct3D9 picture pool creation
>> +
>> ***************************************************************************
>> ** + * Copyright (C) 2015 VLC authors and VideoLAN
>> + *$Id$
>> + *
>> + * Authors: Steve Lhomme <robux4 at gmail.com>,
>> + *
>> + * 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. +
>> ***************************************************************************
>> **/ +
>> +#ifdef HAVE_CONFIG_H
>> +# include "config.h"
>> +#endif
>> +
>> +#include "direct3d9_pool.h"
>> +
>> +static void DestroyPicture(picture_t *picture);
>> +
>> +struct picture_sys_t {
>> +    LPDIRECT3DSURFACE9 surface;
>> +    HINSTANCE          hd3d9_dll;
>> +};
>> +
>> +picture_pool_t *AllocPoolD3D9( vlc_object_t *va, const video_format_t *fmt,
>> unsigned pool_size ) +{
>> +    HINSTANCE         hd3d9_dll = NULL;
>> +    LPDIRECT3D9       d3dobj = NULL;
>> +    LPDIRECT3DDEVICE9 d3ddev = NULL;
>> +
>> +    if (fmt->i_chroma != VLC_CODEC_D3D9_OPAQUE)
>> +        return picture_pool_NewFromFormat(fmt, pool_size);
>> +
>> +    OSVERSIONINFO winVer;
>> +    winVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
>> +    if(GetVersionEx(&winVer) && winVer.dwMajorVersion < 6) {
>> +        msg_Warn(va, "windows version not compatible with D3D9");
>> +        goto error;
>> +    }
>> +
>> +    hd3d9_dll = LoadLibrary(TEXT("D3D9.DLL"));
>> +    if (!hd3d9_dll) {
>> +        msg_Warn(va, "cannot load d3d9.dll, aborting");
>> +        goto error;
>> +    }
>> +
>> +    LPDIRECT3D9 (WINAPI *OurDirect3DCreate9)(UINT SDKVersion);
>> +    OurDirect3DCreate9 = (void *)GetProcAddress(hd3d9_dll,
>> "Direct3DCreate9"); +    if (!OurDirect3DCreate9) {
>> +        msg_Err(va, "Cannot locate reference to Direct3DCreate9 ABI in
>> DLL"); +        goto error;
>> +    }
>> +
>> +    /* Create the D3D object. */
>> +    d3dobj = OurDirect3DCreate9(D3D_SDK_VERSION);
>> +    if (!d3dobj) {
>> +       msg_Err(va, "Could not create Direct3D9 instance.");
>> +       goto error;
>> +    }
>> +
>> +    /*
>> +    ** Get device capabilities
>> +    */
>> +    D3DCAPS9    d3dcaps;
>> +    ZeroMemory(&d3dcaps, sizeof(d3dcaps));
>> +    HRESULT hr = IDirect3D9_GetDeviceCaps(d3dobj, D3DADAPTER_DEFAULT,
>> D3DDEVTYPE_HAL, &d3dcaps); +    if (FAILED(hr)) {
>> +       msg_Err(va, "Could not read adapter capabilities. (hr=0x%0lx)", hr);
>> +       goto error;
>> +    }
>> +
>> +    /* TODO: need to test device capabilities and select the right render
>> function */ +    if (!(d3dcaps.DevCaps2 &
>> D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES) || +
>> !(d3dcaps.TextureFilterCaps & (D3DPTFILTERCAPS_MAGFLINEAR)) || +
>> !(d3dcaps.TextureFilterCaps & (D3DPTFILTERCAPS_MINFLINEAR))) { +
>> msg_Err(va, "Device does not support stretching from textures."); +
>> goto error;
>> +    }
>> +
>> +    // Create the D3DDevice
>> +    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
>> +
>> +    /* */
>> +    D3DADAPTER_IDENTIFIER9 d3dai;
>> +    if (FAILED(IDirect3D9_GetAdapterIdentifier(d3dobj,AdapterToUse,0,
>> &d3dai))) { +        msg_Warn(va, "IDirect3D9_GetAdapterIdentifier
>> failed");
>> +    } else {
>> +        msg_Dbg(va, "Direct3d9 Device: %s %lu %lu %lu", d3dai.Description,
>> +                d3dai.VendorId, d3dai.DeviceId, d3dai.Revision );
>> +    }
>> +
>> +    /*
>> +    ** Get the current desktop display mode, so we can set up a back
>> +    ** buffer of the same format
>> +    */
>> +    D3DDISPLAYMODE d3ddm;
>> +    hr = IDirect3D9_GetAdapterDisplayMode(d3dobj, D3DADAPTER_DEFAULT,
>> &d3ddm); +    if (FAILED(hr)) {
>> +       msg_Err(va, "Could not read adapter display mode. (hr=0x%0lx)", hr);
>> +       goto error;
>> +    }
>> +
>> +    D3DPRESENT_PARAMETERS d3dpp;
>> +    ZeroMemory(&d3dpp, sizeof(d3dpp));
>> +    d3dpp.Flags                  = D3DPRESENTFLAG_VIDEO;
>> +    d3dpp.Windowed               = TRUE;
>> +    d3dpp.hDeviceWindow          = NULL;
>> +    d3dpp.SwapEffect             = D3DSWAPEFFECT_DISCARD;
>> +    d3dpp.MultiSampleType        = D3DMULTISAMPLE_NONE;
>> +    d3dpp.PresentationInterval   = D3DPRESENT_INTERVAL_DEFAULT;
>> +    d3dpp.BackBufferCount        = 0; /* FIXME may not be right */
>> +    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;
>> +
>> +    hr = IDirect3D9_CreateDevice(d3dobj, AdapterToUse,
>> +                                         DeviceType, GetDesktopWindow(),
>> +
>> D3DCREATE_SOFTWARE_VERTEXPROCESSING| +
>>    D3DCREATE_MULTITHREADED, +
>> &d3dpp, &d3ddev);
>> +    if (FAILED(hr)) {
>> +       msg_Err(va, "Could not create the D3D9 device! (hr=0x%0lx)", hr);
>> +       goto error;
>> +    }
>> +
>> +    picture_pool_t *result = AllocPoolD3D9Ex(va, d3ddev, fmt, pool_size);
>> +    if (!result)
>> +        goto error;
>> +
>> +    FreeLibrary(hd3d9_dll);
>> +    return result;
>> +
>> +error:
>> +    if (d3ddev)
>> +        IDirect3DDevice9_Release(d3ddev);
>> +    if (d3dobj)
>> +        IDirect3D9_Release(d3dobj);
>> +    if (hd3d9_dll)
>> +        FreeLibrary(hd3d9_dll);
>> +    return NULL;
>> +}
>> +
>> +picture_pool_t *AllocPoolD3D9Ex(vlc_object_t *va, LPDIRECT3DDEVICE9 d3ddev,
>> +                                const video_format_t *fmt, unsigned
>> pool_size) +{
>> +    picture_t**       pictures = NULL;
>> +    unsigned          picture_count = 0;
>> +
>> +    pictures = calloc(pool_size, sizeof(*pictures));
>> +    if (!pictures)
>> +        goto error;
>> +    for (picture_count = 0; picture_count < pool_size; ++picture_count)
>> +    {
>> +        picture_sys_t *picsys = malloc(sizeof(*picsys));
>> +        if (unlikely(picsys == NULL))
>> +            goto error;
>> +
>> +        HRESULT hr = IDirect3DDevice9_CreateOffscreenPlainSurface(d3ddev,
>> +                                                          fmt->i_width,
>> +                                                          fmt->i_height,
>> +
>> MAKEFOURCC('N','V','1','2'), /* FIXME d3ddm.Format, */ +
>>                                       D3DPOOL_DEFAULT, +
>>                                       &picsys->surface, +
>>                                        NULL);
>> +        if (FAILED(hr)) {
>> +           msg_Err(va, "Failed to allocate surface %d (hr=0x%0lx)",
>> picture_count, hr); +           goto error;
>> +        }
>> +
>> +        picture_resource_t resource = {
>> +            .p_sys = picsys,
>> +            .pf_destroy = DestroyPicture,
>> +        };
>> +
>> +        picture_t *picture = picture_NewFromResource(fmt, &resource);
>> +        if (unlikely(picture == NULL)) {
>> +            free(picsys);
>> +            goto error;
>> +        }
>> +
>> +        pictures[picture_count] = picture;
>> +        /* each picture_t holds a ref to the device and release it on
>> Destroy */ +        IDirect3DDevice9_AddRef(d3ddev);
>> +        /* each picture_t holds a ref to the DLL */
>> +        picsys->hd3d9_dll = LoadLibrary(TEXT("D3D9.DLL"));
>> +    }
>> +
>> +    /* release the system resources, they will be free'd with the pool */
>> +    IDirect3DDevice9_Release(d3ddev);
>> +
>> +    picture_pool_configuration_t pool_cfg;
>> +    memset(&pool_cfg, 0, sizeof(pool_cfg));
>> +    pool_cfg.picture_count = pool_size;
>> +    pool_cfg.picture       = pictures;
>> +
>> +    return picture_pool_NewExtended( &pool_cfg );
>> +
>> +error:
>> +    if (pictures) {
>> +        for (unsigned i=0;i<picture_count; ++i)
>> +            DestroyPicture(pictures[i]);
>> +        free(pictures);
>> +    }
>> +    return NULL;
>> +}
>> +
>> +static void DestroyPicture(picture_t *picture)
>> +{
>> +    LPDIRECT3DDEVICE9 d3ddev;
>> +    if (!FAILED(IDirect3DSurface9_GetDevice(picture->p_sys->surface,
>> &d3ddev))) +        IDirect3DDevice9_Release(d3ddev);
>> +
>> +    IDirect3DSurface9_Release(picture->p_sys->surface);
>> +
>> +    FreeLibrary(picture->p_sys->hd3d9_dll);
>> +
>> +    free(picture->p_sys);
>> +}
>> diff --git a/src/win32/direct3d9_pool.h b/src/win32/direct3d9_pool.h
>> new file mode 100644
>> index 0000000..b1b9fe2
>> --- /dev/null
>> +++ b/src/win32/direct3d9_pool.h
>> @@ -0,0 +1,39 @@
>> +/**************************************************************************
>> *** + * direct3d9_pool.c: Windows Direct3D9 picture pool creation
>> +
>> ***************************************************************************
>> ** + * Copyright (C) 2015 VLC authors and VideoLAN
>> + *$Id$
>> + *
>> + * Authors: Steve Lhomme <robux4 at gmail.com>,
>> + *
>> + * 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 WIN32_DIRECT3D9_POOL_H_
>> +#define WIN32_DIRECT3D9_POOL_H_
>> +
>> +#include <windows.h>
>> +#include <d3d9.h>
>> +
>> +#include <vlc_common.h>
>> +#include <vlc_picture_pool.h>
>> +
>> +#define VA_DXVA2_MAX_SURFACE_COUNT (64)
>> +
>> +picture_pool_t *AllocPoolD3D9( vlc_object_t *obj, const video_format_t
>> *p_fmt, unsigned pool_size ); +picture_pool_t *AllocPoolD3D9Ex(vlc_object_t
>> *obj, LPDIRECT3DDEVICE9 d3ddev, +                                const
>> video_format_t *fmt, unsigned pool_size); +
>> +#endif /* WIN32_DIRECT3D9_POOL_H_ */
>
> --
> Rémi Denis-Courmont
> http://www.remlab.net/
>
> _______________________________________________
> 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