diff mbox series

[FFmpeg-devel,v4] lavc/qsv: adding DX11 support

Message ID 20200306130954.8938-1-artem.galin@gmail.com
State New
Headers show
Series [FFmpeg-devel,v4] lavc/qsv: adding DX11 support | expand

Checks

Context Check Description
andriy/ffmpeg-patchwork success Make fate finished

Commit Message

galinart March 6, 2020, 1:09 p.m. UTC
This enables DX11 support for QSV with higher priority than DX9.
In case of multiple GPUs configuration, DX9 API does not allow to get
access to QSV device in some cases - headless.
Implementation based on DX11 resolves that restriction by enumerating list of available GPUs and finding device with QSV support.

Signed-off-by: Artem Galin <artem.galin@gmail.com>
---
 fftools/ffmpeg_opt.c          |  12 +-
 libavcodec/qsv.c              |  53 +++++++-
 libavcodec/qsv_internal.h     |   2 +
 libavfilter/qsvvpp.c          |  36 +++--
 libavutil/hwcontext_d3d11va.c |  56 +++++++-
 libavutil/hwcontext_qsv.c     | 240 ++++++++++++++++++++++++++++------
 6 files changed, 340 insertions(+), 59 deletions(-)

Comments

Soft Works March 6, 2020, 10:14 p.m. UTC | #1
> -----Original Message-----
> From: ffmpeg-devel <ffmpeg-devel-bounces@ffmpeg.org> On Behalf Of
> Artem Galin
> Sent: Friday, March 6, 2020 2:10 PM
> To: ffmpeg-devel@ffmpeg.org
> Cc: Artem Galin <artem.galin@gmail.com>
> Subject: [FFmpeg-devel] [PATCH v4] lavc/qsv: adding DX11 support
> 
> This enables DX11 support for QSV with higher priority than DX9.
> In case of multiple GPUs configuration, DX9 API does not allow to get access
> to QSV device in some cases - headless.
> Implementation based on DX11 resolves that restriction by enumerating list
> of available GPUs and finding device with QSV support.
> 
> Signed-off-by: Artem Galin <artem.galin@gmail.com>
> ---
>  fftools/ffmpeg_opt.c          |  12 +-
>  libavcodec/qsv.c              |  53 +++++++-
>  libavcodec/qsv_internal.h     |   2 +
>  libavfilter/qsvvpp.c          |  36 +++--
>  libavutil/hwcontext_d3d11va.c |  56 +++++++-
>  libavutil/hwcontext_qsv.c     | 240 ++++++++++++++++++++++++++++------
>  6 files changed, 340 insertions(+), 59 deletions(-)
> 
> diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c index
> 1b721c4954..da619b0043 100644
> --- a/fftools/ffmpeg_opt.c
> +++ b/fftools/ffmpeg_opt.c
> @@ -504,7 +504,17 @@ static int opt_init_hw_device(void *optctx, const
> char *opt, const char *arg)
>          printf("\n");
>          exit_program(0);
>      } else {
> -        return hw_device_init_from_string(arg, NULL);
> +        HWDevice *dev;
> +        int err;
> +        if (!arg)
> +            return AVERROR(ENOMEM);
> +        err = hw_device_init_from_string(arg, &dev);
> +        if (err < 0)
> +            return err;
> +        hw_device_ctx = av_buffer_ref(dev->device_ref);
> +        if (!hw_device_ctx)
> +            return AVERROR(ENOMEM);
> +        return 0;
>      }
>  }
> 
> diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c index
> db98c75073..beea76896f 100644
> --- a/libavcodec/qsv.c
> +++ b/libavcodec/qsv.c
> @@ -36,6 +36,8 @@
>  #include "avcodec.h"
>  #include "qsv_internal.h"
> 
> +#define MFX_IMPL_VIA_MASK(impl) (0x0f00 & (impl))
> +
>  #if QSV_VERSION_ATLEAST(1, 12)
>  #include "mfx/mfxvp8.h"
>  #endif
> @@ -221,8 +223,13 @@ int ff_qsv_find_surface_idx(QSVFramesContext
> *ctx, QSVFrame *frame)
>      int i;
>      for (i = 0; i < ctx->nb_mids; i++) {
>          QSVMid *mid = &ctx->mids[i];
> +#if CONFIG_D3D11VA
> +        if (mid->handle_pair.second == frame->surface.Data.MemId)
> +            return i;
> +#else
>          if (mid->handle == frame->surface.Data.MemId)
>              return i;
> +#endif
>      }
>      return AVERROR_BUG;
>  }
> @@ -362,7 +369,11 @@ static int
> ff_qsv_set_display_handle(AVCodecContext *avctx, QSVSession *qs)  int
> ff_qsv_init_internal_session(AVCodecContext *avctx, QSVSession *qs,
>                                   const char *load_plugins, int gpu_copy)  {
> +#ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE
>      mfxIMPL          impl = MFX_IMPL_AUTO_ANY;
> +#else
> +    mfxIMPL          impl = MFX_IMPL_AUTO_ANY | MFX_IMPL_VIA_D3D11;
> +#endif
>      mfxVersion        ver = { { QSV_VERSION_MINOR, QSV_VERSION_MAJOR }
> };
>      mfxInitParam init_par = { MFX_IMPL_AUTO_ANY };
> 
> @@ -449,11 +460,21 @@ static AVBufferRef *qsv_create_mids(AVBufferRef
> *hw_frames_ref)
>          return NULL;
>      }
> 
> +#if CONFIG_D3D11VA
> +    for (i = 0; i < nb_surfaces; i++) {
> +        QSVMid *mid = &mids[i];
> +        mid->handle_is_pair     = 1;
> +        mid->handle_pair.first  = (mfxHDL)frames_hwctx-
> >surfaces[i].Data.reserved2;
> +        mid->handle_pair.second = frames_hwctx->surfaces[i].Data.MemId;
> +        mid->hw_frames_ref = hw_frames_ref1;
> +    }
> +#else
>      for (i = 0; i < nb_surfaces; i++) {
>          QSVMid *mid = &mids[i];
>          mid->handle        = frames_hwctx->surfaces[i].Data.MemId;
>          mid->hw_frames_ref = hw_frames_ref1;
>      }
> +#endif
> 
>      return mids_buf;
>  }
> @@ -661,7 +682,12 @@ static mfxStatus qsv_frame_unlock(mfxHDL pthis,
> mfxMemId mid, mfxFrameData *ptr)  static mfxStatus
> qsv_frame_get_hdl(mfxHDL pthis, mfxMemId mid, mfxHDL *hdl)  {
>      QSVMid *qsv_mid = (QSVMid*)mid;
> -    *hdl = qsv_mid->handle;
> +    if (qsv_mid->handle_is_pair) {
> +        mfxHDLPair *hdlpair = (mfxHDLPair*)hdl;
> +        *hdlpair = qsv_mid->handle_pair;
> +    } else {
> +        *hdl = qsv_mid->handle;
> +    }
>      return MFX_ERR_NONE;
>  }
> 
> @@ -679,11 +705,11 @@ int ff_qsv_init_session_device(AVCodecContext
> *avctx, mfxSession *psession,
>      mfxSession        parent_session = device_hwctx->session;
>      mfxInitParam            init_par = { MFX_IMPL_AUTO_ANY };
>      mfxHDL                    handle = NULL;
> +    mfxHandleType        handle_type = MFX_HANDLE_D3D11_DEVICE;
> 
>      mfxSession    session;
>      mfxVersion    ver;
>      mfxIMPL       impl;
> -    mfxHandleType handle_type;
>      mfxStatus err;
> 
>      int i, ret;
> @@ -695,11 +721,26 @@ int ff_qsv_init_session_device(AVCodecContext
> *avctx, mfxSession *psession,
>          return ff_qsv_print_error(avctx, err,
>                                    "Error querying the session attributes");
> 
> +    if (MFX_IMPL_VIA_D3D11 == MFX_IMPL_VIA_MASK(impl))
> +    {
> +        handle_type = MFX_HANDLE_D3D11_DEVICE;
> +    }
> +    else if (MFX_IMPL_VIA_D3D9 == MFX_IMPL_VIA_MASK(impl))
> +    {
> +        handle_type = MFX_HANDLE_D3D9_DEVICE_MANAGER;
> +    }
> +    else if (MFX_IMPL_VIA_VAAPI == MFX_IMPL_VIA_MASK(impl))
> +    {
> +        handle_type = MFX_HANDLE_VA_DISPLAY;
> +    }
> +
>      for (i = 0; i < FF_ARRAY_ELEMS(handle_types); i++) {
> -        err = MFXVideoCORE_GetHandle(parent_session, handle_types[i],
> &handle);
> -        if (err == MFX_ERR_NONE) {
> -            handle_type = handle_types[i];
> -            break;
> +        if (handle_types[i] == handle_type)
> +        {
> +            err = MFXVideoCORE_GetHandle(parent_session, handle_types[i],
> &handle);
> +            if (err == MFX_ERR_NONE) {
> +                break;
> +            }
>          }
>          handle = NULL;
>      }
> diff --git a/libavcodec/qsv_internal.h b/libavcodec/qsv_internal.h index
> 6489836a67..99dfa8dcff 100644
> --- a/libavcodec/qsv_internal.h
> +++ b/libavcodec/qsv_internal.h
> @@ -60,7 +60,9 @@
> 
>  typedef struct QSVMid {
>      AVBufferRef *hw_frames_ref;
> +    int handle_is_pair;
>      mfxHDL handle;
> +    mfxHDLPair handle_pair;
> 
>      AVFrame *locked_frame;
>      AVFrame *hw_frame;
> diff --git a/libavfilter/qsvvpp.c b/libavfilter/qsvvpp.c index
> 8d5ff2eb65..306bb2e0c3 100644
> --- a/libavfilter/qsvvpp.c
> +++ b/libavfilter/qsvvpp.c
> @@ -32,10 +32,11 @@
>  #include "qsvvpp.h"
>  #include "video.h"
> 
> -#define IS_VIDEO_MEMORY(mode)  (mode &
> (MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET | \
> +#define IS_VIDEO_MEMORY(mode)   (mode &
> (MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET | \
> 
> MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET))
> -#define IS_OPAQUE_MEMORY(mode) (mode &
> MFX_MEMTYPE_OPAQUE_FRAME) -#define IS_SYSTEM_MEMORY(mode)
> (mode & MFX_MEMTYPE_SYSTEM_MEMORY)
> +#define IS_OPAQUE_MEMORY(mode)  (mode &
> MFX_MEMTYPE_OPAQUE_FRAME)
> +#define IS_SYSTEM_MEMORY(mode)  (mode &
> MFX_MEMTYPE_SYSTEM_MEMORY)
> +#define MFX_IMPL_VIA_MASK(impl) (0x0f00 & (impl))
> 
>  typedef struct QSVFrame {
>      AVFrame          *frame;
> @@ -405,12 +406,12 @@ static int init_vpp_session(AVFilterContext *avctx,
> QSVVPPContext *s)
>      AVFilterLink                *outlink = avctx->outputs[0];
>      AVQSVFramesContext  *in_frames_hwctx = NULL;
>      AVQSVFramesContext *out_frames_hwctx = NULL;
> +    mfxHandleType            handle_type = MFX_HANDLE_D3D11_DEVICE;
> 
>      AVBufferRef *device_ref;
>      AVHWDeviceContext *device_ctx;
>      AVQSVDeviceContext *device_hwctx;
>      mfxHDL handle;
> -    mfxHandleType handle_type;
>      mfxVersion ver;
>      mfxIMPL impl;
>      int ret, i;
> @@ -497,15 +498,30 @@ static int init_vpp_session(AVFilterContext *avctx,
> QSVVPPContext *s)
>          return AVERROR_UNKNOWN;
>      }
> 
> +    if (MFX_IMPL_VIA_D3D11 == MFX_IMPL_VIA_MASK(impl))
> +    {
> +        handle_type = MFX_HANDLE_D3D11_DEVICE;
> +    }
> +    else if (MFX_IMPL_VIA_D3D9 == MFX_IMPL_VIA_MASK(impl))
> +    {
> +        handle_type = MFX_HANDLE_D3D9_DEVICE_MANAGER;
> +    }
> +    else if (MFX_IMPL_VIA_VAAPI == MFX_IMPL_VIA_MASK(impl))
> +    {
> +        handle_type = MFX_HANDLE_VA_DISPLAY;
> +    }
> +
>      for (i = 0; i < FF_ARRAY_ELEMS(handle_types); i++) {
> -        ret = MFXVideoCORE_GetHandle(device_hwctx->session,
> handle_types[i], &handle);
> -        if (ret == MFX_ERR_NONE) {
> -            handle_type = handle_types[i];
> -            break;
> +        if (handle_types[i] == handle_type)
> +        {
> +            ret = MFXVideoCORE_GetHandle(device_hwctx->session,
> handle_types[i], &handle);
> +            if (ret == MFX_ERR_NONE) {
> +                break;
> +            }
>          }
> +        handle = NULL;
>      }
> -
> -    if (ret != MFX_ERR_NONE) {
> +    if (!handle) {
>          av_log(avctx, AV_LOG_ERROR, "Error getting the session handle\n");
>          return AVERROR_UNKNOWN;
>      }
> diff --git a/libavutil/hwcontext_d3d11va.c b/libavutil/hwcontext_d3d11va.c
> index c8ae58f908..13279b7e6f 100644
> --- a/libavutil/e.c
> +++ b/libavutil/hwcontext_d3d11va.c
> @@ -511,15 +511,57 @@ static void
> d3d11va_device_uninit(AVHWDeviceContext *hwdev)
>      }
>  }
> 
> +static int
> d3d11va_device_find_adapter_by_vendor_id(AVHWDeviceContext
> +*ctx, UINT creationFlags, char *vendor) {
> +    HRESULT hr;
> +    IDXGIAdapter *adapter = NULL;
> +    int adapter_id = 0;
> +    IDXGIFactory2 *factory;
> +    long int vendor_id = strtol(vendor, NULL, 0);
> +    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 +581,23 @@ static int
> d3d11va_device_create(AVHWDeviceContext *ctx, const char *device,
>          return AVERROR_UNKNOWN;
>      }
> 
> +    e = av_dict_get(opts, "vendor", NULL, 0);
> +    if (e) {
> +        adapter = d3d11va_device_find_adapter_by_vendor_id(ctx,
> creationFlags, e ? e->value : NULL);
> +        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);
> diff --git a/libavutil/hwcontext_qsv.c b/libavutil/hwcontext_qsv.c index
> b1b67400de..97a18088c0 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;
> @@ -89,6 +95,9 @@ static const struct {
>  #if CONFIG_VAAPI
>      { MFX_HANDLE_VA_DISPLAY,          AV_HWDEVICE_TYPE_VAAPI,
> AV_PIX_FMT_VAAPI },
>  #endif
> +#if CONFIG_D3D11VA
> +    { MFX_HANDLE_D3D11_DEVICE,        AV_HWDEVICE_TYPE_D3D11VA,
> AV_PIX_FMT_D3D11 },
> +#endif
>  #if CONFIG_DXVA2
>      { MFX_HANDLE_D3D9_DEVICE_MANAGER, AV_HWDEVICE_TYPE_DXVA2,
> AV_PIX_FMT_DXVA2_VLD },  #endif @@ -119,25 +128,11 @@ static int
> qsv_device_init(AVHWDeviceContext *ctx)  {
>      AVQSVDeviceContext *hwctx = ctx->hwctx;
>      QSVDeviceContext       *s = ctx->internal->priv;
> +    mfxHandleType handle_type = MFX_HANDLE_D3D11_DEVICE;
> 
>      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)
>          err = MFXQueryVersion(hwctx->session, &s->ver); @@ -146,6 +141,36
> @@ static int qsv_device_init(AVHWDeviceContext *ctx)
>          return AVERROR_UNKNOWN;
>      }
> 
> +    if (MFX_IMPL_VIA_D3D11 == MFX_IMPL_VIA_MASK(s->impl))
> +    {
> +        handle_type = MFX_HANDLE_D3D11_DEVICE;
> +    }
> +    else if (MFX_IMPL_VIA_D3D9 == MFX_IMPL_VIA_MASK(s->impl))
> +    {
> +        handle_type = MFX_HANDLE_D3D9_DEVICE_MANAGER;
> +    }
> +    else if (MFX_IMPL_VIA_VAAPI == MFX_IMPL_VIA_MASK(s->impl))
> +    {
> +        handle_type = MFX_HANDLE_VA_DISPLAY;
> +    }
> +
> +    for (i = 0; supported_handle_types[i].handle_type; i++) {
> +        if (supported_handle_types[i].handle_type == handle_type) {
> +            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");
> +    }
> +
>      return 0;
>  }
> 
> @@ -229,6 +254,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 +287,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;
> +        child_frames_hwctx->MiscFlags |= D3D11_RESOURCE_MISC_SHARED;
> +        if (hwctx->frame_type &
> MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET)
> +            child_frames_hwctx->BindFlags = D3D11_BIND_RENDER_TARGET ;
> +        else
> +            child_frames_hwctx->BindFlags = D3D11_BIND_DECODER;
> +    }
> +#endif
>  #if CONFIG_DXVA2
>      if (child_device_ctx->type == AV_HWDEVICE_TYPE_DXVA2) {
>          AVDXVA2FramesContext *child_frames_hwctx = child_frames_ctx-
> >hwctx; @@ -279,6 +321,19 @@ 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->surfaces_internal[i].Data.MemId = (mfxMemId)(intptr_t)i;
> +            s->surfaces_internal[i].Data.reserved2 =
> (intptr_t)child_frames_hwctx->texture;
> +        }
> +        if (child_frames_hwctx->BindFlags & D3D11_BIND_DECODER)
> +            hwctx->frame_type =
> MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET;
> +        else
> +            hwctx->frame_type =
> MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET;
> +    }
> +#endif
>  #if CONFIG_DXVA2
>      if (child_device_ctx->type == AV_HWDEVICE_TYPE_DXVA2) {
>          AVDXVA2FramesContext *child_frames_hwctx = child_frames_ctx-
> >hwctx; @@ -421,6 +476,19 @@ static mfxStatus frame_unlock(mfxHDL
> pthis, mfxMemId mid, mfxFrameData *ptr)
> 
>  static mfxStatus frame_get_hdl(mfxHDL pthis, mfxMemId mid, mfxHDL
> *hdl)  {
> +#if CONFIG_D3D11VA
> +    AVHWFramesContext *ctx = pthis;
> +    QSVFramesContext    *s = ctx->internal->priv;
> +    AVHWFramesContext *child_ctx =
> +        (AVHWFramesContext*)s->child_frames_ref->data;
> +    if (child_ctx->format == AV_PIX_FMT_D3D11) {
> +        AVD3D11VAFramesContext *child_hwctx = child_ctx->hwctx;
> +        mfxHDLPair *hdlpair = (mfxHDLPair*)hdl;
> +        hdlpair->first  = child_hwctx->texture;
> +        hdlpair->second = mid; // (Texture array index.)
> +        return MFX_ERR_NONE;
> +    }
> +#endif
>      *hdl = mid;
>      return MFX_ERR_NONE;
>  }
> @@ -668,6 +736,11 @@ 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:
> +        child_data = surf->Data.MemId;
> +        break;
> +#endif
>  #if CONFIG_DXVA2
>      case AV_HWDEVICE_TYPE_DXVA2:
>          child_data = surf->Data.MemId;
> @@ -954,6 +1027,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 +1051,27 @@ 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->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->surfaces_internal[i].Data.MemId = (mfxMemId)(intptr_t)i;
> +                s->surfaces_internal[i].Data.reserved2 = (intptr_t)src_hwctx-
> >texture;
> +            }
> +            dst_hwctx->nb_surfaces = src_ctx->initial_pool_size;
> +            if (src_hwctx->BindFlags & D3D11_BIND_DECODER)
> +                dst_hwctx->frame_type =
> MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET;
> +            else
> +                dst_hwctx->frame_type =
> MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET;
> +        }
> +        break;
> +#endif
>  #if CONFIG_DXVA2
>      case AV_HWDEVICE_TYPE_DXVA2:
>          {
> @@ -1005,21 +1105,33 @@ 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++) {
>  #if CONFIG_VAAPI
> -        if (*(VASurfaceID*)hwctx->surfaces[i].Data.MemId ==
> -            (VASurfaceID)(uintptr_t)src->data[3])
> +        if (AV_PIX_FMT_VAAPI == src->format) {
> +            if (*(VASurfaceID*)hwctx->surfaces[i].Data.MemId ==
> +                (VASurfaceID)(uintptr_t)src->data[3])
> +                index = i
>              break;
> +        }
>  #endif
> -#if CONFIG_DXVA2
> -        if ((IDirect3DSurface9*)hwctx->surfaces[i].Data.MemId ==
> -            (IDirect3DSurface9*)(uintptr_t)src->data[3])
> +#if CONFIG_D3D11VA
> +        if (AV_PIX_FMT_D3D11 == src->format) {
> +            if (i == (intptr_t)src->data[1])
> +                index = i;
>              break;
> +        }
> +#endif
> +#if CONFIG_DXVA2
> +        if (AV_PIX_FMT_DXVA2_VLD == src->format) {
> +            if ((IDirect3DSurface9*)hwctx->surfaces[i].Data.MemId ==
> +                (IDirect3DSurface9*)(uintptr_t)src->data[3])
> +                index = i;
> +        }
>  #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 +1144,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 +1186,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 +1215,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 +1245,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 +1316,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 +1341,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);  }
> --
> 2.21.0


This appears to be a bit half-baked. What's missing imo is:

- Allow selection of a specific DXGI adapter
- Change filters to support mfxHandlePair
- Allow deriving from D3D11VA hw context

Also, have you tested all possible use cases:

- Setting up standalone hw decoder (no hw encoder)
- Setting up standalone hw encoder (no hw decoder)
- Filter-only hw device context

Further, I think there should be an explicit selection between D3D9 
and D3D11 instead of an automatic selection.

softworkz
galinart March 12, 2020, 11:04 a.m. UTC | #2
On Fri, 6 Mar 2020 at 22:15, Soft Works <softworkz@hotmail.com> wrote:

> > -----Original Message-----
> > From: ffmpeg-devel <ffmpeg-devel-bounces@ffmpeg.org> On Behalf Of
> > Artem Galin
> > Sent: Friday, March 6, 2020 2:10 PM
> > To: ffmpeg-devel@ffmpeg.org
> > Cc: Artem Galin <artem.galin@gmail.com>
> > Subject: [FFmpeg-devel] [PATCH v4] lavc/qsv: adding DX11 support
> >
> > This enables DX11 support for QSV with higher priority than DX9.
> > In case of multiple GPUs configuration, DX9 API does not allow to get
> access
> > to QSV device in some cases - headless.
> > Implementation based on DX11 resolves that restriction by enumerating
> list
> > of available GPUs and finding device with QSV support.
> >
> > Signed-off-by: Artem Galin <artem.galin@gmail.com>
> > ---
> >  fftools/ffmpeg_opt.c          |  12 +-
> >  libavcodec/qsv.c              |  53 +++++++-
> >  libavcodec/qsv_internal.h     |   2 +
> >  libavfilter/qsvvpp.c          |  36 +++--
> >  libavutil/hwcontext_d3d11va.c |  56 +++++++-
> >  libavutil/hwcontext_qsv.c     | 240 ++++++++++++++++++++++++++++------
> >  6 files changed, 340 insertions(+), 59 deletions(-)
> >
> > diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c index
> > 1b721c4954..da619b0043 100644
> > --- a/fftools/ffmpeg_opt.c
> > +++ b/fftools/ffmpeg_opt.c
> > @@ -504,7 +504,17 @@ static int opt_init_hw_device(void *optctx, const
> > char *opt, const char *arg)
> >          printf("\n");
> >          exit_program(0);
> >      } else {
> > -        return hw_device_init_from_string(arg, NULL);
> > +        HWDevice *dev;
> > +        int err;
> > +        if (!arg)
> > +            return AVERROR(ENOMEM);
> > +        err = hw_device_init_from_string(arg, &dev);
> > +        if (err < 0)
> > +            return err;
> > +        hw_device_ctx = av_buffer_ref(dev->device_ref);
> > +        if (!hw_device_ctx)
> > +            return AVERROR(ENOMEM);
> > +        return 0;
> >      }
> >  }
> >
> > diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c index
> > db98c75073..beea76896f 100644
> > --- a/libavcodec/qsv.c
> > +++ b/libavcodec/qsv.c
> > @@ -36,6 +36,8 @@
> >  #include "avcodec.h"
> >  #include "qsv_internal.h"
> >
> > +#define MFX_IMPL_VIA_MASK(impl) (0x0f00 & (impl))
> > +
> >  #if QSV_VERSION_ATLEAST(1, 12)
> >  #include "mfx/mfxvp8.h"
> >  #endif
> > @@ -221,8 +223,13 @@ int ff_qsv_find_surface_idx(QSVFramesContext
> > *ctx, QSVFrame *frame)
> >      int i;
> >      for (i = 0; i < ctx->nb_mids; i++) {
> >          QSVMid *mid = &ctx->mids[i];
> > +#if CONFIG_D3D11VA
> > +        if (mid->handle_pair.second == frame->surface.Data.MemId)
> > +            return i;
> > +#else
> >          if (mid->handle == frame->surface.Data.MemId)
> >              return i;
> > +#endif
> >      }
> >      return AVERROR_BUG;
> >  }
> > @@ -362,7 +369,11 @@ static int
> > ff_qsv_set_display_handle(AVCodecContext *avctx, QSVSession *qs)  int
> > ff_qsv_init_internal_session(AVCodecContext *avctx, QSVSession *qs,
> >                                   const char *load_plugins, int
> gpu_copy)  {
> > +#ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE
> >      mfxIMPL          impl = MFX_IMPL_AUTO_ANY;
> > +#else
> > +    mfxIMPL          impl = MFX_IMPL_AUTO_ANY | MFX_IMPL_VIA_D3D11;
> > +#endif
> >      mfxVersion        ver = { { QSV_VERSION_MINOR, QSV_VERSION_MAJOR }
> > };
> >      mfxInitParam init_par = { MFX_IMPL_AUTO_ANY };
> >
> > @@ -449,11 +460,21 @@ static AVBufferRef *qsv_create_mids(AVBufferRef
> > *hw_frames_ref)
> >          return NULL;
> >      }
> >
> > +#if CONFIG_D3D11VA
> > +    for (i = 0; i < nb_surfaces; i++) {
> > +        QSVMid *mid = &mids[i];
> > +        mid->handle_is_pair     = 1;
> > +        mid->handle_pair.first  = (mfxHDL)frames_hwctx-
> > >surfaces[i].Data.reserved2;
> > +        mid->handle_pair.second = frames_hwctx->surfaces[i].Data.MemId;
> > +        mid->hw_frames_ref = hw_frames_ref1;
> > +    }
> > +#else
> >      for (i = 0; i < nb_surfaces; i++) {
> >          QSVMid *mid = &mids[i];
> >          mid->handle        = frames_hwctx->surfaces[i].Data.MemId;
> >          mid->hw_frames_ref = hw_frames_ref1;
> >      }
> > +#endif
> >
> >      return mids_buf;
> >  }
> > @@ -661,7 +682,12 @@ static mfxStatus qsv_frame_unlock(mfxHDL pthis,
> > mfxMemId mid, mfxFrameData *ptr)  static mfxStatus
> > qsv_frame_get_hdl(mfxHDL pthis, mfxMemId mid, mfxHDL *hdl)  {
> >      QSVMid *qsv_mid = (QSVMid*)mid;
> > -    *hdl = qsv_mid->handle;
> > +    if (qsv_mid->handle_is_pair) {
> > +        mfxHDLPair *hdlpair = (mfxHDLPair*)hdl;
> > +        *hdlpair = qsv_mid->handle_pair;
> > +    } else {
> > +        *hdl = qsv_mid->handle;
> > +    }
> >      return MFX_ERR_NONE;
> >  }
> >
> > @@ -679,11 +705,11 @@ int ff_qsv_init_session_device(AVCodecContext
> > *avctx, mfxSession *psession,
> >      mfxSession        parent_session = device_hwctx->session;
> >      mfxInitParam            init_par = { MFX_IMPL_AUTO_ANY };
> >      mfxHDL                    handle = NULL;
> > +    mfxHandleType        handle_type = MFX_HANDLE_D3D11_DEVICE;
> >
> >      mfxSession    session;
> >      mfxVersion    ver;
> >      mfxIMPL       impl;
> > -    mfxHandleType handle_type;
> >      mfxStatus err;
> >
> >      int i, ret;
> > @@ -695,11 +721,26 @@ int ff_qsv_init_session_device(AVCodecContext
> > *avctx, mfxSession *psession,
> >          return ff_qsv_print_error(avctx, err,
> >                                    "Error querying the session
> attributes");
> >
> > +    if (MFX_IMPL_VIA_D3D11 == MFX_IMPL_VIA_MASK(impl))
> > +    {
> > +        handle_type = MFX_HANDLE_D3D11_DEVICE;
> > +    }
> > +    else if (MFX_IMPL_VIA_D3D9 == MFX_IMPL_VIA_MASK(impl))
> > +    {
> > +        handle_type = MFX_HANDLE_D3D9_DEVICE_MANAGER;
> > +    }
> > +    else if (MFX_IMPL_VIA_VAAPI == MFX_IMPL_VIA_MASK(impl))
> > +    {
> > +        handle_type = MFX_HANDLE_VA_DISPLAY;
> > +    }
> > +
> >      for (i = 0; i < FF_ARRAY_ELEMS(handle_types); i++) {
> > -        err = MFXVideoCORE_GetHandle(parent_session, handle_types[i],
> > &handle);
> > -        if (err == MFX_ERR_NONE) {
> > -            handle_type = handle_types[i];
> > -            break;
> > +        if (handle_types[i] == handle_type)
> > +        {
> > +            err = MFXVideoCORE_GetHandle(parent_session,
> handle_types[i],
> > &handle);
> > +            if (err == MFX_ERR_NONE) {
> > +                break;
> > +            }
> >          }
> >          handle = NULL;
> >      }
> > diff --git a/libavcodec/qsv_internal.h b/libavcodec/qsv_internal.h index
> > 6489836a67..99dfa8dcff 100644
> > --- a/libavcodec/qsv_internal.h
> > +++ b/libavcodec/qsv_internal.h
> > @@ -60,7 +60,9 @@
> >
> >  typedef struct QSVMid {
> >      AVBufferRef *hw_frames_ref;
> > +    int handle_is_pair;
> >      mfxHDL handle;
> > +    mfxHDLPair handle_pair;
> >
> >      AVFrame *locked_frame;
> >      AVFrame *hw_frame;
> > diff --git a/libavfilter/qsvvpp.c b/libavfilter/qsvvpp.c index
> > 8d5ff2eb65..306bb2e0c3 100644
> > --- a/libavfilter/qsvvpp.c
> > +++ b/libavfilter/qsvvpp.c
> > @@ -32,10 +32,11 @@
> >  #include "qsvvpp.h"
> >  #include "video.h"
> >
> > -#define IS_VIDEO_MEMORY(mode)  (mode &
> > (MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET | \
> > +#define IS_VIDEO_MEMORY(mode)   (mode &
> > (MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET | \
> >
> > MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET))
> > -#define IS_OPAQUE_MEMORY(mode) (mode &
> > MFX_MEMTYPE_OPAQUE_FRAME) -#define IS_SYSTEM_MEMORY(mode)
> > (mode & MFX_MEMTYPE_SYSTEM_MEMORY)
> > +#define IS_OPAQUE_MEMORY(mode)  (mode &
> > MFX_MEMTYPE_OPAQUE_FRAME)
> > +#define IS_SYSTEM_MEMORY(mode)  (mode &
> > MFX_MEMTYPE_SYSTEM_MEMORY)
> > +#define MFX_IMPL_VIA_MASK(impl) (0x0f00 & (impl))
> >
> >  typedef struct QSVFrame {
> >      AVFrame          *frame;
> > @@ -405,12 +406,12 @@ static int init_vpp_session(AVFilterContext *avctx,
> > QSVVPPContext *s)
> >      AVFilterLink                *outlink = avctx->outputs[0];
> >      AVQSVFramesContext  *in_frames_hwctx = NULL;
> >      AVQSVFramesContext *out_frames_hwctx = NULL;
> > +    mfxHandleType            handle_type = MFX_HANDLE_D3D11_DEVICE;
> >
> >      AVBufferRef *device_ref;
> >      AVHWDeviceContext *device_ctx;
> >      AVQSVDeviceContext *device_hwctx;
> >      mfxHDL handle;
> > -    mfxHandleType handle_type;
> >      mfxVersion ver;
> >      mfxIMPL impl;
> >      int ret, i;
> > @@ -497,15 +498,30 @@ static int init_vpp_session(AVFilterContext *avctx,
> > QSVVPPContext *s)
> >          return AVERROR_UNKNOWN;
> >      }
> >
> > +    if (MFX_IMPL_VIA_D3D11 == MFX_IMPL_VIA_MASK(impl))
> > +    {
> > +        handle_type = MFX_HANDLE_D3D11_DEVICE;
> > +    }
> > +    else if (MFX_IMPL_VIA_D3D9 == MFX_IMPL_VIA_MASK(impl))
> > +    {
> > +        handle_type = MFX_HANDLE_D3D9_DEVICE_MANAGER;
> > +    }
> > +    else if (MFX_IMPL_VIA_VAAPI == MFX_IMPL_VIA_MASK(impl))
> > +    {
> > +        handle_type = MFX_HANDLE_VA_DISPLAY;
> > +    }
> > +
> >      for (i = 0; i < FF_ARRAY_ELEMS(handle_types); i++) {
> > -        ret = MFXVideoCORE_GetHandle(device_hwctx->session,
> > handle_types[i], &handle);
> > -        if (ret == MFX_ERR_NONE) {
> > -            handle_type = handle_types[i];
> > -            break;
> > +        if (handle_types[i] == handle_type)
> > +        {
> > +            ret = MFXVideoCORE_GetHandle(device_hwctx->session,
> > handle_types[i], &handle);
> > +            if (ret == MFX_ERR_NONE) {
> > +                break;
> > +            }
> >          }
> > +        handle = NULL;
> >      }
> > -
> > -    if (ret != MFX_ERR_NONE) {
> > +    if (!handle) {
> >          av_log(avctx, AV_LOG_ERROR, "Error getting the session
> handle\n");
> >          return AVERROR_UNKNOWN;
> >      }
> > diff --git a/libavutil/hwcontext_d3d11va.c
> b/libavutil/hwcontext_d3d11va.c
> > index c8ae58f908..13279b7e6f 100644
> > --- a/libavutil/e.c
> > +++ b/libavutil/hwcontext_d3d11va.c
> > @@ -511,15 +511,57 @@ static void
> > d3d11va_device_uninit(AVHWDeviceContext *hwdev)
> >      }
> >  }
> >
> > +static int
> > d3d11va_device_find_adapter_by_vendor_id(AVHWDeviceContext
> > +*ctx, UINT creationFlags, char *vendor) {
> > +    HRESULT hr;
> > +    IDXGIAdapter *adapter = NULL;
> > +    int adapter_id = 0;
> > +    IDXGIFactory2 *factory;
> > +    long int vendor_id = strtol(vendor, NULL, 0);
> > +    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 +581,23 @@ static int
> > d3d11va_device_create(AVHWDeviceContext *ctx, const char *device,
> >          return AVERROR_UNKNOWN;
> >      }
> >
> > +    e = av_dict_get(opts, "vendor", NULL, 0);
> > +    if (e) {
> > +        adapter = d3d11va_device_find_adapter_by_vendor_id(ctx,
> > creationFlags, e ? e->value : NULL);
> > +        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);
> > diff --git a/libavutil/hwcontext_qsv.c b/libavutil/hwcontext_qsv.c index
> > b1b67400de..97a18088c0 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;
> > @@ -89,6 +95,9 @@ static const struct {
> >  #if CONFIG_VAAPI
> >      { MFX_HANDLE_VA_DISPLAY,          AV_HWDEVICE_TYPE_VAAPI,
> > AV_PIX_FMT_VAAPI },
> >  #endif
> > +#if CONFIG_D3D11VA
> > +    { MFX_HANDLE_D3D11_DEVICE,        AV_HWDEVICE_TYPE_D3D11VA,
> > AV_PIX_FMT_D3D11 },
> > +#endif
> >  #if CONFIG_DXVA2
> >      { MFX_HANDLE_D3D9_DEVICE_MANAGER, AV_HWDEVICE_TYPE_DXVA2,
> > AV_PIX_FMT_DXVA2_VLD },  #endif @@ -119,25 +128,11 @@ static int
> > qsv_device_init(AVHWDeviceContext *ctx)  {
> >      AVQSVDeviceContext *hwctx = ctx->hwctx;
> >      QSVDeviceContext       *s = ctx->internal->priv;
> > +    mfxHandleType handle_type = MFX_HANDLE_D3D11_DEVICE;
> >
> >      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)
> >          err = MFXQueryVersion(hwctx->session, &s->ver); @@ -146,6
> +141,36
> > @@ static int qsv_device_init(AVHWDeviceContext *ctx)
> >          return AVERROR_UNKNOWN;
> >      }
> >
> > +    if (MFX_IMPL_VIA_D3D11 == MFX_IMPL_VIA_MASK(s->impl))
> > +    {
> > +        handle_type = MFX_HANDLE_D3D11_DEVICE;
> > +    }
> > +    else if (MFX_IMPL_VIA_D3D9 == MFX_IMPL_VIA_MASK(s->impl))
> > +    {
> > +        handle_type = MFX_HANDLE_D3D9_DEVICE_MANAGER;
> > +    }
> > +    else if (MFX_IMPL_VIA_VAAPI == MFX_IMPL_VIA_MASK(s->impl))
> > +    {
> > +        handle_type = MFX_HANDLE_VA_DISPLAY;
> > +    }
> > +
> > +    for (i = 0; supported_handle_types[i].handle_type; i++) {
> > +        if (supported_handle_types[i].handle_type == handle_type) {
> > +            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");
> > +    }
> > +
> >      return 0;
> >  }
> >
> > @@ -229,6 +254,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 +287,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;
> > +        child_frames_hwctx->MiscFlags |= D3D11_RESOURCE_MISC_SHARED;
> > +        if (hwctx->frame_type &
> > MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET)
> > +            child_frames_hwctx->BindFlags = D3D11_BIND_RENDER_TARGET ;
> > +        else
> > +            child_frames_hwctx->BindFlags = D3D11_BIND_DECODER;
> > +    }
> > +#endif
> >  #if CONFIG_DXVA2
> >      if (child_device_ctx->type == AV_HWDEVICE_TYPE_DXVA2) {
> >          AVDXVA2FramesContext *child_frames_hwctx = child_frames_ctx-
> > >hwctx; @@ -279,6 +321,19 @@ 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->surfaces_internal[i].Data.MemId = (mfxMemId)(intptr_t)i;
> > +            s->surfaces_internal[i].Data.reserved2 =
> > (intptr_t)child_frames_hwctx->texture;
> > +        }
> > +        if (child_frames_hwctx->BindFlags & D3D11_BIND_DECODER)
> > +            hwctx->frame_type =
> > MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET;
> > +        else
> > +            hwctx->frame_type =
> > MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET;
> > +    }
> > +#endif
> >  #if CONFIG_DXVA2
> >      if (child_device_ctx->type == AV_HWDEVICE_TYPE_DXVA2) {
> >          AVDXVA2FramesContext *child_frames_hwctx = child_frames_ctx-
> > >hwctx; @@ -421,6 +476,19 @@ static mfxStatus frame_unlock(mfxHDL
> > pthis, mfxMemId mid, mfxFrameData *ptr)
> >
> >  static mfxStatus frame_get_hdl(mfxHDL pthis, mfxMemId mid, mfxHDL
> > *hdl)  {
> > +#if CONFIG_D3D11VA
> > +    AVHWFramesContext *ctx = pthis;
> > +    QSVFramesContext    *s = ctx->internal->priv;
> > +    AVHWFramesContext *child_ctx =
> > +        (AVHWFramesContext*)s->child_frames_ref->data;
> > +    if (child_ctx->format == AV_PIX_FMT_D3D11) {
> > +        AVD3D11VAFramesContext *child_hwctx = child_ctx->hwctx;
> > +        mfxHDLPair *hdlpair = (mfxHDLPair*)hdl;
> > +        hdlpair->first  = child_hwctx->texture;
> > +        hdlpair->second = mid; // (Texture array index.)
> > +        return MFX_ERR_NONE;
> > +    }
> > +#endif
> >      *hdl = mid;
> >      return MFX_ERR_NONE;
> >  }
> > @@ -668,6 +736,11 @@ 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:
> > +        child_data = surf->Data.MemId;
> > +        break;
> > +#endif
> >  #if CONFIG_DXVA2
> >      case AV_HWDEVICE_TYPE_DXVA2:
> >          child_data = surf->Data.MemId;
> > @@ -954,6 +1027,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 +1051,27 @@ 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->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->surfaces_internal[i].Data.MemId =
> (mfxMemId)(intptr_t)i;
> > +                s->surfaces_internal[i].Data.reserved2 =
> (intptr_t)src_hwctx-
> > >texture;
> > +            }
> > +            dst_hwctx->nb_surfaces = src_ctx->initial_pool_size;
> > +            if (src_hwctx->BindFlags & D3D11_BIND_DECODER)
> > +                dst_hwctx->frame_type =
> > MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET;
> > +            else
> > +                dst_hwctx->frame_type =
> > MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET;
> > +        }
> > +        break;
> > +#endif
> >  #if CONFIG_DXVA2
> >      case AV_HWDEVICE_TYPE_DXVA2:
> >          {
> > @@ -1005,21 +1105,33 @@ 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++) {
> >  #if CONFIG_VAAPI
> > -        if (*(VASurfaceID*)hwctx->surfaces[i].Data.MemId ==
> > -            (VASurfaceID)(uintptr_t)src->data[3])
> > +        if (AV_PIX_FMT_VAAPI == src->format) {
> > +            if (*(VASurfaceID*)hwctx->surfaces[i].Data.MemId ==
> > +                (VASurfaceID)(uintptr_t)src->data[3])
> > +                index = i
> >              break;
> > +        }
> >  #endif
> > -#if CONFIG_DXVA2
> > -        if ((IDirect3DSurface9*)hwctx->surfaces[i].Data.MemId ==
> > -            (IDirect3DSurface9*)(uintptr_t)src->data[3])
> > +#if CONFIG_D3D11VA
> > +        if (AV_PIX_FMT_D3D11 == src->format) {
> > +            if (i == (intptr_t)src->data[1])
> > +                index = i;
> >              break;
> > +        }
> > +#endif
> > +#if CONFIG_DXVA2
> > +        if (AV_PIX_FMT_DXVA2_VLD == src->format) {
> > +            if ((IDirect3DSurface9*)hwctx->surfaces[i].Data.MemId ==
> > +                (IDirect3DSurface9*)(uintptr_t)src->data[3])
> > +                index = i;
> > +        }
> >  #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 +1144,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 +1186,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 +1215,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 +1245,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 +1316,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 +1341,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);  }
> > --
> > 2.21.0
>
>
> This appears to be a bit half-baked. What's missing imo is:
>
> - Allow selection of a specific DXGI adapter
>
        -qsv_device command line option allows you to select specific DXGI
adapter. This options was available for a long time.


> - Change filters to support mfxHandlePair
>
       - filters are next step


> - Allow deriving from D3D11VA hw context
>
      - will check this


> Also, have you tested all possible use cases:
>
> - Setting up standalone hw decoder (no hw encoder)
>
    yes

> - Setting up standalone hw encoder (no hw decoder)
>
     yes

> - Filter-only hw device context
>
     Could you please clarify this?

>
> Further, I think there should be an explicit selection between D3D9
> and D3D11 instead of an automatic selection.
>
     Explicit selection is available via  -init_hw_device
qsv:,child_device_type=d3d11va or  -init_hw_device
qsv:,child_device_type=dxva2 command line options

Thanks,
Artem.
diff mbox series

Patch

diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c
index 1b721c4954..da619b0043 100644
--- a/fftools/ffmpeg_opt.c
+++ b/fftools/ffmpeg_opt.c
@@ -504,7 +504,17 @@  static int opt_init_hw_device(void *optctx, const char *opt, const char *arg)
         printf("\n");
         exit_program(0);
     } else {
-        return hw_device_init_from_string(arg, NULL);
+        HWDevice *dev;
+        int err;
+        if (!arg)
+            return AVERROR(ENOMEM);
+        err = hw_device_init_from_string(arg, &dev);
+        if (err < 0)
+            return err;
+        hw_device_ctx = av_buffer_ref(dev->device_ref);
+        if (!hw_device_ctx)
+            return AVERROR(ENOMEM);
+        return 0;
     }
 }
 
diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c
index db98c75073..beea76896f 100644
--- a/libavcodec/qsv.c
+++ b/libavcodec/qsv.c
@@ -36,6 +36,8 @@ 
 #include "avcodec.h"
 #include "qsv_internal.h"
 
+#define MFX_IMPL_VIA_MASK(impl) (0x0f00 & (impl))
+
 #if QSV_VERSION_ATLEAST(1, 12)
 #include "mfx/mfxvp8.h"
 #endif
@@ -221,8 +223,13 @@  int ff_qsv_find_surface_idx(QSVFramesContext *ctx, QSVFrame *frame)
     int i;
     for (i = 0; i < ctx->nb_mids; i++) {
         QSVMid *mid = &ctx->mids[i];
+#if CONFIG_D3D11VA
+        if (mid->handle_pair.second == frame->surface.Data.MemId)
+            return i;
+#else
         if (mid->handle == frame->surface.Data.MemId)
             return i;
+#endif
     }
     return AVERROR_BUG;
 }
@@ -362,7 +369,11 @@  static int ff_qsv_set_display_handle(AVCodecContext *avctx, QSVSession *qs)
 int ff_qsv_init_internal_session(AVCodecContext *avctx, QSVSession *qs,
                                  const char *load_plugins, int gpu_copy)
 {
+#ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE
     mfxIMPL          impl = MFX_IMPL_AUTO_ANY;
+#else
+    mfxIMPL          impl = MFX_IMPL_AUTO_ANY | MFX_IMPL_VIA_D3D11;
+#endif
     mfxVersion        ver = { { QSV_VERSION_MINOR, QSV_VERSION_MAJOR } };
     mfxInitParam init_par = { MFX_IMPL_AUTO_ANY };
 
@@ -449,11 +460,21 @@  static AVBufferRef *qsv_create_mids(AVBufferRef *hw_frames_ref)
         return NULL;
     }
 
