diff mbox series

[FFmpeg-devel,v2,07/10] avfilter/vf_scale: preserve YUV range by default

Message ID 20231028144430.60538-8-ffmpeg@haasn.xyz
State New
Headers show
Series YUVJ removal preliminary cleanup | expand

Checks

Context Check Description
yinshiyou/make_loongarch64 success Make finished
yinshiyou/make_fate_loongarch64 success Make fate finished
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished

Commit Message

Niklas Haas Oct. 28, 2023, 2:41 p.m. UTC
From: Niklas Haas <git@haasn.dev>

YUV->YUV conversions should preserve input range, if the output range is
unspecified. Ensures full-range YUV input comes out as full-range YUV
output by default, even through YUV->YUV pixel format conversions.
---
 libavfilter/vf_scale.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

Comments

Michael Niedermayer Oct. 30, 2023, 11:42 p.m. UTC | #1
On Sat, Oct 28, 2023 at 04:41:14PM +0200, Niklas Haas wrote:
> From: Niklas Haas <git@haasn.dev>
> 
> YUV->YUV conversions should preserve input range, if the output range is
> unspecified. Ensures full-range YUV input comes out as full-range YUV
> output by default, even through YUV->YUV pixel format conversions.
> ---
>  libavfilter/vf_scale.c | 23 +++++++++++++++++++++++
>  1 file changed, 23 insertions(+)

this seems to change the output of the following:
ffmpeg -i 4493/AVCI100.mov -vframes 3 -bitexact file.nut
did not investigate if this is a bug or bugfix

files are here: https://samples.ffmpeg.org/ffmpeg-bugs/trac/ticket524/

[...]
Niklas Haas Oct. 31, 2023, 11:23 a.m. UTC | #2
On Tue, 31 Oct 2023 00:42:47 +0100 Michael Niedermayer <michael@niedermayer.cc> wrote:
> On Sat, Oct 28, 2023 at 04:41:14PM +0200, Niklas Haas wrote:
> > From: Niklas Haas <git@haasn.dev>
> > 
> > YUV->YUV conversions should preserve input range, if the output range is
> > unspecified. Ensures full-range YUV input comes out as full-range YUV
> > output by default, even through YUV->YUV pixel format conversions.
> > ---
> >  libavfilter/vf_scale.c | 23 +++++++++++++++++++++++
> >  1 file changed, 23 insertions(+)
> 
> this seems to change the output of the following:
> ffmpeg -i 4493/AVCI100.mov -vframes 3 -bitexact file.nut
> did not investigate if this is a bug or bugfix
> 
> files are here: https://samples.ffmpeg.org/ffmpeg-bugs/trac/ticket524/

Seems like it's a regression. mpeg4 does not support full range YUV, so
giving it full range YUV causes wrong levels to be saved.

I will drop this commit from this series and include it as part of the
filter negotiation series, since that one has the necessary
infrastructure to handle this more gracefully.
diff mbox series

Patch

diff --git a/libavfilter/vf_scale.c b/libavfilter/vf_scale.c
index 3d58de0494..cde6f52169 100644
--- a/libavfilter/vf_scale.c
+++ b/libavfilter/vf_scale.c
@@ -687,6 +687,27 @@  static int scale_field(ScaleContext *scale, AVFrame *dst, AVFrame *src,
     return 0;
 }
 
+static int is_regular_yuv(enum AVPixelFormat fmt)
+{
+    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
+    if (desc->flags & (AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_PAL))
+        return 0;
+    if (desc->name && av_strstart(desc->name, "xyz", NULL))
+        return 0;
+    if (desc->nb_components < 3)
+        return 0; /* grayscale is forced full range inside libswscale */
+    switch (fmt) {
+    case AV_PIX_FMT_YUVJ420P:
+    case AV_PIX_FMT_YUVJ422P:
+    case AV_PIX_FMT_YUVJ444P:
+    case AV_PIX_FMT_YUVJ440P:
+    case AV_PIX_FMT_YUVJ411P:
+        return 0;
+    default:
+        return 1;
+    }
+}
+
 static int scale_frame(AVFilterLink *link, AVFrame *in, AVFrame **frame_out)
 {
     AVFilterContext *ctx = link->dst;
@@ -794,6 +815,8 @@  scale:
         in_full = in->color_range == AVCOL_RANGE_JPEG;
     if (scale->out_range != AVCOL_RANGE_UNSPECIFIED)
         out_full = scale->out_range == AVCOL_RANGE_JPEG;
+    else if (is_regular_yuv(in->format) && is_regular_yuv(outlink->format))
+        out_full = in_full; /* preserve pixel range by default */
 
     if (in->width == outlink->w &&
         in->height == outlink->h &&