diff mbox series

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

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

Checks

Context Check Description
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished

Commit Message

Xiang, Haihao June 2, 2022, 3:41 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 config filters 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

TODO: Add a config filter for device on Linux when enumerating all of
available implementations once we may get the corresponding device info
via a VADisplay handle

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

Co-authored-by: galinart <artem.galin@intel.com>
Signed-off-by: galinart <artem.galin@intel.com>
---
 libavcodec/qsv.c                 | 191 ++++++++++--
 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_qsv.c        | 478 ++++++++++++++++++++++++++++---
 libavutil/hwcontext_qsv.h        |   1 +
 15 files changed, 749 insertions(+), 84 deletions(-)

Comments

Anton Khirnov June 13, 2022, 11:01 a.m. UTC | #1
Quoting Xiang, Haihao (2022-06-02 05:41:17)
> From: Haihao Xiang <haihao.xiang@intel.com>
> 
> In oneVPL, MFXLoad() and MFXCreateSession() are required to create a
> workable mfx session[1]
> 
> Add config filters 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
> 
> TODO: Add a config filter for device on Linux when enumerating all of
> available implementations once we may get the corresponding device info
> via a VADisplay handle
> 
> [1] https://spec.oneapi.io/versions/latest/elements/oneVPL/source/programming_guide/VPL_prg_session.html#onevpl-dispatcher
> 
> Co-authored-by: galinart <artem.galin@intel.com>
> Signed-off-by: galinart <artem.galin@intel.com>
> ---
>  libavcodec/qsv.c                 | 191 ++++++++++--
>  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_qsv.c        | 478 ++++++++++++++++++++++++++++---
>  libavutil/hwcontext_qsv.h        |   1 +

Could you please split the API changes into their own patch? That makes
this whole thing easier to understand and review.

> diff --git a/libavutil/hwcontext_qsv.c b/libavutil/hwcontext_qsv.c
> index 21a2a805f8..aaa62f0bcc 100644
> --- a/libavutil/hwcontext_qsv.c
> +++ b/libavutil/hwcontext_qsv.c
> +#if QSV_ONEVPL
> +
> +static int qsv_create_mfx_session(void *ctx,
> +                                  mfxHDL handle,
> +                                  mfxHandleType handle_type,
> +                                  mfxIMPL implementation,
> +                                  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);

Am I understanding correctly that this config object is attached to the
loader and owned/freed by it?
> +
> +    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"
> +               "AccelerationMode property: %d.\n", sts);
> +        goto fail;
> +    }
> +
> +    impl_value.Type = MFX_VARIANT_TYPE_U16;
> +    impl_value.Data.U16 = 0x8086;
> +    sts = MFXSetConfigFilterProperty(cfg,
> +                                     (const mfxU8 *)"mfxExtendedDeviceId.VendorID", impl_value);

Is it necessary to hardcode a specific vendor id?

