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