[vlc-devel] [PATCH 1/2] d3d11va: handle decoding to DXGI_FORMAT_420_OPAQUE using a ID3D11VideoProcessor

Steve Lhomme robux4 at gmail.com
Wed Apr 6 16:38:59 CEST 2016


On Fri, Feb 26, 2016 at 6:37 PM, Jean-Baptiste Kempf <jb at videolan.org> wrote:
> I don't think this should be in the decoder.

I tried to move this away so that it's handled like a normal filter
but it's just not possible with the current core.

The idea would be to have 420_OPAQUE decoder surface -> NV12 surface
-> vout that means the decoder and the vout surface are not the same.
It is fine in a normal case, the vout would have its display pool and
the decoder its decoder pool. Except we can't create a decoder pool
the way it's done now, it's missing the D3D11Device/Context reference
to create the texture for each picture_t in the pool.

We could change the way the decoder pool is created to get it from the
vout so that when it needs resources allocated by the vout it can do
it accordingly. And it would fallback to the current code in the usual
case.
That would mean changing this line to use the vout:

http://git.videolan.org/?p=vlc.git;a=blob;f=src/video_output/vout_wrapper.c;h=10c615ea2a93844399f31a94da2af2ebe1ec32a3;hb=HEAD#l151

Opinion ?