+#if CONFIG_D3D11VA
+    for (i = 0; i < nb_surfaces; i++) {
+        QSVMid *mid = &mids[i];
+        mid->handle_is_pair     = 1;
+        mid->handle_pair.first  = (mfxHDL)frames_hwctx->surfaces[i].Data.reserved2;
+        mid->handle_pair.second = frames_hwctx->surfaces[i].Data.MemId;
+        mid->hw_frames_ref = hw_frames_ref1;
+    }
+#else
     for (i = 0; i < nb_surfaces; i++) {
         QSVMid *mid = &mids[i];
         mid->handle        = frames_hwctx->surfaces[i].Data.MemId;
         mid->hw_frames_ref = hw_frames_ref1;
     }
+#endif
 
     return mids_buf;
 }
@@ -661,7 +682,12 @@  static mfxStatus qsv_frame_unlock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr)
 static mfxStatus qsv_frame_get_hdl(mfxHDL pthis, mfxMemId mid, mfxHDL *hdl)
 {
     QSVMid *qsv_mid = (QSVMid*)mid;
-    *hdl = qsv_mid->handle;
+    if (qsv_mid->handle_is_pair) {
+        mfxHDLPair *hdlpair = (mfxHDLPair*)hdl;
+        *hdlpair = qsv_mid->handle_pair;
+    } else {
+        *hdl = qsv_mid->handle;
+    }
     return MFX_ERR_NONE;
 }
 
