diff options
-rw-r--r-- | contrib/ffmpeg/A13-qsv-dx11.patch | 309 | ||||
-rw-r--r-- | libhb/enc_qsv.c | 74 | ||||
-rw-r--r-- | libhb/handbrake/qsv_common.h | 9 | ||||
-rw-r--r-- | libhb/qsv_common.c | 228 |
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 |