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

Fixes the `sr_amf` filter emitting a **solid green frame** when 
`algorithm=sr1-1` (AMF VideoSR1.1).

### Root cause
Per AMD's `AMF_HQ_Scaler_API.md`, VideoSR1.1 only runs on a DX11/DX12 engine 
and does **not** accept NV12/P010 (it needs packed RGB: 
BGRA/RGBA/R10G10B10A2/RGBA_F16). The filter advertised NV12/P010 and passed the 
input format straight to `AMFHQScaler::Init()`, which returns `AMF_OK` even for 
the unsupported format — so the existing result check never fired and the 
output was green.

### Changes
- `vf_sr_amf.c`: when `algorithm=sr1-1`, restrict the negotiated pixel formats 
to RGBA so libavfilter auto-inserts a converter for YUV input.
- `vf_sr_amf.c`: reject an NV12/P010-backed hardware surface explicitly in 
`config_output` instead of silently producing green.
- `doc/filters.texi`: document the `sr1-1` format/device requirement and the 
alpha caveat.

### Testing
Built with `--enable-amf` and runtime-tested on Windows (Radeon 840M, DX11):

    ffmpeg -init_hw_device amf -f lavfi -i testsrc2=size=1280x720 \
      -vf "sr_amf=w=2560:h=1440:algorithm=sr1-1,hwdownload,format=rgba" 
-frames:v 1 out.png

| `algorithm=sr1-1` | RGB mean (R/G/B) | std | distinct colors |
|---|---|---|---|
| before (unpatched) | 0 / 136 / 0 (solid green) | 0 | 1 |
| after (patched) | 123 / 130 / 124 | ~124 | 2200+ |

After the fix the output matches the known-good algorithms (bilinear / bicubic 
/ point / sr1-0).

### Note on alpha
AMF's VideoSR algorithms (`sr1-0` and `sr1-1`) leave the alpha channel zeroed 
and expose no property to control it (the basic algorithms preserve it). Append 
e.g. `format=rgb24` downstream for an opaque result.

No new FATE samples required.

Refs: AMD `AMF_HQ_Scaler_API.md`, mpv-player/mpv#18068


From 8bf18bf0401dc57803f7fe34d07a847ab7810228 Mon Sep 17 00:00:00 2001
From: Julius Bairaktaris <[email protected]>
Date: Thu, 4 Jun 2026 23:53:01 +0200
Subject: [PATCH] avfilter/vf_sr_amf: fix solid green frame with
 algorithm=sr1-1

Per AMD's AMF_HQ_Scaler_API.md, the HQ Scaler's VideoSR1.1 algorithm is
only supported on a DX11/DX12 engine and with input/output formats other
than NV12 or P010 (it accepts packed RGB: BGRA, RGBA, R10G10B10A2 or
RGBA_F16). The filter however advertised NV12/P010 as valid input and
passed the input format straight to AMFHQScaler::Init(), which returns
AMF_OK even for the unsupported format. The existing result check
therefore never fired and the filter silently emitted a solid green
frame.

When algorithm=sr1-1, restrict the negotiated formats to RGBA, the packed
RGB format that round-trips cleanly through the AMF hwcontext (both upload
and hwdownload), so a converter is auto-inserted for YUV input, and reject
an unsupported hardware surface explicitly in config_output instead of
producing green.

Note that AMF's VideoSR algorithms (sr1-0 and sr1-1) leave the alpha
channel zeroed and expose no property to control it; drop alpha
downstream, e.g. with format=rgb24, for an opaque result.

Refs AMD AMF_HQ_Scaler_API.md and mpv-player/mpv#18068.

Signed-off-by: Julius Bairaktaris <[email protected]>
---
 doc/filters.texi        |  6 ++++++
 libavfilter/vf_sr_amf.c | 38 +++++++++++++++++++++++++++++++++++---
 2 files changed, 41 insertions(+), 3 deletions(-)

diff --git a/doc/filters.texi b/doc/filters.texi
index 2cae41c7c5..1a4314e5f9 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -22947,6 +22947,12 @@ Point
 
 @item sr1-1
 Video SR1.1
