[FFmpeg-devel] [PATCH 2/2] avfilter/vf_tinterlace: support full-range YUV
Niklas Haas
ffmpeg at haasn.xyz
Fri Dec 9 02:28:06 EET 2022
From: Niklas Haas <git at haasn.dev>
This filter, when used in the "pad" mode, currently makes the
distinction between limited and full range solely by testing for YUVJ
pixel formats at link setup time. This is deprecated and should be
improved to perform the detection based on the per-frame metadata.
In order to make this distinction based on color range metadata, which
is only known at the time of filtering frames, for simplicity, we simply
allocate two copies of the "black" frame - one for limited range and the
other for full range metadata. This could be done more dynamically (e.g.
as-needed or simply by blitting the appropriate pixel value directly),
but this change is relatively simple and preserves the structure of the
existing code.
This commit actually fixes a bug in FATE - the new output is correct for
the first time. The previous md5 ref was of a frame that incorrectly
combined full-range pixel data with limited-range black fields. The
corresponding result has been updated.
Signed-off-by: Niklas Haas <git at haasn.dev>
---
libavfilter/tinterlace.h | 2 +-
libavfilter/vf_tinterlace.c | 26 ++++++++++++++------
tests/ref/fate/filter-pixfmts-tinterlace_pad | 2 +-
3 files changed, 20 insertions(+), 10 deletions(-)
diff --git a/libavfilter/tinterlace.h b/libavfilter/tinterlace.h
index 4059ebf81a..37b6c10c08 100644
--- a/libavfilter/tinterlace.h
+++ b/libavfilter/tinterlace.h
@@ -70,7 +70,7 @@ typedef struct TInterlaceContext {
int vsub; ///< chroma vertical subsampling
AVFrame *cur;
AVFrame *next;
- uint8_t *black_data[4]; ///< buffer used to fill padded lines
+ uint8_t *black_data[2][4]; ///< buffer used to fill padded lines (limited/full)
int black_linesize[4];
FFDrawContext draw;
FFDrawColor color;
diff --git a/libavfilter/vf_tinterlace.c b/libavfilter/vf_tinterlace.c
index 7c54861de4..032629279a 100644
--- a/libavfilter/vf_tinterlace.c
+++ b/libavfilter/vf_tinterlace.c
@@ -201,7 +201,8 @@ static av_cold void uninit(AVFilterContext *ctx)
av_frame_free(&tinterlace->cur );
av_frame_free(&tinterlace->next);
- av_freep(&tinterlace->black_data[0]);
+ av_freep(&tinterlace->black_data[0][0]);
+ av_freep(&tinterlace->black_data[1][0]);
}
static int config_out_props(AVFilterLink *outlink)
@@ -225,14 +226,22 @@ static int config_out_props(AVFilterLink *outlink)
int ret;
ff_draw_init(&tinterlace->draw, outlink->format, 0);
ff_draw_color(&tinterlace->draw, &tinterlace->color, black);
- if (ff_fmt_is_in(outlink->format, full_scale_yuvj_pix_fmts))
- tinterlace->color.comp[0].u8[0] = 0;
- ret = av_image_alloc(tinterlace->black_data, tinterlace->black_linesize,
+ /* limited range */
+ if (!ff_fmt_is_in(outlink->format, full_scale_yuvj_pix_fmts)) {
+ ret = av_image_alloc(tinterlace->black_data[0], tinterlace->black_linesize,
+ outlink->w, outlink->h, outlink->format, 16);
+ if (ret < 0)
+ return ret;
+ ff_fill_rectangle(&tinterlace->draw, &tinterlace->color, tinterlace->black_data[0],
+ tinterlace->black_linesize, 0, 0, outlink->w, outlink->h);
+ }
+ /* full range */
+ tinterlace->color.comp[0].u8[0] = 0;
+ ret = av_image_alloc(tinterlace->black_data[1], tinterlace->black_linesize,
outlink->w, outlink->h, outlink->format, 16);
if (ret < 0)
return ret;
-
- ff_fill_rectangle(&tinterlace->draw, &tinterlace->color, tinterlace->black_data,
+ ff_fill_rectangle(&tinterlace->draw, &tinterlace->color, tinterlace->black_data[1],
tinterlace->black_linesize, 0, 0, outlink->w, outlink->h);
}
if (tinterlace->flags & (TINTERLACE_FLAG_VLPF | TINTERLACE_FLAG_CVLPF)
@@ -360,7 +369,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
AVFilterLink *outlink = ctx->outputs[0];
TInterlaceContext *tinterlace = ctx->priv;
AVFrame *cur, *next, *out;
- int field, tff, ret;
+ int field, tff, full, ret;
av_frame_free(&tinterlace->cur);
tinterlace->cur = tinterlace->next;
@@ -418,6 +427,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
out->sample_aspect_ratio = av_mul_q(cur->sample_aspect_ratio, av_make_q(2, 1));
field = (1 + outlink->frame_count_in) & 1 ? FIELD_UPPER : FIELD_LOWER;
+ full = out->color_range == AVCOL_RANGE_JPEG || ff_fmt_is_in(out->format, full_scale_yuvj_pix_fmts);
/* copy upper and lower fields */
copy_picture_field(tinterlace, out->data, out->linesize,
(const uint8_t **)cur->data, cur->linesize,
@@ -425,7 +435,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
FIELD_UPPER_AND_LOWER, 1, field, tinterlace->flags);
/* pad with black the other field */
copy_picture_field(tinterlace, out->data, out->linesize,
- (const uint8_t **)tinterlace->black_data, tinterlace->black_linesize,
+ (const uint8_t **)tinterlace->black_data[full], tinterlace->black_linesize,
inlink->format, inlink->w, inlink->h,
FIELD_UPPER_AND_LOWER, 1, !field, tinterlace->flags);
break;
diff --git a/tests/ref/fate/filter-pixfmts-tinterlace_pad b/tests/ref/fate/filter-pixfmts-tinterlace_pad
index 81a6961215..29321e542b 100644
--- a/tests/ref/fate/filter-pixfmts-tinterlace_pad
+++ b/tests/ref/fate/filter-pixfmts-tinterlace_pad
@@ -1,4 +1,4 @@
-gray 7ef396fecd8d1c9fe32173e4415ba671
+gray 227a6fe36a31fbef80210823454131ea
yuv410p 35bc11d0d32efc9e9a969be7d720f4e6
yuv411p 17ef3cd22a74f7368b5e02f68779f294
yuv420p 93d5b6a4c44d67e4d4447e8dd0bf3d33
--
2.38.1
More information about the ffmpeg-devel
mailing list