diff mbox series

[FFmpeg-devel,v7,09/10] qsv: use a new method to create mfx session when using oneVPL

Message ID 20220311081630.21927-10-haihao.xiang@intel.com
State New
Headers show
Series make QSV works with the Intel's oneVPL | expand

Checks

Context Check Description
yinshiyou/make_loongarch64 success Make finished
yinshiyou/make_fate_loongarch64 success Make fate finished
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished

Commit Message

Xiang, Haihao March 11, 2022, 8:16 a.m. UTC
From: Haihao Xiang <haihao.xiang@intel.com>

In oneVPL, MFXLoad() and MFXCreateSession() are required to create a
workable mfx session[1]

Add AccelerationMode config filter for D3D9/D3D11 session (galinart)

The default device is changed to d3d11va for oneVPL when both d3d11va
and dxva2 are enabled on Microsoft Windows

This is in preparation for oneVPL support

[1] https://spec.oneapi.io/versions/latest/elements/oneVPL/source/programming_guide/VPL_prg_session.html#onevpl-dispatcher

Signed-off-by: galinart <artem.galin@intel.com>
---
 libavcodec/qsv.c                 | 197 ++++++++++++++--
 libavcodec/qsv_internal.h        |   1 +
 libavcodec/qsvdec.c              |  10 +
 libavcodec/qsvenc.h              |   3 +
 libavcodec/qsvenc_h264.c         |   1 -
 libavcodec/qsvenc_hevc.c         |   1 -
 libavcodec/qsvenc_jpeg.c         |   1 -
 libavcodec/qsvenc_mpeg2.c        |   1 -
 libavcodec/qsvenc_vp9.c          |   1 -
 libavfilter/qsvvpp.c             | 113 ++++++++-
 libavfilter/qsvvpp.h             |   5 +
 libavfilter/vf_deinterlace_qsv.c |  14 +-
 libavfilter/vf_scale_qsv.c       |  12 +-
 libavutil/hwcontext_d3d11va.c    |  13 ++
 libavutil/hwcontext_d3d11va.h    |   5 +
 libavutil/hwcontext_dxva2.c      |   8 +
 libavutil/hwcontext_dxva2.h      |   4 +
 libavutil/hwcontext_qsv.c        | 386 +++++++++++++++++++++++++++----
 libavutil/hwcontext_qsv.h        |   1 +
 libavutil/hwcontext_vaapi.c      |  13 ++
 libavutil/hwcontext_vaapi.h      |   4 +
 21 files changed, 706 insertions(+), 88 deletions(-)

Comments

