diff mbox

[FFmpeg-devel] libavcodec/amfenc.h: Added engine selection support for AMFContext initialisation.

Message ID 20191029135745.24680-1-ovchinnikov.dmitrii@gmail.com
State New
Headers show

Commit Message

Дмитрий Овчинников Oct. 29, 2019, 1:57 p.m. UTC
---
 libavcodec/amfenc.c      | 93 +++++++++++++++++++++++++++++++---------
 libavcodec/amfenc.h      |  8 ++++
 libavcodec/amfenc_h264.c |  6 +++
 libavcodec/amfenc_hevc.c |  6 +++
 4 files changed, 93 insertions(+), 20 deletions(-)
diff mbox

Patch

diff --git a/libavcodec/amfenc.c b/libavcodec/amfenc.c
index f66b95645e..a89e14f6cd 100644
--- a/libavcodec/amfenc.c
+++ b/libavcodec/amfenc.c
@@ -210,10 +210,54 @@  static int amf_init_from_dxva2_device(AVCodecContext *avctx, AVDXVA2DeviceContex
 }
 #endif
 
-static int amf_init_context(AVCodecContext *avctx)
+static AMF_RESULT amf_context_init_d3d11(AVCodecContext *avctx)
 {
+    AMF_RESULT res;
+    AmfContext *ctx = avctx->priv_data;
+    res = ctx->context->pVtbl->InitDX11(ctx->context, NULL, AMF_DX11_1);
+    if (res == AMF_OK) {
+        av_log(avctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via D3D11.\n");
+    }
+    return res;
+}
+
+static AMF_RESULT amf_context_init_dxva2(AVCodecContext *avctx)
+{
+    AMF_RESULT res;
+    AmfContext *ctx = avctx->priv_data;
+    res = ctx->context->pVtbl->InitDX9(ctx->context, NULL);
+    if (res == AMF_OK) {
+        av_log(avctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via dxva2.\n");
+    }
+    return res;
+}
+
+static AMF_RESULT amf_context_init_vulkan(AVCodecContext *avctx)
+{
+    AMF_RESULT res;
     AmfContext *ctx = avctx->priv_data;
     AMFContext1 *context1 = NULL;
+    AMFGuid guid = IID_AMFContext1();
+
+    res = ctx->context->pVtbl->QueryInterface(ctx->context, &guid, (void**)&context1);
+    AMF_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);
+    if (res != AMF_OK) {
+        if (res == AMF_NOT_SUPPORTED)
+            av_log(avctx, AV_LOG_ERROR, "AMF via Vulkan is not supported on the given device.\n");
+        else
+            av_log(avctx, AV_LOG_ERROR, "AMF failed to initialise on the given Vulkan device: %d.\n", res);
+        return AMF_FAIL;
+    }
+    av_log(avctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via Vulkan.\n");
+    return res;
+}
+
+static int amf_init_context(AVCodecContext *avctx)
+{
+    AmfContext *ctx = avctx->priv_data;
     AMF_RESULT  res;
     av_unused int ret;
 
@@ -304,30 +348,39 @@  static int amf_init_context(AVCodecContext *avctx)
             return AVERROR(ENOMEM);
 
     } else {
-        res = ctx->context->pVtbl->InitDX11(ctx->context, NULL, AMF_DX11_1);
-        if (res == AMF_OK) {
-            av_log(avctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via D3D11.\n");
-        } else {
-            res = ctx->context->pVtbl->InitDX9(ctx->context, NULL);
-            if (res == AMF_OK) {
-                av_log(avctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via D3D9.\n");
-            } else {
-                AMFGuid guid = IID_AMFContext1();
-                res = ctx->context->pVtbl->QueryInterface(ctx->context, &guid, (void**)&context1);
-                AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "CreateContext1() failed with error %d\n", res);
+        res = AMF_FAIL;
+        switch (ctx->engine) {
+        case AMF_VIDEO_ENCODER_ENGINE_D3D11:
+            res = amf_context_init_d3d11(avctx);
+            break;
+        case AMF_VIDEO_ENCODER_ENGINE_DXVA2:
+            res = amf_context_init_dxva2(avctx);
+            break;
+        case AMF_VIDEO_ENCODER_ENGINE_VULKAN:
+            res = amf_context_init_vulkan(avctx);
+            break;
+        default:
+            break;
+        }
+        if (res != AMF_OK) {
+            if (ctx->engine != AMF_VIDEO_ENCODER_ENGINE_DEFAULT)
+                av_log(avctx, AV_LOG_ERROR, "AMF failed to initialise via preffered engine\n");
+
+            if (ctx->engine != AMF_VIDEO_ENCODER_ENGINE_D3D11)
+                res = amf_context_init_d3d11(avctx);
 
-                res = context1->pVtbl->InitVulkan(context1, NULL);
-                context1->pVtbl->Release(context1);
+            if (res != AMF_OK) {
+                if (ctx->engine != AMF_VIDEO_ENCODER_ENGINE_DXVA2)
+                    res = amf_context_init_dxva2(avctx);
                 if (res != AMF_OK) {
-                    if (res == AMF_NOT_SUPPORTED)
-                        av_log(avctx, AV_LOG_ERROR, "AMF via Vulkan is not supported on the given device.\n");
-                    else
-                        av_log(avctx, AV_LOG_ERROR, "AMF failed to initialise on the given Vulkan device: %d.\n", res);
-                    return AVERROR(ENOSYS);
+                    if (ctx->engine != AMF_VIDEO_ENCODER_ENGINE_VULKAN)
+                        res = amf_context_init_vulkan(avctx);
                 }
-                av_log(avctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via Vulkan.\n");
             }
         }
+        if (res != AMF_OK) {
+            return AVERROR(ENOSYS);
+        }
     }
     return 0;
 }
diff --git a/libavcodec/amfenc.h b/libavcodec/amfenc.h
index b1361842bd..8cfb4776cf 100644
--- a/libavcodec/amfenc.h
+++ b/libavcodec/amfenc.h
@@ -28,6 +28,13 @@ 
 
 #include "avcodec.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
+};
 
 /**
 * AMF trace writer callback class
@@ -86,6 +93,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 7f2817f115..79431942f6 100644
--- a/libavcodec/amfenc_h264.c
+++ b/libavcodec/amfenc_h264.c
@@ -71,6 +71,12 @@  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" },
 
+    /// 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",          "Direct3D11",                           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" },
+
     // 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 7c9a33ab33..d42a9b6ff9 100644
--- a/libavcodec/amfenc_hevc.c
+++ b/libavcodec/amfenc_hevc.c
@@ -58,6 +58,12 @@  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" },
 
+    /// 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",          "Direct3D11",                           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" },
+
     { "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" },