@@ -679,11 +705,11 @@  int ff_qsv_init_session_device(AVCodecContext *avctx, mfxSession *psession,
     mfxSession        parent_session = device_hwctx->session;
     mfxInitParam            init_par = { MFX_IMPL_AUTO_ANY };
     mfxHDL                    handle = NULL;
+    mfxHandleType        handle_type = MFX_HANDLE_D3D11_DEVICE;
 
     mfxSession    session;
     mfxVersion    ver;
     mfxIMPL       impl;
-    mfxHandleType handle_type;
     mfxStatus err;
 
     int i, ret;
@@ -695,11 +721,26 @@  int ff_qsv_init_session_device(AVCodecContext *avctx, mfxSession *psession,
         return ff_qsv_print_error(avctx, err,
                                   "Error querying the session attributes");
 
+    if (MFX_IMPL_VIA_D3D11 == MFX_IMPL_VIA_MASK(impl))
+    {
+        handle_type = MFX_HANDLE_D3D11_DEVICE;
+    }
+    else if (MFX_IMPL_VIA_D3D9 == MFX_IMPL_VIA_MASK(impl))
+    {
+        handle_type = MFX_HANDLE_D3D9_DEVICE_MANAGER;
+    }
+    else if (MFX_IMPL_VIA_VAAPI == MFX_IMPL_VIA_MASK(impl))
+    {
+        handle_type = MFX_HANDLE_VA_DISPLAY;
+    }
+
     for (i = 0; i < FF_ARRAY_ELEMS(handle_types); i++) {
-        err = MFXVideoCORE_GetHandle(parent_session, handle_types[i], &handle);
-        if (err == MFX_ERR_NONE) {
-            handle_type = handle_types[i];
-            break;
+        if (handle_types[i] == handle_type)
+        {
+            err = MFXVideoCORE_GetHandle(parent_session, handle_types[i], &handle);
+            if (err == MFX_ERR_NONE) {
+                break;
+            }
         }
         handle = NULL;
     }
diff --git a/libavcodec/qsv_internal.h b/libavcodec/qsv_internal.h
index 6489836a67..99dfa8dcff 100644
--- a/libavcodec/qsv_internal.h
+++ b/libavcodec/qsv_internal.h
@@ -60,7 +60,9 @@ 
 
 typedef struct QSVMid {
     AVBufferRef *hw_frames_ref;
+    int handle_is_pair;
     mfxHDL handle;
+    mfxHDLPair handle_pair;
 
     AVFrame *locked_frame;
     AVFrame *hw_frame;
diff --git a/libavfilter/qsvvpp.c b/libavfilter/qsvvpp.c
index 8d5ff2eb65..306bb2e0c3 100644
--- a/libavfilter/qsvvpp.c
+++ b/libavfilter/qsvvpp.c
@@ -32,10 +32,11 @@ 
 #include "qsvvpp.h"
 #include "video.h"
 
-#define IS_VIDEO_MEMORY(mode)  (mode & (MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET | \
+#define IS_VIDEO_MEMORY(mode)   (mode & (MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET | \
                                         MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET))
-#define IS_OPAQUE_MEMORY(mode) (mode & MFX_MEMTYPE_OPAQUE_FRAME)
-#define IS_SYSTEM_MEMORY(mode) (mode & MFX_MEMTYPE_SYSTEM_MEMORY)
+#define IS_OPAQUE_MEMORY(mode)  (mode & MFX_MEMTYPE_OPAQUE_FRAME)
+#define IS_SYSTEM_MEMORY(mode)  (mode & MFX_MEMTYPE_SYSTEM_MEMORY)
+#define MFX_IMPL_VIA_MASK(impl) (0x0f00 & (impl))
 
 typedef struct QSVFrame {
     AVFrame          *frame;
@@ -405,12 +406,12 @@  static int init_vpp_session(AVFilterContext *avctx, QSVVPPContext *s)
     AVFilterLink                *outlink = avctx->outputs[0];
     AVQSVFramesContext  *in_frames_hwctx = NULL;
     AVQSVFramesContext *out_frames_hwctx = NULL;
+    mfxHandleType            handle_type = MFX_HANDLE_D3D11_DEVICE;
 
     AVBufferRef *device_ref;
     AVHWDeviceContext *device_ctx;
     AVQSVDeviceContext *device_hwctx;
     mfxHDL handle;
-    mfxHandleType handle_type;
     mfxVersion ver;
     mfxIMPL impl;
     int ret, i;
@@ -497,15 +498,30 @@  static int init_vpp_session(AVFilterContext *avctx, QSVVPPContext *s)
         return AVERROR_UNKNOWN;
     }
 
+    if (MFX_IMPL_VIA_D3D11 == MFX_IMPL_VIA_MASK(impl))
+    {
+        handle_type = MFX_HANDLE_D3D11_DEVICE;
+    }
+    else if (MFX_IMPL_VIA_D3D9 == MFX_IMPL_VIA_MASK(impl))
+    {
+        handle_type = MFX_HANDLE_D3D9_DEVICE_MANAGER;
+    }
+    else if (MFX_IMPL_VIA_VAAPI == MFX_IMPL_VIA_MASK(impl))
+    {
+        handle_type = MFX_HANDLE_VA_DISPLAY;
+    }
+
     for (i = 0; i < FF_ARRAY_ELEMS(handle_types); i++) {
-        ret = MFXVideoCORE_GetHandle(device_hwctx->session, handle_types[i], &handle);
-        if (ret == MFX_ERR_NONE) {
-            handle_type = handle_types[i];
-            break;
+        if (handle_types[i] == handle_type)
+        {
+            ret = MFXVideoCORE_GetHandle(device_hwctx->session, handle_types[i], &handle);
+            if (ret == MFX_ERR_NONE) {
+                break;
+            }
         }
+        handle = NULL;
     }
-
-    if (ret != MFX_ERR_NONE) {
+    if (!handle) {
         av_log(avctx, AV_LOG_ERROR, "Error getting the session handle\n");
         return AVERROR_UNKNOWN;
     }
diff --git a/libavutil/hwcontext_d3d11va.c b/libavutil/hwcontext_d3d11va.c
index c8ae58f908..13279b7e6f 100644
--- a/libavutil/hwcontext_d3d11va.c
+++ b/libavutil/hwcontext_d3d11va.c
@@ -511,15 +511,57 @@  static void d3d11va_device_uninit(AVHWDeviceContext *hwdev)
     }
 }
 
+static int d3d11va_device_find_adapter_by_vendor_id(AVHWDeviceContext *ctx, UINT creationFlags, char *vendor)
+{
+    HRESULT hr;
+    IDXGIAdapter *adapter = NULL;
+    int adapter_id = 0;
+    IDXGIFactory2 *factory;
+    long int vendor_id = strtol(vendor, NULL, 0);
+    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 +581,23 @@  static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device,
         return AVERROR_UNKNOWN;
     }
 
+    e = av_dict_get(opts, "vendor", NULL, 0);
+    if (e) {
+        adapter = d3d11va_device_find_adapter_by_vendor_id(ctx, creationFlags, e ? e->value : NULL);
+        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);
diff --git a/libavutil/hwcontext_qsv.c b/libavutil/hwcontext_qsv.c
index b1b67400de..97a18088c0 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;
@@ -89,6 +95,9 @@  static const struct {
 #if CONFIG_VAAPI
     { MFX_HANDLE_VA_DISPLAY,          AV_HWDEVICE_TYPE_VAAPI, AV_PIX_FMT_VAAPI },
 #endif
+#if CONFIG_D3D11VA
+    { MFX_HANDLE_D3D11_DEVICE,        AV_HWDEVICE_TYPE_D3D11VA, AV_PIX_FMT_D3D11 },
+#endif
 #if CONFIG_DXVA2
     { MFX_HANDLE_D3D9_DEVICE_MANAGER, AV_HWDEVICE_TYPE_DXVA2, AV_PIX_FMT_DXVA2_VLD },
 #endif
@@ -119,25 +128,11 @@  static int qsv_device_init(AVHWDeviceContext *ctx)
 {
     AVQSVDeviceContext *hwctx = ctx->hwctx;
     QSVDeviceContext       *s = ctx->internal->priv;
+    mfxHandleType handle_type = MFX_HANDLE_D3D11_DEVICE;
 
     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)
         err = MFXQueryVersion(hwctx->session, &s->ver);
@@ -146,6 +141,36 @@  static int qsv_device_init(AVHWDeviceContext *ctx)
         return AVERROR_UNKNOWN;
     }
 
+    if (MFX_IMPL_VIA_D3D11 == MFX_IMPL_VIA_MASK(s->impl))
+    {
+        handle_type = MFX_HANDLE_D3D11_DEVICE;
+    }
+    else if (MFX_IMPL_VIA_D3D9 == MFX_IMPL_VIA_MASK(s->impl))
+    {
+        handle_type = MFX_HANDLE_D3D9_DEVICE_MANAGER;
+    }
+    else if (MFX_IMPL_VIA_VAAPI == MFX_IMPL_VIA_MASK(s->impl))
+    {
+        handle_type = MFX_HANDLE_VA_DISPLAY;
+    }
+
+    for (i = 0; supported_handle_types[i].handle_type; i++) {
+        if (supported_handle_types[i].handle_type == handle_type) {
+            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");
+    }
+
     return 0;
 }
 
@@ -229,6 +254,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 +287,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;
+        child_frames_hwctx->MiscFlags |= D3D11_RESOURCE_MISC_SHARED;
+        if (hwctx->frame_type & MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET)
+            child_frames_hwctx->BindFlags = D3D11_BIND_RENDER_TARGET ;
+        else
+            child_frames_hwctx->BindFlags = D3D11_BIND_DECODER;
+    }
+#endif
 #if CONFIG_DXVA2
     if (child_device_ctx->type == AV_HWDEVICE_TYPE_DXVA2) {
         AVDXVA2FramesContext *child_frames_hwctx = child_frames_ctx->hwctx;
@@ -279,6 +321,19 @@  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->surfaces_internal[i].Data.MemId = (mfxMemId)(intptr_t)i;
+            s->surfaces_internal[i].Data.reserved2 = (intptr_t)child_frames_hwctx->texture;
+        }
+        if (child_frames_hwctx->BindFlags & D3D11_BIND_DECODER)
+            hwctx->frame_type = MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET;
+        else
+            hwctx->frame_type = MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET;
+    }
+#endif
 #if CONFIG_DXVA2
     if (child_device_ctx->type == AV_HWDEVICE_TYPE_DXVA2) {
         AVDXVA2FramesContext *child_frames_hwctx = child_frames_ctx->hwctx;
@@ -421,6 +476,19 @@  static mfxStatus frame_unlock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr)
 
 static mfxStatus frame_get_hdl(mfxHDL pthis, mfxMemId mid, mfxHDL *hdl)
 {
+#if CONFIG_D3D11VA
+    AVHWFramesContext *ctx = pthis;
+    QSVFramesContext    *s = ctx->internal->priv;
+    AVHWFramesContext *child_ctx =
+        (AVHWFramesContext*)s->child_frames_ref->data;
+    if (child_ctx->format == AV_PIX_FMT_D3D11) {
+        AVD3D11VAFramesContext *child_hwctx = child_ctx->hwctx;
+        mfxHDLPair *hdlpair = (mfxHDLPair*)hdl;
+        hdlpair->first  = child_hwctx->texture;
+        hdlpair->second = mid; // (Texture array index.)
+        return MFX_ERR_NONE;
+    }
+#endif
     *hdl = mid;
     return MFX_ERR_NONE;
 }
