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

Right after device_derive, FFmpeg also calls device_init. And in device_init 
(amf_device_init), the fact that AMF might be already initialized with, for 
example, Vulkan, is ignored and gets initialized again with DX11. This patch 
fixes that, and introduces the av_amf_get_memory_type to be used in the future 
patches.


>From 098fd6e7191cf73d65a82b02d1dd10f5609d8f92 Mon Sep 17 00:00:00 2001
From: Dmitrii Gershenkop <[email protected]>
Date: Tue, 11 Aug 2026 13:52:05 +0200
Subject: [PATCH] avutil/hwcontext_amf: Fix double init for derived devices.

Right after device_derive, FFmpeg also calls device_init. And in device_init 
(amf_device_init), the fact that AMF might be already initialized with, for 
example, Vulkan, is ignored and gets initialized again with DX11.
---
 libavutil/hwcontext_amf.c | 86 +++++++++++++++++++++++++++------------
 libavutil/hwcontext_amf.h |  2 +
 2 files changed, 63 insertions(+), 25 deletions(-)

diff --git a/libavutil/hwcontext_amf.c b/libavutil/hwcontext_amf.c
index 7d877683b4..2438aab768 100644
--- a/libavutil/hwcontext_amf.c
+++ b/libavutil/hwcontext_amf.c
@@ -558,10 +558,37 @@ static void amf_device_uninit(AVHWDeviceContext 
*device_ctx)
     amf_ctx->version = 0;
 }
 
+enum AMF_MEMORY_TYPE av_amf_get_memory_type(AVAMFDeviceContext *amf_ctx)
+{
+    AMFContext  *context = amf_ctx->context;
+    AMFContext1 *context1 = NULL;
+    AMFGuid guid1 = IID_AMFContext1();
+
+#ifdef _WIN32
+    if (AMF_IFACE_CALL(context, GetDX11Device, AMF_DX11_1))
+        return AMF_MEMORY_DX11;
+
+    if (AMF_IFACE_CALL(context, GetDX9Device, AMF_DX9))
+        return AMF_MEMORY_DX9;
+#endif
+
+    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);
+        return AMF_MEMORY_VULKAN;
+    }
+
+    return AMF_MEMORY_UNKNOWN;
+}
+
 static int amf_device_init(AVHWDeviceContext *ctx)
 {
     AVAMFDeviceContext *amf_ctx = ctx->hwctx;
+    AMFContext  *context = amf_ctx->context;
     AMFContext1 *context1 = NULL;
+    AMFGuid guid1 = IID_AMFContext1();
     AMF_RESULT res;
 
     if (!amf_ctx->lock) {
@@ -574,35 +601,44 @@ static int amf_device_init(AVHWDeviceContext *ctx)
         amf_ctx->unlock = amf_unlock_default;
     }
 
-#ifdef _WIN32
-    res = amf_ctx->context->pVtbl->InitDX11(amf_ctx->context, NULL, 
AMF_DX11_1);
-    if (res == AMF_OK || res == AMF_ALREADY_INITIALIZED) {
-        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 {
-#endif
-            AMFGuid guid = IID_AMFContext1();
-            res = amf_ctx->context->pVtbl->QueryInterface(amf_ctx->context, 
&guid, (void**)&context1);
-            AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, 
"CreateContext1() failed with error %d\n", res);
+    if (av_amf_get_memory_type(amf_ctx) != AMF_MEMORY_UNKNOWN) {
+        av_log(ctx, AV_LOG_VERBOSE, "AMF is already initialized, skipping 
init.\n");
+        return 0;
+    }
 
-            res = context1->pVtbl->InitVulkan(context1, NULL);
-            context1->pVtbl->Release(context1);
-            if (res != AMF_OK && res != AMF_ALREADY_INITIALIZED) {
-                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);
-            }
-            av_log(ctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via 
Vulkan.\n");
 #ifdef _WIN32
-        }
-     }
+    res = AMF_IFACE_CALL(context, InitDX11, NULL, AMF_DX11_1);
+    if (res == AMF_OK) {
+        av_log(ctx, AV_LOG_VERBOSE, "Sucessfully initialized AMF via 
D3D11.\n");
+        return 0;
+    }
+
+    res = AMF_IFACE_CALL(context, InitDX9, NULL);
+    if (res == AMF_OK) {
+        av_log(ctx, AV_LOG_VERBOSE, "Sucessfully initialized AMF via D3D9.\n");
+        return 0;
+    }
+
+    av_log(ctx, AV_LOG_WARNING, "AMF failed to initialize with any of 
supported versions of DirectX, trying Vulkan instead...\n");
 #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);
+
+    res = AMF_IFACE_CALL(context1, InitVulkan, NULL);
+    AMF_IFACE_CALL(context1, Release);
+
+    if (res == AMF_OK)
+        av_log(ctx, AV_LOG_VERBOSE, "Sucessfully initialized AMF via 
Vulkan.\n");
+    else {
+        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, "Failed to initialize AMF via Vulkan, 
error %d\n", res);
+
+        return AVERROR(ENOSYS);
+    }
+
     return 0;
 }
 
diff --git a/libavutil/hwcontext_amf.h b/libavutil/hwcontext_amf.h
index 918eec97b8..d2bbb41891 100644
--- a/libavutil/hwcontext_amf.h
+++ b/libavutil/hwcontext_amf.h
@@ -46,6 +46,8 @@ typedef struct AVAMFDeviceContext {
     void *lock_ctx;
 } AVAMFDeviceContext;
 
+enum AMF_MEMORY_TYPE av_amf_get_memory_type(AVAMFDeviceContext *amf_ctx);
+
 enum AMF_SURFACE_FORMAT av_av_to_amf_format(enum AVPixelFormat fmt);
 enum AVPixelFormat av_amf_to_av_format(enum AMF_SURFACE_FORMAT fmt);
 
-- 
2.52.0

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

Reply via email to