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

# Summary of changes

Check the dimensions and pixel format of decoded frames before converting AMF 
surfaces to AVFrames.
Reinitialize the hardware frames context if the frame dimensions exceed the 
current allocation or the pixel format differs.

This fixes an issue encountered in HandBrake and improves the robustness of AMF 
hardware decoding for other applications.

Reported in: https://github.com/HandBrake/HandBrake/discussions/8223



>From fb1ab2591c2105435f1f307fdaeb8d61776f7c43 Mon Sep 17 00:00:00 2001
From: Araz Iusubov <[email protected]>
Date: Thu, 5 Nov 2026 12:47:43 +0100
Subject: [PATCH] avcodec/amfdec: Reinitilize hw_frames_ctx on resolution or
 format changes

---
 libavcodec/amfdec.c | 55 ++++++++++++++++++++++++++++-----------------
 1 file changed, 34 insertions(+), 21 deletions(-)

diff --git a/libavcodec/amfdec.c b/libavcodec/amfdec.c
index 00a17360f55..d8ca6abad3a 100644
--- a/libavcodec/amfdec.c
+++ b/libavcodec/amfdec.c
@@ -514,6 +514,18 @@ static int amf_amfsurface_to_avframe(AVCodecContext 
*avctx, AMFSurface* surface,
     if (avctx->hw_device_ctx && 
((AVHWDeviceContext*)avctx->hw_device_ctx->data)->type == AV_HWDEVICE_TYPE_AMF) 
{
         // prepare frame similar to  ff_get_buffer(avctx, frame, 
AV_GET_BUFFER_FLAG_REF);
 
+        AVHWFramesContext *frames_ctx = avctx->hw_frames_ctx ? 
(AVHWFramesContext *)avctx->hw_frames_ctx->data : NULL;
+        int sw_format = 
av_amf_to_av_format(surface->pVtbl->GetFormat(surface));
+
+        if (!frames_ctx || frames_ctx->width < avctx->width ||
+            frames_ctx->height < avctx->height ||
+            frames_ctx->sw_format != sw_format) {
+            ret = amf_reinit_frames_context(avctx, sw_format, avctx->width, 
avctx->height);
+
+            if (ret < 0)
+                return ret;
+        }
+
         ret = ff_decode_frame_props(avctx, frame);
         if (ret < 0)
             return ret;
@@ -577,6 +589,25 @@ static int amf_amfsurface_to_avframe(AVCodecContext 
*avctx, AMFSurface* surface,
     return 0;
 }
 
+static void amf_init_dimensions(AVCodecContext *avctx)
+{
+    AMFDecoderContext *ctx = avctx->priv_data;
+    AMFVariantStruct size_var = {0};
+    AMF_RESULT res = AMF_OK;
+
+    res = ctx->decoder->pVtbl->GetProperty(ctx->decoder, 
AMF_VIDEO_DECODER_CURRENT_SIZE, &size_var);
+    if (res == AMF_OK && size_var.sizeValue.width > 0 && 
size_var.sizeValue.height > 0) {
+        avctx->width        = size_var.sizeValue.width;
+        avctx->height       = size_var.sizeValue.height;
+        avctx->coded_width  = size_var.sizeValue.width;
+        avctx->coded_height = size_var.sizeValue.height;
+
+        ctx->dimensions_initialized = 1;
+
+        av_log(avctx, AV_LOG_DEBUG, "AMF: detected initial decoder size 
%dx%d\n", avctx->width, avctx->height);
+    }
+}
+
 static AMF_RESULT amf_receive_frame(AVCodecContext *avctx, AVFrame *frame)
 {
     AMFDecoderContext *ctx = avctx->priv_data;
@@ -599,6 +630,9 @@ static AMF_RESULT amf_receive_frame(AVCodecContext *avctx, 
AVFrame *frame)
         data_out = NULL;
     }
 
+    if (!ctx->dimensions_initialized)
+        amf_init_dimensions(avctx);
+
     ret = amf_amfsurface_to_avframe(avctx, surface, frame);
     AMF_GOTO_FAIL_IF_FALSE(avctx, ret >= 0, AMF_FAIL, "Failed to convert 
AMFSurface to AVFrame = %d\n", ret);
     return AMF_OK;
@@ -654,25 +688,6 @@ static AMF_RESULT amf_buffer_from_packet(AVCodecContext 
*avctx, const AVPacket*
     return amf_update_buffer_properties(avctx, buf, pkt);
 }
 
-static void amf_init_dimensions(AVCodecContext *avctx)
-{
-    AMFDecoderContext *ctx = avctx->priv_data;
-    AMFVariantStruct size_var = {0};
-    AMF_RESULT res = AMF_OK;
-
-    res = ctx->decoder->pVtbl->GetProperty(ctx->decoder, 
AMF_VIDEO_DECODER_CURRENT_SIZE, &size_var);
-    if (res == AMF_OK && size_var.sizeValue.width > 0 && 
size_var.sizeValue.height > 0) {
-        avctx->width        = size_var.sizeValue.width;
-        avctx->height       = size_var.sizeValue.height;
-        avctx->coded_width  = size_var.sizeValue.width;
-        avctx->coded_height = size_var.sizeValue.height;
-
-        ctx->dimensions_initialized = 1;
-
-        av_log(avctx, AV_LOG_DEBUG, "AMF: detected initial decoder size 
%dx%d\n", avctx->width, avctx->height);
-    }
-}
-
 static int amf_decode_frame(AVCodecContext *avctx, struct AVFrame *frame)
 {
     AMFDecoderContext *ctx = avctx->priv_data;
@@ -736,8 +751,6 @@ static int amf_decode_frame(AVCodecContext *avctx, struct 
AVFrame *frame)
     res = amf_receive_frame(avctx, frame);
     if (res == AMF_OK) {
         got_frame = 1;
-        if (!ctx->dimensions_initialized)
-            amf_init_dimensions(avctx);
     } else if (res == AMF_REPEAT)
         // decoder has no output yet
         res = AMF_OK;
-- 
2.54.0

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

Reply via email to