This is an automated email from the git hooks/post-receive script.

Git pushed a commit to branch master
in repository ffmpeg.

commit 23e21331dfc21cb2ad344751fb6941e803546ca5
Author:     Julius Bairaktaris <[email protected]>
AuthorDate: Sun Aug 30 15:53:03 2026 +0200
Commit:     ArazIusubov <[email protected]>
CommitDate: Wed Sep 16 22:05:28 2026 +0000

    avfilter/vf_amf_common: drain the component and tolerate AMF_REPEAT
    
    amf_filter_filter_frame() read the component output exactly once and
    treated anything but AMF_OK as fatal, so a component that had no output
    ready yet, which AMD's Video Converter programming guide documents as
    AMF_REPEAT, produced an error instead of simply consuming the frame.
    
    Poll until the component stops returning data, and accept AMF_REPEAT.
    A component that produces one output per input, which is what the scaler,
    the enhancer and the converter do today, behaves as before: one iteration
    with data, one without. Timestamps now come from the output surface, as
    vf_frc_amf.c already does, so a second output of the same submission does
    not inherit the first one's.
    
    Returning AVERROR(EAGAIN) from a filter_frame callback was wrong and is
    dropped. filter_frame_to_filter() latches a negative return into the
    link's status_out, which stalls a pull driven graph and stops EOF from
    crossing the filter; a frame that yields no output is simply consumed.
    
    AMF_INPUT_FULL on submission stays fatal. It means the frame was not
    accepted, so tolerating it would silently drop it, and the queue is
    already drained after every submission, so it cannot be reached by
    feeding the component faster than it produces.
    
    The input frame is kept until the loop ends, since its properties are
    copied onto every output, and freed once at the end.
    
    Tested on Windows 11, RX 9070 XT, driver 32.0.31041.1004: identical
    output and timestamps for every sr_amf algorithm, vpp_amf, vqe_amf and
    frc_amf, with software, AMF and D3D11VA input.
    
    Assisted-by: Claude Opus 5
    Signed-off-by: Julius Bairaktaris <[email protected]>
---
 libavfilter/vf_amf_common.c | 102 ++++++++++++++++++++++++--------------------
 1 file changed, 55 insertions(+), 47 deletions(-)

diff --git a/libavfilter/vf_amf_common.c b/libavfilter/vf_amf_common.c
index 9b80a7cd1b..0d2a2f6257 100644
--- a/libavfilter/vf_amf_common.c
+++ b/libavfilter/vf_amf_common.c
@@ -99,6 +99,7 @@ int amf_filter_filter_frame(AVFilterLink *inlink, AVFrame *in)
     enum AVColorRange out_color_range;
 
     AVFrame *out = NULL;
+    int got_frame = 0;
     int ret = 0;
 
     if (!ctx->component)
@@ -137,71 +138,78 @@ int amf_filter_filter_frame(AVFilterLink *inlink, AVFrame 
*in)
     res = ctx->component->pVtbl->SubmitInput(ctx->component, 
(AMFData*)surface_in);
     surface_in->pVtbl->Release(surface_in); // release surface after use
     AMF_GOTO_FAIL_IF_FALSE(avctx, res == AMF_OK, AVERROR_UNKNOWN, 
"SubmitInput() failed with error %d\n", res);
-    res = ctx->component->pVtbl->QueryOutput(ctx->component, &data_out);
-    AMF_GOTO_FAIL_IF_FALSE(avctx, res == AMF_OK, AVERROR_UNKNOWN, 
"QueryOutput() failed with error %d\n", res);
 