> +
> +    if (sts != MFX_ERR_NONE) {
> +        av_log(ctx, AV_LOG_ERROR, "Error adding a MFX configuration"
> +               "VendorID property: %d.\n", sts);
> +        goto fail;
> +    }
> +
> +#if CONFIG_D3D11VA
> +    if (MFX_HANDLE_D3D11_DEVICE == handle_type) {
> +        if (handle) {

Why not merge the two conditions and save an indentation level?

> +            IDXGIAdapter* pDXGIAdapter;
> +            DXGI_ADAPTER_DESC adapterDesc;
> +            IDXGIDevice* pDXGIDevice = NULL;
> +            HRESULT hr;
> +            ID3D11Device* device = handle;
> +
> +            hr = ID3D11Device_QueryInterface(device, &IID_IDXGIDevice, (void**)&pDXGIDevice);
> +
> +            if (SUCCEEDED(hr)) {
> +                hr = IDXGIDevice_GetAdapter(pDXGIDevice, &pDXGIAdapter);
> +
> +                if (FAILED(hr)) {
> +                    av_log(ctx, AV_LOG_ERROR, "Error IDXGIDevice_GetAdapter %d\n", hr);
> +                    goto fail;
> +                }
> +
> +                hr = IDXGIAdapter_GetDesc(pDXGIAdapter, &adapterDesc);
> +
> +                if (FAILED(hr)) {
> +                    av_log(ctx, AV_LOG_ERROR, "Error IDXGIAdapter_GetDesc %d\n", hr);
> +                    goto fail;
> +                }
> +            } else {
> +                av_log(ctx, AV_LOG_ERROR, "Error ID3D11Device_QueryInterface %d\n", hr);
> +                goto fail;
> +            }
> +
> +            impl_value.Type = MFX_VARIANT_TYPE_U16;
> +            impl_value.Data.U16 = adapterDesc.DeviceId;
> +            sts = MFXSetConfigFilterProperty(cfg,
> +                                             (const mfxU8 *)"mfxExtendedDeviceId.DeviceID", impl_value);
> +
> +            if (sts != MFX_ERR_NONE) {
> +                av_log(ctx, AV_LOG_ERROR, "Error adding a MFX configuration"
> +                       "DeviceID property: %d.\n", sts);
> +                goto fail;
> +            }
> +
> +            impl_value.Type = MFX_VARIANT_TYPE_PTR;
> +            impl_value.Data.Ptr = &adapterDesc.AdapterLuid;
> +            sts = MFXSetConfigFilterProperty(cfg,
> +                                             (const mfxU8 *)"mfxExtendedDeviceId.DeviceLUID", impl_value);
> +
> +            if (sts != MFX_ERR_NONE) {
> +                av_log(ctx, AV_LOG_ERROR, "Error adding a MFX configuration"
> +                       "DeviceLUID property: %d.\n", sts);
> +                goto fail;
> +            }
> +
> +            impl_value.Type = MFX_VARIANT_TYPE_U32;
> +            impl_value.Data.U32 = 0x0001;
> +            sts = MFXSetConfigFilterProperty(cfg,
> +                                             (const mfxU8 *)"mfxExtendedDeviceId.LUIDDeviceNodeMask", impl_value);
> +
> +            if (sts != MFX_ERR_NONE) {
> +                av_log(ctx, AV_LOG_ERROR, "Error adding a MFX configuration"
> +                       "LUIDDeviceNodeMask property: %d.\n", sts);
> +                goto fail;
> +            }
> +        }
> +    }
> +#endif
> +#if CONFIG_DXVA2
> +    if (MFX_HANDLE_D3D9_DEVICE_MANAGER == handle_type) {
> +        if (handle) {
> +            IDirect3DDeviceManager9* devmgr = handle;
> +            IDirect3DDevice9Ex *device = NULL;
> +            HANDLE device_handle = 0;
> +            IDirect3D9Ex *d3d9ex = NULL;
> +            LUID luid;
> +            D3DDEVICE_CREATION_PARAMETERS params;
> +            HRESULT hr = IDirect3DDeviceManager9_OpenDeviceHandle(devmgr, &device_handle);
> +
> +            if (SUCCEEDED(hr)) {
> +                hr = IDirect3DDeviceManager9_LockDevice(devmgr, device_handle, &device, TRUE);
> +
> +                if (FAILED(hr)) {
> +                    av_log(ctx, AV_LOG_ERROR, "Error LockDevice %d\n", hr);
> +                    goto fail;
> +                }
> +
> +                hr = IDirect3DDevice9Ex_GetCreationParameters(device, &params);
> +
> +                if (FAILED(hr)) {
> +                    av_log(ctx, AV_LOG_ERROR, "Error IDirect3DDevice9_GetCreationParameters %d\n", hr);
> +                    IDirect3DDeviceManager9_UnlockDevice(devmgr, device_handle, FALSE);
> +                    goto fail;
> +                }
> +
> +                hr = IDirect3DDevice9Ex_GetDirect3D(device, &d3d9ex);
> +
> +                if (FAILED(hr)) {
> +                    av_log(ctx, AV_LOG_ERROR, "Error IDirect3DDevice9Ex_GetAdapterLUID %d\n", hr);
> +                    IDirect3DDeviceManager9_UnlockDevice(devmgr, device_handle, FALSE);
> +                    goto fail;
> +                }
> +
> +                hr = IDirect3D9Ex_GetAdapterLUID(d3d9ex, params.AdapterOrdinal, &luid);
> +
> +                if (FAILED(hr)) {
> +                    av_log(ctx, AV_LOG_ERROR, "Error IDirect3DDevice9Ex_GetAdapterLUID %d\n", hr);
> +                    IDirect3DDeviceManager9_UnlockDevice(devmgr, device_handle, FALSE);
> +                    goto fail;
> +                }
> +
> +                hr = IDirect3DDeviceManager9_UnlockDevice(devmgr, device_handle, FALSE);
> +
> +                if (FAILED(hr)) {
> +                    av_log(ctx, AV_LOG_ERROR, "Error IDirect3DDeviceManager9_UnlockDevice %d\n", hr);
> +                    goto fail;
> +                }
> +
> +                impl_value.Type = MFX_VARIANT_TYPE_PTR;
> +                impl_value.Data.Ptr = &luid;
> +                sts = MFXSetConfigFilterProperty(cfg,
> +                                                (const mfxU8 *)"mfxExtendedDeviceId.DeviceLUID", impl_value);
> +
> +                if (sts != MFX_ERR_NONE) {
> +                    av_log(ctx, AV_LOG_ERROR, "Error adding a MFX configuration"
> +                        "DeviceLUID property: %d.\n", sts);
> +                    goto fail;
> +                }
> +            } else {
> +                av_log(ctx, AV_LOG_ERROR, "Error OpenDeviceHandle %d\n", hr);
> +                goto fail;
> +            }
> +        }
> +    }

