1*b2055c35SXin Li // Copyright 2022 Google Inc. All Rights Reserved.
2*b2055c35SXin Li //
3*b2055c35SXin Li // Use of this source code is governed by a BSD-style license
4*b2055c35SXin Li // that can be found in the COPYING file in the root of the source
5*b2055c35SXin Li // tree. An additional intellectual property rights grant can be found
6*b2055c35SXin Li // in the file PATENTS. All contributing project authors may
7*b2055c35SXin Li // be found in the AUTHORS file in the root of the source tree.
8*b2055c35SXin Li // -----------------------------------------------------------------------------
9*b2055c35SXin Li //
10*b2055c35SXin Li // Gamma correction utilities.
11*b2055c35SXin Li
12*b2055c35SXin Li #include "sharpyuv/sharpyuv_gamma.h"
13*b2055c35SXin Li
14*b2055c35SXin Li #include <assert.h>
15*b2055c35SXin Li #include <float.h>
16*b2055c35SXin Li #include <math.h>
17*b2055c35SXin Li
18*b2055c35SXin Li #include "src/webp/types.h"
19*b2055c35SXin Li
20*b2055c35SXin Li // Gamma correction compensates loss of resolution during chroma subsampling.
21*b2055c35SXin Li // Size of pre-computed table for converting from gamma to linear.
22*b2055c35SXin Li #define GAMMA_TO_LINEAR_TAB_BITS 10
23*b2055c35SXin Li #define GAMMA_TO_LINEAR_TAB_SIZE (1 << GAMMA_TO_LINEAR_TAB_BITS)
24*b2055c35SXin Li static uint32_t kGammaToLinearTabS[GAMMA_TO_LINEAR_TAB_SIZE + 2];
25*b2055c35SXin Li #define LINEAR_TO_GAMMA_TAB_BITS 9
26*b2055c35SXin Li #define LINEAR_TO_GAMMA_TAB_SIZE (1 << LINEAR_TO_GAMMA_TAB_BITS)
27*b2055c35SXin Li static uint32_t kLinearToGammaTabS[LINEAR_TO_GAMMA_TAB_SIZE + 2];
28*b2055c35SXin Li
29*b2055c35SXin Li static const double kGammaF = 1. / 0.45;
30*b2055c35SXin Li #define GAMMA_TO_LINEAR_BITS 16
31*b2055c35SXin Li
32*b2055c35SXin Li static volatile int kGammaTablesSOk = 0;
SharpYuvInitGammaTables(void)33*b2055c35SXin Li void SharpYuvInitGammaTables(void) {
34*b2055c35SXin Li assert(GAMMA_TO_LINEAR_BITS <= 16);
35*b2055c35SXin Li if (!kGammaTablesSOk) {
36*b2055c35SXin Li int v;
37*b2055c35SXin Li const double a = 0.09929682680944;
38*b2055c35SXin Li const double thresh = 0.018053968510807;
39*b2055c35SXin Li const double final_scale = 1 << GAMMA_TO_LINEAR_BITS;
40*b2055c35SXin Li // Precompute gamma to linear table.
41*b2055c35SXin Li {
42*b2055c35SXin Li const double norm = 1. / GAMMA_TO_LINEAR_TAB_SIZE;
43*b2055c35SXin Li const double a_rec = 1. / (1. + a);
44*b2055c35SXin Li for (v = 0; v <= GAMMA_TO_LINEAR_TAB_SIZE; ++v) {
45*b2055c35SXin Li const double g = norm * v;
46*b2055c35SXin Li double value;
47*b2055c35SXin Li if (g <= thresh * 4.5) {
48*b2055c35SXin Li value = g / 4.5;
49*b2055c35SXin Li } else {
50*b2055c35SXin Li value = pow(a_rec * (g + a), kGammaF);
51*b2055c35SXin Li }
52*b2055c35SXin Li kGammaToLinearTabS[v] = (uint32_t)(value * final_scale + .5);
53*b2055c35SXin Li }
54*b2055c35SXin Li // to prevent small rounding errors to cause read-overflow:
55*b2055c35SXin Li kGammaToLinearTabS[GAMMA_TO_LINEAR_TAB_SIZE + 1] =
56*b2055c35SXin Li kGammaToLinearTabS[GAMMA_TO_LINEAR_TAB_SIZE];
57*b2055c35SXin Li }
58*b2055c35SXin Li // Precompute linear to gamma table.
59*b2055c35SXin Li {
60*b2055c35SXin Li const double scale = 1. / LINEAR_TO_GAMMA_TAB_SIZE;
61*b2055c35SXin Li for (v = 0; v <= LINEAR_TO_GAMMA_TAB_SIZE; ++v) {
62*b2055c35SXin Li const double g = scale * v;
63*b2055c35SXin Li double value;
64*b2055c35SXin Li if (g <= thresh) {
65*b2055c35SXin Li value = 4.5 * g;
66*b2055c35SXin Li } else {
67*b2055c35SXin Li value = (1. + a) * pow(g, 1. / kGammaF) - a;
68*b2055c35SXin Li }
69*b2055c35SXin Li kLinearToGammaTabS[v] =
70*b2055c35SXin Li (uint32_t)(final_scale * value + 0.5);
71*b2055c35SXin Li }
72*b2055c35SXin Li // to prevent small rounding errors to cause read-overflow:
73*b2055c35SXin Li kLinearToGammaTabS[LINEAR_TO_GAMMA_TAB_SIZE + 1] =
74*b2055c35SXin Li kLinearToGammaTabS[LINEAR_TO_GAMMA_TAB_SIZE];
75*b2055c35SXin Li }
76*b2055c35SXin Li kGammaTablesSOk = 1;
77*b2055c35SXin Li }
78*b2055c35SXin Li }
79*b2055c35SXin Li
Shift(int v,int shift)80*b2055c35SXin Li static WEBP_INLINE int Shift(int v, int shift) {
81*b2055c35SXin Li return (shift >= 0) ? (v << shift) : (v >> -shift);
82*b2055c35SXin Li }
83*b2055c35SXin Li
FixedPointInterpolation(int v,uint32_t * tab,int tab_pos_shift_right,int tab_value_shift)84*b2055c35SXin Li static WEBP_INLINE uint32_t FixedPointInterpolation(int v, uint32_t* tab,
85*b2055c35SXin Li int tab_pos_shift_right,
86*b2055c35SXin Li int tab_value_shift) {
87*b2055c35SXin Li const uint32_t tab_pos = Shift(v, -tab_pos_shift_right);
88*b2055c35SXin Li // fractional part, in 'tab_pos_shift' fixed-point precision
89*b2055c35SXin Li const uint32_t x = v - (tab_pos << tab_pos_shift_right); // fractional part
90*b2055c35SXin Li // v0 / v1 are in kGammaToLinearBits fixed-point precision (range [0..1])
91*b2055c35SXin Li const uint32_t v0 = Shift(tab[tab_pos + 0], tab_value_shift);
92*b2055c35SXin Li const uint32_t v1 = Shift(tab[tab_pos + 1], tab_value_shift);
93*b2055c35SXin Li // Final interpolation.
94*b2055c35SXin Li const uint32_t v2 = (v1 - v0) * x; // note: v1 >= v0.
95*b2055c35SXin Li const int half =
96*b2055c35SXin Li (tab_pos_shift_right > 0) ? 1 << (tab_pos_shift_right - 1) : 0;
97*b2055c35SXin Li const uint32_t result = v0 + ((v2 + half) >> tab_pos_shift_right);
98*b2055c35SXin Li return result;
99*b2055c35SXin Li }
100*b2055c35SXin Li
ToLinearSrgb(uint16_t v,int bit_depth)101*b2055c35SXin Li static uint32_t ToLinearSrgb(uint16_t v, int bit_depth) {
102*b2055c35SXin Li const int shift = GAMMA_TO_LINEAR_TAB_BITS - bit_depth;
103*b2055c35SXin Li if (shift > 0) {
104*b2055c35SXin Li return kGammaToLinearTabS[v << shift];
105*b2055c35SXin Li }
106*b2055c35SXin Li return FixedPointInterpolation(v, kGammaToLinearTabS, -shift, 0);
107*b2055c35SXin Li }
108*b2055c35SXin Li
FromLinearSrgb(uint32_t value,int bit_depth)109*b2055c35SXin Li static uint16_t FromLinearSrgb(uint32_t value, int bit_depth) {
110*b2055c35SXin Li return FixedPointInterpolation(
111*b2055c35SXin Li value, kLinearToGammaTabS,
112*b2055c35SXin Li (GAMMA_TO_LINEAR_BITS - LINEAR_TO_GAMMA_TAB_BITS),
113*b2055c35SXin Li bit_depth - GAMMA_TO_LINEAR_BITS);
114*b2055c35SXin Li }
115*b2055c35SXin Li
116*b2055c35SXin Li ////////////////////////////////////////////////////////////////////////////////
117*b2055c35SXin Li
118*b2055c35SXin Li #define CLAMP(x, low, high) \
119*b2055c35SXin Li (((x) < (low)) ? (low) : (((high) < (x)) ? (high) : (x)))
120*b2055c35SXin Li #define MIN(a, b) (((a) < (b)) ? (a) : (b))
121*b2055c35SXin Li #define MAX(a, b) (((a) > (b)) ? (a) : (b))
122*b2055c35SXin Li
Roundf(float x)123*b2055c35SXin Li static WEBP_INLINE float Roundf(float x) {
124*b2055c35SXin Li if (x < 0)
125*b2055c35SXin Li return (float)ceil((double)(x - 0.5f));
126*b2055c35SXin Li else
127*b2055c35SXin Li return (float)floor((double)(x + 0.5f));
128*b2055c35SXin Li }
129*b2055c35SXin Li
Powf(float base,float exp)130*b2055c35SXin Li static WEBP_INLINE float Powf(float base, float exp) {
131*b2055c35SXin Li return (float)pow((double)base, (double)exp);
132*b2055c35SXin Li }
133*b2055c35SXin Li
Log10f(float x)134*b2055c35SXin Li static WEBP_INLINE float Log10f(float x) { return (float)log10((double)x); }
135*b2055c35SXin Li
ToLinear709(float gamma)136*b2055c35SXin Li static float ToLinear709(float gamma) {
137*b2055c35SXin Li if (gamma < 0.f) {
138*b2055c35SXin Li return 0.f;
139*b2055c35SXin Li } else if (gamma < 4.5f * 0.018053968510807f) {
140*b2055c35SXin Li return gamma / 4.5f;
141*b2055c35SXin Li } else if (gamma < 1.f) {
142*b2055c35SXin Li return Powf((gamma + 0.09929682680944f) / 1.09929682680944f, 1.f / 0.45f);
143*b2055c35SXin Li }
144*b2055c35SXin Li return 1.f;
145*b2055c35SXin Li }
146*b2055c35SXin Li
FromLinear709(float linear)147*b2055c35SXin Li static float FromLinear709(float linear) {
148*b2055c35SXin Li if (linear < 0.f) {
149*b2055c35SXin Li return 0.f;
150*b2055c35SXin Li } else if (linear < 0.018053968510807f) {
151*b2055c35SXin Li return linear * 4.5f;
152*b2055c35SXin Li } else if (linear < 1.f) {
153*b2055c35SXin Li return 1.09929682680944f * Powf(linear, 0.45f) - 0.09929682680944f;
154*b2055c35SXin Li }
155*b2055c35SXin Li return 1.f;
156*b2055c35SXin Li }
157*b2055c35SXin Li
ToLinear470M(float gamma)158*b2055c35SXin Li static float ToLinear470M(float gamma) {
159*b2055c35SXin Li return Powf(CLAMP(gamma, 0.f, 1.f), 2.2f);
160*b2055c35SXin Li }
161*b2055c35SXin Li
FromLinear470M(float linear)162*b2055c35SXin Li static float FromLinear470M(float linear) {
163*b2055c35SXin Li return Powf(CLAMP(linear, 0.f, 1.f), 1.f / 2.2f);
164*b2055c35SXin Li }
165*b2055c35SXin Li
ToLinear470Bg(float gamma)166*b2055c35SXin Li static float ToLinear470Bg(float gamma) {
167*b2055c35SXin Li return Powf(CLAMP(gamma, 0.f, 1.f), 2.8f);
168*b2055c35SXin Li }
169*b2055c35SXin Li
FromLinear470Bg(float linear)170*b2055c35SXin Li static float FromLinear470Bg(float linear) {
171*b2055c35SXin Li return Powf(CLAMP(linear, 0.f, 1.f), 1.f / 2.8f);
172*b2055c35SXin Li }
173*b2055c35SXin Li
ToLinearSmpte240(float gamma)174*b2055c35SXin Li static float ToLinearSmpte240(float gamma) {
175*b2055c35SXin Li if (gamma < 0.f) {
176*b2055c35SXin Li return 0.f;
177*b2055c35SXin Li } else if (gamma < 4.f * 0.022821585529445f) {
178*b2055c35SXin Li return gamma / 4.f;
179*b2055c35SXin Li } else if (gamma < 1.f) {
180*b2055c35SXin Li return Powf((gamma + 0.111572195921731f) / 1.111572195921731f, 1.f / 0.45f);
181*b2055c35SXin Li }
182*b2055c35SXin Li return 1.f;
183*b2055c35SXin Li }
184*b2055c35SXin Li
FromLinearSmpte240(float linear)185*b2055c35SXin Li static float FromLinearSmpte240(float linear) {
186*b2055c35SXin Li if (linear < 0.f) {
187*b2055c35SXin Li return 0.f;
188*b2055c35SXin Li } else if (linear < 0.022821585529445f) {
189*b2055c35SXin Li return linear * 4.f;
190*b2055c35SXin Li } else if (linear < 1.f) {
191*b2055c35SXin Li return 1.111572195921731f * Powf(linear, 0.45f) - 0.111572195921731f;
192*b2055c35SXin Li }
193*b2055c35SXin Li return 1.f;
194*b2055c35SXin Li }
195*b2055c35SXin Li
ToLinearLog100(float gamma)196*b2055c35SXin Li static float ToLinearLog100(float gamma) {
197*b2055c35SXin Li // The function is non-bijective so choose the middle of [0, 0.01].
198*b2055c35SXin Li const float mid_interval = 0.01f / 2.f;
199*b2055c35SXin Li return (gamma <= 0.0f) ? mid_interval
200*b2055c35SXin Li : Powf(10.0f, 2.f * (MIN(gamma, 1.f) - 1.0f));
201*b2055c35SXin Li }
202*b2055c35SXin Li
FromLinearLog100(float linear)203*b2055c35SXin Li static float FromLinearLog100(float linear) {
204*b2055c35SXin Li return (linear < 0.01f) ? 0.0f : 1.0f + Log10f(MIN(linear, 1.f)) / 2.0f;
205*b2055c35SXin Li }
206*b2055c35SXin Li
ToLinearLog100Sqrt10(float gamma)207*b2055c35SXin Li static float ToLinearLog100Sqrt10(float gamma) {
208*b2055c35SXin Li // The function is non-bijective so choose the middle of [0, 0.00316227766f[.
209*b2055c35SXin Li const float mid_interval = 0.00316227766f / 2.f;
210*b2055c35SXin Li return (gamma <= 0.0f) ? mid_interval
211*b2055c35SXin Li : Powf(10.0f, 2.5f * (MIN(gamma, 1.f) - 1.0f));
212*b2055c35SXin Li }
213*b2055c35SXin Li
FromLinearLog100Sqrt10(float linear)214*b2055c35SXin Li static float FromLinearLog100Sqrt10(float linear) {
215*b2055c35SXin Li return (linear < 0.00316227766f) ? 0.0f
216*b2055c35SXin Li : 1.0f + Log10f(MIN(linear, 1.f)) / 2.5f;
217*b2055c35SXin Li }
218*b2055c35SXin Li
ToLinearIec61966(float gamma)219*b2055c35SXin Li static float ToLinearIec61966(float gamma) {
220*b2055c35SXin Li if (gamma <= -4.5f * 0.018053968510807f) {
221*b2055c35SXin Li return Powf((-gamma + 0.09929682680944f) / -1.09929682680944f, 1.f / 0.45f);
222*b2055c35SXin Li } else if (gamma < 4.5f * 0.018053968510807f) {
223*b2055c35SXin Li return gamma / 4.5f;
224*b2055c35SXin Li }
225*b2055c35SXin Li return Powf((gamma + 0.09929682680944f) / 1.09929682680944f, 1.f / 0.45f);
226*b2055c35SXin Li }
227*b2055c35SXin Li
FromLinearIec61966(float linear)228*b2055c35SXin Li static float FromLinearIec61966(float linear) {
229*b2055c35SXin Li if (linear <= -0.018053968510807f) {
230*b2055c35SXin Li return -1.09929682680944f * Powf(-linear, 0.45f) + 0.09929682680944f;
231*b2055c35SXin Li } else if (linear < 0.018053968510807f) {
232*b2055c35SXin Li return linear * 4.5f;
233*b2055c35SXin Li }
234*b2055c35SXin Li return 1.09929682680944f * Powf(linear, 0.45f) - 0.09929682680944f;
235*b2055c35SXin Li }
236*b2055c35SXin Li
ToLinearBt1361(float gamma)237*b2055c35SXin Li static float ToLinearBt1361(float gamma) {
238*b2055c35SXin Li if (gamma < -0.25f) {
239*b2055c35SXin Li return -0.25f;
240*b2055c35SXin Li } else if (gamma < 0.f) {
241*b2055c35SXin Li return Powf((gamma - 0.02482420670236f) / -0.27482420670236f, 1.f / 0.45f) /
242*b2055c35SXin Li -4.f;
243*b2055c35SXin Li } else if (gamma < 4.5f * 0.018053968510807f) {
244*b2055c35SXin Li return gamma / 4.5f;
245*b2055c35SXin Li } else if (gamma < 1.f) {
246*b2055c35SXin Li return Powf((gamma + 0.09929682680944f) / 1.09929682680944f, 1.f / 0.45f);
247*b2055c35SXin Li }
248*b2055c35SXin Li return 1.f;
249*b2055c35SXin Li }
250*b2055c35SXin Li
FromLinearBt1361(float linear)251*b2055c35SXin Li static float FromLinearBt1361(float linear) {
252*b2055c35SXin Li if (linear < -0.25f) {
253*b2055c35SXin Li return -0.25f;
254*b2055c35SXin Li } else if (linear < 0.f) {
255*b2055c35SXin Li return -0.27482420670236f * Powf(-4.f * linear, 0.45f) + 0.02482420670236f;
256*b2055c35SXin Li } else if (linear < 0.018053968510807f) {
257*b2055c35SXin Li return linear * 4.5f;
258*b2055c35SXin Li } else if (linear < 1.f) {
259*b2055c35SXin Li return 1.09929682680944f * Powf(linear, 0.45f) - 0.09929682680944f;
260*b2055c35SXin Li }
261*b2055c35SXin Li return 1.f;
262*b2055c35SXin Li }
263*b2055c35SXin Li
ToLinearPq(float gamma)264*b2055c35SXin Li static float ToLinearPq(float gamma) {
265*b2055c35SXin Li if (gamma > 0.f) {
266*b2055c35SXin Li const float pow_gamma = Powf(gamma, 32.f / 2523.f);
267*b2055c35SXin Li const float num = MAX(pow_gamma - 107.f / 128.f, 0.0f);
268*b2055c35SXin Li const float den = MAX(2413.f / 128.f - 2392.f / 128.f * pow_gamma, FLT_MIN);
269*b2055c35SXin Li return Powf(num / den, 4096.f / 653.f);
270*b2055c35SXin Li }
271*b2055c35SXin Li return 0.f;
272*b2055c35SXin Li }
273*b2055c35SXin Li
FromLinearPq(float linear)274*b2055c35SXin Li static float FromLinearPq(float linear) {
275*b2055c35SXin Li if (linear > 0.f) {
276*b2055c35SXin Li const float pow_linear = Powf(linear, 653.f / 4096.f);
277*b2055c35SXin Li const float num = 107.f / 128.f + 2413.f / 128.f * pow_linear;
278*b2055c35SXin Li const float den = 1.0f + 2392.f / 128.f * pow_linear;
279*b2055c35SXin Li return Powf(num / den, 2523.f / 32.f);
280*b2055c35SXin Li }
281*b2055c35SXin Li return 0.f;
282*b2055c35SXin Li }
283*b2055c35SXin Li
ToLinearSmpte428(float gamma)284*b2055c35SXin Li static float ToLinearSmpte428(float gamma) {
285*b2055c35SXin Li return Powf(MAX(gamma, 0.f), 2.6f) / 0.91655527974030934f;
286*b2055c35SXin Li }
287*b2055c35SXin Li
FromLinearSmpte428(float linear)288*b2055c35SXin Li static float FromLinearSmpte428(float linear) {
289*b2055c35SXin Li return Powf(0.91655527974030934f * MAX(linear, 0.f), 1.f / 2.6f);
290*b2055c35SXin Li }
291*b2055c35SXin Li
292*b2055c35SXin Li // Conversion in BT.2100 requires RGB info. Simplify to gamma correction here.
ToLinearHlg(float gamma)293*b2055c35SXin Li static float ToLinearHlg(float gamma) {
294*b2055c35SXin Li if (gamma < 0.f) {
295*b2055c35SXin Li return 0.f;
296*b2055c35SXin Li } else if (gamma <= 0.5f) {
297*b2055c35SXin Li return Powf((gamma * gamma) * (1.f / 3.f), 1.2f);
298*b2055c35SXin Li }
299*b2055c35SXin Li return Powf((expf((gamma - 0.55991073f) / 0.17883277f) + 0.28466892f) / 12.0f,
300*b2055c35SXin Li 1.2f);
301*b2055c35SXin Li }
302*b2055c35SXin Li
FromLinearHlg(float linear)303*b2055c35SXin Li static float FromLinearHlg(float linear) {
304*b2055c35SXin Li linear = Powf(linear, 1.f / 1.2f);
305*b2055c35SXin Li if (linear < 0.f) {
306*b2055c35SXin Li return 0.f;
307*b2055c35SXin Li } else if (linear <= (1.f / 12.f)) {
308*b2055c35SXin Li return sqrtf(3.f * linear);
309*b2055c35SXin Li }
310*b2055c35SXin Li return 0.17883277f * logf(12.f * linear - 0.28466892f) + 0.55991073f;
311*b2055c35SXin Li }
312*b2055c35SXin Li
SharpYuvGammaToLinear(uint16_t v,int bit_depth,SharpYuvTransferFunctionType transfer_type)313*b2055c35SXin Li uint32_t SharpYuvGammaToLinear(uint16_t v, int bit_depth,
314*b2055c35SXin Li SharpYuvTransferFunctionType transfer_type) {
315*b2055c35SXin Li float v_float, linear;
316*b2055c35SXin Li if (transfer_type == kSharpYuvTransferFunctionSrgb) {
317*b2055c35SXin Li return ToLinearSrgb(v, bit_depth);
318*b2055c35SXin Li }
319*b2055c35SXin Li v_float = (float)v / ((1 << bit_depth) - 1);
320*b2055c35SXin Li switch (transfer_type) {
321*b2055c35SXin Li case kSharpYuvTransferFunctionBt709:
322*b2055c35SXin Li case kSharpYuvTransferFunctionBt601:
323*b2055c35SXin Li case kSharpYuvTransferFunctionBt2020_10Bit:
324*b2055c35SXin Li case kSharpYuvTransferFunctionBt2020_12Bit:
325*b2055c35SXin Li linear = ToLinear709(v_float);
326*b2055c35SXin Li break;
327*b2055c35SXin Li case kSharpYuvTransferFunctionBt470M:
328*b2055c35SXin Li linear = ToLinear470M(v_float);
329*b2055c35SXin Li break;
330*b2055c35SXin Li case kSharpYuvTransferFunctionBt470Bg:
331*b2055c35SXin Li linear = ToLinear470Bg(v_float);
332*b2055c35SXin Li break;
333*b2055c35SXin Li case kSharpYuvTransferFunctionSmpte240:
334*b2055c35SXin Li linear = ToLinearSmpte240(v_float);
335*b2055c35SXin Li break;
336*b2055c35SXin Li case kSharpYuvTransferFunctionLinear:
337*b2055c35SXin Li return v;
338*b2055c35SXin Li case kSharpYuvTransferFunctionLog100:
339*b2055c35SXin Li linear = ToLinearLog100(v_float);
340*b2055c35SXin Li break;
341*b2055c35SXin Li case kSharpYuvTransferFunctionLog100_Sqrt10:
342*b2055c35SXin Li linear = ToLinearLog100Sqrt10(v_float);
343*b2055c35SXin Li break;
344*b2055c35SXin Li case kSharpYuvTransferFunctionIec61966:
345*b2055c35SXin Li linear = ToLinearIec61966(v_float);
346*b2055c35SXin Li break;
347*b2055c35SXin Li case kSharpYuvTransferFunctionBt1361:
348*b2055c35SXin Li linear = ToLinearBt1361(v_float);
349*b2055c35SXin Li break;
350*b2055c35SXin Li case kSharpYuvTransferFunctionSmpte2084:
351*b2055c35SXin Li linear = ToLinearPq(v_float);
352*b2055c35SXin Li break;
353*b2055c35SXin Li case kSharpYuvTransferFunctionSmpte428:
354*b2055c35SXin Li linear = ToLinearSmpte428(v_float);
355*b2055c35SXin Li break;
356*b2055c35SXin Li case kSharpYuvTransferFunctionHlg:
357*b2055c35SXin Li linear = ToLinearHlg(v_float);
358*b2055c35SXin Li break;
359*b2055c35SXin Li default:
360*b2055c35SXin Li assert(0);
361*b2055c35SXin Li linear = 0;
362*b2055c35SXin Li break;
363*b2055c35SXin Li }
364*b2055c35SXin Li return (uint32_t)Roundf(linear * ((1 << 16) - 1));
365*b2055c35SXin Li }
366*b2055c35SXin Li
SharpYuvLinearToGamma(uint32_t v,int bit_depth,SharpYuvTransferFunctionType transfer_type)367*b2055c35SXin Li uint16_t SharpYuvLinearToGamma(uint32_t v, int bit_depth,
368*b2055c35SXin Li SharpYuvTransferFunctionType transfer_type) {
369*b2055c35SXin Li float v_float, linear;
370*b2055c35SXin Li if (transfer_type == kSharpYuvTransferFunctionSrgb) {
371*b2055c35SXin Li return FromLinearSrgb(v, bit_depth);
372*b2055c35SXin Li }
373*b2055c35SXin Li v_float = (float)v / ((1 << 16) - 1);
374*b2055c35SXin Li switch (transfer_type) {
375*b2055c35SXin Li case kSharpYuvTransferFunctionBt709:
376*b2055c35SXin Li case kSharpYuvTransferFunctionBt601:
377*b2055c35SXin Li case kSharpYuvTransferFunctionBt2020_10Bit:
378*b2055c35SXin Li case kSharpYuvTransferFunctionBt2020_12Bit:
379*b2055c35SXin Li linear = FromLinear709(v_float);
380*b2055c35SXin Li break;
381*b2055c35SXin Li case kSharpYuvTransferFunctionBt470M:
382*b2055c35SXin Li linear = FromLinear470M(v_float);
383*b2055c35SXin Li break;
384*b2055c35SXin Li case kSharpYuvTransferFunctionBt470Bg:
385*b2055c35SXin Li linear = FromLinear470Bg(v_float);
386*b2055c35SXin Li break;
387*b2055c35SXin Li case kSharpYuvTransferFunctionSmpte240:
388*b2055c35SXin Li linear = FromLinearSmpte240(v_float);
389*b2055c35SXin Li break;
390*b2055c35SXin Li case kSharpYuvTransferFunctionLinear:
391*b2055c35SXin Li return v;
392*b2055c35SXin Li case kSharpYuvTransferFunctionLog100:
393*b2055c35SXin Li linear = FromLinearLog100(v_float);
394*b2055c35SXin Li break;
395*b2055c35SXin Li case kSharpYuvTransferFunctionLog100_Sqrt10:
396*b2055c35SXin Li linear = FromLinearLog100Sqrt10(v_float);
397*b2055c35SXin Li break;
398*b2055c35SXin Li case kSharpYuvTransferFunctionIec61966:
399*b2055c35SXin Li linear = FromLinearIec61966(v_float);
400*b2055c35SXin Li break;
401*b2055c35SXin Li case kSharpYuvTransferFunctionBt1361:
402*b2055c35SXin Li linear = FromLinearBt1361(v_float);
403*b2055c35SXin Li break;
404*b2055c35SXin Li case kSharpYuvTransferFunctionSmpte2084:
405*b2055c35SXin Li linear = FromLinearPq(v_float);
406*b2055c35SXin Li break;
407*b2055c35SXin Li case kSharpYuvTransferFunctionSmpte428:
408*b2055c35SXin Li linear = FromLinearSmpte428(v_float);
409*b2055c35SXin Li break;
410*b2055c35SXin Li case kSharpYuvTransferFunctionHlg:
411*b2055c35SXin Li linear = FromLinearHlg(v_float);
412*b2055c35SXin Li break;
413*b2055c35SXin Li default:
414*b2055c35SXin Li assert(0);
415*b2055c35SXin Li linear = 0;
416*b2055c35SXin Li break;
417*b2055c35SXin Li }
418*b2055c35SXin Li return (uint16_t)Roundf(linear * ((1 << bit_depth) - 1));
419*b2055c35SXin Li }
420