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

The DXVA2 frame pool is created with a single `CreateSurface()` call. The AMD 
driver fails to encode surfaces from a pool created that way 
(GPUOpen-LibrariesAndSDKs/AMF#632, with a standalone repro):
- After the first `SubmitInput()`, the AMF encoder either stalls without 
returning an error, or crashes with an integer division by zero in 
`AMDXN64.DLL` when the surfaces were written with `StretchRect()`.
- As a result, `ffmpeg -hwaccel dxva2 -hwaccel_output_format dxva2_vld -i 
<H.264 or HEVC> -c:v h264_amf` (or `hevc_amf`, `av1_amf`) never outputs a 
packet unless pre-analysis is enabled.
- The same surfaces encode normally when they are created one by one.

This patch creates the surfaces with one call each. The decoder takes the pool 
as an array of pointers, so nothing else changes. The array is published before 
the loop, so the surfaces already created are released if a later call fails. 
This is a workaround for the AMD bug, and a TODO in the code names the issue so 
that it can be reverted once the driver is fixed.

Tested on Windows 11, RX 9070 XT, driver 32.0.32015.7029:
- DXVA2 H.264 1080p and HEVC 4K input now encodes with all three AMF encoders: 
120, 90 and 120 of 120, 90 and 120 packets, where none were output before.
- Decoded frames are identical to before for H.264, HEVC Main10 and HEVC 4K, 
both downloaded and passed through vpp_amf.

Written with Claude Opus 5.5 in Claude Code; `Assisted-by` trailer on the 
commit.


>From 23dd25bfad28125dbcfcf1bc81b97e788927c14d Mon Sep 17 00:00:00 2001
From: Julius Bairaktaris <[email protected]>
Date: Mon, 26 Oct 2026 14:46:46 +0100
Subject: [PATCH] avutil/hwcontext_dxva2: create the pool surfaces one at a
 time

The pool is created with a single CreateSurface() call. The AMD driver
fails to encode surfaces of a pool created that way: on an RX 9070 XT,
driver 32.0.32015.7029, AMF's H.264, HEVC and AV1 encoders stall after
the first frames on DXVA2-decoded input, or crash with an integer
division by zero in AMDXN64.DLL when the surfaces were written with
StretchRect(). So ffmpeg -hwaccel dxva2 -hwaccel_output_format dxva2_vld
with h264_amf, hevc_amf or av1_amf never outputs a packet, unless
pre-analysis is enabled. The same surfaces created one by one encode
normally (GPUOpen-LibrariesAndSDKs/AMF#632).

Create the surfaces with one call each. The decoder takes them as an
array of pointers, so nothing else changes. Publish the array before the
loop so that the surfaces already created are released if a later call
fails.

Tested on Windows 11, RX 9070 XT, driver 32.0.32015.7029: DXVA2 H.264
1080p and HEVC 4K input now encodes with h264_amf, hevc_amf and av1_amf
(120, 90 and 120 of 120, 90 and 120 packets, none before). The decoded
frames of H.264, HEVC Main10 and HEVC 4K, downloaded or passed through
vpp_amf, are identical to before.

Assisted-by: Claude Opus 5.5
Signed-off-by: Julius Bairaktaris <[email protected]>
---
 libavutil/hwcontext_dxva2.c | 28 ++++++++++++++++------------
 1 file changed, 16 insertions(+), 12 deletions(-)

diff --git a/libavutil/hwcontext_dxva2.c b/libavutil/hwcontext_dxva2.c
index f697690e19c..52831b719e8 100644
--- a/libavutil/hwcontext_dxva2.c
+++ b/libavutil/hwcontext_dxva2.c
@@ -202,15 +202,22 @@ static int dxva2_init_pool(AVHWFramesContext *ctx)
     if (!s->surfaces_internal)
         return AVERROR(ENOMEM);
 
-    hr = IDirectXVideoAccelerationService_CreateSurface(s->service,
-                                                        ctx->width, 
ctx->height,
-                                                        ctx->initial_pool_size 
- 1,
-                                                        s->format, 
D3DPOOL_DEFAULT, 0,
-                                                        
frames_hwctx->surface_type,
-                                                        s->surfaces_internal, 
NULL);
-    if (FAILED(hr)) {
-        av_log(ctx, AV_LOG_ERROR, "Could not create the surfaces\n");
-        return AVERROR_UNKNOWN;
+    frames_hwctx->surfaces    = s->surfaces_internal;
+    frames_hwctx->nb_surfaces = ctx->initial_pool_size;
+
+    // TODO: create the pool in one CreateSurface() call again once
+    // GPUOpen-LibrariesAndSDKs/AMF#632 is fixed: the AMF encoders crash or
+    // stall on surfaces of a pool allocated that way.
+    for (int i = 0; i < ctx->initial_pool_size; i++) {
+        hr = IDirectXVideoAccelerationService_CreateSurface(s->service,
+                                                            ctx->width, 
ctx->height, 0,
+                                                            s->format, 
D3DPOOL_DEFAULT, 0,
+                                                            
frames_hwctx->surface_type,
+                                                            
&s->surfaces_internal[i], NULL);
+        if (FAILED(hr)) {
+            av_log(ctx, AV_LOG_ERROR, "Could not create the surfaces\n");
+            return AVERROR_UNKNOWN;
+        }
     }
 
     ffhwframesctx(ctx)->pool_internal =
@@ -219,9 +226,6 @@ static int dxva2_init_pool(AVHWFramesContext *ctx)
     if (!ffhwframesctx(ctx)->pool_internal)
         return AVERROR(ENOMEM);
 
-    frames_hwctx->surfaces    = s->surfaces_internal;
-    frames_hwctx->nb_surfaces = ctx->initial_pool_size;
-
     return 0;
 }
 
-- 
2.54.0

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

Reply via email to