]> granicus.if.org Git - handbrake/commitdiff
qsv: d3d11 enabling
authoragalin89 <artem.galin@gmail.com>
Wed, 4 Sep 2019 12:17:40 +0000 (13:17 +0100)
committerScott <sr55.hb@outlook.com>
Sun, 22 Sep 2019 14:53:59 +0000 (15:53 +0100)
contrib/ffmpeg/A13-qsv-dx11.patch [new file with mode: 0644]
libhb/enc_qsv.c
libhb/handbrake/qsv_common.h
libhb/qsv_common.c

diff --git a/contrib/ffmpeg/A13-qsv-dx11.patch b/contrib/ffmpeg/A13-qsv-dx11.patch
new file mode 100644 (file)
index 0000000..177f43b
--- /dev/null
@@ -0,0 +1,309 @@
+diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c
+index 986d4f6022..35879834d8 100644
+--- a/libavcodec/qsv.c
++++ b/libavcodec/qsv.c
+@@ -328,7 +328,7 @@ load_plugin_fail:
+ int ff_qsv_init_internal_session(AVCodecContext *avctx, mfxSession *session,
+                                  const char *load_plugins)
+ {
+-    mfxIMPL impl   = MFX_IMPL_AUTO_ANY;
++    mfxIMPL impl   = MFX_IMPL_AUTO_ANY | MFX_IMPL_VIA_D3D11;
+     mfxVersion ver = { { QSV_VERSION_MINOR, QSV_VERSION_MAJOR } };
+     const char *desc;
+@@ -406,6 +406,7 @@ static AVBufferRef *qsv_create_mids(AVBufferRef *hw_frames_ref)
+     for (i = 0; i < nb_surfaces; i++) {
+         QSVMid *mid = &mids[i];
+         mid->handle        = frames_hwctx->surfaces[i].Data.MemId;
++        mid->texture       = frames_hwctx->texture;
+         mid->hw_frames_ref = hw_frames_ref1;
+     }
+@@ -615,7 +616,14 @@ static mfxStatus qsv_frame_unlock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr)
+ static mfxStatus qsv_frame_get_hdl(mfxHDL pthis, mfxMemId mid, mfxHDL *hdl)
+ {
+     QSVMid *qsv_mid = (QSVMid*)mid;
+-    *hdl = qsv_mid->handle;
++
++    if (qsv_mid->texture) {
++        mfxHDLPair *pPair  =  (mfxHDLPair*)hdl;
++        pPair->first  = qsv_mid->texture;
++        pPair->second = qsv_mid->handle;
++    } else {
++        *hdl = qsv_mid->handle;
++    }
+     return MFX_ERR_NONE;
+ }
+@@ -624,8 +632,8 @@ int ff_qsv_init_session_device(AVCodecContext *avctx, mfxSession *psession,
+ {
+     static const mfxHandleType handle_types[] = {
+         MFX_HANDLE_VA_DISPLAY,
+-        MFX_HANDLE_D3D9_DEVICE_MANAGER,
+         MFX_HANDLE_D3D11_DEVICE,
++        MFX_HANDLE_D3D9_DEVICE_MANAGER,
+     };
+     AVHWDeviceContext    *device_ctx = (AVHWDeviceContext*)device_ref->data;
+     AVQSVDeviceContext *device_hwctx = device_ctx->hwctx;
+diff --git a/libavcodec/qsv_internal.h b/libavcodec/qsv_internal.h
+index b63a7d6a31..e8a766d15e 100644
+--- a/libavcodec/qsv_internal.h
++++ b/libavcodec/qsv_internal.h
+@@ -46,6 +46,8 @@ typedef struct QSVMid {
+     AVBufferRef *hw_frames_ref;
+     mfxHDL handle;
++    void *texture;
++
+     AVFrame *locked_frame;
+     AVFrame *hw_frame;
+     mfxFrameSurface1 surf;
+diff --git a/libavutil/hwcontext_d3d11va.c b/libavutil/hwcontext_d3d11va.c
+index 6670c47579..096770b9ce 100644
+--- a/libavutil/hwcontext_d3d11va.c
++++ b/libavutil/hwcontext_d3d11va.c
+@@ -494,12 +494,12 @@ static void d3d11va_device_uninit(AVHWDeviceContext *hwdev)
+     }
+     if (device_hwctx->video_device) {
+-        ID3D11VideoDevice_Release(device_hwctx->video_device);
++        //ID3D11VideoDevice_Release(device_hwctx->video_device);
+         device_hwctx->video_device = NULL;
+     }
+     if (device_hwctx->video_context) {
+-        ID3D11VideoContext_Release(device_hwctx->video_context);
++        //ID3D11VideoContext_Release(device_hwctx->video_context);
+         device_hwctx->video_context = NULL;
+     }
+@@ -510,6 +510,42 @@ static void d3d11va_device_uninit(AVHWDeviceContext *hwdev)
+     }
+ }
++static int d3d11va_device_find_qsv_adapter(AVHWDeviceContext *ctx, UINT creationFlags)
++{
++    HRESULT hr;
++    IDXGIAdapter *pAdapter = NULL;
++    int adapter_id = 0;
++    IDXGIFactory2 *pDXGIFactory;
++    hr = mCreateDXGIFactory(&IID_IDXGIFactory2, (void **)&pDXGIFactory);
++    while (IDXGIFactory2_EnumAdapters(pDXGIFactory, adapter_id++, &pAdapter) != DXGI_ERROR_NOT_FOUND)
++    {
++        ID3D11Device* g_pd3dDevice = NULL;
++        DXGI_ADAPTER_DESC adapterDesc;
++
++        hr = mD3D11CreateDevice(pAdapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, creationFlags, NULL, 0, D3D11_SDK_VERSION, &g_pd3dDevice, NULL, NULL);
++        if (FAILED(hr)) {
++            av_log(ctx, AV_LOG_ERROR, "D3D11CreateDevice returned error\n");
++            continue;
++        }
++
++        hr = IDXGIAdapter2_GetDesc(pAdapter, &adapterDesc);
++        if (FAILED(hr)) {
++            av_log(ctx, AV_LOG_ERROR, "IDXGIAdapter2_GetDesc returned error\n");
++            continue;
++        }
++
++        if (pAdapter)
++            IDXGIAdapter_Release(pAdapter);
++
++        if (adapterDesc.VendorId == 0x8086) {
++            IDXGIFactory2_Release(pDXGIFactory);
++            return adapter_id - 1;
++        }
++    }
++    IDXGIFactory2_Release(pDXGIFactory);
++    return -1;
++}
++
+ static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device,
+                                  AVDictionary *opts, int flags)
+ {
+@@ -519,7 +555,9 @@ static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device,
+     IDXGIAdapter           *pAdapter = NULL;
+     ID3D10Multithread      *pMultithread;
+     UINT creationFlags = D3D11_CREATE_DEVICE_VIDEO_SUPPORT;
++    int adapter = -1;
+     int is_debug       = !!av_dict_get(opts, "debug", NULL, 0);
++    int is_qsv         = !!av_dict_get(opts, "d3d11va_qsv", NULL, 0);
+     int ret;
+     // (On UWP we can't check this.)
+@@ -538,11 +576,22 @@ static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device,
+         return AVERROR_UNKNOWN;
+     }
++    if (is_qsv) {
++        adapter = d3d11va_device_find_qsv_adapter(ctx, creationFlags);
++        if (adapter < 0) {
++            av_log(ctx, AV_LOG_ERROR, "Failed to find DX11 adapter with QSV support\n");
++            return AVERROR_UNKNOWN;
++        }
++    }
++
+     if (device) {
++        adapter = atoi(device);
++    }
++
++    if (adapter >= 0) {
+         IDXGIFactory2 *pDXGIFactory;
+         hr = mCreateDXGIFactory(&IID_IDXGIFactory2, (void **)&pDXGIFactory);
+         if (SUCCEEDED(hr)) {
+-            int adapter = atoi(device);
+             if (FAILED(IDXGIFactory2_EnumAdapters(pDXGIFactory, adapter, &pAdapter)))
+                 pAdapter = NULL;
+             IDXGIFactory2_Release(pDXGIFactory);
+diff --git a/libavutil/hwcontext_qsv.c b/libavutil/hwcontext_qsv.c
+index 59e4ed9157..56f3ccc94a 100644
+--- a/libavutil/hwcontext_qsv.c
++++ b/libavutil/hwcontext_qsv.c
+@@ -30,6 +30,9 @@
+ #if CONFIG_VAAPI
+ #include "hwcontext_vaapi.h"
+ #endif
++#if CONFIG_D3D11VA
++#include "hwcontext_d3d11va.h"
++#endif
+ #if CONFIG_DXVA2
+ #include "hwcontext_dxva2.h"
+ #endif
+@@ -71,7 +74,7 @@ typedef struct QSVFramesContext {
+     AVBufferRef *child_frames_ref;
+     mfxFrameSurface1 *surfaces_internal;
+     int             nb_surfaces_used;
+-
++    void *texture;
+     // used in the frame allocator for non-opaque surfaces
+     mfxMemId *mem_ids;
+     // used in the opaque alloc request for opaque surfaces
+@@ -89,6 +92,9 @@ static const struct {
+ #if CONFIG_VAAPI
+     { MFX_HANDLE_VA_DISPLAY,          AV_HWDEVICE_TYPE_VAAPI, AV_PIX_FMT_VAAPI },
+ #endif
++#if CONFIG_D3D11VA
++    { MFX_HANDLE_D3D11_DEVICE, AV_HWDEVICE_TYPE_D3D11VA, AV_PIX_FMT_D3D11 },
++#endif
+ #if CONFIG_DXVA2
+     { MFX_HANDLE_D3D9_DEVICE_MANAGER, AV_HWDEVICE_TYPE_DXVA2, AV_PIX_FMT_DXVA2_VLD },
+ #endif
+@@ -229,6 +235,12 @@ static int qsv_init_child_ctx(AVHWFramesContext *ctx)
+         child_device_hwctx->display = (VADisplay)device_priv->handle;
+     }
+ #endif
++#if CONFIG_D3D11VA
++    if (child_device_ctx->type == AV_HWDEVICE_TYPE_D3D11VA) {
++        AVD3D11VADeviceContext *child_device_hwctx = child_device_ctx->hwctx;
++        child_device_hwctx->device = (ID3D11Device*)device_priv->handle;
++    }
++#endif
+ #if CONFIG_DXVA2
+     if (child_device_ctx->type == AV_HWDEVICE_TYPE_DXVA2) {
+         AVDXVA2DeviceContext *child_device_hwctx = child_device_ctx->hwctx;
+@@ -255,6 +267,15 @@ static int qsv_init_child_ctx(AVHWFramesContext *ctx)
+     child_frames_ctx->width             = FFALIGN(ctx->width, 16);
+     child_frames_ctx->height            = FFALIGN(ctx->height, 16);
++#if CONFIG_D3D11VA
++    if (child_device_ctx->type == AV_HWDEVICE_TYPE_D3D11VA) {
++        AVD3D11VAFramesContext *child_frames_hwctx = child_frames_ctx->hwctx;
++        if (hwctx->frame_type & MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET)
++            child_frames_hwctx->BindFlags = D3D11_BIND_RENDER_TARGET ;
++        else
++            child_frames_hwctx->BindFlags = D3D11_BIND_DECODER;
++    }
++#endif
+ #if CONFIG_DXVA2
+     if (child_device_ctx->type == AV_HWDEVICE_TYPE_DXVA2) {
+         AVDXVA2FramesContext *child_frames_hwctx = child_frames_ctx->hwctx;
+@@ -279,6 +300,18 @@ static int qsv_init_child_ctx(AVHWFramesContext *ctx)
+         hwctx->frame_type = MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET;
+     }
+ #endif
++#if CONFIG_D3D11VA
++    if (child_device_ctx->type == AV_HWDEVICE_TYPE_D3D11VA) {
++        AVD3D11VAFramesContext *child_frames_hwctx = child_frames_ctx->hwctx;
++        hwctx->texture = child_frames_hwctx->texture;
++        for (i = 0; i < ctx->initial_pool_size; i++)
++            s->surfaces_internal[i].Data.MemId = (mfxMemId)i;
++        if (child_frames_hwctx->BindFlags == D3D11_BIND_DECODER)
++            hwctx->frame_type = MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET;
++        else
++            hwctx->frame_type = MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET;
++    }
++#endif
+ #if CONFIG_DXVA2
+     if (child_device_ctx->type == AV_HWDEVICE_TYPE_DXVA2) {
+         AVDXVA2FramesContext *child_frames_hwctx = child_frames_ctx->hwctx;
+@@ -1074,7 +1107,7 @@ static void qsv_device_free(AVHWDeviceContext *ctx)
+     av_freep(&priv);
+ }
+-static mfxIMPL choose_implementation(const char *device)
++static mfxIMPL choose_implementation(const char *device, enum AVHWDeviceType child_device_type)
+ {
+     static const struct {
+         const char *name;
+@@ -1103,6 +1136,10 @@ static mfxIMPL choose_implementation(const char *device)
+             impl = strtol(device, NULL, 0);
+     }
++    if ( (child_device_type == AV_HWDEVICE_TYPE_D3D11VA) && (impl != MFX_IMPL_SOFTWARE) ) {
++        impl |= MFX_IMPL_VIA_D3D11;
++    }
++
+     return impl;
+ }
+@@ -1129,6 +1166,15 @@ static int qsv_device_derive_from_child(AVHWDeviceContext *ctx,
+         }
+         break;
+ #endif
++#if CONFIG_D3D11VA
++    case AV_HWDEVICE_TYPE_D3D11VA:
++        {
++            AVD3D11VADeviceContext *child_device_hwctx = child_device_ctx->hwctx;
++            handle_type = MFX_HANDLE_D3D11_DEVICE;
++            handle = (mfxHDL)child_device_hwctx->device;
++        }
++        break;
++#endif
+ #if CONFIG_DXVA2
+     case AV_HWDEVICE_TYPE_DXVA2:
+         {
+@@ -1231,9 +1277,12 @@ static int qsv_device_create(AVHWDeviceContext *ctx, const char *device,
+         // possible, even when multiple devices and drivers are available.
+         av_dict_set(&child_device_opts, "kernel_driver", "i915", 0);
+         av_dict_set(&child_device_opts, "driver",        "iHD",  0);
+-    } else if (CONFIG_DXVA2)
++    } else if (CONFIG_D3D11VA) {
++        child_device_type = AV_HWDEVICE_TYPE_D3D11VA;
++        av_dict_set(&child_device_opts, "d3d11va_qsv",   "enabled",  0);
++    } else if (CONFIG_DXVA2) {
+         child_device_type = AV_HWDEVICE_TYPE_DXVA2;
+-    else {
++    } else {
+         av_log(ctx, AV_LOG_ERROR, "No supported child device type is enabled\n");
+         return AVERROR(ENOSYS);
+     }
+@@ -1245,7 +1294,7 @@ static int qsv_device_create(AVHWDeviceContext *ctx, const char *device,
+     child_device = (AVHWDeviceContext*)priv->child_device_ctx->data;
+-    impl = choose_implementation(device);
++    impl = choose_implementation(device, child_device_type);
+     return qsv_device_derive_from_child(ctx, impl, child_device, 0);
+ }
+diff --git a/libavutil/hwcontext_qsv.h b/libavutil/hwcontext_qsv.h
+index b98d611cfc..f5a9691949 100644
+--- a/libavutil/hwcontext_qsv.h
++++ b/libavutil/hwcontext_qsv.h
+@@ -42,6 +42,7 @@ typedef struct AVQSVDeviceContext {
+ typedef struct AVQSVFramesContext {
+     mfxFrameSurface1 *surfaces;
+     int            nb_surfaces;
++    void              *texture;
+     /**
+      * A combination of MFX_MEMTYPE_* describing the frame pool.
index 511f3af240a31a9ae9f187bbb8b80c038c3ad681..61dc996cc6f713c60bc928ffd6b449284da4d5f7 100644 (file)
@@ -117,14 +117,17 @@ struct hb_work_private_s
     hb_list_t          * loaded_plugins;
 };
 
-int hb_qsv_find_surface_idx(EncQSVFramesContext *ctx, mfxMemId MemId)
+int hb_qsv_find_surface_idx(QSVMid *mids, int nb_mids, QSVMid *mid)
 {
-    if(ctx != NULL)
+    if(mids)
     {
+        QSVMid *m = &mids[0];
+        if (m->texture != mid->texture)
+            return -1;
         int i;
-        for (i = 0; i < ctx->nb_mids; i++) {
-            QSVMid *mid = &ctx->mids[i];
-            if (mid->handle == MemId)
+        for (i = 0; i < nb_mids; i++) {
+            m = &mids[i];
+            if ( m->handle == mid->handle )
                 return i;
         }
     }
@@ -522,6 +525,7 @@ AVBufferRef *hb_qsv_create_mids(AVBufferRef *hw_frames_ref)
     for (i = 0; i < nb_surfaces; i++) {
         QSVMid *mid = &mids[i];
         mid->handle        = frames_hwctx->surfaces[i].Data.MemId;
+        mid->texture       = frames_hwctx->texture;
         mid->hw_frames_ref = hw_frames_ref1;
     }
 
@@ -728,7 +732,14 @@ static mfxStatus hb_qsv_frame_unlock(mfxHDL pthis, mfxMemId mid, mfxFrameData *p
 static mfxStatus hb_qsv_frame_get_hdl(mfxHDL pthis, mfxMemId mid, mfxHDL *hdl)
 {
     QSVMid *qsv_mid = (QSVMid*)mid;
-    *hdl = qsv_mid->handle;
+
+    if (qsv_mid->texture) {
+        mfxHDLPair *pPair  =  (mfxHDLPair*)hdl;
+        pPair->first  = qsv_mid->texture;
+        pPair->second = qsv_mid->handle;
+    } else {
+        *hdl = qsv_mid->handle;
+    }
 
     return MFX_ERR_NONE;
 }
@@ -2093,13 +2104,22 @@ static int qsv_enc_work(hb_work_private_t *pv,
                     if(!pv->is_sys_mem)
                     {
                         QSVMid *mid = surface->Data.MemId;
-                        if (hb_enc_qsv_frames_ctx.mids) {
-                            int ret = hb_qsv_find_surface_idx(&hb_enc_qsv_frames_ctx, mid->handle);
+                        int ret = hb_qsv_find_surface_idx(hb_enc_qsv_frames_ctx.mids, hb_enc_qsv_frames_ctx.nb_mids, mid);
+                        if (ret < 0)
+                        {
+                            ret = hb_qsv_find_surface_idx(hb_enc_qsv_frames_ctx.mids2, hb_enc_qsv_frames_ctx.nb_mids, mid);
                             if (ret < 0)
                             {
-                                hb_error("encqsv: Invalid surface to release %d", ret);
+                                hb_error("encqsv: Surface with MemId=%p has not been found in the pool\n", mid);
                                 return -1;
                             }
+                            else
+                            {
+                                ff_qsv_atomic_dec(&hb_enc_qsv_frames_ctx.pool2[ret]);
+                            }
+                        }
+                        else
+                        {
                             ff_qsv_atomic_dec(&hb_enc_qsv_frames_ctx.pool[ret]);
                         }
                     }
@@ -2183,13 +2203,22 @@ static int qsv_enc_work(hb_work_private_t *pv,
                     if(surface_to_release)
                     {
                         QSVMid *mid = surface_to_release->Data.MemId;
-                        if (hb_enc_qsv_frames_ctx.mids) {
-                            int ret = hb_qsv_find_surface_idx(&hb_enc_qsv_frames_ctx, mid->handle);
+                        int ret = hb_qsv_find_surface_idx(hb_enc_qsv_frames_ctx.mids, hb_enc_qsv_frames_ctx.nb_mids, mid);
+                        if (ret < 0)
+                        {
+                            ret = hb_qsv_find_surface_idx(hb_enc_qsv_frames_ctx.mids2, hb_enc_qsv_frames_ctx.nb_mids, mid);
                             if (ret < 0)
                             {
-                                hb_error("encqsv: Invalid surface to release %d", ret);
+                                hb_error("encqsv: Surface with MemId=%p has not been found in the pool\n", mid);
                                 return -1;
                             }
+                            else
+                            {
+                                ff_qsv_atomic_dec(&hb_enc_qsv_frames_ctx.pool2[ret]);
+                            }
+                        }
+                        else
+                        {
                             ff_qsv_atomic_dec(&hb_enc_qsv_frames_ctx.pool[ret]);
                         }
                     }
@@ -2272,23 +2301,36 @@ int encqsvWork(hb_work_object_t *w, hb_buffer_t **buf_in, hb_buffer_t **buf_out)
     else
     {
 #if HB_PROJECT_FEATURE_QSV
+        QSVMid *mid = NULL;
         if(in->qsv_details.frame)
         {
             surface = ((mfxFrameSurface1*)in->qsv_details.frame->data[3]);
+            mid = surface->Data.MemId;
         }
         else
         {
             // Create black buffer in the begining of the encoding, usually first 2 frames
-            QSVMid *mid = NULL;
             hb_qsv_get_free_surface_from_pool(&mid, &surface, HB_POOL_SURFACE_SIZE);
         }
 
         if(surface)
         {
-            if (hb_enc_qsv_frames_ctx.mids) {
-                int ret = hb_qsv_find_surface_idx(&hb_enc_qsv_frames_ctx, surface->Data.MemId);
+            int ret = hb_qsv_find_surface_idx(hb_enc_qsv_frames_ctx.mids, hb_enc_qsv_frames_ctx.nb_mids, mid);
+            if (ret < 0)
+            {
+                ret = hb_qsv_find_surface_idx(hb_enc_qsv_frames_ctx.mids2, hb_enc_qsv_frames_ctx.nb_mids, mid);
                 if (ret < 0)
-                    return ret;
+                {
+                    hb_error("encqsv: Surface with MemId=%p has not been found in the pool\n", mid);
+                    return -1;
+                }
+                else
+                {
+                    surface->Data.MemId = &hb_enc_qsv_frames_ctx.mids2[ret];
+                }
+            }
+            else
+            {
                 surface->Data.MemId = &hb_enc_qsv_frames_ctx.mids[ret];
             }
         }
index 2277468b074bc749916c8ac6e7b247609e2f5674..1f762fa773befb841e75056f265808ad66b997e1 100644 (file)
@@ -206,6 +206,8 @@ typedef struct QSVMid {
     AVBufferRef *hw_frames_ref;
     mfxHDL handle;
 
+    void *texture;
+
     AVFrame *locked_frame;
     AVFrame *hw_frame;
     mfxFrameSurface1 surf;
@@ -224,10 +226,11 @@ typedef struct QSVFrame {
     struct QSVFrame *next;
 } QSVFrame;
 
-#define HB_POOL_SURFACE_SIZE (200)
+#define HB_POOL_SURFACE_SIZE (64)
 
 typedef struct EncQSVFramesContext {
     AVBufferRef *hw_frames_ctx;
+    AVBufferRef *hw_frames_ctx2;
     //void *logctx;
 
     /* The memory ids for the external frames.
@@ -235,9 +238,13 @@ typedef struct EncQSVFramesContext {
      * (i.e. by the encoder/decoder) and another one given to the MFX session
      * from the frame allocator. */
     AVBufferRef *mids_buf;
+    AVBufferRef *mids_buf2;
     QSVMid *mids;
+    QSVMid *mids2;
     int  nb_mids;
     int pool[HB_POOL_SURFACE_SIZE];
+    int pool2[HB_POOL_SURFACE_SIZE];
+    void *input_texture;
 } EncQSVFramesContext;
 
 /* Full QSV pipeline helpers */
index 08d4f030b6d07033053bde51bbdad33afb34f279..93fb60bd9748159189c29e962c6e996e066ad5ea 100644 (file)
@@ -998,6 +998,7 @@ int hb_qsv_decode_is_enabled(hb_job_t *job)
 }
 
 static int hb_dxva2_device_check();
+static int hb_d3d11va_device_check();
 
 int hb_qsv_full_path_is_enabled(hb_job_t *job)
 {
@@ -1005,7 +1006,8 @@ int hb_qsv_full_path_is_enabled(hb_job_t *job)
     static int device_check_succeded = 0;
     if(!device_check_completed)
     {
-       device_check_succeded = (hb_dxva2_device_check() == 0) ? 1 : 0;
+       device_check_succeded = ((hb_d3d11va_device_check() >= 0)
+        || (hb_dxva2_device_check() == 0)) ? 1 : 0;
        device_check_completed = 1;
     }
     return (hb_qsv_decode_is_enabled(job) && hb_qsv_info_get(job->vcodec) && device_check_succeded);
@@ -2293,11 +2295,19 @@ mfxHDL device_manager_handle = NULL;
 
 #if defined(_WIN32) || defined(__MINGW32__)
 // Direct X
+#define COBJMACROS
+#include <d3d11.h>
+#include <dxgi1_2.h>
 #include <d3d9.h>
 #include <dxva2api.h>
 
+#if HAVE_DXGIDEBUG_H
+#include <dxgidebug.h>
+#endif
+
 typedef IDirect3D9* WINAPI pDirect3DCreate9(UINT);
 typedef HRESULT WINAPI pDirect3DCreate9Ex(UINT, IDirect3D9Ex **);
+typedef HRESULT(WINAPI *HB_PFN_CREATE_DXGI_FACTORY)(REFIID riid, void **ppFactory);
 
 static int hb_dxva2_device_create9(HMODULE d3dlib, UINT adapter, IDirect3D9 **d3d9_out)
 {
@@ -2337,6 +2347,63 @@ static int hb_dxva2_device_create9ex(HMODULE d3dlib, UINT adapter, IDirect3D9 **
     return 0;
 }
 
+static int hb_d3d11va_device_check()
+{
+    HANDLE d3dlib, dxgilib;
+
+    d3dlib  = hb_dlopen("d3d11.dll");
+    dxgilib = hb_dlopen("dxgi.dll");
+    if (!d3dlib || !dxgilib)
+    {
+        hb_error("Failed to load d3d11.dll and dxgi.dll");
+        return -1;
+    }
+
+    PFN_D3D11_CREATE_DEVICE mD3D11CreateDevice;
+    HB_PFN_CREATE_DXGI_FACTORY mCreateDXGIFactory;
+    mD3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)hb_dlsym(d3dlib, "D3D11CreateDevice");
+    mCreateDXGIFactory = (HB_PFN_CREATE_DXGI_FACTORY)hb_dlsym(dxgilib, "CreateDXGIFactory1");
+
+    if (!mD3D11CreateDevice || !mCreateDXGIFactory) {
+        hb_error("Failed to load D3D11 library functions");
+        return -1;
+    }
+
+    HRESULT hr;
+    IDXGIAdapter *pAdapter = NULL;
+    int adapter_id = 0;
+    IDXGIFactory2 *pDXGIFactory;
+    hr = mCreateDXGIFactory(&IID_IDXGIFactory2, (void **)&pDXGIFactory);
+    while (IDXGIFactory2_EnumAdapters(pDXGIFactory, adapter_id++, &pAdapter) != DXGI_ERROR_NOT_FOUND)
+    {
+        ID3D11Device* g_pd3dDevice = NULL;
+        DXGI_ADAPTER_DESC adapterDesc;
+
+        hr = mD3D11CreateDevice(pAdapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, D3D11_CREATE_DEVICE_VIDEO_SUPPORT, NULL, 0, D3D11_SDK_VERSION, &g_pd3dDevice, NULL, NULL);
+        if (FAILED(hr)) {
+            hb_error("D3D11CreateDevice returned error");
+            continue;
+        }
+
+        hr = IDXGIAdapter2_GetDesc(pAdapter, &adapterDesc);
+        if (FAILED(hr)) {
+            hb_error("IDXGIAdapter2_GetDesc returned error");
+            continue;
+        }
+
+        if (pAdapter)
+            IDXGIAdapter_Release(pAdapter);
+
+        if (adapterDesc.VendorId == 0x8086) {
+            IDXGIFactory2_Release(pDXGIFactory);
+            hb_log("D3D11: QSV adapter with id %d has been found", adapter_id - 1);
+            return adapter_id - 1;
+        }
+    }
+    IDXGIFactory2_Release(pDXGIFactory);
+    return -1;
+}
+
 static int hb_dxva2_device_check()
 {
     HMODULE d3dlib = NULL;
@@ -2365,7 +2432,6 @@ static int hb_dxva2_device_check()
     }
 
     UINT adapter_count = IDirect3D9_GetAdapterCount(d3d9);
-    hb_log("D3D9: %d adapters available", adapter_count);
     if (FAILED(IDirect3D9_GetAdapterIdentifier(d3d9, D3DADAPTER_DEFAULT, 0, d3dai)))
     {
         hb_error("Failed to get Direct3D adapter identifier");
@@ -2378,7 +2444,7 @@ static int hb_dxva2_device_check()
     {
         if(d3dai->VendorId != intel_id)
         {
-            hb_log("D3D9: Intel adapter is required for zero-copy QSV path");
+            hb_error("D3D9: adapter that was found does not support QSV. It is required for zero-copy QSV path");
             err = -1;
             goto clean_up;
         }
@@ -2459,13 +2525,17 @@ void hb_qsv_get_free_surface_from_pool(QSVMid **out_mid, mfxFrameSurface1 **out_
     AVHWFramesContext *frames_ctx = (AVHWFramesContext*)hb_enc_qsv_frames_ctx.hw_frames_ctx->data;
     AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx;
 
+    AVHWFramesContext *frames_ctx2 = (AVHWFramesContext*)hb_enc_qsv_frames_ctx.hw_frames_ctx2->data;
+    AVQSVFramesContext *frames_hwctx2 = frames_ctx2->hwctx;
+
     // find the first available surface in the pool
     int count = 0;
-    while( (mid == 0) && (output_surface == 0) )
+    while(1)
     {
         if(count > 30)
         {
-            hb_qsv_sleep(10); // prevent hang when all surfaces all used
+            hb_qsv_sleep(100); // prevent hang when all surfaces all used
+            count = 0;
         }
 
         for(int i = 0; i < pool_size; i++)
@@ -2476,22 +2546,32 @@ void hb_qsv_get_free_surface_from_pool(QSVMid **out_mid, mfxFrameSurface1 **out_
                 output_surface = &frames_hwctx->surfaces[i];
                 if(output_surface->Data.Locked == 0)
                 {
+                    *out_mid = mid;
+                    *out_surface = output_surface;
                     ff_qsv_atomic_inc(&hb_enc_qsv_frames_ctx.pool[i]);
-                    break;
+                    return;
                 }
-                else
+            }
+        }
+
+        for(int i = 0; i < pool_size; i++)
+        {
+            if(hb_enc_qsv_frames_ctx.pool2[i] == 0)
+            {
+                mid = &hb_enc_qsv_frames_ctx.mids2[i];
+                output_surface = &frames_hwctx2->surfaces[i];
+                if(output_surface->Data.Locked == 0)
                 {
-                    mid = 0;
-                    output_surface = 0;
+                    *out_mid = mid;
+                    *out_surface = output_surface;
+                    ff_qsv_atomic_inc(&hb_enc_qsv_frames_ctx.pool2[i]);
+                    return;
                 }
             }
         }
 
         count++;
     }
-
-    *out_mid = mid;
-    *out_surface = output_surface;
 }
 
 hb_buffer_t* hb_qsv_copy_frame(AVFrame *frame, hb_qsv_context *qsv_ctx)
@@ -2520,13 +2600,11 @@ hb_buffer_t* hb_qsv_copy_frame(AVFrame *frame, hb_qsv_context *qsv_ctx)
 
     // Get D3DDeviceManger handle from Media SDK
     mfxHandleType handle_type;
-    IDirect3DDevice9 *pDevice = NULL;
-    HANDLE handle;
 
     static const mfxHandleType handle_types[] = {
         MFX_HANDLE_VA_DISPLAY,
-        MFX_HANDLE_D3D9_DEVICE_MANAGER,
         MFX_HANDLE_D3D11_DEVICE,
+        MFX_HANDLE_D3D9_DEVICE_MANAGER
     };
 
     int i;
@@ -2535,47 +2613,77 @@ hb_buffer_t* hb_qsv_copy_frame(AVFrame *frame, hb_qsv_context *qsv_ctx)
     AVQSVDeviceContext *device_hwctx = device_ctx->hwctx;
     mfxSession        parent_session = device_hwctx->session;
 
-    if(device_manager_handle == NULL)
+    if (device_manager_handle == NULL)
     {
-        for (i = 0; i < 3; i++) {
+        for (i = 0; i < 3; i++)
+        {
             int err = MFXVideoCORE_GetHandle(parent_session, handle_types[i], &device_manager_handle);
-            if (err == MFX_ERR_NONE) {
+            if (err == MFX_ERR_NONE)
+            {
                 handle_type = handle_types[i];
                 break;
             }
             device_manager_handle = NULL;
         }
 
-        if (!device_manager_handle) {
+        if (!device_manager_handle)
+        {
             hb_error("No supported hw handle could be retrieved "
                 "from the session\n");
             return out;
         }
     }
 
-    HRESULT result = lock_device((IDirect3DDeviceManager9 *)device_manager_handle, 0, &pDevice, &handle);
-    if(FAILED(result)) {
-        hb_error("copy_frame qsv: LockDevice failded=%d", result);
-        return out;
-    }
+    if (handle_type == MFX_HANDLE_D3D9_DEVICE_MANAGER)
+    {
+        IDirect3DDevice9 *pDevice = NULL;
+        HANDLE handle;
+
+        HRESULT result = lock_device((IDirect3DDeviceManager9 *)device_manager_handle, 0, &pDevice, &handle);
+        if (FAILED(result))
+        {
+            hb_error("copy_frame qsv: LockDevice failded=%d", result);
+            return out;
+        }
 
-    mfxFrameSurface1* input_surface = (mfxFrameSurface1*)frame->data[3];
+        mfxFrameSurface1* input_surface = (mfxFrameSurface1*)frame->data[3];
 
-    // copy all surface fields
-    *output_surface = *input_surface;
-    // replace the mem id to mem id from the pool
-    output_surface->Data.MemId = mid->handle;
-    // copy input sufrace to sufrace from the pool
-    result = IDirect3DDevice9_StretchRect(pDevice, input_surface->Data.MemId, 0, output_surface->Data.MemId, 0, D3DTEXF_LINEAR); // used in media sdk samples
-    if(FAILED(result)) {
-        hb_error("copy_frame qsv: IDirect3DDevice9_StretchRect failded=%d", result);
-        return out;
+        // copy all surface fields
+        *output_surface = *input_surface;
+        // replace the mem id to mem id from the pool
+        output_surface->Data.MemId = mid;
+        // copy input sufrace to sufrace from the pool
+        result = IDirect3DDevice9_StretchRect(pDevice, input_surface->Data.MemId, 0, mid->handle, 0, D3DTEXF_LINEAR);
+        if (FAILED(result))
+        {
+            hb_error("copy_frame qsv: IDirect3DDevice9_StretchRect failded=%d", result);
+            return out;
+        }
+        result = unlock_device((IDirect3DDeviceManager9 *)device_manager_handle, handle);
+        if (FAILED(result))
+        {
+            hb_error("copy_frame qsv: UnlockDevice failded=%d", result);
+            return out;
+        }
     }
-    result = unlock_device((IDirect3DDeviceManager9 *)device_manager_handle, handle);
-    if(FAILED(result)) {
-        hb_error("copy_frame qsv: UnlockDevice failded=%d", result);
-        return out;
+    else
+    {
+        ID3D11DeviceContext *device_context = NULL;
+        ID3D11Device *device = (ID3D11Device *)device_manager_handle;
+        ID3D11Device_GetImmediateContext(device, &device_context);
+        if (!device_context)
+            return out;
+
+        mfxFrameSurface1* input_surface = (mfxFrameSurface1*)frame->data[3];
+
+        // copy all surface fields
+        *output_surface = *input_surface;
+        // replace the mem id to mem id from the pool
+        output_surface->Data.MemId = mid;
+        // copy input sufrace to sufrace from the pool
+        ID3D11DeviceContext_CopySubresourceRegion(device_context, mid->texture, mid->handle, 0, 0, 0, hb_enc_qsv_frames_ctx.input_texture, input_surface->Data.MemId, NULL);
     }
+
     out->qsv_details.frame->data[3] = output_surface;
     out->qsv_details.qsv_atom = 0;
     out->qsv_details.ctx      = qsv_ctx;
@@ -2668,6 +2776,8 @@ static int qsv_init(AVCodecContext *s)
         return ret;
     }
 
+    hb_enc_qsv_frames_ctx.input_texture = frames_hwctx->texture;
+
     av_buffer_unref(&enc_hw_frames_ctx);
     enc_hw_frames_ctx = av_hwframe_ctx_alloc(hb_hw_device_ctx);
     if (!enc_hw_frames_ctx)
@@ -2690,15 +2800,42 @@ static int qsv_init(AVCodecContext *s)
         return ret;
     }
 
+    enc_hw_frames_ctx = av_hwframe_ctx_alloc(hb_hw_device_ctx);
+    if (!enc_hw_frames_ctx)
+        return AVERROR(ENOMEM);
+
+    hb_enc_qsv_frames_ctx.hw_frames_ctx2 = enc_hw_frames_ctx;
+    frames_ctx   = (AVHWFramesContext*)enc_hw_frames_ctx->data;
+    frames_hwctx = frames_ctx->hwctx;
+
+    frames_ctx->width             = FFALIGN(s->coded_width,  32);
+    frames_ctx->height            = FFALIGN(s->coded_height, 32);
+    frames_ctx->format            = AV_PIX_FMT_QSV;
+    frames_ctx->sw_format         = s->sw_pix_fmt;
+    frames_ctx->initial_pool_size = HB_POOL_SURFACE_SIZE;
+    frames_hwctx->frame_type      = MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET;
+
+    ret = av_hwframe_ctx_init(enc_hw_frames_ctx);
+    if (ret < 0) {
+        av_log(NULL, AV_LOG_ERROR, "Error initializing a QSV frame pool\n");
+        return ret;
+    }
+
     /* allocate the memory ids for the external frames */
     av_buffer_unref(&hb_enc_qsv_frames_ctx.mids_buf);
     hb_enc_qsv_frames_ctx.mids_buf = hb_qsv_create_mids(hb_enc_qsv_frames_ctx.hw_frames_ctx);
     if (!hb_enc_qsv_frames_ctx.mids_buf)
         return AVERROR(ENOMEM);
+    av_buffer_unref(&hb_enc_qsv_frames_ctx.mids_buf2);
+    hb_enc_qsv_frames_ctx.mids_buf2 = hb_qsv_create_mids(hb_enc_qsv_frames_ctx.hw_frames_ctx2);
+    if (!hb_enc_qsv_frames_ctx.mids_buf2)
+        return AVERROR(ENOMEM);
+
     hb_enc_qsv_frames_ctx.mids    = (QSVMid*)hb_enc_qsv_frames_ctx.mids_buf->data;
+    hb_enc_qsv_frames_ctx.mids2   = (QSVMid*)hb_enc_qsv_frames_ctx.mids_buf2->data;
     hb_enc_qsv_frames_ctx.nb_mids = frames_hwctx->nb_surfaces;
-
     memset(hb_enc_qsv_frames_ctx.pool, 0, hb_enc_qsv_frames_ctx.nb_mids * sizeof(hb_enc_qsv_frames_ctx.pool[0]));
+    memset(hb_enc_qsv_frames_ctx.pool2, 0, hb_enc_qsv_frames_ctx.nb_mids * sizeof(hb_enc_qsv_frames_ctx.pool2[0]));
     return 0;
 }
 
@@ -2713,6 +2850,7 @@ int hb_qsv_get_buffer(AVCodecContext *s, AVFrame *frame, int flags)
 enum AVPixelFormat hb_qsv_get_format(AVCodecContext *s, const enum AVPixelFormat *pix_fmts)
 {
     const enum AVPixelFormat *p;
+    int ret;
 
     for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) {
         const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(*p);
@@ -2722,7 +2860,11 @@ enum AVPixelFormat hb_qsv_get_format(AVCodecContext *s, const enum AVPixelFormat
 
         if(*p == AV_PIX_FMT_QSV)
         {
-            qsv_init(s);
+            ret = qsv_init(s);
+            if (ret < 0) {
+                av_log(NULL, AV_LOG_FATAL, "QSV hwaccel requested for input stream but cannot be initialized.\n");
+                return AV_PIX_FMT_NONE;
+            }
 
             if (s->hw_frames_ctx) {
                 s->hw_frames_ctx = av_buffer_ref(s->hw_frames_ctx);
@@ -2733,7 +2875,7 @@ enum AVPixelFormat hb_qsv_get_format(AVCodecContext *s, const enum AVPixelFormat
         }
         else
         {
-            hb_error("get_format: p != AV_PIX_FMT_QSV");
+            hb_error("get_format: *p != AV_PIX_FMT_QSV");
         }
     }
 
@@ -2817,6 +2959,10 @@ static int hb_dxva2_device_check()
     return -1;
 }
 
+static int hb_d3d11va_device_check()
+{
+    return -1;
+}
 #endif
 
 #else