[FFmpeg-devel] [PATCH 4/6] avfilter/vf_scale: add in/out_chroma_loc
Niklas Haas
ffmpeg at haasn.xyz
Thu Jul 4 14:52:00 EEST 2024
From: Niklas Haas <git at haasn.dev>
Currently, this just functions as a more principled and user-friendly
replacement for the (undocumented and hard to use) *_chr_pos fields.
However, the goal is to automatically infer these values from the input
frames' chroma location, and deprecate the manual use of *_chr_pos
altogether. (Indeed, my plans for an swscale replacement will most
likely also end up limiting the set of legal chroma locations to those
permissible by AVFrame properties)
---
doc/filters.texi | 15 +++++++++
libavfilter/vf_scale.c | 75 ++++++++++++++++++++++++++++--------------
2 files changed, 66 insertions(+), 24 deletions(-)
diff --git a/doc/filters.texi b/doc/filters.texi
index ca8f6e461a..3cff4eec1c 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -21137,6 +21137,21 @@ Set full range (0-255 in case of 8-bit luma).
Set "MPEG" range (16-235 in case of 8-bit luma).
@end table
+ at item in_chroma_loc
+ at item out_chroma_loc
+Set in/output chroma sample location. If not specified, center-sited chroma
+is used by default. Possible values:
+
+ at table @samp
+ at item auto, unknown
+ at item left
+ at item center
+ at item topleft
+ at item top
+ at item bottomleft
+ at item bottom
+ at end table
+
@item force_original_aspect_ratio
Enable decreasing or increasing output video width or height if necessary to
keep the original aspect ratio. Possible values:
diff --git a/libavfilter/vf_scale.c b/libavfilter/vf_scale.c
index 0b6701673f..f0de0261db 100644
--- a/libavfilter/vf_scale.c
+++ b/libavfilter/vf_scale.c
@@ -168,6 +168,8 @@ typedef struct ScaleContext {
int in_range;
int out_range;
+ int in_chroma_loc;
+ int out_chroma_loc;
int out_h_chr_pos;
int out_v_chr_pos;
int in_h_chr_pos;
@@ -617,6 +619,29 @@ fail:
return ret;
}
+static void calc_chroma_pos(int *h_pos, int *v_pos, int chroma_loc,
+ int h_pos_default, int v_pos_default,
+ int h_sub, int v_sub, int index)
+{
+ *h_pos = h_pos_default;
+ *v_pos = v_pos_default;
+ if (chroma_loc != AVCHROMA_LOC_UNSPECIFIED)
+ av_chroma_location_enum_to_pos(h_pos, v_pos, chroma_loc);
+
+ if (h_sub && index > 0 /* interlaced fields */) {
+ if (*v_pos == -513)
+ *v_pos = 128; /* explicitly default missing info */
+ *v_pos += 256 * (index == 2); /* offset by one luma row for odd rows */
+ *v_pos >>= 1; /* double luma row distance */
+ }
+
+ /* Avoid offsetting chroma for progressive content */
+ if (!h_sub)
+ *h_pos = -513;
+ if (!v_sub)
+ *v_pos = -513;
+}
+
static int config_props(AVFilterLink *outlink)
{
AVFilterContext *ctx = outlink->src;
@@ -673,15 +698,16 @@ static int config_props(AVFilterLink *outlink)
inlink0->h == outlink->h &&
in_range == outlink->color_range &&
in_colorspace == outlink->colorspace &&
- inlink0->format == outlink->format)
+ inlink0->format == outlink->format &&
+ scale->in_chroma_loc == scale->out_chroma_loc)
;
else {
struct SwsContext **swscs[3] = {&scale->sws, &scale->isws[0], &scale->isws[1]};
int i;
for (i = 0; i < 3; i++) {
- int in_v_chr_pos = scale->in_v_chr_pos, out_v_chr_pos = scale->out_v_chr_pos;
int in_full, out_full, brightness, contrast, saturation;
+ int h_chr_pos, v_chr_pos;
const int *inv_table, *table;
struct SwsContext *const s = sws_alloc_context();
if (!s)
@@ -705,28 +731,17 @@ static int config_props(AVFilterLink *outlink)
av_opt_set_int(s, "dst_range",
outlink->color_range == AVCOL_RANGE_JPEG, 0);
- /* Override chroma location default settings to have the correct
- * chroma positions. MPEG chroma positions are used by convention.
- * Note that this works for both MPEG-1/JPEG and MPEG-2/4 chroma
- * locations, since they share a vertical alignment */
- if (desc->log2_chroma_h == 1) {
- if (in_v_chr_pos == -513)
- in_v_chr_pos = 128; /* explicitly default missing info */
- in_v_chr_pos += 256 * (i == 2); /* offset by one luma row for odd rows */
- in_v_chr_pos >>= i > 0; /* double luma row distance */
- }
-
- if (outdesc->log2_chroma_h == 1) {
- if (out_v_chr_pos == -513)
- out_v_chr_pos = 128;
- out_v_chr_pos += 256 * (i == 2);
- out_v_chr_pos >>= i > 0;
- }
-
- av_opt_set_int(s, "src_h_chr_pos", scale->in_h_chr_pos, 0);
- av_opt_set_int(s, "src_v_chr_pos", in_v_chr_pos, 0);
- av_opt_set_int(s, "dst_h_chr_pos", scale->out_h_chr_pos, 0);
- av_opt_set_int(s, "dst_v_chr_pos", out_v_chr_pos, 0);
+ calc_chroma_pos(&h_chr_pos, &v_chr_pos, scale->in_chroma_loc,
+ scale->in_h_chr_pos, scale->in_v_chr_pos,
+ desc->log2_chroma_w, desc->log2_chroma_h, i);
+ av_opt_set_int(s, "src_h_chr_pos", h_chr_pos, 0);
+ av_opt_set_int(s, "src_v_chr_pos", v_chr_pos, 0);
+
+ calc_chroma_pos(&h_chr_pos, &v_chr_pos, scale->out_chroma_loc,
+ scale->out_h_chr_pos, scale->out_v_chr_pos,
+ outdesc->log2_chroma_w, outdesc->log2_chroma_h, i);
+ av_opt_set_int(s, "dst_h_chr_pos", h_chr_pos, 0);
+ av_opt_set_int(s, "dst_v_chr_pos", v_chr_pos, 0);
if ((ret = sws_init_context(s, NULL, NULL)) < 0)
return ret;
@@ -987,6 +1002,8 @@ scale:
out->height = outlink->h;
out->color_range = outlink->color_range;
out->colorspace = outlink->colorspace;
+ if (scale->out_chroma_loc != AVCHROMA_LOC_UNSPECIFIED)
+ out->chroma_location = scale->out_chroma_loc;
if (scale->output_is_pal)
avpriv_set_systematic_pal2((uint32_t*)out->data[1], outlink->format == AV_PIX_FMT_PAL8 ? AV_PIX_FMT_BGR8 : outlink->format);
@@ -1217,6 +1234,16 @@ static const AVOption scale_options[] = {
{ "mpeg", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_MPEG}, 0, 0, FLAGS, .unit = "range" },
{ "tv", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_MPEG}, 0, 0, FLAGS, .unit = "range" },
{ "pc", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_JPEG}, 0, 0, FLAGS, .unit = "range" },
+ { "in_chroma_loc", "set input chroma sample location", OFFSET(in_chroma_loc), AV_OPT_TYPE_INT, { .i64 = AVCHROMA_LOC_UNSPECIFIED }, 0, AVCHROMA_LOC_NB-1, .flags = FLAGS, .unit = "chroma_loc" },
+ { "out_chroma_loc", "set output chroma sample location", OFFSET(out_chroma_loc), AV_OPT_TYPE_INT, { .i64 = AVCHROMA_LOC_UNSPECIFIED }, 0, AVCHROMA_LOC_NB-1, .flags = FLAGS, .unit = "chroma_loc" },
+ {"auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_UNSPECIFIED}, 0, 0, FLAGS, .unit = "chroma_loc"},
+ {"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_UNSPECIFIED}, 0, 0, FLAGS, .unit = "chroma_loc"},
+ {"left", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_LEFT}, 0, 0, FLAGS, .unit = "chroma_loc"},
+ {"center", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_CENTER}, 0, 0, FLAGS, .unit = "chroma_loc"},
+ {"topleft", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_TOPLEFT}, 0, 0, FLAGS, .unit = "chroma_loc"},
+ {"top", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_TOP}, 0, 0, FLAGS, .unit = "chroma_loc"},
+ {"bottomleft", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_BOTTOMLEFT}, 0, 0, FLAGS, .unit = "chroma_loc"},
+ {"bottom", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_BOTTOM}, 0, 0, FLAGS, .unit = "chroma_loc"},
{ "in_v_chr_pos", "input vertical chroma position in luma grid/256" , OFFSET(in_v_chr_pos), AV_OPT_TYPE_INT, { .i64 = -513}, -513, 512, FLAGS },
{ "in_h_chr_pos", "input horizontal chroma position in luma grid/256", OFFSET(in_h_chr_pos), AV_OPT_TYPE_INT, { .i64 = -513}, -513, 512, FLAGS },
{ "out_v_chr_pos", "output vertical chroma position in luma grid/256" , OFFSET(out_v_chr_pos), AV_OPT_TYPE_INT, { .i64 = -513}, -513, 512, FLAGS },
--
2.45.2
More information about the ffmpeg-devel
mailing list