From ff63d4865bc553ca58b923d77df566b6979d2f2d Mon Sep 17 00:00:00 2001 From: GeoffreyAA Date: Fri, 23 Jan 2026 11:32:11 +0000 Subject: [PATCH] avfilter/vf_libplacebo: add chroma_location option Add chroma_location option so that, in the subsampled-to-subsampled case, the destination's chroma siting can be changed from the source's without having to use other filters. Useful, for example, when converting BT.2020 to BT.709, where the former customarily uses "top left" and the latter "left." Update documentation. Closes: #21185 --- doc/filters.texi | 1 + libavfilter/vf_libplacebo.c | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/doc/filters.texi b/doc/filters.texi index 8a7e370a60..0f64b4a3fa 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -16689,6 +16689,7 @@ exist. @item color_primaries @item color_trc @item range +@item chroma_location Configure the colorspace that output frames will be delivered in. The default value of @code{auto} outputs frames in the same format as the input frames, leading to no change. For any other value, conversion will be performed. diff --git a/libavfilter/vf_libplacebo.c b/libavfilter/vf_libplacebo.c index 74c1fd7214..e355f658f7 100644 --- a/libavfilter/vf_libplacebo.c +++ b/libavfilter/vf_libplacebo.c @@ -219,6 +219,7 @@ typedef struct LibplaceboContext { int color_range; int color_primaries; int color_trc; + int chroma_location; int rotation; int alpha_mode; AVDictionary *extra_opts; @@ -1039,6 +1040,8 @@ static int output_frame(AVFilterContext *ctx, int64_t pts) out->color_trc = s->color_trc; if (s->color_primaries >= 0) out->color_primaries = s->color_primaries; + if (s->chroma_location >= 0) + out->chroma_location = s->chroma_location; /* Strip side data if no longer relevant */ if (out->width != ref->width || out->height != ref->height) @@ -1695,6 +1698,17 @@ static const AVOption libplacebo_options[] = { {"arib-std-b67", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_ARIB_STD_B67}, INT_MIN, INT_MAX, STATIC, .unit = "color_trc"}, {"vlog", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_V_LOG}, INT_MIN, INT_MAX, STATIC, .unit = "color_trc"}, + {"chroma_location", "select chroma location", OFFSET(chroma_location), AV_OPT_TYPE_INT, {.i64=-1}, -1, AVCHROMA_LOC_NB-1, DYNAMIC, .unit = "chroma_location"}, + {"auto", "keep the same chroma location", 0, AV_OPT_TYPE_CONST, {.i64=-1}, 0, 0, STATIC, .unit = "chroma_location"}, + {"unspecified", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_UNSPECIFIED}, 0, 0, STATIC, .unit = "chroma_location"}, + {"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_UNSPECIFIED}, 0, 0, STATIC, .unit = "chroma_location"}, + {"left", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_LEFT}, 0, 0, STATIC, .unit = "chroma_location"}, + {"center", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_CENTER}, 0, 0, STATIC, .unit = "chroma_location"}, + {"topleft", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_TOPLEFT}, 0, 0, STATIC, .unit = "chroma_location"}, + {"top", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_TOP}, 0, 0, STATIC, .unit = "chroma_location"}, + {"bottomleft", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_BOTTOMLEFT}, 0, 0, STATIC, .unit = "chroma_location"}, + {"bottom", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_BOTTOM}, 0, 0, STATIC, .unit = "chroma_location"}, + {"rotate", "rotate the input clockwise", OFFSET(rotation), AV_OPT_TYPE_INT, {.i64=PL_ROTATION_0}, PL_ROTATION_0, PL_ROTATION_360, DYNAMIC, .unit = "rotation"}, {"0", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PL_ROTATION_0}, .flags = STATIC, .unit = "rotation"}, {"90", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PL_ROTATION_90}, .flags = STATIC, .unit = "rotation"},