1 /* 2 * Copyright (C) 2016 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 //#define LOG_NDEBUG 0 18 #define LOG_TAG "ColorUtils" 19 20 #include <inttypes.h> 21 #include <arpa/inet.h> 22 #include <media/stagefright/foundation/ABuffer.h> 23 #include <media/stagefright/foundation/ADebug.h> 24 #include <media/stagefright/foundation/ALookup.h> 25 #include <media/stagefright/foundation/ColorUtils.h> 26 #include <media/NdkMediaFormatPriv.h> 27 28 namespace android { 29 30 // shortcut names for brevity in the following tables 31 typedef ColorAspects CA; 32 typedef ColorUtils CU; 33 34 #define HI_UINT16(a) (((a) >> 8) & 0xFF) 35 #define LO_UINT16(a) ((a) & 0xFF) 36 37 const static 38 ALookup<CU::ColorRange, CA::Range> sRanges{ 39 { 40 { CU::kColorRangeLimited, CA::RangeLimited }, 41 { CU::kColorRangeFull, CA::RangeFull }, 42 { CU::kColorRangeUnspecified, CA::RangeUnspecified }, 43 } 44 }; 45 46 const static 47 ALookup<CU::ColorStandard, std::pair<CA::Primaries, CA::MatrixCoeffs>> sStandards { 48 { 49 { CU::kColorStandardUnspecified, { CA::PrimariesUnspecified, CA::MatrixUnspecified } }, 50 { CU::kColorStandardBT709, { CA::PrimariesBT709_5, CA::MatrixBT709_5 } }, 51 { CU::kColorStandardBT601_625, { CA::PrimariesBT601_6_625, CA::MatrixBT601_6 } }, 52 { CU::kColorStandardBT601_625_Unadjusted, 53 // this is a really close match 54 { CA::PrimariesBT601_6_625, CA::MatrixBT709_5 } }, 55 { CU::kColorStandardBT601_525, { CA::PrimariesBT601_6_525, CA::MatrixBT601_6 } }, 56 { CU::kColorStandardBT601_525_Unadjusted, 57 { CA::PrimariesBT601_6_525, CA::MatrixSMPTE240M } }, 58 { CU::kColorStandardBT2020, { CA::PrimariesBT2020, CA::MatrixBT2020 } }, 59 { CU::kColorStandardBT2020Constant, { CA::PrimariesBT2020, CA::MatrixBT2020Constant } }, 60 { CU::kColorStandardBT470M, { CA::PrimariesBT470_6M, CA::MatrixBT470_6M } }, 61 // NOTE: there is no close match to the matrix used by standard film, chose closest 62 { CU::kColorStandardFilm, { CA::PrimariesGenericFilm, CA::MatrixBT2020 } }, 63 } 64 }; 65 66 const static 67 ALookup<CU::ColorTransfer, CA::Transfer> sTransfers{ 68 { 69 { CU::kColorTransferUnspecified, CA::TransferUnspecified }, 70 { CU::kColorTransferLinear, CA::TransferLinear }, 71 { CU::kColorTransferSRGB, CA::TransferSRGB }, 72 { CU::kColorTransferSMPTE_170M, CA::TransferSMPTE170M }, 73 { CU::kColorTransferGamma22, CA::TransferGamma22 }, 74 { CU::kColorTransferGamma28, CA::TransferGamma28 }, 75 { CU::kColorTransferST2084, CA::TransferST2084 }, 76 { CU::kColorTransferHLG, CA::TransferHLG }, 77 } 78 }; 79 80 static bool isValid(ColorAspects::Primaries p) { 81 return p <= ColorAspects::PrimariesOther; 82 } 83 84 static bool isDefined(ColorAspects::Primaries p) { 85 return p <= ColorAspects::PrimariesBT2020; 86 } 87 88 static bool isValid(ColorAspects::MatrixCoeffs c) { 89 return c <= ColorAspects::MatrixOther; 90 } 91 92 static bool isDefined(ColorAspects::MatrixCoeffs c) { 93 return c <= ColorAspects::MatrixBT2020Constant; 94 } 95 96 //static 97 int32_t ColorUtils::wrapColorAspectsIntoColorStandard( 98 ColorAspects::Primaries primaries, ColorAspects::MatrixCoeffs coeffs) { 99 ColorStandard res; 100 if (sStandards.map(std::make_pair(primaries, coeffs), &res)) { 101 return res; 102 } else if (!isValid(primaries) || !isValid(coeffs)) { 103 return kColorStandardUnspecified; 104 } 105 106 // check platform media limits 107 uint32_t numPrimaries = ColorAspects::PrimariesBT2020 + 1; 108 if (isDefined(primaries) && isDefined(coeffs)) { 109 return kColorStandardExtendedStart + primaries + coeffs * numPrimaries; 110 } else { 111 return kColorStandardVendorStart + primaries + coeffs * 0x100; 112 } 113 } 114 115 //static 116 status_t ColorUtils::unwrapColorAspectsFromColorStandard( 117 int32_t standard, 118 ColorAspects::Primaries *primaries, ColorAspects::MatrixCoeffs *coeffs) { 119 std::pair<ColorAspects::Primaries, ColorAspects::MatrixCoeffs> res; 120 if (sStandards.map((ColorStandard)standard, &res)) { 121 *primaries = res.first; 122 *coeffs = res.second; 123 return OK; 124 } 125 126 int32_t start = kColorStandardExtendedStart; 127 int32_t numPrimaries = ColorAspects::PrimariesBT2020 + 1; 128 int32_t numCoeffs = ColorAspects::MatrixBT2020Constant + 1; 129 if (standard >= (int32_t)kColorStandardVendorStart) { 130 start = kColorStandardVendorStart; 131 numPrimaries = ColorAspects::PrimariesOther + 1; // 0x100 132 numCoeffs = ColorAspects::MatrixOther + 1; // 0x100; 133 } 134 if (standard >= start && standard < start + numPrimaries * numCoeffs) { 135 int32_t product = standard - start; 136 *primaries = (ColorAspects::Primaries)(product % numPrimaries); 137 *coeffs = (ColorAspects::MatrixCoeffs)(product / numPrimaries); 138 return OK; 139 } 140 *primaries = ColorAspects::PrimariesOther; 141 *coeffs = ColorAspects::MatrixOther; 142 return BAD_VALUE; 143 } 144 145 static bool isValid(ColorAspects::Range r) { 146 return r <= ColorAspects::RangeOther; 147 } 148 149 static bool isDefined(ColorAspects::Range r) { 150 return r <= ColorAspects::RangeLimited; 151 } 152 153 // static 154 int32_t ColorUtils::wrapColorAspectsIntoColorRange(ColorAspects::Range range) { 155 ColorRange res; 156 if (sRanges.map(range, &res)) { 157 return res; 158 } else if (!isValid(range)) { 159 return kColorRangeUnspecified; 160 } else { 161 CHECK(!isDefined(range)); 162 // all platform values are in sRanges 163 return kColorRangeVendorStart + range; 164 } 165 } 166 167 //static 168 status_t ColorUtils::unwrapColorAspectsFromColorRange( 169 int32_t range, ColorAspects::Range *aspect) { 170 if (sRanges.map((ColorRange)range, aspect)) { 171 return OK; 172 } 173 174 int32_t start = kColorRangeVendorStart; 175 int32_t numRanges = ColorAspects::RangeOther + 1; // 0x100 176 if (range >= start && range < start + numRanges) { 177 *aspect = (ColorAspects::Range)(range - start); 178 return OK; 179 } 180 *aspect = ColorAspects::RangeOther; 181 return BAD_VALUE; 182 } 183 184 static bool isValid(ColorAspects::Transfer t) { 185 return t <= ColorAspects::TransferOther; 186 } 187 188 static bool isDefined(ColorAspects::Transfer t) { 189 return t <= ColorAspects::TransferHLG 190 || (t >= ColorAspects::TransferSMPTE240M && t <= ColorAspects::TransferST428); 191 } 192 193 // static 194 int32_t ColorUtils::wrapColorAspectsIntoColorTransfer( 195 ColorAspects::Transfer transfer) { 196 ColorTransfer res; 197 if (sTransfers.map(transfer, &res)) { 198 return res; 199 } else if (!isValid(transfer)) { 200 return kColorTransferUnspecified; 201 } else if (isDefined(transfer)) { 202 return kColorTransferExtendedStart + transfer; 203 } else { 204 // all platform values are in sRanges 205 return kColorTransferVendorStart + transfer; 206 } 207 } 208 209 //static 210 status_t ColorUtils::unwrapColorAspectsFromColorTransfer( 211 int32_t transfer, ColorAspects::Transfer *aspect) { 212 if (sTransfers.map((ColorTransfer)transfer, aspect)) { 213 return OK; 214 } 215 216 int32_t start = kColorTransferExtendedStart; 217 int32_t numTransfers = ColorAspects::TransferST428 + 1; 218 if (transfer >= (int32_t)kColorTransferVendorStart) { 219 start = kColorTransferVendorStart; 220 numTransfers = ColorAspects::TransferOther + 1; // 0x100 221 } 222 if (transfer >= start && transfer < start + numTransfers) { 223 *aspect = (ColorAspects::Transfer)(transfer - start); 224 return OK; 225 } 226 *aspect = ColorAspects::TransferOther; 227 return BAD_VALUE; 228 } 229 230 // static 231 status_t ColorUtils::convertPlatformColorAspectsToCodecAspects( 232 int32_t range, int32_t standard, int32_t transfer, ColorAspects &aspects) { 233 status_t res1 = unwrapColorAspectsFromColorRange(range, &aspects.mRange); 234 status_t res2 = unwrapColorAspectsFromColorStandard( 235 standard, &aspects.mPrimaries, &aspects.mMatrixCoeffs); 236 status_t res3 = unwrapColorAspectsFromColorTransfer(transfer, &aspects.mTransfer); 237 return res1 != OK ? res1 : (res2 != OK ? res2 : res3); 238 } 239 240 // static 241 status_t ColorUtils::convertCodecColorAspectsToPlatformAspects( 242 const ColorAspects &aspects, int32_t *range, int32_t *standard, int32_t *transfer) { 243 *range = wrapColorAspectsIntoColorRange(aspects.mRange); 244 *standard = wrapColorAspectsIntoColorStandard(aspects.mPrimaries, aspects.mMatrixCoeffs); 245 *transfer = wrapColorAspectsIntoColorTransfer(aspects.mTransfer); 246 if (isValid(aspects.mRange) && isValid(aspects.mPrimaries) 247 && isValid(aspects.mMatrixCoeffs) && isValid(aspects.mTransfer)) { 248 return OK; 249 } else { 250 return BAD_VALUE; 251 } 252 } 253 254 const static 255 ALookup<int32_t, ColorAspects::Primaries> sIsoPrimaries { 256 { 257 { 1, ColorAspects::PrimariesBT709_5 }, 258 { 2, ColorAspects::PrimariesUnspecified }, 259 { 4, ColorAspects::PrimariesBT470_6M }, 260 { 5, ColorAspects::PrimariesBT601_6_625 }, 261 { 6, ColorAspects::PrimariesBT601_6_525 /* main */}, 262 { 7, ColorAspects::PrimariesBT601_6_525 }, 263 // -- ITU T.832 201201 ends here 264 { 8, ColorAspects::PrimariesGenericFilm }, 265 { 9, ColorAspects::PrimariesBT2020 }, 266 { 10, ColorAspects::PrimariesOther /* XYZ */ }, 267 } 268 }; 269 270 const static 271 ALookup<int32_t, ColorAspects::Transfer> sIsoTransfers { 272 { 273 { 1, ColorAspects::TransferSMPTE170M /* main */}, 274 { 2, ColorAspects::TransferUnspecified }, 275 { 4, ColorAspects::TransferGamma22 }, 276 { 5, ColorAspects::TransferGamma28 }, 277 { 6, ColorAspects::TransferSMPTE170M }, 278 { 7, ColorAspects::TransferSMPTE240M }, 279 { 8, ColorAspects::TransferLinear }, 280 { 9, ColorAspects::TransferOther /* log 100:1 */ }, 281 { 10, ColorAspects::TransferOther /* log 316:1 */ }, 282 { 11, ColorAspects::TransferXvYCC }, 283 { 12, ColorAspects::TransferBT1361 }, 284 { 13, ColorAspects::TransferSRGB }, 285 // -- ITU T.832 201201 ends here 286 { 14, ColorAspects::TransferSMPTE170M }, 287 { 15, ColorAspects::TransferSMPTE170M }, 288 { 16, ColorAspects::TransferST2084 }, 289 { 17, ColorAspects::TransferST428 }, 290 { 18, ColorAspects::TransferHLG }, 291 } 292 }; 293 294 const static 295 ALookup<int32_t, ColorAspects::MatrixCoeffs> sIsoMatrixCoeffs { 296 { 297 { 0, ColorAspects::MatrixOther }, 298 { 1, ColorAspects::MatrixBT709_5 }, 299 { 2, ColorAspects::MatrixUnspecified }, 300 { 4, ColorAspects::MatrixBT470_6M }, 301 { 6, ColorAspects::MatrixBT601_6 /* main */ }, 302 { 5, ColorAspects::MatrixBT601_6 }, 303 { 7, ColorAspects::MatrixSMPTE240M }, 304 { 8, ColorAspects::MatrixOther /* YCgCo */ }, 305 // -- ITU T.832 201201 ends here 306 { 9, ColorAspects::MatrixBT2020 }, 307 { 10, ColorAspects::MatrixBT2020Constant }, 308 } 309 }; 310 311 // static 312 void ColorUtils::convertCodecColorAspectsToIsoAspects( 313 const ColorAspects &aspects, 314 int32_t *primaries, int32_t *transfer, int32_t *coeffs, bool *fullRange) { 315 if (aspects.mPrimaries == ColorAspects::PrimariesOther || 316 !sIsoPrimaries.map(aspects.mPrimaries, primaries)) { 317 CHECK(sIsoPrimaries.map(ColorAspects::PrimariesUnspecified, primaries)); 318 } 319 if (aspects.mTransfer == ColorAspects::TransferOther || 320 !sIsoTransfers.map(aspects.mTransfer, transfer)) { 321 CHECK(sIsoTransfers.map(ColorAspects::TransferUnspecified, transfer)); 322 } 323 if (aspects.mMatrixCoeffs == ColorAspects::MatrixOther || 324 !sIsoMatrixCoeffs.map(aspects.mMatrixCoeffs, coeffs)) { 325 CHECK(sIsoMatrixCoeffs.map(ColorAspects::MatrixUnspecified, coeffs)); 326 } 327 *fullRange = aspects.mRange == ColorAspects::RangeFull; 328 } 329 330 // static 331 void ColorUtils::convertIsoColorAspectsToCodecAspects( 332 int32_t primaries, int32_t transfer, int32_t coeffs, bool fullRange, 333 ColorAspects &aspects) { 334 if (!sIsoPrimaries.map(primaries, &aspects.mPrimaries)) { 335 aspects.mPrimaries = ColorAspects::PrimariesUnspecified; 336 } 337 if (!sIsoTransfers.map(transfer, &aspects.mTransfer)) { 338 aspects.mTransfer = ColorAspects::TransferUnspecified; 339 } 340 if (!sIsoMatrixCoeffs.map(coeffs, &aspects.mMatrixCoeffs)) { 341 aspects.mMatrixCoeffs = ColorAspects::MatrixUnspecified; 342 } 343 aspects.mRange = fullRange ? ColorAspects::RangeFull : ColorAspects::RangeLimited; 344 } 345 346 void ColorUtils::convertIsoColorAspectsToPlatformAspects( 347 int32_t primaries, int32_t intransfer, int32_t coeffs, bool fullRange, 348 int32_t *range, int32_t *standard, int32_t *outtransfer) { 349 ColorAspects aspects; 350 convertIsoColorAspectsToCodecAspects(primaries, intransfer, coeffs, fullRange, aspects); 351 convertCodecColorAspectsToPlatformAspects(aspects, range, standard, outtransfer); 352 } 353 354 // static 355 ColorAspects ColorUtils::unpackToColorAspects(uint32_t packed) { 356 ColorAspects aspects; 357 aspects.mRange = (ColorAspects::Range)((packed >> 24) & 0xFF); 358 aspects.mPrimaries = (ColorAspects::Primaries)((packed >> 16) & 0xFF); 359 aspects.mMatrixCoeffs = (ColorAspects::MatrixCoeffs)((packed >> 8) & 0xFF); 360 aspects.mTransfer = (ColorAspects::Transfer)(packed & 0xFF); 361 362 return aspects; 363 } 364 365 // static 366 uint32_t ColorUtils::packToU32(const ColorAspects &aspects) { 367 return (aspects.mRange << 24) | (aspects.mPrimaries << 16) 368 | (aspects.mMatrixCoeffs << 8) | aspects.mTransfer; 369 } 370 371 // static 372 void ColorUtils::setDefaultCodecColorAspectsIfNeeded( 373 ColorAspects &aspects, int32_t width, int32_t height) { 374 ColorAspects::MatrixCoeffs coeffs; 375 ColorAspects::Primaries primaries; 376 377 // Default to BT2020, BT709 or BT601 based on size. Allow 2.35:1 aspect ratio. Limit BT601 378 // to PAL or smaller, BT2020 to 4K or larger, leaving BT709 for all resolutions in between. 379 if (width >= 3840 || height >= 3840 || width * (int64_t)height >= 3840 * 1634) { 380 primaries = ColorAspects::PrimariesBT2020; 381 coeffs = ColorAspects::MatrixBT2020; 382 } else if ((width <= 720 && height > 480 && height <= 576) 383 || (height <= 720 && width > 480 && width <= 576)) { 384 primaries = ColorAspects::PrimariesBT601_6_625; 385 coeffs = ColorAspects::MatrixBT601_6; 386 } else if ((width <= 720 && height <= 480) || (height <= 720 && width <= 480)) { 387 primaries = ColorAspects::PrimariesBT601_6_525; 388 coeffs = ColorAspects::MatrixBT601_6; 389 } else { 390 primaries = ColorAspects::PrimariesBT709_5; 391 coeffs = ColorAspects::MatrixBT709_5; 392 } 393 394 if (aspects.mRange == ColorAspects::RangeUnspecified) { 395 aspects.mRange = ColorAspects::RangeLimited; 396 } 397 398 if (aspects.mPrimaries == ColorAspects::PrimariesUnspecified) { 399 aspects.mPrimaries = primaries; 400 } 401 if (aspects.mMatrixCoeffs == ColorAspects::MatrixUnspecified) { 402 aspects.mMatrixCoeffs = coeffs; 403 } 404 if (aspects.mTransfer == ColorAspects::TransferUnspecified) { 405 aspects.mTransfer = ColorAspects::TransferSMPTE170M; 406 } 407 } 408 409 // TODO: move this into a Video HAL 410 const static 411 ALookup<CU::ColorStandard, std::pair<CA::Primaries, CA::MatrixCoeffs>> sStandardFallbacks { 412 { 413 { CU::kColorStandardBT601_625, { CA::PrimariesBT709_5, CA::MatrixBT470_6M } }, 414 { CU::kColorStandardBT601_625, { CA::PrimariesBT709_5, CA::MatrixBT601_6 } }, 415 { CU::kColorStandardBT709, { CA::PrimariesBT709_5, CA::MatrixSMPTE240M } }, 416 { CU::kColorStandardBT709, { CA::PrimariesBT709_5, CA::MatrixBT2020 } }, 417 { CU::kColorStandardBT601_525, { CA::PrimariesBT709_5, CA::MatrixBT2020Constant } }, 418 419 { CU::kColorStandardBT2020Constant, 420 { CA::PrimariesBT470_6M, CA::MatrixBT2020Constant } }, 421 422 { CU::kColorStandardBT601_625, { CA::PrimariesBT601_6_625, CA::MatrixBT470_6M } }, 423 { CU::kColorStandardBT601_525, { CA::PrimariesBT601_6_625, CA::MatrixBT2020Constant } }, 424 425 { CU::kColorStandardBT601_525, { CA::PrimariesBT601_6_525, CA::MatrixBT470_6M } }, 426 { CU::kColorStandardBT601_525, { CA::PrimariesBT601_6_525, CA::MatrixBT2020Constant } }, 427 428 { CU::kColorStandardBT2020Constant, 429 { CA::PrimariesGenericFilm, CA::MatrixBT2020Constant } }, 430 } 431 }; 432 433 const static 434 ALookup<CU::ColorStandard, CA::Primaries> sStandardPrimariesFallbacks { 435 { 436 { CU::kColorStandardFilm, CA::PrimariesGenericFilm }, 437 { CU::kColorStandardBT470M, CA::PrimariesBT470_6M }, 438 { CU::kColorStandardBT2020, CA::PrimariesBT2020 }, 439 { CU::kColorStandardBT601_525_Unadjusted, CA::PrimariesBT601_6_525 }, 440 { CU::kColorStandardBT601_625_Unadjusted, CA::PrimariesBT601_6_625 }, 441 } 442 }; 443 444 const static 445 ALookup<android_dataspace, android_dataspace> sLegacyDataSpaceToV0 { 446 { 447 { HAL_DATASPACE_SRGB, HAL_DATASPACE_V0_SRGB }, 448 { HAL_DATASPACE_BT709, HAL_DATASPACE_V0_BT709 }, 449 { HAL_DATASPACE_SRGB_LINEAR, HAL_DATASPACE_V0_SRGB_LINEAR }, 450 { HAL_DATASPACE_BT601_525, HAL_DATASPACE_V0_BT601_525 }, 451 { HAL_DATASPACE_BT601_625, HAL_DATASPACE_V0_BT601_625 }, 452 { HAL_DATASPACE_JFIF, HAL_DATASPACE_V0_JFIF }, 453 } 454 }; 455 456 #define GET_HAL_ENUM(class, name) HAL_DATASPACE_##class##name 457 #define GET_HAL_BITFIELD(class, name) (GET_HAL_ENUM(class, _##name) >> GET_HAL_ENUM(class, _SHIFT)) 458 459 const static 460 ALookup<CU::ColorStandard, uint32_t> sGfxStandards { 461 { 462 { CU::kColorStandardUnspecified, GET_HAL_BITFIELD(STANDARD, UNSPECIFIED) }, 463 { CU::kColorStandardBT709, GET_HAL_BITFIELD(STANDARD, BT709) }, 464 { CU::kColorStandardBT601_625, GET_HAL_BITFIELD(STANDARD, BT601_625) }, 465 { CU::kColorStandardBT601_625_Unadjusted, GET_HAL_BITFIELD(STANDARD, BT601_625_UNADJUSTED) }, 466 { CU::kColorStandardBT601_525, GET_HAL_BITFIELD(STANDARD, BT601_525) }, 467 { CU::kColorStandardBT601_525_Unadjusted, GET_HAL_BITFIELD(STANDARD, BT601_525_UNADJUSTED) }, 468 { CU::kColorStandardBT2020, GET_HAL_BITFIELD(STANDARD, BT2020) }, 469 { CU::kColorStandardBT2020Constant, GET_HAL_BITFIELD(STANDARD, BT2020_CONSTANT_LUMINANCE) }, 470 { CU::kColorStandardBT470M, GET_HAL_BITFIELD(STANDARD, BT470M) }, 471 { CU::kColorStandardFilm, GET_HAL_BITFIELD(STANDARD, FILM) }, 472 { CU::kColorStandardDCI_P3, GET_HAL_BITFIELD(STANDARD, DCI_P3) }, 473 } 474 }; 475 476 // verify public values are stable 477 static_assert(CU::kColorStandardUnspecified == 0, "SDK mismatch"); // N 478 static_assert(CU::kColorStandardBT709 == 1, "SDK mismatch"); // N 479 static_assert(CU::kColorStandardBT601_625 == 2, "SDK mismatch"); // N 480 static_assert(CU::kColorStandardBT601_525 == 4, "SDK mismatch"); // N 481 static_assert(CU::kColorStandardBT2020 == 6, "SDK mismatch"); // N 482 483 const static 484 ALookup<CU::ColorTransfer, uint32_t> sGfxTransfers { 485 { 486 { CU::kColorTransferUnspecified, GET_HAL_BITFIELD(TRANSFER, UNSPECIFIED) }, 487 { CU::kColorTransferLinear, GET_HAL_BITFIELD(TRANSFER, LINEAR) }, 488 { CU::kColorTransferSRGB, GET_HAL_BITFIELD(TRANSFER, SRGB) }, 489 { CU::kColorTransferSMPTE_170M, GET_HAL_BITFIELD(TRANSFER, SMPTE_170M) }, 490 { CU::kColorTransferGamma22, GET_HAL_BITFIELD(TRANSFER, GAMMA2_2) }, 491 { CU::kColorTransferGamma28, GET_HAL_BITFIELD(TRANSFER, GAMMA2_8) }, 492 { CU::kColorTransferST2084, GET_HAL_BITFIELD(TRANSFER, ST2084) }, 493 { CU::kColorTransferHLG, GET_HAL_BITFIELD(TRANSFER, HLG) }, 494 } 495 }; 496 497 // verify public values are stable 498 static_assert(CU::kColorTransferUnspecified == 0, "SDK mismatch"); // N 499 static_assert(CU::kColorTransferLinear == 1, "SDK mismatch"); // N 500 static_assert(CU::kColorTransferSRGB == 2, "SDK mismatch"); // N 501 static_assert(CU::kColorTransferSMPTE_170M == 3, "SDK mismatch"); // N 502 static_assert(CU::kColorTransferST2084 == 6, "SDK mismatch"); // N 503 static_assert(CU::kColorTransferHLG == 7, "SDK mismatch"); // N 504 505 const static 506 ALookup<CU::ColorRange, uint32_t> sGfxRanges { 507 { 508 { CU::kColorRangeUnspecified, GET_HAL_BITFIELD(RANGE, UNSPECIFIED) }, 509 { CU::kColorRangeFull, GET_HAL_BITFIELD(RANGE, FULL) }, 510 { CU::kColorRangeLimited, GET_HAL_BITFIELD(RANGE, LIMITED) }, 511 } 512 }; 513 514 // verify public values are stable 515 static_assert(CU::kColorRangeUnspecified == 0, "SDK mismatch"); // N 516 static_assert(CU::kColorRangeFull == 1, "SDK mismatch"); // N 517 static_assert(CU::kColorRangeLimited == 2, "SDK mismatch"); // N 518 519 #undef GET_HAL_BITFIELD 520 #undef GET_HAL_ENUM 521 522 523 bool ColorUtils::convertDataSpaceToV0(android_dataspace &dataSpace) { 524 (void)sLegacyDataSpaceToV0.lookup(dataSpace, &dataSpace); 525 return (dataSpace & 0xC000FFFF) == 0; 526 } 527 528 bool ColorUtils::checkIfAspectsChangedAndUnspecifyThem( 529 ColorAspects &aspects, const ColorAspects &orig, bool usePlatformAspects) { 530 // remove changed aspects (change them to Unspecified) 531 bool changed = false; 532 if (aspects.mRange && aspects.mRange != orig.mRange) { 533 aspects.mRange = ColorAspects::RangeUnspecified; 534 changed = true; 535 } 536 if (aspects.mPrimaries && aspects.mPrimaries != orig.mPrimaries) { 537 aspects.mPrimaries = ColorAspects::PrimariesUnspecified; 538 if (usePlatformAspects) { 539 aspects.mMatrixCoeffs = ColorAspects::MatrixUnspecified; 540 } 541 changed = true; 542 } 543 if (aspects.mMatrixCoeffs && aspects.mMatrixCoeffs != orig.mMatrixCoeffs) { 544 aspects.mMatrixCoeffs = ColorAspects::MatrixUnspecified; 545 if (usePlatformAspects) { 546 aspects.mPrimaries = ColorAspects::PrimariesUnspecified; 547 } 548 changed = true; 549 } 550 if (aspects.mTransfer && aspects.mTransfer != orig.mTransfer) { 551 aspects.mTransfer = ColorAspects::TransferUnspecified; 552 changed = true; 553 } 554 return changed; 555 } 556 557 // static 558 android_dataspace ColorUtils::getDataSpaceForColorAspects(ColorAspects &aspects, bool mayExpand) { 559 // This platform implementation never expands color space (e.g. returns an expanded 560 // dataspace to use where the codec does in-the-background color space conversion) 561 mayExpand = false; 562 563 if (aspects.mRange == ColorAspects::RangeUnspecified 564 || aspects.mPrimaries == ColorAspects::PrimariesUnspecified 565 || aspects.mMatrixCoeffs == ColorAspects::MatrixUnspecified 566 || aspects.mTransfer == ColorAspects::TransferUnspecified) { 567 ALOGW("expected specified color aspects (%u:%u:%u:%u)", 568 aspects.mRange, aspects.mPrimaries, aspects.mMatrixCoeffs, aspects.mTransfer); 569 } 570 571 // default to video range and transfer 572 ColorRange range = kColorRangeLimited; 573 ColorTransfer transfer = kColorTransferSMPTE_170M; 574 (void)sRanges.map(aspects.mRange, &range); 575 (void)sTransfers.map(aspects.mTransfer, &transfer); 576 577 ColorStandard standard = kColorStandardBT709; 578 auto pair = std::make_pair(aspects.mPrimaries, aspects.mMatrixCoeffs); 579 if (!sStandards.map(pair, &standard)) { 580 if (!sStandardFallbacks.map(pair, &standard)) { 581 (void)sStandardPrimariesFallbacks.map(aspects.mPrimaries, &standard); 582 583 if (aspects.mMatrixCoeffs == ColorAspects::MatrixBT2020Constant) { 584 range = kColorRangeFull; 585 } 586 } 587 } 588 589 // assume 1-to-1 mapping to HAL values (to deal with potential vendor extensions) 590 uint32_t gfxRange = range; 591 uint32_t gfxStandard = standard; 592 uint32_t gfxTransfer = transfer; 593 // TRICKY: use & to ensure all three mappings are completed 594 if (!(sGfxRanges.map(range, &gfxRange) & sGfxStandards.map(standard, &gfxStandard) 595 & sGfxTransfers.map(transfer, &gfxTransfer))) { 596 ALOGW("could not safely map platform color aspects (R:%u(%s) S:%u(%s) T:%u(%s) to " 597 "graphics dataspace (R:%u S:%u T:%u)", 598 range, asString(range), standard, asString(standard), transfer, asString(transfer), 599 gfxRange, gfxStandard, gfxTransfer); 600 } 601 602 android_dataspace dataSpace = (android_dataspace)( 603 (gfxRange << HAL_DATASPACE_RANGE_SHIFT) | 604 (gfxStandard << HAL_DATASPACE_STANDARD_SHIFT) | 605 (gfxTransfer << HAL_DATASPACE_TRANSFER_SHIFT)); 606 (void)sLegacyDataSpaceToV0.rlookup(dataSpace, &dataSpace); 607 608 if (!mayExpand) { 609 // update codec aspects based on dataspace 610 convertPlatformColorAspectsToCodecAspects(range, standard, transfer, aspects); 611 } 612 return dataSpace; 613 } 614 615 // static 616 void ColorUtils::getColorConfigFromFormat( 617 const sp<AMessage> &format, int32_t *range, int32_t *standard, int32_t *transfer) { 618 if (!format->findInt32("color-range", range)) { 619 *range = kColorRangeUnspecified; 620 } 621 if (!format->findInt32("color-standard", standard)) { 622 *standard = kColorStandardUnspecified; 623 } 624 if (!format->findInt32("color-transfer", transfer)) { 625 *transfer = kColorTransferUnspecified; 626 } 627 } 628 629 // static 630 void ColorUtils::copyColorConfig(const sp<AMessage> &source, sp<AMessage> &target) { 631 // 0 values are unspecified 632 int32_t value; 633 if (source->findInt32("color-range", &value)) { 634 target->setInt32("color-range", value); 635 } 636 if (source->findInt32("color-standard", &value)) { 637 target->setInt32("color-standard", value); 638 } 639 if (source->findInt32("color-transfer", &value)) { 640 target->setInt32("color-transfer", value); 641 } 642 } 643 644 // static 645 void ColorUtils::getColorAspectsFromFormat(const sp<AMessage> &format, ColorAspects &aspects) { 646 int32_t range, standard, transfer; 647 getColorConfigFromFormat(format, &range, &standard, &transfer); 648 649 if (convertPlatformColorAspectsToCodecAspects( 650 range, standard, transfer, aspects) != OK) { 651 ALOGW("Ignoring illegal color aspects(R:%d(%s), S:%d(%s), T:%d(%s))", 652 range, asString((ColorRange)range), 653 standard, asString((ColorStandard)standard), 654 transfer, asString((ColorTransfer)transfer)); 655 // Invalid values were converted to unspecified !params!, but otherwise were not changed 656 // For encoders, we leave these as is. For decoders, we will use default values. 657 } 658 ALOGV("Got color aspects (R:%d(%s), P:%d(%s), M:%d(%s), T:%d(%s)) " 659 "from format (out:R:%d(%s), S:%d(%s), T:%d(%s))", 660 aspects.mRange, asString(aspects.mRange), 661 aspects.mPrimaries, asString(aspects.mPrimaries), 662 aspects.mMatrixCoeffs, asString(aspects.mMatrixCoeffs), 663 aspects.mTransfer, asString(aspects.mTransfer), 664 range, asString((ColorRange)range), 665 standard, asString((ColorStandard)standard), 666 transfer, asString((ColorTransfer)transfer)); 667 } 668 669 // static 670 void ColorUtils::setColorAspectsIntoFormat( 671 const ColorAspects &aspects, sp<AMessage> &format, bool force) { 672 int32_t range = 0, standard = 0, transfer = 0; 673 convertCodecColorAspectsToPlatformAspects(aspects, &range, &standard, &transfer); 674 // save set values to base output format 675 // (encoder input format will read back actually supported values by the codec) 676 if (range != 0 || force) { 677 format->setInt32("color-range", range); 678 } 679 if (standard != 0 || force) { 680 format->setInt32("color-standard", standard); 681 } 682 if (transfer != 0 || force) { 683 format->setInt32("color-transfer", transfer); 684 } 685 ALOGV("Setting color aspects (R:%d(%s), P:%d(%s), M:%d(%s), T:%d(%s)) " 686 "into format (out:R:%d(%s), S:%d(%s), T:%d(%s))", 687 aspects.mRange, asString(aspects.mRange), 688 aspects.mPrimaries, asString(aspects.mPrimaries), 689 aspects.mMatrixCoeffs, asString(aspects.mMatrixCoeffs), 690 aspects.mTransfer, asString(aspects.mTransfer), 691 range, asString((ColorRange)range), 692 standard, asString((ColorStandard)standard), 693 transfer, asString((ColorTransfer)transfer)); 694 } 695 696 697 // static 698 void ColorUtils::setHDRStaticInfoIntoAMediaFormat( 699 const HDRStaticInfo &info, AMediaFormat *format) { 700 setHDRStaticInfoIntoFormat(info, format->mFormat); 701 } 702 703 // static 704 void ColorUtils::setHDRStaticInfoIntoFormat( 705 const HDRStaticInfo &info, sp<AMessage> &format) { 706 sp<ABuffer> infoBuffer = new ABuffer(25); 707 708 // Convert the data in infoBuffer to little endian format as defined by CTA-861-3 709 uint8_t *data = infoBuffer->data(); 710 // Static_Metadata_Descriptor_ID 711 data[0] = info.mID; 712 713 // display primary 0 714 data[1] = LO_UINT16(info.sType1.mR.x); 715 data[2] = HI_UINT16(info.sType1.mR.x); 716 data[3] = LO_UINT16(info.sType1.mR.y); 717 data[4] = HI_UINT16(info.sType1.mR.y); 718 719 // display primary 1 720 data[5] = LO_UINT16(info.sType1.mG.x); 721 data[6] = HI_UINT16(info.sType1.mG.x); 722 data[7] = LO_UINT16(info.sType1.mG.y); 723 data[8] = HI_UINT16(info.sType1.mG.y); 724 725 // display primary 2 726 data[9] = LO_UINT16(info.sType1.mB.x); 727 data[10] = HI_UINT16(info.sType1.mB.x); 728 data[11] = LO_UINT16(info.sType1.mB.y); 729 data[12] = HI_UINT16(info.sType1.mB.y); 730 731 // white point 732 data[13] = LO_UINT16(info.sType1.mW.x); 733 data[14] = HI_UINT16(info.sType1.mW.x); 734 data[15] = LO_UINT16(info.sType1.mW.y); 735 data[16] = HI_UINT16(info.sType1.mW.y); 736 737 // MaxDisplayLuminance 738 data[17] = LO_UINT16(info.sType1.mMaxDisplayLuminance); 739 data[18] = HI_UINT16(info.sType1.mMaxDisplayLuminance); 740 741 // MinDisplayLuminance 742 data[19] = LO_UINT16(info.sType1.mMinDisplayLuminance); 743 data[20] = HI_UINT16(info.sType1.mMinDisplayLuminance); 744 745 // MaxContentLightLevel 746 data[21] = LO_UINT16(info.sType1.mMaxContentLightLevel); 747 data[22] = HI_UINT16(info.sType1.mMaxContentLightLevel); 748 749 // MaxFrameAverageLightLevel 750 data[23] = LO_UINT16(info.sType1.mMaxFrameAverageLightLevel); 751 data[24] = HI_UINT16(info.sType1.mMaxFrameAverageLightLevel); 752 753 format->setBuffer("hdr-static-info", infoBuffer); 754 } 755 756 // a simple method copied from Utils.cpp 757 static uint16_t U16LE_AT(const uint8_t *ptr) { 758 return ptr[0] | (ptr[1] << 8); 759 } 760 761 // static 762 bool ColorUtils::getHDRStaticInfoFromFormat(const sp<AMessage> &format, HDRStaticInfo *info) { 763 sp<ABuffer> buf; 764 if (!format->findBuffer("hdr-static-info", &buf)) { 765 return false; 766 } 767 768 // TODO: Make this more flexible when adding more members to HDRStaticInfo 769 if (buf->size() != 25 /* static Metadata Type 1 size */) { 770 ALOGW("Ignore invalid HDRStaticInfo with size: %zu", buf->size()); 771 return false; 772 } 773 774 const uint8_t *data = buf->data(); 775 if (*data != HDRStaticInfo::kType1) { 776 ALOGW("Unsupported static Metadata Type %u", *data); 777 return false; 778 } 779 780 info->mID = HDRStaticInfo::kType1; 781 info->sType1.mR.x = U16LE_AT(&data[1]); 782 info->sType1.mR.y = U16LE_AT(&data[3]); 783 info->sType1.mG.x = U16LE_AT(&data[5]); 784 info->sType1.mG.y = U16LE_AT(&data[7]); 785 info->sType1.mB.x = U16LE_AT(&data[9]); 786 info->sType1.mB.y = U16LE_AT(&data[11]); 787 info->sType1.mW.x = U16LE_AT(&data[13]); 788 info->sType1.mW.y = U16LE_AT(&data[15]); 789 info->sType1.mMaxDisplayLuminance = U16LE_AT(&data[17]); 790 info->sType1.mMinDisplayLuminance = U16LE_AT(&data[19]); 791 info->sType1.mMaxContentLightLevel = U16LE_AT(&data[21]); 792 info->sType1.mMaxFrameAverageLightLevel = U16LE_AT(&data[23]); 793 794 ALOGV("Got HDRStaticInfo from config (R: %u %u, G: %u %u, B: %u, %u, W: %u, %u, " 795 "MaxDispL: %u, MinDispL: %u, MaxContentL: %u, MaxFrameAvgL: %u)", 796 info->sType1.mR.x, info->sType1.mR.y, info->sType1.mG.x, info->sType1.mG.y, 797 info->sType1.mB.x, info->sType1.mB.y, info->sType1.mW.x, info->sType1.mW.y, 798 info->sType1.mMaxDisplayLuminance, info->sType1.mMinDisplayLuminance, 799 info->sType1.mMaxContentLightLevel, info->sType1.mMaxFrameAverageLightLevel); 800 return true; 801 } 802 803 } // namespace android 804 805