Move each of these blocks into their own functions, they are logically
separate and having them here makes qsv_create_mfx_session() absurdly
long and hard to read.

This will also allow you to deduplicate all those separate
IDirect3DDeviceManager9_UnlockDevice() calls.

> +#endif
> +#if CONFIG_VAAPI
> +    // TODO: add config filter for device
> +    // Without device info, oneVPL loads the default implementation which doesn't
> +    // matter on a single GPU. But on multiple GPUs, the default implementation might
> +    // not work with the given device. We'll add the config filter for device once we
> +    // can get device info via a VADisplay handle
> +    // if (MFX_HANDLE_VA_DISPLAY == handle_type) {

I think it'd be better to error out here if the handle is provided,
rather than opening something other than what the user requested.

> +    //
> +    // }
> +#endif
> +
> +    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++;
> +    }

This loop could also be a separate function.

> +#else
> +
> +static int qsv_create_mfx_session(void *ctx,
> +                                  mfxHDL handle,
> +                                  mfxHandleType handle_type,
> +                                  mfxIMPL implementation,
> +                                  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);
> +    }

Why is this check here? This function does not even do anything with
handle_type. Same in the other implementation.

> +
> +    *ploader = NULL;
> +    *psession = NULL;
> +    ver = *pver;
> +    sts = MFXInit(implementation, &ver, &session);
> +

nit: typically we have no empty lines between a function call and its
associated error check, there also wasn't one in the code you moved here

> @@ -764,6 +1162,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;
>  
> @@ -1063,6 +1464,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;

Do you actually need two separate loaders here? Can the main hwdevice
one be reused? I would expect it to not have any processing state.

> @@ -1629,6 +2011,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");

Any reason not to log to ctx? I know there's an existing av_log here
that logs to NULL, but IMO that is a bug and should be changes. Same for
the other log you're adding below.

Also, is there a strong reason to print a warning to all users?
Presumably if the user didn't specify a device type, they want the
default one, so this message could be verbose level.

> 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;

This should be documented - who sets and owns this, what are the API
users supposed to use this for.
Xiang, Haihao June 16, 2022, 2:58 p.m. UTC | #2
On Mon, 2022-06-13 at 13:01 +0200, Anton Khirnov wrote:
> Quoting Xiang, Haihao (2022-06-02 05:41:17)
> > From: Haihao Xiang <haihao.xiang@intel.com>
> > 
> > In oneVPL, MFXLoad() and MFXCreateSession() are required to create a
> > workable mfx session[1]
> > 
> > Add config filters 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
> > 
> > TODO: Add a config filter for device on Linux when enumerating all of
> > available implementations once we may get the corresponding device info
> > via a VADisplay handle
> > 
> > [1] 
> > https://spec.oneapi.io/versions/latest/elements/oneVPL/source/programming_guide/VPL_prg_session.html#onevpl-dispatcher
> > 
> > Co-authored-by: galinart <artem.galin@intel.com>
> > Signed-off-by: galinart <artem.galin@intel.com>
> > ---
> >  libavcodec/qsv.c                 | 191 ++++++++++--
> >  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_qsv.c        | 478 ++++++++++++++++++++++++++++---
> >  libavutil/hwcontext_qsv.h        |   1 +
> 
> Could you please split the API changes into their own patch? That makes
> this whole thing easier to understand and review.

Sure, I'll split this patch into smaller patches. 

> 
> > diff --git a/libavutil/hwcontext_qsv.c b/libavutil/hwcontext_qsv.c
> > index 21a2a805f8..aaa62f0bcc 100644
> > --- a/libavutil/hwcontext_qsv.c
> > +++ b/libavutil/hwcontext_qsv.c
> > +#if QSV_ONEVPL
> > +
> > +static int qsv_create_mfx_session(void *ctx,
> > +                                  mfxHDL handle,
> > +                                  mfxHandleType handle_type,
> > +                                  mfxIMPL implementation,
> > +                                  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);
> 
> Am I understanding correctly that this config object is attached to the
> loader and owned/freed by it?

