Coverage Report

Created: 2026-06-15 07:18

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