| 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 |