Right

> > +
> > +    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"
> > +               "AccelerationMode property: %d.\n", sts);
> > +        goto fail;
> > +    }
> > +
> > +    impl_value.Type = MFX_VARIANT_TYPE_U16;
> > +    impl_value.Data.U16 = 0x8086;
> > +    sts = MFXSetConfigFilterProperty(cfg,
> > +                                     (const mfxU8
> > *)"mfxExtendedDeviceId.VendorID", impl_value);
> 
> Is it necessary to hardcode a specific vendor id?

It is used to ensure the implementation is the expected one. 
 
> 
> > +
> > +    if (sts != MFX_ERR_NONE) {
> > +        av_log(ctx, AV_LOG_ERROR, "Error adding a MFX configuration"
> > +               "VendorID property: %d.\n", sts);
> > +        goto fail;
> > +    }
> > +
> > +#if CONFIG_D3D11VA
> > +    if (MFX_HANDLE_D3D11_DEVICE == handle_type) {
> > +        if (handle) {
> 
> Why not merge the two conditions and save an indentation level?

I'll change it in the new version.

> 
> > +            IDXGIAdapter* pDXGIAdapter;
> > +            DXGI_ADAPTER_DESC adapterDesc;
> > +            IDXGIDevice* pDXGIDevice = NULL;
> > +            HRESULT hr;
> > +            ID3D11Device* device = handle;
> > +
> > +            hr = ID3D11Device_QueryInterface(device, &IID_IDXGIDevice,
> > (void**)&pDXGIDevice);
> > +
> > +            if (SUCCEEDED(hr)) {
> > +                hr = IDXGIDevice_GetAdapter(pDXGIDevice, &pDXGIAdapter);
> > +
> > +                if (FAILED(hr)) {
> > +                    av_log(ctx, AV_LOG_ERROR, "Error IDXGIDevice_GetAdapter
> > %d\n", hr);
> > +                    goto fail;
> > +                }
> > +
> > +                hr = IDXGIAdapter_GetDesc(pDXGIAdapter, &adapterDesc);
> > +
> > +                if (FAILED(hr)) {
> > +                    av_log(ctx, AV_LOG_ERROR, "Error IDXGIAdapter_GetDesc
> > %d\n", hr);
> > +                    goto fail;
> > +                }
> > +            } else {
> > +                av_log(ctx, AV_LOG_ERROR, "Error
> > ID3D11Device_QueryInterface %d\n", hr);
> > +                goto fail;
> > +            }
> > +
> > +            impl_value.Type = MFX_VARIANT_TYPE_U16;
> > +            impl_value.Data.U16 = adapterDesc.DeviceId;
> > +            sts = MFXSetConfigFilterProperty(cfg,
> > +                                             (const mfxU8
> > *)"mfxExtendedDeviceId.DeviceID", impl_value);
> > +
> > +            if (sts != MFX_ERR_NONE) {
> > +                av_log(ctx, AV_LOG_ERROR, "Error adding a MFX
> > configuration"
> > +                       "DeviceID property: %d.\n", sts);
> > +                goto fail;
> > +            }
> > +
> > +            impl_value.Type = MFX_VARIANT_TYPE_PTR;
> > +            impl_value.Data.Ptr = &adapterDesc.AdapterLuid;
> > +            sts = MFXSetConfigFilterProperty(cfg,
> > +                                             (const mfxU8
> > *)"mfxExtendedDeviceId.DeviceLUID", impl_value);
> > +
> > +            if (sts != MFX_ERR_NONE) {
> > +                av_log(ctx, AV_LOG_ERROR, "Error adding a MFX
> > configuration"
> > +                       "DeviceLUID property: %d.\n", sts);
> > +                goto fail;
> > +            }
> > +
> > +            impl_value.Type = MFX_VARIANT_TYPE_U32;
> > +            impl_value.Data.U32 = 0x0001;
> > +            sts = MFXSetConfigFilterProperty(cfg,
> > +                                             (const mfxU8
> > *)"mfxExtendedDeviceId.LUIDDeviceNodeMask", impl_value);
> > +
> > +            if (sts != MFX_ERR_NONE) {
> > +                av_log(ctx, AV_LOG_ERROR, "Error adding a MFX
> > configuration"
> > +                       "LUIDDeviceNodeMask property: %d.\n", sts);
> > +                goto fail;
> > +            }
> > +        }
> > +    }
> > +#endif
> > +#if CONFIG_DXVA2
> > +    if (MFX_HANDLE_D3D9_DEVICE_MANAGER == handle_type) {
> > +        if (handle) {
> > +            IDirect3DDeviceManager9* devmgr = handle;
> > +            IDirect3DDevice9Ex *device = NULL;
> > +            HANDLE device_handle = 0;
> > +            IDirect3D9Ex *d3d9ex = NULL;
> > +            LUID luid;
> > +            D3DDEVICE_CREATION_PARAMETERS params;
> > +            HRESULT hr = IDirect3DDeviceManager9_OpenDeviceHandle(devmgr,
> > &device_handle);
> > +
> > +            if (SUCCEEDED(hr)) {
> > +                hr = IDirect3DDeviceManager9_LockDevice(devmgr,
> > device_handle, &device, TRUE);
> > +
> > +                if (FAILED(hr)) {
> > +                    av_log(ctx, AV_LOG_ERROR, "Error LockDevice %d\n", hr);
> > +                    goto fail;
> > +                }
> > +
> > +                hr = IDirect3DDevice9Ex_GetCreationParameters(device,
> > &params);
> > +
> > +                if (FAILED(hr)) {
> > +                    av_log(ctx, AV_LOG_ERROR, "Error
> > IDirect3DDevice9_GetCreationParameters %d\n", hr);
> > +                    IDirect3DDeviceManager9_UnlockDevice(devmgr,
> > device_handle, FALSE);
> > +                    goto fail;
> > +                }
> > +
> > +                hr = IDirect3DDevice9Ex_GetDirect3D(device, &d3d9ex);
> > +
> > +                if (FAILED(hr)) {
> > +                    av_log(ctx, AV_LOG_ERROR, "Error
> > IDirect3DDevice9Ex_GetAdapterLUID %d\n", hr);
> > +                    IDirect3DDeviceManager9_UnlockDevice(devmgr,
> > device_handle, FALSE);
> > +                    goto fail;
> > +                }
> > +
> > +                hr = IDirect3D9Ex_GetAdapterLUID(d3d9ex,
> > params.AdapterOrdinal, &luid);
> > +
> > +                if (FAILED(hr)) {
> > +                    av_log(ctx, AV_LOG_ERROR, "Error
> > IDirect3DDevice9Ex_GetAdapterLUID %d\n", hr);
> > +                    IDirect3DDeviceManager9_UnlockDevice(devmgr,
> > device_handle, FALSE);
> > +                    goto fail;
> > +                }
> > +
> > +                hr = IDirect3DDeviceManager9_UnlockDevice(devmgr,
> > device_handle, FALSE);
> > +
> > +                if (FAILED(hr)) {
> > +                    av_log(ctx, AV_LOG_ERROR, "Error
> > IDirect3DDeviceManager9_UnlockDevice %d\n", hr);
> > +                    goto fail;
> > +                }
> > +
> > +                impl_value.Type = MFX_VARIANT_TYPE_PTR;
> > +                impl_value.Data.Ptr = &luid;
> > +                sts = MFXSetConfigFilterProperty(cfg,
> > +                                                (const mfxU8
> > *)"mfxExtendedDeviceId.DeviceLUID", impl_value);
> > +
> > +                if (sts != MFX_ERR_NONE) {
> > +                    av_log(ctx, AV_LOG_ERROR, "Error adding a MFX
> > configuration"
> > +                        "DeviceLUID property: %d.\n", sts);
> > +                    goto fail;
> > +                }
> > +            } else {
> > +                av_log(ctx, AV_LOG_ERROR, "Error OpenDeviceHandle %d\n",
> > hr);
> > +                goto fail;
> > +            }
> > +        }
> > +    }
> 
> Move each of these blocks into their own functions, they are logically
> separate and having them here makes qsv_create_mfx_session() absurdly
> long and hard to read.
> 
> This will also allow you to deduplicate all those separate
> IDirect3DDeviceManager9_UnlockDevice() calls.

Thanks, I'll follow your suggestion to change the code.
  
> 
> > +#endif
> > +#if CONFIG_VAAPI
> > +    // TODO: add config filter for device
> > +    // Without device info, oneVPL loads the default implementation which
> > doesn't
> > +    // matter on a single GPU. But on multiple GPUs, the default
> > implementation might
> > +    // not work with the given device. We'll add the config filter for
> > device once we
> > +    // can get device info via a VADisplay handle
> > +    // if (MFX_HANDLE_VA_DISPLAY == handle_type) {
> 
> I think it'd be better to error out here if the handle is provided,
> rather than opening something other than what the user requested.

I'm considering to use libva API to get the device info in the new version.

> 
> > +    //
> > +    // }
> > +#endif
> > +
> > +    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++;
> > +    }
> 
> This loop could also be a separate function.

Sure. 

> 
> > +#else
> > +
> > +static int qsv_create_mfx_session(void *ctx,
> > +                                  mfxHDL handle,
> > +                                  mfxHandleType handle_type,
> > +                                  mfxIMPL implementation,
> > +                                  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);
> > +    }
> 
> Why is this check here? This function does not even do anything with
> handle_type. Same in the other implementation.

I'll remove this redundant code.

> 
> > +
> > +    *ploader = NULL;
> > +    *psession = NULL;
> > +    ver = *pver;
> > +    sts = MFXInit(implementation, &ver, &session);
> > +
> 
> nit: typically we have no empty lines between a function call and its
> associated error check, there also wasn't one in the code you moved here
> 
> > @@ -764,6 +1162,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;
> >  
> > @@ -1063,6 +1464,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;
> 
> Do you actually need two separate loaders here? Can the main hwdevice
> one be reused? I would expect it to not have any processing state.

I'll try to use the main hwdevice one for download & upload. 

> 
> > @@ -1629,6 +2011,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");
> 
> Any reason not to log to ctx? I know there's an existing av_log here
> that logs to NULL, but IMO that is a bug and should be changes. Same for
> the other log you're adding below.
> 

Thanks for catching it, I'll use ctx instead NULL.

> Also, is there a strong reason to print a warning to all users?
> Presumably if the user didn't specify a device type, they want the
> default one, so this message could be verbose level.

User might want to use dxva2 but they don't know the default one is d3d11va for
oneVPL. I'm fine to use verbose level instead.
  
> 
> > 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;
> 
> This should be documented - who sets and owns this, what are the API
> users supposed to use this for.

Sure, I'll add some comments.

Many thanks for your careful review and suggestion!

-Haihao
diff mbox series

Patch

diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c
index 432675bccf..666d195c09 100644
--- a/libavcodec/qsv.c
+++ b/libavcodec/qsv.c
@@ -45,6 +45,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) {
@@ -419,6 +425,162 @@  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;
+
+    init_par.GPUCopy = gpu_copy;
+    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)
 {
@@ -428,18 +590,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);
 
-    init_par.GPUCopy        = gpu_copy;
-    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);
@@ -743,7 +900,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;
 
@@ -784,13 +941,11 @@  int ff_qsv_init_session_device(AVCodecContext *avctx, mfxSession *psession,
                "from the session\n");
     }
 
-    init_par.GPUCopy        = gpu_copy;
-    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);
@@ -867,7 +1022,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 5c26914b4c..d3e971562c 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 cd0a0f9cc1..e7f4848052 100644
--- a/libavcodec/qsvdec.c
+++ b/libavcodec/qsvdec.c
@@ -50,6 +50,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 ? \
@@ -177,7 +183,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);
 
