From fd7a789fbffdd0f7e41b77a9d70ae0696142c6db 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 This makes 10000 nits == 65535 in 16-bit, meaning SDR white is 65535*203/10000 = 1330. --- libavfilter/vf_colorspace.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/libavfilter/vf_colorspace.c b/libavfilter/vf_colorspace.c index 1e1ab5fb34..081c1c9d0e 100644 --- a/libavfilter/vf_colorspace.c +++ b/libavfilter/vf_colorspace.c @@ -173,6 +173,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 +198,8 @@ 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; s->lin_lut = av_malloc(sizeof(*s->lin_lut) * 32768 * 2); if (!s->lin_lut) @@ -206,7 +209,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, 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 +227,16 @@ 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); + // note that [0,1] here corresponds to [0,100] in SDR + l = 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; @@ -956,6 +976,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 }, -- 2.30.2