From patchwork Thu Jan 23 14:26:10 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: galinart X-Patchwork-Id: 17486 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id D129A449E3F for ; Thu, 23 Jan 2020 16:27:23 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id AE88E68B373; Thu, 23 Jan 2020 16:27:23 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wm1-f68.google.com (mail-wm1-f68.google.com [209.85.128.68]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 8A7F968B05E for ; Thu, 23 Jan 2020 16:27:17 +0200 (EET) Received: by mail-wm1-f68.google.com with SMTP id f129so2751126wmf.2 for ; Thu, 23 Jan 2020 06:27:17 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=2y5pv3PAZfvDz+9KGr7zhe4ugYNp+7B8vNRgeG5A7eU=; b=QZ9A2RzI9rG0GRU5Ofi4AM6Yy/M35iv5BuFtLRCgNDpOXNA96Bk73oHHVdV2/BddHj hEb2RdEqHNDlRecerpVu0wSxKg5Cb1iETjY7MHIS3dmfGJdQYUufiNH9Y5fZ66Xem/7H /THfIL+FC1kTssMrmIJZ8f/9FVT5L102xzzEBhpkzRAh6J3Xkz9kFwcVe/gpsHpTiOVo /E5wGM+4zOKf/MkHp3R/jo68PGMG5Wkk8SqXtuW+8RT74gbswhF7RSrFyRFeZC9u+vfW SBV8SYb5PvdY2C2M+FBE5kCuVrsh6v0bAce+MYePyMac5xaOpd9/6gq8O8mtUNwIJeR2 70vw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=2y5pv3PAZfvDz+9KGr7zhe4ugYNp+7B8vNRgeG5A7eU=; b=O2et8eIlahxYBYjNh+1LW1J6jXaAQtRN85c1otfnfoGi5Km783V/VHmOUFC5G4OVz/ YmaU693qFt3ubmh9nGQQteQZ2ceZGiV/qMdxkPvNFg2SeZ4rnhyNcTRuUJTSpswtDQuN hRM8h9Q22Eaf1oWF94kOPk3mlFK8jqPscIt8OdkiqaJ70P3v4vl7jRMmnnZ1gqODDwXr +fenzO5oGPY+wBfBvzq5wMOHSaRIBF8v14vfDe1M4Rj/oNn79lahLLRMhI3z6Vqoa0dI qCjwOGQ14RhwTfLbDV7BFPifrGyiDutKYUL0USHCqZgPHafC+wYIJ2jrrcKQfsB0ca3S z3Bw== X-Gm-Message-State: APjAAAVItKji1j59YDkjoZ9ckURbGgJso9ThBMkcLhkxVwRyKVchlBmK ZzHsIPLbXaZM5ZwT+50n01IzN88MS8s= X-Google-Smtp-Source: APXvYqweKZ8HFcm0rtMsqLms1lFhKY3Gr1cLVc2RhtUY2vC7VH0uVINdaU2pWJwkUB5VpdH+UTvZiA== X-Received: by 2002:a1c:9897:: with SMTP id a145mr4396055wme.132.1579789636445; Thu, 23 Jan 2020 06:27:16 -0800 (PST) Received: from localhost.localdomain ([2a02:c7d:3e2e:7400:50ee:9492:6598:b4fa]) by smtp.gmail.com with ESMTPSA id n8sm3223429wrx.42.2020.01.23.06.27.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 23 Jan 2020 06:27:15 -0800 (PST) From: Artem Galin To: ffmpeg-devel@ffmpeg.org Date: Thu, 23 Jan 2020 14:26:10 +0000 Message-Id: <20200123142610.31635-1-artem.galin@gmail.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191223183104.61202-1-artem.galin@gmail.com> References: <20191223183104.61202-1-artem.galin@gmail.com> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH] lavc/qsv: adding DX11 support X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Artem Galin Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" This enables DX11 support for QSV with higher priority than DX9. In case of multiple GPUs configuration, DX9 API does not allow to get access to QSV device in some cases - headless. Implementation based on DX11 resolves that restriction by enumerating list of available GPUs and finding device with QSV support. Signed-off-by: Artem Galin --- libavcodec/qsv.c | 38 ++++---- libavcodec/qsv_internal.h | 5 + libavcodec/version.h | 2 +- libavfilter/qsvvpp.c | 19 +--- libavutil/hwcontext_d3d11va.c | 57 +++++++++++- libavutil/hwcontext_qsv.c | 169 +++++++++++++++++++++++++++++----- libavutil/hwcontext_qsv.h | 13 ++- libavutil/version.h | 2 +- 8 files changed, 242 insertions(+), 63 deletions(-) diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c index db98c75073..df622d9c7d 100644 --- a/libavcodec/qsv.c +++ b/libavcodec/qsv.c @@ -362,7 +362,11 @@ static int ff_qsv_set_display_handle(AVCodecContext *avctx, QSVSession *qs) int ff_qsv_init_internal_session(AVCodecContext *avctx, QSVSession *qs, const char *load_plugins, int gpu_copy) { +#ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE mfxIMPL impl = MFX_IMPL_AUTO_ANY; +#else + mfxIMPL impl = MFX_IMPL_AUTO_ANY | MFX_IMPL_VIA_D3D11; +#endif mfxVersion ver = { { QSV_VERSION_MINOR, QSV_VERSION_MAJOR } }; mfxInitParam init_par = { MFX_IMPL_AUTO_ANY }; @@ -452,6 +456,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; } @@ -661,7 +666,13 @@ 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 *pair = (mfxHDLPair*)hdl; + pair->first = qsv_mid->texture; + pair->second = qsv_mid->handle; + } else { + *hdl = qsv_mid->handle; + } return MFX_ERR_NONE; } @@ -669,14 +680,10 @@ int ff_qsv_init_session_device(AVCodecContext *avctx, mfxSession *psession, AVBufferRef *device_ref, const char *load_plugins, int gpu_copy) { - static const mfxHandleType handle_types[] = { - MFX_HANDLE_VA_DISPLAY, - MFX_HANDLE_D3D9_DEVICE_MANAGER, - MFX_HANDLE_D3D11_DEVICE, - }; AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)device_ref->data; AVQSVDeviceContext *device_hwctx = device_ctx->hwctx; mfxSession parent_session = device_hwctx->session; + mfxHandleType parent_handle_type = device_hwctx->handle_type; mfxInitParam init_par = { MFX_IMPL_AUTO_ANY }; mfxHDL handle = NULL; @@ -686,7 +693,7 @@ int ff_qsv_init_session_device(AVCodecContext *avctx, mfxSession *psession, mfxHandleType handle_type; mfxStatus err; - int i, ret; + int ret; err = MFXQueryIMPL(parent_session, &impl); if (err == MFX_ERR_NONE) @@ -695,17 +702,12 @@ int ff_qsv_init_session_device(AVCodecContext *avctx, mfxSession *psession, return ff_qsv_print_error(avctx, err, "Error querying the session attributes"); - for (i = 0; i < FF_ARRAY_ELEMS(handle_types); i++) { - err = MFXVideoCORE_GetHandle(parent_session, handle_types[i], &handle); - if (err == MFX_ERR_NONE) { - handle_type = handle_types[i]; - break; - } - handle = NULL; - } - if (!handle) { - av_log(avctx, AV_LOG_VERBOSE, "No supported hw handle could be retrieved " - "from the session\n"); + err = MFXVideoCORE_GetHandle(parent_session, parent_handle_type, &handle); + if (err == MFX_ERR_NONE) { + handle_type = parent_handle_type; + } else { + return ff_qsv_print_error(avctx, err, + "Error no supported hw handle could be retrieved from the session"); } #if QSV_VERSION_ATLEAST(1, 16) diff --git a/libavcodec/qsv_internal.h b/libavcodec/qsv_internal.h index 6489836a67..c985f227ec 100644 --- a/libavcodec/qsv_internal.h +++ b/libavcodec/qsv_internal.h @@ -65,6 +65,11 @@ typedef struct QSVMid { AVFrame *locked_frame; AVFrame *hw_frame; mfxFrameSurface1 surf; + /** + * ID3D11Texture2D texture in which the frame is located for D3D11VA device. + * Null in case of DXVA2 device. + */ + void *texture; } QSVMid; typedef struct QSVFrame { diff --git a/libavcodec/version.h b/libavcodec/version.h index 6cf333eeb6..2fba26e8d0 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -28,7 +28,7 @@ #include "libavutil/version.h" #define LIBAVCODEC_VERSION_MAJOR 58 -#define LIBAVCODEC_VERSION_MINOR 66 +#define LIBAVCODEC_VERSION_MINOR 67 #define LIBAVCODEC_VERSION_MICRO 100 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ diff --git a/libavfilter/qsvvpp.c b/libavfilter/qsvvpp.c index 8d5ff2eb65..298c10718e 100644 --- a/libavfilter/qsvvpp.c +++ b/libavfilter/qsvvpp.c @@ -68,12 +68,6 @@ struct QSVVPPContext { int nb_ext_buffers; }; -static const mfxHandleType handle_types[] = { - MFX_HANDLE_VA_DISPLAY, - MFX_HANDLE_D3D9_DEVICE_MANAGER, - MFX_HANDLE_D3D11_DEVICE, -}; - static const AVRational default_tb = { 1, 90000 }; /* functions for frameAlloc */ @@ -497,15 +491,10 @@ static int init_vpp_session(AVFilterContext *avctx, QSVVPPContext *s) return AVERROR_UNKNOWN; } - for (i = 0; i < FF_ARRAY_ELEMS(handle_types); i++) { - ret = MFXVideoCORE_GetHandle(device_hwctx->session, handle_types[i], &handle); - if (ret == MFX_ERR_NONE) { - handle_type = handle_types[i]; - break; - } - } - - if (ret != MFX_ERR_NONE) { + ret = MFXVideoCORE_GetHandle(device_hwctx->session, device_hwctx->handle_type, &handle); + if (ret == MFX_ERR_NONE) { + handle_type = device_hwctx->handle_type; + } else { av_log(avctx, AV_LOG_ERROR, "Error getting the session handle\n"); return AVERROR_UNKNOWN; } diff --git a/libavutil/hwcontext_d3d11va.c b/libavutil/hwcontext_d3d11va.c index 6670c47579..a08479fd96 100644 --- a/libavutil/hwcontext_d3d11va.c +++ b/libavutil/hwcontext_d3d11va.c @@ -244,7 +244,7 @@ static int d3d11va_frames_init(AVHWFramesContext *ctx) return AVERROR(EINVAL); } - texDesc = (D3D11_TEXTURE2D_DESC){ + texDesc = (D3D11_TEXTURE2D_DESC) { .Width = ctx->width, .Height = ctx->height, .MipLevels = 1, @@ -510,6 +510,46 @@ static void d3d11va_device_uninit(AVHWDeviceContext *hwdev) } } +static int d3d11va_device_find_qsv_adapter(AVHWDeviceContext *ctx, UINT creationFlags) +{ + HRESULT hr; + IDXGIAdapter *adapter = NULL; + int adapter_id = 0; + int vendor_id = 0x8086; + IDXGIFactory2 *factory; + hr = mCreateDXGIFactory(&IID_IDXGIFactory2, (void **)&factory); + while (IDXGIFactory2_EnumAdapters(factory, adapter_id++, &adapter) != DXGI_ERROR_NOT_FOUND) + { + ID3D11Device* device = NULL; + DXGI_ADAPTER_DESC adapter_desc; + + hr = mD3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, creationFlags, NULL, 0, D3D11_SDK_VERSION, &device, NULL, NULL); + if (FAILED(hr)) { + av_log(ctx, AV_LOG_ERROR, "D3D11CreateDevice returned error\n"); + continue; + } + + hr = IDXGIAdapter2_GetDesc(adapter, &adapter_desc); + if (FAILED(hr)) { + av_log(ctx, AV_LOG_ERROR, "IDXGIAdapter2_GetDesc returned error\n"); + continue; + } + + if(device) + ID3D11Device_Release(device); + + if (adapter) + IDXGIAdapter_Release(adapter); + + if (adapter_desc.VendorId == vendor_id) { + IDXGIFactory2_Release(factory); + return adapter_id - 1; + } + } + IDXGIFactory2_Release(factory); + return -1; +} + static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device, AVDictionary *opts, int flags) { @@ -519,7 +559,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 +580,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 b1b67400de..05b2ed3333 100644 --- a/libavutil/hwcontext_qsv.c +++ b/libavutil/hwcontext_qsv.c @@ -27,9 +27,13 @@ #include #endif +#define COBJMACROS #if CONFIG_VAAPI #include "hwcontext_vaapi.h" #endif +#if CONFIG_D3D11VA +#include "hwcontext_d3d11va.h" +#endif #if CONFIG_DXVA2 #include "hwcontext_dxva2.h" #endif @@ -89,6 +93,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 @@ -124,18 +131,21 @@ static int qsv_device_init(AVHWDeviceContext *ctx) int i; for (i = 0; supported_handle_types[i].handle_type; i++) { - err = MFXVideoCORE_GetHandle(hwctx->session, supported_handle_types[i].handle_type, - &s->handle); - if (err == MFX_ERR_NONE) { - s->handle_type = supported_handle_types[i].handle_type; - s->child_device_type = supported_handle_types[i].device_type; - s->child_pix_fmt = supported_handle_types[i].pix_fmt; - break; + if (supported_handle_types[i].handle_type == hwctx->handle_type) { + err = MFXVideoCORE_GetHandle(hwctx->session, supported_handle_types[i].handle_type, + &s->handle); + if (err == MFX_ERR_NONE) { + s->handle_type = supported_handle_types[i].handle_type; + s->child_device_type = supported_handle_types[i].device_type; + s->child_pix_fmt = supported_handle_types[i].pix_fmt; + break; + } } } if (!s->handle) { av_log(ctx, AV_LOG_VERBOSE, "No supported hw handle could be retrieved " "from the session\n"); + return AVERROR_UNKNOWN; } err = MFXQueryIMPL(hwctx->session, &s->impl); @@ -229,9 +239,17 @@ 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; + ID3D11Device_AddRef((ID3D11Device*)device_priv->handle); + 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; + IDirect3DDeviceManager9_AddRef((IDirect3DDeviceManager9*)device_priv->handle); child_device_hwctx->devmgr = (IDirect3DDeviceManager9*)device_priv->handle; } #endif @@ -255,6 +273,16 @@ 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; + child_frames_hwctx->MiscFlags |= D3D11_RESOURCE_MISC_SHARED; + 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 +307,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)(int64_t)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; @@ -421,7 +461,16 @@ static mfxStatus frame_unlock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr) static mfxStatus frame_get_hdl(mfxHDL pthis, mfxMemId mid, mfxHDL *hdl) { - *hdl = mid; + AVHWFramesContext *ctx = pthis; + AVQSVFramesContext *hwctx = ctx->hwctx; + + if (hwctx->texture) { + mfxHDLPair *pair = (mfxHDLPair*)hdl; + pair->first = hwctx->texture; + pair->second = mid; + } else { + *hdl = mid; + } return MFX_ERR_NONE; } @@ -492,7 +541,7 @@ static int qsv_init_internal_session(AVHWFramesContext *ctx, err = MFXVideoVPP_Init(*session, &par); if (err != MFX_ERR_NONE) { - av_log(ctx, AV_LOG_VERBOSE, "Error opening the internal VPP session." + av_log(ctx, AV_LOG_ERROR, "Error opening the internal VPP session." "Surface upload/download will not be possible\n"); MFXClose(*session); *session = NULL; @@ -668,6 +717,11 @@ static int qsv_map_from(AVHWFramesContext *ctx, child_data = (uint8_t*)(intptr_t)*(VASurfaceID*)surf->Data.MemId; break; #endif +#if CONFIG_D3D11VA + case AV_HWDEVICE_TYPE_D3D11VA: + child_data = surf->Data.MemId; + break; +#endif #if CONFIG_DXVA2 case AV_HWDEVICE_TYPE_DXVA2: child_data = surf->Data.MemId; @@ -972,6 +1026,27 @@ static int qsv_frames_derive_to(AVHWFramesContext *dst_ctx, } break; #endif +#if CONFIG_D3D11VA + case AV_HWDEVICE_TYPE_D3D11VA: + { + AVD3D11VAFramesContext *src_hwctx = src_ctx->hwctx; + s->surfaces_internal = av_mallocz_array(src_ctx->initial_pool_size, + sizeof(*s->surfaces_internal)); + if (!s->surfaces_internal) + return AVERROR(ENOMEM); + dst_hwctx->texture = src_hwctx->texture; + for (i = 0; i < src_ctx->initial_pool_size; i++) { + qsv_init_surface(dst_ctx, &s->surfaces_internal[i]); + s->surfaces_internal[i].Data.MemId = (mfxMemId)(int64_t)i; + } + dst_hwctx->nb_surfaces = src_ctx->initial_pool_size; + if (src_hwctx->BindFlags == D3D11_BIND_DECODER) + dst_hwctx->frame_type = MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET; + else + dst_hwctx->frame_type = MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET; + } + break; +#endif #if CONFIG_DXVA2 case AV_HWDEVICE_TYPE_DXVA2: { @@ -1004,19 +1079,37 @@ static int qsv_frames_derive_to(AVHWFramesContext *dst_ctx, static int qsv_map_to(AVHWFramesContext *dst_ctx, AVFrame *dst, const AVFrame *src, int flags) { - AVQSVFramesContext *hwctx = dst_ctx->hwctx; + AVHWFramesContext *src_frames; int i, err; + enum AVHWDeviceType type = AV_HWDEVICE_TYPE_NONE; + AVQSVFramesContext *hwctx = dst_ctx->hwctx; + if (src->hw_frames_ctx) { + src_frames = (AVHWFramesContext*)src->hw_frames_ctx->data; + type = src_frames->internal->hw_type->type; + } for (i = 0; i < hwctx->nb_surfaces; i++) { #if CONFIG_VAAPI - if (*(VASurfaceID*)hwctx->surfaces[i].Data.MemId == - (VASurfaceID)(uintptr_t)src->data[3]) - break; + if (AV_HWDEVICE_TYPE_VAAPI == type) { + if (*(VASurfaceID*)hwctx->surfaces[i].Data.MemId == + (VASurfaceID)(uintptr_t)src->data[3]) + break; + } +#endif +#if CONFIG_D3D11VA + if (AV_HWDEVICE_TYPE_D3D11VA == type) { + if ((hwctx->texture == (ID3D11Texture2D*)(uintptr_t)src->data[0]) && + ((ID3D11Texture2D*)hwctx->surfaces[i].Data.MemId == + (ID3D11Texture2D*)(uintptr_t)src->data[1])) + break; + } #endif #if CONFIG_DXVA2 - if ((IDirect3DSurface9*)hwctx->surfaces[i].Data.MemId == - (IDirect3DSurface9*)(uintptr_t)src->data[3]) - break; + if (AV_HWDEVICE_TYPE_DXVA2 == type) { + if ((IDirect3DSurface9*)hwctx->surfaces[i].Data.MemId == + (IDirect3DSurface9*)(uintptr_t)src->data[3]) + break; + } #endif } if (i >= hwctx->nb_surfaces) { @@ -1074,7 +1167,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 +1196,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 +1226,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: { @@ -1180,6 +1286,7 @@ static int qsv_device_derive_from_child(AVHWDeviceContext *ctx, goto fail; } + hwctx->handle_type = handle_type; return 0; fail: @@ -1191,7 +1298,9 @@ fail: static int qsv_device_derive(AVHWDeviceContext *ctx, AVHWDeviceContext *child_device_ctx, int flags) { - return qsv_device_derive_from_child(ctx, MFX_IMPL_HARDWARE_ANY, + mfxIMPL impl; + impl = choose_implementation("hw_any", child_device_ctx->type); + return qsv_device_derive_from_child(ctx, impl, child_device_ctx, flags); } @@ -1226,23 +1335,35 @@ 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); } ret = av_hwdevice_ctx_create(&priv->child_device_ctx, child_device_type, e ? e->value : NULL, child_device_opts, 0); - av_dict_free(&child_device_opts); - if (ret < 0) - return ret; + if (ret < 0) { + if (CONFIG_DXVA2 && (child_device_type == AV_HWDEVICE_TYPE_D3D11VA)) { + // in case of d3d11va fail, try one more chance to create device via dxva2 + child_device_type = AV_HWDEVICE_TYPE_DXVA2; + child_device_opts = NULL; + ret = av_hwdevice_ctx_create(&priv->child_device_ctx, child_device_type, + e ? e->value : NULL, child_device_opts, 0); + } + if (ret < 0) { + return ret; + } + } 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..3a322037e5 100644 --- a/libavutil/hwcontext_qsv.h +++ b/libavutil/hwcontext_qsv.h @@ -34,6 +34,15 @@ */ typedef struct AVQSVDeviceContext { mfxSession session; + /** + * Need to store actual handle type that session uses + * MFXVideoCORE_GetHandle() function returns mfxHandleType + * always equal to MFX_HANDLE_D3D9_DEVICE_MANAGER + * even when MFX_HANDLE_D3D11_DEVICE was set as handle before by + * MFXVideoCORE_SetHandle() to mfx session. + * Fixed already but will be available only with latest driver. + */ + mfxHandleType handle_type; } AVQSVDeviceContext; /** @@ -42,11 +51,11 @@ typedef struct AVQSVDeviceContext { typedef struct AVQSVFramesContext { mfxFrameSurface1 *surfaces; int nb_surfaces; - /** * A combination of MFX_MEMTYPE_* describing the frame pool. */ - int frame_type; + int frame_type; + void *texture; } AVQSVFramesContext; #endif /* AVUTIL_HWCONTEXT_QSV_H */ diff --git a/libavutil/version.h b/libavutil/version.h index af8f614aff..2bc1b98615 100644 --- a/libavutil/version.h +++ b/libavutil/version.h @@ -79,7 +79,7 @@ */ #define LIBAVUTIL_VERSION_MAJOR 56 -#define LIBAVUTIL_VERSION_MINOR 38 +#define LIBAVUTIL_VERSION_MINOR 39 #define LIBAVUTIL_VERSION_MICRO 100 #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \