1 /*
2  * Copyright (c) 2015 Kevin Wheatley <kevin.j.wheatley@gmail.com>
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #include <stddef.h>
22 #include <math.h>
23 
24 #include "libavutil/color_utils.h"
25 #include "libavutil/pixfmt.h"
26 
avpriv_get_gamma_from_trc(enum AVColorTransferCharacteristic trc)27 double avpriv_get_gamma_from_trc(enum AVColorTransferCharacteristic trc)
28 {
29     double gamma;
30     switch (trc) {
31         case AVCOL_TRC_BT709:
32         case AVCOL_TRC_SMPTE170M:
33         case AVCOL_TRC_SMPTE240M:
34         case AVCOL_TRC_BT1361_ECG:
35         case AVCOL_TRC_BT2020_10:
36         case AVCOL_TRC_BT2020_12:
37             /* these share a segmented TRC, but gamma 1.961 is a close
38               approximation, and also more correct for decoding content */
39             gamma = 1.961;
40             break;
41         case AVCOL_TRC_GAMMA22:
42         case AVCOL_TRC_IEC61966_2_1:
43             gamma = 2.2;
44             break;
45         case AVCOL_TRC_GAMMA28:
46             gamma = 2.8;
47             break;
48         case AVCOL_TRC_LINEAR:
49             gamma = 1.0;
50             break;
51         default:
52             gamma = 0.0; // Unknown value representation
53     }
54     return gamma;
55 }
56 
57 #define BT709_alpha 1.099296826809442
58 #define BT709_beta 0.018053968510807
59 
avpriv_trc_bt709(double Lc)60 static double avpriv_trc_bt709(double Lc)
61 {
62     const double a = BT709_alpha;
63     const double b = BT709_beta;
64 
65     return (0.0 > Lc) ? 0.0
66          : (  b > Lc) ? 4.500 * Lc
67          :              a * pow(Lc, 0.45) - (a - 1.0);
68 }
69 
avpriv_trc_gamma22(double Lc)70 static double avpriv_trc_gamma22(double Lc)
71 {
72     return (0.0 > Lc) ? 0.0 : pow(Lc, 1.0/ 2.2);
73 }
74 
avpriv_trc_gamma28(double Lc)75 static double avpriv_trc_gamma28(double Lc)
76 {
77     return (0.0 > Lc) ? 0.0 : pow(Lc, 1.0/ 2.8);
78 }
79 
avpriv_trc_smpte240M(double Lc)80 static double avpriv_trc_smpte240M(double Lc)
81 {
82     const double a = 1.1115;
83     const double b = 0.0228;
84 
85     return (0.0 > Lc) ? 0.0
86          : (  b > Lc) ? 4.000 * Lc
87          :              a * pow(Lc, 0.45) - (a - 1.0);
88 }
89 
avpriv_trc_linear(double Lc)90 static double avpriv_trc_linear(double Lc)
91 {
92     return Lc;
93 }
94 
avpriv_trc_log(double Lc)95 static double avpriv_trc_log(double Lc)
96 {
97     return (0.01 > Lc) ? 0.0 : 1.0 + log10(Lc) / 2.0;
98 }
99 
avpriv_trc_log_sqrt(double Lc)100 static double avpriv_trc_log_sqrt(double Lc)
101 {
102     // sqrt(10) / 1000
103     return (0.00316227766 > Lc) ? 0.0 : 1.0 + log10(Lc) / 2.5;
104 }
105 
avpriv_trc_iec61966_2_4(double Lc)106 static double avpriv_trc_iec61966_2_4(double Lc)
107 {
108     const double a = BT709_alpha;
109     const double b = BT709_beta;
110 
111     return (-b >= Lc) ? -a * pow(-Lc, 0.45) + (a - 1.0)
112          : ( b >  Lc) ? 4.500 * Lc
113          :               a * pow( Lc, 0.45) - (a - 1.0);
114 }
115 
avpriv_trc_bt1361(double Lc)116 static double avpriv_trc_bt1361(double Lc)
117 {
118     const double a = BT709_alpha;
119     const double b = BT709_beta;
120 
121     return (-0.0045 >= Lc) ? -(a * pow(-4.0 * Lc, 0.45) + (a - 1.0)) / 4.0
122          : ( b >  Lc) ? 4.500 * Lc
123          :               a * pow( Lc, 0.45) - (a - 1.0);
124 }
125 
avpriv_trc_iec61966_2_1(double Lc)126 static double avpriv_trc_iec61966_2_1(double Lc)
127 {
128     const double a = 1.055;
129     const double b = 0.0031308;
130 
131     return (0.0 > Lc) ? 0.0
132          : (  b > Lc) ? 12.92 * Lc
133          :              a * pow(Lc, 1.0  / 2.4) - (a - 1.0);
134 }
135 
avpriv_trc_smpte_st2084(double Lc)136 static double avpriv_trc_smpte_st2084(double Lc)
137 {
138     const double c1 =         3424.0 / 4096.0; // c3-c2 + 1
139     const double c2 =  32.0 * 2413.0 / 4096.0;
140     const double c3 =  32.0 * 2392.0 / 4096.0;
141     const double m  = 128.0 * 2523.0 / 4096.0;
142     const double n  =  0.25 * 2610.0 / 4096.0;
143     const double L  = Lc / 10000.0;
144     const double Ln = pow(L, n);
145 
146     return (0.0 > Lc) ? 0.0
147          :              pow((c1 + c2 * Ln) / (1.0 + c3 * Ln), m);
148 
149 }
150 
avpriv_trc_smpte_st428_1(double Lc)151 static double avpriv_trc_smpte_st428_1(double Lc)
152 {
153     return (0.0 > Lc) ? 0.0
154          :              pow(48.0 * Lc / 52.37, 1.0 / 2.6);
155 }
156 
157 
avpriv_trc_arib_std_b67(double Lc)158 static double avpriv_trc_arib_std_b67(double Lc) {
159     // The function uses the definition from HEVC, which assumes that the peak
160     // white is input level = 1. (this is equivalent to scaling E = Lc * 12 and
161     // using the definition from the ARIB STD-B67 spec)
162     const double a = 0.17883277;
163     const double b = 0.28466892;
164     const double c = 0.55991073;
165     return (0.0 > Lc) ? 0.0 :
166         (Lc <= 1.0 / 12.0 ? sqrt(3.0 * Lc) : a * log(12.0 * Lc - b) + c);
167 }
168 
avpriv_get_trc_function_from_trc(enum AVColorTransferCharacteristic trc)169 avpriv_trc_function avpriv_get_trc_function_from_trc(enum AVColorTransferCharacteristic trc)
170 {
171     avpriv_trc_function func = NULL;
172     switch (trc) {
173         case AVCOL_TRC_BT709:
174         case AVCOL_TRC_SMPTE170M:
175         case AVCOL_TRC_BT2020_10:
176         case AVCOL_TRC_BT2020_12:
177             func = avpriv_trc_bt709;
178             break;
179 
180         case AVCOL_TRC_GAMMA22:
181             func = avpriv_trc_gamma22;
182             break;
183         case AVCOL_TRC_GAMMA28:
184             func = avpriv_trc_gamma28;
185             break;
186 
187         case AVCOL_TRC_SMPTE240M:
188             func = avpriv_trc_smpte240M;
189             break;
190 
191         case AVCOL_TRC_LINEAR:
192             func = avpriv_trc_linear;
193             break;
194 
195         case AVCOL_TRC_LOG:
196             func = avpriv_trc_log;
197             break;
198 
199         case AVCOL_TRC_LOG_SQRT:
200             func = avpriv_trc_log_sqrt;
201             break;
202 
203         case AVCOL_TRC_IEC61966_2_4:
204             func = avpriv_trc_iec61966_2_4;
205             break;
206 
207         case AVCOL_TRC_BT1361_ECG:
208             func = avpriv_trc_bt1361;
209             break;
210 
211         case AVCOL_TRC_IEC61966_2_1:
212             func = avpriv_trc_iec61966_2_1;
213             break;
214 
215         case AVCOL_TRC_SMPTEST2084:
216             func = avpriv_trc_smpte_st2084;
217             break;
218 
219         case AVCOL_TRC_SMPTEST428_1:
220             func = avpriv_trc_smpte_st428_1;
221             break;
222 
223         case AVCOL_TRC_ARIB_STD_B67:
224             func = avpriv_trc_arib_std_b67;
225             break;
226 
227         case AVCOL_TRC_RESERVED0:
228         case AVCOL_TRC_UNSPECIFIED:
229         case AVCOL_TRC_RESERVED:
230         default:
231             break;
232     }
233     return func;
234 }
235