PR #24442 opened by DmitriiGershenkop
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24442
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24442.patch

AMF implementation in ffmpeg has a lot of dead code related to DirectX 12 
support. This patch makes the code at least somewhat useful by fixing DX12 
derive for AMF.


>From 715fb2811b95764563add81d50a6660849bf1338 Mon Sep 17 00:00:00 2001
From: Dmitrii Gershenkop <[email protected]>
Date: Wed, 9 Sep 2026 18:16:29 +0200
Subject: [PATCH] av{codec, util}/hwcontext_amf: Fix DX12 => AMF Derive

AMF implementation in ffmpeg has a lot of dead code related to DirectX 12 
support. This patch makes the code at least somewhat useful.
---
 libavcodec/amfenc.c       | 30 ++++++++++++++++++
 libavutil/hwcontext_amf.c | 65 +++++++++++++++++++++++++++++++--------
 2 files changed, 82 insertions(+), 13 deletions(-)

diff --git a/libavcodec/amfenc.c b/libavcodec/amfenc.c
index 3ffca750d8..71db6d7725 100644
--- a/libavcodec/amfenc.c
+++ b/libavcodec/amfenc.c
@@ -22,6 +22,11 @@
 #include "libavutil/imgutils.h"
 #include "libavutil/hwcontext.h"
 #include "libavutil/hwcontext_amf.h"
+#include "libavutil/hwcontext_amf_internal.h"
+
+#if CONFIG_D3D12VA
+#include "libavutil/hwcontext_d3d12va.h"
+#endif
 #if CONFIG_D3D11VA
 #include "libavutil/hwcontext_d3d11va.h"
 #endif