+This algorithm only supports packed RGB formats and requires a DirectX 11 or
+DirectX 12 device, so it is available on Windows only. Inputs in other formats
+such as @code{nv12} or @code{p010} are converted to @code{rgba} automatically.
+Note that the VideoSR algorithms (@code{sr1-0} and @code{sr1-1}) do not
+preserve the alpha channel (it is left zeroed); append e.g. @code{format=rgb24}
+downstream if an opaque result is required.
 
 @end table
 
diff --git a/libavfilter/vf_sr_amf.c b/libavfilter/vf_sr_amf.c
index 8f3ae7ed80..a0be23d114 100644
--- a/libavfilter/vf_sr_amf.c
+++ b/libavfilter/vf_sr_amf.c
@@ -54,8 +54,9 @@
 
 static int amf_filter_query_formats(AVFilterContext *avctx)
 {
-    const enum AVPixelFormat *output_pix_fmts;
-    static const enum AVPixelFormat input_pix_fmts[] = {
+    AMFFilterContext *ctx = avctx->priv;
+    const enum AVPixelFormat *input_pix_fmts, *output_pix_fmts;
+    static const enum AVPixelFormat input_pix_fmts_default[] = {
         AV_PIX_FMT_NV12,
         AV_PIX_FMT_P010,
         AV_PIX_FMT_BGRA,
@@ -75,7 +76,24 @@ static int amf_filter_query_formats(AVFilterContext *avctx)
         AV_PIX_FMT_RGBAF16,
         AV_PIX_FMT_NONE,
     };
-    output_pix_fmts = output_pix_fmts_default;
+    // VideoSR1.1 supports only RGB (BGRA, RGBA, R10G10B10A2, RGBA_F16) on
+    // DX11/DX12, not NV12/P010 (AMF_HQ_Scaler_API.md). Negotiate RGBA, the
+    // packed RGB format that round-trips cleanly through the AMF hwcontext
+    // (both upload and hwdownload), so a converter is inserted for YUV input.
+    // AMF_SURFACE keeps the hardware path; config_output rejects NV12/P010.
+    static const enum AVPixelFormat pix_fmts_sr1_1[] = {
+        AV_PIX_FMT_RGBA,
+        AV_PIX_FMT_AMF_SURFACE,
+        AV_PIX_FMT_NONE,
+    };
+
+    if (ctx->algorithm == AMF_HQ_SCALER_ALGORITHM_VIDEOSR1_1) {
+        input_pix_fmts  = pix_fmts_sr1_1;
+        output_pix_fmts = pix_fmts_sr1_1;
+    } else {
+        input_pix_fmts  = input_pix_fmts_default;
+        output_pix_fmts = output_pix_fmts_default;
+    }
 
     return amf_setup_input_output_formats(avctx, input_pix_fmts, 
output_pix_fmts);
 }
@@ -94,6 +112,20 @@ static int amf_filter_config_output(AVFilterLink *outlink)
     if (err < 0)
         return err;
 
+    // VideoSR1.1 requires a packed RGB surface and does not support NV12/P010.
+    // The format restriction in query_formats inserts a converter for software
+    // input, but a hardware AMF surface backed by NV12/P010 can still reach 
here,
+    // so reject it explicitly instead of silently producing a green frame.
+    if (ctx->algorithm == AMF_HQ_SCALER_ALGORITHM_VIDEOSR1_1 &&
+        (in_format == AV_PIX_FMT_NV12 || in_format == AV_PIX_FMT_P010)) {
+        av_log(avctx, AV_LOG_ERROR,
+               "sr1-1 (VideoSR1.1) requires a packed RGB format (rgba); "
+               "%s is not supported. Convert the input first (e.g. 
format=rgba) or "
+               "select another algorithm.\n",
+               av_get_pix_fmt_name(in_format));
+        return AVERROR(EINVAL);
+    }
+
     // HQ scaler should be used for upscaling only
     if (inlink->w > outlink->w || inlink->h > outlink->h) {
         av_log(avctx, AV_LOG_ERROR, "AMF HQ scaler should be used for 
upscaling only.\n");
-- 
2.52.0

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

Reply via email to