Hendrik Leppkes March 11, 2022, 8:35 a.m. UTC | #1
On Fri, Mar 11, 2022 at 9:18 AM Xiang, Haihao
<haihao.xiang-at-intel.com@ffmpeg.org> wrote:
> diff --git a/libavutil/hwcontext_d3d11va.c b/libavutil/hwcontext_d3d11va.c
> index 8ab96bad25..e0e820f164 100644
> --- a/libavutil/hwcontext_d3d11va.c
> +++ b/libavutil/hwcontext_d3d11va.c
> @@ -525,6 +525,13 @@ static void d3d11va_device_uninit(AVHWDeviceContext *hwdev)
>      }
>  }
>
> +static void d3d11va_device_free(AVHWDeviceContext *ctx)
> +{
> +    AVD3D11VADeviceContext *hwctx = ctx->hwctx;
> +
> +    av_free(hwctx->device_name);
> +}
> +
>  static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device,
>                                   AVDictionary *opts, int flags)
>  {
> @@ -537,6 +544,8 @@ static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device,
>      int is_debug       = !!av_dict_get(opts, "debug", NULL, 0);
>      int ret;
>
> +    ctx->free = d3d11va_device_free;
> +
>      // (On UWP we can't check this.)
>  #if !HAVE_UWP
>      if (!LoadLibrary("d3d11_1sdklayers.dll"))
> @@ -561,6 +570,10 @@ static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device,
>              if (FAILED(IDXGIFactory2_EnumAdapters(pDXGIFactory, adapter, &pAdapter)))
>                  pAdapter = NULL;
>              IDXGIFactory2_Release(pDXGIFactory);
> +
> +            device_hwctx->device_name = av_strdup(device);
> +            if (!device_hwctx->device_name)
> +                return AVERROR(ENOMEM);
>          }
>      }
>
> diff --git a/libavutil/hwcontext_d3d11va.h b/libavutil/hwcontext_d3d11va.h
> index 77d2d72f1b..41a315b9e6 100644
> --- a/libavutil/hwcontext_d3d11va.h
> +++ b/libavutil/hwcontext_d3d11va.h
> @@ -94,6 +94,11 @@ typedef struct AVD3D11VADeviceContext {
>      void (*lock)(void *lock_ctx);
>      void (*unlock)(void *lock_ctx);
>      void *lock_ctx;
> +
> +    /**
> +     * The string for the used adapter
> +     */
> +    char *device_name;
>  } AVD3D11VADeviceContext;
>
>  /**
> diff --git a/libavutil/hwcontext_dxva2.c b/libavutil/hwcontext_dxva2.c
> index 53d00fa815..6967357093 100644
> --- a/libavutil/hwcontext_dxva2.c
> +++ b/libavutil/hwcontext_dxva2.c
> @@ -431,6 +431,7 @@ static void dxva2_device_free(AVHWDeviceContext *ctx)
>          dlclose(priv->dxva2lib);
>
>      av_freep(&ctx->user_opaque);
> +    av_free(hwctx->device_name);
>  }
>
>  static int dxva2_device_create9(AVHWDeviceContext *ctx, UINT adapter)
> @@ -571,6 +572,13 @@ static int dxva2_device_create(AVHWDeviceContext *ctx, const char *device,
>          return AVERROR_UNKNOWN;
>      }
>
> +    if (device) {
> +        hwctx->device_name = av_strdup(device);
> +
> +        if (!hwctx->device_name)
> +            return AVERROR(ENOMEM);
> +    }
> +
>      return 0;
>  }
>
> diff --git a/libavutil/hwcontext_dxva2.h b/libavutil/hwcontext_dxva2.h
> index e1b79bc0de..253ddbed51 100644
> --- a/libavutil/hwcontext_dxva2.h
> +++ b/libavutil/hwcontext_dxva2.h
> @@ -38,6 +38,10 @@
>   */
>  typedef struct AVDXVA2DeviceContext {
>      IDirect3DDeviceManager9 *devmgr;
> +    /**
> +     * The string for the used adapter
> +     */
> +    char *device_name;
>  } AVDXVA2DeviceContext;
>
>  /**

Why are these device names required? I would think deriving a child
device would use the actual device, eg. ID3D11Device or
IDirect3DDeviceManager9 (and whatever for VAAPI), and not some string
(that may or may not even be set).
It feels quite a bit icky to store these in the context just for qsv
to do... what with?

- Hendrik
Xiang, Haihao March 11, 2022, 1:43 p.m. UTC | #2
On Fri, 2022-03-11 at 09:35 +0100, Hendrik Leppkes wrote:
> On Fri, Mar 11, 2022 at 9:18 AM Xiang, Haihao
> <haihao.xiang-at-intel.com@ffmpeg.org> wrote:
> > diff --git a/libavutil/hwcontext_d3d11va.c b/libavutil/hwcontext_d3d11va.c
> > index 8ab96bad25..e0e820f164 100644
> > --- a/libavutil/hwcontext_d3d11va.c
> > +++ b/libavutil/hwcontext_d3d11va.c
> > @@ -525,6 +525,13 @@ static void d3d11va_device_uninit(AVHWDeviceContext
> > *hwdev)
> >      }
> >  }
> > 
> > +static void d3d11va_device_free(AVHWDeviceContext *ctx)
> > +{
> > +    AVD3D11VADeviceContext *hwctx = ctx->hwctx;
> > +
> > +    av_free(hwctx->device_name);
> > +}
> > +
> >  static int d3d11va_device_create(AVHWDeviceContext *ctx, const char
> > *device,
> >                                   AVDictionary *opts, int flags)
> >  {
> > @@ -537,6 +544,8 @@ static int d3d11va_device_create(AVHWDeviceContext *ctx,
> > const char *device,
> >      int is_debug       = !!av_dict_get(opts, "debug", NULL, 0);
> >      int ret;
> > 
> > +    ctx->free = d3d11va_device_free;
> > +
> >      // (On UWP we can't check this.)
> >  #if !HAVE_UWP
> >      if (!LoadLibrary("d3d11_1sdklayers.dll"))
> > @@ -561,6 +570,10 @@ static int d3d11va_device_create(AVHWDeviceContext
> > *ctx, const char *device,
> >              if (FAILED(IDXGIFactory2_EnumAdapters(pDXGIFactory, adapter,
> > &pAdapter)))
> >                  pAdapter = NULL;
> >              IDXGIFactory2_Release(pDXGIFactory);
> > +
> > +            device_hwctx->device_name = av_strdup(device);
> > +            if (!device_hwctx->device_name)
> > +                return AVERROR(ENOMEM);
> >          }
> >      }
> > 
> > diff --git a/libavutil/hwcontext_d3d11va.h b/libavutil/hwcontext_d3d11va.h
> > index 77d2d72f1b..41a315b9e6 100644
> > --- a/libavutil/hwcontext_d3d11va.h
> > +++ b/libavutil/hwcontext_d3d11va.h
> > @@ -94,6 +94,11 @@ typedef struct AVD3D11VADeviceContext {
> >      void (*lock)(void *lock_ctx);
> >      void (*unlock)(void *lock_ctx);
> >      void *lock_ctx;
> > +
> > +    /**
> > +     * The string for the used adapter
> > +     */
> > +    char *device_name;
> >  } AVD3D11VADeviceContext;
> > 
> >  /**
> > diff --git a/libavutil/hwcontext_dxva2.c b/libavutil/hwcontext_dxva2.c
> > index 53d00fa815..6967357093 100644
> > --- a/libavutil/hwcontext_dxva2.c
> > +++ b/libavutil/hwcontext_dxva2.c
> > @@ -431,6 +431,7 @@ static void dxva2_device_free(AVHWDeviceContext *ctx)
> >          dlclose(priv->dxva2lib);
> > 
> >      av_freep(&ctx->user_opaque);
> > +    av_free(hwctx->device_name);
> >  }
> > 
> >  static int dxva2_device_create9(AVHWDeviceContext *ctx, UINT adapter)
> > @@ -571,6 +572,13 @@ static int dxva2_device_create(AVHWDeviceContext *ctx,
> > const char *device,
> >          return AVERROR_UNKNOWN;
> >      }
> > 
> > +    if (device) {
> > +        hwctx->device_name = av_strdup(device);
> > +
> > +        if (!hwctx->device_name)
> > +            return AVERROR(ENOMEM);
> > +    }
> > +
> >      return 0;
> >  }
> > 
> > diff --git a/libavutil/hwcontext_dxva2.h b/libavutil/hwcontext_dxva2.h
> > index e1b79bc0de..253ddbed51 100644
> > --- a/libavutil/hwcontext_dxva2.h
> > +++ b/libavutil/hwcontext_dxva2.h
> > @@ -38,6 +38,10 @@
> >   */
> >  typedef struct AVDXVA2DeviceContext {
> >      IDirect3DDeviceManager9 *devmgr;
> > +    /**
> > +     * The string for the used adapter
> > +     */
> > +    char *device_name;
> >  } AVDXVA2DeviceContext;
> > 
> >  /**
> 
> Why are these device names required? I would think deriving a child
> device would use the actual device, eg. ID3D11Device or
> IDirect3DDeviceManager9 (and whatever for VAAPI), and not some string
> (that may or may not even be set).
> It feels quite a bit icky to store these in the context just for qsv
> to do... what with?

Yes, it is a little ugly here. MediaSDK or oneVPL application creates mfx
session and the device (dxva2, d3d11va or vaapi), then pass this device to the
SDK through MFXVideoCORE_SetHandle(). implementation is introduced in oneVPL (
https://spec.oneapi.io/versions/latest/elements/oneVPL/source/API_ref/VPL_disp_api_struct.html#structmfx_impl_description
) and user must select an available implementation before the creation of mfx
session, however the device handle is unknown in the SDK when selecting an
available implementation, the SDK provides a method to select implementation via
the given adapter (on Windows) or DRI device node (on Linux). The default
implementation will be selected if child device name is unknown. 

Thanks
Haihao
Hendrik Leppkes March 11, 2022, 2 p.m. UTC | #3
On Fri, Mar 11, 2022 at 2:43 PM Xiang, Haihao
<haihao.xiang-at-intel.com@ffmpeg.org> wrote:
>
> On Fri, 2022-03-11 at 09:35 +0100, Hendrik Leppkes wrote:
> > On Fri, Mar 11, 2022 at 9:18 AM Xiang, Haihao
> > <haihao.xiang-at-intel.com@ffmpeg.org> wrote:
> > > diff --git a/libavutil/hwcontext_d3d11va.c b/libavutil/hwcontext_d3d11va.c
> > > index 8ab96bad25..e0e820f164 100644
> > > --- a/libavutil/hwcontext_d3d11va.c
> > > +++ b/libavutil/hwcontext_d3d11va.c
> > > @@ -525,6 +525,13 @@ static void d3d11va_device_uninit(AVHWDeviceContext
> > > *hwdev)
> > >      }
> > >  }
> > >
> > > +static void d3d11va_device_free(AVHWDeviceContext *ctx)
> > > +{
> > > +    AVD3D11VADeviceContext *hwctx = ctx->hwctx;
> > > +
> > > +    av_free(hwctx->device_name);
> > > +}
> > > +
> > >  static int d3d11va_device_create(AVHWDeviceContext *ctx, const char
> > > *device,
> > >                                   AVDictionary *opts, int flags)
> > >  {
> > > @@ -537,6 +544,8 @@ static int d3d11va_device_create(AVHWDeviceContext *ctx,
> > > const char *device,
> > >      int is_debug       = !!av_dict_get(opts, "debug", NULL, 0);
> > >      int ret;
> > >
> > > +    ctx->free = d3d11va_device_free;
> > > +
> > >      // (On UWP we can't check this.)
> > >  #if !HAVE_UWP
> > >      if (!LoadLibrary("d3d11_1sdklayers.dll"))
> > > @@ -561,6 +570,10 @@ static int d3d11va_device_create(AVHWDeviceContext
> > > *ctx, const char *device,
> > >              if (FAILED(IDXGIFactory2_EnumAdapters(pDXGIFactory, adapter,
> > > &pAdapter)))
> > >                  pAdapter = NULL;
> > >              IDXGIFactory2_Release(pDXGIFactory);
> > > +
> > > +            device_hwctx->device_name = av_strdup(device);
> > > +            if (!device_hwctx->device_name)
> > > +                return AVERROR(ENOMEM);
> > >          }
> > >      }
> > >
> > > diff --git a/libavutil/hwcontext_d3d11va.h b/libavutil/hwcontext_d3d11va.h
> > > index 77d2d72f1b..41a315b9e6 100644
> > > --- a/libavutil/hwcontext_d3d11va.h
> > > +++ b/libavutil/hwcontext_d3d11va.h
> > > @@ -94,6 +94,11 @@ typedef struct AVD3D11VADeviceContext {
> > >      void (*lock)(void *lock_ctx);
> > >      void (*unlock)(void *lock_ctx);
> > >      void *lock_ctx;
> > > +
> > > +    /**
> > > +     * The string for the used adapter
> > > +     */
> > > +    char *device_name;
> > >  } AVD3D11VADeviceContext;
> > >
> > >  /**
> > > diff --git a/libavutil/hwcontext_dxva2.c b/libavutil/hwcontext_dxva2.c
> > > index 53d00fa815..6967357093 100644
> > > --- a/libavutil/hwcontext_dxva2.c
> > > +++ b/libavutil/hwcontext_dxva2.c
> > > @@ -431,6 +431,7 @@ static void dxva2_device_free(AVHWDeviceContext *ctx)
> > >          dlclose(priv->dxva2lib);
> > >
> > >      av_freep(&ctx->user_opaque);
> > > +    av_free(hwctx->device_name);
> > >  }
> > >
> > >  static int dxva2_device_create9(AVHWDeviceContext *ctx, UINT adapter)
> > > @@ -571,6 +572,13 @@ static int dxva2_device_create(AVHWDeviceContext *ctx,
> > > const char *device,
> > >          return AVERROR_UNKNOWN;
> > >      }
> > >
> > > +    if (device) {
> > > +        hwctx->device_name = av_strdup(device);
> > > +
> > > +        if (!hwctx->device_name)
> > > +            return AVERROR(ENOMEM);
> > > +    }
> > > +
> > >      return 0;
> > >  }
> > >
> > > diff --git a/libavutil/hwcontext_dxva2.h b/libavutil/hwcontext_dxva2.h
> > > index e1b79bc0de..253ddbed51 100644
> > > --- a/libavutil/hwcontext_dxva2.h
> > > +++ b/libavutil/hwcontext_dxva2.h
> > > @@ -38,6 +38,10 @@
> > >   */
> > >  typedef struct AVDXVA2DeviceContext {
> > >      IDirect3DDeviceManager9 *devmgr;
> > > +    /**
> > > +     * The string for the used adapter
> > > +     */
> > > +    char *device_name;
> > >  } AVDXVA2DeviceContext;
> > >
> > >  /**
> >
> > Why are these device names required? I would think deriving a child
> > device would use the actual device, eg. ID3D11Device or
> > IDirect3DDeviceManager9 (and whatever for VAAPI), and not some string
> > (that may or may not even be set).
> > It feels quite a bit icky to store these in the context just for qsv
> > to do... what with?
>
> Yes, it is a little ugly here. MediaSDK or oneVPL application creates mfx
> session and the device (dxva2, d3d11va or vaapi), then pass this device to the
> SDK through MFXVideoCORE_SetHandle(). implementation is introduced in oneVPL (
> https://spec.oneapi.io/versions/latest/elements/oneVPL/source/API_ref/VPL_disp_api_struct.html#structmfx_impl_description
> ) and user must select an available implementation before the creation of mfx
> session, however the device handle is unknown in the SDK when selecting an
> available implementation, the SDK provides a method to select implementation via
> the given adapter (on Windows) or DRI device node (on Linux). The default
> implementation will be selected if child device name is unknown.
>

First of all, whoever made that API should get a stern message.
Expecting to properly interoperate with the dominant platform APIs
should be a primary goal, and it sounds like it was somehow shoehorned
in after the fact.

For D3D11 for example, you can get the IDXGIAdapter a device was
created from, isn't there enough information in there to pass-on
without storing a string field?
IDXGIAdapter::GetDesc has tons of identification information to
identify the device in use.

D3D9 probably has something similar, haven't checked right now.

- Hendrik
Xiang, Haihao March 15, 2022, 7:24 a.m. UTC | #4
On Fri, 2022-03-11 at 15:00 +0100, Hendrik Leppkes wrote:
> On Fri, Mar 11, 2022 at 2:43 PM Xiang, Haihao
> <haihao.xiang-at-intel.com@ffmpeg.org> wrote:
> > 
> > On Fri, 2022-03-11 at 09:35 +0100, Hendrik Leppkes wrote:
> > > On Fri, Mar 11, 2022 at 9:18 AM Xiang, Haihao
> > > <haihao.xiang-at-intel.com@ffmpeg.org> wrote:
> > > > diff --git a/libavutil/hwcontext_d3d11va.c
> > > > b/libavutil/hwcontext_d3d11va.c
> > > > index 8ab96bad25..e0e820f164 100644
> > > > --- a/libavutil/hwcontext_d3d11va.c
> > > > +++ b/libavutil/hwcontext_d3d11va.c
> > > > @@ -525,6 +525,13 @@ static void d3d11va_device_uninit(AVHWDeviceContext
> > > > *hwdev)
> > > >      }
> > > >  }
> > > > 
> > > > +static void d3d11va_device_free(AVHWDeviceContext *ctx)
> > > > +{
> > > > +    AVD3D11VADeviceContext *hwctx = ctx->hwctx;
> > > > +
> > > > +    av_free(hwctx->device_name);
> > > > +}
> > > > +
> > > >  static int d3d11va_device_create(AVHWDeviceContext *ctx, const char
> > > > *device,
> > > >                                   AVDictionary *opts, int flags)
> > > >  {
> > > > @@ -537,6 +544,8 @@ static int d3d11va_device_create(AVHWDeviceContext
> > > > *ctx,
> > > > const char *device,
> > > >      int is_debug       = !!av_dict_get(opts, "debug", NULL, 0);
> > > >      int ret;
> > > > 
> > > > +    ctx->free = d3d11va_device_free;
> > > > +
> > > >      // (On UWP we can't check this.)
> > > >  #if !HAVE_UWP
> > > >      if (!LoadLibrary("d3d11_1sdklayers.dll"))
> > > > @@ -561,6 +570,10 @@ static int d3d11va_device_create(AVHWDeviceContext
> > > > *ctx, const char *device,
> > > >              if (FAILED(IDXGIFactory2_EnumAdapters(pDXGIFactory,
> > > > adapter,
> > > > &pAdapter)))
> > > >                  pAdapter = NULL;
> > > >              IDXGIFactory2_Release(pDXGIFactory);
> > > > +
> > > > +            device_hwctx->device_name = av_strdup(device);
> > > > +            if (!device_hwctx->device_name)
> > > > +                return AVERROR(ENOMEM);
> > > >          }
> > > >      }
> > > > 
> > > > diff --git a/libavutil/hwcontext_d3d11va.h
> > > > b/libavutil/hwcontext_d3d11va.h
> > > > index 77d2d72f1b..41a315b9e6 100644
> > > > --- a/libavutil/hwcontext_d3d11va.h
> > > > +++ b/libavutil/hwcontext_d3d11va.h
> > > > @@ -94,6 +94,11 @@ typedef struct AVD3D11VADeviceContext {
> > > >      void (*lock)(void *lock_ctx);
> > > >      void (*unlock)(void *lock_ctx);
> > > >      void *lock_ctx;
> > > > +
> > > > +    /**
> > > > +     * The string for the used adapter
> > > > +     */
> > > > +    char *device_name;
> > > >  } AVD3D11VADeviceContext;
> > > > 
> > > >  /**
> > > > diff --git a/libavutil/hwcontext_dxva2.c b/libavutil/hwcontext_dxva2.c
> > > > index 53d00fa815..6967357093 100644
> > > > --- a/libavutil/hwcontext_dxva2.c
> > > > +++ b/libavutil/hwcontext_dxva2.c
> > > > @@ -431,6 +431,7 @@ static void dxva2_device_free(AVHWDeviceContext
> > > > *ctx)
> > > >          dlclose(priv->dxva2lib);
> > > > 
> > > >      av_freep(&ctx->user_opaque);
> > > > +    av_free(hwctx->device_name);
> > > >  }
> > > > 
> > > >  static int dxva2_device_create9(AVHWDeviceContext *ctx, UINT adapter)
> > > > @@ -571,6 +572,13 @@ static int dxva2_device_create(AVHWDeviceContext
> > > > *ctx,
> > > > const char *device,
> > > >          return AVERROR_UNKNOWN;
> > > >      }
> > > > 
> > > > +    if (device) {
> > > > +        hwctx->device_name = av_strdup(device);
> > > > +
> > > > +        if (!hwctx->device_name)
> > > > +            return AVERROR(ENOMEM);
> > > > +    }
> > > > +
> > > >      return 0;
> > > >  }
> > > > 
> > > > diff --git a/libavutil/hwcontext_dxva2.h b/libavutil/hwcontext_dxva2.h
> > > > index e1b79bc0de..253ddbed51 100644
> > > > --- a/libavutil/hwcontext_dxva2.h
> > > > +++ b/libavutil/hwcontext_dxva2.h
> > > > @@ -38,6 +38,10 @@
> > > >   */
> > > >  typedef struct AVDXVA2DeviceContext {
> > > >      IDirect3DDeviceManager9 *devmgr;
> > > > +    /**
> > > > +     * The string for the used adapter
> > > > +     */
> > > > +    char *device_name;
> > > >  } AVDXVA2DeviceContext;
> > > > 
> > > >  /**
> > > 
> > > Why are these device names required? I would think deriving a child
> > > device would use the actual device, eg. ID3D11Device or
> > > IDirect3DDeviceManager9 (and whatever for VAAPI), and not some string
> > > (that may or may not even be set).
> > > It feels quite a bit icky to store these in the context just for qsv
> > > to do... what with?
> > 
> > Yes, it is a little ugly here. MediaSDK or oneVPL application creates mfx
> > session and the device (dxva2, d3d11va or vaapi), then pass this device to
> > the
> > SDK through MFXVideoCORE_SetHandle(). implementation is introduced in oneVPL
> > (
> > 
https://spec.oneapi.io/versions/latest/elements/oneVPL/source/API_ref/VPL_disp_api_struct.html#structmfx_impl_description
> > ) and user must select an available implementation before the creation of
> > mfx
> > session, however the device handle is unknown in the SDK when selecting an
> > available implementation, the SDK provides a method to select implementation
> > via
> > the given adapter (on Windows) or DRI device node (on Linux). The default
> > implementation will be selected if child device name is unknown.
> > 
> 
> First of all, whoever made that API should get a stern message.
> Expecting to properly interoperate with the dominant platform APIs
> should be a primary goal, and it sounds like it was somehow shoehorned
> in after the fact.
> 
> For D3D11 for example, you can get the IDXGIAdapter a device was
> created from, isn't there enough information in there to pass-on
> without storing a string field?
> IDXGIAdapter::GetDesc has tons of identification information to
> identify the device in use.
> 
> D3D9 probably has something similar, haven't checked right now.


Thanks for the info, I may get AdapterLuid from the adapter description, however
the required parameter in oneVPL is the index of the adapter, is there a way to
map AdapterLuid to adapter index ? (Sorry for this dumb question)

There is `IDirect3DDeviceManager9 *devmgr` only in AVDXVA2DeviceContext for
D3D9, it seems we have to add other members to get adapter description. 

As for vaapi, there is no API to get the used DRI device from VADisplay handle,
we have to store this info in AVVAAPIDeviceContext, and I prefer using the same
way for d3d9 & d3d11va too.

Note
We may get the specified child device (or default device) in hwcontext_qsv.c if
initializing qsv device directly, e.g. -init_hw_device
qsv:hw_any,child_device=/dev/dri/renderD129, and needn't change
AVD3D11VADeviceContext / AVDXVA2DeviceContext / AVVAAPIDeviceContext. This
change is required if deriving QSV device from a child device, e.g.
-init_hw_device vaapi=va:/dev/dri/renderD129 -init_hw_device qsv=hw@va

Thanks
Haihao
Hendrik Leppkes April 4, 2022, 9:46 a.m. UTC | #5
On Tue, Mar 15, 2022 at 8:24 AM Xiang, Haihao
<haihao.xiang-at-intel.com@ffmpeg.org> wrote:
>
> On Fri, 2022-03-11 at 15:00 +0100, Hendrik Leppkes wrote:
> > On Fri, Mar 11, 2022 at 2:43 PM Xiang, Haihao
> > <haihao.xiang-at-intel.com@ffmpeg.org> wrote:
> > >
> > > On Fri, 2022-03-11 at 09:35 +0100, Hendrik Leppkes wrote:
> > > > On Fri, Mar 11, 2022 at 9:18 AM Xiang, Haihao
> > > > <haihao.xiang-at-intel.com@ffmpeg.org> wrote:
> > > > > diff --git a/libavutil/hwcontext_d3d11va.c
> > > > > b/libavutil/hwcontext_d3d11va.c
> > > > > index 8ab96bad25..e0e820f164 100644
> > > > > --- a/libavutil/hwcontext_d3d11va.c
> > > > > +++ b/libavutil/hwcontext_d3d11va.c
> > > > > @@ -525,6 +525,13 @@ static void d3d11va_device_uninit(AVHWDeviceContext
> > > > > *hwdev)
> > > > >      }
> > > > >  }
> > > > >
> > > > > +static void d3d11va_device_free(AVHWDeviceContext *ctx)
> > > > > +{
> > > > > +    AVD3D11VADeviceContext *hwctx = ctx->hwctx;
> > > > > +
> > > > > +    av_free(hwctx->device_name);
> > > > > +}
> > > > > +
> > > > >  static int d3d11va_device_create(AVHWDeviceContext *ctx, const char
> > > > > *device,
> > > > >                                   AVDictionary *opts, int flags)
> > > > >  {
> > > > > @@ -537,6 +544,8 @@ static int d3d11va_device_create(AVHWDeviceContext
> > > > > *ctx,
> > > > > const char *device,
> > > > >      int is_debug       = !!av_dict_get(opts, "debug", NULL, 0);
> > > > >      int ret;
> > > > >
> > > > > +    ctx->free = d3d11va_device_free;
> > > > > +
> > > > >      // (On UWP we can't check this.)
> > > > >  #if !HAVE_UWP
> > > > >      if (!LoadLibrary("d3d11_1sdklayers.dll"))
> > > > > @@ -561,6 +570,10 @@ static int d3d11va_device_create(AVHWDeviceContext
> > > > > *ctx, const char *device,
> > > > >              if (FAILED(IDXGIFactory2_EnumAdapters(pDXGIFactory,
> > > > > adapter,
> > > > > &pAdapter)))
> > > > >                  pAdapter = NULL;
> > > > >              IDXGIFactory2_Release(pDXGIFactory);
> > > > > +
> > > > > +            device_hwctx->device_name = av_strdup(device);
> > > > > +            if (!device_hwctx->device_name)
> > > > > +                return AVERROR(ENOMEM);
> > > > >          }
> > > > >      }
> > > > >
> > > > > diff --git a/libavutil/hwcontext_d3d11va.h
> > > > > b/libavutil/hwcontext_d3d11va.h
> > > > > index 77d2d72f1b..41a315b9e6 100644
> > > > > --- a/libavutil/hwcontext_d3d11va.h
> > > > > +++ b/libavutil/hwcontext_d3d11va.h
> > > > > @@ -94,6 +94,11 @@ typedef struct AVD3D11VADeviceContext {
> > > > >      void (*lock)(void *lock_ctx);
> > > > >      void (*unlock)(void *lock_ctx);
> > > > >      void *lock_ctx;
> > > > > +
> > > > > +    /**
> > > > > +     * The string for the used adapter
> > > > > +     */
> > > > > +    char *device_name;
> > > > >  } AVD3D11VADeviceContext;
> > > > >
> > > > >  /**
> > > > > diff --git a/libavutil/hwcontext_dxva2.c b/libavutil/hwcontext_dxva2.c
> > > > > index 53d00fa815..6967357093 100644
> > > > > --- a/libavutil/hwcontext_dxva2.c
> > > > > +++ b/libavutil/hwcontext_dxva2.c
> > > > > @@ -431,6 +431,7 @@ static void dxva2_device_free(AVHWDeviceContext
> > > > > *ctx)
> > > > >          dlclose(priv->dxva2lib);
> > > > >
> > > > >      av_freep(&ctx->user_opaque);
> > > > > +    av_free(hwctx->device_name);
> > > > >  }
> > > > >
> > > > >  static int dxva2_device_create9(AVHWDeviceContext *ctx, UINT adapter)
> > > > > @@ -571,6 +572,13 @@ static int dxva2_device_create(AVHWDeviceContext
> > > > > *ctx,
> > > > > const char *device,
> > > > >          return AVERROR_UNKNOWN;
> > > > >      }
> > > > >
> > > > > +    if (device) {
> > > > > +        hwctx->device_name = av_strdup(device);
> > > > > +
> > > > > +        if (!hwctx->device_name)
> > > > > +            return AVERROR(ENOMEM);
> > > > > +    }
> > > > > +
> > > > >      return 0;
> > > > >  }
> > > > >
> > > > > diff --git a/libavutil/hwcontext_dxva2.h b/libavutil/hwcontext_dxva2.h
> > > > > index e1b79bc0de..253ddbed51 100644
> > > > > --- a/libavutil/hwcontext_dxva2.h
> > > > > +++ b/libavutil/hwcontext_dxva2.h
> > > > > @@ -38,6 +38,10 @@
> > > > >   */
> > > > >  typedef struct AVDXVA2DeviceContext {
> > > > >      IDirect3DDeviceManager9 *devmgr;
> > > > > +    /**
> > > > > +     * The string for the used adapter
> > > > > +     */
> > > > > +    char *device_name;
> > > > >  } AVDXVA2DeviceContext;
> > > > >
> > > > >  /**
> > > >
> > > > Why are these device names required? I would think deriving a child
> > > > device would use the actual device, eg. ID3D11Device or
> > > > IDirect3DDeviceManager9 (and whatever for VAAPI), and not some string
> > > > (that may or may not even be set).
> > > > It feels quite a bit icky to store these in the context just for qsv
> > > > to do... what with?
> > >
> > > Yes, it is a little ugly here. MediaSDK or oneVPL application creates mfx
> > > session and the device (dxva2, d3d11va or vaapi), then pass this device to
> > > the
> > > SDK through MFXVideoCORE_SetHandle(). implementation is introduced in oneVPL
> > > (
> > >
> https://spec.oneapi.io/versions/latest/elements/oneVPL/source/API_ref/VPL_disp_api_struct.html#structmfx_impl_description
> > > ) and user must select an available implementation before the creation of
> > > mfx
> > > session, however the device handle is unknown in the SDK when selecting an
> > > available implementation, the SDK provides a method to select implementation
> > > via
> > > the given adapter (on Windows) or DRI device node (on Linux). The default
> > > implementation will be selected if child device name is unknown.
> > >
> >
> > First of all, whoever made that API should get a stern message.
> > Expecting to properly interoperate with the dominant platform APIs
> > should be a primary goal, and it sounds like it was somehow shoehorned
> > in after the fact.
> >
> > For D3D11 for example, you can get the IDXGIAdapter a device was
> > created from, isn't there enough information in there to pass-on
> > without storing a string field?
> > IDXGIAdapter::GetDesc has tons of identification information to
> > identify the device in use.
> >
> > D3D9 probably has something similar, haven't checked right now.
>
>
> Thanks for the info, I may get AdapterLuid from the adapter description, however
> the required parameter in oneVPL is the index of the adapter, is there a way to
> map AdapterLuid to adapter index ? (Sorry for this dumb question)
>
> There is `IDirect3DDeviceManager9 *devmgr` only in AVDXVA2DeviceContext for
> D3D9, it seems we have to add other members to get adapter description.
>
> As for vaapi, there is no API to get the used DRI device from VADisplay handle,
> we have to store this info in AVVAAPIDeviceContext, and I prefer using the same
> way for d3d9 & d3d11va too.
>

I'm not sure about VAAPI, but not storing a string just for this one
purpose seems like a win to me.
What values would
mfxImplDescription.mfxDeviceDescription.device.DeviceID contain, and
would that perhaps match something in the D3D11 or DXVA2 device
description?

You already have big alternate pathes inside those functions for
windows or vaapi, so that doesn't seem like a big step to handle
separately.

- Hendrik
Xiang, Haihao April 6, 2022, 3:58 a.m. UTC | #6
On Mon, 2022-04-04 at 11:46 +0200, Hendrik Leppkes wrote:
> On Tue, Mar 15, 2022 at 8:24 AM Xiang, Haihao
> <haihao.xiang-at-intel.com@ffmpeg.org> wrote:
> > 
> > On Fri, 2022-03-11 at 15:00 +0100, Hendrik Leppkes wrote:
> > > On Fri, Mar 11, 2022 at 2:43 PM Xiang, Haihao
> > > <haihao.xiang-at-intel.com@ffmpeg.org> wrote:
> > > > 
> > > > On Fri, 2022-03-11 at 09:35 +0100, Hendrik Leppkes wrote:
> > > > > On Fri, Mar 11, 2022 at 9:18 AM Xiang, Haihao
> > > > > <haihao.xiang-at-intel.com@ffmpeg.org> wrote:
> > > > > > diff --git a/libavutil/hwcontext_d3d11va.c
> > > > > > b/libavutil/hwcontext_d3d11va.c
> > > > > > index 8ab96bad25..e0e820f164 100644
> > > > > > --- a/libavutil/hwcontext_d3d11va.c
> > > > > > +++ b/libavutil/hwcontext_d3d11va.c
> > > > > > @@ -525,6 +525,13 @@ static void
> > > > > > d3d11va_device_uninit(AVHWDeviceContext
> > > > > > *hwdev)
> > > > > >      }
> > > > > >  }
> > > > > > 
> > > > > > +static void d3d11va_device_free(AVHWDeviceContext *ctx)
> > > > > > +{
> > > > > > +    AVD3D11VADeviceContext *hwctx = ctx->hwctx;
> > > > > > +
> > > > > > +    av_free(hwctx->device_name);
> > > > > > +}
> > > > > > +
> > > > > >  static int d3d11va_device_create(AVHWDeviceContext *ctx, const char
> > > > > > *device,
> > > > > >                                   AVDictionary *opts, int flags)
> > > > > >  {
> > > > > > @@ -537,6 +544,8 @@ static int
> > > > > > d3d11va_device_create(AVHWDeviceContext
> > > > > > *ctx,
> > > > > > const char *device,
> > > > > >      int is_debug       = !!av_dict_get(opts, "debug", NULL, 0);
> > > > > >      int ret;
> > > > > > 
> > > > > > +    ctx->free = d3d11va_device_free;
> > > > > > +
> > > > > >      // (On UWP we can't check this.)
> > > > > >  #if !HAVE_UWP
> > > > > >      if (!LoadLibrary("d3d11_1sdklayers.dll"))
> > > > > > @@ -561,6 +570,10 @@ static int
> > > > > > d3d11va_device_create(AVHWDeviceContext
> > > > > > *ctx, const char *device,
> > > > > >              if (FAILED(IDXGIFactory2_EnumAdapters(pDXGIFactory,
> > > > > > adapter,
> > > > > > &pAdapter)))
> > > > > >                  pAdapter = NULL;
> > > > > >              IDXGIFactory2_Release(pDXGIFactory);
> > > > > > +
> > > > > > +            device_hwctx->device_name = av_strdup(device);
> > > > > > +            if (!device_hwctx->device_name)
> > > > > > +                return AVERROR(ENOMEM);
> > > > > >          }
> > > > > >      }
> > > > > > 
> > > > > > diff --git a/libavutil/hwcontext_d3d11va.h
> > > > > > b/libavutil/hwcontext_d3d11va.h
> > > > > > index 77d2d72f1b..41a315b9e6 100644
> > > > > > --- a/libavutil/hwcontext_d3d11va.h
> > > > > > +++ b/libavutil/hwcontext_d3d11va.h
> > > > > > @@ -94,6 +94,11 @@ typedef struct AVD3D11VADeviceContext {
> > > > > >      void (*lock)(void *lock_ctx);
> > > > > >      void (*unlock)(void *lock_ctx);
> > > > > >      void *lock_ctx;
> > > > > > +
> > > > > > +    /**
> > > > > > +     * The string for the used adapter
> > > > > > +     */
> > > > > > +    char *device_name;
> > > > > >  } AVD3D11VADeviceContext;
> > > > > > 
> > > > > >  /**
> > > > > > diff --git a/libavutil/hwcontext_dxva2.c
> > > > > > b/libavutil/hwcontext_dxva2.c
> > > > > > index 53d00fa815..6967357093 100644
> > > > > > --- a/libavutil/hwcontext_dxva2.c
> > > > > > +++ b/libavutil/hwcontext_dxva2.c
> > > > > > @@ -431,6 +431,7 @@ static void dxva2_device_free(AVHWDeviceContext
> > > > > > *ctx)
> > > > > >          dlclose(priv->dxva2lib);
> > > > > > 
> > > > > >      av_freep(&ctx->user_opaque);
> > > > > > +    av_free(hwctx->device_name);
> > > > > >  }
> > > > > > 
> > > > > >  static int dxva2_device_create9(AVHWDeviceContext *ctx, UINT
> > > > > > adapter)
> > > > > > @@ -571,6 +572,13 @@ static int
> > > > > > dxva2_device_create(AVHWDeviceContext
> > > > > > *ctx,
> > > > > > const char *device,
> > > > > >          return AVERROR_UNKNOWN;
> > > > > >      }
> > > > > > 
> > > > > > +    if (device) {
> > > > > > +        hwctx->device_name = av_strdup(device);
> > > > > > +
> > > > > > +        if (!hwctx->device_name)
> > > > > > +            return AVERROR(ENOMEM);
> > > > > > +    }
> > > > > > +
> > > > > >      return 0;
> > > > > >  }
> > > > > > 
> > > > > > diff --git a/libavutil/hwcontext_dxva2.h
> > > > > > b/libavutil/hwcontext_dxva2.h
> > > > > > index e1b79bc0de..253ddbed51 100644
> > > > > > --- a/libavutil/hwcontext_dxva2.h
> > > > > > +++ b/libavutil/hwcontext_dxva2.h
> > > > > > @@ -38,6 +38,10 @@
> > > > > >   */
> > > > > >  typedef struct AVDXVA2DeviceContext {
> > > > > >      IDirect3DDeviceManager9 *devmgr;
> > > > > > +    /**
> > > > > > +     * The string for the used adapter
> > > > > > +     */
> > > > > > +    char *device_name;
> > > > > >  } AVDXVA2DeviceContext;
> > > > > > 
> > > > > >  /**
> > > > > 
> > > > > Why are these device names required? I would think deriving a child
> > > > > device would use the actual device, eg. ID3D11Device or
> > > > > IDirect3DDeviceManager9 (and whatever for VAAPI), and not some string
> > > > > (that may or may not even be set).
> > > > > It feels quite a bit icky to store these in the context just for qsv
> > > > > to do... what with?
> > > > 
> > > > Yes, it is a little ugly here. MediaSDK or oneVPL application creates
> > > > mfx
> > > > session and the device (dxva2, d3d11va or vaapi), then pass this device
> > > > to
> > > > the
> > > > SDK through MFXVideoCORE_SetHandle(). implementation is introduced in
> > > > oneVPL
> > > > (
> > > > 
> > 
> > 
https://spec.oneapi.io/versions/latest/elements/oneVPL/source/API_ref/VPL_disp_api_struct.html#structmfx_impl_description
> > > > ) and user must select an available implementation before the creation
> > > > of
> > > > mfx
> > > > session, however the device handle is unknown in the SDK when selecting
> > > > an
> > > > available implementation, the SDK provides a method to select
> > > > implementation
> > > > via
> > > > the given adapter (on Windows) or DRI device node (on Linux). The
> > > > default
> > > > implementation will be selected if child device name is unknown.
> > > > 
> > > 
> > > First of all, whoever made that API should get a stern message.
> > > Expecting to properly interoperate with the dominant platform APIs
> > > should be a primary goal, and it sounds like it was somehow shoehorned
> > > in after the fact.
> > > 
> > > For D3D11 for example, you can get the IDXGIAdapter a device was
> > > created from, isn't there enough information in there to pass-on
> > > without storing a string field?
> > > IDXGIAdapter::GetDesc has tons of identification information to
> > > identify the device in use.
> > > 
> > > D3D9 probably has something similar, haven't checked right now.
> > 
> > 
> > Thanks for the info, I may get AdapterLuid from the adapter description,
> > however
> > the required parameter in oneVPL is the index of the adapter, is there a way
> > to
> > map AdapterLuid to adapter index ? (Sorry for this dumb question)
> > 
> > There is `IDirect3DDeviceManager9 *devmgr` only in AVDXVA2DeviceContext for
> > D3D9, it seems we have to add other members to get adapter description.
> > 
> > As for vaapi, there is no API to get the used DRI device from VADisplay
> > handle,
> > we have to store this info in AVVAAPIDeviceContext, and I prefer using the
> > same
> > way for d3d9 & d3d11va too.
> > 
> 
> I'm not sure about VAAPI, but not storing a string just for this one
> purpose seems like a win to me.
> What values would
> mfxImplDescription.mfxDeviceDescription.device.DeviceID contain, and
> would that perhaps match something in the D3D11 or DXVA2 device
> description?
> 
> You already have big alternate pathes inside those functions for
> windows or vaapi, so that doesn't seem like a big step to handle
> separately.

Thanks, I will try other members in mfxImplDescription and update you whether it
is doable.

BRs
Haihao
Xiang, Haihao April 28, 2022, 9:31 a.m. UTC | #7
On Wed, 2022-04-06 at 03:58 +0000, Xiang, Haihao wrote:

[...]
> > > 
> > > 
> 
> 
https://spec.oneapi.io/versions/latest/elements/oneVPL/source/API_ref/VPL_disp_api_struct.html#structmfx_impl_description
> > > > > ) and user must select an available implementation before the creation
> > > > > of
> > > > > mfx
> > > > > session, however the device handle is unknown in the SDK when
> > > > > selecting
> > > > > an
> > > > > available implementation, the SDK provides a method to select
> > > > > implementation
> > > > > via
> > > > > the given adapter (on Windows) or DRI device node (on Linux). The
> > > > > default
> > > > > implementation will be selected if child device name is unknown.
> > > > > 
> > > > 
> > > > First of all, whoever made that API should get a stern message.
> > > > Expecting to properly interoperate with the dominant platform APIs
> > > > should be a primary goal, and it sounds like it was somehow shoehorned
> > > > in after the fact.
> > > > 
> > > > For D3D11 for example, you can get the IDXGIAdapter a device was
> > > > created from, isn't there enough information in there to pass-on
> > > > without storing a string field?
> > > > IDXGIAdapter::GetDesc has tons of identification information to
> > > > identify the device in use.
> > > > 
> > > > D3D9 probably has something similar, haven't checked right now.
> > > 
> > > 
> > > Thanks for the info, I may get AdapterLuid from the adapter description,
> > > however
> > > the required parameter in oneVPL is the index of the adapter, is there a
> > > way
> > > to
> > > map AdapterLuid to adapter index ? (Sorry for this dumb question)
> > > 
> > > There is `IDirect3DDeviceManager9 *devmgr` only in AVDXVA2DeviceContext
> > > for
> > > D3D9, it seems we have to add other members to get adapter description.
> > > 
> > > As for vaapi, there is no API to get the used DRI device from VADisplay
> > > handle,
> > > we have to store this info in AVVAAPIDeviceContext, and I prefer using the
> > > same
> > > way for d3d9 & d3d11va too.
> > > 
> > 
> > I'm not sure about VAAPI, but not storing a string just for this one
> > purpose seems like a win to me.
> > What values would
> > mfxImplDescription.mfxDeviceDescription.device.DeviceID contain, and
> > would that perhaps match something in the D3D11 or DXVA2 device
> > description?
> > 
> > You already have big alternate pathes inside those functions for
> > windows or vaapi, so that doesn't seem like a big step to handle
> > separately.
> 
> Thanks, I will try other members in mfxImplDescription and update you whether
> it
> is doable.


We updated the patch not to change AVD3D11VADeviceContext and
AVDXVA2DeviceContext. Could you take a look when you have time ?

https://ffmpeg.org/pipermail/ffmpeg-devel/2022-April/295760.html

Thanks
Haihao
diff mbox series

Patch

diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c
index c708964c80..0a0a42932f 100644
--- a/libavcodec/qsv.c
+++ b/libavcodec/qsv.c
@@ -47,6 +47,12 @@ 
 #include <mfxplugin.h>
 #endif
 
+#if QSV_ONEVPL
+#include <mfxdispatcher.h>
+#else
+#define MFXUnload(a) do { } while(0)
+#endif
+
 int ff_qsv_codec_id_to_mfx(enum AVCodecID codec_id)
 {
     switch (codec_id) {
@@ -403,6 +409,164 @@  static int ff_qsv_set_display_handle(AVCodecContext *avctx, QSVSession *qs)
 }
 #endif //AVCODEC_QSV_LINUX_SESSION_HANDLE
 
+#if QSV_ONEVPL
+
+static int qsv_create_mfx_session(AVCodecContext *avctx,
+                                  mfxIMPL implementation,
+                                  mfxVersion *pver,
+                                  int gpu_copy,
+                                  mfxSession *psession,
+                                  void **ploader)
+{
+    mfxStatus sts;
+    mfxLoader loader = NULL;
+    mfxSession session = NULL;
+    mfxConfig cfg;
+    mfxVariant impl_value;
+    uint32_t impl_idx = 0;
+
+    *psession = NULL;
+
+    /* Don't create a new MFX loader if the input loader is valid */
+    if (*ploader == NULL) {
+        av_log(avctx, AV_LOG_VERBOSE,
+               "Use Intel(R) oneVPL to create MFX session, the required "
+               "implementation version is %d.%d\n",
+               pver->Major, pver->Minor);
+
+        loader = MFXLoad();
+
+        if (!loader) {
+            av_log(avctx, AV_LOG_ERROR, "Error creating a MFX loader\n");
+            goto fail;
+        }
+
+        /* Create configurations for implementation */
+        cfg = MFXCreateConfig(loader);
+
+        if (!cfg) {
+            av_log(avctx, AV_LOG_ERROR, "Error creating a MFX configurations\n");
+            goto fail;
+        }
+
+        impl_value.Type = MFX_VARIANT_TYPE_U32;
+        impl_value.Data.U32 = (implementation == MFX_IMPL_SOFTWARE) ?
+            MFX_IMPL_TYPE_SOFTWARE : MFX_IMPL_TYPE_HARDWARE;
+        sts = MFXSetConfigFilterProperty(cfg,
+                                         (const mfxU8 *)"mfxImplDescription.Impl", impl_value);
+
+        if (sts != MFX_ERR_NONE) {
+            av_log(avctx, AV_LOG_ERROR, "Error adding a MFX configuration "
+                   "property: %d\n", sts);
+            goto fail;
+        }
+
+        impl_value.Type = MFX_VARIANT_TYPE_U32;
+        impl_value.Data.U32 = pver->Version;
+        sts = MFXSetConfigFilterProperty(cfg,
+                                         (const mfxU8 *)"mfxImplDescription.ApiVersion.Version",
+                                         impl_value);
+
+        if (sts != MFX_ERR_NONE) {
+            av_log(avctx, AV_LOG_ERROR, "Error adding a MFX configuration "
+                   "property: %d\n", sts);
+            goto fail;
+        }
+    } else {
+        av_log(avctx, AV_LOG_VERBOSE,
+               "Use Intel(R) oneVPL to create MFX session with the specified MFX loader\n");
+
+        loader = *ploader;
+    }
+
+    while (1) {
+        /* Enumerate all implementations */
+        mfxImplDescription *impl_desc;
+
+        sts = MFXEnumImplementations(loader, impl_idx,
+                                     MFX_IMPLCAPS_IMPLDESCSTRUCTURE,
+                                     (mfxHDL *)&impl_desc);
+
+        /* Failed to find an available implementation */
+        if (sts == MFX_ERR_NOT_FOUND)
+            break;
+        else if (sts != MFX_ERR_NONE) {
+            impl_idx++;
+            continue;
+        }
+
+        sts = MFXCreateSession(loader, impl_idx, &session);
+        MFXDispReleaseImplDescription(loader, impl_desc);
+
+        if (sts == MFX_ERR_NONE)
+            break;
+
+        impl_idx++;
+    }
+
+    if (sts != MFX_ERR_NONE) {
+        av_log(avctx, AV_LOG_ERROR, "Error creating a MFX session: %d.\n", sts);
+        goto fail;
+    }
+
+    *psession = session;
+
+    if (!*ploader)
+        *ploader = loader;
+
+    return 0;
+
+fail:
+    if (!*ploader && loader)
+        MFXUnload(loader);
+
+    return AVERROR_UNKNOWN;
+}
+
+#else
+
+static int qsv_create_mfx_session(AVCodecContext *avctx,
+                                  mfxIMPL implementation,
+                                  mfxVersion *pver,
+                                  int gpu_copy,
+                                  mfxSession *psession,
+                                  void **ploader)
+{
+    mfxInitParam init_par = { MFX_IMPL_AUTO_ANY };
+    mfxSession session = NULL;
+    mfxStatus sts;
+
+    av_log(avctx, AV_LOG_VERBOSE,
+           "Use Intel(R) Media SDK to create MFX session, the required "
+           "implementation version is %d.%d\n",
+           pver->Major, pver->Minor);
+
+    *psession = NULL;
+    *ploader = NULL;
+
+#if QSV_VERSION_ATLEAST(1, 16)
+    init_par.GPUCopy = gpu_copy;
+#endif
+    init_par.Implementation = implementation;
+    init_par.Version = *pver;
+    sts = MFXInitEx(init_par, &session);
+
+    if (sts < 0)
+        return ff_qsv_print_error(avctx, sts,
+                                  "Error initializing a MFX session");
+    else if (sts > 0) {
+        ff_qsv_print_warning(avctx, sts,
+                             "Warning in MFX initialization");
+        return AVERROR_UNKNOWN;
+    }
+
+    *psession = session;
+
+    return 0;
+}
+
+#endif
+
 int ff_qsv_init_internal_session(AVCodecContext *avctx, QSVSession *qs,
                                  const char *load_plugins, int gpu_copy)
 {
@@ -412,20 +576,13 @@  int ff_qsv_init_internal_session(AVCodecContext *avctx, QSVSession *qs,
     mfxIMPL          impl = MFX_IMPL_AUTO_ANY;
 #endif
     mfxVersion        ver = { { QSV_VERSION_MINOR, QSV_VERSION_MAJOR } };
-    mfxInitParam init_par = { MFX_IMPL_AUTO_ANY };
 
     const char *desc;
-    int ret;
+    int ret = qsv_create_mfx_session(avctx, impl, &ver, gpu_copy, &qs->session,
+                                     &qs->loader);
 
-#if QSV_VERSION_ATLEAST(1, 16)
-    init_par.GPUCopy        = gpu_copy;
-#endif
-    init_par.Implementation = impl;
-    init_par.Version        = ver;
-    ret = MFXInitEx(init_par, &qs->session);
-    if (ret < 0)
-        return ff_qsv_print_error(avctx, ret,
-                                  "Error initializing an internal MFX session");
+    if (ret)
+        return ret;
 
 #ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE
     ret = ff_qsv_set_display_handle(avctx, qs);
@@ -729,7 +886,7 @@  int ff_qsv_init_session_device(AVCodecContext *avctx, mfxSession *psession,
     AVHWDeviceContext    *device_ctx = (AVHWDeviceContext*)device_ref->data;
     AVQSVDeviceContext *device_hwctx = device_ctx->hwctx;
     mfxSession        parent_session = device_hwctx->session;
-    mfxInitParam            init_par = { MFX_IMPL_AUTO_ANY };
+    void                     *loader = device_hwctx->loader;
     mfxHDL                    handle = NULL;
     int          hw_handle_supported = 0;
 
@@ -770,15 +927,11 @@  int ff_qsv_init_session_device(AVCodecContext *avctx, mfxSession *psession,
                "from the session\n");
     }
 
-#if QSV_VERSION_ATLEAST(1, 16)
-    init_par.GPUCopy        = gpu_copy;
-#endif
-    init_par.Implementation = impl;
-    init_par.Version        = ver;
-    err = MFXInitEx(init_par, &session);
-    if (err != MFX_ERR_NONE)
-        return ff_qsv_print_error(avctx, err,
-                                  "Error initializing a child MFX session");
+    ret = qsv_create_mfx_session(avctx, impl, &ver, gpu_copy, &session,
+                                 &loader);
+
+    if (ret)
+        return ret;
 
     if (handle) {
         err = MFXVideoCORE_SetHandle(session, handle_type, handle);
@@ -855,7 +1008,9 @@  int ff_qsv_close_internal_session(QSVSession *qs)
 {
     if (qs->session) {
         MFXClose(qs->session);
+        MFXUnload(qs->loader);
         qs->session = NULL;
+        qs->loader = NULL;
     }
 #ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE
     av_buffer_unref(&qs->va_device_ref);
diff --git a/libavcodec/qsv_internal.h b/libavcodec/qsv_internal.h
index c788293286..09c915aeee 100644
--- a/libavcodec/qsv_internal.h
+++ b/libavcodec/qsv_internal.h
@@ -99,6 +99,7 @@  typedef struct QSVSession {
     AVBufferRef *va_device_ref;
     AVHWDeviceContext *va_device_ctx;
 #endif
+    void *loader;
 } QSVSession;
 
 typedef struct QSVFramesContext {
diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c
index 391e5d1c72..da0d691c4c 100644
--- a/libavcodec/qsvdec.c
+++ b/libavcodec/qsvdec.c
@@ -47,6 +47,12 @@ 
 #include "qsv.h"
 #include "qsv_internal.h"
 
+#if QSV_ONEVPL
+#include <mfxdispatcher.h>
+#else
+#define MFXUnload(a) do { } while(0)
+#endif
+
 static const AVRational mfx_tb = { 1, 90000 };
 
 #define PTS_TO_MFX_PTS(pts, pts_tb) ((pts) == AV_NOPTS_VALUE ? \
@@ -168,7 +174,9 @@  static int qsv_init_session(AVCodecContext *avctx, QSVContext *q, mfxSession ses
     } else if (hw_frames_ref) {
         if (q->internal_qs.session) {
             MFXClose(q->internal_qs.session);
+            MFXUnload(q->internal_qs.loader);
             q->internal_qs.session = NULL;
+            q->internal_qs.loader = NULL;
         }
         av_buffer_unref(&q->frames_ctx.hw_frames_ctx);
 
@@ -193,7 +201,9 @@  static int qsv_init_session(AVCodecContext *avctx, QSVContext *q, mfxSession ses
     } else if (hw_device_ref) {
         if (q->internal_qs.session) {
             MFXClose(q->internal_qs.session);
+            MFXUnload(q->internal_qs.loader);
             q->internal_qs.session = NULL;
+            q->internal_qs.loader = NULL;
         }
 
         ret = ff_qsv_init_session_device(avctx, &q->internal_qs.session,
diff --git a/libavcodec/qsvenc.h b/libavcodec/qsvenc.h
index 8be00d43f7..7fec3ca322 100644
--- a/libavcodec/qsvenc.h
+++ b/libavcodec/qsvenc.h
@@ -28,6 +28,9 @@ 
 
 #include <mfxvideo.h>
 
+#include "libavutil/common.h"
+#include "libavutil/hwcontext.h"
+#include "libavutil/hwcontext_qsv.h"
 #include "libavutil/avutil.h"
 #include "libavutil/fifo.h"
 
diff --git a/libavcodec/qsvenc_h264.c b/libavcodec/qsvenc_h264.c
index 7c6f3a530c..fed6cf420e 100644
--- a/libavcodec/qsvenc_h264.c
+++ b/libavcodec/qsvenc_h264.c
@@ -32,7 +32,6 @@ 
 #include "avcodec.h"
 #include "internal.h"
 #include "qsv.h"
-#include "qsv_internal.h"
 #include "qsvenc.h"
 #include "atsc_a53.h"
 
diff --git a/libavcodec/qsvenc_hevc.c b/libavcodec/qsvenc_hevc.c
index e383caf238..7a37db52d6 100644
--- a/libavcodec/qsvenc_hevc.c
+++ b/libavcodec/qsvenc_hevc.c
@@ -35,7 +35,6 @@ 
 #include "h2645_parse.h"
 #include "internal.h"
 #include "qsv.h"
-#include "qsv_internal.h"
 #include "qsvenc.h"
 
 enum LoadPlugin {
diff --git a/libavcodec/qsvenc_jpeg.c b/libavcodec/qsvenc_jpeg.c
index ad8f09befe..f473b1ddbc 100644
--- a/libavcodec/qsvenc_jpeg.c
+++ b/libavcodec/qsvenc_jpeg.c
@@ -30,7 +30,6 @@ 
 #include "avcodec.h"
 #include "internal.h"
 #include "qsv.h"
-#include "qsv_internal.h"
 #include "qsvenc.h"
 
 typedef struct QSVMJPEGEncContext {
diff --git a/libavcodec/qsvenc_mpeg2.c b/libavcodec/qsvenc_mpeg2.c
index 610bbf79c1..0e2a51811c 100644
--- a/libavcodec/qsvenc_mpeg2.c
+++ b/libavcodec/qsvenc_mpeg2.c
@@ -30,7 +30,6 @@ 
 #include "avcodec.h"
 #include "internal.h"
 #include "qsv.h"
-#include "qsv_internal.h"
 #include "qsvenc.h"
 
 typedef struct QSVMpeg2EncContext {
diff --git a/libavcodec/qsvenc_vp9.c b/libavcodec/qsvenc_vp9.c
index 5a0c04481d..aa58ea9540 100644
--- a/libavcodec/qsvenc_vp9.c
+++ b/libavcodec/qsvenc_vp9.c
@@ -30,7 +30,6 @@ 
 #include "avcodec.h"
 #include "internal.h"
 #include "qsv.h"
-#include "qsv_internal.h"
 #include "qsvenc.h"
 
 typedef struct QSVVP9EncContext {
diff --git a/libavfilter/qsvvpp.c b/libavfilter/qsvvpp.c
index 3f984fd5f9..bc87f316aa 100644
--- a/libavfilter/qsvvpp.c
+++ b/libavfilter/qsvvpp.c
@@ -23,8 +23,6 @@ 
 
 #include "libavutil/common.h"
 #include "libavutil/mathematics.h"
-#include "libavutil/hwcontext.h"
-#include "libavutil/hwcontext_qsv.h"
 #include "libavutil/time.h"
 #include "libavutil/pixdesc.h"
 
@@ -32,6 +30,12 @@ 
 #include "qsvvpp.h"
 #include "video.h"
 
+#if QSV_ONEVPL
+#include <mfxdispatcher.h>
+#else
+#define MFXUnload(a) do { } while(0)
+#endif
+
 #define IS_VIDEO_MEMORY(mode)  (mode & (MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET | \
                                         MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET))
 #if QSV_HAVE_OPAQUE
@@ -614,13 +618,11 @@  static int init_vpp_session(AVFilterContext *avctx, QSVVPPContext *s)
     }
 
     /* create a "slave" session with those same properties, to be used for vpp */
-    ret = MFXInit(impl, &ver, &s->session);
-    if (ret < 0)
-        return ff_qsvvpp_print_error(avctx, ret, "Error initializing a session");
-    else if (ret > 0) {
-        ff_qsvvpp_print_warning(avctx, ret, "Warning in session initialization");
-        return AVERROR_UNKNOWN;
-    }
+    ret = ff_qsvvpp_create_mfx_session(avctx, device_hwctx->loader, impl, &ver,
+                                       &s->session);
+
+    if (ret)
+        return ret;
 
     if (handle) {
         ret = MFXVideoCORE_SetHandle(s->session, handle_type, handle);
@@ -906,3 +908,96 @@  int ff_qsvvpp_filter_frame(QSVVPPContext *s, AVFilterLink *inlink, AVFrame *picr
 
     return 0;
 }
+
+#if QSV_ONEVPL
+
+int ff_qsvvpp_create_mfx_session(void *ctx,
+                                 void *loader,
+                                 mfxIMPL implementation,
+                                 mfxVersion *pver,
+                                 mfxSession *psession)
+{
+    mfxStatus sts;
+    mfxSession session = NULL;
+    uint32_t impl_idx = 0;
+
+    av_log(ctx, AV_LOG_VERBOSE,
+           "Use Intel(R) oneVPL to create MFX session with the specified MFX loader\n");
+
+    if (!loader) {
+        av_log(ctx, AV_LOG_ERROR, "Invalid MFX Loader handle\n");
+        return AVERROR(EINVAL);
+    }
+
+    while (1) {
+        /* Enumerate all implementations */
+        mfxImplDescription *impl_desc;
+
+        sts = MFXEnumImplementations(loader, impl_idx,
+                                     MFX_IMPLCAPS_IMPLDESCSTRUCTURE,
+                                     (mfxHDL *)&impl_desc);
+
+        /* Failed to find an available implementation */
+        if (sts == MFX_ERR_NOT_FOUND)
+            break;
+        else if (sts != MFX_ERR_NONE) {
+            impl_idx++;
+            continue;
+        }
+
+        sts = MFXCreateSession(loader, impl_idx, &session);
+        MFXDispReleaseImplDescription(loader, impl_desc);
+
+        if (sts == MFX_ERR_NONE)
+            break;
+
+        impl_idx++;
+    }
+
+    if (sts < 0)
+        return ff_qsvvpp_print_error(ctx, sts,
+                                     "Error creating a MFX session");
+    else if (sts > 0) {
+        ff_qsvvpp_print_warning(ctx, sts,
+                                "Warning in MFX session creation");
+        return AVERROR_UNKNOWN;
+    }
+
+    *psession = session;
+
+    return 0;
+}
+
+#else
+
+int ff_qsvvpp_create_mfx_session(void *ctx,
+                                 void *loader,
+                                 mfxIMPL implementation,
+                                 mfxVersion *pver,
+                                 mfxSession *psession)
+{
+    mfxSession session = NULL;
+    mfxStatus sts;
+
+    av_log(ctx, AV_LOG_VERBOSE,
+           "Use Intel(R) Media SDK to create MFX session, API version is "
+           "%d.%d, the required implementation version is %d.%d\n",
+           MFX_VERSION_MAJOR, MFX_VERSION_MINOR, pver->Major, pver->Minor);
+
+    *psession = NULL;
+    sts = MFXInit(implementation, pver, &session);
+
+    if (sts < 0)
+        return ff_qsvvpp_print_error(ctx, sts,
+                                     "Error initializing an MFX session");
+    else if (sts > 0) {
+        ff_qsvvpp_print_warning(ctx, sts, "Warning in MFX session initialization");
+        return AVERROR_UNKNOWN;
+    }
+
+    *psession = session;
+
+    return 0;
+}
+
+#endif
diff --git a/libavfilter/qsvvpp.h b/libavfilter/qsvvpp.h
index 3e7d56021b..a8cfcc565a 100644
--- a/libavfilter/qsvvpp.h
+++ b/libavfilter/qsvvpp.h
@@ -28,6 +28,8 @@ 
 
 #include "avfilter.h"
 #include "libavutil/fifo.h"
+#include "libavutil/hwcontext.h"
+#include "libavutil/hwcontext_qsv.h"
 
 #define FF_INLINK_IDX(link)  ((int)((link)->dstpad - (link)->dst->input_pads))
 #define FF_OUTLINK_IDX(link) ((int)((link)->srcpad - (link)->src->output_pads))
@@ -122,4 +124,7 @@  int ff_qsvvpp_print_error(void *log_ctx, mfxStatus err,
 int ff_qsvvpp_print_warning(void *log_ctx, mfxStatus err,
                             const char *warning_string);
 
+int ff_qsvvpp_create_mfx_session(void *ctx, void *loader, mfxIMPL implementation,
+                                 mfxVersion *pver, mfxSession *psession);
+
 #endif /* AVFILTER_QSVVPP_H */
diff --git a/libavfilter/vf_deinterlace_qsv.c b/libavfilter/vf_deinterlace_qsv.c
index 50f9156d14..4986873cbb 100644
--- a/libavfilter/vf_deinterlace_qsv.c
+++ b/libavfilter/vf_deinterlace_qsv.c
@@ -163,7 +163,7 @@  static int init_out_session(AVFilterContext *ctx)
     mfxIMPL impl;
     mfxVideoParam par;
     mfxStatus err;
-    int i;
+    int i, ret;
 
 #if QSV_HAVE_OPAQUE
     opaque = !!(hw_frames_hwctx->frame_type & MFX_MEMTYPE_OPAQUE_FRAME);
@@ -198,13 +198,11 @@  static int init_out_session(AVFilterContext *ctx)
 
     /* create a "slave" session with those same properties, to be used for
      * actual deinterlacing */
-    err = MFXInit(impl, &ver, &s->session);
-    if (err < 0)
-        return ff_qsvvpp_print_error(ctx, err, "Error initializing a session for deinterlacing");
-    else if (err > 0) {
-        ff_qsvvpp_print_warning(ctx, err, "Warning in session initialization");
-        return AVERROR_UNKNOWN;
-    }
+    ret = ff_qsvvpp_create_mfx_session(ctx, device_hwctx->loader, impl, &ver,
+                                       &s->session);
+
+    if (ret)
+        return ret;
 
     if (handle) {
         err = MFXVideoCORE_SetHandle(s->session, handle_type, handle);
diff --git a/libavfilter/vf_scale_qsv.c b/libavfilter/vf_scale_qsv.c
index 30434033d1..82a51ee837 100644
--- a/libavfilter/vf_scale_qsv.c
+++ b/libavfilter/vf_scale_qsv.c
@@ -281,7 +281,7 @@  static int init_out_session(AVFilterContext *ctx)
     mfxIMPL impl;
     mfxVideoParam par;
     mfxStatus err;
-    int i;
+    int i, ret;
 
 #if QSV_HAVE_OPAQUE
     opaque = !!(in_frames_hwctx->frame_type & MFX_MEMTYPE_OPAQUE_FRAME);
@@ -318,11 +318,11 @@  static int init_out_session(AVFilterContext *ctx)
 
     /* create a "slave" session with those same properties, to be used for
      * actual scaling */
-    err = MFXInit(impl, &ver, &s->session);
-    if (err != MFX_ERR_NONE) {
-        av_log(ctx, AV_LOG_ERROR, "Error initializing a session for scaling\n");
-        return AVERROR_UNKNOWN;
-    }
+    ret = ff_qsvvpp_create_mfx_session(ctx, device_hwctx->loader, impl, &ver,
+                                       &s->session);
+
+    if (ret)
+        return ret;
 
     if (handle) {
         err = MFXVideoCORE_SetHandle(s->session, handle_type, handle);
diff --git a/libavutil/hwcontext_d3d11va.c b/libavutil/hwcontext_d3d11va.c
index 8ab96bad25..e0e820f164 100644
--- a/libavutil/hwcontext_d3d11va.c
+++ b/libavutil/hwcontext_d3d11va.c
@@ -525,6 +525,13 @@  static void d3d11va_device_uninit(AVHWDeviceContext *hwdev)
     }
 }
 
+static void d3d11va_device_free(AVHWDeviceContext *ctx)
+{
+    AVD3D11VADeviceContext *hwctx = ctx->hwctx;
+
+    av_free(hwctx->device_name);
+}
+
 static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device,
                                  AVDictionary *opts, int flags)
 {
@@ -537,6 +544,8 @@  static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device,
     int is_debug       = !!av_dict_get(opts, "debug", NULL, 0);
     int ret;
 
+    ctx->free = d3d11va_device_free;
+
     // (On UWP we can't check this.)
 #if !HAVE_UWP
     if (!LoadLibrary("d3d11_1sdklayers.dll"))
@@ -561,6 +570,10 @@  static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device,
             if (FAILED(IDXGIFactory2_EnumAdapters(pDXGIFactory, adapter, &pAdapter)))
                 pAdapter = NULL;
             IDXGIFactory2_Release(pDXGIFactory);
+
+            device_hwctx->device_name = av_strdup(device);
+            if (!device_hwctx->device_name)
+                return AVERROR(ENOMEM);
         }
     }
 
diff --git a/libavutil/hwcontext_d3d11va.h b/libavutil/hwcontext_d3d11va.h
index 77d2d72f1b..41a315b9e6 100644
--- a/libavutil/hwcontext_d3d11va.h
+++ b/libavutil/hwcontext_d3d11va.h
@@ -94,6 +94,11 @@  typedef struct AVD3D11VADeviceContext {
     void (*lock)(void *lock_ctx);
     void (*unlock)(void *lock_ctx);
     void *lock_ctx;
+
+    /**
+     * The string for the used adapter
+     */
+    char *device_name;
 } AVD3D11VADeviceContext;
 
 /**
diff --git a/libavutil/hwcontext_dxva2.c b/libavutil/hwcontext_dxva2.c
index 53d00fa815..6967357093 100644
--- a/libavutil/hwcontext_dxva2.c
+++ b/libavutil/hwcontext_dxva2.c
@@ -431,6 +431,7 @@  static void dxva2_device_free(AVHWDeviceContext *ctx)
         dlclose(priv->dxva2lib);
 
     av_freep(&ctx->user_opaque);
+    av_free(hwctx->device_name);
 }
 
 static int dxva2_device_create9(AVHWDeviceContext *ctx, UINT adapter)
@@ -571,6 +572,13 @@  static int dxva2_device_create(AVHWDeviceContext *ctx, const char *device,
         return AVERROR_UNKNOWN;
     }
 
+    if (device) {
+        hwctx->device_name = av_strdup(device);
+
+        if (!hwctx->device_name)
+            return AVERROR(ENOMEM);
+    }
+
     return 0;
 }
 
diff --git a/libavutil/hwcontext_dxva2.h b/libavutil/hwcontext_dxva2.h
index e1b79bc0de..253ddbed51 100644
--- a/libavutil/hwcontext_dxva2.h
+++ b/libavutil/hwcontext_dxva2.h
@@ -38,6 +38,10 @@ 
  */
 typedef struct AVDXVA2DeviceContext {
     IDirect3DDeviceManager9 *devmgr;
+    /**
+     * The string for the used adapter
+     */
+    char *device_name;
 } AVDXVA2DeviceContext;
 
 /**
diff --git a/libavutil/hwcontext_qsv.c b/libavutil/hwcontext_qsv.c
index f5bdb84f52..b6cbdf264d 100644
--- a/libavutil/hwcontext_qsv.c
+++ b/libavutil/hwcontext_qsv.c
@@ -58,6 +58,12 @@ 
 #define QSV_ONEVPL       QSV_VERSION_ATLEAST(2, 0)
 #define QSV_HAVE_OPAQUE  !QSV_ONEVPL
 
+#if QSV_ONEVPL
+#include <mfxdispatcher.h>
+#else
+#define MFXUnload(a) do { } while(0)
+#endif
+
 typedef struct QSVDevicePriv {
     AVBufferRef *child_device_ctx;
 } QSVDevicePriv;
@@ -70,12 +76,15 @@  typedef struct QSVDeviceContext {
 
     enum AVHWDeviceType child_device_type;
     enum AVPixelFormat  child_pix_fmt;
+    char               *child_device;
 } QSVDeviceContext;
 
 typedef struct QSVFramesContext {
     mfxSession session_download;
+    void *loader_download;
     atomic_int session_download_init;
     mfxSession session_upload;
+    void *loader_upload;
     atomic_int session_upload_init;
 #if HAVE_PTHREADS
     pthread_mutex_t session_lock;
@@ -288,15 +297,19 @@  static void qsv_frames_uninit(AVHWFramesContext *ctx)
     if (s->session_download) {
         MFXVideoVPP_Close(s->session_download);
         MFXClose(s->session_download);
+        MFXUnload(s->loader_download);
     }
     s->session_download = NULL;
+    s->loader_download = NULL;
     s->session_download_init = 0;
 
     if (s->session_upload) {
         MFXVideoVPP_Close(s->session_upload);
         MFXClose(s->session_upload);
+        MFXUnload(s->loader_upload);
     }
     s->session_upload = NULL;
+    s->loader_upload = NULL;
     s->session_upload_init = 0;
 
 #if HAVE_PTHREADS
@@ -619,8 +632,265 @@  static mfxStatus frame_get_hdl(mfxHDL pthis, mfxMemId mid, mfxHDL *hdl)
     return MFX_ERR_NONE;
 }
 
+#if QSV_ONEVPL
+
+static int qsv_create_mfx_session(void *ctx,
+                                  mfxHandleType handle_type,
+                                  mfxIMPL implementation,
+                                  char *child_device,
+                                  mfxVersion *pver,
+                                  mfxSession *psession,
+                                  void **ploader)
+{
+    mfxStatus sts;
+    mfxLoader loader = NULL;
+    mfxSession session = NULL;
+    mfxConfig cfg;
+    mfxVersion ver;
+    mfxVariant impl_value;
+    uint32_t impl_idx = 0;
+
+    av_log(ctx, AV_LOG_VERBOSE,
+           "Use Intel(R) oneVPL to create MFX session, API version is "
+           "%d.%d, the required implementation version is %d.%d\n",
+           MFX_VERSION_MAJOR, MFX_VERSION_MINOR, pver->Major, pver->Minor);
+
+    if (handle_type != MFX_HANDLE_VA_DISPLAY &&
+        handle_type != MFX_HANDLE_D3D9_DEVICE_MANAGER &&
+        handle_type != MFX_HANDLE_D3D11_DEVICE) {
+        av_log(ctx, AV_LOG_ERROR,
+               "Invalid MFX device handle\n");
+        return AVERROR(EXDEV);
+    }
+
+    *psession = NULL;
+    *ploader = NULL;
+    loader = MFXLoad();
+
+    if (!loader) {
+        av_log(ctx, AV_LOG_ERROR, "Error creating a MFX loader\n");
+        goto fail;
+    }
+
+    /* Create configurations for implementation */
+    cfg = MFXCreateConfig(loader);
+
+    if (!cfg) {
+        av_log(ctx, AV_LOG_ERROR, "Error creating a MFX configuration\n");
+        goto fail;
+    }
+
+    impl_value.Type = MFX_VARIANT_TYPE_U32;
+    impl_value.Data.U32 = (implementation == MFX_IMPL_SOFTWARE) ?
+        MFX_IMPL_TYPE_SOFTWARE : MFX_IMPL_TYPE_HARDWARE;
+    sts = MFXSetConfigFilterProperty(cfg,
+                                     (const mfxU8 *)"mfxImplDescription.Impl", impl_value);
+
+    if (sts != MFX_ERR_NONE) {
+        av_log(ctx, AV_LOG_ERROR, "Error adding a MFX configuration "
+               "property: %d.\n", sts);
+        goto fail;
+    }
+
+    impl_value.Type = MFX_VARIANT_TYPE_U32;
+
+    if (MFX_HANDLE_VA_DISPLAY == handle_type)
+        impl_value.Data.U32 = MFX_ACCEL_MODE_VIA_VAAPI;
+    else if (MFX_HANDLE_D3D9_DEVICE_MANAGER == handle_type)
+        impl_value.Data.U32 = MFX_ACCEL_MODE_VIA_D3D9;
+    else
+        impl_value.Data.U32 = MFX_ACCEL_MODE_VIA_D3D11;
+
+    sts = MFXSetConfigFilterProperty(cfg,
+                                     (const mfxU8 *)"mfxImplDescription.AccelerationMode", impl_value);
+
+    if (sts != MFX_ERR_NONE) {
+        av_log(ctx, AV_LOG_ERROR, "Error adding a MFX configuration"
+               "MFX_ACCEL_MODE_VIA_D3D9 property: %d.\n", sts);
+        goto fail;
+    }
+
+    if (child_device) {
+        if ((MFX_HANDLE_D3D9_DEVICE_MANAGER == handle_type ||
+             MFX_HANDLE_D3D11_DEVICE == handle_type)) {
+            uint32_t idx = atoi(child_device);
+
+            impl_value.Type = MFX_VARIANT_TYPE_U32;
+            impl_value.Data.U32 = idx;
+            sts = MFXSetConfigFilterProperty(cfg,
+                                             (const mfxU8 *)"mfxImplDescription.VendorImplID", impl_value);
+
+            if (sts != MFX_ERR_NONE) {
+                av_log(ctx, AV_LOG_ERROR, "Error adding a MFX configuration"
+                       "VendorImplID property: %d.\n", sts);
+                goto fail;
+            }
+        } else {
+            uint32_t node;
+
+            if ((sscanf(child_device, "/dev/dri/renderD%d", &node) != 1) &&
+                (sscanf(child_device, "/dev/dri/card%d", &node) != 1)) {
+                av_log(ctx, AV_LOG_ERROR, "Invalid DRI device\n");
+                goto fail;
+            }
+
+            /* Use the corresponding render node to find the implementation for card0, card1, ... */
+            if (node < 128)
+                node += 128;
+
+            impl_value.Type = MFX_VARIANT_TYPE_U32;
+            impl_value.Data.U32 = node;
+            MFXSetConfigFilterProperty(cfg,
+                                       (const mfxU8 *)"mfxExtendedDeviceId.DRMRenderNodeNum", impl_value);
+
+            if (sts != MFX_ERR_NONE) {
+                av_log(ctx, AV_LOG_ERROR, "Error adding a MFX configuration"
+                       "DRMRenderNodeNum property: %d.\n", sts);
+                goto fail;
+            }
+        }
+    }
+
+    impl_value.Type = MFX_VARIANT_TYPE_U32;
+    impl_value.Data.U32 = pver->Version;
+    sts = MFXSetConfigFilterProperty(cfg,
+                                     (const mfxU8 *)"mfxImplDescription.ApiVersion.Version",
+                                     impl_value);
+
+    if (sts != MFX_ERR_NONE) {
+        av_log(ctx, AV_LOG_ERROR, "Error adding a MFX configuration "
+               "property: %d.\n", sts);
+        goto fail;
+    }
+
+    while (1) {
+        /* Enumerate all implementations */
+        mfxImplDescription *impl_desc;
+
+        sts = MFXEnumImplementations(loader, impl_idx,
+                                     MFX_IMPLCAPS_IMPLDESCSTRUCTURE,
+                                     (mfxHDL *)&impl_desc);
+
+        /* Failed to find an available implementation */
+        if (sts == MFX_ERR_NOT_FOUND)
+            break;
+        else if (sts != MFX_ERR_NONE) {
+            impl_idx++;
+            continue;
+        }
+
+        sts = MFXCreateSession(loader, impl_idx, &session);
+        MFXDispReleaseImplDescription(loader, impl_desc);
+
+        if (sts == MFX_ERR_NONE)
+            break;
+
+        impl_idx++;
+    }
+
+    if (sts != MFX_ERR_NONE) {
+        av_log(ctx, AV_LOG_ERROR, "Error creating a MFX session: %d.\n", sts);
+        goto fail;
+    }
+
+    sts = MFXQueryVersion(session, &ver);
+
+    if (sts != MFX_ERR_NONE) {
+        av_log(ctx, AV_LOG_ERROR, "Error querying a MFX session: %d.\n", sts);
+        goto fail;
+    }
+
+    av_log(ctx, AV_LOG_VERBOSE, "Initialize MFX session: implementation "
+           "version is %d.%d\n", ver.Major, ver.Minor);
+
+    *psession = session;
+    *ploader = loader;
+
+    return 0;
+
+fail:
+    if (session)
+        MFXClose(session);
+
+    MFXUnload(loader);
+
+    return AVERROR_UNKNOWN;
+}
+
+#else
+
+static int qsv_create_mfx_session(void *ctx,
+                                  mfxHandleType handle_type,
+                                  mfxIMPL implementation,
+                                  char *child_device,
+                                  mfxVersion *pver,
+                                  mfxSession *psession,
+                                  void **ploader)
+{
+    mfxVersion ver;
+    mfxStatus sts;
+    mfxSession session = NULL;
+
+    av_log(ctx, AV_LOG_VERBOSE,
+           "Use Intel(R) Media SDK to create MFX session, API version is "
+           "%d.%d, the required implementation version is %d.%d\n",
+           MFX_VERSION_MAJOR, MFX_VERSION_MINOR, pver->Major, pver->Minor);
+
+    if (handle_type != MFX_HANDLE_VA_DISPLAY &&
+        handle_type != MFX_HANDLE_D3D9_DEVICE_MANAGER &&
+        handle_type != MFX_HANDLE_D3D11_DEVICE) {
+        av_log(ctx, AV_LOG_ERROR,
+               "Invalid MFX device handle\n");
+        return AVERROR(EXDEV);
+    }
+
+    *ploader = NULL;
+    *psession = NULL;
+    ver = *pver;
+    sts = MFXInit(implementation, &ver, &session);
+
+    if (sts != MFX_ERR_NONE) {
+        av_log(ctx, AV_LOG_ERROR, "Error initializing an MFX session: "
+               "%d.\n", sts);
+        goto fail;
+    }
+
+    sts = MFXQueryVersion(session, &ver);
+
+    if (sts != MFX_ERR_NONE) {
+        av_log(ctx, AV_LOG_ERROR, "Error querying an MFX session: "
+               "%d.\n", sts);
+        goto fail;
+    }
+
+    av_log(ctx, AV_LOG_VERBOSE, "Initialize MFX session: implementation "
+           "version is %d.%d\n", ver.Major, ver.Minor);
+
+    MFXClose(session);
+    sts = MFXInit(implementation, &ver, &session);
+
+    if (sts != MFX_ERR_NONE) {
+        av_log(ctx, AV_LOG_ERROR, "Error initializing an MFX session: "
+               "%d.\n", sts);
+        goto fail;
+    }
+
+    *psession = session;
+
+    return 0;
+
+fail:
+    if (session)
+        MFXClose(session);
+
+    return AVERROR_UNKNOWN;
+}
+
+#endif
+
 static int qsv_init_internal_session(AVHWFramesContext *ctx,
-                                     mfxSession *session, int upload)
+                                     mfxSession *session, void **loader,
+                                     int upload)
 {
     AVQSVFramesContext *frames_hwctx = ctx->hwctx;
     QSVDeviceContext   *device_priv  = ctx->device_ctx->internal->priv;
@@ -637,29 +907,36 @@  static int qsv_init_internal_session(AVHWFramesContext *ctx,
 
     mfxVideoParam par;
     mfxStatus err;
+    int ret = AVERROR_UNKNOWN;
 
 #if QSV_HAVE_OPAQUE
     QSVFramesContext              *s = ctx->internal->priv;
     opaque = !!(frames_hwctx->frame_type & MFX_MEMTYPE_OPAQUE_FRAME);
 #endif
 
-    err = MFXInit(device_priv->impl, &device_priv->ver, session);
-    if (err != MFX_ERR_NONE) {
-        av_log(ctx, AV_LOG_ERROR, "Error initializing an internal session\n");
-        return AVERROR_UNKNOWN;
-    }
+    ret = qsv_create_mfx_session(ctx, device_priv->handle_type,
+                                 device_priv->impl, device_priv->child_device,
+                                 &device_priv->ver, session,
+                                 loader);
+
+    if (ret)
+        goto fail;
 
     if (device_priv->handle) {
         err = MFXVideoCORE_SetHandle(*session, device_priv->handle_type,
                                      device_priv->handle);
-        if (err != MFX_ERR_NONE)
-            return AVERROR_UNKNOWN;
+        if (err != MFX_ERR_NONE) {
+            ret = AVERROR_UNKNOWN;
+            goto fail;
+        }
     }
 
     if (!opaque) {
         err = MFXVideoCORE_SetFrameAllocator(*session, &frame_allocator);
-        if (err != MFX_ERR_NONE)
-            return AVERROR_UNKNOWN;
+        if (err != MFX_ERR_NONE) {
+            ret = AVERROR_UNKNOWN;
+            goto fail;
+        }
     }
 
     memset(&par, 0, sizeof(par));
@@ -695,11 +972,22 @@  static int qsv_init_internal_session(AVHWFramesContext *ctx,
     if (err != MFX_ERR_NONE) {
         av_log(ctx, AV_LOG_VERBOSE, "Error opening the internal VPP session."
                "Surface upload/download will not be possible\n");
-        MFXClose(*session);
-        *session = NULL;
+
+        ret = AVERROR_UNKNOWN;
+        goto fail;
     }
 
     return 0;
+
+fail:
+    if (*session)
+        MFXClose(*session);
+
+    MFXUnload(*loader);
+    *session = NULL;
+    *loader = NULL;
+
+    return ret;
 }
 
 static int qsv_frames_init(AVHWFramesContext *ctx)
@@ -764,6 +1052,9 @@  static int qsv_frames_init(AVHWFramesContext *ctx)
     s->session_download = NULL;
     s->session_upload   = NULL;
 
+    s->loader_download = NULL;
+    s->loader_upload = NULL;
+
     s->session_download_init = 0;
     s->session_upload_init   = 0;
 
@@ -1053,6 +1344,7 @@  static int qsv_internal_session_check_init(AVHWFramesContext *ctx, int upload)
     QSVFramesContext *s = ctx->internal->priv;
     atomic_int *inited  = upload ? &s->session_upload_init : &s->session_download_init;
     mfxSession *session = upload ? &s->session_upload      : &s->session_download;
+    void **loader       = upload ? &s->loader_upload       : &s->loader_download;
     int ret = 0;
 
     if (atomic_load(inited))
@@ -1063,7 +1355,7 @@  static int qsv_internal_session_check_init(AVHWFramesContext *ctx, int upload)
 #endif
 
     if (!atomic_load(inited)) {
-        ret = qsv_init_internal_session(ctx, session, upload);
+        ret = qsv_init_internal_session(ctx, session, loader, upload);
         atomic_store(inited, 1);
     }
 
@@ -1406,10 +1698,14 @@  static void qsv_device_free(AVHWDeviceContext *ctx)
 {
     AVQSVDeviceContext *hwctx = ctx->hwctx;
     QSVDevicePriv       *priv = ctx->user_opaque;
+    QSVDeviceContext *device_priv = ctx->internal->priv;
+
+    av_free(device_priv->child_device);
 
     if (hwctx->session)
         MFXClose(hwctx->session);
 
+    MFXUnload(hwctx->loader);
     av_buffer_unref(&priv->child_device_ctx);
     av_freep(&priv);
 }
@@ -1459,6 +1755,7 @@  static int qsv_device_derive_from_child(AVHWDeviceContext *ctx,
                                         int flags)
 {
     AVQSVDeviceContext *hwctx = ctx->hwctx;
+    char *child_device = NULL;
 
     mfxVersion    ver = { { 3, 1 } };
     mfxHDL        handle;
@@ -1473,6 +1770,7 @@  static int qsv_device_derive_from_child(AVHWDeviceContext *ctx,
             AVVAAPIDeviceContext *child_device_hwctx = child_device_ctx->hwctx;
             handle_type = MFX_HANDLE_VA_DISPLAY;
             handle = (mfxHDL)child_device_hwctx->display;
+            child_device = child_device_hwctx->device_name;
         }
         break;
 #endif
@@ -1482,6 +1780,7 @@  static int qsv_device_derive_from_child(AVHWDeviceContext *ctx,
             AVD3D11VADeviceContext *child_device_hwctx = child_device_ctx->hwctx;
             handle_type = MFX_HANDLE_D3D11_DEVICE;
             handle = (mfxHDL)child_device_hwctx->device;
+            child_device = child_device_hwctx->device_name;
         }
         break;
 #endif
@@ -1491,6 +1790,7 @@  static int qsv_device_derive_from_child(AVHWDeviceContext *ctx,
             AVDXVA2DeviceContext *child_device_hwctx = child_device_ctx->hwctx;
             handle_type = MFX_HANDLE_D3D9_DEVICE_MANAGER;
             handle = (mfxHDL)child_device_hwctx->devmgr;
+            child_device = child_device_hwctx->device_name;
         }
         break;
 #endif
@@ -1499,34 +1799,11 @@  static int qsv_device_derive_from_child(AVHWDeviceContext *ctx,
         goto fail;
     }
 
-    err = MFXInit(implementation, &ver, &hwctx->session);
-    if (err != MFX_ERR_NONE) {
-        av_log(ctx, AV_LOG_ERROR, "Error initializing an MFX session: "
-               "%d.\n", err);
-        ret = AVERROR_UNKNOWN;
-        goto fail;
-    }
+    ret = qsv_create_mfx_session(ctx, handle_type, implementation, child_device,
+                                 &ver, &hwctx->session, &hwctx->loader);
 
-    err = MFXQueryVersion(hwctx->session, &ver);
-    if (err != MFX_ERR_NONE) {
-        av_log(ctx, AV_LOG_ERROR, "Error querying an MFX session: %d.\n", err);
-        ret = AVERROR_UNKNOWN;
+    if (ret)
         goto fail;
-    }
-
-    av_log(ctx, AV_LOG_VERBOSE,
-           "Initialize MFX session: API version is %d.%d, implementation version is %d.%d\n",
-           MFX_VERSION_MAJOR, MFX_VERSION_MINOR, ver.Major, ver.Minor);
-
-    MFXClose(hwctx->session);
-
-    err = MFXInit(implementation, &ver, &hwctx->session);
-    if (err != MFX_ERR_NONE) {
-        av_log(ctx, AV_LOG_ERROR,
-               "Error initializing an MFX session: %d.\n", err);
-        ret = AVERROR_UNKNOWN;
-        goto fail;
-    }
 
     err = MFXVideoCORE_SetHandle(hwctx->session, handle_type, handle);
     if (err != MFX_ERR_NONE) {
@@ -1541,6 +1818,8 @@  static int qsv_device_derive_from_child(AVHWDeviceContext *ctx,
 fail:
     if (hwctx->session)
         MFXClose(hwctx->session);
+
+    MFXUnload(hwctx->loader);
     return ret;
 }
 
@@ -1562,6 +1841,7 @@  static int qsv_device_create(AVHWDeviceContext *ctx, const char *device,
     AVHWDeviceContext *child_device;
     AVDictionary *child_device_opts;
     AVDictionaryEntry *e;
+    QSVDeviceContext *device_priv;
 
     mfxIMPL impl;
     int ret;
@@ -1583,6 +1863,16 @@  static int qsv_device_create(AVHWDeviceContext *ctx, const char *device,
         }
     } else if (CONFIG_VAAPI) {
         child_device_type = AV_HWDEVICE_TYPE_VAAPI;
+#if QSV_ONEVPL
+    } else if (CONFIG_D3D11VA) {  // Use D3D11 by default if d3d11va is enabled
+        av_log(NULL, AV_LOG_WARNING,
+               "WARNING: defaulting child_device_type to AV_HWDEVICE_TYPE_D3D11VA for "
+               "oneVPL. Please explicitly set child device type via \"-init_hw_device\" "
+               "option if needed.\n");
+        child_device_type = AV_HWDEVICE_TYPE_D3D11VA;
+    } else if (CONFIG_DXVA2) {
+        child_device_type = AV_HWDEVICE_TYPE_DXVA2;
+#else
     } else if (CONFIG_DXVA2) {
         av_log(NULL, AV_LOG_WARNING,
                 "WARNING: defaulting child_device_type to AV_HWDEVICE_TYPE_DXVA2 for compatibility "
@@ -1591,6 +1881,7 @@  static int qsv_device_create(AVHWDeviceContext *ctx, const char *device,
         child_device_type = AV_HWDEVICE_TYPE_DXVA2;
     } else if (CONFIG_D3D11VA) {
         child_device_type = AV_HWDEVICE_TYPE_D3D11VA;
+#endif
     } else {
         av_log(ctx, AV_LOG_ERROR, "No supported child device type is enabled\n");
         return AVERROR(ENOSYS);
@@ -1617,6 +1908,13 @@  static int qsv_device_create(AVHWDeviceContext *ctx, const char *device,
 #endif
 #if CONFIG_DXVA2
     case AV_HWDEVICE_TYPE_DXVA2:
+#if QSV_ONEVPL
+        {
+            av_log(NULL, AV_LOG_WARNING,
+                   "WARNING: d3d11va is not available or child device type is "
+                   "set to dxva2 explicitly for oneVPL.\n");
+        }
+#endif
         break;
 #endif
     default:
@@ -1627,7 +1925,17 @@  static int qsv_device_create(AVHWDeviceContext *ctx, const char *device,
         break;
     }
 
+    device_priv = ctx->internal->priv;
+    device_priv->child_device = NULL;
     e = av_dict_get(opts, "child_device", NULL, 0);
+
+    if (e) {
+        device_priv->child_device = av_strdup(e->value);
+
+        if (!device_priv->child_device)
+            return AVERROR(ENOMEM);
+    }
+
     ret = av_hwdevice_ctx_create(&priv->child_device_ctx, child_device_type,
                                  e ? e->value : NULL, child_device_opts, 0);
 
diff --git a/libavutil/hwcontext_qsv.h b/libavutil/hwcontext_qsv.h
index 42e34d0dda..2485daa899 100644
--- a/libavutil/hwcontext_qsv.h
+++ b/libavutil/hwcontext_qsv.h
@@ -34,6 +34,7 @@ 
  */
 typedef struct AVQSVDeviceContext {
     mfxSession session;
+    void      *loader;
 } AVQSVDeviceContext;
 
 /**
diff --git a/libavutil/hwcontext_vaapi.c b/libavutil/hwcontext_vaapi.c
index 994b744e4d..89fdefee68 100644
--- a/libavutil/hwcontext_vaapi.c
+++ b/libavutil/hwcontext_vaapi.c
@@ -1517,6 +1517,7 @@  static void vaapi_device_free(AVHWDeviceContext *ctx)
     if (priv->drm_fd >= 0)
         close(priv->drm_fd);
 
+    av_free(hwctx->device_name);
     av_freep(&priv);
 }
 
@@ -1565,6 +1566,7 @@  static int vaapi_device_connect(AVHWDeviceContext *ctx,
 static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
                                AVDictionary *opts, int flags)
 {
+    AVVAAPIDeviceContext *hwctx = ctx->hwctx;
     VAAPIDevicePriv *priv;
     VADisplay display = NULL;
     const AVDictionaryEntry *ent;
@@ -1610,6 +1612,11 @@  static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
                        "DRM device node.\n", device);
                 break;
             }
+
+            hwctx->device_name = av_strdup(device);
+
+            if (!hwctx->device_name)
+                return AVERROR(ENOMEM);
         } else {
             char path[64];
             int n, max_devices = 8;
@@ -1650,6 +1657,12 @@  static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
                     av_log(ctx, AV_LOG_VERBOSE, "Trying to use "
                            "DRM render node for device %d.\n", n);
                 }
+
+                hwctx->device_name = av_strdup(path);
+
+                if (!hwctx->device_name)
+                    return AVERROR(ENOMEM);
+
                 break;
             }
             if (n >= max_devices)
diff --git a/libavutil/hwcontext_vaapi.h b/libavutil/hwcontext_vaapi.h
index 0b2e071cb3..3e0b54f5e9 100644
--- a/libavutil/hwcontext_vaapi.h
+++ b/libavutil/hwcontext_vaapi.h
@@ -78,6 +78,10 @@  typedef struct AVVAAPIDeviceContext {
      * operations using VAAPI with the same VADisplay.
      */
     unsigned int driver_quirks;
+    /**
+     * The string for the used device
+     */
+    char *device_name;
 } AVVAAPIDeviceContext;
 
 /**