From patchwork Fri Apr 24 14:52:19 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: galinart X-Patchwork-Id: 19215 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 DDB1B44A379 for ; Fri, 24 Apr 2020 17:54:26 +0300 (EEST) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id BF7B068BFF1; Fri, 24 Apr 2020 17:54:26 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wm1-f41.google.com (mail-wm1-f41.google.com [209.85.128.41]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 817DB68BEF7 for ; Fri, 24 Apr 2020 17:54:20 +0300 (EEST) Received: by mail-wm1-f41.google.com with SMTP id e26so10805483wmk.5 for ; Fri, 24 Apr 2020 07:54:20 -0700 (PDT) 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=WyH63qtwCjKhcbYxMQRoPTCdiCrBWANFDr4tf1Hulwg=; b=WlGMLyNMJgYkOiXooeOSecJbX3PzHizQRE74gx/EAtEy9T8DZnxB3sVz/2jQ+ZDceR mgWC4ZGJtFlbj61gl2lsazx4zC8BkUAqjdZ9SG6J9NR/IEPwQtXT3/w1Br0lcz/gRpZk 7vR6zeXaEkBJW/CmxQcU+f4X0/wR2VksxtKTD7TVPAChOw03T+FHzkPFO0hoeVHCaa+W U9GjhMG3FffK6beg9Gx7sOd4BWtkz8R3giftputOPuWGujl11eV2LcMycyTb/CINqsOe XukNnGhQCgvU8KWMWO/due+zY1NYgKs0wOkPX98ovsfB7pJn7oer6tSTn6DaOFf6d/0Y x8gQ== 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=WyH63qtwCjKhcbYxMQRoPTCdiCrBWANFDr4tf1Hulwg=; b=d+UGNnxzZNLH7PqQ3HCfkdD6k+WDW9+FloxRt+B5q4MMsNbKZZhJfrZqjP9YJZvCXJ 2wslt/A5eJfpNgyN+HU7DGVaHMFPKX81ECRUaaDegaD6u7IcfJW0GViCRYqOyejMV27+ zsJpLLUb0lYSGeGUt3i1/Bxgp4o1vqksq4KApJ2g+e15bPdOaWSz6UlFj+Jo9GkufyI/ 4HAfxulhYUcckOPq1KKRFuZ4fFG0AJ8rcyX4u90b653aK2aTmFsLIjHEKQud0NJL0do5 EFBHQh/5JLJhEom60ZNofr2bvnmCIHySNH4sXnPmSCE76uXz+gzLOjIunWg8g1De2sFt jgAA== X-Gm-Message-State: AGi0PubOs7sVHoaqKOwCUBz01egspb9d7RwTlaUszeAQZKvyoQLMNa8i EQ/ugmuL7BkvwmIsIe1CSZXiMhYvP14= X-Google-Smtp-Source: APiQypKxM5rfz2romBGDLFp+fj0W2jzH5n7O8WyvhKIeQ5hJcTPLvr8O3s8gDevaurjigE3blmgIaw== X-Received: by 2002:a1c:59c3:: with SMTP id n186mr3765554wmb.24.1587740059020; Fri, 24 Apr 2020 07:54:19 -0700 (PDT) Received: from localhost.localdomain ([2a02:c7d:3e2e:7400:d810:daa5:1027:e125]) by smtp.googlemail.com with ESMTPSA id p190sm3180552wmp.38.2020.04.24.07.54.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 24 Apr 2020 07:54:18 -0700 (PDT) From: artem.galin@gmail.com To: ffmpeg-devel@ffmpeg.org Date: Fri, 24 Apr 2020 15:52:19 +0100 Message-Id: <20200424145219.54067-4-artem.galin@gmail.com> X-Mailer: git-send-email 2.26.0 In-Reply-To: <20200424145219.54067-1-artem.galin@gmail.com> References: <20200415130741.27263-1-artem.galin@gmail.com> <20200424145219.54067-1-artem.galin@gmail.com> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v3 4/4] libavutil/qsv: enabling d3d11va 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 , robux4@ycbcr.xyz Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" From: Artem Galin Makes selection of d3d11va device type by default and over DirectX 9, which is still supported but requires explicit selection. This enables usage of non-powered/headless GPU, better HDR support. Pool of resources is allocated as one texture with array of slices. Added d3d11va device selection by vendor id. Example: --init_hw_device d3d11va:,vendor=0x8086 DirectX 9 usage. Example: --init_hw_device qsv:hw,child_device_type=dxva2 Signed-off-by: Artem Galin --- libavutil/hwcontext_d3d11va.c | 82 +++++++- libavutil/hwcontext_d3d11va.h | 8 + libavutil/hwcontext_qsv.c | 363 +++++++++++++++++++++++++++------- 3 files changed, 379 insertions(+), 74 deletions(-) diff --git a/libavutil/hwcontext_d3d11va.c b/libavutil/hwcontext_d3d11va.c index c8ae58f908..c5e127aadb 100644 --- a/libavutil/hwcontext_d3d11va.c +++ b/libavutil/hwcontext_d3d11va.c @@ -72,7 +72,7 @@ static av_cold void load_functions(void) } typedef struct D3D11VAFramesContext { - int nb_surfaces_used; + size_t nb_surfaces; DXGI_FORMAT format; @@ -112,6 +112,8 @@ static void d3d11va_frames_uninit(AVHWFramesContext *ctx) if (s->staging_texture) ID3D11Texture2D_Release(s->staging_texture); s->staging_texture = NULL; + + av_freep(&frames_hwctx->texture_infos); } static int d3d11va_frames_get_constraints(AVHWDeviceContext *ctx, @@ -152,8 +154,9 @@ static void free_texture(void *opaque, uint8_t *data) av_free(data); } -static AVBufferRef *wrap_texture_buf(ID3D11Texture2D *tex, int index) +static AVBufferRef *wrap_texture_buf(AVHWFramesContext *ctx, ID3D11Texture2D *tex, int index) { + AVD3D11VAFramesContext *frames_hwctx = ctx->hwctx; AVBufferRef *buf; AVD3D11FrameDescriptor *desc = av_mallocz(sizeof(*desc)); if (!desc) { @@ -161,6 +164,10 @@ static AVBufferRef *wrap_texture_buf(ID3D11Texture2D *tex, int index) return NULL; } + frames_hwctx->texture_infos[frames_hwctx->nb_surfaces_used].texture = tex; + frames_hwctx->texture_infos[frames_hwctx->nb_surfaces_used].index = index; + frames_hwctx->nb_surfaces_used++; + desc->texture = tex; desc->index = index; @@ -199,13 +206,12 @@ static AVBufferRef *d3d11va_alloc_single(AVHWFramesContext *ctx) return NULL; } - return wrap_texture_buf(tex, 0); + return wrap_texture_buf(ctx, tex, 0); } static AVBufferRef *d3d11va_pool_alloc(void *opaque, int size) { AVHWFramesContext *ctx = (AVHWFramesContext*)opaque; - D3D11VAFramesContext *s = ctx->internal->priv; AVD3D11VAFramesContext *hwctx = ctx->hwctx; D3D11_TEXTURE2D_DESC texDesc; @@ -214,13 +220,13 @@ static AVBufferRef *d3d11va_pool_alloc(void *opaque, int size) ID3D11Texture2D_GetDesc(hwctx->texture, &texDesc); - if (s->nb_surfaces_used >= texDesc.ArraySize) { + if (hwctx->nb_surfaces_used >= texDesc.ArraySize) { av_log(ctx, AV_LOG_ERROR, "Static surface pool size exceeded.\n"); return NULL; } ID3D11Texture2D_AddRef(hwctx->texture); - return wrap_texture_buf(hwctx->texture, s->nb_surfaces_used++); + return wrap_texture_buf(ctx, hwctx->texture, hwctx->nb_surfaces_used); } static int d3d11va_frames_init(AVHWFramesContext *ctx) @@ -267,7 +273,7 @@ static int d3d11va_frames_init(AVHWFramesContext *ctx) av_log(ctx, AV_LOG_ERROR, "User-provided texture has mismatching parameters\n"); return AVERROR(EINVAL); } - } else if (texDesc.ArraySize > 0) { + } else if (!(texDesc.BindFlags & D3D11_BIND_RENDER_TARGET) && texDesc.ArraySize > 0) { hr = ID3D11Device_CreateTexture2D(device_hwctx->device, &texDesc, NULL, &hwctx->texture); if (FAILED(hr)) { av_log(ctx, AV_LOG_ERROR, "Could not create the texture (%lx)\n", (long)hr); @@ -275,6 +281,12 @@ static int d3d11va_frames_init(AVHWFramesContext *ctx) } } + hwctx->texture_infos = av_mallocz_array(ctx->initial_pool_size, sizeof(*hwctx->texture_infos)); + if (!hwctx->texture_infos) + return AVERROR(ENOMEM); + + s->nb_surfaces = ctx->initial_pool_size; + ctx->internal->pool_internal = av_buffer_pool_init2(sizeof(AVD3D11FrameDescriptor), ctx, d3d11va_pool_alloc, NULL); if (!ctx->internal->pool_internal) @@ -511,15 +523,55 @@ static void d3d11va_device_uninit(AVHWDeviceContext *hwdev) } } +static int d3d11va_device_find_adapter_by_vendor_id(AVHWDeviceContext *ctx, UINT creationFlags, long int vendor_id) +{ + HRESULT hr; + IDXGIAdapter *adapter = NULL; + int adapter_id = 0; + 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) { AVD3D11VADeviceContext *device_hwctx = ctx->hwctx; HRESULT hr; + AVDictionaryEntry *e; 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 ret; @@ -539,11 +591,24 @@ static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device, return AVERROR_UNKNOWN; } + e = av_dict_get(opts, "vendor", NULL, 0); + if (e) { + long int vendor_id = strtol(e->value, NULL, 0); + adapter = d3d11va_device_find_adapter_by_vendor_id(ctx, creationFlags, vendor_id); + if (adapter < 0) { + av_log(ctx, AV_LOG_ERROR, "Failed to find d3d11va adapter by vendor id %s\n", e ? e->value : NULL); + 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); @@ -568,6 +633,7 @@ static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device, return AVERROR_UNKNOWN; } + av_log(ctx, AV_LOG_VERBOSE, "Using D3D11 device.\n"); hr = ID3D11Device_QueryInterface(device_hwctx->device, &IID_ID3D10Multithread, (void **)&pMultithread); if (SUCCEEDED(hr)) { ID3D10Multithread_SetMultithreadProtected(pMultithread, TRUE); diff --git a/libavutil/hwcontext_d3d11va.h b/libavutil/hwcontext_d3d11va.h index 9f91e9b1b6..f3def15bea 100644 --- a/libavutil/hwcontext_d3d11va.h +++ b/libavutil/hwcontext_d3d11va.h @@ -39,6 +39,11 @@ #include #include +typedef struct D3D11TextureInfo { + ID3D11Texture2D *texture; + size_t index; +} D3D11TextureInfo; + /** * This struct is allocated as AVHWDeviceContext.hwctx */ @@ -164,6 +169,9 @@ typedef struct AVD3D11VAFramesContext { * This field is ignored/invalid if a user-allocated texture is provided. */ UINT MiscFlags; + + D3D11TextureInfo *texture_infos; + size_t nb_surfaces_used; } AVD3D11VAFramesContext; #endif /* AVUTIL_HWCONTEXT_D3D11VA_H */ diff --git a/libavutil/hwcontext_qsv.c b/libavutil/hwcontext_qsv.c index b1b67400de..3a9c3f8ff0 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 @@ -44,6 +48,8 @@ #include "pixdesc.h" #include "time.h" +#define MFX_IMPL_VIA_MASK(impl) (0x0f00 & (impl)) + typedef struct QSVDevicePriv { AVBufferRef *child_device_ctx; } QSVDevicePriv; @@ -70,6 +76,7 @@ typedef struct QSVFramesContext { AVBufferRef *child_frames_ref; mfxFrameSurface1 *surfaces_internal; + mfxHDLPair *handle_pairs_internal; int nb_surfaces_used; // used in the frame allocator for non-opaque surfaces @@ -81,20 +88,6 @@ typedef struct QSVFramesContext { mfxExtBuffer *ext_buffers[1]; } QSVFramesContext; -static const struct { - mfxHandleType handle_type; - enum AVHWDeviceType device_type; - enum AVPixelFormat pix_fmt; -} supported_handle_types[] = { -#if CONFIG_VAAPI - { MFX_HANDLE_VA_DISPLAY, AV_HWDEVICE_TYPE_VAAPI, AV_PIX_FMT_VAAPI }, -#endif -#if CONFIG_DXVA2 - { MFX_HANDLE_D3D9_DEVICE_MANAGER, AV_HWDEVICE_TYPE_DXVA2, AV_PIX_FMT_DXVA2_VLD }, -#endif - { 0 }, -}; - static const struct { enum AVPixelFormat pix_fmt; uint32_t fourcc; @@ -115,28 +108,32 @@ static uint32_t qsv_fourcc_from_pix_fmt(enum AVPixelFormat pix_fmt) return 0; } +#if CONFIG_D3D11VA +static uint32_t qsv_get_d3d11va_bind_flags(int mem_type) +{ + uint32_t bind_flags = 0; + + if ((mem_type & MFX_MEMTYPE_VIDEO_MEMORY_ENCODER_TARGET) && (mem_type & MFX_MEMTYPE_INTERNAL_FRAME)) + bind_flags = D3D11_BIND_DECODER | D3D11_BIND_VIDEO_ENCODER; + else + bind_flags = D3D11_BIND_DECODER; + + if ((MFX_MEMTYPE_FROM_VPPOUT & mem_type) || (MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET & mem_type)) + bind_flags = D3D11_BIND_RENDER_TARGET; + + return bind_flags; +} +#endif + static int qsv_device_init(AVHWDeviceContext *ctx) { AVQSVDeviceContext *hwctx = ctx->hwctx; QSVDeviceContext *s = ctx->internal->priv; - + int hw_handle_supported = 0; + mfxHandleType handle_type; + enum AVHWDeviceType device_type; + enum AVPixelFormat pix_fmt; mfxStatus err; - 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 (!s->handle) { - av_log(ctx, AV_LOG_VERBOSE, "No supported hw handle could be retrieved " - "from the session\n"); - } err = MFXQueryIMPL(hwctx->session, &s->impl); if (err == MFX_ERR_NONE) @@ -146,6 +143,41 @@ static int qsv_device_init(AVHWDeviceContext *ctx) return AVERROR_UNKNOWN; } + if (MFX_IMPL_VIA_VAAPI == MFX_IMPL_VIA_MASK(s->impl)) { +#if CONFIG_VAAPI + handle_type = MFX_HANDLE_VA_DISPLAY; + device_type = AV_HWDEVICE_TYPE_VAAPI; + pix_fmt = AV_PIX_FMT_VAAPI; + hw_handle_supported = 1; +#endif + } else if (MFX_IMPL_VIA_D3D11 == MFX_IMPL_VIA_MASK(s->impl)) { +#if CONFIG_D3D11VA + handle_type = MFX_HANDLE_D3D11_DEVICE; + device_type = AV_HWDEVICE_TYPE_D3D11VA; + pix_fmt = AV_PIX_FMT_D3D11; + hw_handle_supported = 1; +#endif + } else if (MFX_IMPL_VIA_D3D9 == MFX_IMPL_VIA_MASK(s->impl)) { +#if CONFIG_DXVA2 + handle_type = MFX_HANDLE_D3D9_DEVICE_MANAGER; + device_type = AV_HWDEVICE_TYPE_DXVA2; + pix_fmt = AV_PIX_FMT_DXVA2_VLD; + hw_handle_supported = 1; +#endif + } + + if (hw_handle_supported) { + err = MFXVideoCORE_GetHandle(hwctx->session, handle_type, &s->handle); + if (err == MFX_ERR_NONE) { + s->handle_type = handle_type; + s->child_device_type = device_type; + s->child_pix_fmt = pix_fmt; + } + } + if (!s->handle) { + av_log(ctx, AV_LOG_VERBOSE, "No supported hw handle could be retrieved " + "from the session\n"); + } return 0; } @@ -175,6 +207,7 @@ static void qsv_frames_uninit(AVHWFramesContext *ctx) av_freep(&s->mem_ids); av_freep(&s->surface_ptrs); av_freep(&s->surfaces_internal); + av_freep(&s->handle_pairs_internal); av_buffer_unref(&s->child_frames_ref); } @@ -190,6 +223,8 @@ static AVBufferRef *qsv_pool_alloc(void *opaque, int size) if (s->nb_surfaces_used < hwctx->nb_surfaces) { s->nb_surfaces_used++; + av_buffer_create((uint8_t*)(s->handle_pairs_internal + s->nb_surfaces_used - 1), + sizeof(*s->handle_pairs_internal), qsv_pool_release_dummy, NULL, 0); return av_buffer_create((uint8_t*)(s->surfaces_internal + s->nb_surfaces_used - 1), sizeof(*hwctx->surfaces), qsv_pool_release_dummy, NULL, 0); } @@ -229,6 +264,13 @@ 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; @@ -255,6 +297,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; + if (hwctx->frame_type == 0) + hwctx->frame_type = MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET; + if (hwctx->frame_type & MFX_MEMTYPE_SHARED_RESOURCE) + child_frames_hwctx->MiscFlags = D3D11_RESOURCE_MISC_SHARED; + child_frames_hwctx->BindFlags = qsv_get_d3d11va_bind_flags(hwctx->frame_type); + } +#endif #if CONFIG_DXVA2 if (child_device_ctx->type == AV_HWDEVICE_TYPE_DXVA2) { AVDXVA2FramesContext *child_frames_hwctx = child_frames_ctx->hwctx; @@ -279,11 +331,33 @@ 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; + for (i = 0; i < ctx->initial_pool_size; i++) { + s->handle_pairs_internal[i].first = (mfxMemId)child_frames_hwctx->texture_infos[i].texture; + if(child_frames_hwctx->BindFlags & D3D11_BIND_RENDER_TARGET) { + s->handle_pairs_internal[i].second = (mfxMemId)MFX_INFINITE; + } else { + s->handle_pairs_internal[i].second = (mfxMemId)child_frames_hwctx->texture_infos[i].index; + } + s->surfaces_internal[i].Data.MemId = (mfxMemId)&s->handle_pairs_internal[i]; + } + if (child_frames_hwctx->BindFlags & D3D11_BIND_RENDER_TARGET) { + hwctx->frame_type |= MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET; + } else { + hwctx->frame_type |= MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET; + } + } +#endif #if CONFIG_DXVA2 if (child_device_ctx->type == AV_HWDEVICE_TYPE_DXVA2) { AVDXVA2FramesContext *child_frames_hwctx = child_frames_ctx->hwctx; - for (i = 0; i < ctx->initial_pool_size; i++) - s->surfaces_internal[i].Data.MemId = (mfxMemId)child_frames_hwctx->surfaces[i]; + for (i = 0; i < ctx->initial_pool_size; i++) { + s->handle_pairs_internal[i].first = (mfxMemId)child_frames_hwctx->surfaces[i]; + s->handle_pairs_internal[i].second = (mfxMemId)MFX_INFINITE; + s->surfaces_internal[i].Data.MemId = (mfxMemId)&s->handle_pairs_internal[i]; + } if (child_frames_hwctx->surface_type == DXVA2_VideoProcessorRenderTarget) hwctx->frame_type = MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET; else @@ -348,6 +422,11 @@ static int qsv_init_pool(AVHWFramesContext *ctx, uint32_t fourcc) return AVERROR(EINVAL); } + s->handle_pairs_internal = av_mallocz_array(ctx->initial_pool_size, + sizeof(*s->handle_pairs_internal)); + if (!s->handle_pairs_internal) + return AVERROR(ENOMEM); + s->surfaces_internal = av_mallocz_array(ctx->initial_pool_size, sizeof(*s->surfaces_internal)); if (!s->surfaces_internal) @@ -421,7 +500,17 @@ static mfxStatus frame_unlock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr) static mfxStatus frame_get_hdl(mfxHDL pthis, mfxMemId mid, mfxHDL *hdl) { +#if CONFIG_VAAPI *hdl = mid; +#else + mfxHDLPair *pair_dst = (mfxHDLPair*)hdl; + mfxHDLPair *pair_src = (mfxHDLPair*)mid; + + pair_dst->first = pair_src->first; + + if (pair_src->second != (mfxMemId)MFX_INFINITE) + pair_dst->second = pair_src->second; +#endif return MFX_ERR_NONE; } @@ -621,6 +710,18 @@ static int qsv_frames_derive_from(AVHWFramesContext *dst_ctx, } break; #endif +#if CONFIG_D3D11VA + case AV_HWDEVICE_TYPE_D3D11VA: + { + AVD3D11VAFramesContext *dst_hwctx = dst_ctx->hwctx; + mfxHDLPair *pair = (mfxHDLPair*)src_hwctx->surfaces[i].Data.MemId; + dst_hwctx->texture = (ID3D11Texture2D*)pair->first; + if (src_hwctx->frame_type & MFX_MEMTYPE_SHARED_RESOURCE) + dst_hwctx->MiscFlags = D3D11_RESOURCE_MISC_SHARED; + dst_hwctx->BindFlags = qsv_get_d3d11va_bind_flags(src_hwctx->frame_type); + } + break; +#endif #if CONFIG_DXVA2 case AV_HWDEVICE_TYPE_DXVA2: { @@ -629,9 +730,10 @@ static int qsv_frames_derive_from(AVHWFramesContext *dst_ctx, sizeof(*dst_hwctx->surfaces)); if (!dst_hwctx->surfaces) return AVERROR(ENOMEM); - for (i = 0; i < src_hwctx->nb_surfaces; i++) - dst_hwctx->surfaces[i] = - (IDirect3DSurface9*)src_hwctx->surfaces[i].Data.MemId; + for (i = 0; i < src_hwctx->nb_surfaces; i++) { + mfxHDLPair *pair = (mfxHDLPair*)src_hwctx->surfaces[i].Data.MemId; + dst_hwctx->surfaces[i] = (IDirect3DSurface9*)pair->first; + } dst_hwctx->nb_surfaces = src_hwctx->nb_surfaces; if (src_hwctx->frame_type == MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET) dst_hwctx->surface_type = DXVA2_VideoDecoderRenderTarget; @@ -668,10 +770,21 @@ 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: + { + mfxHDLPair *pair = (mfxHDLPair*)surf->Data.MemId; + child_data = pair->first; + break; + } +#endif #if CONFIG_DXVA2 case AV_HWDEVICE_TYPE_DXVA2: - child_data = surf->Data.MemId; + { + mfxHDLPair *pair = (mfxHDLPair*)surf->Data.MemId; + child_data = pair->first; break; + } #endif default: return AVERROR(ENOSYS); @@ -685,7 +798,14 @@ static int qsv_map_from(AVHWFramesContext *ctx, dst->width = src->width; dst->height = src->height; - dst->data[3] = child_data; + + if (child_frames_ctx->device_ctx->type == AV_HWDEVICE_TYPE_D3D11VA) { + mfxHDLPair *pair = (mfxHDLPair*)surf->Data.MemId; + dst->data[0] = pair->first; + dst->data[1] = pair->second; + } else { + dst->data[3] = child_data; + } return 0; } @@ -708,7 +828,14 @@ static int qsv_map_from(AVHWFramesContext *ctx, dummy->format = child_frames_ctx->format; dummy->width = src->width; dummy->height = src->height; - dummy->data[3] = child_data; + + if (child_frames_ctx->device_ctx->type == AV_HWDEVICE_TYPE_D3D11VA) { + mfxHDLPair *pair = (mfxHDLPair*)surf->Data.MemId; + dummy->data[0] = pair->first; + dummy->data[1] = pair->second; + } else { + dummy->data[3] = child_data; + } ret = av_hwframe_map(dst, dummy, flags); @@ -954,6 +1081,12 @@ static int qsv_frames_derive_to(AVHWFramesContext *dst_ctx, AVQSVFramesContext *dst_hwctx = dst_ctx->hwctx; int i; + if (src_ctx->initial_pool_size == 0) { + av_log(dst_ctx, AV_LOG_ERROR, "Only fixed-size pools can be " + "mapped to QSV frames.\n"); + return AVERROR(EINVAL); + } + switch (src_ctx->device_ctx->type) { #if CONFIG_VAAPI case AV_HWDEVICE_TYPE_VAAPI: @@ -972,6 +1105,36 @@ 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->handle_pairs_internal = av_mallocz_array(src_ctx->initial_pool_size, sizeof(*s->handle_pairs_internal)); + if (!s->handle_pairs_internal) + return AVERROR(ENOMEM); + s->surfaces_internal = av_mallocz_array(src_ctx->initial_pool_size, + sizeof(*s->surfaces_internal)); + if (!s->surfaces_internal) + return AVERROR(ENOMEM); + for (i = 0; i < src_ctx->initial_pool_size; i++) { + qsv_init_surface(dst_ctx, &s->surfaces_internal[i]); + s->handle_pairs_internal[i].first = (mfxMemId)src_hwctx->texture_infos[i].texture; + if (src_hwctx->BindFlags & D3D11_BIND_RENDER_TARGET) { + s->handle_pairs_internal[i].second = (mfxMemId)MFX_INFINITE; + } else { + s->handle_pairs_internal[i].second = (mfxMemId)src_hwctx->texture_infos[i].index; + } + s->surfaces_internal[i].Data.MemId = (mfxMemId)&s->handle_pairs_internal[i]; + } + dst_hwctx->nb_surfaces = src_ctx->initial_pool_size; + if (src_hwctx->BindFlags & D3D11_BIND_RENDER_TARGET) { + dst_hwctx->frame_type |= MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET; + } else { + dst_hwctx->frame_type |= MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET; + } + } + break; +#endif #if CONFIG_DXVA2 case AV_HWDEVICE_TYPE_DXVA2: { @@ -982,7 +1145,9 @@ static int qsv_frames_derive_to(AVHWFramesContext *dst_ctx, return AVERROR(ENOMEM); for (i = 0; i < src_hwctx->nb_surfaces; i++) { qsv_init_surface(dst_ctx, &s->surfaces_internal[i]); - s->surfaces_internal[i].Data.MemId = (mfxMemId)src_hwctx->surfaces[i]; + s->handle_pairs_internal[i].first = (mfxMemId)src_hwctx->surfaces[i]; + s->handle_pairs_internal[i].second = (mfxMemId)MFX_INFINITE; + s->surfaces_internal[i].Data.MemId = (mfxMemId)&s->handle_pairs_internal[i]; } dst_hwctx->nb_surfaces = src_hwctx->nb_surfaces; if (src_hwctx->surface_type == DXVA2_VideoProcessorRenderTarget) @@ -1005,21 +1170,41 @@ static int qsv_map_to(AVHWFramesContext *dst_ctx, AVFrame *dst, const AVFrame *src, int flags) { AVQSVFramesContext *hwctx = dst_ctx->hwctx; - int i, err; + int i, err, index = -1; - for (i = 0; i < hwctx->nb_surfaces; i++) { + for (i = 0; i < hwctx->nb_surfaces && index < 0; i++) { + switch(src->format) { #if CONFIG_VAAPI - if (*(VASurfaceID*)hwctx->surfaces[i].Data.MemId == - (VASurfaceID)(uintptr_t)src->data[3]) + case AV_PIX_FMT_VAAPI: + if (*(VASurfaceID*)hwctx->surfaces[i].Data.MemId == + (VASurfaceID)(uintptr_t)src->data[3]) + index = i; break; #endif +#if CONFIG_D3D11VA + case AV_PIX_FMT_D3D11: + { + mfxHDLPair *pair = (mfxHDLPair*)hwctx->surfaces[i].Data.MemId; + if (pair->first == src->data[0] + && pair->second == src->data[1]) { + index = i; + break; + } + } +#endif #if CONFIG_DXVA2 - if ((IDirect3DSurface9*)hwctx->surfaces[i].Data.MemId == - (IDirect3DSurface9*)(uintptr_t)src->data[3]) - break; + case AV_PIX_FMT_DXVA2_VLD: + { + mfxHDLPair *pair = (mfxHDLPair*)hwctx->surfaces[i].Data.MemId; + if (pair->first == src->data[3]) { + index = i; + break; + } + } #endif + } } - if (i >= hwctx->nb_surfaces) { + if (index < 0) { av_log(dst_ctx, AV_LOG_ERROR, "Trying to map from a surface which " "is not in the mapped frames context.\n"); return AVERROR(EINVAL); @@ -1032,7 +1217,7 @@ static int qsv_map_to(AVHWFramesContext *dst_ctx, dst->width = src->width; dst->height = src->height; - dst->data[3] = (uint8_t*)&hwctx->surfaces[i]; + dst->data[3] = (uint8_t*)&hwctx->surfaces[index]; return 0; } @@ -1074,7 +1259,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 +1288,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 +1318,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: { @@ -1191,7 +1389,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); } @@ -1214,35 +1414,66 @@ static int qsv_device_create(AVHWDeviceContext *ctx, const char *device, ctx->user_opaque = priv; ctx->free = qsv_device_free; - e = av_dict_get(opts, "child_device", NULL, 0); - - child_device_opts = NULL; - if (CONFIG_VAAPI) { + e = av_dict_get(opts, "child_device_type", NULL, 0); + if (e) { + child_device_type = av_hwdevice_find_type_by_name(e ? e->value : NULL); + if (child_device_type == AV_HWDEVICE_TYPE_NONE) { + av_log(ctx, AV_LOG_ERROR, "Unknown child device type " + "\"%s\".\n", e ? e->value : NULL); + return AVERROR(EINVAL); + } + } else if (CONFIG_VAAPI) { child_device_type = AV_HWDEVICE_TYPE_VAAPI; - // libmfx does not actually implement VAAPI properly, rather it - // depends on the specific behaviour of a matching iHD driver when - // used on recent Intel hardware. Set options to the VAAPI device - // creation so that we should pick a usable setup by default if - // 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; + } 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); } + child_device_opts = NULL; + switch (child_device_type) { +#if CONFIG_VAAPI + case AV_HWDEVICE_TYPE_VAAPI: + { + // libmfx does not actually implement VAAPI properly, rather it + // depends on the specific behaviour of a matching iHD driver when + // used on recent Intel hardware. Set options to the VAAPI device + // creation so that we should pick a usable setup by default if + // 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); + } + break; +#endif +#if CONFIG_D3D11VA + case AV_HWDEVICE_TYPE_D3D11VA: + break; +#endif +#if CONFIG_DXVA2 + case AV_HWDEVICE_TYPE_DXVA2: + break; +#endif + default: + { + av_log(ctx, AV_LOG_ERROR, "No supported child device type is enabled\n"); + return AVERROR(ENOSYS); + } + break; + } + + e = av_dict_get(opts, "child_device", NULL, 0); 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; 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); }