diff mbox series

[FFmpeg-devel,v3,4/4] libavutil/qsv: enabling d3d11va support

Message ID 20200424145219.54067-4-artem.galin@gmail.com
State New
Headers show
Series [FFmpeg-devel,v3,1/4] fftools/qsv: enabling d3d11va/dxva2 device selection
Related show

Checks

Context Check Description
andriy/default pending
andriy/make success Make finished
andriy/make_fate success Make fate finished

Commit Message

Artem Galin April 24, 2020, 2:52 p.m. UTC
From: Artem Galin <artem.galin@intel.com>

Makes selection of d3d11va device type by default and over DirectX 9,
which is still supported but requires explicit selection.
This enables usage of non-powered/headless GPU, better HDR support.
Pool of resources is allocated as one texture with array of slices.

Added d3d11va device selection by vendor id.
Example: --init_hw_device d3d11va:,vendor=0x8086

DirectX 9 usage.
Example: --init_hw_device qsv:hw,child_device_type=dxva2

Signed-off-by: Artem Galin <artem.galin@intel.com>
---
 libavutil/hwcontext_d3d11va.c |  82 +++++++-
 libavutil/hwcontext_d3d11va.h |   8 +
 libavutil/hwcontext_qsv.c     | 363 +++++++++++++++++++++++++++-------
 3 files changed, 379 insertions(+), 74 deletions(-)

Comments

Mark Thompson April 26, 2020, 6:54 p.m. UTC | #1
On 24/04/2020 15:52, artem.galin@gmail.com wrote:
> From: Artem Galin <artem.galin@intel.com>
> 
> Makes selection of d3d11va device type by default and over DirectX 9,
> which is still supported but requires explicit selection.

... which might break users with older drivers/systems.  Some comment on exactly which setups are broken would be helpful here.

> This enables usage of non-powered/headless GPU, better HDR support.
> Pool of resources is allocated as one texture with array of slices.
> 
> Added d3d11va device selection by vendor id.
> Example: --init_hw_device d3d11va:,vendor=0x8086
> 
> DirectX 9 usage.
> Example: --init_hw_device qsv:hw,child_device_type=dxva2
> 
> Signed-off-by: Artem Galin <artem.galin@intel.com>
> ---
>  libavutil/hwcontext_d3d11va.c |  82 +++++++-
>  libavutil/hwcontext_d3d11va.h |   8 +
>  libavutil/hwcontext_qsv.c     | 363 +++++++++++++++++++++++++++-------
>  3 files changed, 379 insertions(+), 74 deletions(-)

Please split this patch into the different changes.  There are at least three separate things here:

- Adding more texture information to the D3D11 hwcontext API.
- Adding the vendor option to D3D11 device creation.
- Supporting D3D11 in libmfx hwcontext.

Since the first one is an external API change it probably wants more explanation as to why it is wanted and the effects on compatibility.

> diff --git a/libavutil/hwcontext_d3d11va.c b/libavutil/hwcontext_d3d11va.c
> index c8ae58f908..c5e127aadb 100644
> --- a/libavutil/hwcontext_d3d11va.c
> +++ b/libavutil/hwcontext_d3d11va.c
> @@ -72,7 +72,7 @@ static av_cold void load_functions(void)
>  }
>  
>  typedef struct D3D11VAFramesContext {
> -    int nb_surfaces_used;
> +    size_t nb_surfaces;
>  
>      DXGI_FORMAT format;
>  
> @@ -112,6 +112,8 @@ static void d3d11va_frames_uninit(AVHWFramesContext *ctx)
>      if (s->staging_texture)
>          ID3D11Texture2D_Release(s->staging_texture);
>      s->staging_texture = NULL;
> +
> +    av_freep(&frames_hwctx->texture_infos);
>  }
>  
>  static int d3d11va_frames_get_constraints(AVHWDeviceContext *ctx,
> @@ -152,8 +154,9 @@ static void free_texture(void *opaque, uint8_t *data)
>      av_free(data);
>  }
>  
> -static AVBufferRef *wrap_texture_buf(ID3D11Texture2D *tex, int index)
> +static AVBufferRef *wrap_texture_buf(AVHWFramesContext *ctx, ID3D11Texture2D *tex, int index)
>  {
> +    AVD3D11VAFramesContext *frames_hwctx = ctx->hwctx;
>      AVBufferRef *buf;
>      AVD3D11FrameDescriptor *desc = av_mallocz(sizeof(*desc));
>      if (!desc) {
> @@ -161,6 +164,10 @@ static AVBufferRef *wrap_texture_buf(ID3D11Texture2D *tex, int index)
>          return NULL;
>      }
>  
> +    frames_hwctx->texture_infos[frames_hwctx->nb_surfaces_used].texture = tex;
> +    frames_hwctx->texture_infos[frames_hwctx->nb_surfaces_used].index = index;
> +    frames_hwctx->nb_surfaces_used++;
> +
>      desc->texture = tex;
>      desc->index   = index;
>  
> @@ -199,13 +206,12 @@ static AVBufferRef *d3d11va_alloc_single(AVHWFramesContext *ctx)
>          return NULL;
>      }
>  
> -    return wrap_texture_buf(tex, 0);
> +    return wrap_texture_buf(ctx, tex, 0);
>  }
>  
>  static AVBufferRef *d3d11va_pool_alloc(void *opaque, int size)
>  {
>      AVHWFramesContext        *ctx = (AVHWFramesContext*)opaque;
> -    D3D11VAFramesContext       *s = ctx->internal->priv;
>      AVD3D11VAFramesContext *hwctx = ctx->hwctx;
>      D3D11_TEXTURE2D_DESC  texDesc;
>  
> @@ -214,13 +220,13 @@ static AVBufferRef *d3d11va_pool_alloc(void *opaque, int size)
>  
>      ID3D11Texture2D_GetDesc(hwctx->texture, &texDesc);
>  
> -    if (s->nb_surfaces_used >= texDesc.ArraySize) {
> +    if (hwctx->nb_surfaces_used >= texDesc.ArraySize) {
>          av_log(ctx, AV_LOG_ERROR, "Static surface pool size exceeded.\n");
>          return NULL;
>      }
>  
>      ID3D11Texture2D_AddRef(hwctx->texture);
> -    return wrap_texture_buf(hwctx->texture, s->nb_surfaces_used++);
> +    return wrap_texture_buf(ctx, hwctx->texture, hwctx->nb_surfaces_used);
>  }
>  
>  static int d3d11va_frames_init(AVHWFramesContext *ctx)
> @@ -267,7 +273,7 @@ static int d3d11va_frames_init(AVHWFramesContext *ctx)
>              av_log(ctx, AV_LOG_ERROR, "User-provided texture has mismatching parameters\n");
>              return AVERROR(EINVAL);
>          }
> -    } else if (texDesc.ArraySize > 0) {
> +    } else if (!(texDesc.BindFlags & D3D11_BIND_RENDER_TARGET) && texDesc.ArraySize > 0) {
>          hr = ID3D11Device_CreateTexture2D(device_hwctx->device, &texDesc, NULL, &hwctx->texture);
>          if (FAILED(hr)) {
>              av_log(ctx, AV_LOG_ERROR, "Could not create the texture (%lx)\n", (long)hr);
> @@ -275,6 +281,12 @@ static int d3d11va_frames_init(AVHWFramesContext *ctx)
>          }
>      }
>  
> +    hwctx->texture_infos = av_mallocz_array(ctx->initial_pool_size, sizeof(*hwctx->texture_infos));
> +    if (!hwctx->texture_infos)
> +        return AVERROR(ENOMEM);
> +
> +    s->nb_surfaces = ctx->initial_pool_size;
> +
>      ctx->internal->pool_internal = av_buffer_pool_init2(sizeof(AVD3D11FrameDescriptor),
>                                                          ctx, d3d11va_pool_alloc, NULL);
>      if (!ctx->internal->pool_internal)
> @@ -511,15 +523,55 @@ static void d3d11va_device_uninit(AVHWDeviceContext *hwdev)
>      }
>  }
>  
> +static int d3d11va_device_find_adapter_by_vendor_id(AVHWDeviceContext *ctx, UINT creationFlags, long int vendor_id)
> +{
> +    HRESULT hr;
> +    IDXGIAdapter *adapter = NULL;
> +    int adapter_id = 0;
> +    IDXGIFactory2 *factory;
> +    hr = mCreateDXGIFactory(&IID_IDXGIFactory2, (void **)&factory);
> +    while (IDXGIFactory2_EnumAdapters(factory, adapter_id++, &adapter) != DXGI_ERROR_NOT_FOUND) {
> +        ID3D11Device* device = NULL;
> +        DXGI_ADAPTER_DESC adapter_desc;
> +
> +        hr = mD3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, creationFlags, NULL, 0, D3D11_SDK_VERSION, &device, NULL, NULL);
> +        if (FAILED(hr)) {
> +            av_log(ctx, AV_LOG_ERROR, "D3D11CreateDevice returned error\n");
> +            continue;
> +        }
> +
> +        hr = IDXGIAdapter2_GetDesc(adapter, &adapter_desc);
> +        if (FAILED(hr)) {
> +            av_log(ctx, AV_LOG_ERROR, "IDXGIAdapter2_GetDesc returned error\n");
> +            continue;
> +        }
> +
> +        if (device)
> +            ID3D11Device_Release(device);
> +
> +        if (adapter)
> +            IDXGIAdapter_Release(adapter);
> +
> +        if (adapter_desc.VendorId == vendor_id) {
> +            IDXGIFactory2_Release(factory);
> +            return adapter_id - 1;
> +        }
> +    }
> +    IDXGIFactory2_Release(factory);
> +    return -1;
> +}

This duplicates quite a bit of the function below.  Can you rearrange the code it to avoid doing that?

> +
>  static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device,
>                                   AVDictionary *opts, int flags)
>  {
>      AVD3D11VADeviceContext *device_hwctx = ctx->hwctx;
>  
>      HRESULT hr;
> +    AVDictionaryEntry *e;
>      IDXGIAdapter           *pAdapter = NULL;
>      ID3D10Multithread      *pMultithread;
>      UINT creationFlags = D3D11_CREATE_DEVICE_VIDEO_SUPPORT;
> +    int adapter = -1;
>      int is_debug       = !!av_dict_get(opts, "debug", NULL, 0);
>      int ret;
>  
> @@ -539,11 +591,24 @@ static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device,
>          return AVERROR_UNKNOWN;
>      }
>  
> +    e = av_dict_get(opts, "vendor", NULL, 0);
> +    if (e) {
> +        long int vendor_id = strtol(e->value, NULL, 0);
> +        adapter = d3d11va_device_find_adapter_by_vendor_id(ctx, creationFlags, vendor_id);
> +        if (adapter < 0) {
> +            av_log(ctx, AV_LOG_ERROR, "Failed to find d3d11va adapter by vendor id %s\n", e ? e->value : NULL);
> +            return AVERROR_UNKNOWN;
> +        }
> +    }
> +
>      if (device) {
> +        adapter = atoi(device);
> +    }
> +
> +    if (adapter >= 0) {
>          IDXGIFactory2 *pDXGIFactory;
>          hr = mCreateDXGIFactory(&IID_IDXGIFactory2, (void **)&pDXGIFactory);
>          if (SUCCEEDED(hr)) {
> -            int adapter = atoi(device);
>              if (FAILED(IDXGIFactory2_EnumAdapters(pDXGIFactory, adapter, &pAdapter)))
>                  pAdapter = NULL;
>              IDXGIFactory2_Release(pDXGIFactory);
> @@ -568,6 +633,7 @@ static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device,
>          return AVERROR_UNKNOWN;
>      }
>  
> +    av_log(ctx, AV_LOG_VERBOSE, "Using D3D11 device.\n");

This log message is not adding very much.

>      hr = ID3D11Device_QueryInterface(device_hwctx->device, &IID_ID3D10Multithread, (void **)&pMultithread);
>      if (SUCCEEDED(hr)) {
>          ID3D10Multithread_SetMultithreadProtected(pMultithread, TRUE);
> diff --git a/libavutil/hwcontext_d3d11va.h b/libavutil/hwcontext_d3d11va.h
> index 9f91e9b1b6..f3def15bea 100644
> --- a/libavutil/hwcontext_d3d11va.h
> +++ b/libavutil/hwcontext_d3d11va.h
> @@ -39,6 +39,11 @@
>  #include <d3d11.h>
>  #include <stdint.h>
>  
> +typedef struct D3D11TextureInfo {
> +    ID3D11Texture2D *texture;
> +    size_t index;
> +} D3D11TextureInfo;
> +
>  /**
>   * This struct is allocated as AVHWDeviceContext.hwctx
>   */
> @@ -164,6 +169,9 @@ typedef struct AVD3D11VAFramesContext {
>       * This field is ignored/invalid if a user-allocated texture is provided.
>       */
>      UINT MiscFlags;
> +
> +    D3D11TextureInfo *texture_infos;

Please include documentation for this new field.  (In particular, explain what the user should set it to in a user-created context.)

> +    size_t nb_surfaces_used;

Why is this value added to the public API?  You haven't used it outside hwcontext_d3d11.c.

>  } AVD3D11VAFramesContext;
>  
>  #endif /* AVUTIL_HWCONTEXT_D3D11VA_H */
> ...

- Mark
Soft Works April 26, 2020, 8 p.m. UTC | #2
> -----Original Message-----
> From: ffmpeg-devel <ffmpeg-devel-bounces@ffmpeg.org> On Behalf Of
> Mark Thompson
> Sent: Sunday, April 26, 2020 8:54 PM
> To: ffmpeg-devel@ffmpeg.org
> Subject: Re: [FFmpeg-devel] [PATCH v3 4/4] libavutil/qsv: enabling d3d11va
> support
> 
> On 24/04/2020 15:52, artem.galin@gmail.com wrote:
> > From: Artem Galin <artem.galin@intel.com>
> >
> > Makes selection of d3d11va device type by default and over DirectX 9,
> > which is still supported but requires explicit selection.
> 
> ... which might break users with older drivers/systems.  Some comment on
> exactly which setups are broken would be helpful here.

I have done some investigation on this question: https://github.com/softworkz/ffmpeg_dx11/issues/1

A short summary: 

- D3D11 will fail for Gen 3 Intel CPUs

- D3D11 will fail for Gen 4 and Gen 5 Intel CPUs as long as DX11 array textures are used
  (to get these working, the D3D11 hw context needs to be extended to support non-array textures)

- For all newer CPUs: For all drivers that are older than 14-16 months, D3D11 may fail
  (except when implementing support for non-array DX11 textures)

Note: by "working" or "fail" I'm considering the full set of hw features including VPP filters.
Simple decoding or encoding might still work in cases where I wrote "fail".


An additional objection I have is about the non-deterministic selection between D3D9 and DX11.
The -qsv_device parameter allows to specify the device numer/Index of a graphics adapter to use.

On Windows, the numbering graphic adapters is very different between D3D9 and DX11 (=> DXGI).
You could roughly say that D3D9 is counting by connected displays while DXGI is counting by 
Physical device.

As long as there is no way to specify whether to enforce D3D9 or DX11, it is impossible to know
which adapter ID should be specified when the implementation makes an internal decision whether
to select D3D9 or DX11. In that context, defaulting to DX11 will break applications that are 
specifying D3D9 adapter IDs.

There needs to be a deterministic and reliable behavior which can be controlled from the 
command line. The proposed method for selecting D3D9 is not sufficient from my point of view
because the QSV codecs are standalone codecs and intended to work without dealing with explicit
hw context creation. For the other half, there should also be a way to explicitly select "DX11-or-fail". 

IMO there should be a global command line option to explicitly choose between D3D9 or DX11.
(global, because there's no way to mix the two).


softworkz
Max Dmitrichenko April 28, 2020, 11:41 a.m. UTC | #3
On Sun, Apr 26, 2020 at 10:00 PM Soft Works <softworkz@hotmail.com> wrote:

> > -----Original Message-----
> > From: ffmpeg-devel <ffmpeg-devel-bounces@ffmpeg.org> On Behalf Of
> > Mark Thompson
> > Sent: Sunday, April 26, 2020 8:54 PM
> > To: ffmpeg-devel@ffmpeg.org
> > Subject: Re: [FFmpeg-devel] [PATCH v3 4/4] libavutil/qsv: enabling
> d3d11va
> > support
> >
> > On 24/04/2020 15:52, artem.galin@gmail.com wrote:
> > > From: Artem Galin <artem.galin@intel.com>
> > >
> > > Makes selection of d3d11va device type by default and over DirectX 9,
> > > which is still supported but requires explicit selection.
> >
> > ... which might break users with older drivers/systems.  Some comment on
> > exactly which setups are broken would be helpful here.
>
> I have done some investigation on this question:
> https://github.com/softworkz/ffmpeg_dx11/issues/1
>
> A short summary:
>
> - D3D11 will fail for Gen 3 Intel CPUs
>


DX9 is still possible to use,
this patch is not about DX9 removing


>
> - D3D11 will fail for Gen 4 and Gen 5 Intel CPUs as long as DX11 array
> textures are used
>   (to get these working, the D3D11 hw context needs to be extended to
> support non-array textures)
>
>

Feel free to share a patch with support of non-array textures


> - For all newer CPUs: For all drivers that are older than 14-16 months,
> D3D11 may fail
>   (except when implementing support for non-array DX11 textures)
>
>

Windows DCH Drivers allow to install latest drivers,
even on OEM devices


> Note: by "working" or "fail" I'm considering the full set of hw features
> including VPP filters.
> Simple decoding or encoding might still work in cases where I wrote "fail".
>
>

Feel free to share a patch with support



>
> An additional objection I have is about the non-deterministic selection
> between D3D9 and DX11.
> The -qsv_device parameter allows to specify the device numer/Index of a
> graphics adapter to use.
>
> On Windows, the numbering graphic adapters is very different between D3D9
> and DX11 (=> DXGI).
> You could roughly say that D3D9 is counting by connected displays while
> DXGI is counting by
> Physical device.
>
> As long as there is no way to specify whether to enforce D3D9 or DX11, it
> is impossible to know
> which adapter ID should be specified when the implementation makes an
> internal decision whether
> to select D3D9 or DX11. In that context, defaulting to DX11 will break
> applications that are
> specifying D3D9 adapter IDs.
>
> There needs to be a deterministic and reliable behavior which can be
> controlled from the
> command line. The proposed method for selecting D3D9 is not sufficient
> from my point of view
> because the QSV codecs are standalone codecs and intended to work without
> dealing with explicit
> hw context creation. For the other half, there should also be a way to
> explicitly select "DX11-or-fail".
>
> IMO there should be a global command line option to explicitly choose
> between D3D9 or DX11.
> (global, because there's no way to mix the two).
>
>

Usage examples describe explicit selection.

DX11 has certain advantages, already described, over DX9
and should be used by default,
this also helps to end-customers which are not (dont want to be?) very
familiar with DX details and limitations.
it is not possible to avoid such fact of switching.


> softworkz
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".



regards
Max
Artem Galin May 8, 2020, 4:08 p.m. UTC | #4
On Sun, 26 Apr 2020 at 19:54, Mark Thompson <sw@jkqxz.net> wrote:

> On 24/04/2020 15:52, artem.galin@gmail.com wrote:
> > From: Artem Galin <artem.galin@intel.com>
> >
> > Makes selection of d3d11va device type by default and over DirectX 9,
> > which is still supported but requires explicit selection.
>
> ... which might break users with older drivers/systems.  Some comment on
> exactly which setups are broken would be helpful here.
>
> > This enables usage of non-powered/headless GPU, better HDR support.
> > Pool of resources is allocated as one texture with array of slices.
> >
> > Added d3d11va device selection by vendor id.
> > Example: --init_hw_device d3d11va:,vendor=0x8086
> >
> > DirectX 9 usage.
> > Example: --init_hw_device qsv:hw,child_device_type=dxva2
> >
> > Signed-off-by: Artem Galin <artem.galin@intel.com>
> > ---
> >  libavutil/hwcontext_d3d11va.c |  82 +++++++-
> >  libavutil/hwcontext_d3d11va.h |   8 +
> >  libavutil/hwcontext_qsv.c     | 363 +++++++++++++++++++++++++++-------
> >  3 files changed, 379 insertions(+), 74 deletions(-)
>
> Please split this patch into the different changes.  There are at least
> three separate things here:
>
> Done in new patch set
https://patchwork.ffmpeg.org/project/ffmpeg/list/?series=1165


> - Adding more texture information to the D3D11 hwcontext API.
> - Adding the vendor option to D3D11 device creation.
> - Supporting D3D11 in libmfx hwcontext.
>
> Since the first one is an external API change it probably wants more
> explanation as to why it is wanted and the effects on compatibility.
>
> > diff --git a/libavutil/hwcontext_d3d11va.c
> b/libavutil/hwcontext_d3d11va.c
> > index c8ae58f908..c5e127aadb 100644
> > --- a/libavutil/hwcontext_d3d11va.c
> > +++ b/libavutil/hwcontext_d3d11va.c
> > @@ -72,7 +72,7 @@ static av_cold void load_functions(void)
> >  }
> >
> >  typedef struct D3D11VAFramesContext {
> > -    int nb_surfaces_used;
> > +    size_t nb_surfaces;
> >
> >      DXGI_FORMAT format;
> >
> > @@ -112,6 +112,8 @@ static void d3d11va_frames_uninit(AVHWFramesContext
> *ctx)
> >      if (s->staging_texture)
> >          ID3D11Texture2D_Release(s->staging_texture);
> >      s->staging_texture = NULL;
> > +
> > +    av_freep(&frames_hwctx->texture_infos);
> >  }
> >
> >  static int d3d11va_frames_get_constraints(AVHWDeviceContext *ctx,
> > @@ -152,8 +154,9 @@ static void free_texture(void *opaque, uint8_t *data)
> >      av_free(data);
> >  }
> >
> > -static AVBufferRef *wrap_texture_buf(ID3D11Texture2D *tex, int index)
> > +static AVBufferRef *wrap_texture_buf(AVHWFramesContext *ctx,
> ID3D11Texture2D *tex, int index)
> >  {
> > +    AVD3D11VAFramesContext *frames_hwctx = ctx->hwctx;
> >      AVBufferRef *buf;
> >      AVD3D11FrameDescriptor *desc = av_mallocz(sizeof(*desc));
> >      if (!desc) {
> > @@ -161,6 +164,10 @@ static AVBufferRef
> *wrap_texture_buf(ID3D11Texture2D *tex, int index)
> >          return NULL;
> >      }
> >
> > +    frames_hwctx->texture_infos[frames_hwctx->nb_surfaces_used].texture
> = tex;
> > +    frames_hwctx->texture_infos[frames_hwctx->nb_surfaces_used].index =
> index;
> > +    frames_hwctx->nb_surfaces_used++;
> > +
> >      desc->texture = tex;
> >      desc->index   = index;
> >
> > @@ -199,13 +206,12 @@ static AVBufferRef
> *d3d11va_alloc_single(AVHWFramesContext *ctx)
> >          return NULL;
> >      }
> >
> > -    return wrap_texture_buf(tex, 0);
> > +    return wrap_texture_buf(ctx, tex, 0);
> >  }
> >
> >  static AVBufferRef *d3d11va_pool_alloc(void *opaque, int size)
> >  {
> >      AVHWFramesContext        *ctx = (AVHWFramesContext*)opaque;
> > -    D3D11VAFramesContext       *s = ctx->internal->priv;
> >      AVD3D11VAFramesContext *hwctx = ctx->hwctx;
> >      D3D11_TEXTURE2D_DESC  texDesc;
> >
> > @@ -214,13 +220,13 @@ static AVBufferRef *d3d11va_pool_alloc(void
> *opaque, int size)
> >
> >      ID3D11Texture2D_GetDesc(hwctx->texture, &texDesc);
> >
> > -    if (s->nb_surfaces_used >= texDesc.ArraySize) {
> > +    if (hwctx->nb_surfaces_used >= texDesc.ArraySize) {
> >          av_log(ctx, AV_LOG_ERROR, "Static surface pool size
> exceeded.\n");
> >          return NULL;
> >      }
> >
> >      ID3D11Texture2D_AddRef(hwctx->texture);
> > -    return wrap_texture_buf(hwctx->texture, s->nb_surfaces_used++);
> > +    return wrap_texture_buf(ctx, hwctx->texture,
> hwctx->nb_surfaces_used);
> >  }
> >
> >  static int d3d11va_frames_init(AVHWFramesContext *ctx)
> > @@ -267,7 +273,7 @@ static int d3d11va_frames_init(AVHWFramesContext
> *ctx)
> >              av_log(ctx, AV_LOG_ERROR, "User-provided texture has
> mismatching parameters\n");
> >              return AVERROR(EINVAL);
> >          }
> > -    } else if (texDesc.ArraySize > 0) {
> > +    } else if (!(texDesc.BindFlags & D3D11_BIND_RENDER_TARGET) &&
> texDesc.ArraySize > 0) {
> >          hr = ID3D11Device_CreateTexture2D(device_hwctx->device,
> &texDesc, NULL, &hwctx->texture);
> >          if (FAILED(hr)) {
> >              av_log(ctx, AV_LOG_ERROR, "Could not create the texture
> (%lx)\n", (long)hr);
> > @@ -275,6 +281,12 @@ static int d3d11va_frames_init(AVHWFramesContext
> *ctx)
> >          }
> >      }
> >
> > +    hwctx->texture_infos = av_mallocz_array(ctx->initial_pool_size,
> sizeof(*hwctx->texture_infos));
> > +    if (!hwctx->texture_infos)
> > +        return AVERROR(ENOMEM);
> > +
> > +    s->nb_surfaces = ctx->initial_pool_size;
> > +
> >      ctx->internal->pool_internal =
> av_buffer_pool_init2(sizeof(AVD3D11FrameDescriptor),
> >                                                          ctx,
> d3d11va_pool_alloc, NULL);
> >      if (!ctx->internal->pool_internal)
> > @@ -511,15 +523,55 @@ static void
> d3d11va_device_uninit(AVHWDeviceContext *hwdev)
> >      }
> >  }
> >
> > +static int d3d11va_device_find_adapter_by_vendor_id(AVHWDeviceContext
> *ctx, UINT creationFlags, long int vendor_id)
> > +{
> > +    HRESULT hr;
> > +    IDXGIAdapter *adapter = NULL;
> > +    int adapter_id = 0;
> > +    IDXGIFactory2 *factory;
> > +    hr = mCreateDXGIFactory(&IID_IDXGIFactory2, (void **)&factory);
> > +    while (IDXGIFactory2_EnumAdapters(factory, adapter_id++, &adapter)
> != DXGI_ERROR_NOT_FOUND) {
> > +        ID3D11Device* device = NULL;
> > +        DXGI_ADAPTER_DESC adapter_desc;
> > +
> > +        hr = mD3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL,
> creationFlags, NULL, 0, D3D11_SDK_VERSION, &device, NULL, NULL);
> > +        if (FAILED(hr)) {
> > +            av_log(ctx, AV_LOG_ERROR, "D3D11CreateDevice returned
> error\n");
> > +            continue;
> > +        }
> > +
> > +        hr = IDXGIAdapter2_GetDesc(adapter, &adapter_desc);
> > +        if (FAILED(hr)) {
> > +            av_log(ctx, AV_LOG_ERROR, "IDXGIAdapter2_GetDesc returned
> error\n");
> > +            continue;
> > +        }
> > +
> > +        if (device)
> > +            ID3D11Device_Release(device);
> > +
> > +        if (adapter)
> > +            IDXGIAdapter_Release(adapter);
> > +
> > +        if (adapter_desc.VendorId == vendor_id) {
> > +            IDXGIFactory2_Release(factory);
> > +            return adapter_id - 1;
> > +        }
> > +    }
> > +    IDXGIFactory2_Release(factory);
> > +    return -1;
> > +}
>
> This duplicates quite a bit of the function below.  Can you rearrange the
> code it to avoid doing that?
>
Refactored.

>
> > +
> >  static int d3d11va_device_create(AVHWDeviceContext *ctx, const char
> *device,
> >                                   AVDictionary *opts, int flags)
> >  {
> >      AVD3D11VADeviceContext *device_hwctx = ctx->hwctx;
> >
> >      HRESULT hr;
> > +    AVDictionaryEntry *e;
> >      IDXGIAdapter           *pAdapter = NULL;
> >      ID3D10Multithread      *pMultithread;
> >      UINT creationFlags = D3D11_CREATE_DEVICE_VIDEO_SUPPORT;
> > +    int adapter = -1;
> >      int is_debug       = !!av_dict_get(opts, "debug", NULL, 0);
> >      int ret;
> >
> > @@ -539,11 +591,24 @@ static int d3d11va_device_create(AVHWDeviceContext
> *ctx, const char *device,
> >          return AVERROR_UNKNOWN;
> >      }
> >
> > +    e = av_dict_get(opts, "vendor", NULL, 0);
> > +    if (e) {
> > +        long int vendor_id = strtol(e->value, NULL, 0);
> > +        adapter = d3d11va_device_find_adapter_by_vendor_id(ctx,
> creationFlags, vendor_id);
> > +        if (adapter < 0) {
> > +            av_log(ctx, AV_LOG_ERROR, "Failed to find d3d11va adapter
> by vendor id %s\n", e ? e->value : NULL);
> > +            return AVERROR_UNKNOWN;
> > +        }
> > +    }
> > +
> >      if (device) {
> > +        adapter = atoi(device);
> > +    }
> > +
> > +    if (adapter >= 0) {
> >          IDXGIFactory2 *pDXGIFactory;
> >          hr = mCreateDXGIFactory(&IID_IDXGIFactory2, (void
> **)&pDXGIFactory);
> >          if (SUCCEEDED(hr)) {
> > -            int adapter = atoi(device);
> >              if (FAILED(IDXGIFactory2_EnumAdapters(pDXGIFactory,
> adapter, &pAdapter)))
> >                  pAdapter = NULL;
> >              IDXGIFactory2_Release(pDXGIFactory);
> > @@ -568,6 +633,7 @@ static int d3d11va_device_create(AVHWDeviceContext
> *ctx, const char *device,
> >          return AVERROR_UNKNOWN;
> >      }
> >
> > +    av_log(ctx, AV_LOG_VERBOSE, "Using D3D11 device.\n");
>
> This log message is not adding very much.
>
Fixed.

>
> >      hr = ID3D11Device_QueryInterface(device_hwctx->device,
> &IID_ID3D10Multithread, (void **)&pMultithread);
> >      if (SUCCEEDED(hr)) {
> >          ID3D10Multithread_SetMultithreadProtected(pMultithread, TRUE);
> > diff --git a/libavutil/hwcontext_d3d11va.h
> b/libavutil/hwcontext_d3d11va.h
> > index 9f91e9b1b6..f3def15bea 100644
> > --- a/libavutil/hwcontext_d3d11va.h
> > +++ b/libavutil/hwcontext_d3d11va.h
> > @@ -39,6 +39,11 @@
> >  #include <d3d11.h>
> >  #include <stdint.h>
> >
> > +typedef struct D3D11TextureInfo {
> > +    ID3D11Texture2D *texture;
> > +    size_t index;
> > +} D3D11TextureInfo;
> > +
> >  /**
> >   * This struct is allocated as AVHWDeviceContext.hwctx
> >   */
> > @@ -164,6 +169,9 @@ typedef struct AVD3D11VAFramesContext {
> >       * This field is ignored/invalid if a user-allocated texture is
> provided.
> >       */
> >      UINT MiscFlags;
> > +
> > +    D3D11TextureInfo *texture_infos;
>
> Please include documentation for this new field.  (In particular, explain
> what the user should set it to in a user-created context.)
>
> > +    size_t nb_surfaces_used;
>
> Why is this value added to the public API?  You haven't used it outside
> hwcontext_d3d11.c.
>
> >  } AVD3D11VAFramesContext;
> >
> >  #endif /* AVUTIL_HWCONTEXT_D3D11VA_H */
> > ...
>
> - Mark
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
diff mbox series

Patch

diff --git a/libavutil/hwcontext_d3d11va.c b/libavutil/hwcontext_d3d11va.c
index c8ae58f908..c5e127aadb 100644
--- a/libavutil/hwcontext_d3d11va.c
+++ b/libavutil/hwcontext_d3d11va.c
@@ -72,7 +72,7 @@  static av_cold void load_functions(void)
 }
 
 typedef struct D3D11VAFramesContext {
-    int nb_surfaces_used;
+    size_t nb_surfaces;
 
     DXGI_FORMAT format;
 
@@ -112,6 +112,8 @@  static void d3d11va_frames_uninit(AVHWFramesContext *ctx)
     if (s->staging_texture)
         ID3D11Texture2D_Release(s->staging_texture);
     s->staging_texture = NULL;
+
+    av_freep(&frames_hwctx->texture_infos);
 }
 
 static int d3d11va_frames_get_constraints(AVHWDeviceContext *ctx,
@@ -152,8 +154,9 @@  static void free_texture(void *opaque, uint8_t *data)
     av_free(data);
 }
 
-static AVBufferRef *wrap_texture_buf(ID3D11Texture2D *tex, int index)
+static AVBufferRef *wrap_texture_buf(AVHWFramesContext *ctx, ID3D11Texture2D *tex, int index)
 {
+    AVD3D11VAFramesContext *frames_hwctx = ctx->hwctx;
     AVBufferRef *buf;
     AVD3D11FrameDescriptor *desc = av_mallocz(sizeof(*desc));
     if (!desc) {
@@ -161,6 +164,10 @@  static AVBufferRef *wrap_texture_buf(ID3D11Texture2D *tex, int index)
         return NULL;
     }
 
+    frames_hwctx->texture_infos[frames_hwctx->nb_surfaces_used].texture = tex;
+    frames_hwctx->texture_infos[frames_hwctx->nb_surfaces_used].index = index;
+    frames_hwctx->nb_surfaces_used++;
+
     desc->texture = tex;
     desc->index   = index;
 
@@ -199,13 +206,12 @@  static AVBufferRef *d3d11va_alloc_single(AVHWFramesContext *ctx)
         return NULL;
     }
 
-    return wrap_texture_buf(tex, 0);
+    return wrap_texture_buf(ctx, tex, 0);
 }
 
 static AVBufferRef *d3d11va_pool_alloc(void *opaque, int size)
 {
     AVHWFramesContext        *ctx = (AVHWFramesContext*)opaque;
-    D3D11VAFramesContext       *s = ctx->internal->priv;
     AVD3D11VAFramesContext *hwctx = ctx->hwctx;
     D3D11_TEXTURE2D_DESC  texDesc;
 
@@ -214,13 +220,13 @@  static AVBufferRef *d3d11va_pool_alloc(void *opaque, int size)
 
     ID3D11Texture2D_GetDesc(hwctx->texture, &texDesc);
 
-    if (s->nb_surfaces_used >= texDesc.ArraySize) {
+    if (hwctx->nb_surfaces_used >= texDesc.ArraySize) {
         av_log(ctx, AV_LOG_ERROR, "Static surface pool size exceeded.\n");
         return NULL;
     }
 
     ID3D11Texture2D_AddRef(hwctx->texture);
-    return wrap_texture_buf(hwctx->texture, s->nb_surfaces_used++);
+    return wrap_texture_buf(ctx, hwctx->texture, hwctx->nb_surfaces_used);
 }
 
 static int d3d11va_frames_init(AVHWFramesContext *ctx)
@@ -267,7 +273,7 @@  static int d3d11va_frames_init(AVHWFramesContext *ctx)
             av_log(ctx, AV_LOG_ERROR, "User-provided texture has mismatching parameters\n");
             return AVERROR(EINVAL);
         }
-    } else if (texDesc.ArraySize > 0) {
+    } else if (!(texDesc.BindFlags & D3D11_BIND_RENDER_TARGET) && texDesc.ArraySize > 0) {
         hr = ID3D11Device_CreateTexture2D(device_hwctx->device, &texDesc, NULL, &hwctx->texture);
         if (FAILED(hr)) {
             av_log(ctx, AV_LOG_ERROR, "Could not create the texture (%lx)\n", (long)hr);
@@ -275,6 +281,12 @@  static int d3d11va_frames_init(AVHWFramesContext *ctx)
         }
     }
 
+    hwctx->texture_infos = av_mallocz_array(ctx->initial_pool_size, sizeof(*hwctx->texture_infos));
+    if (!hwctx->texture_infos)
+        return AVERROR(ENOMEM);
+
+    s->nb_surfaces = ctx->initial_pool_size;
+
     ctx->internal->pool_internal = av_buffer_pool_init2(sizeof(AVD3D11FrameDescriptor),
                                                         ctx, d3d11va_pool_alloc, NULL);
     if (!ctx->internal->pool_internal)
@@ -511,15 +523,55 @@  static void d3d11va_device_uninit(AVHWDeviceContext *hwdev)
     }
 }
 
+static int d3d11va_device_find_adapter_by_vendor_id(AVHWDeviceContext *ctx, UINT creationFlags, long int vendor_id)
+{
+    HRESULT hr;
+    IDXGIAdapter *adapter = NULL;
+    int adapter_id = 0;
+    IDXGIFactory2 *factory;
+    hr = mCreateDXGIFactory(&IID_IDXGIFactory2, (void **)&factory);
+    while (IDXGIFactory2_EnumAdapters(factory, adapter_id++, &adapter) != DXGI_ERROR_NOT_FOUND) {
+        ID3D11Device* device = NULL;
+        DXGI_ADAPTER_DESC adapter_desc;
+
+        hr = mD3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, creationFlags, NULL, 0, D3D11_SDK_VERSION, &device, NULL, NULL);
+        if (FAILED(hr)) {
+            av_log(ctx, AV_LOG_ERROR, "D3D11CreateDevice returned error\n");
+            continue;
+        }
+
+        hr = IDXGIAdapter2_GetDesc(adapter, &adapter_desc);
+        if (FAILED(hr)) {
+            av_log(ctx, AV_LOG_ERROR, "IDXGIAdapter2_GetDesc returned error\n");
+            continue;
+        }
+
+        if (device)
+            ID3D11Device_Release(device);
+
+        if (adapter)
+            IDXGIAdapter_Release(adapter);
+
+        if (adapter_desc.VendorId == vendor_id) {
+            IDXGIFactory2_Release(factory);
+            return adapter_id - 1;
+        }
+    }
+    IDXGIFactory2_Release(factory);
+    return -1;
+}
+
 static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device,
                                  AVDictionary *opts, int flags)
 {
     AVD3D11VADeviceContext *device_hwctx = ctx->hwctx;
 
     HRESULT hr;
+    AVDictionaryEntry *e;
     IDXGIAdapter           *pAdapter = NULL;
     ID3D10Multithread      *pMultithread;
     UINT creationFlags = D3D11_CREATE_DEVICE_VIDEO_SUPPORT;
+    int adapter = -1;
     int is_debug       = !!av_dict_get(opts, "debug", NULL, 0);
     int ret;
 
@@ -539,11 +591,24 @@  static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device,
         return AVERROR_UNKNOWN;
     }
 
+    e = av_dict_get(opts, "vendor", NULL, 0);
+    if (e) {
+        long int vendor_id = strtol(e->value, NULL, 0);
+        adapter = d3d11va_device_find_adapter_by_vendor_id(ctx, creationFlags, vendor_id);
+        if (adapter < 0) {
+            av_log(ctx, AV_LOG_ERROR, "Failed to find d3d11va adapter by vendor id %s\n", e ? e->value : NULL);
+            return AVERROR_UNKNOWN;
+        }
+    }
+
     if (device) {
+        adapter = atoi(device);
+    }
+
+    if (adapter >= 0) {
         IDXGIFactory2 *pDXGIFactory;
         hr = mCreateDXGIFactory(&IID_IDXGIFactory2, (void **)&pDXGIFactory);
         if (SUCCEEDED(hr)) {
-            int adapter = atoi(device);
             if (FAILED(IDXGIFactory2_EnumAdapters(pDXGIFactory, adapter, &pAdapter)))
                 pAdapter = NULL;
             IDXGIFactory2_Release(pDXGIFactory);
@@ -568,6 +633,7 @@  static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device,
         return AVERROR_UNKNOWN;
     }
 
+    av_log(ctx, AV_LOG_VERBOSE, "Using D3D11 device.\n");
     hr = ID3D11Device_QueryInterface(device_hwctx->device, &IID_ID3D10Multithread, (void **)&pMultithread);
     if (SUCCEEDED(hr)) {
         ID3D10Multithread_SetMultithreadProtected(pMultithread, TRUE);
diff --git a/libavutil/hwcontext_d3d11va.h b/libavutil/hwcontext_d3d11va.h
index 9f91e9b1b6..f3def15bea 100644
--- a/libavutil/hwcontext_d3d11va.h
+++ b/libavutil/hwcontext_d3d11va.h
@@ -39,6 +39,11 @@ 
 #include <d3d11.h>
 #include <stdint.h>
 
+typedef struct D3D11TextureInfo {
+    ID3D11Texture2D *texture;
+    size_t index;
+} D3D11TextureInfo;
+
 /**
  * This struct is allocated as AVHWDeviceContext.hwctx
  */
@@ -164,6 +169,9 @@  typedef struct AVD3D11VAFramesContext {
      * This field is ignored/invalid if a user-allocated texture is provided.
      */
     UINT MiscFlags;
+
+    D3D11TextureInfo *texture_infos;
+    size_t nb_surfaces_used;
 } AVD3D11VAFramesContext;
 
 #endif /* AVUTIL_HWCONTEXT_D3D11VA_H */
diff --git a/libavutil/hwcontext_qsv.c b/libavutil/hwcontext_qsv.c
index b1b67400de..3a9c3f8ff0 100644
--- a/libavutil/hwcontext_qsv.c
+++ b/libavutil/hwcontext_qsv.c
@@ -27,9 +27,13 @@ 
 #include <pthread.h>
 #endif
 
+#define COBJMACROS
 #if CONFIG_VAAPI
 #include "hwcontext_vaapi.h"
 #endif
+#if CONFIG_D3D11VA
+#include "hwcontext_d3d11va.h"
+#endif
 #if CONFIG_DXVA2
 #include "hwcontext_dxva2.h"
 #endif
@@ -44,6 +48,8 @@ 
 #include "pixdesc.h"
 #include "time.h"
 
+#define MFX_IMPL_VIA_MASK(impl) (0x0f00 & (impl))
+
 typedef struct QSVDevicePriv {
     AVBufferRef *child_device_ctx;
 } QSVDevicePriv;
@@ -70,6 +76,7 @@  typedef struct QSVFramesContext {
 
     AVBufferRef *child_frames_ref;
     mfxFrameSurface1 *surfaces_internal;
+    mfxHDLPair *handle_pairs_internal;
     int             nb_surfaces_used;
 
     // used in the frame allocator for non-opaque surfaces
@@ -81,20 +88,6 @@  typedef struct QSVFramesContext {
     mfxExtBuffer *ext_buffers[1];
 } QSVFramesContext;
 
-static const struct {
-    mfxHandleType handle_type;
-    enum AVHWDeviceType device_type;
-    enum AVPixelFormat  pix_fmt;
-} supported_handle_types[] = {
-#if CONFIG_VAAPI
-    { MFX_HANDLE_VA_DISPLAY,          AV_HWDEVICE_TYPE_VAAPI, AV_PIX_FMT_VAAPI },
-#endif
-#if CONFIG_DXVA2
-    { MFX_HANDLE_D3D9_DEVICE_MANAGER, AV_HWDEVICE_TYPE_DXVA2, AV_PIX_FMT_DXVA2_VLD },
-#endif
-    { 0 },
-};
-
 static const struct {
     enum AVPixelFormat pix_fmt;
     uint32_t           fourcc;
@@ -115,28 +108,32 @@  static uint32_t qsv_fourcc_from_pix_fmt(enum AVPixelFormat pix_fmt)
     return 0;
 }
 
+#if CONFIG_D3D11VA
+static uint32_t qsv_get_d3d11va_bind_flags(int mem_type)
+{
+    uint32_t bind_flags = 0;
+
+    if ((mem_type & MFX_MEMTYPE_VIDEO_MEMORY_ENCODER_TARGET) && (mem_type & MFX_MEMTYPE_INTERNAL_FRAME))
+        bind_flags = D3D11_BIND_DECODER | D3D11_BIND_VIDEO_ENCODER;
+    else
+        bind_flags = D3D11_BIND_DECODER;
+
+    if ((MFX_MEMTYPE_FROM_VPPOUT & mem_type) || (MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET & mem_type))
+        bind_flags = D3D11_BIND_RENDER_TARGET;
+
+    return bind_flags;
+}
+#endif
+
 static int qsv_device_init(AVHWDeviceContext *ctx)
 {
     AVQSVDeviceContext *hwctx = ctx->hwctx;
     QSVDeviceContext       *s = ctx->internal->priv;
-
+    int   hw_handle_supported = 0;
+    mfxHandleType handle_type;
+    enum AVHWDeviceType device_type;
+    enum AVPixelFormat  pix_fmt;
     mfxStatus err;
-    int i;
-
-    for (i = 0; supported_handle_types[i].handle_type; i++) {
-        err = MFXVideoCORE_GetHandle(hwctx->session, supported_handle_types[i].handle_type,
-                                     &s->handle);
-        if (err == MFX_ERR_NONE) {
-            s->handle_type       = supported_handle_types[i].handle_type;
-            s->child_device_type = supported_handle_types[i].device_type;
-            s->child_pix_fmt     = supported_handle_types[i].pix_fmt;
-            break;
-        }
-    }
-    if (!s->handle) {
-        av_log(ctx, AV_LOG_VERBOSE, "No supported hw handle could be retrieved "
-               "from the session\n");
-    }
 
     err = MFXQueryIMPL(hwctx->session, &s->impl);
     if (err == MFX_ERR_NONE)
@@ -146,6 +143,41 @@  static int qsv_device_init(AVHWDeviceContext *ctx)
         return AVERROR_UNKNOWN;
     }
 
+    if (MFX_IMPL_VIA_VAAPI == MFX_IMPL_VIA_MASK(s->impl)) {
+#if CONFIG_VAAPI
+        handle_type = MFX_HANDLE_VA_DISPLAY;
+        device_type = AV_HWDEVICE_TYPE_VAAPI;
+        pix_fmt = AV_PIX_FMT_VAAPI;
+        hw_handle_supported = 1;
+#endif
+    } else if (MFX_IMPL_VIA_D3D11 == MFX_IMPL_VIA_MASK(s->impl)) {
+#if CONFIG_D3D11VA
+        handle_type = MFX_HANDLE_D3D11_DEVICE;
+        device_type = AV_HWDEVICE_TYPE_D3D11VA;
+        pix_fmt = AV_PIX_FMT_D3D11;
+        hw_handle_supported = 1;
+#endif
+    } else if (MFX_IMPL_VIA_D3D9 == MFX_IMPL_VIA_MASK(s->impl)) {
+#if CONFIG_DXVA2
+        handle_type = MFX_HANDLE_D3D9_DEVICE_MANAGER;
+        device_type = AV_HWDEVICE_TYPE_DXVA2;
+        pix_fmt = AV_PIX_FMT_DXVA2_VLD;
+        hw_handle_supported = 1;
+#endif
+    }
+
+    if (hw_handle_supported) {
+        err = MFXVideoCORE_GetHandle(hwctx->session, handle_type, &s->handle);
+        if (err == MFX_ERR_NONE) {
+            s->handle_type       = handle_type;
+            s->child_device_type = device_type;
+            s->child_pix_fmt     = pix_fmt;
+        }
+    }
+    if (!s->handle) {
+        av_log(ctx, AV_LOG_VERBOSE, "No supported hw handle could be retrieved "
+               "from the session\n");
+    }
     return 0;
 }
 
@@ -175,6 +207,7 @@  static void qsv_frames_uninit(AVHWFramesContext *ctx)
     av_freep(&s->mem_ids);
     av_freep(&s->surface_ptrs);
     av_freep(&s->surfaces_internal);
+    av_freep(&s->handle_pairs_internal);
     av_buffer_unref(&s->child_frames_ref);
 }
 
@@ -190,6 +223,8 @@  static AVBufferRef *qsv_pool_alloc(void *opaque, int size)
 
     if (s->nb_surfaces_used < hwctx->nb_surfaces) {
         s->nb_surfaces_used++;
+        av_buffer_create((uint8_t*)(s->handle_pairs_internal + s->nb_surfaces_used - 1),
+                                sizeof(*s->handle_pairs_internal), qsv_pool_release_dummy, NULL, 0);
         return av_buffer_create((uint8_t*)(s->surfaces_internal + s->nb_surfaces_used - 1),
                                 sizeof(*hwctx->surfaces), qsv_pool_release_dummy, NULL, 0);
     }
@@ -229,6 +264,13 @@  static int qsv_init_child_ctx(AVHWFramesContext *ctx)
         child_device_hwctx->display = (VADisplay)device_priv->handle;
     }
 #endif
+#if CONFIG_D3D11VA
+    if (child_device_ctx->type == AV_HWDEVICE_TYPE_D3D11VA) {
+        AVD3D11VADeviceContext *child_device_hwctx = child_device_ctx->hwctx;
+        ID3D11Device_AddRef((ID3D11Device*)device_priv->handle);
+        child_device_hwctx->device = (ID3D11Device*)device_priv->handle;
+    }
+#endif
 #if CONFIG_DXVA2
     if (child_device_ctx->type == AV_HWDEVICE_TYPE_DXVA2) {
         AVDXVA2DeviceContext *child_device_hwctx = child_device_ctx->hwctx;
@@ -255,6 +297,16 @@  static int qsv_init_child_ctx(AVHWFramesContext *ctx)
     child_frames_ctx->width             = FFALIGN(ctx->width, 16);
     child_frames_ctx->height            = FFALIGN(ctx->height, 16);
 
+#if CONFIG_D3D11VA
+    if (child_device_ctx->type == AV_HWDEVICE_TYPE_D3D11VA) {
+        AVD3D11VAFramesContext *child_frames_hwctx = child_frames_ctx->hwctx;
+        if (hwctx->frame_type == 0)
+            hwctx->frame_type = MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET;
+        if (hwctx->frame_type & MFX_MEMTYPE_SHARED_RESOURCE)
+            child_frames_hwctx->MiscFlags = D3D11_RESOURCE_MISC_SHARED;
+        child_frames_hwctx->BindFlags = qsv_get_d3d11va_bind_flags(hwctx->frame_type);
+    }
+#endif
 #if CONFIG_DXVA2
     if (child_device_ctx->type == AV_HWDEVICE_TYPE_DXVA2) {
         AVDXVA2FramesContext *child_frames_hwctx = child_frames_ctx->hwctx;
@@ -279,11 +331,33 @@  static int qsv_init_child_ctx(AVHWFramesContext *ctx)
         hwctx->frame_type = MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET;
     }
 #endif
+#if CONFIG_D3D11VA
+    if (child_device_ctx->type == AV_HWDEVICE_TYPE_D3D11VA) {
+        AVD3D11VAFramesContext *child_frames_hwctx = child_frames_ctx->hwctx;
+        for (i = 0; i < ctx->initial_pool_size; i++) {
+            s->handle_pairs_internal[i].first = (mfxMemId)child_frames_hwctx->texture_infos[i].texture;
+            if(child_frames_hwctx->BindFlags & D3D11_BIND_RENDER_TARGET) {
+                s->handle_pairs_internal[i].second = (mfxMemId)MFX_INFINITE;
+            } else {
+                s->handle_pairs_internal[i].second = (mfxMemId)child_frames_hwctx->texture_infos[i].index;
+            }
+            s->surfaces_internal[i].Data.MemId = (mfxMemId)&s->handle_pairs_internal[i];
+        }
+        if (child_frames_hwctx->BindFlags & D3D11_BIND_RENDER_TARGET) {
+            hwctx->frame_type |= MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET;
+        } else {
+            hwctx->frame_type |= MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET;
+        }
+    }
+#endif
 #if CONFIG_DXVA2
     if (child_device_ctx->type == AV_HWDEVICE_TYPE_DXVA2) {
         AVDXVA2FramesContext *child_frames_hwctx = child_frames_ctx->hwctx;
-        for (i = 0; i < ctx->initial_pool_size; i++)
-            s->surfaces_internal[i].Data.MemId = (mfxMemId)child_frames_hwctx->surfaces[i];
+        for (i = 0; i < ctx->initial_pool_size; i++) {
+            s->handle_pairs_internal[i].first = (mfxMemId)child_frames_hwctx->surfaces[i];
+            s->handle_pairs_internal[i].second = (mfxMemId)MFX_INFINITE;
+            s->surfaces_internal[i].Data.MemId = (mfxMemId)&s->handle_pairs_internal[i];
+        }
         if (child_frames_hwctx->surface_type == DXVA2_VideoProcessorRenderTarget)
             hwctx->frame_type = MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET;
         else
@@ -348,6 +422,11 @@  static int qsv_init_pool(AVHWFramesContext *ctx, uint32_t fourcc)
         return AVERROR(EINVAL);
     }
 
+    s->handle_pairs_internal = av_mallocz_array(ctx->initial_pool_size,
+                                            sizeof(*s->handle_pairs_internal));
+    if (!s->handle_pairs_internal)
+        return AVERROR(ENOMEM);
+
     s->surfaces_internal = av_mallocz_array(ctx->initial_pool_size,
                                             sizeof(*s->surfaces_internal));
     if (!s->surfaces_internal)
@@ -421,7 +500,17 @@  static mfxStatus frame_unlock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr)
 
 static mfxStatus frame_get_hdl(mfxHDL pthis, mfxMemId mid, mfxHDL *hdl)
 {
+#if CONFIG_VAAPI
     *hdl = mid;
+#else
+    mfxHDLPair *pair_dst = (mfxHDLPair*)hdl;
+    mfxHDLPair *pair_src = (mfxHDLPair*)mid;
+
+    pair_dst->first = pair_src->first;
+
+    if (pair_src->second != (mfxMemId)MFX_INFINITE)
+        pair_dst->second = pair_src->second;
+#endif
     return MFX_ERR_NONE;
 }
 
@@ -621,6 +710,18 @@  static int qsv_frames_derive_from(AVHWFramesContext *dst_ctx,
         }
         break;
 #endif
+#if CONFIG_D3D11VA
+    case AV_HWDEVICE_TYPE_D3D11VA:
+        {
+            AVD3D11VAFramesContext *dst_hwctx = dst_ctx->hwctx;
+            mfxHDLPair *pair = (mfxHDLPair*)src_hwctx->surfaces[i].Data.MemId;
+            dst_hwctx->texture = (ID3D11Texture2D*)pair->first;
+            if (src_hwctx->frame_type & MFX_MEMTYPE_SHARED_RESOURCE)
+                dst_hwctx->MiscFlags = D3D11_RESOURCE_MISC_SHARED;
+            dst_hwctx->BindFlags = qsv_get_d3d11va_bind_flags(src_hwctx->frame_type);
+        }
+        break;
+#endif
 #if CONFIG_DXVA2
     case AV_HWDEVICE_TYPE_DXVA2:
         {
@@ -629,9 +730,10 @@  static int qsv_frames_derive_from(AVHWFramesContext *dst_ctx,
                                                    sizeof(*dst_hwctx->surfaces));
             if (!dst_hwctx->surfaces)
                 return AVERROR(ENOMEM);
-            for (i = 0; i < src_hwctx->nb_surfaces; i++)
-                dst_hwctx->surfaces[i] =
-                    (IDirect3DSurface9*)src_hwctx->surfaces[i].Data.MemId;
+            for (i = 0; i < src_hwctx->nb_surfaces; i++) {
+                mfxHDLPair *pair = (mfxHDLPair*)src_hwctx->surfaces[i].Data.MemId;
+                dst_hwctx->surfaces[i] = (IDirect3DSurface9*)pair->first;
+            }
             dst_hwctx->nb_surfaces = src_hwctx->nb_surfaces;
             if (src_hwctx->frame_type == MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET)
                 dst_hwctx->surface_type = DXVA2_VideoDecoderRenderTarget;
@@ -668,10 +770,21 @@  static int qsv_map_from(AVHWFramesContext *ctx,
         child_data = (uint8_t*)(intptr_t)*(VASurfaceID*)surf->Data.MemId;
         break;
 #endif
+#if CONFIG_D3D11VA
+    case AV_HWDEVICE_TYPE_D3D11VA:
+    {
+        mfxHDLPair *pair = (mfxHDLPair*)surf->Data.MemId;
+        child_data = pair->first;
+        break;
+    }
+#endif
 #if CONFIG_DXVA2
     case AV_HWDEVICE_TYPE_DXVA2:
-        child_data = surf->Data.MemId;
+    {
+        mfxHDLPair *pair = (mfxHDLPair*)surf->Data.MemId;
+        child_data = pair->first;
         break;
+    }
 #endif
     default:
         return AVERROR(ENOSYS);
@@ -685,7 +798,14 @@  static int qsv_map_from(AVHWFramesContext *ctx,
 
         dst->width   = src->width;
         dst->height  = src->height;
-        dst->data[3] = child_data;
+
+       if (child_frames_ctx->device_ctx->type == AV_HWDEVICE_TYPE_D3D11VA) {
+            mfxHDLPair *pair = (mfxHDLPair*)surf->Data.MemId;
+            dst->data[0] = pair->first;
+            dst->data[1] = pair->second;
+        } else {
+            dst->data[3] = child_data;
+        }
 
         return 0;
     }
@@ -708,7 +828,14 @@  static int qsv_map_from(AVHWFramesContext *ctx,
     dummy->format        = child_frames_ctx->format;
     dummy->width         = src->width;
     dummy->height        = src->height;
-    dummy->data[3]       = child_data;
+
+    if (child_frames_ctx->device_ctx->type == AV_HWDEVICE_TYPE_D3D11VA) {
+        mfxHDLPair *pair = (mfxHDLPair*)surf->Data.MemId;
+        dummy->data[0] = pair->first;
+        dummy->data[1] = pair->second;
+    } else {
+        dummy->data[3] = child_data;
+    }
 
     ret = av_hwframe_map(dst, dummy, flags);
 
@@ -954,6 +1081,12 @@  static int qsv_frames_derive_to(AVHWFramesContext *dst_ctx,
     AVQSVFramesContext *dst_hwctx = dst_ctx->hwctx;
     int i;
 
+    if (src_ctx->initial_pool_size == 0) {
+        av_log(dst_ctx, AV_LOG_ERROR, "Only fixed-size pools can be "
+            "mapped to QSV frames.\n");
+        return AVERROR(EINVAL);
+    }
+
     switch (src_ctx->device_ctx->type) {
 #if CONFIG_VAAPI
     case AV_HWDEVICE_TYPE_VAAPI:
@@ -972,6 +1105,36 @@  static int qsv_frames_derive_to(AVHWFramesContext *dst_ctx,
         }
         break;
 #endif
+#if CONFIG_D3D11VA
+    case AV_HWDEVICE_TYPE_D3D11VA:
+        {
+            AVD3D11VAFramesContext *src_hwctx = src_ctx->hwctx;
+            s->handle_pairs_internal = av_mallocz_array(src_ctx->initial_pool_size, sizeof(*s->handle_pairs_internal));
+            if (!s->handle_pairs_internal)
+                return AVERROR(ENOMEM);
+            s->surfaces_internal = av_mallocz_array(src_ctx->initial_pool_size,
+                                                    sizeof(*s->surfaces_internal));
+            if (!s->surfaces_internal)
+                return AVERROR(ENOMEM);
+            for (i = 0; i < src_ctx->initial_pool_size; i++) {
+                qsv_init_surface(dst_ctx, &s->surfaces_internal[i]);
+                s->handle_pairs_internal[i].first = (mfxMemId)src_hwctx->texture_infos[i].texture;
+                if (src_hwctx->BindFlags & D3D11_BIND_RENDER_TARGET) {
+                    s->handle_pairs_internal[i].second = (mfxMemId)MFX_INFINITE;
+                } else {
+                    s->handle_pairs_internal[i].second = (mfxMemId)src_hwctx->texture_infos[i].index;
+                }
+                s->surfaces_internal[i].Data.MemId = (mfxMemId)&s->handle_pairs_internal[i];
+            }
+            dst_hwctx->nb_surfaces = src_ctx->initial_pool_size;
+            if (src_hwctx->BindFlags & D3D11_BIND_RENDER_TARGET) {
+                dst_hwctx->frame_type |= MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET;
+            } else {
+                dst_hwctx->frame_type |= MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET;
+            }
+        }
+        break;
+#endif
 #if CONFIG_DXVA2
     case AV_HWDEVICE_TYPE_DXVA2:
         {
@@ -982,7 +1145,9 @@  static int qsv_frames_derive_to(AVHWFramesContext *dst_ctx,
                 return AVERROR(ENOMEM);
             for (i = 0; i < src_hwctx->nb_surfaces; i++) {
                 qsv_init_surface(dst_ctx, &s->surfaces_internal[i]);
-                s->surfaces_internal[i].Data.MemId = (mfxMemId)src_hwctx->surfaces[i];
+                s->handle_pairs_internal[i].first = (mfxMemId)src_hwctx->surfaces[i];
+                s->handle_pairs_internal[i].second = (mfxMemId)MFX_INFINITE;
+                s->surfaces_internal[i].Data.MemId = (mfxMemId)&s->handle_pairs_internal[i];
             }
             dst_hwctx->nb_surfaces = src_hwctx->nb_surfaces;
             if (src_hwctx->surface_type == DXVA2_VideoProcessorRenderTarget)
@@ -1005,21 +1170,41 @@  static int qsv_map_to(AVHWFramesContext *dst_ctx,
                       AVFrame *dst, const AVFrame *src, int flags)
 {
     AVQSVFramesContext *hwctx = dst_ctx->hwctx;
-    int i, err;
+    int i, err, index = -1;
 
-    for (i = 0; i < hwctx->nb_surfaces; i++) {
+    for (i = 0; i < hwctx->nb_surfaces && index < 0; i++) {
+        switch(src->format) {
 #if CONFIG_VAAPI
-        if (*(VASurfaceID*)hwctx->surfaces[i].Data.MemId ==
-            (VASurfaceID)(uintptr_t)src->data[3])
+        case AV_PIX_FMT_VAAPI:
+            if (*(VASurfaceID*)hwctx->surfaces[i].Data.MemId ==
+                (VASurfaceID)(uintptr_t)src->data[3])
+                index = i;
             break;
 #endif
+#if CONFIG_D3D11VA
+        case AV_PIX_FMT_D3D11:
+        {
+            mfxHDLPair *pair = (mfxHDLPair*)hwctx->surfaces[i].Data.MemId;
+            if (pair->first == src->data[0]
+                && pair->second == src->data[1]) {
+                index = i;
+                break;
+            }
+        }
+#endif
 #if CONFIG_DXVA2
-        if ((IDirect3DSurface9*)hwctx->surfaces[i].Data.MemId ==
-            (IDirect3DSurface9*)(uintptr_t)src->data[3])
-            break;
+        case AV_PIX_FMT_DXVA2_VLD:
+        {
+            mfxHDLPair *pair = (mfxHDLPair*)hwctx->surfaces[i].Data.MemId;
+            if (pair->first == src->data[3]) {
+                index = i;
+                break;
+            }
+        }
 #endif
+        }
     }
-    if (i >= hwctx->nb_surfaces) {
+    if (index < 0) {
         av_log(dst_ctx, AV_LOG_ERROR, "Trying to map from a surface which "
                "is not in the mapped frames context.\n");
         return AVERROR(EINVAL);
@@ -1032,7 +1217,7 @@  static int qsv_map_to(AVHWFramesContext *dst_ctx,
 
     dst->width   = src->width;
     dst->height  = src->height;
-    dst->data[3] = (uint8_t*)&hwctx->surfaces[i];
+    dst->data[3] = (uint8_t*)&hwctx->surfaces[index];
 
     return 0;
 }
@@ -1074,7 +1259,7 @@  static void qsv_device_free(AVHWDeviceContext *ctx)
     av_freep(&priv);
 }
 
-static mfxIMPL choose_implementation(const char *device)
+static mfxIMPL choose_implementation(const char *device, enum AVHWDeviceType child_device_type)
 {
     static const struct {
         const char *name;
@@ -1103,6 +1288,10 @@  static mfxIMPL choose_implementation(const char *device)
             impl = strtol(device, NULL, 0);
     }
 
+    if ( (child_device_type == AV_HWDEVICE_TYPE_D3D11VA) && (impl != MFX_IMPL_SOFTWARE) ) {
+        impl |= MFX_IMPL_VIA_D3D11;
+    }
+
     return impl;
 }
 
@@ -1129,6 +1318,15 @@  static int qsv_device_derive_from_child(AVHWDeviceContext *ctx,
         }
         break;
 #endif
+#if CONFIG_D3D11VA
+    case AV_HWDEVICE_TYPE_D3D11VA:
+        {
+            AVD3D11VADeviceContext *child_device_hwctx = child_device_ctx->hwctx;
+            handle_type = MFX_HANDLE_D3D11_DEVICE;
+            handle = (mfxHDL)child_device_hwctx->device;
+        }
+        break;
+#endif
 #if CONFIG_DXVA2
     case AV_HWDEVICE_TYPE_DXVA2:
         {
@@ -1191,7 +1389,9 @@  fail:
 static int qsv_device_derive(AVHWDeviceContext *ctx,
                              AVHWDeviceContext *child_device_ctx, int flags)
 {
-    return qsv_device_derive_from_child(ctx, MFX_IMPL_HARDWARE_ANY,
+    mfxIMPL impl;
+    impl = choose_implementation("hw_any", child_device_ctx->type);
+    return qsv_device_derive_from_child(ctx, impl,
                                         child_device_ctx, flags);
 }
 
@@ -1214,35 +1414,66 @@  static int qsv_device_create(AVHWDeviceContext *ctx, const char *device,
     ctx->user_opaque = priv;
     ctx->free        = qsv_device_free;
 
-    e = av_dict_get(opts, "child_device", NULL, 0);
-
-    child_device_opts = NULL;
-    if (CONFIG_VAAPI) {
+    e = av_dict_get(opts, "child_device_type", NULL, 0);
+    if (e) {
+        child_device_type = av_hwdevice_find_type_by_name(e ? e->value : NULL);
+        if (child_device_type == AV_HWDEVICE_TYPE_NONE) {
+            av_log(ctx, AV_LOG_ERROR, "Unknown child device type "
+                   "\"%s\".\n", e ? e->value : NULL);
+            return AVERROR(EINVAL);
+        }
+    } else if (CONFIG_VAAPI) {
         child_device_type = AV_HWDEVICE_TYPE_VAAPI;
-        // libmfx does not actually implement VAAPI properly, rather it
-        // depends on the specific behaviour of a matching iHD driver when
-        // used on recent Intel hardware.  Set options to the VAAPI device
-        // creation so that we should pick a usable setup by default if
-        // possible, even when multiple devices and drivers are available.
-        av_dict_set(&child_device_opts, "kernel_driver", "i915", 0);
-        av_dict_set(&child_device_opts, "driver",        "iHD",  0);
-    } else if (CONFIG_DXVA2)
+    } else if (CONFIG_D3D11VA) {
+        child_device_type = AV_HWDEVICE_TYPE_D3D11VA;
+    } else if (CONFIG_DXVA2) {
         child_device_type = AV_HWDEVICE_TYPE_DXVA2;
-    else {
+    } else {
         av_log(ctx, AV_LOG_ERROR, "No supported child device type is enabled\n");
         return AVERROR(ENOSYS);
     }
 
+    child_device_opts = NULL;
+    switch (child_device_type) {
+#if CONFIG_VAAPI
+    case AV_HWDEVICE_TYPE_VAAPI:
+        {
+            // libmfx does not actually implement VAAPI properly, rather it
+            // depends on the specific behaviour of a matching iHD driver when
+            // used on recent Intel hardware.  Set options to the VAAPI device
+            // creation so that we should pick a usable setup by default if
+            // possible, even when multiple devices and drivers are available.
+            av_dict_set(&child_device_opts, "kernel_driver", "i915", 0);
+            av_dict_set(&child_device_opts, "driver",        "iHD",  0);
+        }
+        break;
+#endif
+#if CONFIG_D3D11VA
+    case AV_HWDEVICE_TYPE_D3D11VA:
+        break;
+#endif
+#if CONFIG_DXVA2
+    case AV_HWDEVICE_TYPE_DXVA2:
+        break;
+#endif
+    default:
+        {
+            av_log(ctx, AV_LOG_ERROR, "No supported child device type is enabled\n");
+            return AVERROR(ENOSYS);
+        }
+        break;
+    }
+
+    e = av_dict_get(opts, "child_device", NULL, 0);
     ret = av_hwdevice_ctx_create(&priv->child_device_ctx, child_device_type,
                                  e ? e->value : NULL, child_device_opts, 0);
-
     av_dict_free(&child_device_opts);
     if (ret < 0)
         return ret;
 
     child_device = (AVHWDeviceContext*)priv->child_device_ctx->data;
 
-    impl = choose_implementation(device);
+    impl = choose_implementation(device, child_device_type);
 
     return qsv_device_derive_from_child(ctx, impl, child_device, 0);
 }