@@ -202,7 +210,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 0ca69b1a8f..59c0a4c45a 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 a9d720822b..d09f58504c 100644
--- a/libavcodec/qsvenc_h264.c
+++ b/libavcodec/qsvenc_h264.c
@@ -32,7 +32,6 @@ 
 #include "avcodec.h"
 #include "codec_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 0dff0fe406..20101886b5 100644
--- a/libavcodec/qsvenc_hevc.c
+++ b/libavcodec/qsvenc_hevc.c
@@ -35,7 +35,6 @@ 
 #include "hevcdec.h"
 #include "h2645_parse.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 030b358d75..ca56989d23 100644
--- a/libavcodec/qsvenc_jpeg.c
+++ b/libavcodec/qsvenc_jpeg.c
@@ -30,7 +30,6 @@ 
 #include "avcodec.h"
 #include "codec_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 c68bf64231..6b7677148c 100644
--- a/libavcodec/qsvenc_mpeg2.c
+++ b/libavcodec/qsvenc_mpeg2.c
@@ -30,7 +30,6 @@ 
 #include "avcodec.h"
 #include "codec_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 9e96751828..81f5e69e24 100644
--- a/libavcodec/qsvenc_vp9.c
+++ b/libavcodec/qsvenc_vp9.c
@@ -30,7 +30,6 @@ 
 #include "avcodec.h"
 #include "codec_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 fa0152d785..97355ec056 100644
