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]

Reply via email to