The branch, master has been updated
       via  01b105bb06f30d275c3a1932de4d03a4767f8a18 (commit)
       via  9a386078cc0484f064e6cc4309a2a9048bd25fae (commit)
       via  84b365d522a59c5e80fb0b3f960d1c36a2674797 (commit)
       via  6c3a63112be927526b08c0154b2df786fa7bce3d (commit)
       via  7b564e2efc295ca205642c5c2ddfe5d8e77ecf08 (commit)
       via  ad5b151f88aed49b4c36e764186214c13e0788ac (commit)
       via  f5bc9704edb3254e65c108509052f19eb77622c1 (commit)
       via  c1717cb6669f986a8bd04c8bfc5e37927c12769d (commit)
      from  c9710dae3c6151a22f0fff60f0a9b4514f6a3b97 (commit)


- Log -----------------------------------------------------------------
commit 01b105bb06f30d275c3a1932de4d03a4767f8a18
Author:     Niklas Haas <[email protected]>
AuthorDate: Thu Nov 6 17:00:04 2025 +0100
Commit:     Niklas Haas <[email protected]>
CommitDate: Thu Nov 6 20:34:51 2025 +0000

    tests/fate/swscale: add swscale self-test
    
    This one takes about 2.93s on my machine, but ensures that every pixel
    format conversion roundtrips correctly. Note that due to existing bugs in
    libswscale, this one only passes when using the new format conversion code.
    
    Restrict the test to -v 16 (AV_LOG_ERROR) to avoid excess amounts of output.

diff --git a/tests/fate/libswscale.mak b/tests/fate/libswscale.mak
index 4c29220e6f..59da506648 100644
--- a/tests/fate/libswscale.mak
+++ b/tests/fate/libswscale.mak
@@ -31,6 +31,11 @@ fate-sws-yuv-range: CMD = framecrc \
   -frames 1 \
   -vf 
scale=in_color_matrix=bt601:in_range=limited:out_color_matrix=bt601:out_range=full:flags=+accurate_rnd+bitexact
 
+# This self-check currently fails for legacy swscale, so pass SWS_UNSTABLE to 
use the new code
+FATE_LIBSWSCALE-$(CONFIG_UNSTABLE) += fate-sws-unscaled
+fate-sws-unscaled: libswscale/tests/swscale$(EXESUF)
+fate-sws-unscaled: CMD = run libswscale/tests/swscale$(EXESUF) -unscaled 1 
-flags 0x100000 -v 16
+
 FATE_LIBSWSCALE += $(FATE_LIBSWSCALE-yes)
 FATE_LIBSWSCALE_SAMPLES += $(FATE_LIBSWSCALE_SAMPLES-yes)
 FATE-$(CONFIG_SWSCALE) += $(FATE_LIBSWSCALE)
diff --git a/tests/ref/fate/sws-unscaled b/tests/ref/fate/sws-unscaled
new file mode 100644
index 0000000000..e69de29bb2

commit 9a386078cc0484f064e6cc4309a2a9048bd25fae
Author:     Niklas Haas <[email protected]>
AuthorDate: Thu Nov 6 19:03:22 2025 +0100
Commit:     Niklas Haas <[email protected]>
CommitDate: Thu Nov 6 20:34:51 2025 +0000

    tests/swscale: use av_log() where appropriate
    
    We can't use ANSI color codes inside av_log(), so fall back to printf()
    for these; but match the INFO verbosity level.
    
    Also change the format slightly to drop SSIM numbers down to just below
    VERBOSE level, since VERBOSE tends to generate a lot of swscale related
    spam.

