| Nick Deakin | 65f492a | 2022-11-29 22:47:40 -0500 | [diff] [blame] | 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 | #include <cmath> | 
 | 18 | #include <gtest/gtest.h> | 
 | 19 | #include <gmock/gmock.h> | 
 | 20 | #include <jpegrecoverymap/recoverymapmath.h> | 
 | 21 |  | 
 | 22 | namespace android::recoverymap { | 
 | 23 |  | 
 | 24 | class RecoveryMapMathTest : public testing::Test { | 
 | 25 | public: | 
 | 26 |   RecoveryMapMathTest(); | 
 | 27 |   ~RecoveryMapMathTest(); | 
 | 28 |  | 
 | 29 |   float ComparisonEpsilon() { return 1e-4f; } | 
 | 30 |   float LuminanceEpsilon() { return 1e-2f; } | 
 | 31 |  | 
 | 32 |   Color Yuv420(uint8_t y, uint8_t u, uint8_t v) { | 
 | 33 |       return {{{ static_cast<float>(y) / 255.0f, | 
 | 34 |                  (static_cast<float>(u) - 128.0f) / 255.0f, | 
 | 35 |                  (static_cast<float>(v) - 128.0f) / 255.0f }}}; | 
 | 36 |   } | 
 | 37 |  | 
 | 38 |   Color P010(uint16_t y, uint16_t u, uint16_t v) { | 
| Nick Deakin | 3812533 | 2022-12-12 15:48:24 -0500 | [diff] [blame] | 39 |       return {{{ (static_cast<float>(y) - 64.0f) / 876.0f, | 
 | 40 |                  (static_cast<float>(u) - 64.0f) / 896.0f - 0.5f, | 
 | 41 |                  (static_cast<float>(v) - 64.0f) / 896.0f - 0.5f }}}; | 
| Nick Deakin | 65f492a | 2022-11-29 22:47:40 -0500 | [diff] [blame] | 42 |   } | 
 | 43 |  | 
 | 44 |   float Map(uint8_t e) { | 
 | 45 |     return (static_cast<float>(e) - 127.5f) / 127.5f; | 
 | 46 |   } | 
 | 47 |  | 
 | 48 |   Color ColorMin(Color e1, Color e2) { | 
 | 49 |     return {{{ fmin(e1.r, e2.r), fmin(e1.g, e2.g), fmin(e1.b, e2.b) }}}; | 
 | 50 |   } | 
 | 51 |  | 
 | 52 |   Color ColorMax(Color e1, Color e2) { | 
 | 53 |     return {{{ fmax(e1.r, e2.r), fmax(e1.g, e2.g), fmax(e1.b, e2.b) }}}; | 
 | 54 |   } | 
 | 55 |  | 
 | 56 |   Color RgbBlack() { return {{{ 0.0f, 0.0f, 0.0f }}}; } | 
 | 57 |   Color RgbWhite() { return {{{ 1.0f, 1.0f, 1.0f }}}; } | 
 | 58 |  | 
 | 59 |   Color RgbRed() { return {{{ 1.0f, 0.0f, 0.0f }}}; } | 
 | 60 |   Color RgbGreen() { return {{{ 0.0f, 1.0f, 0.0f }}}; } | 
 | 61 |   Color RgbBlue() { return {{{ 0.0f, 0.0f, 1.0f }}}; } | 
 | 62 |  | 
 | 63 |   Color YuvBlack() { return {{{ 0.0f, 0.0f, 0.0f }}}; } | 
 | 64 |   Color YuvWhite() { return {{{ 1.0f, 0.0f, 0.0f }}}; } | 
 | 65 |  | 
 | 66 |   Color SrgbYuvRed() { return {{{ 0.299f, -0.1687f, 0.5f }}}; } | 
 | 67 |   Color SrgbYuvGreen() { return {{{ 0.587f, -0.3313f, -0.4187f }}}; } | 
 | 68 |   Color SrgbYuvBlue() { return {{{ 0.114f, 0.5f, -0.0813f }}}; } | 
 | 69 |  | 
 | 70 |   Color Bt2100YuvRed() { return {{{ 0.2627f, -0.13963f, 0.5f }}}; } | 
 | 71 |   Color Bt2100YuvGreen() { return {{{ 0.6780f, -0.36037f, -0.45979f }}}; } | 
 | 72 |   Color Bt2100YuvBlue() { return {{{ 0.0593f, 0.5f, -0.04021f }}}; } | 
 | 73 |  | 
 | 74 |   float SrgbYuvToLuminance(Color yuv_gamma, ColorCalculationFn luminanceFn) { | 
 | 75 |     Color rgb_gamma = srgbYuvToRgb(yuv_gamma); | 
 | 76 |     Color rgb = srgbInvOetf(rgb_gamma); | 
 | 77 |     float luminance_scaled = luminanceFn(rgb); | 
 | 78 |     return luminance_scaled * kSdrWhiteNits; | 
 | 79 |   } | 
 | 80 |  | 
 | 81 |   float Bt2100YuvToLuminance(Color yuv_gamma, ColorTransformFn hdrInvOetf, | 
 | 82 |                              ColorTransformFn gamutConversionFn, ColorCalculationFn luminanceFn, | 
 | 83 |                              float scale_factor) { | 
 | 84 |     Color rgb_gamma = bt2100YuvToRgb(yuv_gamma); | 
 | 85 |     Color rgb = hdrInvOetf(rgb_gamma); | 
 | 86 |     rgb = gamutConversionFn(rgb); | 
 | 87 |     float luminance_scaled = luminanceFn(rgb); | 
 | 88 |     return luminance_scaled * scale_factor; | 
 | 89 |   } | 
 | 90 |  | 
 | 91 |   Color Recover(Color yuv_gamma, float recovery, float range_scaling_factor) { | 
 | 92 |     Color rgb_gamma = srgbYuvToRgb(yuv_gamma); | 
 | 93 |     Color rgb = srgbInvOetf(rgb_gamma); | 
 | 94 |     return applyRecovery(rgb, recovery, range_scaling_factor); | 
 | 95 |   } | 
 | 96 |  | 
 | 97 |   jpegr_uncompressed_struct Yuv420Image() { | 
 | 98 |     static uint8_t pixels[] = { | 
 | 99 |       // Y | 
 | 100 |       0x00, 0x10, 0x20, 0x30, | 
 | 101 |       0x01, 0x11, 0x21, 0x31, | 
 | 102 |       0x02, 0x12, 0x22, 0x32, | 
 | 103 |       0x03, 0x13, 0x23, 0x33, | 
 | 104 |       // U | 
 | 105 |       0xA0, 0xA1, | 
 | 106 |       0xA2, 0xA3, | 
 | 107 |       // V | 
 | 108 |       0xB0, 0xB1, | 
 | 109 |       0xB2, 0xB3, | 
 | 110 |     }; | 
 | 111 |     return { pixels, 4, 4, JPEGR_COLORGAMUT_BT709 }; | 
 | 112 |   } | 
 | 113 |  | 
 | 114 |   Color (*Yuv420Colors())[4] { | 
 | 115 |     static Color colors[4][4] = { | 
 | 116 |       { | 
 | 117 |         Yuv420(0x00, 0xA0, 0xB0), Yuv420(0x10, 0xA0, 0xB0), | 
 | 118 |         Yuv420(0x20, 0xA1, 0xB1), Yuv420(0x30, 0xA1, 0xB1), | 
 | 119 |       }, { | 
 | 120 |         Yuv420(0x01, 0xA0, 0xB0), Yuv420(0x11, 0xA0, 0xB0), | 
 | 121 |         Yuv420(0x21, 0xA1, 0xB1), Yuv420(0x31, 0xA1, 0xB1), | 
 | 122 |       }, { | 
 | 123 |         Yuv420(0x02, 0xA2, 0xB2), Yuv420(0x12, 0xA2, 0xB2), | 
 | 124 |         Yuv420(0x22, 0xA3, 0xB3), Yuv420(0x32, 0xA3, 0xB3), | 
 | 125 |       }, { | 
 | 126 |         Yuv420(0x03, 0xA2, 0xB2), Yuv420(0x13, 0xA2, 0xB2), | 
 | 127 |         Yuv420(0x23, 0xA3, 0xB3), Yuv420(0x33, 0xA3, 0xB3), | 
 | 128 |       }, | 
 | 129 |     }; | 
 | 130 |     return colors; | 
 | 131 |   } | 
 | 132 |  | 
 | 133 |   jpegr_uncompressed_struct P010Image() { | 
 | 134 |     static uint16_t pixels[] = { | 
 | 135 |       // Y | 
 | 136 |       0x00 << 6, 0x10 << 6, 0x20 << 6, 0x30 << 6, | 
 | 137 |       0x01 << 6, 0x11 << 6, 0x21 << 6, 0x31 << 6, | 
 | 138 |       0x02 << 6, 0x12 << 6, 0x22 << 6, 0x32 << 6, | 
 | 139 |       0x03 << 6, 0x13 << 6, 0x23 << 6, 0x33 << 6, | 
 | 140 |       // UV | 
 | 141 |       0xA0 << 6, 0xB0 << 6, 0xA1 << 6, 0xB1 << 6, | 
 | 142 |       0xA2 << 6, 0xB2 << 6, 0xA3 << 6, 0xB3 << 6, | 
 | 143 |     }; | 
 | 144 |     return { pixels, 4, 4, JPEGR_COLORGAMUT_BT709 }; | 
 | 145 |   } | 
 | 146 |  | 
 | 147 |   Color (*P010Colors())[4] { | 
 | 148 |     static Color colors[4][4] = { | 
 | 149 |       { | 
 | 150 |         P010(0x00, 0xA0, 0xB0), P010(0x10, 0xA0, 0xB0), | 
 | 151 |         P010(0x20, 0xA1, 0xB1), P010(0x30, 0xA1, 0xB1), | 
 | 152 |       }, { | 
 | 153 |         P010(0x01, 0xA0, 0xB0), P010(0x11, 0xA0, 0xB0), | 
 | 154 |         P010(0x21, 0xA1, 0xB1), P010(0x31, 0xA1, 0xB1), | 
 | 155 |       }, { | 
 | 156 |         P010(0x02, 0xA2, 0xB2), P010(0x12, 0xA2, 0xB2), | 
 | 157 |         P010(0x22, 0xA3, 0xB3), P010(0x32, 0xA3, 0xB3), | 
 | 158 |       }, { | 
 | 159 |         P010(0x03, 0xA2, 0xB2), P010(0x13, 0xA2, 0xB2), | 
 | 160 |         P010(0x23, 0xA3, 0xB3), P010(0x33, 0xA3, 0xB3), | 
 | 161 |       }, | 
 | 162 |     }; | 
 | 163 |     return colors; | 
 | 164 |   } | 
 | 165 |  | 
 | 166 |   jpegr_uncompressed_struct MapImage() { | 
 | 167 |     static uint8_t pixels[] = { | 
 | 168 |       0x00, 0x10, 0x20, 0x30, | 
 | 169 |       0x01, 0x11, 0x21, 0x31, | 
 | 170 |       0x02, 0x12, 0x22, 0x32, | 
 | 171 |       0x03, 0x13, 0x23, 0x33, | 
 | 172 |     }; | 
 | 173 |     return { pixels, 4, 4, JPEGR_COLORGAMUT_UNSPECIFIED }; | 
 | 174 |   } | 
 | 175 |  | 
 | 176 |   float (*MapValues())[4] { | 
 | 177 |     static float values[4][4] = { | 
 | 178 |       { | 
 | 179 |         Map(0x00), Map(0x10), Map(0x20), Map(0x30), | 
 | 180 |       }, { | 
 | 181 |         Map(0x01), Map(0x11), Map(0x21), Map(0x31), | 
 | 182 |       }, { | 
 | 183 |         Map(0x02), Map(0x12), Map(0x22), Map(0x32), | 
 | 184 |       }, { | 
 | 185 |         Map(0x03), Map(0x13), Map(0x23), Map(0x33), | 
 | 186 |       }, | 
 | 187 |     }; | 
 | 188 |     return values; | 
 | 189 |   } | 
 | 190 |  | 
 | 191 | protected: | 
 | 192 |   virtual void SetUp(); | 
 | 193 |   virtual void TearDown(); | 
 | 194 | }; | 
 | 195 |  | 
 | 196 | RecoveryMapMathTest::RecoveryMapMathTest() {} | 
 | 197 | RecoveryMapMathTest::~RecoveryMapMathTest() {} | 
 | 198 |  | 
 | 199 | void RecoveryMapMathTest::SetUp() {} | 
 | 200 | void RecoveryMapMathTest::TearDown() {} | 
 | 201 |  | 
 | 202 | #define EXPECT_RGB_EQ(e1, e2)       \ | 
 | 203 |   EXPECT_FLOAT_EQ((e1).r, (e2).r);  \ | 
 | 204 |   EXPECT_FLOAT_EQ((e1).g, (e2).g);  \ | 
 | 205 |   EXPECT_FLOAT_EQ((e1).b, (e2).b) | 
 | 206 |  | 
 | 207 | #define EXPECT_RGB_NEAR(e1, e2)                     \ | 
 | 208 |   EXPECT_NEAR((e1).r, (e2).r, ComparisonEpsilon()); \ | 
 | 209 |   EXPECT_NEAR((e1).g, (e2).g, ComparisonEpsilon()); \ | 
 | 210 |   EXPECT_NEAR((e1).b, (e2).b, ComparisonEpsilon()) | 
 | 211 |  | 
 | 212 | #define EXPECT_RGB_CLOSE(e1, e2)                            \ | 
 | 213 |   EXPECT_NEAR((e1).r, (e2).r, ComparisonEpsilon() * 10.0f); \ | 
 | 214 |   EXPECT_NEAR((e1).g, (e2).g, ComparisonEpsilon() * 10.0f); \ | 
 | 215 |   EXPECT_NEAR((e1).b, (e2).b, ComparisonEpsilon() * 10.0f) | 
 | 216 |  | 
 | 217 | #define EXPECT_YUV_EQ(e1, e2)       \ | 
 | 218 |   EXPECT_FLOAT_EQ((e1).y, (e2).y);  \ | 
 | 219 |   EXPECT_FLOAT_EQ((e1).u, (e2).u);  \ | 
 | 220 |   EXPECT_FLOAT_EQ((e1).v, (e2).v) | 
 | 221 |  | 
 | 222 | #define EXPECT_YUV_NEAR(e1, e2)                     \ | 
 | 223 |   EXPECT_NEAR((e1).y, (e2).y, ComparisonEpsilon()); \ | 
 | 224 |   EXPECT_NEAR((e1).u, (e2).u, ComparisonEpsilon()); \ | 
 | 225 |   EXPECT_NEAR((e1).v, (e2).v, ComparisonEpsilon()) | 
 | 226 |  | 
 | 227 | #define EXPECT_YUV_BETWEEN(e, min, max)                                           \ | 
 | 228 |   EXPECT_THAT((e).y, testing::AllOf(testing::Ge((min).y), testing::Le((max).y))); \ | 
 | 229 |   EXPECT_THAT((e).u, testing::AllOf(testing::Ge((min).u), testing::Le((max).u))); \ | 
 | 230 |   EXPECT_THAT((e).v, testing::AllOf(testing::Ge((min).v), testing::Le((max).v))) | 
 | 231 |  | 
 | 232 | // TODO: a bunch of these tests can be parameterized. | 
 | 233 |  | 
 | 234 | TEST_F(RecoveryMapMathTest, ColorConstruct) { | 
 | 235 |   Color e1 = {{{ 0.1f, 0.2f, 0.3f }}}; | 
 | 236 |  | 
 | 237 |   EXPECT_FLOAT_EQ(e1.r, 0.1f); | 
 | 238 |   EXPECT_FLOAT_EQ(e1.g, 0.2f); | 
 | 239 |   EXPECT_FLOAT_EQ(e1.b, 0.3f); | 
 | 240 |  | 
 | 241 |   EXPECT_FLOAT_EQ(e1.y, 0.1f); | 
 | 242 |   EXPECT_FLOAT_EQ(e1.u, 0.2f); | 
 | 243 |   EXPECT_FLOAT_EQ(e1.v, 0.3f); | 
 | 244 | } | 
 | 245 |  | 
 | 246 | TEST_F(RecoveryMapMathTest, ColorAddColor) { | 
 | 247 |   Color e1 = {{{ 0.1f, 0.2f, 0.3f }}}; | 
 | 248 |  | 
 | 249 |   Color e2 = e1 + e1; | 
 | 250 |   EXPECT_FLOAT_EQ(e2.r, e1.r * 2.0f); | 
 | 251 |   EXPECT_FLOAT_EQ(e2.g, e1.g * 2.0f); | 
 | 252 |   EXPECT_FLOAT_EQ(e2.b, e1.b * 2.0f); | 
 | 253 |  | 
 | 254 |   e2 += e1; | 
 | 255 |   EXPECT_FLOAT_EQ(e2.r, e1.r * 3.0f); | 
 | 256 |   EXPECT_FLOAT_EQ(e2.g, e1.g * 3.0f); | 
 | 257 |   EXPECT_FLOAT_EQ(e2.b, e1.b * 3.0f); | 
 | 258 | } | 
 | 259 |  | 
 | 260 | TEST_F(RecoveryMapMathTest, ColorAddFloat) { | 
 | 261 |   Color e1 = {{{ 0.1f, 0.2f, 0.3f }}}; | 
 | 262 |  | 
 | 263 |   Color e2 = e1 + 0.1f; | 
 | 264 |   EXPECT_FLOAT_EQ(e2.r, e1.r + 0.1f); | 
 | 265 |   EXPECT_FLOAT_EQ(e2.g, e1.g + 0.1f); | 
 | 266 |   EXPECT_FLOAT_EQ(e2.b, e1.b + 0.1f); | 
 | 267 |  | 
 | 268 |   e2 += 0.1f; | 
 | 269 |   EXPECT_FLOAT_EQ(e2.r, e1.r + 0.2f); | 
 | 270 |   EXPECT_FLOAT_EQ(e2.g, e1.g + 0.2f); | 
 | 271 |   EXPECT_FLOAT_EQ(e2.b, e1.b + 0.2f); | 
 | 272 | } | 
 | 273 |  | 
 | 274 | TEST_F(RecoveryMapMathTest, ColorSubtractColor) { | 
 | 275 |   Color e1 = {{{ 0.1f, 0.2f, 0.3f }}}; | 
 | 276 |  | 
 | 277 |   Color e2 = e1 - e1; | 
 | 278 |   EXPECT_FLOAT_EQ(e2.r, 0.0f); | 
 | 279 |   EXPECT_FLOAT_EQ(e2.g, 0.0f); | 
 | 280 |   EXPECT_FLOAT_EQ(e2.b, 0.0f); | 
 | 281 |  | 
 | 282 |   e2 -= e1; | 
 | 283 |   EXPECT_FLOAT_EQ(e2.r, -e1.r); | 
 | 284 |   EXPECT_FLOAT_EQ(e2.g, -e1.g); | 
 | 285 |   EXPECT_FLOAT_EQ(e2.b, -e1.b); | 
 | 286 | } | 
 | 287 |  | 
 | 288 | TEST_F(RecoveryMapMathTest, ColorSubtractFloat) { | 
 | 289 |   Color e1 = {{{ 0.1f, 0.2f, 0.3f }}}; | 
 | 290 |  | 
 | 291 |   Color e2 = e1 - 0.1f; | 
 | 292 |   EXPECT_FLOAT_EQ(e2.r, e1.r - 0.1f); | 
 | 293 |   EXPECT_FLOAT_EQ(e2.g, e1.g - 0.1f); | 
 | 294 |   EXPECT_FLOAT_EQ(e2.b, e1.b - 0.1f); | 
 | 295 |  | 
 | 296 |   e2 -= 0.1f; | 
 | 297 |   EXPECT_FLOAT_EQ(e2.r, e1.r - 0.2f); | 
 | 298 |   EXPECT_FLOAT_EQ(e2.g, e1.g - 0.2f); | 
 | 299 |   EXPECT_FLOAT_EQ(e2.b, e1.b - 0.2f); | 
 | 300 | } | 
 | 301 |  | 
 | 302 | TEST_F(RecoveryMapMathTest, ColorMultiplyFloat) { | 
 | 303 |   Color e1 = {{{ 0.1f, 0.2f, 0.3f }}}; | 
 | 304 |  | 
 | 305 |   Color e2 = e1 * 2.0f; | 
 | 306 |   EXPECT_FLOAT_EQ(e2.r, e1.r * 2.0f); | 
 | 307 |   EXPECT_FLOAT_EQ(e2.g, e1.g * 2.0f); | 
 | 308 |   EXPECT_FLOAT_EQ(e2.b, e1.b * 2.0f); | 
 | 309 |  | 
 | 310 |   e2 *= 2.0f; | 
 | 311 |   EXPECT_FLOAT_EQ(e2.r, e1.r * 4.0f); | 
 | 312 |   EXPECT_FLOAT_EQ(e2.g, e1.g * 4.0f); | 
 | 313 |   EXPECT_FLOAT_EQ(e2.b, e1.b * 4.0f); | 
 | 314 | } | 
 | 315 |  | 
 | 316 | TEST_F(RecoveryMapMathTest, ColorDivideFloat) { | 
 | 317 |   Color e1 = {{{ 0.1f, 0.2f, 0.3f }}}; | 
 | 318 |  | 
 | 319 |   Color e2 = e1 / 2.0f; | 
 | 320 |   EXPECT_FLOAT_EQ(e2.r, e1.r / 2.0f); | 
 | 321 |   EXPECT_FLOAT_EQ(e2.g, e1.g / 2.0f); | 
 | 322 |   EXPECT_FLOAT_EQ(e2.b, e1.b / 2.0f); | 
 | 323 |  | 
 | 324 |   e2 /= 2.0f; | 
 | 325 |   EXPECT_FLOAT_EQ(e2.r, e1.r / 4.0f); | 
 | 326 |   EXPECT_FLOAT_EQ(e2.g, e1.g / 4.0f); | 
 | 327 |   EXPECT_FLOAT_EQ(e2.b, e1.b / 4.0f); | 
 | 328 | } | 
 | 329 |  | 
 | 330 | TEST_F(RecoveryMapMathTest, SrgbLuminance) { | 
 | 331 |   EXPECT_FLOAT_EQ(srgbLuminance(RgbBlack()), 0.0f); | 
 | 332 |   EXPECT_FLOAT_EQ(srgbLuminance(RgbWhite()), 1.0f); | 
 | 333 |   EXPECT_FLOAT_EQ(srgbLuminance(RgbRed()), 0.2126f); | 
 | 334 |   EXPECT_FLOAT_EQ(srgbLuminance(RgbGreen()), 0.7152f); | 
 | 335 |   EXPECT_FLOAT_EQ(srgbLuminance(RgbBlue()), 0.0722f); | 
 | 336 | } | 
 | 337 |  | 
 | 338 | TEST_F(RecoveryMapMathTest, SrgbYuvToRgb) { | 
 | 339 |   Color rgb_black = srgbYuvToRgb(YuvBlack()); | 
 | 340 |   EXPECT_RGB_NEAR(rgb_black, RgbBlack()); | 
 | 341 |  | 
 | 342 |   Color rgb_white = srgbYuvToRgb(YuvWhite()); | 
 | 343 |   EXPECT_RGB_NEAR(rgb_white, RgbWhite()); | 
 | 344 |  | 
 | 345 |   Color rgb_r = srgbYuvToRgb(SrgbYuvRed()); | 
 | 346 |   EXPECT_RGB_NEAR(rgb_r, RgbRed()); | 
 | 347 |  | 
 | 348 |   Color rgb_g = srgbYuvToRgb(SrgbYuvGreen()); | 
 | 349 |   EXPECT_RGB_NEAR(rgb_g, RgbGreen()); | 
 | 350 |  | 
 | 351 |   Color rgb_b = srgbYuvToRgb(SrgbYuvBlue()); | 
 | 352 |   EXPECT_RGB_NEAR(rgb_b, RgbBlue()); | 
 | 353 | } | 
 | 354 |  | 
 | 355 | TEST_F(RecoveryMapMathTest, SrgbRgbToYuv) { | 
 | 356 |   Color yuv_black = srgbRgbToYuv(RgbBlack()); | 
 | 357 |   EXPECT_YUV_NEAR(yuv_black, YuvBlack()); | 
 | 358 |  | 
 | 359 |   Color yuv_white = srgbRgbToYuv(RgbWhite()); | 
 | 360 |   EXPECT_YUV_NEAR(yuv_white, YuvWhite()); | 
 | 361 |  | 
 | 362 |   Color yuv_r = srgbRgbToYuv(RgbRed()); | 
 | 363 |   EXPECT_YUV_NEAR(yuv_r, SrgbYuvRed()); | 
 | 364 |  | 
 | 365 |   Color yuv_g = srgbRgbToYuv(RgbGreen()); | 
 | 366 |   EXPECT_YUV_NEAR(yuv_g, SrgbYuvGreen()); | 
 | 367 |  | 
 | 368 |   Color yuv_b = srgbRgbToYuv(RgbBlue()); | 
 | 369 |   EXPECT_YUV_NEAR(yuv_b, SrgbYuvBlue()); | 
 | 370 | } | 
 | 371 |  | 
 | 372 | TEST_F(RecoveryMapMathTest, SrgbRgbYuvRoundtrip) { | 
 | 373 |   Color rgb_black = srgbYuvToRgb(srgbRgbToYuv(RgbBlack())); | 
 | 374 |   EXPECT_RGB_NEAR(rgb_black, RgbBlack()); | 
 | 375 |  | 
 | 376 |   Color rgb_white = srgbYuvToRgb(srgbRgbToYuv(RgbWhite())); | 
 | 377 |   EXPECT_RGB_NEAR(rgb_white, RgbWhite()); | 
 | 378 |  | 
 | 379 |   Color rgb_r = srgbYuvToRgb(srgbRgbToYuv(RgbRed())); | 
 | 380 |   EXPECT_RGB_NEAR(rgb_r, RgbRed()); | 
 | 381 |  | 
 | 382 |   Color rgb_g = srgbYuvToRgb(srgbRgbToYuv(RgbGreen())); | 
 | 383 |   EXPECT_RGB_NEAR(rgb_g, RgbGreen()); | 
 | 384 |  | 
 | 385 |   Color rgb_b = srgbYuvToRgb(srgbRgbToYuv(RgbBlue())); | 
 | 386 |   EXPECT_RGB_NEAR(rgb_b, RgbBlue()); | 
 | 387 | } | 
 | 388 |  | 
 | 389 | TEST_F(RecoveryMapMathTest, SrgbTransferFunction) { | 
 | 390 |   EXPECT_FLOAT_EQ(srgbInvOetf(0.0f), 0.0f); | 
 | 391 |   EXPECT_NEAR(srgbInvOetf(0.02f), 0.00154f, ComparisonEpsilon()); | 
 | 392 |   EXPECT_NEAR(srgbInvOetf(0.04045f), 0.00313f, ComparisonEpsilon()); | 
 | 393 |   EXPECT_NEAR(srgbInvOetf(0.5f), 0.21404f, ComparisonEpsilon()); | 
 | 394 |   EXPECT_FLOAT_EQ(srgbInvOetf(1.0f), 1.0f); | 
 | 395 | } | 
 | 396 |  | 
 | 397 | TEST_F(RecoveryMapMathTest, P3Luminance) { | 
 | 398 |   EXPECT_FLOAT_EQ(p3Luminance(RgbBlack()), 0.0f); | 
 | 399 |   EXPECT_FLOAT_EQ(p3Luminance(RgbWhite()), 1.0f); | 
 | 400 |   EXPECT_FLOAT_EQ(p3Luminance(RgbRed()), 0.20949f); | 
 | 401 |   EXPECT_FLOAT_EQ(p3Luminance(RgbGreen()), 0.72160f); | 
 | 402 |   EXPECT_FLOAT_EQ(p3Luminance(RgbBlue()), 0.06891f); | 
 | 403 | } | 
 | 404 |  | 
 | 405 | TEST_F(RecoveryMapMathTest, Bt2100Luminance) { | 
 | 406 |   EXPECT_FLOAT_EQ(bt2100Luminance(RgbBlack()), 0.0f); | 
 | 407 |   EXPECT_FLOAT_EQ(bt2100Luminance(RgbWhite()), 1.0f); | 
 | 408 |   EXPECT_FLOAT_EQ(bt2100Luminance(RgbRed()), 0.2627f); | 
 | 409 |   EXPECT_FLOAT_EQ(bt2100Luminance(RgbGreen()), 0.6780f); | 
 | 410 |   EXPECT_FLOAT_EQ(bt2100Luminance(RgbBlue()), 0.0593f); | 
 | 411 | } | 
 | 412 |  | 
 | 413 | TEST_F(RecoveryMapMathTest, Bt2100YuvToRgb) { | 
 | 414 |   Color rgb_black = bt2100YuvToRgb(YuvBlack()); | 
 | 415 |   EXPECT_RGB_NEAR(rgb_black, RgbBlack()); | 
 | 416 |  | 
 | 417 |   Color rgb_white = bt2100YuvToRgb(YuvWhite()); | 
 | 418 |   EXPECT_RGB_NEAR(rgb_white, RgbWhite()); | 
 | 419 |  | 
 | 420 |   Color rgb_r = bt2100YuvToRgb(Bt2100YuvRed()); | 
 | 421 |   EXPECT_RGB_NEAR(rgb_r, RgbRed()); | 
 | 422 |  | 
 | 423 |   Color rgb_g = bt2100YuvToRgb(Bt2100YuvGreen()); | 
 | 424 |   EXPECT_RGB_NEAR(rgb_g, RgbGreen()); | 
 | 425 |  | 
 | 426 |   Color rgb_b = bt2100YuvToRgb(Bt2100YuvBlue()); | 
 | 427 |   EXPECT_RGB_NEAR(rgb_b, RgbBlue()); | 
 | 428 | } | 
 | 429 |  | 
 | 430 | TEST_F(RecoveryMapMathTest, Bt2100RgbToYuv) { | 
 | 431 |   Color yuv_black = bt2100RgbToYuv(RgbBlack()); | 
 | 432 |   EXPECT_YUV_NEAR(yuv_black, YuvBlack()); | 
 | 433 |  | 
 | 434 |   Color yuv_white = bt2100RgbToYuv(RgbWhite()); | 
 | 435 |   EXPECT_YUV_NEAR(yuv_white, YuvWhite()); | 
 | 436 |  | 
 | 437 |   Color yuv_r = bt2100RgbToYuv(RgbRed()); | 
 | 438 |   EXPECT_YUV_NEAR(yuv_r, Bt2100YuvRed()); | 
 | 439 |  | 
 | 440 |   Color yuv_g = bt2100RgbToYuv(RgbGreen()); | 
 | 441 |   EXPECT_YUV_NEAR(yuv_g, Bt2100YuvGreen()); | 
 | 442 |  | 
 | 443 |   Color yuv_b = bt2100RgbToYuv(RgbBlue()); | 
 | 444 |   EXPECT_YUV_NEAR(yuv_b, Bt2100YuvBlue()); | 
 | 445 | } | 
 | 446 |  | 
 | 447 | TEST_F(RecoveryMapMathTest, Bt2100RgbYuvRoundtrip) { | 
 | 448 |   Color rgb_black = bt2100YuvToRgb(bt2100RgbToYuv(RgbBlack())); | 
 | 449 |   EXPECT_RGB_NEAR(rgb_black, RgbBlack()); | 
 | 450 |  | 
 | 451 |   Color rgb_white = bt2100YuvToRgb(bt2100RgbToYuv(RgbWhite())); | 
 | 452 |   EXPECT_RGB_NEAR(rgb_white, RgbWhite()); | 
 | 453 |  | 
 | 454 |   Color rgb_r = bt2100YuvToRgb(bt2100RgbToYuv(RgbRed())); | 
 | 455 |   EXPECT_RGB_NEAR(rgb_r, RgbRed()); | 
 | 456 |  | 
 | 457 |   Color rgb_g = bt2100YuvToRgb(bt2100RgbToYuv(RgbGreen())); | 
 | 458 |   EXPECT_RGB_NEAR(rgb_g, RgbGreen()); | 
 | 459 |  | 
 | 460 |   Color rgb_b = bt2100YuvToRgb(bt2100RgbToYuv(RgbBlue())); | 
 | 461 |   EXPECT_RGB_NEAR(rgb_b, RgbBlue()); | 
 | 462 | } | 
 | 463 |  | 
 | 464 | TEST_F(RecoveryMapMathTest, HlgOetf) { | 
 | 465 |   EXPECT_FLOAT_EQ(hlgOetf(0.0f), 0.0f); | 
 | 466 |   EXPECT_NEAR(hlgOetf(0.04167f), 0.35357f, ComparisonEpsilon()); | 
 | 467 |   EXPECT_NEAR(hlgOetf(0.08333f), 0.5f, ComparisonEpsilon()); | 
 | 468 |   EXPECT_NEAR(hlgOetf(0.5f), 0.87164f, ComparisonEpsilon()); | 
 | 469 |   EXPECT_FLOAT_EQ(hlgOetf(1.0f), 1.0f); | 
 | 470 |  | 
 | 471 |   Color e = {{{ 0.04167f, 0.08333f, 0.5f }}}; | 
 | 472 |   Color e_gamma = {{{ 0.35357f, 0.5f, 0.87164f }}}; | 
 | 473 |   EXPECT_RGB_NEAR(hlgOetf(e), e_gamma); | 
 | 474 | } | 
 | 475 |  | 
 | 476 | TEST_F(RecoveryMapMathTest, HlgInvOetf) { | 
 | 477 |   EXPECT_FLOAT_EQ(hlgInvOetf(0.0f), 0.0f); | 
 | 478 |   EXPECT_NEAR(hlgInvOetf(0.25f), 0.02083f, ComparisonEpsilon()); | 
 | 479 |   EXPECT_NEAR(hlgInvOetf(0.5f), 0.08333f, ComparisonEpsilon()); | 
 | 480 |   EXPECT_NEAR(hlgInvOetf(0.75f), 0.26496f, ComparisonEpsilon()); | 
 | 481 |   EXPECT_FLOAT_EQ(hlgInvOetf(1.0f), 1.0f); | 
 | 482 |  | 
 | 483 |   Color e_gamma = {{{ 0.25f, 0.5f, 0.75f }}}; | 
 | 484 |   Color e = {{{ 0.02083f, 0.08333f, 0.26496f }}}; | 
 | 485 |   EXPECT_RGB_NEAR(hlgInvOetf(e_gamma), e); | 
 | 486 | } | 
 | 487 |  | 
 | 488 | TEST_F(RecoveryMapMathTest, HlgTransferFunctionRoundtrip) { | 
 | 489 |   EXPECT_FLOAT_EQ(hlgInvOetf(hlgOetf(0.0f)), 0.0f); | 
 | 490 |   EXPECT_NEAR(hlgInvOetf(hlgOetf(0.04167f)), 0.04167f, ComparisonEpsilon()); | 
 | 491 |   EXPECT_NEAR(hlgInvOetf(hlgOetf(0.08333f)), 0.08333f, ComparisonEpsilon()); | 
 | 492 |   EXPECT_NEAR(hlgInvOetf(hlgOetf(0.5f)), 0.5f, ComparisonEpsilon()); | 
 | 493 |   EXPECT_FLOAT_EQ(hlgInvOetf(hlgOetf(1.0f)), 1.0f); | 
 | 494 | } | 
 | 495 |  | 
 | 496 | TEST_F(RecoveryMapMathTest, PqOetf) { | 
 | 497 |   EXPECT_FLOAT_EQ(pqOetf(0.0f), 0.0f); | 
 | 498 |   EXPECT_NEAR(pqOetf(0.01f), 0.50808f, ComparisonEpsilon()); | 
 | 499 |   EXPECT_NEAR(pqOetf(0.5f), 0.92655f, ComparisonEpsilon()); | 
 | 500 |   EXPECT_NEAR(pqOetf(0.99f), 0.99895f, ComparisonEpsilon()); | 
 | 501 |   EXPECT_FLOAT_EQ(pqOetf(1.0f), 1.0f); | 
 | 502 |  | 
 | 503 |   Color e = {{{ 0.01f, 0.5f, 0.99f }}}; | 
 | 504 |   Color e_gamma = {{{ 0.50808f, 0.92655f, 0.99895f }}}; | 
 | 505 |   EXPECT_RGB_NEAR(pqOetf(e), e_gamma); | 
 | 506 | } | 
 | 507 |  | 
 | 508 | TEST_F(RecoveryMapMathTest, PqInvOetf) { | 
 | 509 |   EXPECT_FLOAT_EQ(pqInvOetf(0.0f), 0.0f); | 
 | 510 |   EXPECT_NEAR(pqInvOetf(0.01f), 2.31017e-7f, ComparisonEpsilon()); | 
 | 511 |   EXPECT_NEAR(pqInvOetf(0.5f), 0.00922f, ComparisonEpsilon()); | 
 | 512 |   EXPECT_NEAR(pqInvOetf(0.99f), 0.90903f, ComparisonEpsilon()); | 
 | 513 |   EXPECT_FLOAT_EQ(pqInvOetf(1.0f), 1.0f); | 
 | 514 |  | 
 | 515 |   Color e_gamma = {{{ 0.01f, 0.5f, 0.99f }}}; | 
 | 516 |   Color e = {{{ 2.31017e-7f, 0.00922f, 0.90903f }}}; | 
 | 517 |   EXPECT_RGB_NEAR(pqInvOetf(e_gamma), e); | 
 | 518 | } | 
 | 519 |  | 
 | 520 | TEST_F(RecoveryMapMathTest, PqTransferFunctionRoundtrip) { | 
 | 521 |   EXPECT_FLOAT_EQ(pqInvOetf(pqOetf(0.0f)), 0.0f); | 
 | 522 |   EXPECT_NEAR(pqInvOetf(pqOetf(0.01f)), 0.01f, ComparisonEpsilon()); | 
 | 523 |   EXPECT_NEAR(pqInvOetf(pqOetf(0.5f)), 0.5f, ComparisonEpsilon()); | 
 | 524 |   EXPECT_NEAR(pqInvOetf(pqOetf(0.99f)), 0.99f, ComparisonEpsilon()); | 
 | 525 |   EXPECT_FLOAT_EQ(pqInvOetf(pqOetf(1.0f)), 1.0f); | 
 | 526 | } | 
 | 527 |  | 
 | 528 | TEST_F(RecoveryMapMathTest, ColorConversionLookup) { | 
 | 529 |   EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_BT709, JPEGR_COLORGAMUT_UNSPECIFIED), | 
 | 530 |             nullptr); | 
 | 531 |   EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_BT709, JPEGR_COLORGAMUT_BT709), | 
 | 532 |             identityConversion); | 
 | 533 |   EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_BT709, JPEGR_COLORGAMUT_P3), | 
 | 534 |             p3ToBt709); | 
 | 535 |   EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_BT709, JPEGR_COLORGAMUT_BT2100), | 
 | 536 |             bt2100ToBt709); | 
 | 537 |  | 
 | 538 |   EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_P3, JPEGR_COLORGAMUT_UNSPECIFIED), | 
 | 539 |             nullptr); | 
 | 540 |   EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_P3, JPEGR_COLORGAMUT_BT709), | 
 | 541 |             bt709ToP3); | 
 | 542 |   EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_P3, JPEGR_COLORGAMUT_P3), | 
 | 543 |             identityConversion); | 
 | 544 |   EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_P3, JPEGR_COLORGAMUT_BT2100), | 
 | 545 |             bt2100ToP3); | 
 | 546 |  | 
 | 547 |   EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_BT2100, JPEGR_COLORGAMUT_UNSPECIFIED), | 
 | 548 |             nullptr); | 
 | 549 |   EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_BT2100, JPEGR_COLORGAMUT_BT709), | 
 | 550 |             bt709ToBt2100); | 
 | 551 |   EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_BT2100, JPEGR_COLORGAMUT_P3), | 
 | 552 |             p3ToBt2100); | 
 | 553 |   EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_BT2100, JPEGR_COLORGAMUT_BT2100), | 
 | 554 |             identityConversion); | 
 | 555 |  | 
 | 556 |   EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_UNSPECIFIED, JPEGR_COLORGAMUT_UNSPECIFIED), | 
 | 557 |             nullptr); | 
 | 558 |   EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_UNSPECIFIED, JPEGR_COLORGAMUT_BT709), | 
 | 559 |             nullptr); | 
 | 560 |   EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_UNSPECIFIED, JPEGR_COLORGAMUT_P3), | 
 | 561 |             nullptr); | 
 | 562 |   EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_UNSPECIFIED, JPEGR_COLORGAMUT_BT2100), | 
 | 563 |             nullptr); | 
 | 564 | } | 
 | 565 |  | 
 | 566 | TEST_F(RecoveryMapMathTest, EncodeRecovery) { | 
 | 567 |   EXPECT_EQ(encodeRecovery(0.0f, 0.0f, 4.0f), 127); | 
 | 568 |   EXPECT_EQ(encodeRecovery(0.0f, 1.0f, 4.0f), 127); | 
 | 569 |   EXPECT_EQ(encodeRecovery(1.0f, 0.0f, 4.0f), 0); | 
 | 570 |   EXPECT_EQ(encodeRecovery(0.5f, 0.0f, 4.0f), 0); | 
 | 571 |  | 
 | 572 |   EXPECT_EQ(encodeRecovery(1.0f, 1.0f, 4.0f), 127); | 
 | 573 |   EXPECT_EQ(encodeRecovery(1.0f, 4.0f, 4.0f), 255); | 
 | 574 |   EXPECT_EQ(encodeRecovery(1.0f, 5.0f, 4.0f), 255); | 
 | 575 |   EXPECT_EQ(encodeRecovery(4.0f, 1.0f, 4.0f), 0); | 
 | 576 |   EXPECT_EQ(encodeRecovery(4.0f, 0.5f, 4.0f), 0); | 
 | 577 |   EXPECT_EQ(encodeRecovery(1.0f, 2.0f, 4.0f), 191); | 
 | 578 |   EXPECT_EQ(encodeRecovery(2.0f, 1.0f, 4.0f), 63); | 
 | 579 |  | 
 | 580 |   EXPECT_EQ(encodeRecovery(1.0f, 2.0f, 2.0f), 255); | 
 | 581 |   EXPECT_EQ(encodeRecovery(2.0f, 1.0f, 2.0f), 0); | 
 | 582 |   EXPECT_EQ(encodeRecovery(1.0f, 1.41421f, 2.0f), 191); | 
 | 583 |   EXPECT_EQ(encodeRecovery(1.41421f, 1.0f, 2.0f), 63); | 
 | 584 |  | 
 | 585 |   EXPECT_EQ(encodeRecovery(1.0f, 8.0f, 8.0f), 255); | 
 | 586 |   EXPECT_EQ(encodeRecovery(8.0f, 1.0f, 8.0f), 0); | 
 | 587 |   EXPECT_EQ(encodeRecovery(1.0f, 2.82843f, 8.0f), 191); | 
 | 588 |   EXPECT_EQ(encodeRecovery(2.82843f, 1.0f, 8.0f), 63); | 
 | 589 | } | 
 | 590 |  | 
 | 591 | TEST_F(RecoveryMapMathTest, ApplyRecovery) { | 
 | 592 |   EXPECT_RGB_NEAR(applyRecovery(RgbBlack(), -1.0f, 4.0f), RgbBlack()); | 
 | 593 |   EXPECT_RGB_NEAR(applyRecovery(RgbBlack(), 0.0f, 4.0f), RgbBlack()); | 
 | 594 |   EXPECT_RGB_NEAR(applyRecovery(RgbBlack(), 1.0f, 4.0f), RgbBlack()); | 
 | 595 |  | 
 | 596 |   EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), -1.0f, 4.0f), RgbWhite() / 4.0f); | 
 | 597 |   EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), -0.5f, 4.0f), RgbWhite() / 2.0f); | 
 | 598 |   EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.0f, 4.0f), RgbWhite()); | 
 | 599 |   EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.5f, 4.0f), RgbWhite() * 2.0f); | 
 | 600 |   EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 1.0f, 4.0f), RgbWhite() * 4.0f); | 
 | 601 |  | 
 | 602 |   EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), -1.0f, 2.0f), RgbWhite() / 2.0f); | 
 | 603 |   EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), -0.5f, 2.0f), RgbWhite() / 1.41421f); | 
 | 604 |   EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.0f, 2.0f), RgbWhite()); | 
 | 605 |   EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.5f, 2.0f), RgbWhite() * 1.41421f); | 
 | 606 |   EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 1.0f, 2.0f), RgbWhite() * 2.0f); | 
 | 607 |  | 
 | 608 |   EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), -1.0f, 8.0f), RgbWhite() / 8.0f); | 
 | 609 |   EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), -0.5f, 8.0f), RgbWhite() / 2.82843f); | 
 | 610 |   EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.0f, 8.0f), RgbWhite()); | 
 | 611 |   EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.5f, 8.0f), RgbWhite() * 2.82843f); | 
 | 612 |   EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 1.0f, 8.0f), RgbWhite() * 8.0f); | 
 | 613 |  | 
 | 614 |   Color e = {{{ 0.0f, 0.5f, 1.0f }}}; | 
 | 615 |  | 
 | 616 |   EXPECT_RGB_NEAR(applyRecovery(e, -1.0f, 4.0f), e / 4.0f); | 
 | 617 |   EXPECT_RGB_NEAR(applyRecovery(e, -0.5f, 4.0f), e / 2.0f); | 
 | 618 |   EXPECT_RGB_NEAR(applyRecovery(e, 0.0f, 4.0f), e); | 
 | 619 |   EXPECT_RGB_NEAR(applyRecovery(e, 0.5f, 4.0f), e * 2.0f); | 
 | 620 |   EXPECT_RGB_NEAR(applyRecovery(e, 1.0f, 4.0f), e * 4.0f); | 
 | 621 | } | 
 | 622 |  | 
 | 623 | TEST_F(RecoveryMapMathTest, GetYuv420Pixel) { | 
 | 624 |   jpegr_uncompressed_struct image = Yuv420Image(); | 
 | 625 |   Color (*colors)[4] = Yuv420Colors(); | 
 | 626 |  | 
 | 627 |   for (size_t y = 0; y < 4; ++y) { | 
 | 628 |     for (size_t x = 0; x < 4; ++x) { | 
 | 629 |       EXPECT_YUV_NEAR(getYuv420Pixel(&image, x, y), colors[y][x]); | 
 | 630 |     } | 
 | 631 |   } | 
 | 632 | } | 
 | 633 |  | 
 | 634 | TEST_F(RecoveryMapMathTest, GetP010Pixel) { | 
 | 635 |   jpegr_uncompressed_struct image = P010Image(); | 
 | 636 |   Color (*colors)[4] = P010Colors(); | 
 | 637 |  | 
 | 638 |   for (size_t y = 0; y < 4; ++y) { | 
 | 639 |     for (size_t x = 0; x < 4; ++x) { | 
 | 640 |       EXPECT_YUV_NEAR(getP010Pixel(&image, x, y), colors[y][x]); | 
 | 641 |     } | 
 | 642 |   } | 
 | 643 | } | 
 | 644 |  | 
 | 645 | TEST_F(RecoveryMapMathTest, SampleYuv420) { | 
 | 646 |   jpegr_uncompressed_struct image = Yuv420Image(); | 
 | 647 |   Color (*colors)[4] = Yuv420Colors(); | 
 | 648 |  | 
 | 649 |   static const size_t kMapScaleFactor = 2; | 
 | 650 |   for (size_t y = 0; y < 4 / kMapScaleFactor; ++y) { | 
 | 651 |     for (size_t x = 0; x < 4 / kMapScaleFactor; ++x) { | 
 | 652 |       Color min = {{{ 1.0f, 1.0f, 1.0f }}}; | 
 | 653 |       Color max = {{{ -1.0f, -1.0f, -1.0f }}}; | 
 | 654 |  | 
 | 655 |       for (size_t dy = 0; dy < kMapScaleFactor; ++dy) { | 
 | 656 |         for (size_t dx = 0; dx < kMapScaleFactor; ++dx) { | 
 | 657 |           Color e = colors[y * kMapScaleFactor + dy][x * kMapScaleFactor + dx]; | 
 | 658 |           min = ColorMin(min, e); | 
 | 659 |           max = ColorMax(max, e); | 
 | 660 |         } | 
 | 661 |       } | 
 | 662 |  | 
 | 663 |       // Instead of reimplementing the sampling algorithm, confirm that the | 
 | 664 |       // sample output is within the range of the min and max of the nearest | 
 | 665 |       // points. | 
 | 666 |       EXPECT_YUV_BETWEEN(sampleYuv420(&image, kMapScaleFactor, x, y), min, max); | 
 | 667 |     } | 
 | 668 |   } | 
 | 669 | } | 
 | 670 |  | 
 | 671 | TEST_F(RecoveryMapMathTest, SampleP010) { | 
 | 672 |   jpegr_uncompressed_struct image = P010Image(); | 
 | 673 |   Color (*colors)[4] = P010Colors(); | 
 | 674 |  | 
 | 675 |   static const size_t kMapScaleFactor = 2; | 
 | 676 |   for (size_t y = 0; y < 4 / kMapScaleFactor; ++y) { | 
 | 677 |     for (size_t x = 0; x < 4 / kMapScaleFactor; ++x) { | 
 | 678 |       Color min = {{{ 1.0f, 1.0f, 1.0f }}}; | 
 | 679 |       Color max = {{{ -1.0f, -1.0f, -1.0f }}}; | 
 | 680 |  | 
 | 681 |       for (size_t dy = 0; dy < kMapScaleFactor; ++dy) { | 
 | 682 |         for (size_t dx = 0; dx < kMapScaleFactor; ++dx) { | 
 | 683 |           Color e = colors[y * kMapScaleFactor + dy][x * kMapScaleFactor + dx]; | 
 | 684 |           min = ColorMin(min, e); | 
 | 685 |           max = ColorMax(max, e); | 
 | 686 |         } | 
 | 687 |       } | 
 | 688 |  | 
 | 689 |       // Instead of reimplementing the sampling algorithm, confirm that the | 
 | 690 |       // sample output is within the range of the min and max of the nearest | 
 | 691 |       // points. | 
 | 692 |       EXPECT_YUV_BETWEEN(sampleP010(&image, kMapScaleFactor, x, y), min, max); | 
 | 693 |     } | 
 | 694 |   } | 
 | 695 | } | 
 | 696 |  | 
 | 697 | TEST_F(RecoveryMapMathTest, SampleMap) { | 
 | 698 |   jpegr_uncompressed_struct image = MapImage(); | 
 | 699 |   float (*values)[4] = MapValues(); | 
 | 700 |  | 
 | 701 |   static const size_t kMapScaleFactor = 2; | 
 | 702 |   for (size_t y = 0; y < 4 * kMapScaleFactor; ++y) { | 
 | 703 |     for (size_t x = 0; x < 4 * kMapScaleFactor; ++x) { | 
 | 704 |       size_t x_base = x / kMapScaleFactor; | 
 | 705 |       size_t y_base = y / kMapScaleFactor; | 
 | 706 |  | 
 | 707 |       float min = 1.0f; | 
 | 708 |       float max = -1.0f; | 
 | 709 |  | 
 | 710 |       min = fmin(min, values[y_base][x_base]); | 
 | 711 |       max = fmax(max, values[y_base][x_base]); | 
 | 712 |       if (y_base + 1 < 4) { | 
 | 713 |         min = fmin(min, values[y_base + 1][x_base]); | 
 | 714 |         max = fmax(max, values[y_base + 1][x_base]); | 
 | 715 |       } | 
 | 716 |       if (x_base + 1 < 4) { | 
 | 717 |         min = fmin(min, values[y_base][x_base + 1]); | 
 | 718 |         max = fmax(max, values[y_base][x_base + 1]); | 
 | 719 |       } | 
 | 720 |       if (y_base + 1 < 4 && x_base + 1 < 4) { | 
 | 721 |         min = fmin(min, values[y_base + 1][x_base + 1]); | 
 | 722 |         max = fmax(max, values[y_base + 1][x_base + 1]); | 
 | 723 |       } | 
 | 724 |  | 
 | 725 |       // Instead of reimplementing the sampling algorithm, confirm that the | 
 | 726 |       // sample output is within the range of the min and max of the nearest | 
 | 727 |       // points. | 
 | 728 |       EXPECT_THAT(sampleMap(&image, kMapScaleFactor, x, y), | 
 | 729 |                   testing::AllOf(testing::Ge(min), testing::Le(max))); | 
 | 730 |     } | 
 | 731 |   } | 
 | 732 | } | 
 | 733 |  | 
 | 734 | TEST_F(RecoveryMapMathTest, ColorToRgba1010102) { | 
 | 735 |   EXPECT_EQ(colorToRgba1010102(RgbBlack()), 0x3 << 30); | 
 | 736 |   EXPECT_EQ(colorToRgba1010102(RgbWhite()), 0xFFFFFFFF); | 
 | 737 |   EXPECT_EQ(colorToRgba1010102(RgbRed()), 0x3 << 30 | 0x3ff); | 
 | 738 |   EXPECT_EQ(colorToRgba1010102(RgbGreen()), 0x3 << 30 | 0x3ff << 10); | 
 | 739 |   EXPECT_EQ(colorToRgba1010102(RgbBlue()), 0x3 << 30 | 0x3ff << 20); | 
 | 740 |  | 
 | 741 |   Color e_gamma = {{{ 0.1f, 0.2f, 0.3f }}}; | 
 | 742 |   EXPECT_EQ(colorToRgba1010102(e_gamma), | 
 | 743 |             0x3 << 30 | 
 | 744 |           | static_cast<uint32_t>(0.1f * static_cast<float>(0x3ff)) | 
 | 745 |           | static_cast<uint32_t>(0.2f * static_cast<float>(0x3ff)) << 10 | 
 | 746 |           | static_cast<uint32_t>(0.3f * static_cast<float>(0x3ff)) << 20); | 
 | 747 | } | 
 | 748 |  | 
 | 749 | TEST_F(RecoveryMapMathTest, GenerateMapLuminanceSrgb) { | 
 | 750 |   EXPECT_FLOAT_EQ(SrgbYuvToLuminance(YuvBlack(), srgbLuminance), | 
 | 751 |                   0.0f); | 
 | 752 |   EXPECT_FLOAT_EQ(SrgbYuvToLuminance(YuvWhite(), srgbLuminance), | 
 | 753 |                   kSdrWhiteNits); | 
 | 754 |   EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvRed(), srgbLuminance), | 
 | 755 |               srgbLuminance(RgbRed()) * kSdrWhiteNits, LuminanceEpsilon()); | 
 | 756 |   EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvGreen(), srgbLuminance), | 
 | 757 |               srgbLuminance(RgbGreen()) * kSdrWhiteNits, LuminanceEpsilon()); | 
 | 758 |   EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvBlue(), srgbLuminance), | 
 | 759 |               srgbLuminance(RgbBlue()) * kSdrWhiteNits, LuminanceEpsilon()); | 
 | 760 | } | 
 | 761 |  | 
 | 762 | TEST_F(RecoveryMapMathTest, GenerateMapLuminanceSrgbP3) { | 
 | 763 |   EXPECT_FLOAT_EQ(SrgbYuvToLuminance(YuvBlack(), p3Luminance), | 
 | 764 |                   0.0f); | 
 | 765 |   EXPECT_FLOAT_EQ(SrgbYuvToLuminance(YuvWhite(), p3Luminance), | 
 | 766 |                   kSdrWhiteNits); | 
 | 767 |   EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvRed(), p3Luminance), | 
 | 768 |               p3Luminance(RgbRed()) * kSdrWhiteNits, LuminanceEpsilon()); | 
 | 769 |   EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvGreen(), p3Luminance), | 
 | 770 |               p3Luminance(RgbGreen()) * kSdrWhiteNits, LuminanceEpsilon()); | 
 | 771 |   EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvBlue(), p3Luminance), | 
 | 772 |               p3Luminance(RgbBlue()) * kSdrWhiteNits, LuminanceEpsilon()); | 
 | 773 | } | 
 | 774 |  | 
 | 775 | TEST_F(RecoveryMapMathTest, GenerateMapLuminanceSrgbBt2100) { | 
 | 776 |   EXPECT_FLOAT_EQ(SrgbYuvToLuminance(YuvBlack(), bt2100Luminance), | 
 | 777 |                   0.0f); | 
 | 778 |   EXPECT_FLOAT_EQ(SrgbYuvToLuminance(YuvWhite(), bt2100Luminance), | 
 | 779 |                   kSdrWhiteNits); | 
 | 780 |   EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvRed(), bt2100Luminance), | 
 | 781 |               bt2100Luminance(RgbRed()) * kSdrWhiteNits, LuminanceEpsilon()); | 
 | 782 |   EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvGreen(), bt2100Luminance), | 
 | 783 |               bt2100Luminance(RgbGreen()) * kSdrWhiteNits, LuminanceEpsilon()); | 
 | 784 |   EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvBlue(), bt2100Luminance), | 
 | 785 |               bt2100Luminance(RgbBlue()) * kSdrWhiteNits, LuminanceEpsilon()); | 
 | 786 | } | 
 | 787 |  | 
 | 788 | TEST_F(RecoveryMapMathTest, GenerateMapLuminanceHlg) { | 
 | 789 |   EXPECT_FLOAT_EQ(Bt2100YuvToLuminance(YuvBlack(), hlgInvOetf, identityConversion, | 
 | 790 |                                        bt2100Luminance, kHlgMaxNits), | 
 | 791 |                   0.0f); | 
 | 792 |   EXPECT_FLOAT_EQ(Bt2100YuvToLuminance(YuvWhite(), hlgInvOetf, identityConversion, | 
 | 793 |                                        bt2100Luminance, kHlgMaxNits), | 
 | 794 |                   kHlgMaxNits); | 
 | 795 |   EXPECT_NEAR(Bt2100YuvToLuminance(Bt2100YuvRed(), hlgInvOetf, identityConversion, | 
 | 796 |                                    bt2100Luminance, kHlgMaxNits), | 
 | 797 |               bt2100Luminance(RgbRed()) * kHlgMaxNits, LuminanceEpsilon()); | 
 | 798 |   EXPECT_NEAR(Bt2100YuvToLuminance(Bt2100YuvGreen(), hlgInvOetf, identityConversion, | 
 | 799 |                                    bt2100Luminance, kHlgMaxNits), | 
 | 800 |               bt2100Luminance(RgbGreen()) * kHlgMaxNits, LuminanceEpsilon()); | 
 | 801 |   EXPECT_NEAR(Bt2100YuvToLuminance(Bt2100YuvBlue(), hlgInvOetf, identityConversion, | 
 | 802 |                                    bt2100Luminance, kHlgMaxNits), | 
 | 803 |               bt2100Luminance(RgbBlue()) * kHlgMaxNits, LuminanceEpsilon()); | 
 | 804 | } | 
 | 805 |  | 
 | 806 | TEST_F(RecoveryMapMathTest, GenerateMapLuminancePq) { | 
 | 807 |   EXPECT_FLOAT_EQ(Bt2100YuvToLuminance(YuvBlack(), pqInvOetf, identityConversion, | 
 | 808 |                                        bt2100Luminance, kPqMaxNits), | 
 | 809 |                   0.0f); | 
 | 810 |   EXPECT_FLOAT_EQ(Bt2100YuvToLuminance(YuvWhite(), pqInvOetf, identityConversion, | 
 | 811 |                                        bt2100Luminance, kPqMaxNits), | 
 | 812 |                   kPqMaxNits); | 
 | 813 |   EXPECT_NEAR(Bt2100YuvToLuminance(Bt2100YuvRed(), pqInvOetf, identityConversion, | 
 | 814 |                                        bt2100Luminance, kPqMaxNits), | 
 | 815 |               bt2100Luminance(RgbRed()) * kPqMaxNits, LuminanceEpsilon()); | 
 | 816 |   EXPECT_NEAR(Bt2100YuvToLuminance(Bt2100YuvGreen(), pqInvOetf, identityConversion, | 
 | 817 |                                        bt2100Luminance, kPqMaxNits), | 
 | 818 |               bt2100Luminance(RgbGreen()) * kPqMaxNits, LuminanceEpsilon()); | 
 | 819 |   EXPECT_NEAR(Bt2100YuvToLuminance(Bt2100YuvBlue(), pqInvOetf, identityConversion, | 
 | 820 |                                        bt2100Luminance, kPqMaxNits), | 
 | 821 |               bt2100Luminance(RgbBlue()) * kPqMaxNits, LuminanceEpsilon()); | 
 | 822 | } | 
 | 823 |  | 