@@ -668,6 +736,11 @@  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:
+        child_data = surf->Data.MemId;
+        break;
+#endif
 #if CONFIG_DXVA2
     case AV_HWDEVICE_TYPE_DXVA2:
         child_data = surf->Data.MemId;
@@ -954,6 +1027,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 +1051,27 @@  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->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->surfaces_internal[i].Data.MemId = (mfxMemId)(intptr_t)i;
+                s->surfaces_internal[i].Data.reserved2 = (intptr_t)src_hwctx->texture;
+            }
+            dst_hwctx->nb_surfaces = src_ctx->initial_pool_size;
+            if (src_hwctx->BindFlags & D3D11_BIND_DECODER)
+                dst_hwctx->frame_type = MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET;
+            else
+                dst_hwctx->frame_type = MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET;
+        }
+        break;
+#endif
 #if CONFIG_DXVA2
     case AV_HWDEVICE_TYPE_DXVA2:
         {
@@ -1005,21 +1105,33 @@  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++) {
 #if CONFIG_VAAPI
-        if (*(VASurfaceID*)hwctx->surfaces[i].Data.MemId ==
-            (VASurfaceID)(uintptr_t)src->data[3])
+        if (AV_PIX_FMT_VAAPI == src->format) {
+            if (*(VASurfaceID*)hwctx->surfaces[i].Data.MemId ==
+                (VASurfaceID)(uintptr_t)src->data[3])
+                index = i
             break;
+        }
 #endif
-#if CONFIG_DXVA2
-        if ((IDirect3DSurface9*)hwctx->surfaces[i].Data.MemId ==
-            (IDirect3DSurface9*)(uintptr_t)src->data[3])
+#if CONFIG_D3D11VA
+        if (AV_PIX_FMT_D3D11 == src->format) {
+            if (i == (intptr_t)src->data[1])
+                index = i;
             break;
+        }
+#endif
+#if CONFIG_DXVA2
+        if (AV_PIX_FMT_DXVA2_VLD == src->format) {
+            if ((IDirect3DSurface9*)hwctx->surfaces[i].Data.MemId ==
+                (IDirect3DSurface9*)(uintptr_t)src->data[3])
+                index = i;
+        }
 #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 +1144,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 +1186,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 +1215,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 +1245,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 +1316,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 +1341,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);
 }