Commit f42ad4dea8 for ffmpeg

commit f42ad4dea839248c160719b6da6239987e227ef4
Author: Kacper Michajłow <kasper93@gmail.com>
Date:   Wed Sep 9 07:13:15 2026 +0200

    avfilter/vf_format: add chroma_locations parameter

    A '|'-separated list, or the inverse of one for the noformat variant, which
    also excludes an unspecified location, since that keeps the location of the
    input. This is how fftools tells the graph which chroma locations the
    encoder accepts.

    Signed-off-by: Kacper Michajłow <kasper93@gmail.com>

diff --git a/doc/filters.texi b/doc/filters.texi
index 7de2855c78..0d20892f1f 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -14727,6 +14727,10 @@ A '|'-separated list of color range names, such as
 A '|'-separated list of color range names, such as
 "alpha_modes=straight|premultiplied".

+@item chroma_locations
+A '|'-separated list of chroma sample location names, such as
+"chroma_locations=left|topleft".
+
 @end table

 @subsection Examples
diff --git a/libavfilter/vf_format.c b/libavfilter/vf_format.c
index fd3cc4a647..793a482de4 100644
--- a/libavfilter/vf_format.c
+++ b/libavfilter/vf_format.c
@@ -43,11 +43,13 @@ typedef struct FormatContext {
     char *csps;
     char *ranges;
     char *alphamodes;
+    char *chromalocations;

     AVFilterFormats *formats; ///< parsed from `pix_fmts`
     AVFilterFormats *color_spaces; ///< parsed from `csps`
     AVFilterFormats *color_ranges; ///< parsed from `ranges`
     AVFilterFormats *alpha_modes; ///< parsed from `alphamodes`
+    AVFilterFormats *chroma_locations; ///< parsed from `chromalocations`
 } FormatContext;

 static av_cold void uninit(AVFilterContext *ctx)
@@ -57,6 +59,7 @@ static av_cold void uninit(AVFilterContext *ctx)
     ff_formats_unref(&s->color_spaces);
     ff_formats_unref(&s->color_ranges);
     ff_formats_unref(&s->alpha_modes);
+    ff_formats_unref(&s->chroma_locations);
 }

 static av_cold int invert_formats(AVFilterFormats **fmts,
@@ -108,6 +111,7 @@ DEFINE_PARSE(pixel_format, AVPixelFormat, av_get_pix_fmt, "pixel format", !av_pi
 DEFINE_PARSE(color_space, AVColorSpace, av_color_space_from_name, "color space", 0)
 DEFINE_PARSE(color_range, AVColorRange, av_color_range_from_name, "color range", 0)
 DEFINE_PARSE(alpha_mode, AVAlphaMode, av_alpha_mode_from_name, "alpha mode", 0)
+DEFINE_PARSE(chroma_location, AVChromaLocation, av_chroma_location_from_name, "chroma location", 0)

 static av_cold int init(AVFilterContext *ctx)
 {
@@ -116,6 +120,7 @@ static av_cold int init(AVFilterContext *ctx)
     enum AVColorSpace csp;
     enum AVColorRange crg;
     enum AVAlphaMode alm;
+    enum AVChromaLocation cloc;
     int ret;

     #define PARSE_LIST(strfield, fmtfield, tvar, parse) \
@@ -132,12 +137,17 @@ static av_cold int init(AVFilterContext *ctx)
     PARSE_LIST(csps, color_spaces, csp, parse_color_space)
     PARSE_LIST(ranges, color_ranges, crg, parse_color_range)
     PARSE_LIST(alphamodes, alpha_modes, alm, parse_alpha_mode)
+    PARSE_LIST(chromalocations, chroma_locations, cloc, parse_chroma_location)

     if (!strcmp(ctx->filter->name, "noformat")) {
+        if (s->chroma_locations &&
+            (ret = ff_add_format(&s->chroma_locations, AVCHROMA_LOC_UNSPECIFIED)) < 0)
+            return ret;
         if ((ret = invert_formats(&s->formats,      ff_all_formats(AVMEDIA_TYPE_VIDEO))) < 0 ||
             (ret = invert_formats(&s->color_spaces, ff_all_color_spaces())) < 0 ||
             (ret = invert_formats(&s->color_ranges, ff_all_color_ranges())) < 0 ||
-            (ret = invert_formats(&s->alpha_modes,  ff_all_alpha_modes())) < 0)
+            (ret = invert_formats(&s->alpha_modes,  ff_all_alpha_modes())) < 0 ||
+            (ret = invert_formats(&s->chroma_locations, ff_all_chroma_locations())) < 0)
             return ret;
     }

@@ -145,7 +155,8 @@ static av_cold int init(AVFilterContext *ctx)
     if (s->formats      && (ret = ff_formats_ref(s->formats,      &s->formats)) < 0 ||
         s->color_spaces && (ret = ff_formats_ref(s->color_spaces, &s->color_spaces)) < 0 ||
         s->color_ranges && (ret = ff_formats_ref(s->color_ranges, &s->color_ranges)) < 0 ||
-        s->alpha_modes  && (ret = ff_formats_ref(s->alpha_modes,  &s->alpha_modes)) < 0)
+        s->alpha_modes  && (ret = ff_formats_ref(s->alpha_modes,  &s->alpha_modes)) < 0 ||
+        s->chroma_locations && (ret = ff_formats_ref(s->chroma_locations, &s->chroma_locations)) < 0)
         return ret;

     return 0;
@@ -161,7 +172,8 @@ static int query_formats(const AVFilterContext *ctx,
     if (s->formats      && (ret = ff_set_common_formats2     (ctx, cfg_in, cfg_out, s->formats)) < 0 ||
         s->color_spaces && (ret = ff_set_common_color_spaces2(ctx, cfg_in, cfg_out, s->color_spaces)) < 0 ||
         s->color_ranges && (ret = ff_set_common_color_ranges2(ctx, cfg_in, cfg_out, s->color_ranges)) < 0 ||
-        s->alpha_modes  && (ret = ff_set_common_alpha_modes2(ctx, cfg_in, cfg_out, s->alpha_modes)) < 0)
+        s->alpha_modes  && (ret = ff_set_common_alpha_modes2(ctx, cfg_in, cfg_out, s->alpha_modes)) < 0 ||
+        s->chroma_locations && (ret = ff_set_common_chroma_locations2(ctx, cfg_in, cfg_out, s->chroma_locations)) < 0)
         return ret;

     return 0;
@@ -174,6 +186,7 @@ static const AVOption options[] = {
     { "color_spaces", "A '|'-separated list of color spaces", OFFSET(csps), AV_OPT_TYPE_STRING, .flags = AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM },
     { "color_ranges", "A '|'-separated list of color ranges", OFFSET(ranges), AV_OPT_TYPE_STRING, .flags = AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM },
     { "alpha_modes", "A '|'-separated list of alpha modes", OFFSET(alphamodes), AV_OPT_TYPE_STRING, .flags = AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM },
+    { "chroma_locations", "A '|'-separated list of chroma sample locations", OFFSET(chromalocations), AV_OPT_TYPE_STRING, .flags = AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM },
     { NULL }
 };