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 27namespace android { 28 29// shortcut names for brevity in the following tables 30typedef ColorAspects CA; 31typedef ColorUtils CU; 32 33#define HI_UINT16(a) (((a) >> 8) & 0xFF) 34#define LO_UINT16(a) ((a) & 0xFF) 35 36const static 37ALookup<CU::ColorRange, CA::Range> sRanges{ 38 { 39 { CU::kColorRangeLimited, CA::RangeLimited }, 40 { CU::kColorRangeFull, CA::RangeFull }, 41 { CU::kColorRangeUnspecified, CA::RangeUnspecified }, 42 } 43}; 44 45const static 46ALookup<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 65const static 66ALookup<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 79static bool isValid(ColorAspects::Primaries p) { 80 return p <= ColorAspects::PrimariesOther; 81} 82 83static bool isDefined(ColorAspects::Primaries p) { 84 return p <= ColorAspects::PrimariesBT2020; 85} 86 87static bool isValid(ColorAspects::MatrixCoeffs c) { 88 return c <= ColorAspects::MatrixOther; 89} 90 91static bool isDefined(ColorAspects::MatrixCoeffs c) { 92 return c <= ColorAspects::MatrixBT2020Constant; 93} 94 95//static 96int32_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 115status_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 144static bool isValid(ColorAspects::Range r) { 145 return r <= ColorAspects::RangeOther; 146} 147 148static bool isDefined(ColorAspects::Range r) { 149 return r <= ColorAspects::RangeLimited; 150} 151 152// static 153int32_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 167status_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 183static bool isValid(ColorAspects::Transfer t) { 184 return t <= ColorAspects::TransferOther; 185} 186 187static bool isDefined(ColorAspects::Transfer t) { 188 return t <= ColorAspects::TransferHLG 189 || (t >= ColorAspects::TransferSMPTE240M && t <= ColorAspects::TransferST428); 190} 191 192// static 193int32_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 209status_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 230status_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 240status_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 253const static 254ALookup<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 269const static 270ALookup<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 { 18, ColorAspects::TransferHLG }, 290 } 291}; 292 293const static 294ALookup<int32_t, ColorAspects::MatrixCoeffs> sIsoMatrixCoeffs { 295 { 296 { 0, ColorAspects::MatrixOther }, 297 { 1, ColorAspects::MatrixBT709_5 }, 298 { 2, ColorAspects::MatrixUnspecified }, 299 { 4, ColorAspects::MatrixBT470_6M }, 300 { 6, ColorAspects::MatrixBT601_6 /* main */ }, 301 { 5, ColorAspects::MatrixBT601_6 }, 302 { 7, ColorAspects::MatrixSMPTE240M }, 303 { 8, ColorAspects::MatrixOther /* YCgCo */ }, 304 // -- ITU T.832 201201 ends here 305 { 9, ColorAspects::MatrixBT2020 }, 306 { 10, ColorAspects::MatrixBT2020Constant }, 307 } 308}; 309 310// static 311void ColorUtils::convertCodecColorAspectsToIsoAspects( 312 const ColorAspects &aspects, 313 int32_t *primaries, int32_t *transfer, int32_t *coeffs, bool *fullRange) { 314 if (aspects.mPrimaries == ColorAspects::PrimariesOther || 315 !sIsoPrimaries.map(aspects.mPrimaries, primaries)) { 316 CHECK(sIsoPrimaries.map(ColorAspects::PrimariesUnspecified, primaries)); 317 } 318 if (aspects.mTransfer == ColorAspects::TransferOther || 319 !sIsoTransfers.map(aspects.mTransfer, transfer)) { 320 CHECK(sIsoTransfers.map(ColorAspects::TransferUnspecified, transfer)); 321 } 322 if (aspects.mMatrixCoeffs == ColorAspects::MatrixOther || 323 !sIsoMatrixCoeffs.map(aspects.mMatrixCoeffs, coeffs)) { 324 CHECK(sIsoMatrixCoeffs.map(ColorAspects::MatrixUnspecified, coeffs)); 325 } 326 *fullRange = aspects.mRange == ColorAspects::RangeFull; 327} 328 329// static 330void ColorUtils::convertIsoColorAspectsToCodecAspects( 331 int32_t primaries, int32_t transfer, int32_t coeffs, bool fullRange, 332 ColorAspects &aspects) { 333 if (!sIsoPrimaries.map(primaries, &aspects.mPrimaries)) { 334 aspects.mPrimaries = ColorAspects::PrimariesUnspecified; 335 } 336 if (!sIsoTransfers.map(transfer, &aspects.mTransfer)) { 337 aspects.mTransfer = ColorAspects::TransferUnspecified; 338 } 339 if (!sIsoMatrixCoeffs.map(coeffs, &aspects.mMatrixCoeffs)) { 340 aspects.mMatrixCoeffs = ColorAspects::MatrixUnspecified; 341 } 342 aspects.mRange = fullRange ? ColorAspects::RangeFull : ColorAspects::RangeLimited; 343} 344 345// static 346ColorAspects ColorUtils::unpackToColorAspects(uint32_t packed) { 347 ColorAspects aspects; 348 aspects.mRange = (ColorAspects::Range)((packed >> 24) & 0xFF); 349 aspects.mPrimaries = (ColorAspects::Primaries)((packed >> 16) & 0xFF); 350 aspects.mMatrixCoeffs = (ColorAspects::MatrixCoeffs)((packed >> 8) & 0xFF); 351 aspects.mTransfer = (ColorAspects::Transfer)(packed & 0xFF); 352 353 return aspects; 354} 355 356// static 357uint32_t ColorUtils::packToU32(const ColorAspects &aspects) { 358 return (aspects.mRange << 24) | (aspects.mPrimaries << 16) 359 | (aspects.mMatrixCoeffs << 8) | aspects.mTransfer; 360} 361 362// static 363void ColorUtils::setDefaultCodecColorAspectsIfNeeded( 364 ColorAspects &aspects, int32_t width, int32_t height) { 365 ColorAspects::MatrixCoeffs coeffs; 366 ColorAspects::Primaries primaries; 367 368 // Default to BT2020, BT709 or BT601 based on size. Allow 2.35:1 aspect ratio. Limit BT601 369 // to PAL or smaller, BT2020 to 4K or larger, leaving BT709 for all resolutions in between. 370 if (width >= 3840 || height >= 3840 || width * (int64_t)height >= 3840 * 1634) { 371 primaries = ColorAspects::PrimariesBT2020; 372 coeffs = ColorAspects::MatrixBT2020; 373 } else if ((width <= 720 && height > 480 && height <= 576) 374 || (height <= 720 && width > 480 && width <= 576)) { 375 primaries = ColorAspects::PrimariesBT601_6_625; 376 coeffs = ColorAspects::MatrixBT601_6; 377 } else if ((width <= 720 && height <= 480) || (height <= 720 && width <= 480)) { 378 primaries = ColorAspects::PrimariesBT601_6_525; 379 coeffs = ColorAspects::MatrixBT601_6; 380 } else { 381 primaries = ColorAspects::PrimariesBT709_5; 382 coeffs = ColorAspects::MatrixBT709_5; 383 } 384 385 if (aspects.mRange == ColorAspects::RangeUnspecified) { 386 aspects.mRange = ColorAspects::RangeLimited; 387 } 388 389 if (aspects.mPrimaries == ColorAspects::PrimariesUnspecified) { 390 aspects.mPrimaries = primaries; 391 } 392 if (aspects.mMatrixCoeffs == ColorAspects::MatrixUnspecified) { 393 aspects.mMatrixCoeffs = coeffs; 394 } 395 if (aspects.mTransfer == ColorAspects::TransferUnspecified) { 396 aspects.mTransfer = ColorAspects::TransferSMPTE170M; 397 } 398} 399 400// TODO: move this into a Video HAL 401ALookup<CU::ColorStandard, std::pair<CA::Primaries, CA::MatrixCoeffs>> sStandardFallbacks { 402 { 403 { CU::kColorStandardBT601_625, { CA::PrimariesBT709_5, CA::MatrixBT470_6M } }, 404 { CU::kColorStandardBT601_625, { CA::PrimariesBT709_5, CA::MatrixBT601_6 } }, 405 { CU::kColorStandardBT709, { CA::PrimariesBT709_5, CA::MatrixSMPTE240M } }, 406 { CU::kColorStandardBT709, { CA::PrimariesBT709_5, CA::MatrixBT2020 } }, 407 { CU::kColorStandardBT601_525, { CA::PrimariesBT709_5, CA::MatrixBT2020Constant } }, 408 409 { CU::kColorStandardBT2020Constant, 410 { CA::PrimariesBT470_6M, CA::MatrixBT2020Constant } }, 411 412 { CU::kColorStandardBT601_625, { CA::PrimariesBT601_6_625, CA::MatrixBT470_6M } }, 413 { CU::kColorStandardBT601_525, { CA::PrimariesBT601_6_625, CA::MatrixBT2020Constant } }, 414 415 { CU::kColorStandardBT601_525, { CA::PrimariesBT601_6_525, CA::MatrixBT470_6M } }, 416 { CU::kColorStandardBT601_525, { CA::PrimariesBT601_6_525, CA::MatrixBT2020Constant } }, 417 418 { CU::kColorStandardBT2020Constant, 419 { CA::PrimariesGenericFilm, CA::MatrixBT2020Constant } }, 420 } 421}; 422 423ALookup<CU::ColorStandard, CA::Primaries> sStandardPrimariesFallbacks { 424 { 425 { CU::kColorStandardFilm, CA::PrimariesGenericFilm }, 426 { CU::kColorStandardBT470M, CA::PrimariesBT470_6M }, 427 { CU::kColorStandardBT2020, CA::PrimariesBT2020 }, 428 { CU::kColorStandardBT601_525_Unadjusted, CA::PrimariesBT601_6_525 }, 429 { CU::kColorStandardBT601_625_Unadjusted, CA::PrimariesBT601_6_625 }, 430 } 431}; 432 433static ALookup<android_dataspace, android_dataspace> sLegacyDataSpaceToV0 { 434 { 435 { HAL_DATASPACE_SRGB, HAL_DATASPACE_V0_SRGB }, 436 { HAL_DATASPACE_BT709, HAL_DATASPACE_V0_BT709 }, 437 { HAL_DATASPACE_SRGB_LINEAR, HAL_DATASPACE_V0_SRGB_LINEAR }, 438 { HAL_DATASPACE_BT601_525, HAL_DATASPACE_V0_BT601_525 }, 439 { HAL_DATASPACE_BT601_625, HAL_DATASPACE_V0_BT601_625 }, 440 { HAL_DATASPACE_JFIF, HAL_DATASPACE_V0_JFIF }, 441 } 442}; 443 444bool ColorUtils::convertDataSpaceToV0(android_dataspace &dataSpace) { 445 (void)sLegacyDataSpaceToV0.lookup(dataSpace, &dataSpace); 446 return (dataSpace & 0xC000FFFF) == 0; 447} 448 449bool ColorUtils::checkIfAspectsChangedAndUnspecifyThem( 450 ColorAspects &aspects, const ColorAspects &orig, bool usePlatformAspects) { 451 // remove changed aspects (change them to Unspecified) 452 bool changed = false; 453 if (aspects.mRange && aspects.mRange != orig.mRange) { 454 aspects.mRange = ColorAspects::RangeUnspecified; 455 changed = true; 456 } 457 if (aspects.mPrimaries && aspects.mPrimaries != orig.mPrimaries) { 458 aspects.mPrimaries = ColorAspects::PrimariesUnspecified; 459 if (usePlatformAspects) { 460 aspects.mMatrixCoeffs = ColorAspects::MatrixUnspecified; 461 } 462 changed = true; 463 } 464 if (aspects.mMatrixCoeffs && aspects.mMatrixCoeffs != orig.mMatrixCoeffs) { 465 aspects.mMatrixCoeffs = ColorAspects::MatrixUnspecified; 466 if (usePlatformAspects) { 467 aspects.mPrimaries = ColorAspects::PrimariesUnspecified; 468 } 469 changed = true; 470 } 471 if (aspects.mTransfer && aspects.mTransfer != orig.mTransfer) { 472 aspects.mTransfer = ColorAspects::TransferUnspecified; 473 changed = true; 474 } 475 return changed; 476} 477 478// static 479android_dataspace ColorUtils::getDataSpaceForColorAspects(ColorAspects &aspects, bool mayExpand) { 480 // This platform implementation never expands color space (e.g. returns an expanded 481 // dataspace to use where the codec does in-the-background color space conversion) 482 mayExpand = false; 483 484 if (aspects.mRange == ColorAspects::RangeUnspecified 485 || aspects.mPrimaries == ColorAspects::PrimariesUnspecified 486 || aspects.mMatrixCoeffs == ColorAspects::MatrixUnspecified 487 || aspects.mTransfer == ColorAspects::TransferUnspecified) { 488 ALOGW("expected specified color aspects (%u:%u:%u:%u)", 489 aspects.mRange, aspects.mPrimaries, aspects.mMatrixCoeffs, aspects.mTransfer); 490 } 491 492 // default to video range and transfer 493 ColorRange range = kColorRangeLimited; 494 ColorTransfer transfer = kColorTransferSMPTE_170M; 495 (void)sRanges.map(aspects.mRange, &range); 496 (void)sTransfers.map(aspects.mTransfer, &transfer); 497 498 ColorStandard standard = kColorStandardBT709; 499 auto pair = std::make_pair(aspects.mPrimaries, aspects.mMatrixCoeffs); 500 if (!sStandards.map(pair, &standard)) { 501 if (!sStandardFallbacks.map(pair, &standard)) { 502 (void)sStandardPrimariesFallbacks.map(aspects.mPrimaries, &standard); 503 504 if (aspects.mMatrixCoeffs == ColorAspects::MatrixBT2020Constant) { 505 range = kColorRangeFull; 506 } 507 } 508 } 509 510 android_dataspace dataSpace = (android_dataspace)( 511 (range << HAL_DATASPACE_RANGE_SHIFT) | (standard << HAL_DATASPACE_STANDARD_SHIFT) | 512 (transfer << HAL_DATASPACE_TRANSFER_SHIFT)); 513 (void)sLegacyDataSpaceToV0.rlookup(dataSpace, &dataSpace); 514 515 if (!mayExpand) { 516 // update codec aspects based on dataspace 517 convertPlatformColorAspectsToCodecAspects(range, standard, transfer, aspects); 518 } 519 return dataSpace; 520} 521 522// static 523void ColorUtils::getColorConfigFromFormat( 524 const sp<AMessage> &format, int32_t *range, int32_t *standard, int32_t *transfer) { 525 if (!format->findInt32("color-range", range)) { 526 *range = kColorRangeUnspecified; 527 } 528 if (!format->findInt32("color-standard", standard)) { 529 *standard = kColorStandardUnspecified; 530 } 531 if (!format->findInt32("color-transfer", transfer)) { 532 *transfer = kColorTransferUnspecified; 533 } 534} 535 536// static 537void ColorUtils::copyColorConfig(const sp<AMessage> &source, sp<AMessage> &target) { 538 // 0 values are unspecified 539 int32_t value; 540 if (source->findInt32("color-range", &value)) { 541 target->setInt32("color-range", value); 542 } 543 if (source->findInt32("color-standard", &value)) { 544 target->setInt32("color-standard", value); 545 } 546 if (source->findInt32("color-transfer", &value)) { 547 target->setInt32("color-transfer", value); 548 } 549} 550 551// static 552void ColorUtils::getColorAspectsFromFormat(const sp<AMessage> &format, ColorAspects &aspects) { 553 int32_t range, standard, transfer; 554 getColorConfigFromFormat(format, &range, &standard, &transfer); 555 556 if (convertPlatformColorAspectsToCodecAspects( 557 range, standard, transfer, aspects) != OK) { 558 ALOGW("Ignoring illegal color aspects(R:%d(%s), S:%d(%s), T:%d(%s))", 559 range, asString((ColorRange)range), 560 standard, asString((ColorStandard)standard), 561 transfer, asString((ColorTransfer)transfer)); 562 // Invalid values were converted to unspecified !params!, but otherwise were not changed 563 // For encoders, we leave these as is. For decoders, we will use default values. 564 } 565 ALOGV("Got color aspects (R:%d(%s), P:%d(%s), M:%d(%s), T:%d(%s)) " 566 "from format (out:R:%d(%s), S:%d(%s), T:%d(%s))", 567 aspects.mRange, asString(aspects.mRange), 568 aspects.mPrimaries, asString(aspects.mPrimaries), 569 aspects.mMatrixCoeffs, asString(aspects.mMatrixCoeffs), 570 aspects.mTransfer, asString(aspects.mTransfer), 571 range, asString((ColorRange)range), 572 standard, asString((ColorStandard)standard), 573 transfer, asString((ColorTransfer)transfer)); 574} 575 576// static 577void ColorUtils::setColorAspectsIntoFormat( 578 const ColorAspects &aspects, sp<AMessage> &format, bool force) { 579 int32_t range = 0, standard = 0, transfer = 0; 580 convertCodecColorAspectsToPlatformAspects(aspects, &range, &standard, &transfer); 581 // save set values to base output format 582 // (encoder input format will read back actually supported values by the codec) 583 if (range != 0 || force) { 584 format->setInt32("color-range", range); 585 } 586 if (standard != 0 || force) { 587 format->setInt32("color-standard", standard); 588 } 589 if (transfer != 0 || force) { 590 format->setInt32("color-transfer", transfer); 591 } 592 ALOGV("Setting color aspects (R:%d(%s), P:%d(%s), M:%d(%s), T:%d(%s)) " 593 "into format (out:R:%d(%s), S:%d(%s), T:%d(%s))", 594 aspects.mRange, asString(aspects.mRange), 595 aspects.mPrimaries, asString(aspects.mPrimaries), 596 aspects.mMatrixCoeffs, asString(aspects.mMatrixCoeffs), 597 aspects.mTransfer, asString(aspects.mTransfer), 598 range, asString((ColorRange)range), 599 standard, asString((ColorStandard)standard), 600 transfer, asString((ColorTransfer)transfer)); 601} 602 603// static 604void ColorUtils::setHDRStaticInfoIntoFormat( 605 const HDRStaticInfo &info, sp<AMessage> &format) { 606 sp<ABuffer> infoBuffer = new ABuffer(25); 607 608 // Convert the data in infoBuffer to little endian format as defined by CTA-861-3 609 uint8_t *data = infoBuffer->data(); 610 // Static_Metadata_Descriptor_ID 611 data[0] = info.mID; 612 613 // display primary 0 614 data[1] = LO_UINT16(info.sType1.mR.x); 615 data[2] = HI_UINT16(info.sType1.mR.x); 616 data[3] = LO_UINT16(info.sType1.mR.y); 617 data[4] = HI_UINT16(info.sType1.mR.y); 618 619 // display primary 1 620 data[5] = LO_UINT16(info.sType1.mG.x); 621 data[6] = HI_UINT16(info.sType1.mG.x); 622 data[7] = LO_UINT16(info.sType1.mG.y); 623 data[8] = HI_UINT16(info.sType1.mG.y); 624 625 // display primary 2 626 data[9] = LO_UINT16(info.sType1.mB.x); 627 data[10] = HI_UINT16(info.sType1.mB.x); 628 data[11] = LO_UINT16(info.sType1.mB.y); 629 data[12] = HI_UINT16(info.sType1.mB.y); 630 631 // white point 632 data[13] = LO_UINT16(info.sType1.mW.x); 633 data[14] = HI_UINT16(info.sType1.mW.x); 634 data[15] = LO_UINT16(info.sType1.mW.y); 635 data[16] = HI_UINT16(info.sType1.mW.y); 636 637 // MaxDisplayLuminance 638 data[17] = LO_UINT16(info.sType1.mMaxDisplayLuminance); 639 data[18] = HI_UINT16(info.sType1.mMaxDisplayLuminance); 640 641 // MinDisplayLuminance 642 data[19] = LO_UINT16(info.sType1.mMinDisplayLuminance); 643 data[20] = HI_UINT16(info.sType1.mMinDisplayLuminance); 644 645 // MaxContentLightLevel 646 data[21] = LO_UINT16(info.sType1.mMaxContentLightLevel); 647 data[22] = HI_UINT16(info.sType1.mMaxContentLightLevel); 648 649 // MaxFrameAverageLightLevel 650 data[23] = LO_UINT16(info.sType1.mMaxFrameAverageLightLevel); 651 data[24] = HI_UINT16(info.sType1.mMaxFrameAverageLightLevel); 652 653 format->setBuffer("hdr-static-info", infoBuffer); 654} 655 656// a simple method copied from Utils.cpp 657static uint16_t U16LE_AT(const uint8_t *ptr) { 658 return ptr[0] | (ptr[1] << 8); 659} 660 661// static 662bool ColorUtils::getHDRStaticInfoFromFormat(const sp<AMessage> &format, HDRStaticInfo *info) { 663 sp<ABuffer> buf; 664 if (!format->findBuffer("hdr-static-info", &buf)) { 665 return false; 666 } 667 668 // TODO: Make this more flexible when adding more members to HDRStaticInfo 669 if (buf->size() != 25 /* static Metadata Type 1 size */) { 670 ALOGW("Ignore invalid HDRStaticInfo with size: %zu", buf->size()); 671 return false; 672 } 673 674 const uint8_t *data = buf->data(); 675 if (*data != HDRStaticInfo::kType1) { 676 ALOGW("Unsupported static Metadata Type %u", *data); 677 return false; 678 } 679 680 info->mID = HDRStaticInfo::kType1; 681 info->sType1.mR.x = U16LE_AT(&data[1]); 682 info->sType1.mR.y = U16LE_AT(&data[3]); 683 info->sType1.mG.x = U16LE_AT(&data[5]); 684 info->sType1.mG.y = U16LE_AT(&data[7]); 685 info->sType1.mB.x = U16LE_AT(&data[9]); 686 info->sType1.mB.y = U16LE_AT(&data[11]); 687 info->sType1.mW.x = U16LE_AT(&data[13]); 688 info->sType1.mW.y = U16LE_AT(&data[15]); 689 info->sType1.mMaxDisplayLuminance = U16LE_AT(&data[17]); 690 info->sType1.mMinDisplayLuminance = U16LE_AT(&data[19]); 691 info->sType1.mMaxContentLightLevel = U16LE_AT(&data[21]); 692 info->sType1.mMaxFrameAverageLightLevel = U16LE_AT(&data[23]); 693 694 ALOGV("Got HDRStaticInfo from config (R: %u %u, G: %u %u, B: %u, %u, W: %u, %u, " 695 "MaxDispL: %u, MinDispL: %u, MaxContentL: %u, MaxFrameAvgL: %u)", 696 info->sType1.mR.x, info->sType1.mR.y, info->sType1.mG.x, info->sType1.mG.y, 697 info->sType1.mB.x, info->sType1.mB.y, info->sType1.mW.x, info->sType1.mW.y, 698 info->sType1.mMaxDisplayLuminance, info->sType1.mMinDisplayLuminance, 699 info->sType1.mMaxContentLightLevel, info->sType1.mMaxFrameAverageLightLevel); 700 return true; 701} 702 703} // namespace android 704 705