PR #25166 opened by Edison Ling (edisonling)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25166
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25166.patch

Previously the queue limit was raised from pa_lookahead_buffer_depth
inside ff_amf_encode_init(), before per-codec setup. Adaptive mini-GOP
can force AMF_PA_LOOKAHEAD_BUFFER_DEPTH to 1 when that option is -1 or
0, so async_depth stayed at 1. The receive path can then refuse further
input and the encoder can stall.

Fix this by reading the applied depth back after lookahead and B-frame
properties are final and widening async_depth to that value plus one,
before Init(). Option ranges stay at MAX_LOOKAHEAD_DEPTH.

This is the read-back part of #24055; runtime maximum and option-ceiling
changes are planned as a follow-up PR.

## Testing

AMD Radeon RX 9070 XT, driver 32.0.31041.1004, MSVC `--enable-amf`.
Patched vs unpatched at the same upstream commit; 2 s `testsrc2` 1280x720.

Unpatched ffmpeg on an RX 9070 (#24055) could hang with `h264_amf`,
`-preanalysis 1 -pa_adaptive_mini_gop 1 -async_depth 1`. On my 9070 XT both 
builds finish; only the patched build logs widening async_depth after read-back.

Default `h264_amf`: no change vs unpatched.

Same preanalysis/adaptive mini-GOP/`async_depth 1` on `h264_amf` and
`av1_amf`: patched widens async_depth when needed; output matches unpatched.

`-pa_lookahead_buffer_depth 20 -async_depth 4`: with preanalysis off,
unpatched still bumps async_depth from the option alone; patched does not,
with unchanged output vs a normal encode. With preanalysis on, both bump;
outputs match.


>From a0515a10c6a9524a11b842870476f033f28ac10b Mon Sep 17 00:00:00 2001
From: Edison Ling <[email protected]>
Date: Sat, 17 Oct 2026 21:23:12 -0400
Subject: [PATCH] avcodec/amfenc: fix async_depth sizing from applied lookahead

Previously the queue limit was raised from pa_lookahead_buffer_depth
inside ff_amf_encode_init(), before per-codec setup. Adaptive mini-GOP
can force AMF_PA_LOOKAHEAD_BUFFER_DEPTH to 1 when that option is -1 or
0, so async_depth stayed at 1. The receive path can then refuse further
input and the encoder can stall.

Fix this by reading the applied depth back after lookahead and B-frame
properties are final and widening async_depth to that value plus one,
before Init(). Option ranges stay at MAX_LOOKAHEAD_DEPTH.

Signed-off-by: Edison Ling <[email protected]>
---
 libavcodec/amfenc.c      | 25 ++++++++++++++++---------
 libavcodec/amfenc.h      |  7 +++++++
 libavcodec/amfenc_av1.c  |  2 ++
 libavcodec/amfenc_h264.c |  2 ++
 libavcodec/amfenc_hevc.c |  2 ++
 5 files changed, 29 insertions(+), 9 deletions(-)

diff --git a/libavcodec/amfenc.c b/libavcodec/amfenc.c
index 20bc22d98c..f78d7ba39e 100644
--- a/libavcodec/amfenc.c
+++ b/libavcodec/amfenc.c
@@ -33,6 +33,8 @@
 #include "libavutil/pixdesc.h"
 #include "libavutil/time.h"
 
+#include <AMF/components/PreAnalysis.h>
+
 #include "amfenc.h"
 #include "encode.h"
 
@@ -278,6 +280,20 @@ static int amf_copy_buffer(AVCodecContext *avctx, AVPacket 
*pkt, AMFBuffer *buff
     return 0;
 }
 
+void ff_amf_fit_async_depth(AVCodecContext *avctx, AMFEncoderContext *ctx)
+{
+    AMFVariantStruct var = { 0 };
+    AMF_RESULT res;
+
+    res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, 
AMF_PA_LOOKAHEAD_BUFFER_DEPTH, &var);
+    if (res == AMF_OK && var.int64Value >= ctx->hwsurfaces_in_queue_max) {
+        av_log(avctx, AV_LOG_WARNING,
+               "async_depth (%d) too small for lookahead (%lld), increasing to 
(%lld)\n",
+               ctx->hwsurfaces_in_queue_max, (long long)var.int64Value, (long 
long)(var.int64Value + 1));
+        ctx->hwsurfaces_in_queue_max = (int)(var.int64Value + 1);
+    }
+}
+
 // amfenc API implementation
 int ff_amf_encode_init(AVCodecContext *avctx)
 {
@@ -326,15 +342,6 @@ int ff_amf_encode_init(AVCodecContext *avctx)
         AMF_RETURN_IF_FALSE(ctx, ret == 0, ret, "Failed to create  hardware 
device context (AMF) : %s\n", av_err2str(ret));
     }
 
-    if (ctx->pa_lookahead_buffer_depth >= ctx->hwsurfaces_in_queue_max) {
-        av_log(avctx, AV_LOG_WARNING,
-               "async_depth (%d) too small for lookahead (%d), increasing to 
(%d)\n",
-                ctx->hwsurfaces_in_queue_max,
-                ctx->pa_lookahead_buffer_depth,
-                ctx->pa_lookahead_buffer_depth + 1);
-        ctx->hwsurfaces_in_queue_max = ctx->pa_lookahead_buffer_depth + 1;
-    }
-
     if ((ret = amf_init_encoder(avctx)) == 0) {
         return 0;
     }
diff --git a/libavcodec/amfenc.h b/libavcodec/amfenc.h
index 6a380208d1..03320fecd7 100644
--- a/libavcodec/amfenc.h
+++ b/libavcodec/amfenc.h
@@ -154,6 +154,13 @@ int ff_amf_encode_init(AVCodecContext *avctx);
 */
 int ff_amf_encode_close(AVCodecContext *avctx);
 
+/**
+ * Widen async_depth (hwsurfaces_in_queue_max) to the lookahead depth AMF
+ * has applied, plus one. Call before encoder Init(), after lookahead and
+ * B-frame properties are final.
+ */
+void ff_amf_fit_async_depth(AVCodecContext *avctx, AMFEncoderContext *ctx);
+
 /**
 * Ecoding one frame - common function for all AMF encoders
 */
diff --git a/libavcodec/amfenc_av1.c b/libavcodec/amfenc_av1.c
index a572d439a7..896899806c 100644
--- a/libavcodec/amfenc_av1.c
+++ b/libavcodec/amfenc_av1.c
@@ -574,6 +574,8 @@ static av_cold int amf_encode_init_av1(AVCodecContext* 
avctx)
     res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, 
AMF_VIDEO_ENCODER_AV1_QUERY_TIMEOUT, &var);
     ctx->query_timeout_supported = res == AMF_OK && var.int64Value;
 
