On 15/10/2020 01:16, OvchinnikovDmitrii wrote:
---
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(-)
Why? Given that you are already initialising from a specific device when one
is given, what does this actually change?
(With patch 1 you can do "ffmpeg ... -init_hw_device d3d11:3 ... -c:v h264_amf
..." and it picks up the device you asked for.)
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
Doesn't seem obviously Windows-dependent?
+ 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
The presence of options shouldn't be platform dependent, even if they don't
actually get used in other places.
Also, "preferred" is normally spelled with one 'f' and two 'r's (also in more
places below).
+
// 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
Can this be common rather than duplicated? It doesn't have the crazy option
dependency on the codec like all of the AMF options.
+
{ "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) {
What is the intent of the fallback? If you asked for a particular backend then
presumably you had a reason for that.
+ 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 enum would need namespacing. I suspect that passing strings around would be simpler
and easier to reason about (e.g. "ffmpeg -init_hw_device amf:,engine=d3d11").
/**
* This struct is allocated as AVHWDeviceContext.hwctx
- Mark
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".