PR #25525 opened by JuliusBairaktaris URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25525 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25525.patch
Fixes #21326. Every frame the AMF decoders output owns a reference to its `AMFSurface`, which is released when the frame is freed. With software output, the frames reference no hardware context, so a frame that outlives the decoder releases its surface after `amf_decode_close()` has dropped the last reference to the AMF device, and with it the runtime. The release then crashes with an access violation. The ffmpeg CLI frees its last frames after closing the decoder. As a result, every software-output decode with `h264_amf`, `hevc_amf` or `av1_amf` ends with exit code 5 (`0xC0000005` truncated) after writing all frames. The Windows error log puts the fault in `amf_free_amfsurface()`. This patch makes each surface buffer hold a reference to the AMF device and drops it after releasing the surface. The AMF-surface output path already kept the device alive through `hw_frames_ctx`, and now takes the same path. Tested on Windows 11, RX 9070 XT, driver 32.0.32015.7029: - `h264_amf` and `hevc_amf` (8 and 10 bit) with software output now exit with 0 (5 before), and framemd5 is unchanged. - AMF-surface output (`-hwaccel amf -hwaccel_output_format amf`, then `hwdownload`) is unchanged. Written with Claude Opus 5.5 in Claude Code; `Assisted-by` trailer on the commit. >From 1334917554ffcd94d0dca9b098a05a89612ffafe Mon Sep 17 00:00:00 2001 From: Julius Bairaktaris <[email protected]> Date: Tue, 27 Oct 2026 15:19:40 +0100 Subject: [PATCH] avcodec/amfdec: keep the AMF device alive while frames hold surfaces Every output frame owns a reference to its AMFSurface, which is released when the frame is freed. With software output, the frames reference no hardware context, so a frame that outlives the decoder releases its surface after amf_decode_close() has dropped the last reference to the AMF device and the runtime is gone. The release then crashes with an access violation. The ffmpeg CLI frees its last frames after closing the decoder, so every software-output decode with the AMF decoders ended with exit code 5 (0xC0000005) after writing all frames. Hold a reference to the AMF device in each surface buffer and drop it after releasing the surface. Tested on Windows 11, RX 9070 XT, driver 32.0.32015.7029: h264_amf and hevc_amf (8 and 10 bit) with software output exit with 0, with unchanged framemd5; the AMF-surface output path is unchanged. Assisted-by: Claude Opus 5.5 Signed-off-by: Julius Bairaktaris <[email protected]> --- libavcodec/amfdec.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/libavcodec/amfdec.c b/libavcodec/amfdec.c index 00a17360f55..2b87e36ba04 100644 --- a/libavcodec/amfdec.c +++ b/libavcodec/amfdec.c @@ -58,7 +58,25 @@ static const AVCodecHWConfigInternal *const amf_hw_configs[] = { static void amf_free_amfsurface(void *opaque, uint8_t *data) { AMFSurface *surface = (AMFSurface*)(data); + AVBufferRef *device_ref = opaque; surface->pVtbl->Release(surface); + av_buffer_unref(&device_ref); +} + +static AVBufferRef *amf_wrap_amfsurface(AVCodecContext *avctx, AMFSurface *surface) +{ + AMFDecoderContext *ctx = avctx->priv_data; + AVBufferRef *device_ref = av_buffer_ref(ctx->device_ctx_ref); + AVBufferRef *buf; + + if (!device_ref) + return NULL; + buf = av_buffer_create((uint8_t *)surface, sizeof(surface), + amf_free_amfsurface, device_ref, + AV_BUFFER_FLAG_READONLY); + if (!buf) + av_buffer_unref(&device_ref); + return buf; } static int amf_legacy_driver_no_bitness_detect(AVAMFDeviceContext *amf_device_ctx) @@ -527,9 +545,7 @@ static int amf_amfsurface_to_avframe(AVCodecContext *avctx, AMFSurface* surface, frame->height = avctx->height; //// - frame->buf[0] = av_buffer_create((uint8_t *)surface, sizeof(surface), - amf_free_amfsurface, (void*)avctx, - AV_BUFFER_FLAG_READONLY); + frame->buf[0] = amf_wrap_amfsurface(avctx, surface); AMF_RETURN_IF_FALSE(avctx, !!frame->buf[0], AVERROR(ENOMEM), "av_buffer_create for amf surface failed."); frame->data[0] = (uint8_t *)surface; @@ -547,9 +563,7 @@ static int amf_amfsurface_to_avframe(AVCodecContext *avctx, AMFSurface* surface, frame->linesize[i] = plane->pVtbl->GetHPitch(plane); } - frame->buf[0] = av_buffer_create((uint8_t *)surface, sizeof(surface), - amf_free_amfsurface, (void*)avctx, - AV_BUFFER_FLAG_READONLY); + frame->buf[0] = amf_wrap_amfsurface(avctx, surface); AMF_RETURN_IF_FALSE(avctx, !!frame->buf[0], AVERROR(ENOMEM), "av_buffer_create for amf surface failed."); format_amf = surface->pVtbl->GetFormat(surface); -- 2.54.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
