[FFmpeg-devel] [PATCH 4/5] lavu/hwcontext_amf: Engine selection support for AMF context
OvchinnikovDmitrii
ovchinnikov.dmitrii at gmail.com
Thu Oct 15 03:16:24 EEST 2020
---
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 <dlfcn.h>
#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
--
2.19.1.windows.1
More information about the ffmpeg-devel
mailing list