xref: /aosp_15_r20/external/webp/sharpyuv/sharpyuv_gamma.c (revision b2055c353e87c8814eb2b6b1b11112a1562253bd)
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