| Nick Deakin | 65f492a | 2022-11-29 22:47:40 -0500 | [diff] [blame] | 824 | TEST_F(RecoveryMapMathTest, ApplyMap) { | 
 | 825 |   EXPECT_RGB_EQ(Recover(YuvWhite(), 1.0f, 8.0f), | 
 | 826 |                 RgbWhite() * 8.0f); | 
 | 827 |   EXPECT_RGB_EQ(Recover(YuvBlack(), 1.0f, 8.0f), | 
 | 828 |                 RgbBlack()); | 
 | 829 |   EXPECT_RGB_CLOSE(Recover(SrgbYuvRed(), 1.0f, 8.0f), | 
 | 830 |                   RgbRed() * 8.0f); | 
 | 831 |   EXPECT_RGB_CLOSE(Recover(SrgbYuvGreen(), 1.0f, 8.0f), | 
 | 832 |                   RgbGreen() * 8.0f); | 
 | 833 |   EXPECT_RGB_CLOSE(Recover(SrgbYuvBlue(), 1.0f, 8.0f), | 
 | 834 |                   RgbBlue() * 8.0f); | 
 | 835 |  | 
 | 836 |   EXPECT_RGB_EQ(Recover(YuvWhite(), 0.5f, 8.0f), | 
 | 837 |                 RgbWhite() * sqrt(8.0f)); | 
 | 838 |   EXPECT_RGB_EQ(Recover(YuvBlack(), 0.5f, 8.0f), | 
 | 839 |                 RgbBlack()); | 
 | 840 |   EXPECT_RGB_CLOSE(Recover(SrgbYuvRed(), 0.5f, 8.0f), | 
 | 841 |                   RgbRed() * sqrt(8.0f)); | 
 | 842 |   EXPECT_RGB_CLOSE(Recover(SrgbYuvGreen(), 0.5f, 8.0f), | 
 | 843 |                   RgbGreen() * sqrt(8.0f)); | 
 | 844 |   EXPECT_RGB_CLOSE(Recover(SrgbYuvBlue(), 0.5f, 8.0f), | 
 | 845 |                   RgbBlue() * sqrt(8.0f)); | 
 | 846 |  | 
 | 847 |   EXPECT_RGB_EQ(Recover(YuvWhite(), 0.0f, 8.0f), | 
 | 848 |                 RgbWhite()); | 
 | 849 |   EXPECT_RGB_EQ(Recover(YuvBlack(), 0.0f, 8.0f), | 
 | 850 |                 RgbBlack()); | 
 | 851 |   EXPECT_RGB_CLOSE(Recover(SrgbYuvRed(), 0.0f, 8.0f), | 
 | 852 |                   RgbRed()); | 
 | 853 |   EXPECT_RGB_CLOSE(Recover(SrgbYuvGreen(), 0.0f, 8.0f), | 
 | 854 |                   RgbGreen()); | 
 | 855 |   EXPECT_RGB_CLOSE(Recover(SrgbYuvBlue(), 0.0f, 8.0f), | 
 | 856 |                   RgbBlue()); | 
 | 857 |  | 
 | 858 |   EXPECT_RGB_EQ(Recover(YuvWhite(), -0.5f, 8.0f), | 
 | 859 |                 RgbWhite() / sqrt(8.0f)); | 
 | 860 |   EXPECT_RGB_EQ(Recover(YuvBlack(), -0.5f, 8.0f), | 
 | 861 |                 RgbBlack()); | 
 | 862 |   EXPECT_RGB_CLOSE(Recover(SrgbYuvRed(), -0.5f, 8.0f), | 
 | 863 |                   RgbRed() / sqrt(8.0f)); | 
 | 864 |   EXPECT_RGB_CLOSE(Recover(SrgbYuvGreen(), -0.5f, 8.0f), | 
 | 865 |                   RgbGreen() / sqrt(8.0f)); | 
 | 866 |   EXPECT_RGB_CLOSE(Recover(SrgbYuvBlue(), -0.5f, 8.0f), | 
 | 867 |                   RgbBlue() / sqrt(8.0f)); | 
 | 868 |  | 
 | 869 |   EXPECT_RGB_EQ(Recover(YuvWhite(), -1.0f, 8.0f), | 
 | 870 |                 RgbWhite() / 8.0f); | 
 | 871 |   EXPECT_RGB_EQ(Recover(YuvBlack(), -1.0f, 8.0f), | 
 | 872 |                 RgbBlack()); | 
 | 873 |   EXPECT_RGB_CLOSE(Recover(SrgbYuvRed(), -1.0f, 8.0f), | 
 | 874 |                   RgbRed() / 8.0f); | 
 | 875 |   EXPECT_RGB_CLOSE(Recover(SrgbYuvGreen(), -1.0f, 8.0f), | 
 | 876 |                   RgbGreen() / 8.0f); | 
 | 877 |   EXPECT_RGB_CLOSE(Recover(SrgbYuvBlue(), -1.0f, 8.0f), | 
 | 878 |                   RgbBlue() / 8.0f); | 
 | 879 | } | 
 | 880 |  | 
 | 881 | } // namespace android::recoverymap |