1*89a0ef05SAndroid Build Coastguard Worker /*
2*89a0ef05SAndroid Build Coastguard Worker * Copyright 2022 The Android Open Source Project
3*89a0ef05SAndroid Build Coastguard Worker *
4*89a0ef05SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*89a0ef05SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*89a0ef05SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*89a0ef05SAndroid Build Coastguard Worker *
8*89a0ef05SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*89a0ef05SAndroid Build Coastguard Worker *
10*89a0ef05SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*89a0ef05SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*89a0ef05SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*89a0ef05SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*89a0ef05SAndroid Build Coastguard Worker * limitations under the License.
15*89a0ef05SAndroid Build Coastguard Worker */
16*89a0ef05SAndroid Build Coastguard Worker
17*89a0ef05SAndroid Build Coastguard Worker #ifndef ULTRAHDR_GAINMAPMATH_H
18*89a0ef05SAndroid Build Coastguard Worker #define ULTRAHDR_GAINMAPMATH_H
19*89a0ef05SAndroid Build Coastguard Worker
20*89a0ef05SAndroid Build Coastguard Worker #include <array>
21*89a0ef05SAndroid Build Coastguard Worker #include <cmath>
22*89a0ef05SAndroid Build Coastguard Worker #include <cstring>
23*89a0ef05SAndroid Build Coastguard Worker #include <functional>
24*89a0ef05SAndroid Build Coastguard Worker
25*89a0ef05SAndroid Build Coastguard Worker #include "ultrahdr_api.h"
26*89a0ef05SAndroid Build Coastguard Worker #include "ultrahdr/ultrahdrcommon.h"
27*89a0ef05SAndroid Build Coastguard Worker #include "ultrahdr/jpegr.h"
28*89a0ef05SAndroid Build Coastguard Worker
29*89a0ef05SAndroid Build Coastguard Worker #if (defined(UHDR_ENABLE_INTRINSICS) && (defined(__ARM_NEON__) || defined(__ARM_NEON)))
30*89a0ef05SAndroid Build Coastguard Worker #include <arm_neon.h>
31*89a0ef05SAndroid Build Coastguard Worker #endif
32*89a0ef05SAndroid Build Coastguard Worker
33*89a0ef05SAndroid Build Coastguard Worker #define USE_SRGB_INVOETF_LUT 1
34*89a0ef05SAndroid Build Coastguard Worker #define USE_HLG_OETF_LUT 1
35*89a0ef05SAndroid Build Coastguard Worker #define USE_PQ_OETF_LUT 1
36*89a0ef05SAndroid Build Coastguard Worker #define USE_HLG_INVOETF_LUT 1
37*89a0ef05SAndroid Build Coastguard Worker #define USE_PQ_INVOETF_LUT 1
38*89a0ef05SAndroid Build Coastguard Worker #define USE_APPLY_GAIN_LUT 1
39*89a0ef05SAndroid Build Coastguard Worker
40*89a0ef05SAndroid Build Coastguard Worker #define CLIP3(x, min, max) ((x) < (min)) ? (min) : ((x) > (max)) ? (max) : (x)
41*89a0ef05SAndroid Build Coastguard Worker
42*89a0ef05SAndroid Build Coastguard Worker namespace ultrahdr {
43*89a0ef05SAndroid Build Coastguard Worker
44*89a0ef05SAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////
45*89a0ef05SAndroid Build Coastguard Worker // Framework
46*89a0ef05SAndroid Build Coastguard Worker
47*89a0ef05SAndroid Build Coastguard Worker // nominal {SDR, HLG, PQ} peak display luminance
48*89a0ef05SAndroid Build Coastguard Worker // This aligns with the suggested default reference diffuse white from ISO/TS 22028-5
49*89a0ef05SAndroid Build Coastguard Worker // sdr white
50*89a0ef05SAndroid Build Coastguard Worker static const float kSdrWhiteNits = 203.0f;
51*89a0ef05SAndroid Build Coastguard Worker // hlg peak white. 75% of hlg peak white maps to reference diffuse white
52*89a0ef05SAndroid Build Coastguard Worker static const float kHlgMaxNits = 1000.0f;
53*89a0ef05SAndroid Build Coastguard Worker // pq peak white. 58% of pq peak white maps to reference diffuse white
54*89a0ef05SAndroid Build Coastguard Worker static const float kPqMaxNits = 10000.0f;
55*89a0ef05SAndroid Build Coastguard Worker
56*89a0ef05SAndroid Build Coastguard Worker float getReferenceDisplayPeakLuminanceInNits(uhdr_color_transfer_t transfer);
57*89a0ef05SAndroid Build Coastguard Worker
58*89a0ef05SAndroid Build Coastguard Worker // Image pixel descriptor
59*89a0ef05SAndroid Build Coastguard Worker struct Color {
60*89a0ef05SAndroid Build Coastguard Worker union {
61*89a0ef05SAndroid Build Coastguard Worker struct {
62*89a0ef05SAndroid Build Coastguard Worker float r;
63*89a0ef05SAndroid Build Coastguard Worker float g;
64*89a0ef05SAndroid Build Coastguard Worker float b;
65*89a0ef05SAndroid Build Coastguard Worker };
66*89a0ef05SAndroid Build Coastguard Worker struct {
67*89a0ef05SAndroid Build Coastguard Worker float y;
68*89a0ef05SAndroid Build Coastguard Worker float u;
69*89a0ef05SAndroid Build Coastguard Worker float v;
70*89a0ef05SAndroid Build Coastguard Worker };
71*89a0ef05SAndroid Build Coastguard Worker };
72*89a0ef05SAndroid Build Coastguard Worker };
73*89a0ef05SAndroid Build Coastguard Worker
74*89a0ef05SAndroid Build Coastguard Worker typedef Color (*ColorTransformFn)(Color);
75*89a0ef05SAndroid Build Coastguard Worker typedef float (*LuminanceFn)(Color);
76*89a0ef05SAndroid Build Coastguard Worker typedef Color (*SceneToDisplayLuminanceFn)(Color, LuminanceFn);
77*89a0ef05SAndroid Build Coastguard Worker typedef Color (*GetPixelFn)(uhdr_raw_image_t*, size_t, size_t);
78*89a0ef05SAndroid Build Coastguard Worker typedef Color (*SamplePixelFn)(uhdr_raw_image_t*, size_t, size_t, size_t);
79*89a0ef05SAndroid Build Coastguard Worker typedef void (*PutPixelFn)(uhdr_raw_image_t*, size_t, size_t, Color&);
80*89a0ef05SAndroid Build Coastguard Worker
81*89a0ef05SAndroid Build Coastguard Worker inline Color operator+=(Color& lhs, const Color& rhs) {
82*89a0ef05SAndroid Build Coastguard Worker lhs.r += rhs.r;
83*89a0ef05SAndroid Build Coastguard Worker lhs.g += rhs.g;
84*89a0ef05SAndroid Build Coastguard Worker lhs.b += rhs.b;
85*89a0ef05SAndroid Build Coastguard Worker return lhs;
86*89a0ef05SAndroid Build Coastguard Worker }
87*89a0ef05SAndroid Build Coastguard Worker
88*89a0ef05SAndroid Build Coastguard Worker inline Color operator-=(Color& lhs, const Color& rhs) {
89*89a0ef05SAndroid Build Coastguard Worker lhs.r -= rhs.r;
90*89a0ef05SAndroid Build Coastguard Worker lhs.g -= rhs.g;
91*89a0ef05SAndroid Build Coastguard Worker lhs.b -= rhs.b;
92*89a0ef05SAndroid Build Coastguard Worker return lhs;
93*89a0ef05SAndroid Build Coastguard Worker }
94*89a0ef05SAndroid Build Coastguard Worker
95*89a0ef05SAndroid Build Coastguard Worker inline Color operator+(const Color& lhs, const Color& rhs) {
96*89a0ef05SAndroid Build Coastguard Worker Color temp = lhs;
97*89a0ef05SAndroid Build Coastguard Worker return temp += rhs;
98*89a0ef05SAndroid Build Coastguard Worker }
99*89a0ef05SAndroid Build Coastguard Worker
100*89a0ef05SAndroid Build Coastguard Worker inline Color operator-(const Color& lhs, const Color& rhs) {
101*89a0ef05SAndroid Build Coastguard Worker Color temp = lhs;
102*89a0ef05SAndroid Build Coastguard Worker return temp -= rhs;
103*89a0ef05SAndroid Build Coastguard Worker }
104*89a0ef05SAndroid Build Coastguard Worker
105*89a0ef05SAndroid Build Coastguard Worker inline Color operator+=(Color& lhs, const float rhs) {
106*89a0ef05SAndroid Build Coastguard Worker lhs.r += rhs;
107*89a0ef05SAndroid Build Coastguard Worker lhs.g += rhs;
108*89a0ef05SAndroid Build Coastguard Worker lhs.b += rhs;
109*89a0ef05SAndroid Build Coastguard Worker return lhs;
110*89a0ef05SAndroid Build Coastguard Worker }
111*89a0ef05SAndroid Build Coastguard Worker
112*89a0ef05SAndroid Build Coastguard Worker inline Color operator-=(Color& lhs, const float rhs) {
113*89a0ef05SAndroid Build Coastguard Worker lhs.r -= rhs;
114*89a0ef05SAndroid Build Coastguard Worker lhs.g -= rhs;
115*89a0ef05SAndroid Build Coastguard Worker lhs.b -= rhs;
116*89a0ef05SAndroid Build Coastguard Worker return lhs;
117*89a0ef05SAndroid Build Coastguard Worker }
118*89a0ef05SAndroid Build Coastguard Worker
119*89a0ef05SAndroid Build Coastguard Worker inline Color operator*=(Color& lhs, const float rhs) {
120*89a0ef05SAndroid Build Coastguard Worker lhs.r *= rhs;
121*89a0ef05SAndroid Build Coastguard Worker lhs.g *= rhs;
122*89a0ef05SAndroid Build Coastguard Worker lhs.b *= rhs;
123*89a0ef05SAndroid Build Coastguard Worker return lhs;
124*89a0ef05SAndroid Build Coastguard Worker }
125*89a0ef05SAndroid Build Coastguard Worker
126*89a0ef05SAndroid Build Coastguard Worker inline Color operator/=(Color& lhs, const float rhs) {
127*89a0ef05SAndroid Build Coastguard Worker lhs.r /= rhs;
128*89a0ef05SAndroid Build Coastguard Worker lhs.g /= rhs;
129*89a0ef05SAndroid Build Coastguard Worker lhs.b /= rhs;
130*89a0ef05SAndroid Build Coastguard Worker return lhs;
131*89a0ef05SAndroid Build Coastguard Worker }
132*89a0ef05SAndroid Build Coastguard Worker
133*89a0ef05SAndroid Build Coastguard Worker inline Color operator+(const Color& lhs, const float rhs) {
134*89a0ef05SAndroid Build Coastguard Worker Color temp = lhs;
135*89a0ef05SAndroid Build Coastguard Worker return temp += rhs;
136*89a0ef05SAndroid Build Coastguard Worker }
137*89a0ef05SAndroid Build Coastguard Worker
138*89a0ef05SAndroid Build Coastguard Worker inline Color operator-(const Color& lhs, const float rhs) {
139*89a0ef05SAndroid Build Coastguard Worker Color temp = lhs;
140*89a0ef05SAndroid Build Coastguard Worker return temp -= rhs;
141*89a0ef05SAndroid Build Coastguard Worker }
142*89a0ef05SAndroid Build Coastguard Worker
143*89a0ef05SAndroid Build Coastguard Worker inline Color operator*(const Color& lhs, const float rhs) {
144*89a0ef05SAndroid Build Coastguard Worker Color temp = lhs;
145*89a0ef05SAndroid Build Coastguard Worker return temp *= rhs;
146*89a0ef05SAndroid Build Coastguard Worker }
147*89a0ef05SAndroid Build Coastguard Worker
148*89a0ef05SAndroid Build Coastguard Worker inline Color operator/(const Color& lhs, const float rhs) {
149*89a0ef05SAndroid Build Coastguard Worker Color temp = lhs;
150*89a0ef05SAndroid Build Coastguard Worker return temp /= rhs;
151*89a0ef05SAndroid Build Coastguard Worker }
152*89a0ef05SAndroid Build Coastguard Worker
153*89a0ef05SAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////
154*89a0ef05SAndroid Build Coastguard Worker // Float to Half and Half to Float conversions
155*89a0ef05SAndroid Build Coastguard Worker union FloatUIntUnion {
156*89a0ef05SAndroid Build Coastguard Worker uint32_t mUInt;
157*89a0ef05SAndroid Build Coastguard Worker float mFloat;
158*89a0ef05SAndroid Build Coastguard Worker };
159*89a0ef05SAndroid Build Coastguard Worker
160*89a0ef05SAndroid Build Coastguard Worker // FIXME: The shift operations in this function are causing UBSAN (Undefined-shift) errors
161*89a0ef05SAndroid Build Coastguard Worker // Precisely,
162*89a0ef05SAndroid Build Coastguard Worker // runtime error: left shift of negative value -112
163*89a0ef05SAndroid Build Coastguard Worker // runtime error : shift exponent 125 is too large for 32 - bit type 'uint32_t'(aka 'unsigned int')
164*89a0ef05SAndroid Build Coastguard Worker // These need to be addressed. Until then, disable ubsan analysis for this function
165*89a0ef05SAndroid Build Coastguard Worker UHDR_NO_SANITIZE_UNDEFINED
floatToHalf(float f)166*89a0ef05SAndroid Build Coastguard Worker inline uint16_t floatToHalf(float f) {
167*89a0ef05SAndroid Build Coastguard Worker FloatUIntUnion floatUnion;
168*89a0ef05SAndroid Build Coastguard Worker floatUnion.mFloat = f;
169*89a0ef05SAndroid Build Coastguard Worker // round-to-nearest-even: add last bit after truncated mantissa
170*89a0ef05SAndroid Build Coastguard Worker const uint32_t b = floatUnion.mUInt + 0x00001000;
171*89a0ef05SAndroid Build Coastguard Worker
172*89a0ef05SAndroid Build Coastguard Worker const int32_t e = (b & 0x7F800000) >> 23; // exponent
173*89a0ef05SAndroid Build Coastguard Worker const uint32_t m = b & 0x007FFFFF; // mantissa
174*89a0ef05SAndroid Build Coastguard Worker
175*89a0ef05SAndroid Build Coastguard Worker // sign : normalized : denormalized : saturate
176*89a0ef05SAndroid Build Coastguard Worker return (b & 0x80000000) >> 16 | (e > 112) * ((((e - 112) << 10) & 0x7C00) | m >> 13) |
177*89a0ef05SAndroid Build Coastguard Worker ((e < 113) & (e > 101)) * ((((0x007FF000 + m) >> (125 - e)) + 1) >> 1) |
178*89a0ef05SAndroid Build Coastguard Worker (e > 143) * 0x7FFF;
179*89a0ef05SAndroid Build Coastguard Worker }
180*89a0ef05SAndroid Build Coastguard Worker
181*89a0ef05SAndroid Build Coastguard Worker // Taken from frameworks/base/libs/hwui/jni/android_graphics_ColorSpace.cpp
182*89a0ef05SAndroid Build Coastguard Worker
183*89a0ef05SAndroid Build Coastguard Worker #if defined(__ANDROID__) // __fp16 is not defined on non-Android builds
halfToFloat(uint16_t bits)184*89a0ef05SAndroid Build Coastguard Worker inline float halfToFloat(uint16_t bits) {
185*89a0ef05SAndroid Build Coastguard Worker __fp16 h;
186*89a0ef05SAndroid Build Coastguard Worker memcpy(&h, &bits, 2);
187*89a0ef05SAndroid Build Coastguard Worker return (float)h;
188*89a0ef05SAndroid Build Coastguard Worker }
189*89a0ef05SAndroid Build Coastguard Worker #else
190*89a0ef05SAndroid Build Coastguard Worker // This is Skia's implementation of SkHalfToFloat, which is
191*89a0ef05SAndroid Build Coastguard Worker // based on Fabien Giesen's half_to_float_fast2()
192*89a0ef05SAndroid Build Coastguard Worker // see https://fgiesen.wordpress.com/2012/03/28/half-to-float-done-quic/
halfMantissa(uint16_t h)193*89a0ef05SAndroid Build Coastguard Worker inline uint16_t halfMantissa(uint16_t h) { return h & 0x03ff; }
194*89a0ef05SAndroid Build Coastguard Worker
halfExponent(uint16_t h)195*89a0ef05SAndroid Build Coastguard Worker inline uint16_t halfExponent(uint16_t h) { return (h >> 10) & 0x001f; }
196*89a0ef05SAndroid Build Coastguard Worker
halfSign(uint16_t h)197*89a0ef05SAndroid Build Coastguard Worker inline uint16_t halfSign(uint16_t h) { return h >> 15; }
198*89a0ef05SAndroid Build Coastguard Worker
halfToFloat(uint16_t bits)199*89a0ef05SAndroid Build Coastguard Worker inline float halfToFloat(uint16_t bits) {
200*89a0ef05SAndroid Build Coastguard Worker static const FloatUIntUnion magic = {126 << 23};
201*89a0ef05SAndroid Build Coastguard Worker FloatUIntUnion o;
202*89a0ef05SAndroid Build Coastguard Worker
203*89a0ef05SAndroid Build Coastguard Worker if (halfExponent(bits) == 0) {
204*89a0ef05SAndroid Build Coastguard Worker // Zero / Denormal
205*89a0ef05SAndroid Build Coastguard Worker o.mUInt = magic.mUInt + halfMantissa(bits);
206*89a0ef05SAndroid Build Coastguard Worker o.mFloat -= magic.mFloat;
207*89a0ef05SAndroid Build Coastguard Worker } else {
208*89a0ef05SAndroid Build Coastguard Worker // Set mantissa
209*89a0ef05SAndroid Build Coastguard Worker o.mUInt = halfMantissa(bits) << 13;
210*89a0ef05SAndroid Build Coastguard Worker // Set exponent
211*89a0ef05SAndroid Build Coastguard Worker if (halfExponent(bits) == 0x1f) {
212*89a0ef05SAndroid Build Coastguard Worker // Inf/NaN
213*89a0ef05SAndroid Build Coastguard Worker o.mUInt |= (255 << 23);
214*89a0ef05SAndroid Build Coastguard Worker } else {
215*89a0ef05SAndroid Build Coastguard Worker o.mUInt |= ((127 - 15 + halfExponent(bits)) << 23);
216*89a0ef05SAndroid Build Coastguard Worker }
217*89a0ef05SAndroid Build Coastguard Worker }
218*89a0ef05SAndroid Build Coastguard Worker
219*89a0ef05SAndroid Build Coastguard Worker // Set sign
220*89a0ef05SAndroid Build Coastguard Worker o.mUInt |= (halfSign(bits) << 31);
221*89a0ef05SAndroid Build Coastguard Worker return o.mFloat;
222*89a0ef05SAndroid Build Coastguard Worker }
223*89a0ef05SAndroid Build Coastguard Worker #endif // defined(__ANDROID__)
224*89a0ef05SAndroid Build Coastguard Worker
225*89a0ef05SAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////
226*89a0ef05SAndroid Build Coastguard Worker // Use Shepard's method for inverse distance weighting. For more information:
227*89a0ef05SAndroid Build Coastguard Worker // en.wikipedia.org/wiki/Inverse_distance_weighting#Shepard's_method
228*89a0ef05SAndroid Build Coastguard Worker struct ShepardsIDW {
ShepardsIDWShepardsIDW229*89a0ef05SAndroid Build Coastguard Worker ShepardsIDW(int mapScaleFactor) : mMapScaleFactor{mapScaleFactor} {
230*89a0ef05SAndroid Build Coastguard Worker const int size = mMapScaleFactor * mMapScaleFactor * 4;
231*89a0ef05SAndroid Build Coastguard Worker mWeights = new float[size];
232*89a0ef05SAndroid Build Coastguard Worker mWeightsNR = new float[size];
233*89a0ef05SAndroid Build Coastguard Worker mWeightsNB = new float[size];
234*89a0ef05SAndroid Build Coastguard Worker mWeightsC = new float[size];
235*89a0ef05SAndroid Build Coastguard Worker fillShepardsIDW(mWeights, 1, 1);
236*89a0ef05SAndroid Build Coastguard Worker fillShepardsIDW(mWeightsNR, 0, 1);
237*89a0ef05SAndroid Build Coastguard Worker fillShepardsIDW(mWeightsNB, 1, 0);
238*89a0ef05SAndroid Build Coastguard Worker fillShepardsIDW(mWeightsC, 0, 0);
239*89a0ef05SAndroid Build Coastguard Worker }
240*89a0ef05SAndroid Build Coastguard Worker
~ShepardsIDWShepardsIDW241*89a0ef05SAndroid Build Coastguard Worker ~ShepardsIDW() {
242*89a0ef05SAndroid Build Coastguard Worker delete[] mWeights;
243*89a0ef05SAndroid Build Coastguard Worker delete[] mWeightsNR;
244*89a0ef05SAndroid Build Coastguard Worker delete[] mWeightsNB;
245*89a0ef05SAndroid Build Coastguard Worker delete[] mWeightsC;
246*89a0ef05SAndroid Build Coastguard Worker }
247*89a0ef05SAndroid Build Coastguard Worker
248*89a0ef05SAndroid Build Coastguard Worker int mMapScaleFactor;
249*89a0ef05SAndroid Build Coastguard Worker // curr, right, bottom, bottom-right are used during interpolation. hence table weight size is 4.
250*89a0ef05SAndroid Build Coastguard Worker float* mWeights; // default
251*89a0ef05SAndroid Build Coastguard Worker float* mWeightsNR; // no right
252*89a0ef05SAndroid Build Coastguard Worker float* mWeightsNB; // no bottom
253*89a0ef05SAndroid Build Coastguard Worker float* mWeightsC; // no right & bottom
254*89a0ef05SAndroid Build Coastguard Worker
255*89a0ef05SAndroid Build Coastguard Worker float euclideanDistance(float x1, float x2, float y1, float y2);
256*89a0ef05SAndroid Build Coastguard Worker void fillShepardsIDW(float* weights, int incR, int incB);
257*89a0ef05SAndroid Build Coastguard Worker };
258*89a0ef05SAndroid Build Coastguard Worker
259*89a0ef05SAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////
260*89a0ef05SAndroid Build Coastguard Worker // sRGB transformations.
261*89a0ef05SAndroid Build Coastguard Worker // for all functions range in and out [0.0, 1.0]
262*89a0ef05SAndroid Build Coastguard Worker
263*89a0ef05SAndroid Build Coastguard Worker // sRGB luminance
264*89a0ef05SAndroid Build Coastguard Worker float srgbLuminance(Color e);
265*89a0ef05SAndroid Build Coastguard Worker
266*89a0ef05SAndroid Build Coastguard Worker // sRGB rgb <-> yuv conversion
267*89a0ef05SAndroid Build Coastguard Worker Color srgbRgbToYuv(Color e_gamma);
268*89a0ef05SAndroid Build Coastguard Worker Color srgbYuvToRgb(Color e_gamma);
269*89a0ef05SAndroid Build Coastguard Worker
270*89a0ef05SAndroid Build Coastguard Worker // sRGB eotf
271*89a0ef05SAndroid Build Coastguard Worker float srgbInvOetf(float e_gamma);
272*89a0ef05SAndroid Build Coastguard Worker Color srgbInvOetf(Color e_gamma);
273*89a0ef05SAndroid Build Coastguard Worker float srgbInvOetfLUT(float e_gamma);
274*89a0ef05SAndroid Build Coastguard Worker Color srgbInvOetfLUT(Color e_gamma);
275*89a0ef05SAndroid Build Coastguard Worker
276*89a0ef05SAndroid Build Coastguard Worker // sRGB oetf
277*89a0ef05SAndroid Build Coastguard Worker float srgbOetf(float e);
278*89a0ef05SAndroid Build Coastguard Worker Color srgbOetf(Color e);
279*89a0ef05SAndroid Build Coastguard Worker
280*89a0ef05SAndroid Build Coastguard Worker constexpr int32_t kSrgbInvOETFPrecision = 10;
281*89a0ef05SAndroid Build Coastguard Worker constexpr int32_t kSrgbInvOETFNumEntries = 1 << kSrgbInvOETFPrecision;
282*89a0ef05SAndroid Build Coastguard Worker
283*89a0ef05SAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////
284*89a0ef05SAndroid Build Coastguard Worker // Display-P3 transformations
285*89a0ef05SAndroid Build Coastguard Worker // for all functions range in and out [0.0, 1.0]
286*89a0ef05SAndroid Build Coastguard Worker
287*89a0ef05SAndroid Build Coastguard Worker // DispP3 luminance
288*89a0ef05SAndroid Build Coastguard Worker float p3Luminance(Color e);
289*89a0ef05SAndroid Build Coastguard Worker
290*89a0ef05SAndroid Build Coastguard Worker // DispP3 rgb <-> yuv conversion
291*89a0ef05SAndroid Build Coastguard Worker Color p3RgbToYuv(Color e_gamma);
292*89a0ef05SAndroid Build Coastguard Worker Color p3YuvToRgb(Color e_gamma);
293*89a0ef05SAndroid Build Coastguard Worker
294*89a0ef05SAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////
295*89a0ef05SAndroid Build Coastguard Worker // BT.2100 transformations
296*89a0ef05SAndroid Build Coastguard Worker // for all functions range in and out [0.0, 1.0]
297*89a0ef05SAndroid Build Coastguard Worker
298*89a0ef05SAndroid Build Coastguard Worker // bt2100 luminance
299*89a0ef05SAndroid Build Coastguard Worker float bt2100Luminance(Color e);
300*89a0ef05SAndroid Build Coastguard Worker
301*89a0ef05SAndroid Build Coastguard Worker // bt2100 rgb <-> yuv conversion
302*89a0ef05SAndroid Build Coastguard Worker Color bt2100RgbToYuv(Color e_gamma);
303*89a0ef05SAndroid Build Coastguard Worker Color bt2100YuvToRgb(Color e_gamma);
304*89a0ef05SAndroid Build Coastguard Worker
305*89a0ef05SAndroid Build Coastguard Worker // hlg oetf (normalized)
306*89a0ef05SAndroid Build Coastguard Worker float hlgOetf(float e);
307*89a0ef05SAndroid Build Coastguard Worker Color hlgOetf(Color e);
308*89a0ef05SAndroid Build Coastguard Worker float hlgOetfLUT(float e);
309*89a0ef05SAndroid Build Coastguard Worker Color hlgOetfLUT(Color e);
310*89a0ef05SAndroid Build Coastguard Worker
311*89a0ef05SAndroid Build Coastguard Worker constexpr int32_t kHlgOETFPrecision = 16;
312*89a0ef05SAndroid Build Coastguard Worker constexpr int32_t kHlgOETFNumEntries = 1 << kHlgOETFPrecision;
313*89a0ef05SAndroid Build Coastguard Worker
314*89a0ef05SAndroid Build Coastguard Worker // hlg inverse oetf (normalized)
315*89a0ef05SAndroid Build Coastguard Worker float hlgInvOetf(float e_gamma);
316*89a0ef05SAndroid Build Coastguard Worker Color hlgInvOetf(Color e_gamma);
317*89a0ef05SAndroid Build Coastguard Worker float hlgInvOetfLUT(float e_gamma);
318*89a0ef05SAndroid Build Coastguard Worker Color hlgInvOetfLUT(Color e_gamma);
319*89a0ef05SAndroid Build Coastguard Worker
320*89a0ef05SAndroid Build Coastguard Worker constexpr int32_t kHlgInvOETFPrecision = 12;
321*89a0ef05SAndroid Build Coastguard Worker constexpr int32_t kHlgInvOETFNumEntries = 1 << kHlgInvOETFPrecision;
322*89a0ef05SAndroid Build Coastguard Worker
323*89a0ef05SAndroid Build Coastguard Worker // hlg ootf (normalized)
324*89a0ef05SAndroid Build Coastguard Worker Color hlgOotf(Color e, LuminanceFn luminance);
325*89a0ef05SAndroid Build Coastguard Worker Color hlgOotfApprox(Color e, [[maybe_unused]] LuminanceFn luminance);
identityOotf(Color e,LuminanceFn)326*89a0ef05SAndroid Build Coastguard Worker inline Color identityOotf(Color e, [[maybe_unused]] LuminanceFn) { return e; }
327*89a0ef05SAndroid Build Coastguard Worker
328*89a0ef05SAndroid Build Coastguard Worker // hlg inverse ootf (normalized)
329*89a0ef05SAndroid Build Coastguard Worker Color hlgInverseOotf(Color e, LuminanceFn luminance);
330*89a0ef05SAndroid Build Coastguard Worker Color hlgInverseOotfApprox(Color e);
331*89a0ef05SAndroid Build Coastguard Worker
332*89a0ef05SAndroid Build Coastguard Worker // pq oetf
333*89a0ef05SAndroid Build Coastguard Worker float pqOetf(float e);
334*89a0ef05SAndroid Build Coastguard Worker Color pqOetf(Color e);
335*89a0ef05SAndroid Build Coastguard Worker float pqOetfLUT(float e);
336*89a0ef05SAndroid Build Coastguard Worker Color pqOetfLUT(Color e);
337*89a0ef05SAndroid Build Coastguard Worker
338*89a0ef05SAndroid Build Coastguard Worker constexpr int32_t kPqOETFPrecision = 16;
339*89a0ef05SAndroid Build Coastguard Worker constexpr int32_t kPqOETFNumEntries = 1 << kPqOETFPrecision;
340*89a0ef05SAndroid Build Coastguard Worker
341*89a0ef05SAndroid Build Coastguard Worker // pq inverse oetf
342*89a0ef05SAndroid Build Coastguard Worker float pqInvOetf(float e_gamma);
343*89a0ef05SAndroid Build Coastguard Worker Color pqInvOetf(Color e_gamma);
344*89a0ef05SAndroid Build Coastguard Worker float pqInvOetfLUT(float e_gamma);
345*89a0ef05SAndroid Build Coastguard Worker Color pqInvOetfLUT(Color e_gamma);
346*89a0ef05SAndroid Build Coastguard Worker
347*89a0ef05SAndroid Build Coastguard Worker constexpr int32_t kPqInvOETFPrecision = 12;
348*89a0ef05SAndroid Build Coastguard Worker constexpr int32_t kPqInvOETFNumEntries = 1 << kPqInvOETFPrecision;
349*89a0ef05SAndroid Build Coastguard Worker
350*89a0ef05SAndroid Build Coastguard Worker // util class to prepare look up tables for oetf/eotf functions
351*89a0ef05SAndroid Build Coastguard Worker class LookUpTable {
352*89a0ef05SAndroid Build Coastguard Worker public:
LookUpTable(size_t numEntries,std::function<float (float)> computeFunc)353*89a0ef05SAndroid Build Coastguard Worker LookUpTable(size_t numEntries, std::function<float(float)> computeFunc) {
354*89a0ef05SAndroid Build Coastguard Worker for (size_t idx = 0; idx < numEntries; idx++) {
355*89a0ef05SAndroid Build Coastguard Worker float value = static_cast<float>(idx) / static_cast<float>(numEntries - 1);
356*89a0ef05SAndroid Build Coastguard Worker table.push_back(computeFunc(value));
357*89a0ef05SAndroid Build Coastguard Worker }
358*89a0ef05SAndroid Build Coastguard Worker }
getTable()359*89a0ef05SAndroid Build Coastguard Worker const std::vector<float>& getTable() const { return table; }
360*89a0ef05SAndroid Build Coastguard Worker
361*89a0ef05SAndroid Build Coastguard Worker private:
362*89a0ef05SAndroid Build Coastguard Worker std::vector<float> table;
363*89a0ef05SAndroid Build Coastguard Worker };
364*89a0ef05SAndroid Build Coastguard Worker
365*89a0ef05SAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////
366*89a0ef05SAndroid Build Coastguard Worker // Color access functions
367*89a0ef05SAndroid Build Coastguard Worker
368*89a0ef05SAndroid Build Coastguard Worker // Get pixel from the image at the provided location.
369*89a0ef05SAndroid Build Coastguard Worker Color getYuv444Pixel(uhdr_raw_image_t* image, size_t x, size_t y);
370*89a0ef05SAndroid Build Coastguard Worker Color getYuv422Pixel(uhdr_raw_image_t* image, size_t x, size_t y);
371*89a0ef05SAndroid Build Coastguard Worker Color getYuv420Pixel(uhdr_raw_image_t* image, size_t x, size_t y);
372*89a0ef05SAndroid Build Coastguard Worker Color getYuv400Pixel(uhdr_raw_image_t* image, size_t x, size_t y);
373*89a0ef05SAndroid Build Coastguard Worker Color getP010Pixel(uhdr_raw_image_t* image, size_t x, size_t y);
374*89a0ef05SAndroid Build Coastguard Worker Color getYuv444Pixel10bit(uhdr_raw_image_t* image, size_t x, size_t y);
375*89a0ef05SAndroid Build Coastguard Worker Color getRgb888Pixel(uhdr_raw_image_t* image, size_t x, size_t y);
376*89a0ef05SAndroid Build Coastguard Worker Color getRgba8888Pixel(uhdr_raw_image_t* image, size_t x, size_t y);
377*89a0ef05SAndroid Build Coastguard Worker Color getRgba1010102Pixel(uhdr_raw_image_t* image, size_t x, size_t y);
378*89a0ef05SAndroid Build Coastguard Worker Color getRgbaF16Pixel(uhdr_raw_image_t* image, size_t x, size_t y);
379*89a0ef05SAndroid Build Coastguard Worker
380*89a0ef05SAndroid Build Coastguard Worker // Sample the image at the provided location, with a weighting based on nearby pixels and the map
381*89a0ef05SAndroid Build Coastguard Worker // scale factor.
382*89a0ef05SAndroid Build Coastguard Worker Color sampleYuv444(uhdr_raw_image_t* map, size_t map_scale_factor, size_t x, size_t y);
383*89a0ef05SAndroid Build Coastguard Worker Color sampleYuv422(uhdr_raw_image_t* map, size_t map_scale_factor, size_t x, size_t y);
384*89a0ef05SAndroid Build Coastguard Worker Color sampleYuv420(uhdr_raw_image_t* map, size_t map_scale_factor, size_t x, size_t y);
385*89a0ef05SAndroid Build Coastguard Worker Color sampleP010(uhdr_raw_image_t* map, size_t map_scale_factor, size_t x, size_t y);
386*89a0ef05SAndroid Build Coastguard Worker Color sampleYuv44410bit(uhdr_raw_image_t* image, size_t map_scale_factor, size_t x, size_t y);
387*89a0ef05SAndroid Build Coastguard Worker Color sampleRgba8888(uhdr_raw_image_t* image, size_t map_scale_factor, size_t x, size_t y);
388*89a0ef05SAndroid Build Coastguard Worker Color sampleRgba1010102(uhdr_raw_image_t* image, size_t map_scale_factor, size_t x, size_t y);
389*89a0ef05SAndroid Build Coastguard Worker Color sampleRgbaF16(uhdr_raw_image_t* image, size_t map_scale_factor, size_t x, size_t y);
390*89a0ef05SAndroid Build Coastguard Worker
391*89a0ef05SAndroid Build Coastguard Worker // Put pixel in the image at the provided location.
392*89a0ef05SAndroid Build Coastguard Worker void putRgba8888Pixel(uhdr_raw_image_t* image, size_t x, size_t y, Color& pixel);
393*89a0ef05SAndroid Build Coastguard Worker void putRgb888Pixel(uhdr_raw_image_t* image, size_t x, size_t y, Color& pixel);
394*89a0ef05SAndroid Build Coastguard Worker void putYuv400Pixel(uhdr_raw_image_t* image, size_t x, size_t y, Color& pixel);
395*89a0ef05SAndroid Build Coastguard Worker void putYuv444Pixel(uhdr_raw_image_t* image, size_t x, size_t y, Color& pixel);
396*89a0ef05SAndroid Build Coastguard Worker
397*89a0ef05SAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////
398*89a0ef05SAndroid Build Coastguard Worker // Color space conversions
399*89a0ef05SAndroid Build Coastguard Worker
400*89a0ef05SAndroid Build Coastguard Worker // color gamut conversion (rgb) functions
identityConversion(Color e)401*89a0ef05SAndroid Build Coastguard Worker inline Color identityConversion(Color e) { return e; }
402*89a0ef05SAndroid Build Coastguard Worker Color bt709ToP3(Color e);
403*89a0ef05SAndroid Build Coastguard Worker Color bt709ToBt2100(Color e);
404*89a0ef05SAndroid Build Coastguard Worker Color p3ToBt709(Color e);
405*89a0ef05SAndroid Build Coastguard Worker Color p3ToBt2100(Color e);
406*89a0ef05SAndroid Build Coastguard Worker Color bt2100ToBt709(Color e);
407*89a0ef05SAndroid Build Coastguard Worker Color bt2100ToP3(Color e);
408*89a0ef05SAndroid Build Coastguard Worker
409*89a0ef05SAndroid Build Coastguard Worker // convert between yuv encodings
410*89a0ef05SAndroid Build Coastguard Worker extern const std::array<float, 9> kYuvBt709ToBt601;
411*89a0ef05SAndroid Build Coastguard Worker extern const std::array<float, 9> kYuvBt709ToBt2100;
412*89a0ef05SAndroid Build Coastguard Worker extern const std::array<float, 9> kYuvBt601ToBt709;
413*89a0ef05SAndroid Build Coastguard Worker extern const std::array<float, 9> kYuvBt601ToBt2100;
414*89a0ef05SAndroid Build Coastguard Worker extern const std::array<float, 9> kYuvBt2100ToBt709;
415*89a0ef05SAndroid Build Coastguard Worker extern const std::array<float, 9> kYuvBt2100ToBt601;
416*89a0ef05SAndroid Build Coastguard Worker
417*89a0ef05SAndroid Build Coastguard Worker #if (defined(UHDR_ENABLE_INTRINSICS) && (defined(__ARM_NEON__) || defined(__ARM_NEON)))
418*89a0ef05SAndroid Build Coastguard Worker
419*89a0ef05SAndroid Build Coastguard Worker extern const int16_t kYuv709To601_coeffs_neon[8];
420*89a0ef05SAndroid Build Coastguard Worker extern const int16_t kYuv709To2100_coeffs_neon[8];
421*89a0ef05SAndroid Build Coastguard Worker extern const int16_t kYuv601To709_coeffs_neon[8];
422*89a0ef05SAndroid Build Coastguard Worker extern const int16_t kYuv601To2100_coeffs_neon[8];
423*89a0ef05SAndroid Build Coastguard Worker extern const int16_t kYuv2100To709_coeffs_neon[8];
424*89a0ef05SAndroid Build Coastguard Worker extern const int16_t kYuv2100To601_coeffs_neon[8];
425*89a0ef05SAndroid Build Coastguard Worker
426*89a0ef05SAndroid Build Coastguard Worker /*
427*89a0ef05SAndroid Build Coastguard Worker * The Y values are provided at half the width of U & V values to allow use of the widening
428*89a0ef05SAndroid Build Coastguard Worker * arithmetic instructions.
429*89a0ef05SAndroid Build Coastguard Worker */
430*89a0ef05SAndroid Build Coastguard Worker int16x8x3_t yuvConversion_neon(uint8x8_t y, int16x8_t u, int16x8_t v, int16x8_t coeffs);
431*89a0ef05SAndroid Build Coastguard Worker
432*89a0ef05SAndroid Build Coastguard Worker void transformYuv420_neon(uhdr_raw_image_t* image, const int16_t* coeffs_ptr);
433*89a0ef05SAndroid Build Coastguard Worker
434*89a0ef05SAndroid Build Coastguard Worker void transformYuv444_neon(uhdr_raw_image_t* image, const int16_t* coeffs_ptr);
435*89a0ef05SAndroid Build Coastguard Worker
436*89a0ef05SAndroid Build Coastguard Worker uhdr_error_info_t convertYuv_neon(uhdr_raw_image_t* image, uhdr_color_gamut_t src_encoding,
437*89a0ef05SAndroid Build Coastguard Worker uhdr_color_gamut_t dst_encoding);
438*89a0ef05SAndroid Build Coastguard Worker #endif
439*89a0ef05SAndroid Build Coastguard Worker
440*89a0ef05SAndroid Build Coastguard Worker // Performs a color gamut transformation on an yuv image.
441*89a0ef05SAndroid Build Coastguard Worker Color yuvColorGamutConversion(Color e_gamma, const std::array<float, 9>& coeffs);
442*89a0ef05SAndroid Build Coastguard Worker void transformYuv420(uhdr_raw_image_t* image, const std::array<float, 9>& coeffs);
443*89a0ef05SAndroid Build Coastguard Worker void transformYuv444(uhdr_raw_image_t* image, const std::array<float, 9>& coeffs);
444*89a0ef05SAndroid Build Coastguard Worker
445*89a0ef05SAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////
446*89a0ef05SAndroid Build Coastguard Worker // Gain map calculations
447*89a0ef05SAndroid Build Coastguard Worker
448*89a0ef05SAndroid Build Coastguard Worker constexpr int32_t kGainFactorPrecision = 10;
449*89a0ef05SAndroid Build Coastguard Worker constexpr int32_t kGainFactorNumEntries = 1 << kGainFactorPrecision;
450*89a0ef05SAndroid Build Coastguard Worker
451*89a0ef05SAndroid Build Coastguard Worker struct GainLUT {
GainLUTGainLUT452*89a0ef05SAndroid Build Coastguard Worker GainLUT(uhdr_gainmap_metadata_ext_t* metadata) {
453*89a0ef05SAndroid Build Coastguard Worker this->mGammaInv = 1.0f / metadata->gamma;
454*89a0ef05SAndroid Build Coastguard Worker for (int32_t idx = 0; idx < kGainFactorNumEntries; idx++) {
455*89a0ef05SAndroid Build Coastguard Worker float value = static_cast<float>(idx) / static_cast<float>(kGainFactorNumEntries - 1);
456*89a0ef05SAndroid Build Coastguard Worker float logBoost = log2(metadata->min_content_boost) * (1.0f - value) +
457*89a0ef05SAndroid Build Coastguard Worker log2(metadata->max_content_boost) * value;
458*89a0ef05SAndroid Build Coastguard Worker mGainTable[idx] = exp2(logBoost);
459*89a0ef05SAndroid Build Coastguard Worker }
460*89a0ef05SAndroid Build Coastguard Worker }
461*89a0ef05SAndroid Build Coastguard Worker
GainLUTGainLUT462*89a0ef05SAndroid Build Coastguard Worker GainLUT(uhdr_gainmap_metadata_ext_t* metadata, float gainmapWeight) {
463*89a0ef05SAndroid Build Coastguard Worker this->mGammaInv = 1.0f / metadata->gamma;
464*89a0ef05SAndroid Build Coastguard Worker for (int32_t idx = 0; idx < kGainFactorNumEntries; idx++) {
465*89a0ef05SAndroid Build Coastguard Worker float value = static_cast<float>(idx) / static_cast<float>(kGainFactorNumEntries - 1);
466*89a0ef05SAndroid Build Coastguard Worker float logBoost = log2(metadata->min_content_boost) * (1.0f - value) +
467*89a0ef05SAndroid Build Coastguard Worker log2(metadata->max_content_boost) * value;
468*89a0ef05SAndroid Build Coastguard Worker mGainTable[idx] = exp2(logBoost * gainmapWeight);
469*89a0ef05SAndroid Build Coastguard Worker }
470*89a0ef05SAndroid Build Coastguard Worker }
471*89a0ef05SAndroid Build Coastguard Worker
~GainLUTGainLUT472*89a0ef05SAndroid Build Coastguard Worker ~GainLUT() {}
473*89a0ef05SAndroid Build Coastguard Worker
getGainFactorGainLUT474*89a0ef05SAndroid Build Coastguard Worker float getGainFactor(float gain) {
475*89a0ef05SAndroid Build Coastguard Worker if (mGammaInv != 1.0f) gain = pow(gain, mGammaInv);
476*89a0ef05SAndroid Build Coastguard Worker int32_t idx = static_cast<int32_t>(gain * (kGainFactorNumEntries - 1) + 0.5);
477*89a0ef05SAndroid Build Coastguard Worker // TODO() : Remove once conversion modules have appropriate clamping in place
478*89a0ef05SAndroid Build Coastguard Worker idx = CLIP3(idx, 0, kGainFactorNumEntries - 1);
479*89a0ef05SAndroid Build Coastguard Worker return mGainTable[idx];
480*89a0ef05SAndroid Build Coastguard Worker }
481*89a0ef05SAndroid Build Coastguard Worker
482*89a0ef05SAndroid Build Coastguard Worker private:
483*89a0ef05SAndroid Build Coastguard Worker float mGainTable[kGainFactorNumEntries];
484*89a0ef05SAndroid Build Coastguard Worker float mGammaInv;
485*89a0ef05SAndroid Build Coastguard Worker };
486*89a0ef05SAndroid Build Coastguard Worker
487*89a0ef05SAndroid Build Coastguard Worker /*
488*89a0ef05SAndroid Build Coastguard Worker * Calculate the 8-bit unsigned integer gain value for the given SDR and HDR
489*89a0ef05SAndroid Build Coastguard Worker * luminances in linear space and gainmap metadata fields.
490*89a0ef05SAndroid Build Coastguard Worker */
491*89a0ef05SAndroid Build Coastguard Worker uint8_t encodeGain(float y_sdr, float y_hdr, uhdr_gainmap_metadata_ext_t* metadata);
492*89a0ef05SAndroid Build Coastguard Worker uint8_t encodeGain(float y_sdr, float y_hdr, uhdr_gainmap_metadata_ext_t* metadata,
493*89a0ef05SAndroid Build Coastguard Worker float log2MinContentBoost, float log2MaxContentBoost);
494*89a0ef05SAndroid Build Coastguard Worker float computeGain(float sdr, float hdr);
495*89a0ef05SAndroid Build Coastguard Worker uint8_t affineMapGain(float gainlog2, float mingainlog2, float maxgainlog2, float gamma);
496*89a0ef05SAndroid Build Coastguard Worker
497*89a0ef05SAndroid Build Coastguard Worker /*
498*89a0ef05SAndroid Build Coastguard Worker * Calculates the linear luminance in nits after applying the given gain
499*89a0ef05SAndroid Build Coastguard Worker * value, with the given hdr ratio, to the given sdr input in the range [0, 1].
500*89a0ef05SAndroid Build Coastguard Worker */
501*89a0ef05SAndroid Build Coastguard Worker Color applyGain(Color e, float gain, uhdr_gainmap_metadata_ext_t* metadata);
502*89a0ef05SAndroid Build Coastguard Worker Color applyGain(Color e, float gain, uhdr_gainmap_metadata_ext_t* metadata, float gainmapWeight);
503*89a0ef05SAndroid Build Coastguard Worker Color applyGainLUT(Color e, float gain, GainLUT& gainLUT, uhdr_gainmap_metadata_ext_t* metadata);
504*89a0ef05SAndroid Build Coastguard Worker
505*89a0ef05SAndroid Build Coastguard Worker /*
506*89a0ef05SAndroid Build Coastguard Worker * Apply gain in R, G and B channels, with the given hdr ratio, to the given sdr input
507*89a0ef05SAndroid Build Coastguard Worker * in the range [0, 1].
508*89a0ef05SAndroid Build Coastguard Worker */
509*89a0ef05SAndroid Build Coastguard Worker Color applyGain(Color e, Color gain, uhdr_gainmap_metadata_ext_t* metadata);
510*89a0ef05SAndroid Build Coastguard Worker Color applyGain(Color e, Color gain, uhdr_gainmap_metadata_ext_t* metadata, float gainmapWeight);
511*89a0ef05SAndroid Build Coastguard Worker Color applyGainLUT(Color e, Color gain, GainLUT& gainLUT, uhdr_gainmap_metadata_ext_t* metadata);
512*89a0ef05SAndroid Build Coastguard Worker
513*89a0ef05SAndroid Build Coastguard Worker /*
514*89a0ef05SAndroid Build Coastguard Worker * Sample the gain value for the map from a given x,y coordinate on a scale
515*89a0ef05SAndroid Build Coastguard Worker * that is map scale factor larger than the map size.
516*89a0ef05SAndroid Build Coastguard Worker */
517*89a0ef05SAndroid Build Coastguard Worker float sampleMap(uhdr_raw_image_t* map, float map_scale_factor, size_t x, size_t y);
518*89a0ef05SAndroid Build Coastguard Worker float sampleMap(uhdr_raw_image_t* map, size_t map_scale_factor, size_t x, size_t y,
519*89a0ef05SAndroid Build Coastguard Worker ShepardsIDW& weightTables);
520*89a0ef05SAndroid Build Coastguard Worker Color sampleMap3Channel(uhdr_raw_image_t* map, float map_scale_factor, size_t x, size_t y,
521*89a0ef05SAndroid Build Coastguard Worker bool has_alpha);
522*89a0ef05SAndroid Build Coastguard Worker Color sampleMap3Channel(uhdr_raw_image_t* map, size_t map_scale_factor, size_t x, size_t y,
523*89a0ef05SAndroid Build Coastguard Worker ShepardsIDW& weightTables, bool has_alpha);
524*89a0ef05SAndroid Build Coastguard Worker
525*89a0ef05SAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////
526*89a0ef05SAndroid Build Coastguard Worker // function selectors
527*89a0ef05SAndroid Build Coastguard Worker
528*89a0ef05SAndroid Build Coastguard Worker ColorTransformFn getGamutConversionFn(uhdr_color_gamut_t dst_gamut, uhdr_color_gamut_t src_gamut);
529*89a0ef05SAndroid Build Coastguard Worker ColorTransformFn getYuvToRgbFn(uhdr_color_gamut_t gamut);
530*89a0ef05SAndroid Build Coastguard Worker LuminanceFn getLuminanceFn(uhdr_color_gamut_t gamut);
531*89a0ef05SAndroid Build Coastguard Worker ColorTransformFn getInverseOetfFn(uhdr_color_transfer_t transfer);
532*89a0ef05SAndroid Build Coastguard Worker SceneToDisplayLuminanceFn getOotfFn(uhdr_color_transfer_t transfer);
533*89a0ef05SAndroid Build Coastguard Worker GetPixelFn getPixelFn(uhdr_img_fmt_t format);
534*89a0ef05SAndroid Build Coastguard Worker SamplePixelFn getSamplePixelFn(uhdr_img_fmt_t format);
535*89a0ef05SAndroid Build Coastguard Worker PutPixelFn putPixelFn(uhdr_img_fmt_t format);
536*89a0ef05SAndroid Build Coastguard Worker
537*89a0ef05SAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////
538*89a0ef05SAndroid Build Coastguard Worker // common utils
539*89a0ef05SAndroid Build Coastguard Worker
540*89a0ef05SAndroid Build Coastguard Worker // maximum limit of normalized pixel value in float representation
541*89a0ef05SAndroid Build Coastguard Worker static const float kMaxPixelFloat = 1.0f;
542*89a0ef05SAndroid Build Coastguard Worker
clampPixelFloat(float value)543*89a0ef05SAndroid Build Coastguard Worker static inline float clampPixelFloat(float value) {
544*89a0ef05SAndroid Build Coastguard Worker return (value < 0.0f) ? 0.0f : (value > kMaxPixelFloat) ? kMaxPixelFloat : value;
545*89a0ef05SAndroid Build Coastguard Worker }
546*89a0ef05SAndroid Build Coastguard Worker
clampPixelFloat(Color e)547*89a0ef05SAndroid Build Coastguard Worker static inline Color clampPixelFloat(Color e) {
548*89a0ef05SAndroid Build Coastguard Worker return {{{clampPixelFloat(e.r), clampPixelFloat(e.g), clampPixelFloat(e.b)}}};
549*89a0ef05SAndroid Build Coastguard Worker }
550*89a0ef05SAndroid Build Coastguard Worker
551*89a0ef05SAndroid Build Coastguard Worker // maximum limit of pixel value for linear hdr intent raw resource
552*89a0ef05SAndroid Build Coastguard Worker static const float kMaxPixelFloatHdrLinear = 10000.0f / 203.0f;
553*89a0ef05SAndroid Build Coastguard Worker
clampPixelFloatLinear(float value)554*89a0ef05SAndroid Build Coastguard Worker static inline float clampPixelFloatLinear(float value) {
555*89a0ef05SAndroid Build Coastguard Worker return CLIP3(value, 0.0f, kMaxPixelFloatHdrLinear);
556*89a0ef05SAndroid Build Coastguard Worker }
557*89a0ef05SAndroid Build Coastguard Worker
clampPixelFloatLinear(Color e)558*89a0ef05SAndroid Build Coastguard Worker static inline Color clampPixelFloatLinear(Color e) {
559*89a0ef05SAndroid Build Coastguard Worker return {{{clampPixelFloatLinear(e.r), clampPixelFloatLinear(e.g), clampPixelFloatLinear(e.b)}}};
560*89a0ef05SAndroid Build Coastguard Worker }
561*89a0ef05SAndroid Build Coastguard Worker
mapNonFiniteFloats(float val)562*89a0ef05SAndroid Build Coastguard Worker static float mapNonFiniteFloats(float val) {
563*89a0ef05SAndroid Build Coastguard Worker if (std::isinf(val)) {
564*89a0ef05SAndroid Build Coastguard Worker return val > 0 ? kMaxPixelFloatHdrLinear : 0.0f;
565*89a0ef05SAndroid Build Coastguard Worker }
566*89a0ef05SAndroid Build Coastguard Worker // nan
567*89a0ef05SAndroid Build Coastguard Worker return 0.0f;
568*89a0ef05SAndroid Build Coastguard Worker }
569*89a0ef05SAndroid Build Coastguard Worker
sanitizePixel(Color e)570*89a0ef05SAndroid Build Coastguard Worker static inline Color sanitizePixel(Color e) {
571*89a0ef05SAndroid Build Coastguard Worker float r = std::isfinite(e.r) ? clampPixelFloatLinear(e.r) : mapNonFiniteFloats(e.r);
572*89a0ef05SAndroid Build Coastguard Worker float g = std::isfinite(e.g) ? clampPixelFloatLinear(e.g) : mapNonFiniteFloats(e.g);
573*89a0ef05SAndroid Build Coastguard Worker float b = std::isfinite(e.b) ? clampPixelFloatLinear(e.b) : mapNonFiniteFloats(e.b);
574*89a0ef05SAndroid Build Coastguard Worker return {{{r, g, b}}};
575*89a0ef05SAndroid Build Coastguard Worker }
576*89a0ef05SAndroid Build Coastguard Worker
577*89a0ef05SAndroid Build Coastguard Worker bool isPixelFormatRgb(uhdr_img_fmt_t format);
578*89a0ef05SAndroid Build Coastguard Worker
579*89a0ef05SAndroid Build Coastguard Worker uint32_t colorToRgba1010102(Color e_gamma);
580*89a0ef05SAndroid Build Coastguard Worker uint64_t colorToRgbaF16(Color e_gamma);
581*89a0ef05SAndroid Build Coastguard Worker
582*89a0ef05SAndroid Build Coastguard Worker std::unique_ptr<uhdr_raw_image_ext_t> copy_raw_image(uhdr_raw_image_t* src);
583*89a0ef05SAndroid Build Coastguard Worker
584*89a0ef05SAndroid Build Coastguard Worker uhdr_error_info_t copy_raw_image(uhdr_raw_image_t* src, uhdr_raw_image_t* dst);
585*89a0ef05SAndroid Build Coastguard Worker
586*89a0ef05SAndroid Build Coastguard Worker std::unique_ptr<uhdr_raw_image_ext_t> convert_raw_input_to_ycbcr(
587*89a0ef05SAndroid Build Coastguard Worker uhdr_raw_image_t* src, bool chroma_sampling_enabled = false);
588*89a0ef05SAndroid Build Coastguard Worker
589*89a0ef05SAndroid Build Coastguard Worker #if (defined(UHDR_ENABLE_INTRINSICS) && (defined(__ARM_NEON__) || defined(__ARM_NEON)))
590*89a0ef05SAndroid Build Coastguard Worker std::unique_ptr<uhdr_raw_image_ext_t> convert_raw_input_to_ycbcr_neon(uhdr_raw_image_t* src);
591*89a0ef05SAndroid Build Coastguard Worker #endif
592*89a0ef05SAndroid Build Coastguard Worker
593*89a0ef05SAndroid Build Coastguard Worker bool floatToSignedFraction(float v, int32_t* numerator, uint32_t* denominator);
594*89a0ef05SAndroid Build Coastguard Worker bool floatToUnsignedFraction(float v, uint32_t* numerator, uint32_t* denominator);
595*89a0ef05SAndroid Build Coastguard Worker
596*89a0ef05SAndroid Build Coastguard Worker } // namespace ultrahdr
597*89a0ef05SAndroid Build Coastguard Worker
598*89a0ef05SAndroid Build Coastguard Worker #endif // ULTRAHDR_GAINMAPMATH_H
599