From patchwork Thu Jan 26 16:32:27 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Leo Izen X-Patchwork-Id: 40127 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:3ca3:b0:b9:1511:ac2c with SMTP id b35csp652579pzj; Thu, 26 Jan 2023 08:32:44 -0800 (PST) X-Google-Smtp-Source: AMrXdXvJb/f6zjNVbioeCvAmckMV4jlcX8Wk2uSoW2Fs/lKFtyMAStszHXmG5S5mLf2w+8UH7Wop X-Received: by 2002:a05:6402:3894:b0:49e:45a8:1ac9 with SMTP id fd20-20020a056402389400b0049e45a81ac9mr37209227edb.24.1674750763925; Thu, 26 Jan 2023 08:32:43 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1674750763; cv=none; d=google.com; s=arc-20160816; b=n/rAe0WVMsTlzkrYVhoG4AHr+0tIfk1hBkCBu2eMJzCEbByUjc4ue8ndqa/rsasI+t YEvDfcpvmLEf++GJro0T6x7fHinDahNjWl3P6huEzz0yFGufP8UmVn68B8fLVOs+TQD/ z26SIQVpv+klVTkVSk+CoPcZsuBTi5SCJ6oqUT5dVkfZ8EzpdCHOyY6R5BpWHlaaCwkg KmGJAh8fpWKgLAHGUMyv34B/KpIa81LSxuw8CuamoNkY1m860ST4cvA6ZTqgHDcf91eb lssXX8h9f2SaoCLRUbdC0PbHVap91Nx9+UGgOFkB1sv+KMenlw7wYzkC2oQC2M0MAo3M fprA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:message-id:date:to:from :dkim-signature:delivered-to; bh=nz6ZJD8txleUKMVi0JLDU3hh3JL37Yr5PXCqVN6VWWA=; b=azoqMZCBJBzhLtDYTABs6y8SPF6brya5MKafzrojrxQm2NJac5UGYoWIwauVXbAugY WQV0O59fEW4sOGMqMwchA6Wlzsp3f4KY413zJnEZffrGj4760I8qFgMlrshTGXFROWNg oA0Yi+lJ3RF5BiRvroGsAgAjqOMYnCY7wuSPsxHWoAp0W5MCjc9lin2/ierXFbv7OMKW 9bA7GOyHiVIMHyWQ8/fNY04jPCRBiQqtEUdSChUqKYFxWl+2IVunUMe79nv3CNijSzMP Lo8fdO/sC/0e28ynIJK+OyYLya7ZCdblpv0HXtuyxmwpl4tuuNcmhOpQGfNXLe6NQuNR XMPw== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20210112 header.b=EwDCg4cu; 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; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id cz27-20020a0564021cbb00b0049e76c617c5si1990831edb.253.2023.01.26.08.32.42; Thu, 26 Jan 2023 08:32:43 -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; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20210112 header.b=EwDCg4cu; 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; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 64E9868B0C1; Thu, 26 Jan 2023 18:32:39 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-il1-f182.google.com (mail-il1-f182.google.com [209.85.166.182]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 30C7768B0C1 for ; Thu, 26 Jan 2023 18:32:32 +0200 (EET) Received: by mail-il1-f182.google.com with SMTP id g15so986543ild.3 for ; Thu, 26 Jan 2023 08:32:32 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=sOb44xCCA20f7KaJXBxYyTmbamG4blBJaYmV4PlKLw0=; b=EwDCg4cuNjWQugNRUDFGI5l7urs+MG+2tJj4kONbn7o4z/mE0PWSvwhoacWdgJeZLJ K5BisSOKkoeWE4s4ZZp1btcgH5FYmpLN7lXo9bA0OwewdZ5LkZqAIi+hgCY8WJIksoYz kcIjJmv3fZczoZuq8GN9r8W82x/K9lwd+EeyBsFU8K652ArwP8gMXEstzc34F52sVKV1 0caPxy41/BIvELMrJstCdAxJWyfOt6+FESXPIkbRlab0SbgOK0fcE/m3sQ2YEJXiRKEB NcHjlxiVxqd8QinLgzyw+YV9flOifkExpN8Tskd7xrbcEcDOCgeJtHXYfdNn8WQUFwLl 3Djg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=sOb44xCCA20f7KaJXBxYyTmbamG4blBJaYmV4PlKLw0=; b=11zXy/nlpoyEcFEMUDHTom/niowO/9R3oKKFGvgrlwvAp3wdZ6WWmUALnt0Yymo9eT itspCcMp1RqpAHjS9HZz7CLCFgsajvdK+Kwqm5HUEFxKNxbhtScwldbWFQa65UOFUbwp kbNB+eySFNHXhiVKUWz7IvA6eg5kcNzftVoeJH4u6Ir+1w+4Dd0yySlnoHBUiiEsovVX Ara9IagyxS1o5Di104PalqXbgfGhEmv5rLqXHuDwIfF5WsEDwHlFNm+fKhsiahEpxfYw G9/SWfsHNUENarb6OWaF6IK0j9LXxndr9CKYk1n/LQFWLKNpeWTu6aqk9S4T6Mh+cNr0 Svsg== X-Gm-Message-State: AFqh2koF8NHL7OGVp5QygT76lr4Z6Kol2xubSfx4o6+CCP1r1M+8lZLf ggSZYMrcVORPRtwUgooAt7cG+qMo0WU= X-Received: by 2002:a05:6e02:1d09:b0:30d:c6b1:b5de with SMTP id i9-20020a056e021d0900b0030dc6b1b5demr33544537ila.15.1674750750265; Thu, 26 Jan 2023 08:32:30 -0800 (PST) Received: from gauss.local (c-68-41-54-207.hsd1.mi.comcast.net. [68.41.54.207]) by smtp.gmail.com with ESMTPSA id s19-20020a92c5d3000000b00304ad1e7d21sm471082ilt.28.2023.01.26.08.32.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 26 Jan 2023 08:32:29 -0800 (PST) From: Leo Izen To: ffmpeg-devel@ffmpeg.org Date: Thu, 26 Jan 2023 11:32:27 -0500 Message-Id: <20230126163227.138309-1-leo.izen@gmail.com> X-Mailer: git-send-email 2.39.1 MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH] avutil/{color_utils, csp}: merge color_utils into csp and expose API 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 Cc: Leo Izen Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: Np15Yzt0DN4w libavutil/color_utils contains some avpriv_ symbols that map enum AVTransferCharacteristic values to gamma-curve approximations and to the actual transfer functions to invert them (i.e. -> linear). There's two issues with this: (1) avpriv is evil and should be avoided whenever possible (2) libavutil/csp.h exposes a public API for handling color that already handles primaries and matricies I don't see any reason this API has to be private, so this commit takes the functionality from avutil/color_utils and merges it into avutil/csp with an exposed av_ API rather than the previous avpriv_ API. Every reference to the previous API has been updated to point to the new one. color_utils.h has been deleted as well. This should not break any applications as it only contained avpriv_ symbols in the first place, so nothing in that header could be referenced by other applications. --- libavcodec/exr.c | 8 +- libavcodec/fflcms2.c | 1 - libavcodec/pngenc.c | 3 +- libavformat/movenc.c | 7 +- libavutil/Makefile | 1 - libavutil/color_utils.c | 234 ---------------------------------- libavutil/color_utils.h | 56 -------- libavutil/csp.c | 172 +++++++++++++++++++++++++ libavutil/csp.h | 39 ++++++ libavutil/tests/color_utils.c | 4 +- 10 files changed, 221 insertions(+), 304 deletions(-) delete mode 100644 libavutil/color_utils.c delete mode 100644 libavutil/color_utils.h diff --git a/libavcodec/exr.c b/libavcodec/exr.c index 6a0af96ce4..2f1766c17b 100644 --- a/libavcodec/exr.c +++ b/libavcodec/exr.c @@ -36,11 +36,11 @@ #include "libavutil/avassert.h" #include "libavutil/common.h" +#include "libavutil/csp.h" #include "libavutil/imgutils.h" #include "libavutil/intfloat.h" #include "libavutil/avstring.h" #include "libavutil/opt.h" -#include "libavutil/color_utils.h" #include "libavutil/half2float.h" #include "avcodec.h" @@ -1189,7 +1189,7 @@ static int decode_block(AVCodecContext *avctx, void *tdata, int i, x, buf_size = s->buf_size; int c, rgb_channel_count; float one_gamma = 1.0f / s->gamma; - avpriv_trc_function trc_func = avpriv_get_trc_function_from_trc(s->apply_trc_type); + av_csp_trc_function trc_func = av_csp_trc_func_from_id(s->apply_trc_type); int ret; line_offset = AV_RL64(s->gb.buffer + jobnr * 8); @@ -2215,7 +2215,7 @@ static av_cold int decode_init(AVCodecContext *avctx) uint32_t i; union av_intfloat32 t; float one_gamma = 1.0f / s->gamma; - avpriv_trc_function trc_func = NULL; + av_csp_trc_function trc_func = NULL; ff_init_half2float_tables(&s->h2f_tables); @@ -2227,7 +2227,7 @@ static av_cold int decode_init(AVCodecContext *avctx) ff_bswapdsp_init(&s->bbdsp); #endif - trc_func = avpriv_get_trc_function_from_trc(s->apply_trc_type); + trc_func = av_csp_trc_func_from_id(s->apply_trc_type); if (trc_func) { for (i = 0; i < 65536; ++i) { t.i = half2float(i, &s->h2f_tables); diff --git a/libavcodec/fflcms2.c b/libavcodec/fflcms2.c index fd370fb310..5443f178bc 100644 --- a/libavcodec/fflcms2.c +++ b/libavcodec/fflcms2.c @@ -17,7 +17,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavutil/color_utils.h" #include "libavutil/csp.h" #include "fflcms2.h" diff --git a/libavcodec/pngenc.c b/libavcodec/pngenc.c index 0ce684342e..e97150f55f 100644 --- a/libavcodec/pngenc.c +++ b/libavcodec/pngenc.c @@ -29,7 +29,6 @@ #include "zlib_wrapper.h" #include "libavutil/avassert.h" -#include "libavutil/color_utils.h" #include "libavutil/crc.h" #include "libavutil/csp.h" #include "libavutil/libm.h" @@ -317,7 +316,7 @@ static int png_get_chrm(enum AVColorPrimaries prim, uint8_t *buf) static int png_get_gama(enum AVColorTransferCharacteristic trc, uint8_t *buf) { - double gamma = avpriv_get_gamma_from_trc(trc); + double gamma = av_csp_approximate_trc_gamma(trc); if (gamma <= 1e-6) return 0; diff --git a/libavformat/movenc.c b/libavformat/movenc.c index 8d31317838..6182dc7f58 100644 --- a/libavformat/movenc.c +++ b/libavformat/movenc.c @@ -47,6 +47,7 @@ #include "internal.h" #include "libavutil/avstring.h" #include "libavutil/channel_layout.h" +#include "libavutil/csp.h" #include "libavutil/intfloat.h" #include "libavutil/mathematics.h" #include "libavutil/libm.h" @@ -56,7 +57,6 @@ #include "libavutil/stereo3d.h" #include "libavutil/timecode.h" #include "libavutil/dovi_meta.h" -#include "libavutil/color_utils.h" #include "libavutil/uuid.h" #include "hevc.h" #include "rtpenc.h" @@ -2011,9 +2011,8 @@ static int mov_write_pasp_tag(AVIOContext *pb, MOVTrack *track) static int mov_write_gama_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track, double gamma) { uint32_t gama = 0; - if (gamma <= 0.0) { - gamma = avpriv_get_gamma_from_trc(track->par->color_trc); - } + if (gamma <= 0.0) + gamma = av_csp_approximate_trc_gamma(track->par->color_trc); av_log(s, AV_LOG_DEBUG, "gamma value %g\n", gamma); if (gamma > 1e-6) { diff --git a/libavutil/Makefile b/libavutil/Makefile index 29b06665f5..dc9012f9a8 100644 --- a/libavutil/Makefile +++ b/libavutil/Makefile @@ -114,7 +114,6 @@ OBJS = adler32.o \ cast5.o \ camellia.o \ channel_layout.o \ - color_utils.o \ cpu.o \ crc.o \ csp.o \ diff --git a/libavutil/color_utils.c b/libavutil/color_utils.c deleted file mode 100644 index 5e221fb798..0000000000 --- a/libavutil/color_utils.c +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright (c) 2015 Kevin Wheatley - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include - -#include "libavutil/color_utils.h" -#include "libavutil/pixfmt.h" - -double avpriv_get_gamma_from_trc(enum AVColorTransferCharacteristic trc) -{ - double gamma; - switch (trc) { - case AVCOL_TRC_BT709: - case AVCOL_TRC_SMPTE170M: - case AVCOL_TRC_SMPTE240M: - case AVCOL_TRC_BT1361_ECG: - case AVCOL_TRC_BT2020_10: - case AVCOL_TRC_BT2020_12: - /* these share a segmented TRC, but gamma 1.961 is a close - approximation, and also more correct for decoding content */ - gamma = 1.961; - break; - case AVCOL_TRC_GAMMA22: - case AVCOL_TRC_IEC61966_2_1: - gamma = 2.2; - break; - case AVCOL_TRC_GAMMA28: - gamma = 2.8; - break; - case AVCOL_TRC_LINEAR: - gamma = 1.0; - break; - default: - gamma = 0.0; // Unknown value representation - } - return gamma; -} - -#define BT709_alpha 1.099296826809442 -#define BT709_beta 0.018053968510807 - -static double avpriv_trc_bt709(double Lc) -{ - const double a = BT709_alpha; - const double b = BT709_beta; - - return (0.0 > Lc) ? 0.0 - : ( b > Lc) ? 4.500 * Lc - : a * pow(Lc, 0.45) - (a - 1.0); -} - -static double avpriv_trc_gamma22(double Lc) -{ - return (0.0 > Lc) ? 0.0 : pow(Lc, 1.0/ 2.2); -} - -static double avpriv_trc_gamma28(double Lc) -{ - return (0.0 > Lc) ? 0.0 : pow(Lc, 1.0/ 2.8); -} - -static double avpriv_trc_smpte240M(double Lc) -{ - const double a = 1.1115; - const double b = 0.0228; - - return (0.0 > Lc) ? 0.0 - : ( b > Lc) ? 4.000 * Lc - : a * pow(Lc, 0.45) - (a - 1.0); -} - -static double avpriv_trc_linear(double Lc) -{ - return Lc; -} - -static double avpriv_trc_log(double Lc) -{ - return (0.01 > Lc) ? 0.0 : 1.0 + log10(Lc) / 2.0; -} - -static double avpriv_trc_log_sqrt(double Lc) -{ - // sqrt(10) / 1000 - return (0.00316227766 > Lc) ? 0.0 : 1.0 + log10(Lc) / 2.5; -} - -static double avpriv_trc_iec61966_2_4(double Lc) -{ - const double a = BT709_alpha; - const double b = BT709_beta; - - return (-b >= Lc) ? -a * pow(-Lc, 0.45) + (a - 1.0) - : ( b > Lc) ? 4.500 * Lc - : a * pow( Lc, 0.45) - (a - 1.0); -} - -static double avpriv_trc_bt1361(double Lc) -{ - const double a = BT709_alpha; - const double b = BT709_beta; - - return (-0.0045 >= Lc) ? -(a * pow(-4.0 * Lc, 0.45) + (a - 1.0)) / 4.0 - : ( b > Lc) ? 4.500 * Lc - : a * pow( Lc, 0.45) - (a - 1.0); -} - -static double avpriv_trc_iec61966_2_1(double Lc) -{ - const double a = 1.055; - const double b = 0.0031308; - - return (0.0 > Lc) ? 0.0 - : ( b > Lc) ? 12.92 * Lc - : a * pow(Lc, 1.0 / 2.4) - (a - 1.0); -} - -static double avpriv_trc_smpte_st2084(double Lc) -{ - const double c1 = 3424.0 / 4096.0; // c3-c2 + 1 - const double c2 = 32.0 * 2413.0 / 4096.0; - const double c3 = 32.0 * 2392.0 / 4096.0; - const double m = 128.0 * 2523.0 / 4096.0; - const double n = 0.25 * 2610.0 / 4096.0; - const double L = Lc / 10000.0; - const double Ln = pow(L, n); - - return (0.0 > Lc) ? 0.0 - : pow((c1 + c2 * Ln) / (1.0 + c3 * Ln), m); - -} - -static double avpriv_trc_smpte_st428_1(double Lc) -{ - return (0.0 > Lc) ? 0.0 - : pow(48.0 * Lc / 52.37, 1.0 / 2.6); -} - - -static double avpriv_trc_arib_std_b67(double Lc) { - // The function uses the definition from HEVC, which assumes that the peak - // white is input level = 1. (this is equivalent to scaling E = Lc * 12 and - // using the definition from the ARIB STD-B67 spec) - const double a = 0.17883277; - const double b = 0.28466892; - const double c = 0.55991073; - return (0.0 > Lc) ? 0.0 : - (Lc <= 1.0 / 12.0 ? sqrt(3.0 * Lc) : a * log(12.0 * Lc - b) + c); -} - -avpriv_trc_function avpriv_get_trc_function_from_trc(enum AVColorTransferCharacteristic trc) -{ - avpriv_trc_function func = NULL; - switch (trc) { - case AVCOL_TRC_BT709: - case AVCOL_TRC_SMPTE170M: - case AVCOL_TRC_BT2020_10: - case AVCOL_TRC_BT2020_12: - func = avpriv_trc_bt709; - break; - - case AVCOL_TRC_GAMMA22: - func = avpriv_trc_gamma22; - break; - case AVCOL_TRC_GAMMA28: - func = avpriv_trc_gamma28; - break; - - case AVCOL_TRC_SMPTE240M: - func = avpriv_trc_smpte240M; - break; - - case AVCOL_TRC_LINEAR: - func = avpriv_trc_linear; - break; - - case AVCOL_TRC_LOG: - func = avpriv_trc_log; - break; - - case AVCOL_TRC_LOG_SQRT: - func = avpriv_trc_log_sqrt; - break; - - case AVCOL_TRC_IEC61966_2_4: - func = avpriv_trc_iec61966_2_4; - break; - - case AVCOL_TRC_BT1361_ECG: - func = avpriv_trc_bt1361; - break; - - case AVCOL_TRC_IEC61966_2_1: - func = avpriv_trc_iec61966_2_1; - break; - - case AVCOL_TRC_SMPTEST2084: - func = avpriv_trc_smpte_st2084; - break; - - case AVCOL_TRC_SMPTEST428_1: - func = avpriv_trc_smpte_st428_1; - break; - - case AVCOL_TRC_ARIB_STD_B67: - func = avpriv_trc_arib_std_b67; - break; - - case AVCOL_TRC_RESERVED0: - case AVCOL_TRC_UNSPECIFIED: - case AVCOL_TRC_RESERVED: - default: - break; - } - return func; -} diff --git a/libavutil/color_utils.h b/libavutil/color_utils.h deleted file mode 100644 index 9529006452..0000000000 --- a/libavutil/color_utils.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2015 Kevin Wheatley - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef AVUTIL_COLOR_UTILS_H -#define AVUTIL_COLOR_UTILS_H - - -#include "libavutil/pixfmt.h" - -/** - * Determine a suitable 'gamma' value to match the supplied - * AVColorTransferCharacteristic. - * - * See Apple Technical Note TN2257 (https://developer.apple.com/library/mac/technotes/tn2257/_index.html) - * - * @return Will return an approximation to the simple gamma function matching - * the supplied Transfer Characteristic, Will return 0.0 for any - * we cannot reasonably match against. - */ -double avpriv_get_gamma_from_trc(enum AVColorTransferCharacteristic trc); - - -typedef double (*avpriv_trc_function)(double); - -/** - * Determine the function needed to apply the given - * AVColorTransferCharacteristic to linear input. - * - * The function returned should expect a nominal domain and range of [0.0-1.0] - * values outside of this range maybe valid depending on the chosen - * characteristic function. - * - * @return Will return pointer to the function matching the - * supplied Transfer Characteristic. If unspecified will - * return NULL: - */ -avpriv_trc_function avpriv_get_trc_function_from_trc(enum AVColorTransferCharacteristic trc); - -#endif diff --git a/libavutil/csp.c b/libavutil/csp.c index 98fc83c1da..7ef822c60b 100644 --- a/libavutil/csp.c +++ b/libavutil/csp.c @@ -1,5 +1,8 @@ /* + * Copyright (c) 2015 Kevin Wheatley * Copyright (c) 2016 Ronald S. Bultje + * Copyright (c) 2023 Leo Izen + * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or @@ -21,9 +24,11 @@ * @file Colorspace functions for libavutil * @author Ronald S. Bultje * @author Leo Izen + * @author Kevin Wheatley */ #include +#include #include "attributes.h" #include "csp.h" @@ -126,3 +131,170 @@ enum AVColorPrimaries av_csp_primaries_id_from_desc(const AVColorPrimariesDesc * return AVCOL_PRI_UNSPECIFIED; } + +static const double approximate_gamma[AVCOL_TRC_NB] = { + [AVCOL_TRC_BT709] = 1.961, + [AVCOL_TRC_SMPTE170M] = 1.961, + [AVCOL_TRC_SMPTE240M] = 1.961, + [AVCOL_TRC_BT1361_ECG] = 1.961, + [AVCOL_TRC_BT2020_10] = 1.961, + [AVCOL_TRC_BT2020_12] = 1.961, + [AVCOL_TRC_GAMMA22] = 2.2, + [AVCOL_TRC_IEC61966_2_1] = 2.2, + [AVCOL_TRC_GAMMA28] = 2.8, + [AVCOL_TRC_LINEAR] = 1.0, + [AVCOL_TRC_SMPTE428] = 2.6, +}; + +double av_csp_approximate_trc_gamma(enum AVColorTransferCharacteristic trc) +{ + double gamma; + if (trc >= AVCOL_TRC_NB) + return 0.0; + gamma = approximate_gamma[trc]; + if (gamma > 0) + return gamma; + return 0.0; +} + +#define BT709_alpha 1.099296826809442 +#define BT709_beta 0.018053968510807 + +static double trc_bt709(double Lc) +{ + const double a = BT709_alpha; + const double b = BT709_beta; + + return (0.0 > Lc) ? 0.0 + : ( b > Lc) ? 4.500 * Lc + : a * pow(Lc, 0.45) - (a - 1.0); +} + +static double trc_gamma22(double Lc) +{ + return (0.0 > Lc) ? 0.0 : pow(Lc, 1.0/ 2.2); +} + +static double trc_gamma28(double Lc) +{ + return (0.0 > Lc) ? 0.0 : pow(Lc, 1.0/ 2.8); +} + +static double trc_smpte240M(double Lc) +{ + const double a = 1.1115; + const double b = 0.0228; + + return (0.0 > Lc) ? 0.0 + : ( b > Lc) ? 4.000 * Lc + : a * pow(Lc, 0.45) - (a - 1.0); +} + +static double trc_linear(double Lc) +{ + return Lc; +} + +static double trc_log(double Lc) +{ + return (0.01 > Lc) ? 0.0 : 1.0 + log10(Lc) / 2.0; +} + +static double trc_log_sqrt(double Lc) +{ + // sqrt(10) / 1000 + return (0.00316227766 > Lc) ? 0.0 : 1.0 + log10(Lc) / 2.5; +} + +static double trc_iec61966_2_4(double Lc) +{ + const double a = BT709_alpha; + const double b = BT709_beta; + + return (-b >= Lc) ? -a * pow(-Lc, 0.45) + (a - 1.0) + : ( b > Lc) ? 4.500 * Lc + : a * pow( Lc, 0.45) - (a - 1.0); +} + +static double trc_bt1361(double Lc) +{ + const double a = BT709_alpha; + const double b = BT709_beta; + + return (-0.0045 >= Lc) ? -(a * pow(-4.0 * Lc, 0.45) + (a - 1.0)) / 4.0 + : ( b > Lc) ? 4.500 * Lc + : a * pow( Lc, 0.45) - (a - 1.0); +} + +static double trc_iec61966_2_1(double Lc) +{ + const double a = 1.055; + const double b = 0.0031308; + + return (0.0 > Lc) ? 0.0 + : ( b > Lc) ? 12.92 * Lc + : a * pow(Lc, 1.0 / 2.4) - (a - 1.0); +} + +static double trc_smpte_st2084(double Lc) +{ + const double c1 = 3424.0 / 4096.0; // c3-c2 + 1 + const double c2 = 32.0 * 2413.0 / 4096.0; + const double c3 = 32.0 * 2392.0 / 4096.0; + const double m = 128.0 * 2523.0 / 4096.0; + const double n = 0.25 * 2610.0 / 4096.0; + const double L = Lc / 10000.0; + const double Ln = pow(L, n); + + return (0.0 > Lc) ? 0.0 + : pow((c1 + c2 * Ln) / (1.0 + c3 * Ln), m); + +} + +static double trc_smpte_st428_1(double Lc) +{ + return (0.0 > Lc) ? 0.0 + : pow(48.0 * Lc / 52.37, 1.0 / 2.6); +} + + +static double trc_arib_std_b67(double Lc) { + // The function uses the definition from HEVC, which assumes that the peak + // white is input level = 1. (this is equivalent to scaling E = Lc * 12 and + // using the definition from the ARIB STD-B67 spec) + const double a = 0.17883277; + const double b = 0.28466892; + const double c = 0.55991073; + return (0.0 > Lc) ? 0.0 : + (Lc <= 1.0 / 12.0 ? sqrt(3.0 * Lc) : a * log(12.0 * Lc - b) + c); +} + +static const av_csp_trc_function trc_funcs[AVCOL_TRC_NB] = { + [AVCOL_TRC_BT709] = trc_bt709, + [AVCOL_TRC_GAMMA22] = trc_gamma22, + [AVCOL_TRC_GAMMA28] = trc_gamma28, + [AVCOL_TRC_SMPTE170M] = trc_bt709, + [AVCOL_TRC_SMPTE240M] = trc_smpte240M, + [AVCOL_TRC_LINEAR] = trc_linear, + [AVCOL_TRC_LOG] = trc_log, + [AVCOL_TRC_LOG_SQRT] = trc_log_sqrt, + [AVCOL_TRC_IEC61966_2_4] = trc_iec61966_2_4, + [AVCOL_TRC_BT1361_ECG] = trc_bt1361, + [AVCOL_TRC_IEC61966_2_1] = trc_iec61966_2_1, + [AVCOL_TRC_BT2020_10] = trc_bt709, + [AVCOL_TRC_BT2020_12] = trc_bt709, + [AVCOL_TRC_SMPTE2084] = trc_smpte_st2084, + [AVCOL_TRC_SMPTE428] = trc_smpte_st428_1, + [AVCOL_TRC_ARIB_STD_B67] = trc_arib_std_b67, +}; + +av_csp_trc_function av_csp_trc_func_from_id(enum AVColorTransferCharacteristic trc) +{ + av_csp_trc_function func; + if (trc >= AVCOL_TRC_NB) + return NULL; + func = trc_funcs[trc]; + if (!func) + return NULL; + return func; +} diff --git a/libavutil/csp.h b/libavutil/csp.h index 18ef208adf..73bce52bc0 100644 --- a/libavutil/csp.h +++ b/libavutil/csp.h @@ -1,5 +1,8 @@ /* + * Copyright (c) 2015 Kevin Wheatley * Copyright (c) 2016 Ronald S. Bultje + * Copyright (c) 2023 Leo Izen + * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or @@ -29,6 +32,7 @@ * @ingroup lavu_math_csp * @author Ronald S. Bultje * @author Leo Izen + * @author Kevin Wheatley */ /** @@ -76,6 +80,12 @@ typedef struct AVColorPrimariesDesc { AVPrimaryCoefficients prim; } AVColorPrimariesDesc; +/** + * Function pointer representing a double -> double transfer function that performs + * an EOTF transfer inversion. This function outputs linear light. + */ +typedef double (*av_csp_trc_function)(double); + /** * Retrieves the Luma coefficients necessary to construct a conversion matrix * from an enum constant describing the colorspace. @@ -104,6 +114,35 @@ const AVColorPrimariesDesc *av_csp_primaries_desc_from_id(enum AVColorPrimaries */ enum AVColorPrimaries av_csp_primaries_id_from_desc(const AVColorPrimariesDesc *prm); +/** + * Determine a suitable 'gamma' value to match the supplied + * AVColorTransferCharacteristic. + * + * See Apple Technical Note TN2257 (https://developer.apple.com/library/mac/technotes/tn2257/_index.html) + * + * This function returns the gamma exponent for the OETF. For example, sRGB is approximated + * by gamma 2.2, not by gamma 0.45455. + * + * @return Will return an approximation to the simple gamma function matching + * the supplied Transfer Characteristic, Will return 0.0 for any + * we cannot reasonably match against. + */ +double av_csp_approximate_trc_gamma(enum AVColorTransferCharacteristic trc); + +/** + * Determine the function needed to apply the given + * AVColorTransferCharacteristic to linear input. + * + * The function returned should expect a nominal domain and range of [0.0-1.0] + * values outside of this range maybe valid depending on the chosen + * characteristic function. + * + * @return Will return pointer to the function matching the + * supplied Transfer Characteristic. If unspecified will + * return NULL: + */ +av_csp_trc_function av_csp_trc_func_from_id(enum AVColorTransferCharacteristic trc); + /** * @} */ diff --git a/libavutil/tests/color_utils.c b/libavutil/tests/color_utils.c index 4bdc550330..95fb3c1d56 100644 --- a/libavutil/tests/color_utils.c +++ b/libavutil/tests/color_utils.c @@ -19,7 +19,7 @@ */ #include -#include "libavutil/color_utils.c" +#include "libavutil/csp.h" #include "libavutil/macros.h" int main(int argc, char *argv[]) @@ -32,7 +32,7 @@ int main(int argc, char *argv[]) }; for(i = 0; i < AVCOL_TRC_NB; i++) { - avpriv_trc_function func = avpriv_get_trc_function_from_trc(i); + av_csp_trc_function func = av_csp_trc_func_from_id(i); for(j = 0; j < FF_ARRAY_ELEMS(test_data); j++) { if(func != NULL) { double result = func(test_data[j]);