summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--contrib/ffmpeg/A13-qsv-dx11.patch309
-rw-r--r--libhb/enc_qsv.c74
-rw-r--r--libhb/handbrake/qsv_common.h9
-rw-r--r--libhb/qsv_common.c228
4 files changed, 562 insertions, 58 deletions
diff --git a/contrib/ffmpeg/A13-qsv-dx11.patch b/contrib/ffmpeg/A13-qsv-dx11.patch
new file mode 100644
index 000000000..177f43bb7
--- /dev/null
+++ b/contrib/ffmpeg/A13-qsv-dx11.patch
@@ -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.
diff --git a/libhb/enc_qsv.c b/libhb/enc_qsv.c
index 511f3af24..61dc996cc 100644
--- a/libhb/enc_qsv.c
+++ b/libhb/enc_qsv.c
@@ -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];
}
}
diff --git a/libhb/handbrake/qsv_common.h b/libhb/handbrake/qsv_common.h
index 2277468b0..1f762fa77 100644
--- a/libhb/handbrake/qsv_common.h
+++ b/libhb/handbrake/qsv_common.h
@@ -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 */
diff --git a/libhb/qsv_common.c b/libhb/qsv_common.c
index 08d4f030b..93fb60bd9 100644
--- a/libhb/qsv_common.c
+++ b/libhb/qsv_common.c
@@ -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