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

As noted in #21185, a common use case for libplacebo is converting BT.2020 
video to BT.709. Customarily, the former uses a chroma location of "top left," 
whereas the latter uses "left."

`-vf 
libplacebo=w=-1:h=1080:colorspace=bt709:color_trc=bt709:color_primaries=bt709:range=limited:format=yuv420p`

Using this command on UHD video, the output carries over the original top-left 
chroma siting. In practice, this should make no difference; but it would be 
ideal and more flexible if one could specify the destination siting. No doubt, 
another filter could be used downstream, such as zscale, but this would require 
further processing. So, ideally, this should be done in libplacebo, either in 
the library or the filter, when the internal RGB is converted to YUV and 
subsampled, the desired chroma siting being done at that point.

This patch adds the chroma_location setting to vf_libplacebo, and updates the 
documentation (with minimal change).


>From d282319b4d3fa73c6c24f46bd7f51a14069e434b Mon Sep 17 00:00:00 2001
From: GeoffreyAA <[email protected]>
Date: Fri, 23 Jan 2026 11:32:11 +0000
Subject: [PATCH 1/2] 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."
---
 libavfilter/vf_libplacebo.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/libavfilter/vf_libplacebo.c b/libavfilter/vf_libplacebo.c
index 74c1fd7214..0e62be5e42 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;
@@ -1023,6 +1024,7 @@ static int output_frame(AVFilterContext *ctx, int64_t pts)
     out->height = outlink->h;
     out->colorspace = outlink->colorspace;
     out->color_range = outlink->color_range;
+    out->chroma_location = outlink->chroma_location;
     out->alpha_mode = outlink->alpha_mode;
     if (s->deinterlace)
         out->flags &= ~(AV_FRAME_FLAG_INTERLACED | 
AV_FRAME_FLAG_TOP_FIELD_FIRST);
@@ -1695,6 +1697,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"},
-- 
2.52.0


>From 27993cdfe625c49d2471b135d8cba93b1806e66e Mon Sep 17 00:00:00 2001
From: GeoffreyAA <[email protected]>
Date: Fri, 23 Jan 2026 11:37:06 +0000
Subject: [PATCH 2/2] doc/filters.texi: update libplacebo documentation, adding
 chroma_location

Update libplacebo documentation, adding chroma_location.
---
 doc/filters.texi | 1 +
 1 file changed, 1 insertion(+)

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.
-- 
2.52.0

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

Reply via email to