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]
