Coverage Report

Created: 2025-12-14 07:25

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