--- a/libavfilter/vf_scale_qsv.c
+++ b/libavfilter/vf_scale_qsv.c
@@ -278,7 +278,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);
@@ -315,11 +315,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_qsv.c b/libavutil/hwcontext_qsv.c
index 21a2a805f8..aaa62f0bcc 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;
@@ -74,8 +80,10 @@  typedef struct 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;
@@ -287,15 +295,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 +631,378 @@  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,
+                                  mfxHDL handle,
+                                  mfxHandleType handle_type,
+                                  mfxIMPL implementation,
+                                  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"
+               "AccelerationMode property: %d.\n", sts);
+        goto fail;
+    }
+
+    impl_value.Type = MFX_VARIANT_TYPE_U16;
+    impl_value.Data.U16 = 0x8086;
+    sts = MFXSetConfigFilterProperty(cfg,
+                                     (const mfxU8 *)"mfxExtendedDeviceId.VendorID", impl_value);
+
+    if (sts != MFX_ERR_NONE) {
+        av_log(ctx, AV_LOG_ERROR, "Error adding a MFX configuration"
+               "VendorID property: %d.\n", sts);
+        goto fail;
+    }
+
+#if CONFIG_D3D11VA
+    if (MFX_HANDLE_D3D11_DEVICE == handle_type) {
+        if (handle) {
+            IDXGIAdapter* pDXGIAdapter;
+            DXGI_ADAPTER_DESC adapterDesc;
+            IDXGIDevice* pDXGIDevice = NULL;
+            HRESULT hr;
+            ID3D11Device* device = handle;
+
+            hr = ID3D11Device_QueryInterface(device, &IID_IDXGIDevice, (void**)&pDXGIDevice);
+
+            if (SUCCEEDED(hr)) {
+                hr = IDXGIDevice_GetAdapter(pDXGIDevice, &pDXGIAdapter);
+
+                if (FAILED(hr)) {
+                    av_log(ctx, AV_LOG_ERROR, "Error IDXGIDevice_GetAdapter %d\n", hr);
+                    goto fail;
+                }
+
+                hr = IDXGIAdapter_GetDesc(pDXGIAdapter, &adapterDesc);
+
+                if (FAILED(hr)) {
+                    av_log(ctx, AV_LOG_ERROR, "Error IDXGIAdapter_GetDesc %d\n", hr);
+                    goto fail;
+                }
+            } else {
+                av_log(ctx, AV_LOG_ERROR, "Error ID3D11Device_QueryInterface %d\n", hr);
+                goto fail;
+            }
+
+            impl_value.Type = MFX_VARIANT_TYPE_U16;
+            impl_value.Data.U16 = adapterDesc.DeviceId;
+            sts = MFXSetConfigFilterProperty(cfg,
+                                             (const mfxU8 *)"mfxExtendedDeviceId.DeviceID", impl_value);
+
+            if (sts != MFX_ERR_NONE) {
+                av_log(ctx, AV_LOG_ERROR, "Error adding a MFX configuration"
+                       "DeviceID property: %d.\n", sts);
+                goto fail;
+            }
+
+            impl_value.Type = MFX_VARIANT_TYPE_PTR;
+            impl_value.Data.Ptr = &adapterDesc.AdapterLuid;
+            sts = MFXSetConfigFilterProperty(cfg,
+                                             (const mfxU8 *)"mfxExtendedDeviceId.DeviceLUID", impl_value);
+
+            if (sts != MFX_ERR_NONE) {
+                av_log(ctx, AV_LOG_ERROR, "Error adding a MFX configuration"
+                       "DeviceLUID property: %d.\n", sts);
+                goto fail;
+            }
+
+            impl_value.Type = MFX_VARIANT_TYPE_U32;
+            impl_value.Data.U32 = 0x0001;
+            sts = MFXSetConfigFilterProperty(cfg,
+                                             (const mfxU8 *)"mfxExtendedDeviceId.LUIDDeviceNodeMask", impl_value);
+
+            if (sts != MFX_ERR_NONE) {
+                av_log(ctx, AV_LOG_ERROR, "Error adding a MFX configuration"
+                       "LUIDDeviceNodeMask property: %d.\n", sts);
+                goto fail;
+            }
+        }
+    }
+#endif
+#if CONFIG_DXVA2
+    if (MFX_HANDLE_D3D9_DEVICE_MANAGER == handle_type) {
+        if (handle) {
+            IDirect3DDeviceManager9* devmgr = handle;
+            IDirect3DDevice9Ex *device = NULL;
+            HANDLE device_handle = 0;
+            IDirect3D9Ex *d3d9ex = NULL;
+            LUID luid;
+            D3DDEVICE_CREATION_PARAMETERS params;
+            HRESULT hr = IDirect3DDeviceManager9_OpenDeviceHandle(devmgr, &device_handle);
+
+            if (SUCCEEDED(hr)) {
+                hr = IDirect3DDeviceManager9_LockDevice(devmgr, device_handle, &device, TRUE);
+
+                if (FAILED(hr)) {
+                    av_log(ctx, AV_LOG_ERROR, "Error LockDevice %d\n", hr);
+                    goto fail;
+                }
+
+                hr = IDirect3DDevice9Ex_GetCreationParameters(device, &params);
+
+                if (FAILED(hr)) {
+                    av_log(ctx, AV_LOG_ERROR, "Error IDirect3DDevice9_GetCreationParameters %d\n", hr);
+                    IDirect3DDeviceManager9_UnlockDevice(devmgr, device_handle, FALSE);
+                    goto fail;
+                }
+
+                hr = IDirect3DDevice9Ex_GetDirect3D(device, &d3d9ex);
+
+                if (FAILED(hr)) {
+                    av_log(ctx, AV_LOG_ERROR, "Error IDirect3DDevice9Ex_GetAdapterLUID %d\n", hr);
+                    IDirect3DDeviceManager9_UnlockDevice(devmgr, device_handle, FALSE);
+                    goto fail;
+                }
+
+                hr = IDirect3D9Ex_GetAdapterLUID(d3d9ex, params.AdapterOrdinal, &luid);
+
+                if (FAILED(hr)) {
+                    av_log(ctx, AV_LOG_ERROR, "Error IDirect3DDevice9Ex_GetAdapterLUID %d\n", hr);
+                    IDirect3DDeviceManager9_UnlockDevice(devmgr, device_handle, FALSE);
+                    goto fail;
+                }
+
+                hr = IDirect3DDeviceManager9_UnlockDevice(devmgr, device_handle, FALSE);
+
+                if (FAILED(hr)) {
+                    av_log(ctx, AV_LOG_ERROR, "Error IDirect3DDeviceManager9_UnlockDevice %d\n", hr);
+                    goto fail;
+                }
+
+                impl_value.Type = MFX_VARIANT_TYPE_PTR;
+                impl_value.Data.Ptr = &luid;
+                sts = MFXSetConfigFilterProperty(cfg,
+                                                (const mfxU8 *)"mfxExtendedDeviceId.DeviceLUID", impl_value);
+
+                if (sts != MFX_ERR_NONE) {
+                    av_log(ctx, AV_LOG_ERROR, "Error adding a MFX configuration"
+                        "DeviceLUID property: %d.\n", sts);
+                    goto fail;
+                }
+            } else {
+                av_log(ctx, AV_LOG_ERROR, "Error OpenDeviceHandle %d\n", hr);
+                goto fail;
+            }
+        }
+    }
+#endif
+#if CONFIG_VAAPI
+    // TODO: add config filter for device
+    // Without device info, oneVPL loads the default implementation which doesn't
+    // matter on a single GPU. But on multiple GPUs, the default implementation might
+    // not work with the given device. We'll add the config filter for device once we
+    // can get device info via a VADisplay handle
+    // if (MFX_HANDLE_VA_DISPLAY == handle_type) {
+    //
+    // }
+#endif
+
+    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,
+                                  mfxHDL handle,
+                                  mfxHandleType handle_type,
+                                  mfxIMPL implementation,
+                                  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 +1019,34 @@  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, device_priv->handle_type,
+                                 device_priv->impl, &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 +1082,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 +1162,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;
 
@@ -1063,6 +1464,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))
@@ -1073,7 +1475,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);
     }
 
@@ -1456,6 +1858,7 @@  static void qsv_device_free(AVHWDeviceContext *ctx)
     if (hwctx->session)
         MFXClose(hwctx->session);
 
+    MFXUnload(hwctx->loader);
     av_buffer_unref(&priv->child_device_ctx);
     av_freep(&priv);
 }
@@ -1545,34 +1948,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;
-    }
-
-    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;
-        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);
+    ret = qsv_create_mfx_session(ctx, handle, handle_type, implementation, &ver,
+                                 &hwctx->session, &hwctx->loader);
 
-    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;
+    if (ret)
         goto fail;
-    }
 
     err = MFXVideoCORE_SetHandle(hwctx->session, handle_type, handle);
     if (err != MFX_ERR_NONE) {
@@ -1587,6 +1967,8 @@  static int qsv_device_derive_from_child(AVHWDeviceContext *ctx,
 fail:
     if (hwctx->session)
         MFXClose(hwctx->session);
+
+    MFXUnload(hwctx->loader);
     return ret;
 }
 
@@ -1629,6 +2011,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 "
@@ -1637,6 +2029,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);
@@ -1663,6 +2056,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:
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;
 
 /**