@@ -55,6 +60,9 @@
 const enum AVPixelFormat ff_amf_pix_fmts[] = {
     AV_PIX_FMT_NV12,
     AV_PIX_FMT_YUV420P,
+#if CONFIG_D3D12VA
+    AV_PIX_FMT_D3D12,
+#endif
 #if CONFIG_D3D11VA
     AV_PIX_FMT_D3D11,
 #endif
@@ -402,6 +410,24 @@ static int amf_submit_frame(AVCodecContext *avctx, AVFrame 
   *frame, AMFSurface
 
 // prepare surface from frame
     switch (frame->format) {
+#if CONFIG_D3D12VA
+    case AV_PIX_FMT_D3D12:
+        {
+            AVD3D12VAFrame *frame_dx12 = (AVD3D12VAFrame *)frame->data[0];
+            AMFGuid guid = IID_AMFContext2();
+            AMFContext2 *context2 = NULL;
+
+            res = AMF_IFACE_CALL(amf_device_ctx->context, QueryInterface, 
&guid, (void**)&context2);
+            AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, 
"CreateContext2() failed with error %d\n", res);
+
+            res = AMF_IFACE_CALL(context2, CreateSurfaceFromDX12Native, 
frame_dx12->texture, &surface, NULL);
+            AMF_IFACE_CALL(context2, Release);
+            AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, 
"CreateSurfaceFromDX12Native() failed with error %d\n", res);
+
+            hw_surface = 1;
+        }
+        break;
+#endif
 #if CONFIG_D3D11VA
     case AV_PIX_FMT_D3D11:
         {
@@ -712,6 +738,10 @@ int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket 
*avpkt)
 }
 
 const AVCodecHWConfigInternal *const ff_amfenc_hw_configs[] = {
+#if CONFIG_D3D12VA
+    HW_CONFIG_ENCODER_FRAMES(D3D12, D3D12VA),
+    HW_CONFIG_ENCODER_DEVICE(NONE,  D3D12VA),
+#endif
 #if CONFIG_D3D11VA
     HW_CONFIG_ENCODER_FRAMES(D3D11, D3D11VA),
     HW_CONFIG_ENCODER_DEVICE(NONE,  D3D11VA),
diff --git a/libavutil/hwcontext_amf.c b/libavutil/hwcontext_amf.c
index 505424af74..32fde79f40 100644
--- a/libavutil/hwcontext_amf.c
+++ b/libavutil/hwcontext_amf.c
@@ -562,12 +562,24 @@ enum AMF_MEMORY_TYPE 
av_amf_get_memory_type(AVAMFDeviceContext *amf_ctx)
 {
     AMFContext  *context = amf_ctx->context;
     AMFContext1 *context1 = NULL;
+    AMFContext2 *context2 = NULL;
     AMFGuid guid1 = IID_AMFContext1();
+    AMFGuid guid2 = IID_AMFContext2();
+    void * device = NULL;
 
     if (!amf_ctx)
         return AMF_MEMORY_UNKNOWN;
 
 #ifdef _WIN32
+    if (AMF_IFACE_CALL(context, QueryInterface, &guid2, (void**)&context2) == 
AMF_OK)
+    {
+        device = AMF_IFACE_CALL(context2, GetDX12Device, AMF_DX12);
+        AMF_IFACE_CALL(context2, Release);
+
+        if (device)
+            return AMF_MEMORY_DX12;
+    }
+
     if (AMF_IFACE_CALL(context, GetDX11Device, AMF_DX11_1))
         return AMF_MEMORY_DX11;
 
@@ -578,10 +590,10 @@ enum AMF_MEMORY_TYPE 
av_amf_get_memory_type(AVAMFDeviceContext *amf_ctx)
     if (AMF_IFACE_CALL(context, QueryInterface, &guid1, (void**)&context1) != 
AMF_OK)
         return AMF_MEMORY_UNKNOWN;
 
-    if (AMF_IFACE_CALL(context1, GetVulkanDevice)) {
-        context1->pVtbl->Release(context1);
+    device = AMF_IFACE_CALL(context1, GetVulkanDevice);
+    AMF_IFACE_CALL(context1, Release);
+    if (device)
         return AMF_MEMORY_VULKAN;
-    }
 
     return AMF_MEMORY_UNKNOWN;
 }
@@ -589,9 +601,11 @@ enum AMF_MEMORY_TYPE 
av_amf_get_memory_type(AVAMFDeviceContext *amf_ctx)
 static int amf_device_init(AVHWDeviceContext *ctx)
 {
     AVAMFDeviceContext *amf_ctx = ctx->hwctx;
-    AMFContext *context = amf_ctx->context;
+    AMFContext  *context = amf_ctx->context;
     AMFContext1 *context1 = NULL;
+    AMFContext2 *context2 = NULL;
     AMFGuid guid1 = IID_AMFContext1();
+    AMFGuid guid2 = IID_AMFContext2();
     AMF_RESULT res;
 
     if (!amf_ctx->lock) {
@@ -610,6 +624,18 @@ static int amf_device_init(AVHWDeviceContext *ctx)
     }
 
 #ifdef _WIN32
+    res = AMF_IFACE_CALL(context, QueryInterface, &guid2, (void**)&context2);
+    if (res == AMF_OK) {
+        res = AMF_IFACE_CALL(context2, InitDX12, NULL, AMF_DX12);
+        AMF_IFACE_CALL(context2, Release);
+        if (res == AMF_OK) {
+            av_log(ctx, AV_LOG_VERBOSE, "Sucessfully initialized AMF via 
D3D12.\n");
+            return 0;
+        }
+    } else {
+        av_log(ctx, AV_LOG_VERBOSE, "CreateContext2() failed with error %d, 
trying older D3D APIs...\n", res);
+    }
+
     res = AMF_IFACE_CALL(context, InitDX11, NULL, AMF_DX11_1);
     if (res == AMF_OK) {
         av_log(ctx, AV_LOG_VERBOSE, "Successfully initialized AMF via 
D3D11.\n");
@@ -626,23 +652,36 @@ static int amf_device_init(AVHWDeviceContext *ctx)
 #endif
 
     res = AMF_IFACE_CALL(context, QueryInterface, &guid1, (void**)&context1);
-    AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "CreateContext1() 
failed with error %d\n", res);
+    if (res != AMF_OK) {
+        av_log(ctx, AV_LOG_ERROR, "CreateContext1() failed with error %d\n", 
res);
+        return res;
+    }
 
     res = AMF_IFACE_CALL(context1, InitVulkan, NULL);
     AMF_IFACE_CALL(context1, Release);
 
-    if (res == AMF_OK)
+    if (res == AMF_OK) {
         av_log(ctx, AV_LOG_VERBOSE, "Successfully initialized AMF via 
Vulkan.\n");
-    else {
-        if (res == AMF_NOT_SUPPORTED)
+        return 0;
+    } else {
+        if (res == AMF_NOT_SUPPORTED) {
             av_log(ctx, AV_LOG_ERROR, "AMF via Vulkan is not supported on the 
given device.\n");
-        else
+            return AVERROR(ENOTSUP);
+        }
+        else {
             av_log(ctx, AV_LOG_ERROR, "Failed to initialize AMF via Vulkan, 
error %d\n", res);
-
-        return AVERROR(ENOSYS);
+            return AVERROR(ENOSYS);
+        }
     }
 
-    return 0;
+    // Shouldn't get here under normal circumstances.
+    if (context1)
+        AMF_IFACE_CALL(context1, Release);
+
+    if (context2)
+        AMF_IFACE_CALL(context2, Release);
+
+    return AVERROR_BUG;
 }
 
 static int amf_load_library(AVAMFDeviceContext* amf_ctx,  void* avcl)
@@ -829,7 +868,7 @@ static int amf_device_derive(AVHWDeviceContext *device_ctx,
                               AVHWDeviceContext *child_device_ctx, 
AVDictionary *opts,
                               int flags)
 {
-#if CONFIG_DXVA2 || CONFIG_D3D11VA
+#if CONFIG_DXVA2 || CONFIG_D3D11VA || CONFIG_D3D12VA
     AVAMFDeviceContext        *amf_ctx = device_ctx->hwctx;
 #endif
     int ret;
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to