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

Haihao Xiang haihao.xiang at intel.com
Thu Apr 28 12:23:26 EEST 2022


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

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

Co-authored-by: galinart <artem.galin at intel.com>
Signed-off-by: galinart <artem.galin at 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    |   7 +
 libavutil/hwcontext_qsv.c        | 515 ++++++++++++++++++++++++++++---
 libavutil/hwcontext_qsv.h        |   1 +
 libavutil/hwcontext_vaapi.c      |  13 +
 libavutil/hwcontext_vaapi.h      |   4 +
 18 files changed, 812 insertions(+), 88 deletions(-)

diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c
index ad9f4df3f2..2892699728 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) {
@@ -439,6 +445,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)
 {
@@ -448,20 +612,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);
@@ -765,7 +922,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;
 
@@ -806,15 +963,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);
@@ -891,7 +1044,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 807633b473..ca3f7fee90 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 dfe5733856..c7c4578163 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 64209591bd..e269ff3a7b 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 d596c62346..7b956db556 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 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..fd5fedbdac 100644
--- a/libavutil/hwcontext_d3d11va.c
+++ b/libavutil/hwcontext_d3d11va.c
@@ -525,6 +525,11 @@ static void d3d11va_device_uninit(AVHWDeviceContext *hwdev)
     }
 }
 
+static void d3d11va_device_free(AVHWDeviceContext *ctx)
+{
+    AVD3D11VADeviceContext *hwctx = ctx->hwctx;
+}
+
 static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device,
                                  AVDictionary *opts, int flags)
 {
@@ -537,6 +542,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"))
diff --git a/libavutil/hwcontext_qsv.c b/libavutil/hwcontext_qsv.c
index f1b2970e68..e83e1c89a2 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;
@@ -289,15 +298,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
@@ -621,8 +634,396 @@ 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,
+                                  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"
+               "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;
+            }
+        }
+    } else
+#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;
+            }
+        }
+    } else
+#endif
+    if (MFX_HANDLE_VA_DISPLAY == handle_type) {
+        if (child_device) {
+            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,
+                                  mfxHDL handle,
+                                  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;
@@ -639,29 +1040,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, 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));
@@ -697,11 +1105,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)
@@ -766,6 +1185,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;
 
@@ -1055,6 +1477,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))
@@ -1065,7 +1488,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);
     }
 
@@ -1443,10 +1866,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);
 }
@@ -1496,6 +1923,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;
@@ -1510,6 +1938,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
@@ -1536,34 +1965,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, child_device,
+                                 &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) {
@@ -1578,6 +1984,8 @@ static int qsv_device_derive_from_child(AVHWDeviceContext *ctx,
 fail:
     if (hwctx->session)
         MFXClose(hwctx->session);
+
+    MFXUnload(hwctx->loader);
     return ret;
 }
 
@@ -1599,6 +2007,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;
@@ -1620,6 +2029,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 "
@@ -1628,6 +2047,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);
@@ -1654,6 +2074,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:
@@ -1664,7 +2091,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 c3a98bc4b1..cb714df934 100644
--- a/libavutil/hwcontext_vaapi.c
+++ b/libavutil/hwcontext_vaapi.c
@@ -1572,6 +1572,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);
 }
 
@@ -1620,6 +1621,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;
@@ -1665,6 +1667,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;
@@ -1705,6 +1712,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;
 
 /**
-- 
2.17.1



More information about the ffmpeg-devel mailing list