+    ff_amf_fit_async_depth(avctx, ctx);
+
     // init encoder
     res = ctx->encoder->pVtbl->Init(ctx->encoder, ctx->format, avctx->width, 
avctx->height);
     AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_BUG, "encoder->Init() 
failed with error %d\n", res);
diff --git a/libavcodec/amfenc_h264.c b/libavcodec/amfenc_h264.c
index 214fac6909..04a74c25df 100644
--- a/libavcodec/amfenc_h264.c
+++ b/libavcodec/amfenc_h264.c
@@ -552,6 +552,8 @@ static av_cold int amf_encode_init_h264(AVCodecContext 
*avctx)
     res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, 
AMF_VIDEO_ENCODER_QUERY_TIMEOUT, &var);
     ctx->query_timeout_supported = res == AMF_OK && var.int64Value;
 
+    ff_amf_fit_async_depth(avctx, ctx);
+
     // Initialize Encoder
     res = ctx->encoder->pVtbl->Init(ctx->encoder, ctx->format, avctx->width, 
avctx->height);
     AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_BUG, "encoder->Init() 
failed with error %d\n", res);
diff --git a/libavcodec/amfenc_hevc.c b/libavcodec/amfenc_hevc.c
index 4e280fcf15..290b64f73d 100644
--- a/libavcodec/amfenc_hevc.c
+++ b/libavcodec/amfenc_hevc.c
@@ -484,6 +484,8 @@ static av_cold int amf_encode_init_hevc(AVCodecContext 
*avctx)
     res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, 
AMF_VIDEO_ENCODER_HEVC_QUERY_TIMEOUT, &var);
     ctx->query_timeout_supported = res == AMF_OK && var.int64Value;
 
+    ff_amf_fit_async_depth(avctx, ctx);
+
     // init encoder
     res = ctx->encoder->pVtbl->Init(ctx->encoder, ctx->format, avctx->width, 
avctx->height);
     AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_BUG, "encoder->Init() 
failed with error %d\n", res);
-- 
2.54.0

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

Reply via email to