diff --git a/libswscale/tests/swscale.c b/libswscale/tests/swscale.c
index 564f38af2e..8a85bef94e 100644
--- a/libswscale/tests/swscale.c
+++ b/libswscale/tests/swscale.c
@@ -264,8 +264,8 @@ static int run_test(enum AVPixelFormat src_fmt, enum 
AVPixelFormat dst_fmt,
     dst->height = dst_h;
 
     if (sws_scale_frame(sws[0], src, ref) < 0) {
-        fprintf(stderr, "Failed %s ---> %s\n", 
av_get_pix_fmt_name(ref->format),
-                av_get_pix_fmt_name(src->format));
+        av_log(NULL, AV_LOG_ERROR, "Failed %s ---> %s\n",
+               av_get_pix_fmt_name(ref->format), 
av_get_pix_fmt_name(src->format));
         goto error;
     }
 
@@ -277,8 +277,8 @@ static int run_test(enum AVPixelFormat src_fmt, enum 
AVPixelFormat dst_fmt,
 
     for (int i = 0; i < opts.iters; i++) {
         if (sws_scale_frame(sws[1], dst, src) < 0) {
-            fprintf(stderr, "Failed %s ---> %s\n", 
av_get_pix_fmt_name(src->format),
-                    av_get_pix_fmt_name(dst->format));
+            av_log(NULL, AV_LOG_ERROR, "Failed %s ---> %s\n",
+                   av_get_pix_fmt_name(src->format), 
av_get_pix_fmt_name(dst->format));
             goto error;
         }
     }
@@ -286,23 +286,29 @@ static int run_test(enum AVPixelFormat src_fmt, enum 
AVPixelFormat dst_fmt,
     time = av_gettime_relative() - time;
 
     if (sws_scale_frame(sws[2], out, dst) < 0) {
-        fprintf(stderr, "Failed %s ---> %s\n", 
av_get_pix_fmt_name(dst->format),
-                av_get_pix_fmt_name(out->format));
+        av_log(NULL, AV_LOG_ERROR, "Failed %s ---> %s\n",
+               av_get_pix_fmt_name(dst->format), 
av_get_pix_fmt_name(out->format));
         goto error;
     }
 
     get_ssim(ssim, out, ref, comps);
-    printf("%s %dx%d -> %s %3dx%3d, flags=0x%x dither=%u, "
-           "SSIM {Y=%f U=%f V=%f A=%f}\n",
+    av_log(NULL, AV_LOG_INFO, "%s %dx%d -> %s %3dx%3d, flags=0x%x dither=%u\n",
            av_get_pix_fmt_name(src->format), src->width, src->height,
            av_get_pix_fmt_name(dst->format), dst->width, dst->height,
-           mode.flags, mode.dither,
+           mode.flags, mode.dither);
+
+    av_log(NULL, AV_LOG_VERBOSE - 4, "  SSIM {Y=%f U=%f V=%f A=%f}\n",
            ssim[0], ssim[1], ssim[2], ssim[3]);
 
     loss = get_loss(ssim);
     if (loss - expected_loss > 1e-4 && dst_w >= ref->width && dst_h >= 
ref->height) {
-        int bad = loss - expected_loss > 1e-2;
-        printf("\033[1;31m  loss %g is %s by %g, expected loss %g\033[0m\n",
+        const int bad = loss - expected_loss > 1e-2;
+        const int level = bad ? AV_LOG_ERROR : AV_LOG_WARNING;
+        av_log(NULL, level, "%s %dx%d -> %s %3dx%3d, flags=0x%x dither=%u\n",
+               av_get_pix_fmt_name(src->format), src->width, src->height,
+               av_get_pix_fmt_name(dst->format), dst->width, dst->height,
+               mode.flags, mode.dither);
+        av_log(NULL, level, "  loss %g is %s by %g, expected loss %g\n",
                loss, bad ? "WORSE" : "worse", loss - expected_loss, 
expected_loss);
         if (bad)
             goto error;
@@ -312,8 +318,8 @@ static int run_test(enum AVPixelFormat src_fmt, enum 
AVPixelFormat dst_fmt,
         /* Compare against the legacy swscale API as a reference */
         time_ref = av_gettime_relative();
         if (scale_legacy(dst, src, mode, opts) < 0) {
-            fprintf(stderr, "Failed ref %s ---> %s\n", 
av_get_pix_fmt_name(src->format),
-                    av_get_pix_fmt_name(dst->format));
+            av_log(NULL, AV_LOG_ERROR, "Failed ref %s ---> %s\n",
+                   av_get_pix_fmt_name(src->format), 
av_get_pix_fmt_name(dst->format));
             goto error;
         }
         time_ref = av_gettime_relative() - time_ref;
@@ -341,8 +347,9 @@ static int run_test(enum AVPixelFormat src_fmt, enum 
AVPixelFormat dst_fmt,
         const float loss_ref = get_loss(ssim_ref);
         if (loss - loss_ref > 1e-4) {
             int bad = loss - loss_ref > 1e-2;
-            printf("\033[1;31m  loss %g is %s by %g, ref loss %g, "
-                   "SSIM {Y=%f U=%f V=%f A=%f}\033[0m\n",
+            av_log(NULL, bad ? AV_LOG_ERROR : AV_LOG_WARNING,
+                   "  loss %g is %s by %g, ref loss %g, "
+                   "SSIM {Y=%f U=%f V=%f A=%f}\n",
                    loss, bad ? "WORSE" : "worse", loss - loss_ref, loss_ref,
                    ssim_ref[0], ssim_ref[1], ssim_ref[2], ssim_ref[3]);
             if (bad)
@@ -359,11 +366,13 @@ static int run_test(enum AVPixelFormat src_fmt, enum 
AVPixelFormat dst_fmt,
             speedup_count++;
         }
 
-        printf("  time=%"PRId64" us, ref=%"PRId64" us, speedup=%.3fx 
%s%s\033[0m\n",
-               time / opts.iters, time_ref / opts.iters, ratio,
-               speedup_color(ratio), ratio >= 1.0 ? "faster" : "slower");
+        if (av_log_get_level() >= AV_LOG_INFO) {
+            printf("  time=%"PRId64" us, ref=%"PRId64" us, speedup=%.3fx 
%s%s\033[0m\n",
+                   time / opts.iters, time_ref / opts.iters, ratio,
+                   speedup_color(ratio), ratio >= 1.0 ? "faster" : "slower");
+        }
     } else if (opts.bench) {
-        printf("  time=%"PRId64" us\n", time / opts.iters);
+        av_log(NULL, AV_LOG_INFO, "  time=%"PRId64" us\n", time / opts.iters);
     }
 
     fflush(stdout);
@@ -466,7 +475,7 @@ static int run_file_tests(const AVFrame *ref, FILE *fp, 
struct options opts)
         if (src_fmt == AV_PIX_FMT_NONE || dst_fmt == AV_PIX_FMT_NONE ||
             sw != ref->width || sh != ref->height || dw > 8192 || dh > 8192 ||
             mode.dither >= SWS_DITHER_NB) {
-            fprintf(stderr, "malformed input file\n");
+            av_log(NULL, AV_LOG_FATAL, "malformed input file\n");
             return -1;
         }
 

commit 84b365d522a59c5e80fb0b3f960d1c36a2674797
Author:     Niklas Haas <[email protected]>
AuthorDate: Thu Nov 6 18:16:10 2025 +0100
Commit:     Niklas Haas <[email protected]>
CommitDate: Thu Nov 6 18:16:10 2025 +0100

    avfilter/avfiltergraph: print both failing links on conversion error
    
    This is more informative than the current behavior, because when the first
    MERGE() succeeds but the second fails, the original link already has
    merged formats and thus the error message is confusing.

diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
index 285a701d09..a46a7bd408 100644
--- a/libavfilter/avfiltergraph.c
+++ b/libavfilter/avfiltergraph.c
@@ -692,7 +692,8 @@ retry:
                         av_log(log_ctx, AV_LOG_ERROR,
                                "Impossible to convert between the formats 
supported by the filter "
                                "'%s' and the filter '%s'\n", link->src->name, 
link->dst->name);
-                        print_link_formats(log_ctx, AV_LOG_ERROR, link, &m, 1);
+                        print_link_formats(log_ctx, AV_LOG_ERROR, inlink,  &m, 
1);
+                        print_link_formats(log_ctx, AV_LOG_ERROR, outlink, &m, 
1);
                         return AVERROR(ENOSYS);
                     } else {
                         count_merged += 2;

commit 6c3a63112be927526b08c0154b2df786fa7bce3d
Author:     Niklas Haas <[email protected]>
AuthorDate: Thu Nov 6 18:09:36 2025 +0100
Commit:     Niklas Haas <[email protected]>
CommitDate: Thu Nov 6 18:09:36 2025 +0100

    avfilter/avfiltergraph: only print format lists for failing mergers
    
    Instead of printing all format lists on a link negotiation error, just print
    the relevant/failing format lists.

diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
index 15978fc7a8..285a701d09 100644
--- a/libavfilter/avfiltergraph.c
+++ b/libavfilter/avfiltergraph.c
@@ -443,7 +443,9 @@ static int formats_declared(AVFilterContext *f)
     return 1;
 }
 
-static void print_link_formats(void *log_ctx, int level, const AVFilterLink *l)
+static void print_link_formats(void *log_ctx, int level, const AVFilterLink *l,
+                               const AVFilterFormatsMerger *mergers[],
+                               int nb_mergers)
 {
     if (av_log_get_level() < level)
         return;
@@ -454,9 +456,8 @@ static void print_link_formats(void *log_ctx, int level, 
const AVFilterLink *l)
     av_log(log_ctx, level, "Link '%s.%s' -> '%s.%s':\n",
            l->src->name, l->srcpad->name, l->dst->name, l->dstpad->name);
 
-    const AVFilterNegotiation *neg = ff_filter_get_negotiation(l);
-    for (unsigned i = 0; i < neg->nb_mergers; i++) {
-        const AVFilterFormatsMerger *m = &neg->mergers[i];
+    for (unsigned i = 0; i < nb_mergers; i++) {
+        const AVFilterFormatsMerger *m = mergers[i];
         av_log(log_ctx, level, "  %s:\n", m->name);
         m->print_list(&bp, FF_FIELD_AT(void *, m->offset, l->incfg));
         if (av_bprint_is_complete(&bp))
@@ -554,8 +555,9 @@ retry:
             AVFilterLink *link = filter->inputs[j];
             const AVFilterNegotiation *neg;
             AVFilterContext *conv[4];
+            const AVFilterFormatsMerger *mergers[4]; /* triggered mergers */
             const char *conv_filters[4], *conv_opts[4] = {0};
-            unsigned neg_step, num_conv = 0;
+            unsigned neg_step, num_conv = 0, num_mergers = 0;
 
             if (!link)
                 continue;
@@ -578,6 +580,8 @@ retry:
                             conv_opts[num_conv] = FF_FIELD_AT(char *, 
m->conversion_opts_offset, *graph);
                         num_conv++;
                     }
+                    av_assert1(num_mergers < FF_ARRAY_ELEMS(mergers));
+                    mergers[num_mergers++] = m;
                 }
             }
             for (neg_step = 0; neg_step < neg->nb_mergers; neg_step++) {
@@ -594,6 +598,7 @@ retry:
                     if (ret < 0)
                         return ret;
                     if (!ret) {
+                        mergers[num_mergers++] = m;
                         conv_filters[num_conv] = m->conversion_filter;
                         if (m->conversion_opts_offset)
                             conv_opts[num_conv] = FF_FIELD_AT(char *, 
m->conversion_opts_offset, *graph);
@@ -616,7 +621,7 @@ retry:
                            "The filters '%s' and '%s' do not have a common 
format "
                            "and automatic conversion is disabled.\n",
                            link->src->name, link->dst->name);
-                    print_link_formats(log_ctx, AV_LOG_ERROR, link);
+                    print_link_formats(log_ctx, AV_LOG_ERROR, link, mergers, 
num_mergers);
                     return AVERROR(EINVAL);
                 }
 
@@ -624,7 +629,7 @@ retry:
                     av_log(log_ctx, AV_LOG_ERROR,
                            "'%s' filter not present, cannot convert 
formats.\n",
                            conv_filters[k]);
-                    print_link_formats(log_ctx, AV_LOG_ERROR, link);
+                    print_link_formats(log_ctx, AV_LOG_ERROR, link, mergers, 
num_mergers);
                     return AVERROR(EINVAL);
                 }
                 snprintf(inst_name, sizeof(inst_name), "auto_%s_%d",
@@ -687,7 +692,7 @@ retry:
                         av_log(log_ctx, AV_LOG_ERROR,
                                "Impossible to convert between the formats 
supported by the filter "
                                "'%s' and the filter '%s'\n", link->src->name, 
link->dst->name);
-                        print_link_formats(log_ctx, AV_LOG_ERROR, link);
+                        print_link_formats(log_ctx, AV_LOG_ERROR, link, &m, 1);
                         return AVERROR(ENOSYS);
                     } else {
                         count_merged += 2;

commit 7b564e2efc295ca205642c5c2ddfe5d8e77ecf08
Author:     Niklas Haas <[email protected]>
AuthorDate: Thu Nov 6 18:01:37 2025 +0100
Commit:     Niklas Haas <[email protected]>
CommitDate: Thu Nov 6 18:01:37 2025 +0100

    avfilter/avfiltergraph: print all format lists on config failure
    
    Instead of just printing the pixel/sample formats.

diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
index 4c80204f01..15978fc7a8 100644
--- a/libavfilter/avfiltergraph.c
+++ b/libavfilter/avfiltergraph.c
@@ -443,60 +443,73 @@ static int formats_declared(AVFilterContext *f)
     return 1;
 }
 
-static void print_formats(void *log_ctx, int level, enum AVMediaType type,
-                          const AVFilterFormats *formats)
+static void print_link_formats(void *log_ctx, int level, const AVFilterLink *l)
 {
+    if (av_log_get_level() < level)
+        return;
+
     AVBPrint bp;
     av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED);
 
-    switch (type) {
-    case AVMEDIA_TYPE_VIDEO:
-        for (unsigned i = 0; i < formats->nb_formats; i++)
-            av_bprintf(&bp, "%s%s", bp.len ? " " : "", 
av_get_pix_fmt_name(formats->formats[i]));
-        break;
-    case AVMEDIA_TYPE_AUDIO:
-        for (unsigned i = 0; i < formats->nb_formats; i++)
-            av_bprintf(&bp, "%s%s", bp.len ? " " : "", 
av_get_sample_fmt_name(formats->formats[i]));
-        break;
-    default:
-        av_bprintf(&bp, "(unknown)");
-        break;
+    av_log(log_ctx, level, "Link '%s.%s' -> '%s.%s':\n",
+           l->src->name, l->srcpad->name, l->dst->name, l->dstpad->name);
+
+    const AVFilterNegotiation *neg = ff_filter_get_negotiation(l);
+    for (unsigned i = 0; i < neg->nb_mergers; i++) {
+        const AVFilterFormatsMerger *m = &neg->mergers[i];
+        av_log(log_ctx, level, "  %s:\n", m->name);
+        m->print_list(&bp, FF_FIELD_AT(void *, m->offset, l->incfg));
+        if (av_bprint_is_complete(&bp))
+            av_log(log_ctx, level, "    src: %s\n", bp.str);
+        av_bprint_clear(&bp);
+
+        m->print_list(&bp, FF_FIELD_AT(void *, m->offset, l->outcfg));
+        if (av_bprint_is_complete(&bp))
+            av_log(log_ctx, level, "    dst: %s\n", bp.str);
+        av_bprint_clear(&bp);
     }
 
-    if (av_bprint_is_complete(&bp)) {
-        av_log(log_ctx, level, "%s\n", bp.str);
-    } else {
-        av_log(log_ctx, level, "(out of memory)\n");
-    }
     av_bprint_finalize(&bp, NULL);
 }
 
-static void print_link_formats(void *log_ctx, int level, const AVFilterLink *l)
-{
-    if (av_log_get_level() < level)
-        return;
-
-    av_log(log_ctx, level, "Link '%s.%s' -> '%s.%s':\n"
-                           "  src: ", l->src->name, l->srcpad->name, 
l->dst->name, l->dstpad->name);
-    print_formats(log_ctx, level, l->type, l->incfg.formats);
-    av_log(log_ctx, level, "  dst: ");
-    print_formats(log_ctx, level, l->type, l->outcfg.formats);
-}
-
 static void print_filter_formats(void *log_ctx, int level, const 
AVFilterContext *f)
 {
     if (av_log_get_level() < level)
         return;
 
+    AVBPrint bp;
+    av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED);
+
     av_log(log_ctx, level, "Filter '%s' formats:\n", f->name);
     for (int i = 0; i < f->nb_inputs; i++) {
-        av_log(log_ctx, level, "  in[%d] '%s': ", i, f->input_pads[i].name);
-        print_formats(log_ctx, level, f->inputs[i]->type, 
f->inputs[i]->outcfg.formats);
+        const AVFilterLink *in = f->inputs[i];
+        const AVFilterNegotiation *neg = ff_filter_get_negotiation(in);
+        av_log(log_ctx, level, "  in[%d] '%s':", i, f->input_pads[i].name);
+
+        for (unsigned i = 0; i < neg->nb_mergers; i++) {
+            const AVFilterFormatsMerger *m = &neg->mergers[i];
+            m->print_list(&bp, FF_FIELD_AT(void *, m->offset, in->outcfg));
+            if (av_bprint_is_complete(&bp))
+                av_log(log_ctx, level, "    %s: %s", m->name, bp.str);
+            av_bprint_clear(&bp);
+        }
     }
+
     for (int i = 0; i < f->nb_outputs; i++) {
-        av_log(log_ctx, level, "  out[%d] '%s': ", i, f->output_pads[i].name);
-        print_formats(log_ctx, level, f->outputs[i]->type, 
f->outputs[i]->incfg.formats);
+        const AVFilterLink *out = f->outputs[i];
+        const AVFilterNegotiation *neg = ff_filter_get_negotiation(out);
+        av_log(log_ctx, level, "  out[%d] '%s':", i, f->output_pads[i].name);
+
+        for (unsigned i = 0; i < neg->nb_mergers; i++) {
+            const AVFilterFormatsMerger *m = &neg->mergers[i];
+            m->print_list(&bp, FF_FIELD_AT(void *, m->offset, out->incfg));
+            if (av_bprint_is_complete(&bp))
+                av_log(log_ctx, level, "    %s: %s", m->name, bp.str);
+            av_bprint_clear(&bp);
+        }
     }
+
+    av_bprint_finalize(&bp, NULL);
 }
 
 /**

commit ad5b151f88aed49b4c36e764186214c13e0788ac
Author:     Niklas Haas <[email protected]>
AuthorDate: Thu Nov 6 17:58:10 2025 +0100
Commit:     Niklas Haas <[email protected]>
CommitDate: Thu Nov 6 18:01:33 2025 +0100

    avfilter/formats: add name field to AVFilterFormatMerger
    
    Needed to properly print format lists on format configuration failure.

diff --git a/libavfilter/formats.c b/libavfilter/formats.c
index 36e45c53c1..5ba961f059 100644
--- a/libavfilter/formats.c
+++ b/libavfilter/formats.c
@@ -389,6 +389,7 @@ static void print_sample_rate(AVBPrint *bp, const void 
*ratesp)
 
 static const AVFilterFormatsMerger mergers_video[] = {
     {
+        .name       = "Pixel formats",
         .offset     = offsetof(AVFilterFormatsConfig, formats),
         .merge      = merge_pix_fmts,
         .can_merge  = can_merge_pix_fmts,
@@ -396,6 +397,7 @@ static const AVFilterFormatsMerger mergers_video[] = {
         CONVERSION_FILTER_SWSCALE
     },
     {
+        .name       = "Color spaces",
         .offset     = offsetof(AVFilterFormatsConfig, color_spaces),
         .merge      = merge_generic,
         .can_merge  = can_merge_generic,
@@ -403,6 +405,7 @@ static const AVFilterFormatsMerger mergers_video[] = {
         CONVERSION_FILTER_SWSCALE
     },
     {
+        .name       = "Color ranges",
         .offset     = offsetof(AVFilterFormatsConfig, color_ranges),
         .merge      = merge_generic,
         .can_merge  = can_merge_generic,
@@ -410,6 +413,7 @@ static const AVFilterFormatsMerger mergers_video[] = {
         CONVERSION_FILTER_SWSCALE
     },
     {
+        .name       = "Alpha modes",
         .offset     = offsetof(AVFilterFormatsConfig, alpha_modes),
         .merge      = merge_generic,
         .can_merge  = can_merge_generic,
@@ -420,6 +424,7 @@ static const AVFilterFormatsMerger mergers_video[] = {
 
 static const AVFilterFormatsMerger mergers_audio[] = {
     {
+        .name       = "Channel layouts",
         .offset     = offsetof(AVFilterFormatsConfig, channel_layouts),
         .merge      = merge_channel_layouts,
         .can_merge  = can_merge_channel_layouts,
@@ -427,6 +432,7 @@ static const AVFilterFormatsMerger mergers_audio[] = {
         CONVERSION_FILTER_ARESAMPLE
     },
     {
+        .name       = "Sample rates",
         .offset     = offsetof(AVFilterFormatsConfig, samplerates),
         .merge      = merge_samplerates,
         .can_merge  = can_merge_samplerates,
@@ -434,6 +440,7 @@ static const AVFilterFormatsMerger mergers_audio[] = {
         CONVERSION_FILTER_ARESAMPLE
     },
     {
+        .name       = "Sample formats",
         .offset     = offsetof(AVFilterFormatsConfig, formats),
         .merge      = merge_sample_fmts,
         .can_merge  = can_merge_sample_fmts,
diff --git a/libavfilter/formats.h b/libavfilter/formats.h
index 4fe96187ba..969bb230f1 100644
--- a/libavfilter/formats.h
+++ b/libavfilter/formats.h
@@ -516,6 +516,7 @@ int ff_formats_check_alpha_modes(void *log, const 
AVFilterFormats *fmts);
 struct AVBPrint;
 
 typedef struct AVFilterFormatMerger {
+    const char *name;
     unsigned offset;
     int (*merge)(void *a, void *b);
     int (*can_merge)(const void *a, const void *b);

commit f5bc9704edb3254e65c108509052f19eb77622c1
Author:     Niklas Haas <[email protected]>
AuthorDate: Thu Nov 6 17:48:32 2025 +0100
Commit:     Niklas Haas <[email protected]>
CommitDate: Thu Nov 6 17:48:50 2025 +0100

    avfilter/formats: constify ff_filter_get_negotiation

diff --git a/libavfilter/formats.c b/libavfilter/formats.c
index b9487fe0cf..36e45c53c1 100644
--- a/libavfilter/formats.c
+++ b/libavfilter/formats.c
@@ -452,7 +452,7 @@ static const AVFilterNegotiation negotiate_audio = {
     .mergers = mergers_audio,
 };
 
-const AVFilterNegotiation *ff_filter_get_negotiation(AVFilterLink *link)
+const AVFilterNegotiation *ff_filter_get_negotiation(const AVFilterLink *link)
 {
     switch (link->type) {
     case AVMEDIA_TYPE_VIDEO: return &negotiate_video;
diff --git a/libavfilter/formats.h b/libavfilter/formats.h
index d0b2a0b96a..4fe96187ba 100644
--- a/libavfilter/formats.h
+++ b/libavfilter/formats.h
@@ -614,6 +614,6 @@ typedef struct AVFilterNegotiation {
     const AVFilterFormatsMerger *mergers;
 } AVFilterNegotiation;
 
-const AVFilterNegotiation *ff_filter_get_negotiation(AVFilterLink *link);
+const AVFilterNegotiation *ff_filter_get_negotiation(const AVFilterLink *link);
 
 #endif /* AVFILTER_FORMATS_H */

commit c1717cb6669f986a8bd04c8bfc5e37927c12769d
Author:     Niklas Haas <[email protected]>
AuthorDate: Thu Nov 6 17:26:19 2025 +0100
Commit:     Niklas Haas <[email protected]>
CommitDate: Thu Nov 6 17:34:43 2025 +0100

    avfilter/format: add print_list() to AVFilterFormatsMerger
    
    So that the generic code can correctly print format lists for failing 
mergers.

diff --git a/libavfilter/formats.c b/libavfilter/formats.c
index 847199dda1..b9487fe0cf 100644
--- a/libavfilter/formats.c
+++ b/libavfilter/formats.c
@@ -20,6 +20,7 @@
  */
 
 #include "libavutil/avassert.h"
+#include "libavutil/bprint.h"
 #include "libavutil/channel_layout.h"
 #include "libavutil/common.h"
 #include "libavutil/mem.h"
@@ -345,6 +346,39 @@ static int merge_generic(void *a, void *b)
     return merge_generic_internal(a, b, 0);
 }
 
+#define PRINT_NAME(type, type_name)                                            
 \
+static void print_##type_name(AVBPrint *bp, const void *fmtsp)                 
 \
+{                                                                              
 \
+    const AVFilterFormats *fmts = fmtsp;                                       
 \
+    for (int i = 0; i < fmts->nb_formats; i++) {                               
 \
+        const char *name = av_##type_name(fmts->formats[i]);                   
 \
+        av_bprint_chars(bp, ' ', i ? 1 : 0);                                   
 \
+        av_bprint_append_data(bp, name, name ? strlen(name) : 0);              
 \
+    }                                                                          
 \
+}
+
+PRINT_NAME(enum AVSampleFormat, get_sample_fmt_name)
+PRINT_NAME(enum AVPixelFormat,  get_pix_fmt_name)
+PRINT_NAME(enum AVColorSpace,   color_space_name)
+PRINT_NAME(enum AVColorRange,   color_range_name)
+PRINT_NAME(enum AVAlphaMode,    alpha_mode_name)
+
+static void print_channel_layout_desc(AVBPrint *bp, const void *layoutsp)
+{
+    const AVFilterChannelLayouts *layouts = layoutsp;
+    for (int i = 0; i < layouts->nb_channel_layouts; i++) {
+        av_bprint_chars(bp, ' ', i ? 1 : 0);
+        av_channel_layout_describe_bprint(&layouts->channel_layouts[i], bp);
+    }
+}
+
+static void print_sample_rate(AVBPrint *bp, const void *ratesp)
+{
+    const AVFilterFormats *rates = ratesp;
+    for (int i = 0; i < rates->nb_formats; i++)
+        av_bprintf(bp, "%s%d", i ? " " : "", rates->formats[i]);
+}
+
 #define CONVERSION_FILTER_SWSCALE \
     .conversion_filter = "scale", \
     .conversion_opts_offset = offsetof(AVFilterGraph, scale_sws_opts),
@@ -358,24 +392,28 @@ static const AVFilterFormatsMerger mergers_video[] = {
         .offset     = offsetof(AVFilterFormatsConfig, formats),
         .merge      = merge_pix_fmts,
         .can_merge  = can_merge_pix_fmts,
+        .print_list = print_get_pix_fmt_name,
         CONVERSION_FILTER_SWSCALE
     },
     {
         .offset     = offsetof(AVFilterFormatsConfig, color_spaces),
         .merge      = merge_generic,
         .can_merge  = can_merge_generic,
+        .print_list = print_color_space_name,
         CONVERSION_FILTER_SWSCALE
     },
     {
         .offset     = offsetof(AVFilterFormatsConfig, color_ranges),
         .merge      = merge_generic,
         .can_merge  = can_merge_generic,
+        .print_list = print_color_range_name,
         CONVERSION_FILTER_SWSCALE
     },
     {
         .offset     = offsetof(AVFilterFormatsConfig, alpha_modes),
         .merge      = merge_generic,
         .can_merge  = can_merge_generic,
+        .print_list = print_alpha_mode_name,
         .conversion_filter = "premultiply_dynamic",
     },
 };
@@ -385,18 +423,21 @@ static const AVFilterFormatsMerger mergers_audio[] = {
         .offset     = offsetof(AVFilterFormatsConfig, channel_layouts),
         .merge      = merge_channel_layouts,
         .can_merge  = can_merge_channel_layouts,
+        .print_list = print_channel_layout_desc,
         CONVERSION_FILTER_ARESAMPLE
     },
     {
         .offset     = offsetof(AVFilterFormatsConfig, samplerates),
         .merge      = merge_samplerates,
         .can_merge  = can_merge_samplerates,
+        .print_list = print_sample_rate,
         CONVERSION_FILTER_ARESAMPLE
     },
     {
         .offset     = offsetof(AVFilterFormatsConfig, formats),
         .merge      = merge_sample_fmts,
         .can_merge  = can_merge_sample_fmts,
+        .print_list = print_get_sample_fmt_name,
         CONVERSION_FILTER_ARESAMPLE
     },
 };
diff --git a/libavfilter/formats.h b/libavfilter/formats.h
index 0c92ecad3f..d0b2a0b96a 100644
--- a/libavfilter/formats.h
+++ b/libavfilter/formats.h
@@ -513,10 +513,13 @@ int ff_formats_check_color_ranges(void *log, const 
AVFilterFormats *fmts);
  */
 int ff_formats_check_alpha_modes(void *log, const AVFilterFormats *fmts);
 
+struct AVBPrint;
+
 typedef struct AVFilterFormatMerger {
     unsigned offset;
     int (*merge)(void *a, void *b);
     int (*can_merge)(const void *a, const void *b);
+    void (*print_list)(struct AVBPrint *bp, const void *fmts);
     const char *conversion_filter;
     unsigned conversion_opts_offset;
 } AVFilterFormatsMerger;

-----------------------------------------------------------------------

Summary of changes:
 libavfilter/avfiltergraph.c                        | 97 +++++++++++++---------
 libavfilter/formats.c                              | 50 ++++++++++-
 libavfilter/formats.h                              |  6 +-
 libswscale/tests/swscale.c                         | 49 ++++++-----
 tests/fate/libswscale.mak                          |  5 ++
 .../fate/{ffmpeg-error-rate-fail => sws-unscaled}  |  0
 6 files changed, 146 insertions(+), 61 deletions(-)
 copy tests/ref/fate/{ffmpeg-error-rate-fail => sws-unscaled} (100%)


hooks/post-receive
-- 

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

Reply via email to