-    if (data_out) {
+    while (1) {
         AMFGuid guid = IID_AMFSurface();
+
+        res = ctx->component->pVtbl->QueryOutput(ctx->component, &data_out);
+        AMF_GOTO_FAIL_IF_FALSE(avctx, res == AMF_OK || res == AMF_REPEAT, 
AVERROR_UNKNOWN, "QueryOutput() failed with error %d\n", res);
+        if (!data_out)
+            break;
+
         res = data_out->pVtbl->QueryInterface(data_out, &guid, 
(void**)&surface_out); // query for buffer interface
         data_out->pVtbl->Release(data_out);
+        data_out = NULL;
         AMF_GOTO_FAIL_IF_FALSE(avctx, res == AMF_OK, AVERROR_UNKNOWN, 
"QueryInterface(IID_AMFSurface) failed with error %d\n", res);
-    } else {
-        ret = AVERROR(EAGAIN);
-        goto fail;
-    }
 
-    out = amf_amfsurface_to_avframe(avctx, surface_out);
-    AMF_GOTO_FAIL_IF_FALSE(avctx, out != NULL, AVERROR(ENOMEM), "Failed to 
convert AMFSurface to AVFrame\n");
+        out = amf_amfsurface_to_avframe(avctx, surface_out);
+        AMF_GOTO_FAIL_IF_FALSE(avctx, out != NULL, AVERROR(ENOMEM), "Failed to 
convert AMFSurface to AVFrame\n");
 
-    ret = av_frame_copy_props(out, in);
-    av_frame_unref(in);
+        ret = av_frame_copy_props(out, in);
+        if (ret < 0)
+            goto fail;
+        out->pts = surface_out->pVtbl->GetPts(surface_out);
 
-    out_colorspace = AVCOL_SPC_UNSPECIFIED;
+        out_colorspace = AVCOL_SPC_UNSPECIFIED;
 
-    if (ctx->color_profile != AMF_VIDEO_CONVERTER_COLOR_PROFILE_UNKNOWN) {
-        switch(ctx->color_profile) {
-        case AMF_VIDEO_CONVERTER_COLOR_PROFILE_601:
-            out_colorspace = AVCOL_SPC_SMPTE170M;
-        break;
-        case AMF_VIDEO_CONVERTER_COLOR_PROFILE_709:
-            out_colorspace = AVCOL_SPC_BT709;
-        break;
-        case AMF_VIDEO_CONVERTER_COLOR_PROFILE_2020:
-            out_colorspace = AVCOL_SPC_BT2020_NCL;
-        break;
-        case AMF_VIDEO_CONVERTER_COLOR_PROFILE_JPEG:
-            out_colorspace = AVCOL_SPC_RGB;
-        break;
-        default:
-            out_colorspace = AVCOL_SPC_UNSPECIFIED;
-        break;
+        if (ctx->color_profile != AMF_VIDEO_CONVERTER_COLOR_PROFILE_UNKNOWN) {
+            switch(ctx->color_profile) {
+            case AMF_VIDEO_CONVERTER_COLOR_PROFILE_601:
+                out_colorspace = AVCOL_SPC_SMPTE170M;
+            break;
+            case AMF_VIDEO_CONVERTER_COLOR_PROFILE_709:
+                out_colorspace = AVCOL_SPC_BT709;
+            break;
+            case AMF_VIDEO_CONVERTER_COLOR_PROFILE_2020:
+                out_colorspace = AVCOL_SPC_BT2020_NCL;
+            break;
+            case AMF_VIDEO_CONVERTER_COLOR_PROFILE_JPEG:
+                out_colorspace = AVCOL_SPC_RGB;
+            break;
+            default:
+                out_colorspace = AVCOL_SPC_UNSPECIFIED;
+            break;
+            }
+            out->colorspace = out_colorspace;
         }
-        out->colorspace = out_colorspace;
-    }
 
-    out_color_range = AVCOL_RANGE_UNSPECIFIED;
-    if (ctx->out_color_range == AMF_COLOR_RANGE_FULL)
-        out_color_range = AVCOL_RANGE_JPEG;
-    else if (ctx->out_color_range == AMF_COLOR_RANGE_STUDIO)
-        out_color_range = AVCOL_RANGE_MPEG;
+        out_color_range = AVCOL_RANGE_UNSPECIFIED;
+        if (ctx->out_color_range == AMF_COLOR_RANGE_FULL)
+            out_color_range = AVCOL_RANGE_JPEG;
+        else if (ctx->out_color_range == AMF_COLOR_RANGE_STUDIO)
+            out_color_range = AVCOL_RANGE_MPEG;
 
-    if (ctx->out_color_range != AMF_COLOR_RANGE_UNDEFINED)
-        out->color_range = out_color_range;
+        if (ctx->out_color_range != AMF_COLOR_RANGE_UNDEFINED)
+            out->color_range = out_color_range;
 
-    if (ctx->out_primaries != AMF_COLOR_PRIMARIES_UNDEFINED)
-        out->color_primaries = ctx->out_primaries;
+        if (ctx->out_primaries != AMF_COLOR_PRIMARIES_UNDEFINED)
+            out->color_primaries = ctx->out_primaries;
 
-    if (ctx->out_trc != AMF_COLOR_TRANSFER_CHARACTERISTIC_UNDEFINED)
-        out->color_trc = ctx->out_trc;
+        if (ctx->out_trc != AMF_COLOR_TRANSFER_CHARACTERISTIC_UNDEFINED)
+            out->color_trc = ctx->out_trc;
 
-    if (ctx->pre_converter)
-        out->colorspace = AVCOL_SPC_RGB;
+        if (ctx->pre_converter)
+            out->colorspace = AVCOL_SPC_RGB;
 
-    if (ret < 0)
-        goto fail;
+        ret = ff_filter_frame(outlink, out);
+        out = NULL;
+        if (ret < 0)
+            goto fail;
+        got_frame = 1;
+    }
 
     av_frame_free(&in);
-    return ff_filter_frame(outlink, out);
+    return got_frame ? ret : 0;
 fail:
     av_frame_free(&in);
     av_frame_free(&out);

-- 
To stop receiving notification emails like this one, please contact
[email protected].
_______________________________________________
ffmpeg-cvslog mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to