diff mbox

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

Message ID 20191223183104.61202-1-artem.galin@gmail.com
State Superseded
Headers show

Commit Message

galinart Dec. 23, 2019, 6:31 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>
---
 libavcodec/qsv.c              | 13 +++--
 libavcodec/qsv_internal.h     |  1 +
 libavutil/hwcontext_d3d11va.c | 57 +++++++++++++++++++++-
 libavutil/hwcontext_qsv.c     | 89 +++++++++++++++++++++++++++++++----
 libavutil/hwcontext_qsv.h     |  1 +
 5 files changed, 147 insertions(+), 14 deletions(-)

Comments

Hendrik Leppkes Dec. 23, 2019, 6:56 p.m. UTC | #1
On Mon, Dec 23, 2019 at 7:40 PM Artem Galin <artem.galin@gmail.com> wrote:
>
> 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>

Did you test this in combination of D3D11VA decoding and QSV encoding?
Historically, QSV failed at accepting the array-textures that are used
by a D3D11 decoder, which is why this was not included.

- Hendrik
Max Dmitrichenko Jan. 8, 2020, 10:26 p.m. UTC | #2
On Mon, Dec 23, 2019 at 8:24 PM Hendrik Leppkes <h.leppkes@gmail.com> wrote:

> On Mon, Dec 23, 2019 at 7:40 PM Artem Galin <artem.galin@gmail.com> wrote:
> >
> > 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>
>
> Did you test this in combination of D3D11VA decoding and QSV encoding?
>


yes, it has been tested


> Historically, QSV failed at accepting the array-textures that are used
> by a D3D11 decoder, which is why this was not included.
>
>

right but not anymore,
therefore this patch.


> - Hendrik
>


regards
Max
Hendrik Leppkes Jan. 9, 2020, 12:04 a.m. UTC | #3
On Thu, Jan 9, 2020 at 12:32 AM Max Dmitrichenko <maxim.d33@gmail.com> wrote:
> > Historically, QSV failed at accepting the array-textures that are used
> > by a D3D11 decoder, which is why this was not included.
> >
> >
>
> right but not anymore,
> therefore this patch.
>

Cool. Whats the requirement on that? New MFX library? Certain driver versions?

- Hendrik
Max Dmitrichenko Jan. 9, 2020, 9:39 a.m. UTC | #4
On Thu, Jan 9, 2020 at 1:04 AM Hendrik Leppkes <h.leppkes@gmail.com> wrote:

> On Thu, Jan 9, 2020 at 12:32 AM Max Dmitrichenko <maxim.d33@gmail.com>
> wrote:
> > > Historically, QSV failed at accepting the array-textures that are used
> > > by a D3D11 decoder, which is why this was not included.
> > >
> > >
> >
> > right but not anymore,
> > therefore this patch.
> >
>
> Cool. Whats the requirement on that? New MFX library? Certain driver
> versions?
>
>
MFX library can be used as it is, as it used to be mostly driver issue
(which was extended in support and publicly released with several releases
already)

As such driver fix cannot be considered as major improvement - there is not
dedicated flag to check,
assumption with 2019/latest drivers should be: array-textures is working
and any deviation is regression to fix asap.

hope this explains


> - Hendrik
>

thank you for the comments,

my feedback to Artem: LGTM

regards
Max


> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
Anton Khirnov Jan. 10, 2020, 10:41 a.m. UTC | #5
Quoting Artem Galin (2019-12-23 19:31:04)
> 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>
> ---
>  libavcodec/qsv.c              | 13 +++--
>  libavcodec/qsv_internal.h     |  1 +
>  libavutil/hwcontext_d3d11va.c | 57 +++++++++++++++++++++-
>  libavutil/hwcontext_qsv.c     | 89 +++++++++++++++++++++++++++++++----
>  libavutil/hwcontext_qsv.h     |  1 +
>  5 files changed, 147 insertions(+), 14 deletions(-)
> 
> diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c
> index b00e427435..33ac7a3373 100644
> --- a/libavcodec/qsv.c
> +++ b/libavcodec/qsv.c
> @@ -414,7 +414,7 @@ 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)
>  {
> -    mfxIMPL          impl = MFX_IMPL_AUTO_ANY;
> +    mfxIMPL          impl = MFX_IMPL_AUTO_ANY | MFX_IMPL_VIA_D3D11;
>      mfxVersion        ver = { { QSV_VERSION_MINOR, QSV_VERSION_MAJOR } };
>      mfxInitParam init_par = { MFX_IMPL_AUTO_ANY };
>  
> @@ -504,6 +504,7 @@ static AVBufferRef *qsv_create_mids(AVBufferRef *hw_frames_ref)
>      for (i = 0; i < nb_surfaces; i++) {
>          QSVMid *mid = &mids[i];
>          mid->handle        = frames_hwctx->surfaces[i].Data.MemId;
> +        mid->texture       = frames_hwctx->texture;
>          mid->hw_frames_ref = hw_frames_ref1;
>      }
>  
> @@ -713,7 +714,13 @@ 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->texture) {
> +        mfxHDLPair *pair  =  (mfxHDLPair*)hdl;
> +        pair->first  = qsv_mid->texture;
> +        pair->second = qsv_mid->handle;
> +    } else {
> +        *hdl = qsv_mid->handle;
> +    }
>      return MFX_ERR_NONE;
>  }
>  
> @@ -723,8 +730,8 @@ int ff_qsv_init_session_device(AVCodecContext *avctx, mfxSession *psession,
>  {
>      static const mfxHandleType handle_types[] = {
>          MFX_HANDLE_VA_DISPLAY,
> -        MFX_HANDLE_D3D9_DEVICE_MANAGER,
>          MFX_HANDLE_D3D11_DEVICE,
> +        MFX_HANDLE_D3D9_DEVICE_MANAGER,
>      };
>      AVHWDeviceContext    *device_ctx = (AVHWDeviceContext*)device_ref->data;
>      AVQSVDeviceContext *device_hwctx = device_ctx->hwctx;
> diff --git a/libavcodec/qsv_internal.h b/libavcodec/qsv_internal.h
> index 37559270e5..09425fb431 100644
> --- a/libavcodec/qsv_internal.h
> +++ b/libavcodec/qsv_internal.h
> @@ -60,6 +60,7 @@
>  
>  typedef struct QSVMid {
>      AVBufferRef *hw_frames_ref;
> +    void *texture;
>      mfxHDL handle;
>  
>      AVFrame *locked_frame;
> diff --git a/libavutil/hwcontext_d3d11va.c b/libavutil/hwcontext_d3d11va.c
> index 6670c47579..a08479fd96 100644
> --- a/libavutil/hwcontext_d3d11va.c
> +++ b/libavutil/hwcontext_d3d11va.c
> @@ -244,7 +244,7 @@ static int d3d11va_frames_init(AVHWFramesContext *ctx)
>          return AVERROR(EINVAL);
>      }
>  
> -    texDesc = (D3D11_TEXTURE2D_DESC){
> +    texDesc = (D3D11_TEXTURE2D_DESC) {
>          .Width      = ctx->width,
>          .Height     = ctx->height,
>          .MipLevels  = 1,
> @@ -510,6 +510,46 @@ static void d3d11va_device_uninit(AVHWDeviceContext *hwdev)
>      }
>  }
>  
> +static int d3d11va_device_find_qsv_adapter(AVHWDeviceContext *ctx, UINT creationFlags)
> +{
> +    HRESULT hr;
> +    IDXGIAdapter *adapter = NULL;
> +    int adapter_id = 0;
> +    int vendor_id = 0x8086;
> +    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)
>  {
> @@ -519,7 +559,9 @@ static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device,
>      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 is_qsv         = !!av_dict_get(opts, "d3d11va_qsv", NULL, 0);
>      int ret;
>  
>      // (On UWP we can't check this.)
> @@ -538,11 +580,22 @@ static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device,
>          return AVERROR_UNKNOWN;
>      }
>  
> +    if (is_qsv) {
> +        adapter = d3d11va_device_find_qsv_adapter(ctx, creationFlags);
> +        if (adapter < 0) {
> +            av_log(ctx, AV_LOG_ERROR, "Failed to find DX11 adapter with QSV support\n");
> +            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..ae4247abf2 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
> @@ -89,6 +93,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
> @@ -229,9 +236,17 @@ 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;
> +        IDirect3DDeviceManager9_AddRef((IDirect3DDeviceManager9*)device_priv->handle);
>          child_device_hwctx->devmgr = (IDirect3DDeviceManager9*)device_priv->handle;
>      }
>  #endif
> @@ -255,6 +270,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 +304,18 @@ 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;
> +        hwctx->texture = child_frames_hwctx->texture;
> +        for (i = 0; i < ctx->initial_pool_size; i++)
> +            s->surfaces_internal[i].Data.MemId = (mfxMemId)(int64_t)i;
> +        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,7 +458,16 @@ static mfxStatus frame_unlock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr)
>  
>  static mfxStatus frame_get_hdl(mfxHDL pthis, mfxMemId mid, mfxHDL *hdl)
>  {
> -    *hdl = mid;
> +    AVHWFramesContext    *ctx = pthis;
> +    AVQSVFramesContext *hwctx = ctx->hwctx;
> +
> +    if (hwctx->texture) {
> +        mfxHDLPair *pair  =  (mfxHDLPair*)hdl;
> +        pair->first  = hwctx->texture;
> +        pair->second = mid;
> +    } else {
> +        *hdl = mid;
> +    }
>      return MFX_ERR_NONE;
>  }
>  
> @@ -492,7 +538,7 @@ static int qsv_init_internal_session(AVHWFramesContext *ctx,
>  
>      err = MFXVideoVPP_Init(*session, &par);
>      if (err != MFX_ERR_NONE) {
> -        av_log(ctx, AV_LOG_VERBOSE, "Error opening the internal VPP session."
> +        av_log(ctx, AV_LOG_ERROR, "Error opening the internal VPP session."
>                 "Surface upload/download will not be possible\n");
>          MFXClose(*session);
>          *session = NULL;
> @@ -1074,7 +1120,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 +1149,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 +1179,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:
>          {
> @@ -1226,23 +1285,35 @@ static int qsv_device_create(AVHWDeviceContext *ctx, const char *device,
>          // 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;
> +        av_dict_set(&child_device_opts, "d3d11va_qsv",   "enabled",  0);
> +    } 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);
>      }
>  
>      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;
> +    if (ret < 0) {
> +        if (CONFIG_DXVA2 && (child_device_type == AV_HWDEVICE_TYPE_D3D11VA)) {
> +            // in case of d3d11va fail, try one more chance to create device via dxva2
> +            child_device_type = AV_HWDEVICE_TYPE_DXVA2;
> +            child_device_opts = NULL;
> +            ret = av_hwdevice_ctx_create(&priv->child_device_ctx, child_device_type,
> +                            e ? e->value : NULL, child_device_opts, 0);
> +        }
> +        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);
>  }
> diff --git a/libavutil/hwcontext_qsv.h b/libavutil/hwcontext_qsv.h
> index b98d611cfc..f5a9691949 100644
> --- a/libavutil/hwcontext_qsv.h
> +++ b/libavutil/hwcontext_qsv.h
> @@ -42,6 +42,7 @@ typedef struct AVQSVDeviceContext {
>  typedef struct AVQSVFramesContext {
>      mfxFrameSurface1 *surfaces;
>      int            nb_surfaces;
> +    void              *texture;

This is a public struct, so new fields have to be added at the end,
otherwise it's an ABI break.

Also, API changes require a minor library version bump and an APIchanges
entry. Some documentation would be nice too.
galinart Jan. 23, 2020, 4:54 p.m. UTC | #6
On Fri, 10 Jan 2020 at 10:41, Anton Khirnov <anton@khirnov.net> wrote:

> Quoting Artem Galin (2019-12-23 19:31:04)
> > 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>
> > ---
> >  libavcodec/qsv.c              | 13 +++--
> >  libavcodec/qsv_internal.h     |  1 +
> >  libavutil/hwcontext_d3d11va.c | 57 +++++++++++++++++++++-
> >  libavutil/hwcontext_qsv.c     | 89 +++++++++++++++++++++++++++++++----
> >  libavutil/hwcontext_qsv.h     |  1 +
> >  5 files changed, 147 insertions(+), 14 deletions(-)
> >
> > diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c
> > index b00e427435..33ac7a3373 100644
> > --- a/libavcodec/qsv.c
> > +++ b/libavcodec/qsv.c
> > @@ -414,7 +414,7 @@ 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)
> >  {
> > -    mfxIMPL          impl = MFX_IMPL_AUTO_ANY;
> > +    mfxIMPL          impl = MFX_IMPL_AUTO_ANY | MFX_IMPL_VIA_D3D11;
> >      mfxVersion        ver = { { QSV_VERSION_MINOR, QSV_VERSION_MAJOR }
> };
> >      mfxInitParam init_par = { MFX_IMPL_AUTO_ANY };
> >
> > @@ -504,6 +504,7 @@ static AVBufferRef *qsv_create_mids(AVBufferRef
> *hw_frames_ref)
> >      for (i = 0; i < nb_surfaces; i++) {
> >          QSVMid *mid = &mids[i];
> >          mid->handle        = frames_hwctx->surfaces[i].Data.MemId;
> > +        mid->texture       = frames_hwctx->texture;
> >          mid->hw_frames_ref = hw_frames_ref1;
> >      }
> >
> > @@ -713,7 +714,13 @@ 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->texture) {
> > +        mfxHDLPair *pair  =  (mfxHDLPair*)hdl;
> > +        pair->first  = qsv_mid->texture;
> > +        pair->second = qsv_mid->handle;
> > +    } else {
> > +        *hdl = qsv_mid->handle;
> > +    }
> >      return MFX_ERR_NONE;
> >  }
> >
> > @@ -723,8 +730,8 @@ int ff_qsv_init_session_device(AVCodecContext
> *avctx, mfxSession *psession,
> >  {
> >      static const mfxHandleType handle_types[] = {
> >          MFX_HANDLE_VA_DISPLAY,
> > -        MFX_HANDLE_D3D9_DEVICE_MANAGER,
> >          MFX_HANDLE_D3D11_DEVICE,
> > +        MFX_HANDLE_D3D9_DEVICE_MANAGER,
> >      };
> >      AVHWDeviceContext    *device_ctx =
> (AVHWDeviceContext*)device_ref->data;
> >      AVQSVDeviceContext *device_hwctx = device_ctx->hwctx;
> > diff --git a/libavcodec/qsv_internal.h b/libavcodec/qsv_internal.h
> > index 37559270e5..09425fb431 100644
> > --- a/libavcodec/qsv_internal.h
> > +++ b/libavcodec/qsv_internal.h
> > @@ -60,6 +60,7 @@
> >
> >  typedef struct QSVMid {
> >      AVBufferRef *hw_frames_ref;
> > +    void *texture;
> >      mfxHDL handle;
> >
> >      AVFrame *locked_frame;
> > diff --git a/libavutil/hwcontext_d3d11va.c
> b/libavutil/hwcontext_d3d11va.c
> > index 6670c47579..a08479fd96 100644
> > --- a/libavutil/hwcontext_d3d11va.c
> > +++ b/libavutil/hwcontext_d3d11va.c
> > @@ -244,7 +244,7 @@ static int d3d11va_frames_init(AVHWFramesContext
> *ctx)
> >          return AVERROR(EINVAL);
> >      }
> >
> > -    texDesc = (D3D11_TEXTURE2D_DESC){
> > +    texDesc = (D3D11_TEXTURE2D_DESC) {
> >          .Width      = ctx->width,
> >          .Height     = ctx->height,
> >          .MipLevels  = 1,
> > @@ -510,6 +510,46 @@ static void d3d11va_device_uninit(AVHWDeviceContext
> *hwdev)
> >      }
> >  }
> >
> > +static int d3d11va_device_find_qsv_adapter(AVHWDeviceContext *ctx, UINT
> creationFlags)
> > +{
> > +    HRESULT hr;
> > +    IDXGIAdapter *adapter = NULL;
> > +    int adapter_id = 0;
> > +    int vendor_id = 0x8086;
> > +    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)
> >  {
> > @@ -519,7 +559,9 @@ static int d3d11va_device_create(AVHWDeviceContext
> *ctx, const char *device,
> >      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 is_qsv         = !!av_dict_get(opts, "d3d11va_qsv", NULL, 0);
> >      int ret;
> >
> >      // (On UWP we can't check this.)
> > @@ -538,11 +580,22 @@ static int d3d11va_device_create(AVHWDeviceContext
> *ctx, const char *device,
> >          return AVERROR_UNKNOWN;
> >      }
> >
> > +    if (is_qsv) {
> > +        adapter = d3d11va_device_find_qsv_adapter(ctx, creationFlags);
> > +        if (adapter < 0) {
> > +            av_log(ctx, AV_LOG_ERROR, "Failed to find DX11 adapter with
> QSV support\n");
> > +            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..ae4247abf2 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
> > @@ -89,6 +93,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
> > @@ -229,9 +236,17 @@ 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;
> > +
> IDirect3DDeviceManager9_AddRef((IDirect3DDeviceManager9*)device_priv->handle);
> >          child_device_hwctx->devmgr =
> (IDirect3DDeviceManager9*)device_priv->handle;
> >      }
> >  #endif
> > @@ -255,6 +270,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 +304,18 @@ 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;
> > +        hwctx->texture = child_frames_hwctx->texture;
> > +        for (i = 0; i < ctx->initial_pool_size; i++)
> > +            s->surfaces_internal[i].Data.MemId = (mfxMemId)(int64_t)i;
> > +        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,7 +458,16 @@ static mfxStatus frame_unlock(mfxHDL pthis,
> mfxMemId mid, mfxFrameData *ptr)
> >
> >  static mfxStatus frame_get_hdl(mfxHDL pthis, mfxMemId mid, mfxHDL *hdl)
> >  {
> > -    *hdl = mid;
> > +    AVHWFramesContext    *ctx = pthis;
> > +    AVQSVFramesContext *hwctx = ctx->hwctx;
> > +
> > +    if (hwctx->texture) {
> > +        mfxHDLPair *pair  =  (mfxHDLPair*)hdl;
> > +        pair->first  = hwctx->texture;
> > +        pair->second = mid;
> > +    } else {
> > +        *hdl = mid;
> > +    }
> >      return MFX_ERR_NONE;
> >  }
> >
> > @@ -492,7 +538,7 @@ static int
> qsv_init_internal_session(AVHWFramesContext *ctx,
> >
> >      err = MFXVideoVPP_Init(*session, &par);
> >      if (err != MFX_ERR_NONE) {
> > -        av_log(ctx, AV_LOG_VERBOSE, "Error opening the internal VPP
> session."
> > +        av_log(ctx, AV_LOG_ERROR, "Error opening the internal VPP
> session."
> >                 "Surface upload/download will not be possible\n");
> >          MFXClose(*session);
> >          *session = NULL;
> > @@ -1074,7 +1120,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 +1149,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 +1179,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:
> >          {
> > @@ -1226,23 +1285,35 @@ static int qsv_device_create(AVHWDeviceContext
> *ctx, const char *device,
> >          // 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;
> > +        av_dict_set(&child_device_opts, "d3d11va_qsv",   "enabled",  0);
> > +    } 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);
> >      }
> >
> >      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;
> > +    if (ret < 0) {
> > +        if (CONFIG_DXVA2 && (child_device_type ==
> AV_HWDEVICE_TYPE_D3D11VA)) {
> > +            // in case of d3d11va fail, try one more chance to create
> device via dxva2
> > +            child_device_type = AV_HWDEVICE_TYPE_DXVA2;
> > +            child_device_opts = NULL;
> > +            ret = av_hwdevice_ctx_create(&priv->child_device_ctx,
> child_device_type,
> > +                            e ? e->value : NULL, child_device_opts, 0);
> > +        }
> > +        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);
> >  }
> > diff --git a/libavutil/hwcontext_qsv.h b/libavutil/hwcontext_qsv.h
> > index b98d611cfc..f5a9691949 100644
> > --- a/libavutil/hwcontext_qsv.h
> > +++ b/libavutil/hwcontext_qsv.h
> > @@ -42,6 +42,7 @@ typedef struct AVQSVDeviceContext {
> >  typedef struct AVQSVFramesContext {
> >      mfxFrameSurface1 *surfaces;
> >      int            nb_surfaces;
> > +    void              *texture;
>
> This is a public struct, so new fields have to be added at the end,
> otherwise it's an ABI break.
>
> Also, API changes require a minor library version bump and an APIchanges
> entry. Some documentation would be nice too.
>
>
Done.
Sorry for the thread duplication, something wrong with replying to this
thread with new patch version.
Updated patch is available by link below:
https://patchwork.ffmpeg.org/project/ffmpeg/patch/20200123151813.31739-1-artem.galin@gmail.com/

Thanks,
Artem.
diff mbox

Patch

diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c
index b00e427435..33ac7a3373 100644
--- a/libavcodec/qsv.c
+++ b/libavcodec/qsv.c
@@ -414,7 +414,7 @@  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)
 {
-    mfxIMPL          impl = MFX_IMPL_AUTO_ANY;
+    mfxIMPL          impl = MFX_IMPL_AUTO_ANY | MFX_IMPL_VIA_D3D11;
     mfxVersion        ver = { { QSV_VERSION_MINOR, QSV_VERSION_MAJOR } };
     mfxInitParam init_par = { MFX_IMPL_AUTO_ANY };
 
@@ -504,6 +504,7 @@  static AVBufferRef *qsv_create_mids(AVBufferRef *hw_frames_ref)
     for (i = 0; i < nb_surfaces; i++) {
         QSVMid *mid = &mids[i];
         mid->handle        = frames_hwctx->surfaces[i].Data.MemId;
+        mid->texture       = frames_hwctx->texture;
         mid->hw_frames_ref = hw_frames_ref1;
     }
 
@@ -713,7 +714,13 @@  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->texture) {
+        mfxHDLPair *pair  =  (mfxHDLPair*)hdl;
+        pair->first  = qsv_mid->texture;
+        pair->second = qsv_mid->handle;
+    } else {
+        *hdl = qsv_mid->handle;
+    }
     return MFX_ERR_NONE;
 }
 
@@ -723,8 +730,8 @@  int ff_qsv_init_session_device(AVCodecContext *avctx, mfxSession *psession,
 {
     static const mfxHandleType handle_types[] = {
         MFX_HANDLE_VA_DISPLAY,
-        MFX_HANDLE_D3D9_DEVICE_MANAGER,
         MFX_HANDLE_D3D11_DEVICE,
+        MFX_HANDLE_D3D9_DEVICE_MANAGER,
     };
     AVHWDeviceContext    *device_ctx = (AVHWDeviceContext*)device_ref->data;
     AVQSVDeviceContext *device_hwctx = device_ctx->hwctx;
diff --git a/libavcodec/qsv_internal.h b/libavcodec/qsv_internal.h
index 37559270e5..09425fb431 100644
--- a/libavcodec/qsv_internal.h
+++ b/libavcodec/qsv_internal.h
@@ -60,6 +60,7 @@ 
 
 typedef struct QSVMid {
     AVBufferRef *hw_frames_ref;
+    void *texture;
     mfxHDL handle;
 
     AVFrame *locked_frame;
diff --git a/libavutil/hwcontext_d3d11va.c b/libavutil/hwcontext_d3d11va.c
index 6670c47579..a08479fd96 100644
--- a/libavutil/hwcontext_d3d11va.c
+++ b/libavutil/hwcontext_d3d11va.c
@@ -244,7 +244,7 @@  static int d3d11va_frames_init(AVHWFramesContext *ctx)
         return AVERROR(EINVAL);
     }
 
-    texDesc = (D3D11_TEXTURE2D_DESC){
+    texDesc = (D3D11_TEXTURE2D_DESC) {
         .Width      = ctx->width,
         .Height     = ctx->height,
         .MipLevels  = 1,
@@ -510,6 +510,46 @@  static void d3d11va_device_uninit(AVHWDeviceContext *hwdev)
     }
 }
 
+static int d3d11va_device_find_qsv_adapter(AVHWDeviceContext *ctx, UINT creationFlags)
+{
+    HRESULT hr;
+    IDXGIAdapter *adapter = NULL;
+    int adapter_id = 0;
+    int vendor_id = 0x8086;
+    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)
 {
@@ -519,7 +559,9 @@  static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device,
     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 is_qsv         = !!av_dict_get(opts, "d3d11va_qsv", NULL, 0);
     int ret;
 
     // (On UWP we can't check this.)
@@ -538,11 +580,22 @@  static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device,
         return AVERROR_UNKNOWN;
     }
 
+    if (is_qsv) {
+        adapter = d3d11va_device_find_qsv_adapter(ctx, creationFlags);
+        if (adapter < 0) {
+            av_log(ctx, AV_LOG_ERROR, "Failed to find DX11 adapter with QSV support\n");
+            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..ae4247abf2 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
@@ -89,6 +93,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
@@ -229,9 +236,17 @@  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;
+        IDirect3DDeviceManager9_AddRef((IDirect3DDeviceManager9*)device_priv->handle);
         child_device_hwctx->devmgr = (IDirect3DDeviceManager9*)device_priv->handle;
     }
 #endif
@@ -255,6 +270,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 +304,18 @@  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;
+        hwctx->texture = child_frames_hwctx->texture;
+        for (i = 0; i < ctx->initial_pool_size; i++)
+            s->surfaces_internal[i].Data.MemId = (mfxMemId)(int64_t)i;
+        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,7 +458,16 @@  static mfxStatus frame_unlock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr)
 
 static mfxStatus frame_get_hdl(mfxHDL pthis, mfxMemId mid, mfxHDL *hdl)
 {
-    *hdl = mid;
+    AVHWFramesContext    *ctx = pthis;
+    AVQSVFramesContext *hwctx = ctx->hwctx;
+
+    if (hwctx->texture) {
+        mfxHDLPair *pair  =  (mfxHDLPair*)hdl;
+        pair->first  = hwctx->texture;
+        pair->second = mid;
+    } else {
+        *hdl = mid;
+    }
     return MFX_ERR_NONE;
 }
 
@@ -492,7 +538,7 @@  static int qsv_init_internal_session(AVHWFramesContext *ctx,
 
     err = MFXVideoVPP_Init(*session, &par);
     if (err != MFX_ERR_NONE) {
-        av_log(ctx, AV_LOG_VERBOSE, "Error opening the internal VPP session."
+        av_log(ctx, AV_LOG_ERROR, "Error opening the internal VPP session."
                "Surface upload/download will not be possible\n");
         MFXClose(*session);
         *session = NULL;
@@ -1074,7 +1120,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 +1149,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 +1179,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:
         {
@@ -1226,23 +1285,35 @@  static int qsv_device_create(AVHWDeviceContext *ctx, const char *device,
         // 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;
+        av_dict_set(&child_device_opts, "d3d11va_qsv",   "enabled",  0);
+    } 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);
     }
 
     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;
+    if (ret < 0) {
+        if (CONFIG_DXVA2 && (child_device_type == AV_HWDEVICE_TYPE_D3D11VA)) {
+            // in case of d3d11va fail, try one more chance to create device via dxva2
+            child_device_type = AV_HWDEVICE_TYPE_DXVA2;
+            child_device_opts = NULL;
+            ret = av_hwdevice_ctx_create(&priv->child_device_ctx, child_device_type,
+                            e ? e->value : NULL, child_device_opts, 0);
+        }
+        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);
 }
diff --git a/libavutil/hwcontext_qsv.h b/libavutil/hwcontext_qsv.h
index b98d611cfc..f5a9691949 100644
--- a/libavutil/hwcontext_qsv.h
+++ b/libavutil/hwcontext_qsv.h
@@ -42,6 +42,7 @@  typedef struct AVQSVDeviceContext {
 typedef struct AVQSVFramesContext {
     mfxFrameSurface1 *surfaces;
     int            nb_surfaces;
+    void              *texture;
 
     /**
      * A combination of MFX_MEMTYPE_* describing the frame pool.