From patchwork Mon Feb 6 14:53:11 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Tomas_H=C3=A4rdin?= X-Patchwork-Id: 40304 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:5494:b0:bf:7b3a:fd32 with SMTP id i20csp3425846pzk; Mon, 6 Feb 2023 06:53:24 -0800 (PST) X-Google-Smtp-Source: AK7set/m++d9dMpz0tROdPbP6xmubp8trwm6aakoNuMnqW8ifllp2ctUr0QRnx1BfV84baxyNStK X-Received: by 2002:a17:907:9916:b0:887:915d:7502 with SMTP id ka22-20020a170907991600b00887915d7502mr23779805ejc.31.1675695204453; Mon, 06 Feb 2023 06:53:24 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1675695204; cv=none; d=google.com; s=arc-20160816; b=oxrUsLERymOnE6adNPdPtAtzTNhJZTDJKGpBUzJCnTR0zjevOM49Wvqk3aNW3NSMdM pi84vBwgF6xfrpE9qFvitWMgThgdbH4eAe0KM8wxZoGKRz8VkxQPtyDK+ur/A3RgHMJf PYkZs+pf4vl1ml7dpf8KIwpDe3wMNvOoZYE7+75OyNVJNd56IysA7mgxti6Rmtq8S0kP gdOwQ3jLD4ljSZAIEQ+xEMItyTgldVsqyDwEPBLs3hWgdBwyLRrcgWG9kzhRtHNcBaTE ydcIcUR9e1n2X0Mp7EptcsTMByebWBPyRcWYkJ3pO3mH5w6Ekpnn6+qPYQtaMAbBUnWe x33g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:reply-to:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence:subject :mime-version:user-agent:references:in-reply-to:date:to:from :message-id:delivered-to; bh=jbWLgmbT2UKAz1eWN/qUCWhiZpT2BfLXit5kv2CLKzs=; b=pxb26nlv89Q42hBN4ZZjno1xrKZa0VHc1tLo0S7LPQLtN5JOw3rp3bWARkF3mv09zf UkYtYIw+vIIWqY2RvMFj2jjXV9EJQIhSwWAQrYl4xPqGee/06GdI6tYXcR6giD5n5Aha 1VyBKpQiBgZu/RDzxYp0GorXuFsi1IS9A9l7VpvoaAetJbyXBhCiSKH/OA9e2ThFCh9B 7/GBdfilqLHo5YlE0Vsc/QonrCFPRX9V9rGAWvHHY3b16Th26D+WeYEJUGaWyyr/MjOE 4Q/kSZaw75BOSBthXFnXw7r3k1LYdyc2kD5zurV7dW/co6ayMjidySaaVsYRRnfGREoi ER3g== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id c28-20020a1709063f1c00b0088e2f1b2df2si11985029ejj.376.2023.02.06.06.53.23; Mon, 06 Feb 2023 06:53:24 -0800 (PST) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 669BD68B7DE; Mon, 6 Feb 2023 16:53:20 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail.frobbit.se (mail.frobbit.se [85.30.129.176]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 84B5C68B7DE for ; Mon, 6 Feb 2023 16:53:13 +0200 (EET) Received: from [10.10.150.68] (1346516434.ip.84grams.net [134.65.164.34]) by mail.frobbit.se (Postfix) with ESMTPSA id 15D3720548 for ; Mon, 6 Feb 2023 15:53:13 +0100 (CET) Message-ID: <4f54a34f6b77734f83b812bc95e0124016b0236a.camel@haerdin.se> From: Tomas =?iso-8859-1?q?H=E4rdin?= To: FFmpeg development discussions and patches Date: Mon, 06 Feb 2023 15:53:11 +0100 In-Reply-To: <22244352f670c17aee4d2ba0f97cc894dfa4199b.camel@haerdin.se> References: <22244352f670c17aee4d2ba0f97cc894dfa4199b.camel@haerdin.se> User-Agent: Evolution 3.38.3-1+deb11u1 MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 2/2 v2] lavfi/vf_colorspace: Add SMPTE ST 2084 support X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: KNtdByCpxcML Here's a version of this patch with options for specifying input and output nits. 32-bit LUTs would make this situation better if vf_colorspace tracked nits internally. 32-bit would only be necessary when dealing with HDR. That way SDR colorspace conversion can still use the 16-bit SIMD. /Tomas From c63beb4581bcd3140e122b7a7c5b4a53ae35ec29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20H=C3=A4rdin?= Date: Fri, 3 Feb 2023 14:00:38 +0100 Subject: [PATCH 2/2] lavfi/vf_colorspace: Add SMPTE ST 2084 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also adds inits and onits options for specifying what 28672 means in terms of nits (cd/m²). --- doc/filters.texi | 30 ++++++++++++++++++++++++++++ libavfilter/vf_colorspace.c | 39 +++++++++++++++++++++++++++++++++++-- 2 files changed, 67 insertions(+), 2 deletions(-) diff --git a/doc/filters.texi b/doc/filters.texi index 3a54c68f3e..26d9dfe54b 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -9839,6 +9839,10 @@ BT.2020 for 10-bits content @item bt2020-12 BT.2020 for 12-bits content +@anchor{smpte2084} +@item smpte2084 +SMPTE ST 2084 (perceptual quantizer) used by BT.2100. See @ref{inits} and @ref{onits}. + @end table @anchor{primaries} @@ -9980,6 +9984,32 @@ Override input transfer characteristics. Same accepted values as @ref{trc}. @item irange Override input color range. Same accepted values as @ref{range}. +@anchor{inits} +@item inits +Required when input trc is @ref{smpte2084}. +Specifies what the peak intermediate level should correspond to in nits (cd/m²). +Perceptually dequantized values get scaled and clipped so that the range [0,inits] fits in the filter's internal psuedo-restricted 15-bit format. +For inits < 10000 this corresponds to clipping of values outside the [0,inits]³ RGB cube. +For inits = 10000 values are not clipped, but values in the lower range will get truncated to zero due to the internal format's limited range. + +With BT.2100 input basic usage is: +@example +colorspace=bt709:inits=100 +@end example +which clips HDR to SDR in BT.709 colorspace. + +A more advanced use case is as follows: +@example +colorspace=bt709:inits=10000:trc=linear:format=yuv444p16,tonemap=hable:peak=0.01 +@end example +which with BT.2100 input performs very basic tonemapping. + +@anchor{onits} +@item onits +Used in combination with @ref{smpte2084}, defaults to 10000. +Similar to @ref{inits} but in reverse. +Specifies how to treat the peak intermediate level in nits (cd/m²) prior to perceptual quantization (PQ) as per SMPTE ST 2084. + @end table The filter converts the transfer characteristics, color space and color diff --git a/libavfilter/vf_colorspace.c b/libavfilter/vf_colorspace.c index 1e1ab5fb34..996c5f4e25 100644 --- a/libavfilter/vf_colorspace.c +++ b/libavfilter/vf_colorspace.c @@ -118,6 +118,7 @@ typedef struct ColorSpaceContext { enum AVColorTransferCharacteristic in_trc, out_trc, user_trc, user_itrc; enum AVColorPrimaries in_prm, out_prm, user_prm, user_iprm; enum AVPixelFormat in_format, user_format; + double user_inits, user_onits; int fast_mode; enum DitherMode dither; enum WhitepointAdaptation wp_adapt; @@ -173,6 +174,7 @@ static const struct TransferCharacteristics transfer_characteristics[AVCOL_TRC_N [AVCOL_TRC_IEC61966_2_4] = { 1.099, 0.018, 0.45, 4.5 }, [AVCOL_TRC_BT2020_10] = { 1.099, 0.018, 0.45, 4.5 }, [AVCOL_TRC_BT2020_12] = { 1.0993, 0.0181, 0.45, 4.5 }, + [AVCOL_TRC_SMPTE2084] = { 1.0, 0, 0, 0 }, // fake entry, actual TRC uses entirely separate formula }; static const struct TransferCharacteristics * @@ -197,6 +199,9 @@ static int fill_gamma_table(ColorSpaceContext *s) double in_ialpha = 1.0 / in_alpha, in_igamma = 1.0 / in_gamma, in_idelta = 1.0 / in_delta; double out_alpha = s->out_txchr->alpha, out_beta = s->out_txchr->beta; double out_gamma = s->out_txchr->gamma, out_delta = s->out_txchr->delta; + double m1 = 1305.0/8192, m2 = 2523.0/32, c2 = 2413.0/128, c3 = 2392.0/128, c1 = c3 - c2 + 1; + double im1 = 1.0 / m1, im2 = 1.0 / m2; + double iscale = 10000.0 / s->user_inits, ioscale = s->user_onits / 10000.0; s->lin_lut = av_malloc(sizeof(*s->lin_lut) * 32768 * 2); if (!s->lin_lut) @@ -206,7 +211,15 @@ static int fill_gamma_table(ColorSpaceContext *s) double v = (n - 2048.0) / 28672.0, d, l; // delinearize - if (v <= -out_beta) { + if (s->out_trc == AVCOL_TRC_SMPTE2084) { + // see BT.2100-2 + if (v >= 0) { + double vm1 = pow(v * ioscale, m1); + d = pow((c1 + c2 * vm1)/(1 + c3 * vm1), m2); + } else { + d = 0; + } + } else if (v <= -out_beta) { d = -out_alpha * pow(-v, out_gamma) + (out_alpha - 1.0); } else if (v < out_beta) { d = out_delta * v; @@ -216,7 +229,19 @@ static int fill_gamma_table(ColorSpaceContext *s) s->delin_lut[n] = av_clip_int16(lrint(d * 28672.0)); // linearize - if (v <= -in_beta * in_delta) { + if (s->in_trc == AVCOL_TRC_SMPTE2084) { + // see BT.2100-2 + if (v >= 0) { + double vim2 = pow(v, im2); + // for inits < 10000 this will tonemap by clipping in RGB + // for inits = 10000 this makes unclipped linear values accessible when trc=linear + // note that precision will be lost in the lower end of PQ values, for example with + // 12-bit PQ and 16-bit output the first 422 values all get truncated to zero + l = iscale * pow((vim2 - c1 > 0 ? vim2 - c1 : 0) / (c2 - c3 * vim2), im1); + } else { + l = 0; + } + } else if (v <= -in_beta * in_delta) { l = -pow((1.0 - in_alpha - v) * in_ialpha, in_igamma); } else if (v < in_beta * in_delta) { l = v * in_idelta; @@ -514,6 +539,11 @@ static int create_filtergraph(AVFilterContext *ctx, } } + if (s->in_trc == AVCOL_TRC_SMPTE2084 && s->user_inits <= 0) { + av_log(ctx, AV_LOG_ERROR, "smpte2084 requires inits\n"); + return AVERROR(EINVAL); + } + if (!s->out_txchr) { av_freep(&s->lin_lut); s->out_trc = out->color_trc; @@ -956,6 +986,7 @@ static const AVOption colorspace_options[] = { ENUM("iec61966-2-4", AVCOL_TRC_IEC61966_2_4, "trc"), ENUM("bt2020-10", AVCOL_TRC_BT2020_10, "trc"), ENUM("bt2020-12", AVCOL_TRC_BT2020_12, "trc"), + ENUM("smpte2084", AVCOL_TRC_SMPTE2084, "trc"), { "format", "Output pixel format", OFFSET(user_format), AV_OPT_TYPE_INT, { .i64 = AV_PIX_FMT_NONE }, @@ -1008,6 +1039,10 @@ static const AVOption colorspace_options[] = { { "itrc", "Input transfer characteristics", OFFSET(user_itrc), AV_OPT_TYPE_INT, { .i64 = AVCOL_TRC_UNSPECIFIED }, AVCOL_TRC_RESERVED0, AVCOL_TRC_NB - 1, FLAGS, "trc" }, + { "inits", "Input nits. Specifies how PQ (SMPTE ST 2084) values are to be mapped to intermediate/output linear RGB", + OFFSET(user_inits), AV_OPT_TYPE_DOUBLE, {.dbl = 0}, 0, 10000, FLAGS }, + { "onits", "Output nits. Specifies how input/intermediate linear RGB is scaled for output PQ (SMPTE ST 2084) values", + OFFSET(user_onits), AV_OPT_TYPE_DOUBLE, {.dbl = 10000}, 1, 10000, FLAGS }, { NULL } }; -- 2.30.2