From patchwork Thu Oct 15 00:16:24 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitrii Ovchinnikov X-Patchwork-Id: 22960 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 EC5B744A83F for ; Thu, 15 Oct 2020 03:22:13 +0300 (EEST) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id D235468B9F9; Thu, 15 Oct 2020 03:22:13 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-lf1-f66.google.com (mail-lf1-f66.google.com [209.85.167.66]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id BAF9A68B941 for ; Thu, 15 Oct 2020 03:22:06 +0300 (EEST) Received: by mail-lf1-f66.google.com with SMTP id l28so1450891lfp.10 for ; Wed, 14 Oct 2020 17:22:06 -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=k2juirwkQREguJJBaw33lMzdT9waSXVEFOp91m1k7i8=; b=BFN0AeTKwFizLPKPEzRSsAYpYC+PkSr5sh+xuh1jxEGNLB3XvGd/vVoVx+AF1tzvBc Ec9mLX8iGM5VwuTyw4uLJTnGJL22WeA7AFn3r9JxTvKTppjpO9uR7nahWYlm7mxSFZSO xyZrXz5T+M/tBynVXXW00g3ZMSR3nwBXuUMIKnhKd3aIr/wBx/9oNQJrJUynDtEIgBpv tywMLxl8xbPD91h4jDHUYpgGu8d23YRNFAYX4JYp3HClS9iZzC7RZEFM1bUnVEghHs9s HR5tiv37Mn92mQasf1T2lN0jeH2nHESswCZioP7sNF9ZV/mS6r/rm9hTPIbiOnOvWXST gxuw== 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=k2juirwkQREguJJBaw33lMzdT9waSXVEFOp91m1k7i8=; b=sDpuLSG7SzpCLc7J5MBbQYFHTUwkLFPxoKHlM9wbg8v3IpIKjtodG1tCI6J6n9ss1o 6KrrFCnvGR+2LWmaWikzUROl0CXPy9byaTweqMO9oCHg57oTxEV+x70i9eYr4Ac5Xk68 HcUrZ139y7qgZ4mvSnF9uEr8sMxcB7yz6GQErN3HCSzZswjPE1EqoRxd6QfdV9CTnCUs 7X6t0e2GxBi7BhWbVX/sqHUJ1Yh7fTGl5ykP2G1BAyoKcwcXCD8+dyiEyjlgrJYpjQbq 1QhKSt/warBY0wYPPE1W1GEAZ4JJ1UGkWYqb1QI7BUuMDtcPRSoLQhifZmkieCZWx0Ws GLiA== X-Gm-Message-State: AOAM530RsbVlB0C3deDaLfRikMRU4z/9jCKYY1s8lVURlCeCRCW356vx 7H4ZnuK3G2/LjblF3nMN/Ahh7wzbk6gLHA== X-Google-Smtp-Source: ABdhPJxB1/MDo7d+lSi+MWAFeownt7EIGIt7MzkwXX4wceaTtA/uYNlVYV8GCqlfL6sMkTY2S6TSwQ== X-Received: by 2002:a05:651c:543:: with SMTP id q3mr231333ljp.6.1602721001496; Wed, 14 Oct 2020 17:16:41 -0700 (PDT) Received: from localhost.localdomain (95-55-4-47.dynamic.avangarddsl.ru. [95.55.4.47]) by smtp.googlemail.com with ESMTPSA id q20sm333291lfp.43.2020.10.14.17.16.40 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 14 Oct 2020 17:16:40 -0700 (PDT) From: OvchinnikovDmitrii To: ffmpeg-devel@ffmpeg.org Date: Thu, 15 Oct 2020 03:16:24 +0300 Message-Id: <20201015001625.32832-4-ovchinnikov.dmitrii@gmail.com> X-Mailer: git-send-email 2.19.1.windows.1 In-Reply-To: <20201015001625.32832-1-ovchinnikov.dmitrii@gmail.com> References: <20201015001625.32832-1-ovchinnikov.dmitrii@gmail.com> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 4/5] lavu/hwcontext_amf: Engine selection support for AMF context 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: OvchinnikovDmitrii Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" --- libavcodec/amfenc.c | 9 +++- libavcodec/amfenc.h | 1 + libavcodec/amfenc_h264.c | 8 +++ libavcodec/amfenc_hevc.c | 8 +++ libavutil/hwcontext_amf.c | 104 ++++++++++++++++++++++++++++++-------- libavutil/hwcontext_amf.h | 7 +++ 6 files changed, 116 insertions(+), 21 deletions(-) diff --git a/libavcodec/amfenc.c b/libavcodec/amfenc.c index 767eab3d56..b7eb74811b 100644 --- a/libavcodec/amfenc.c +++ b/libavcodec/amfenc.c @@ -82,6 +82,7 @@ static int amf_init_context(AVCodecContext *avctx) { AmfContext *ctx = avctx->priv_data; AVAMFDeviceContext *amf_ctx; + AVDictionary *dict = NULL; int ret; ctx->delayed_frame = av_frame_alloc(); @@ -123,10 +124,16 @@ static int amf_init_context(AVCodecContext *avctx) if (ret < 0) return ret; } else { - ret = av_hwdevice_ctx_create(&ctx->amf_device_ctx, AV_HWDEVICE_TYPE_AMF, NULL, NULL, 0); +#if defined(_WIN32) + if (ctx->engine) { + ret = av_dict_set_int(&dict, "engine", ctx->engine, 0); if (ret < 0) return ret; } +#endif + ret = av_hwdevice_ctx_create(&ctx->amf_device_ctx, AV_HWDEVICE_TYPE_AMF, NULL, dict, 0);if (ret < 0) + return ret; + } amf_ctx = ((AVHWDeviceContext*)ctx->amf_device_ctx->data)->hwctx; ctx->context = amf_ctx->context; ctx->factory = amf_ctx->factory; diff --git a/libavcodec/amfenc.h b/libavcodec/amfenc.h index 96d1942a37..f4897c9b2a 100644 --- a/libavcodec/amfenc.h +++ b/libavcodec/amfenc.h @@ -73,6 +73,7 @@ typedef struct AmfContext { int quality; int b_frame_delta_qp; int ref_b_frame_delta_qp; + int engine; // Dynamic options, can be set after Init() call diff --git a/libavcodec/amfenc_h264.c b/libavcodec/amfenc_h264.c index 622ee85946..9fb42323d8 100644 --- a/libavcodec/amfenc_h264.c +++ b/libavcodec/amfenc_h264.c @@ -71,6 +71,14 @@ static const AVOption options[] = { { "balanced", "Balanced", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_QUALITY_PRESET_BALANCED }, 0, 0, VE, "quality" }, { "quality", "Prefer Quality", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_QUALITY_PRESET_QUALITY }, 0, 0, VE, "quality" }, +#if defined(_WIN32) +//preffered engine + { "engine", "Preffered engine", OFFSET(engine), AV_OPT_TYPE_INT, { .i64 = AMF_VIDEO_ENCODER_ENGINE_DEFAULT }, AMF_VIDEO_ENCODER_ENGINE_DEFAULT, AMF_VIDEO_ENCODER_ENGINE_VULKAN, VE, "engine" }, + { "dxva2", "DirectX Video Acceleration 2", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_ENGINE_DXVA2 }, 0, 0, VE, "engine" }, + { "d3d11", "Direct2D11", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_ENGINE_D3D11 }, 0, 0, VE, "engine" }, + { "vulkan", "Vulkan", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_ENGINE_VULKAN }, 0, 0, VE, "engine" }, +#endif + // Dynamic /// Rate Control Method { "rc", "Rate Control Method", OFFSET(rate_control_mode), AV_OPT_TYPE_INT, { .i64 = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_UNKNOWN }, AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_UNKNOWN, AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR, VE, "rc" }, diff --git a/libavcodec/amfenc_hevc.c b/libavcodec/amfenc_hevc.c index bb224c5fec..fc2c40a6ed 100644 --- a/libavcodec/amfenc_hevc.c +++ b/libavcodec/amfenc_hevc.c @@ -58,6 +58,14 @@ static const AVOption options[] = { { "speed", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_SPEED }, 0, 0, VE, "quality" }, { "quality", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_QUALITY }, 0, 0, VE, "quality" }, +#if defined(_WIN32) +//preffered engine + { "engine", "Preffered engine", OFFSET(engine), AV_OPT_TYPE_INT, { .i64 = AMF_VIDEO_ENCODER_ENGINE_DEFAULT }, AMF_VIDEO_ENCODER_ENGINE_DEFAULT, AMF_VIDEO_ENCODER_ENGINE_VULKAN, VE, "engine" }, + { "dxva2", "DirectX Video Acceleration 2", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_ENGINE_DXVA2 }, 0, 0, VE, "engine" }, + { "d3d11", "Direct2D11", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_ENGINE_D3D11 }, 0, 0, VE, "engine" }, + { "vulkan", "Vulkan", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_ENGINE_VULKAN }, 0, 0, VE, "engine" }, +#endif + { "rc", "Set the rate control mode", OFFSET(rate_control_mode), AV_OPT_TYPE_INT, { .i64 = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_UNKNOWN }, AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_UNKNOWN, AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CBR, VE, "rc" }, { "cqp", "Constant Quantization Parameter", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CONSTANT_QP }, 0, 0, VE, "rc" }, { "cbr", "Constant Bitrate", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CBR }, 0, 0, VE, "rc" }, diff --git a/libavutil/hwcontext_amf.c b/libavutil/hwcontext_amf.c index b70ee90d40..faae57dda3 100644 --- a/libavutil/hwcontext_amf.c +++ b/libavutil/hwcontext_amf.c @@ -41,6 +41,7 @@ #else #include #endif +#include "libavutil/opt.h" /** * Error handling helper @@ -151,6 +152,51 @@ static int amf_init_device_ctx_object(AVHWDeviceContext *ctx) return 0; } +static AMF_RESULT amf_context_init_d3d11(AVHWDeviceContext * avctx) +{ + AMF_RESULT res; + AVAMFDeviceContext * ctx = avctx->hwctx; + res = ctx->context->pVtbl->InitDX11(ctx->context, NULL, AMF_DX11_1); + if (res == AMF_OK){ + av_log(avctx, AV_LOG_VERBOSE, "AMF initialisation successed via D3D11.\n"); + } + return res; +} + +static AMF_RESULT amf_context_init_dxva2(AVHWDeviceContext * avctx) +{ + AMF_RESULT res; + AVAMFDeviceContext * ctx = avctx->hwctx; + res = ctx->context->pVtbl->InitDX9(ctx->context, NULL); + if (res == AMF_OK){ + av_log(avctx, AV_LOG_VERBOSE, "AMF initialisation successed via DXVA2.\n"); + } + return res; +} + +static AMF_RESULT amf_context_init_vulkan(AVHWDeviceContext * avctx) +{ + AMF_RESULT res; + AVAMFDeviceContext * ctx = avctx->hwctx; + AMFContext1 *context1 = NULL; + AMFGuid guid = IID_AMFContext1(); + + res = ctx->context->pVtbl->QueryInterface(ctx->context, &guid, (void**)&context1); + AMFAV_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "CreateContext1() fialed with error %d\n", res); + + res = context1->pVtbl->InitVulkan(context1, NULL); + context1->pVtbl->Release(context1); + if (res != AMF_OK){ + if (res == AMF_NOT_SUPPORTED) + av_log(avctx, AV_LOG_VERBOSE, "AMF via vulkan is not supported on the given device.\n"); + else + av_log(avctx, AV_LOG_VERBOSE, "AMF failed to initialise on the given vulkan device. %d.\n", res); + return AMF_FAIL; + } + av_log(avctx, AV_LOG_VERBOSE, "AMF initialisation successed via vulkan.\n"); + return res; +} + static int amf_device_create(AVHWDeviceContext *ctx, const char *device, AVDictionary *opts, int flags) { @@ -158,35 +204,53 @@ static int amf_device_create(AVHWDeviceContext *ctx, const char *device, AMFContext1 *context1 = NULL; AMF_RESULT res; int err; + AVDictionaryEntry *e; + int preffered_engine = AMF_VIDEO_ENCODER_ENGINE_DEFAULT; err = amf_init_device_ctx_object(ctx); if(err < 0) return err; - res = amf_ctx->context->pVtbl->InitDX11(amf_ctx->context, NULL, AMF_DX11_1); - if (res == AMF_OK) { - av_log(ctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via D3D11.\n"); - } else { - res = amf_ctx->context->pVtbl->InitDX9(amf_ctx->context, NULL); - if (res == AMF_OK) { - av_log(ctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via D3D9.\n"); - } else { - AMFGuid guid = IID_AMFContext1(); - res = amf_ctx->context->pVtbl->QueryInterface(amf_ctx->context, &guid, (void**)&context1); - AMFAV_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "CreateContext1() failed with error %d\n", res); - - res = context1->pVtbl->InitVulkan(context1, NULL); - context1->pVtbl->Release(context1); + e = av_dict_get(opts, "engine", NULL, 0); + if (!!e) { + preffered_engine = atoi(e->value); + } + + res = AMF_FAIL; + switch(preffered_engine) { + case AMF_VIDEO_ENCODER_ENGINE_D3D11: + res = amf_context_init_d3d11(ctx); + break; + case AMF_VIDEO_ENCODER_ENGINE_DXVA2: + res = amf_context_init_dxva2(ctx); + break; + case AMF_VIDEO_ENCODER_ENGINE_VULKAN: + res = amf_context_init_vulkan(ctx); + break; + default: + break; + } + if (res != AMF_OK) { + if (preffered_engine != AMF_VIDEO_ENCODER_ENGINE_DEFAULT) + av_log(ctx, AV_LOG_ERROR, "AMF failed to initialise via preffered engine.\n"); + + if (preffered_engine != AMF_VIDEO_ENCODER_ENGINE_D3D11)//already tried in switch case + res = amf_context_init_d3d11(ctx); + + if (res != AMF_OK) { + if (preffered_engine != AMF_VIDEO_ENCODER_ENGINE_DXVA2) + res = amf_context_init_dxva2(ctx); + if (res != AMF_OK) { - if (res == AMF_NOT_SUPPORTED) - av_log(ctx, AV_LOG_ERROR, "AMF via Vulkan is not supported on the given device.\n"); - else - av_log(ctx, AV_LOG_ERROR, "AMF failed to initialise on the given Vulkan device: %d.\n", res); - return AVERROR(ENOSYS); + if (preffered_engine != AMF_VIDEO_ENCODER_ENGINE_VULKAN) + res = amf_context_init_vulkan(ctx); } - av_log(ctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via Vulkan.\n"); } } + + if (res != AMF_OK) { + return AVERROR(ENOSYS); + } return 0; } diff --git a/libavutil/hwcontext_amf.h b/libavutil/hwcontext_amf.h index ae2a37f425..82e2ce7abb 100644 --- a/libavutil/hwcontext_amf.h +++ b/libavutil/hwcontext_amf.h @@ -30,6 +30,13 @@ #include "AMF/core/Context.h" #include "AMF/core/Factory.h" +enum AMF_VIDEO_ENCODER_PREFFERED_ENGINE +{ + AMF_VIDEO_ENCODER_ENGINE_DEFAULT = 0, + AMF_VIDEO_ENCODER_ENGINE_DXVA2, + AMF_VIDEO_ENCODER_ENGINE_D3D11, + AMF_VIDEO_ENCODER_ENGINE_VULKAN +}; /** * This struct is allocated as AVHWDeviceContext.hwctx