> On 26 Feb, Steve Lhomme wrote :
>> ---
>>  modules/codec/avcodec/d3d11va.c       | 197 +++++++++++++++++++++++++++++++---
>>  modules/codec/avcodec/directx_va.c    |   2 +-
>>  modules/codec/avcodec/directx_va.h    |   2 +-
>>  modules/codec/avcodec/dxva2.c         |   5 +-
>>  modules/video_output/msw/direct3d11.c |   8 +-
>>  5 files changed, 194 insertions(+), 20 deletions(-)
>>
>> diff --git a/modules/codec/avcodec/d3d11va.c b/modules/codec/avcodec/d3d11va.c
>> index 9b3e72e..79f89e4 100644
>> --- a/modules/codec/avcodec/d3d11va.c
>> +++ b/modules/codec/avcodec/d3d11va.c
>> @@ -114,6 +114,11 @@ struct vlc_va_sys_t
>>      /* Option conversion */
>>      filter_t                     *filter;
>>
>> +    /* video decoder for 420_OPAQUE */
>> +    ID3D11VideoProcessor         *d3dprocessor;
>> +    DXGI_FORMAT                  processor_output;
>> +    ID3D11VideoProcessorEnumerator *d3dprocenum;
>> +
>>      /* avcodec internals */
>>      struct AVD3D11VAContext      hw;
>>  };
>> @@ -124,6 +129,7 @@ struct picture_sys_t
>>      ID3D11VideoDecoderOutputView  *decoder; /* may be NULL for pictures from the pool */
>>      ID3D11Texture2D               *texture;
>>      ID3D11DeviceContext           *context;
>> +    ID3D11VideoProcessorInputView *inputView;
>>  };
>>
>>  /* */
>> @@ -137,7 +143,7 @@ static void D3dDestroyDeviceManager(vlc_va_t *);
>>  static int DxCreateVideoService(vlc_va_t *);
>>  static void DxDestroyVideoService(vlc_va_t *);
>>  static int DxGetInputList(vlc_va_t *, input_list_t *);
>> -static int DxSetupOutput(vlc_va_t *, const GUID *);
>> +static int DxSetupOutput(vlc_va_t *, const GUID *, const video_format_t *);
>>
>>  static int DxCreateDecoderSurfaces(vlc_va_t *, int codec_id, const video_format_t *fmt, bool b_threading);
>>  static void DxDestroySurfaces(vlc_va_t *);
>> @@ -219,20 +225,59 @@ static int Extract(vlc_va_t *va, picture_t *output, uint8_t *data)
>>
>>      if (output->format.i_chroma == VLC_CODEC_D3D11_OPAQUE)
>>      {
>> -        /* copy decoder slice to surface */
>> -        D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC viewDesc;
>>          picture_sys_t *p_sys_out = output->p_sys;
>>          picture_sys_t *p_sys_in = surface->p_pic->p_sys;
>>
>>          assert(p_sys_out->texture != NULL);
>>          assert(p_sys_in->decoder == src);
>>
>> -        ID3D11VideoDecoderOutputView_GetDesc( src, &viewDesc );
>> -        ID3D11DeviceContext_CopySubresourceRegion(sys->d3dctx, (ID3D11Resource*) p_sys_out->texture,
>> -                                                  0, 0, 0, 0,
>> -                                                  (ID3D11Resource*) p_sys_in->texture,
>> -                                                  viewDesc.Texture2D.ArraySlice,
>> -                                                  NULL);
>> +        if (sys->d3dprocessor)
>> +        {
>> +            // extract the decoded video to a the output Texture
>> +            if (p_sys_out->decoder == NULL)
>> +            {
>> +                D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC outDesc = {
>> +                    .ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D,
>> +                };
>> +
>> +                HRESULT hr = ID3D11VideoDevice_CreateVideoProcessorOutputView((ID3D11VideoDevice*) sys->dx_sys.d3ddec,
>> +                                                                 (ID3D11Resource*) p_sys_out->texture,
>> +                                                                 sys->d3dprocenum,
>> +                                                                 &outDesc,
>> +                                                                 (ID3D11VideoProcessorOutputView**) &p_sys_out->decoder);
>> +                if (FAILED(hr))
>> +                {
>> +                    msg_Err(va, "Failed to create the processor output. (hr=0x%lX)", hr);
>> +                    return VLC_EGENERIC;
>> +                }
>> +            }
>> +
>> +            D3D11_VIDEO_PROCESSOR_STREAM stream = {
>> +                .Enable = TRUE,
>> +                .pInputSurface = p_sys_in->inputView,
>> +            };
>> +
>> +            HRESULT hr = ID3D11VideoContext_VideoProcessorBlt(sys->d3dvidctx, sys->d3dprocessor,
>> +                                                      (ID3D11VideoProcessorOutputView*) p_sys_out->decoder,
>> +                                                      0, 1, &stream);
>> +            if (FAILED(hr))
>> +            {
>> +                msg_Err(va, "Failed to process the video. (hr=0x%lX)", hr);
>> +                return VLC_EGENERIC;
>> +            }
>> +        }
>> +        else
>> +        {
>> +            D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC viewDesc;
>> +            ID3D11VideoDecoderOutputView_GetDesc( src, &viewDesc );
>> +
>> +            /* copy decoder slice to surface */
>> +            ID3D11DeviceContext_CopySubresourceRegion(sys->d3dctx, (ID3D11Resource*) p_sys_out->texture,
>> +                                                      0, 0, 0, 0,
>> +                                                      (ID3D11Resource*) p_sys_in->texture,
>> +                                                      viewDesc.Texture2D.ArraySlice,
>> +                                                      NULL);
>> +        }
>>      }
>>      else if (output->format.i_chroma == VLC_CODEC_YV12) {
>>          va->sys->filter->owner.sys = output;
>> @@ -453,6 +498,10 @@ static void D3dDestroyDevice(vlc_va_t *va)
>>          ID3D11VideoContext_Release(va->sys->d3dvidctx);
>>      if (va->sys->d3dctx)
>>          ID3D11DeviceContext_Release(va->sys->d3dctx);
>> +    if (va->sys->d3dprocessor)
>> +        ID3D11VideoProcessor_Release(va->sys->d3dprocessor);
>> +    if (va->sys->d3dprocenum)
>> +        ID3D11VideoProcessorEnumerator_Release(va->sys->d3dprocenum);
>>  }
>>  /**
>>   * It describes our Direct3D object
>> @@ -619,7 +668,7 @@ static int DxGetInputList(vlc_va_t *va, input_list_t *p_list)
>>      return VLC_SUCCESS;
>>  }
>>
>> -static int DxSetupOutput(vlc_va_t *va, const GUID *input)
>> +static int DxSetupOutput(vlc_va_t *va, const GUID *input, const video_format_t *fmt)
>>  {
>>      directx_sys_t *dx_sys = &va->sys->dx_sys;
>>      HRESULT hr;
>> @@ -638,6 +687,7 @@ static int DxSetupOutput(vlc_va_t *va, const GUID *input)
>>      if ( va->sys->render != DXGI_FORMAT_UNKNOWN )
>>          processorInput[idx++] = va->sys->render;
>>      processorInput[idx++] = DXGI_FORMAT_NV12;
>> +    processorInput[idx++] = DXGI_FORMAT_420_OPAQUE;
>>      processorInput[idx++] = DXGI_FORMAT_UNKNOWN;
>>
>>      char *psz_decoder_name = directx_va_GetDecoderName(input);
>> @@ -666,13 +716,113 @@ static int DxSetupOutput(vlc_va_t *va, const GUID *input)
>>                  ( i_formatSupport & i_quadSupportFlags ) == i_quadSupportFlags )
>>              b_needsProcessor = false;
>>
>> -        if ( !b_needsProcessor )
>> +        if (!b_needsProcessor)
>>          {
>>              msg_Dbg(va, "Using output format %s for decoder %s", DxgiFormatToStr(processorInput[idx]), psz_decoder_name);
>>              va->sys->render = processorInput[idx];
>>              free(psz_decoder_name);
>>              return VLC_SUCCESS;
>>          }
>> +        else
>> +        {
>> +            ID3D11VideoProcessorEnumerator *processorEnumerator;
>> +            D3D11_VIDEO_PROCESSOR_CONTENT_DESC processorDesc = {
>> +                .InputFrameFormat = D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE,   /* TODO */
>> +                .InputFrameRate = {
>> +                    .Numerator   = fmt->i_frame_rate,
>> +                    .Denominator = fmt->i_frame_rate_base,
>> +                },
>> +                .InputWidth   = fmt->i_width,
>> +                .InputHeight  = fmt->i_height,
>> +                .OutputWidth  = fmt->i_width,
>> +                .OutputHeight = fmt->i_height,
>> +                .Usage = D3D11_VIDEO_USAGE_PLAYBACK_NORMAL,
>> +            };
>> +            hr = ID3D11VideoDevice_CreateVideoProcessorEnumerator((ID3D11VideoDevice*) dx_sys->d3ddec, &processorDesc, &processorEnumerator);
>> +            if ( processorEnumerator == NULL )
>> +            {
>> +                msg_Dbg(va, "Can't get a video processor for the video.");
>> +                continue;
>> +            }
>> +
>> +            UINT flags;
>> +#ifndef NDEBUG
>> +            for (int format = 0; format < 188; format++) {
>> +                hr = ID3D11VideoProcessorEnumerator_CheckVideoProcessorFormat(processorEnumerator, format, &flags);
>> +                if (SUCCEEDED(hr) && (flags & D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_INPUT))
>> +                    msg_Dbg(va, "processor format %s is supported for input", DxgiFormatToStr(format));
>> +                if (SUCCEEDED(hr) && (flags & D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_OUTPUT))
>> +                    msg_Dbg(va, "processor format %s is supported for output", DxgiFormatToStr(format));
>> +            }
>> +#endif
>> +            DXGI_FORMAT processorOutput = DXGI_FORMAT_UNKNOWN;
>> +            if ( va->sys->render != DXGI_FORMAT_UNKNOWN )
>> +            {
>> +                hr = ID3D11VideoProcessorEnumerator_CheckVideoProcessorFormat(processorEnumerator, va->sys->render, &flags);
>> +                if (FAILED(hr) && !(flags & D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_OUTPUT))
>> +                    msg_Dbg(va, "processor format %s not supported for output", DxgiFormatToStr(va->sys->render));
>> +                else
>> +                    processorOutput = va->sys->render;
>> +            }
>> +
>> +            if (processorOutput == DXGI_FORMAT_UNKNOWN)
>> +            {
>> +                // check if we can create render texture of that format
>> +                // check the decoder can output to that format
>> +                const UINT i_quadSupportFlags = D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_SHADER_LOAD;
>> +                for (const d3d_format_t *output = GetRenderFormatList();
>> +                     output->name != NULL; ++output)
>> +                {
>> +                    UINT i_formatSupport;
>> +                    if( SUCCEEDED( ID3D11Device_CheckFormatSupport((ID3D11Device*) dx_sys->d3ddev,
>> +                                                                   output->formatTexture,
>> +                                                                   &i_formatSupport)) &&
>> +                            ( i_formatSupport & i_quadSupportFlags ) == i_quadSupportFlags )
>> +                    {
>> +                        msg_Dbg(va, "Render pixel format %s supported", DxgiFormatToStr(output->formatTexture) );
>> +
>> +                        hr = ID3D11VideoProcessorEnumerator_CheckVideoProcessorFormat(processorEnumerator, output->formatTexture, &flags);
>> +                        if (FAILED(hr) && !(flags & D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_OUTPUT))
>> +                            msg_Dbg(va, "Processor format %s not supported for output", DxgiFormatToStr(output->formatTexture));
>> +                        else
>> +                        {
>> +                            processorOutput = output->formatTexture;
>> +                            break;
>> +                        }
>> +                    }
>> +                }
>> +            }
>> +
>> +            if (processorOutput != DXGI_FORMAT_UNKNOWN)
>> +            {
>> +                D3D11_VIDEO_PROCESSOR_CAPS processorCaps;
>> +
>> +                hr = ID3D11VideoProcessorEnumerator_GetVideoProcessorCaps(processorEnumerator, &processorCaps);
>> +
>> +                ID3D11VideoProcessor *opaque_processor = NULL;
>> +                for (UINT type = 0; type < processorCaps.RateConversionCapsCount; ++type)
>> +                {
>> +                    hr = ID3D11VideoDevice_CreateVideoProcessor((ID3D11VideoDevice*) dx_sys->d3ddec, processorEnumerator, type, &opaque_processor);
>> +                    if (SUCCEEDED(hr))
>> +                        break;
>> +                    opaque_processor = NULL;
>> +                }
>> +
>> +                if (opaque_processor != NULL)
>> +                {
>> +                    msg_Dbg(va, "Using processor %s to %s", DxgiFormatToStr(processorInput[idx]), DxgiFormatToStr(processorOutput));
>> +
>> +                    va->sys->d3dprocessor     = opaque_processor;
>> +                    va->sys->processor_output = processorOutput;
>> +                    va->sys->render           = processorInput[idx];
>> +                    va->sys->d3dprocenum      = processorEnumerator;
>> +                    free(psz_decoder_name);
>> +                    return VLC_SUCCESS;
>> +                }
>> +
>> +            }
>> +            ID3D11VideoProcessorEnumerator_Release(processorEnumerator);
>> +        }
>>      }
>>      free(psz_decoder_name);
>>
>> @@ -824,6 +974,8 @@ static void DestroyPicture(picture_t *picture)
>>  {
>>      picture_sys_t *p_sys = picture->p_sys;
>>      ID3D11Texture2D_Release( p_sys->texture );
>> +    if (p_sys->inputView)
>> +        ID3D11View_Release( (ID3D11View*) p_sys->inputView );
>>
>>      free(p_sys);
>>      free(picture);
>> @@ -831,16 +983,37 @@ static void DestroyPicture(picture_t *picture)
>>
>>  static picture_t *DxAllocPicture(vlc_va_t *va, const video_format_t *fmt, unsigned index)
>>  {
>> +    vlc_va_sys_t *sys = va->sys;
>>      video_format_t src_fmt = *fmt;
>>      src_fmt.i_chroma = VLC_CODEC_D3D11_OPAQUE;
>>      picture_sys_t *pic_sys = calloc(1, sizeof(*pic_sys));
>>      if (unlikely(pic_sys == NULL))
>>          return NULL;
>>
>> -    pic_sys->decoder  = (ID3D11VideoDecoderOutputView*) va->sys->dx_sys.hw_surface[index];
>> +    pic_sys->decoder  = (ID3D11VideoDecoderOutputView*) sys->dx_sys.hw_surface[index];
>>      ID3D11VideoDecoderOutputView_GetResource(pic_sys->decoder, (ID3D11Resource**) &pic_sys->texture);
>>      pic_sys->context  = va->sys->d3dctx;
>>
>> +    if (sys->d3dprocenum)
>> +    {
>> +        D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC inDesc = {
>> +            .ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D,
>> +            .Texture2D.MipSlice = 0,
>> +            .Texture2D.ArraySlice = index,
>> +        };
>> +
>> +        HRESULT hr = ID3D11VideoDevice_CreateVideoProcessorInputView((ID3D11VideoDevice*) sys->dx_sys.d3ddec,
>> +                                                        (ID3D11Resource*) pic_sys->texture,
>> +                                                        sys->d3dprocenum,
>> +                                                        &inDesc,
>> +                                                        &pic_sys->inputView);
>> +        if (FAILED(hr))
>> +        {
>> +            msg_Err(va, "Failed to create the processor input ArraySlice=%d. (hr=0x%lX)", inDesc.Texture2D.ArraySlice, hr);
>> +            return NULL;
>> +        }
>> +    }
>> +
>>      picture_resource_t res = {
>>          .p_sys      = pic_sys,
>>          .pf_destroy = DestroyPicture,
>> diff --git a/modules/codec/avcodec/directx_va.c b/modules/codec/avcodec/directx_va.c
>> index 538b45e..85f3c76 100644
>> --- a/modules/codec/avcodec/directx_va.c
>> +++ b/modules/codec/avcodec/directx_va.c
>> @@ -554,7 +554,7 @@ static int FindVideoServiceConversion(vlc_va_t *va, directx_sys_t *dx_sys, const
>>
>>          /* */
>>          msg_Dbg(va, "Trying to use '%s' as input", mode->name);
>> -        if (dx_sys->pf_setup_output(va, mode->guid)==VLC_SUCCESS)
>> +        if (dx_sys->pf_setup_output( va, mode->guid, &fmt->video )==VLC_SUCCESS)
>>          {
>>              dx_sys->input = *mode->guid;
>>              err = VLC_SUCCESS;
>> diff --git a/modules/codec/avcodec/directx_va.h b/modules/codec/avcodec/directx_va.h
>> index 905ae0d..dcc4f6e 100644
>> --- a/modules/codec/avcodec/directx_va.h
>> +++ b/modules/codec/avcodec/directx_va.h
>> @@ -110,7 +110,7 @@ typedef struct
>>       * Find a suitable decoder configuration for the input and set the
>>       * internal state to use that output
>>       */
>> -    int (*pf_setup_output)(vlc_va_t *, const GUID *input);
>> +    int (*pf_setup_output)(vlc_va_t *, const GUID *input, const video_format_t *fmt);
>>
>>      /**
>>       * Create the DirectX surfaces in hw_surface and the decoder in decoder
>> diff --git a/modules/codec/avcodec/dxva2.c b/modules/codec/avcodec/dxva2.c
>> index 4ab9fc9..89bbb13 100644
>> --- a/modules/codec/avcodec/dxva2.c
>> +++ b/modules/codec/avcodec/dxva2.c
>> @@ -151,7 +151,7 @@ static void D3dDestroyDeviceManager(vlc_va_t *);
>>  static int DxCreateVideoService(vlc_va_t *);
>>  static void DxDestroyVideoService(vlc_va_t *);
>>  static int DxGetInputList(vlc_va_t *, input_list_t *);
>> -static int DxSetupOutput(vlc_va_t *, const GUID *);
>> +static int DxSetupOutput(vlc_va_t *, const GUID *, const video_format_t *);
>>
>>  static int DxCreateVideoDecoder(vlc_va_t *,
>>                                  int codec_id, const video_format_t *, bool);
>> @@ -613,8 +613,9 @@ static int DxGetInputList(vlc_va_t *va, input_list_t *p_list)
>>      return VLC_SUCCESS;
>>  }
>>
>> -static int DxSetupOutput(vlc_va_t *va, const GUID *input)
>> +static int DxSetupOutput(vlc_va_t *va, const GUID *input, const video_format_t *fmt)
>>  {
>> +    VLC_UNUSED(fmt);
>>      int err = VLC_EGENERIC;
>>      UINT      output_count = 0;
>>      D3DFORMAT *output_list = NULL;
>> diff --git a/modules/video_output/msw/direct3d11.c b/modules/video_output/msw/direct3d11.c
>> index b3ea08f..19409b5 100644
>> --- a/modules/video_output/msw/direct3d11.c
>> +++ b/modules/video_output/msw/direct3d11.c
>> @@ -530,9 +530,9 @@ static picture_pool_t *Pool(vout_display_t *vd, unsigned pool_size)
>>      texDesc.SampleDesc.Count = 1;
>>      texDesc.MiscFlags = 0; //D3D11_RESOURCE_MISC_SHARED;
>>      texDesc.ArraySize = 1;
>> -    texDesc.Usage = D3D11_USAGE_DYNAMIC;
>> -    texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
>> -    texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
>> +    texDesc.Usage = D3D11_USAGE_DEFAULT;
>> +    texDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
>> +    texDesc.CPUAccessFlags = 0;
>>
>>      for (picture_count = 0; picture_count < pool_size; picture_count++) {
>>          picture_sys_t *picsys = calloc(1, sizeof(*picsys));
>> @@ -861,7 +861,7 @@ static int Direct3D11Open(vout_display_t *vd, video_format_t *fmt)
>>
>>  #if !VLC_WINSTORE_APP
>>
>> -    UINT creationFlags = 0;
>> +    UINT creationFlags = D3D11_CREATE_DEVICE_VIDEO_SUPPORT;
>>      HRESULT hr = S_OK;
>>
>>  # if !defined(NDEBUG) && defined(_MSC_VER)
>> --
>> 2.6.1.windows.1
>>
>> _______________________________________________
>> vlc-devel mailing list
>> To unsubscribe or modify your subscription options:
>> https://mailman.videolan.org/listinfo/vlc-devel
>
> --
> With my kindest regards,
>
> --
> Jean-Baptiste Kempf
> http://www.jbkempf.com/ - +33 672 704 734
> Sent from my Electronic Device
> _______________________________________________
> 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