]> git.sesse.net Git - ffmpeg/blob - libavutil/color_utils.c
Merge commit '11843ededacd0157aea642771837557549b5b417'
[ffmpeg] / libavutil / color_utils.c
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 "common.h"
25 #include "libavutil/color_utils.h"
26 #include "libavutil/pixfmt.h"
27
28 double avpriv_get_gamma_from_trc(enum AVColorTransferCharacteristic trc)
29 {
30     double gamma;
31     switch (trc) {
32         case AVCOL_TRC_BT709:
33         case AVCOL_TRC_SMPTE170M:
34         case AVCOL_TRC_SMPTE240M:
35         case AVCOL_TRC_BT1361_ECG:
36         case AVCOL_TRC_BT2020_10:
37         case AVCOL_TRC_BT2020_12:
38             /* these share a segmented TRC, but gamma 1.961 is a close
39               approximation, and also more correct for decoding content */
40             gamma = 1.961;
41             break;
42         case AVCOL_TRC_GAMMA22:
43         case AVCOL_TRC_IEC61966_2_1:
44             gamma = 2.2;
45             break;
46         case AVCOL_TRC_GAMMA28:
47             gamma = 2.8;
48             break;
49         case AVCOL_TRC_LINEAR:
50             gamma = 1.0;
51             break;
52         default:
53             gamma = 0.0; // Unknown value representation
54     }
55     return gamma;
56 }
57
58 #define BT709_alpha 1.099296826809442
59 #define BT709_beta 0.018053968510807
60
61 static double avpriv_trc_bt709(double Lc)
62 {
63     const double a = BT709_alpha;
64     const double b = BT709_beta;
65
66     return (0.0 > Lc) ? 0.0
67          : (  b > Lc) ? 4.500 * Lc
68          :              a * pow(Lc, 0.45) - (a - 1.0);
69 }
70
71 static double avpriv_trc_gamma22(double Lc)
72 {
73     return (0.0 > Lc) ? 0.0 : pow(Lc, 1.0/ 2.2);
74 }
75
76 static double avpriv_trc_gamma28(double Lc)
77 {
78     return (0.0 > Lc) ? 0.0 : pow(Lc, 1.0/ 2.8);
79 }
80
81 static double avpriv_trc_smpte240M(double Lc)
82 {
83     const double a = 1.1115;
84     const double b = 0.0228;
85
86     return (0.0 > Lc) ? 0.0
87          : (  b > Lc) ? 4.000 * Lc
88          :              a * pow(Lc, 0.45) - (a - 1.0);
89 }
90
91 static double avpriv_trc_linear(double Lc)
92 {
93     return Lc;
94 }
95
96 static double avpriv_trc_log(double Lc)
97 {
98     return (0.01 > Lc) ? 0.0 : 1.0 + log10(Lc) / 2.0;
99 }
100
101 static double avpriv_trc_log_sqrt(double Lc)
102 {
103     // sqrt(10) / 1000
104     return (0.00316227766 > Lc) ? 0.0 : 1.0 + log10(Lc) / 2.5;
105 }
106
107 static double avpriv_trc_iec61966_2_4(double Lc)
108 {
109     const double a = BT709_alpha;
110     const double b = BT709_beta;
111
112     return (-b >= Lc) ? -a * pow(-Lc, 0.45) + (a - 1.0)
113          : ( b >  Lc) ? 4.500 * Lc
114          :               a * pow( Lc, 0.45) - (a - 1.0);
115 }
116
117 static double avpriv_trc_bt1361(double Lc)
118 {
119     const double a = BT709_alpha;
120     const double b = BT709_beta;
121
122     return (-0.0045 >= Lc) ? -(a * pow(-4.0 * Lc, 0.45) + (a - 1.0)) / 4.0
123          : ( b >  Lc) ? 4.500 * Lc
124          :               a * pow( Lc, 0.45) - (a - 1.0);
125 }
126
127 static double avpriv_trc_iec61966_2_1(double Lc)
128 {
129     const double a = 1.055;
130     const double b = 0.0031308;
131
132     return (0.0 > Lc) ? 0.0
133          : (  b > Lc) ? 12.92 * Lc
134          :              a * pow(Lc, 1.0  / 2.4) - (a - 1.0);
135 }
136
137 static double avpriv_trc_smpte_st2084(double Lc)
138 {
139     const double c1 =         3424.0 / 4096.0; // c3-c2 + 1
140     const double c2 =  32.0 * 2413.0 / 4096.0;
141     const double c3 =  32.0 * 2392.0 / 4096.0;
142     const double m  = 128.0 * 2523.0 / 4096.0;
143     const double n  =  0.25 * 2610.0 / 4096.0;
144     const double L  = Lc / 10000.0;
145     const double Ln = pow(L, n);
146
147     return (0.0 > Lc) ? 0.0
148          :              pow((c1 + c2 * Ln) / (1.0 + c3 * Ln), m);
149
150 }
151
152 static double avpriv_trc_smpte_st428_1(double Lc)
153 {
154     return (0.0 > Lc) ? 0.0
155          :              pow(48.0 * Lc / 52.37, 1.0 / 2.6);
156 }
157
158 avpriv_trc_function avpriv_get_trc_function_from_trc(enum AVColorTransferCharacteristic trc)
159 {
160     avpriv_trc_function func = NULL;
161     switch (trc) {
162         case AVCOL_TRC_BT709:
163         case AVCOL_TRC_SMPTE170M:
164         case AVCOL_TRC_BT2020_10:
165         case AVCOL_TRC_BT2020_12:
166             func = avpriv_trc_bt709;
167             break;
168
169         case AVCOL_TRC_GAMMA22:
170             func = avpriv_trc_gamma22;
171             break;
172         case AVCOL_TRC_GAMMA28:
173             func = avpriv_trc_gamma28;
174             break;
175
176         case AVCOL_TRC_SMPTE240M:
177             func = avpriv_trc_smpte240M;
178             break;
179
180         case AVCOL_TRC_LINEAR:
181             func = avpriv_trc_linear;
182             break;
183
184         case AVCOL_TRC_LOG:
185             func = avpriv_trc_log;
186             break;
187
188         case AVCOL_TRC_LOG_SQRT:
189             func = avpriv_trc_log_sqrt;
190             break;
191
192         case AVCOL_TRC_IEC61966_2_4:
193             func = avpriv_trc_iec61966_2_4;
194             break;
195
196         case AVCOL_TRC_BT1361_ECG:
197             func = avpriv_trc_bt1361;
198             break;
199
200         case AVCOL_TRC_IEC61966_2_1:
201             func = avpriv_trc_iec61966_2_1;
202             break;
203
204         case AVCOL_TRC_SMPTEST2084:
205             func = avpriv_trc_smpte_st2084;
206             break;
207
208         case AVCOL_TRC_SMPTEST428_1:
209             func = avpriv_trc_smpte_st428_1;
210             break;
211
212         case AVCOL_TRC_RESERVED0:
213         case AVCOL_TRC_UNSPECIFIED:
214         case AVCOL_TRC_RESERVED:
215         default:
216             break;
217     }
218     return func;
219 }
220
221 #ifdef TEST
222 // LCOV_EXCL_START
223
224 int main(int argc, char *argv[])
225 {
226   int i, j;
227   static const double test_data[] = {
228       -0.1, -0.018053968510807, -0.01, -0.00449, 0.0, 0.00316227760, 0.005,
229       0.009, 0.015, 0.1, 1.0, 52.37, 125.098765, 1999.11123, 6945.443,
230       15123.4567, 19845.88923, 98678.4231, 99999.899998
231   };
232
233   for(i = 0; i < AVCOL_TRC_NB; i++) {
234       avpriv_trc_function func = avpriv_get_trc_function_from_trc(i);
235       for(j = 0; j < FF_ARRAY_ELEMS(test_data); j++) {
236           if(func != NULL) {
237               double result = func(test_data[j]);
238               printf("AVColorTransferCharacteristic=%d calling func(%f) expected=%f\n",
239                      i, test_data[j], result);
240           }
241       }
242   }
243
244 }
245
246 // LCOV_EXCL_STOP
247 #endif