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 401const static 402ALookup<CU::ColorStandard, std::pair<CA::Primaries, CA::MatrixCoeffs>> sStandardFallbacks { 403 { 404 { CU::kColorStandardBT601_625, { CA::PrimariesBT709_5, CA::MatrixBT470_6M } }, 405 { CU::kColorStandardBT601_625, { CA::PrimariesBT709_5, CA::MatrixBT601_6 } }, 406 { CU::kColorStandardBT709, { CA::PrimariesBT709_5, CA::MatrixSMPTE240M } }, 407 { CU::kColorStandardBT709, { CA::PrimariesBT709_5, CA::MatrixBT2020 } }, 408 { CU::kColorStandardBT601_525, { CA::PrimariesBT709_5, CA::MatrixBT2020Constant } }, 409 410 { CU::kColorStandardBT2020Constant, 411 { CA::PrimariesBT470_6M, CA::MatrixBT2020Constant } }, 412 413 { CU::kColorStandardBT601_625, { CA::PrimariesBT601_6_625, CA::MatrixBT470_6M } }, 414 { CU::kColorStandardBT601_525, { CA::PrimariesBT601_6_625, CA::MatrixBT2020Constant } }, 415 416 { CU::kColorStandardBT601_525, { CA::PrimariesBT601_6_525, CA::MatrixBT470_6M } }, 417 { CU::kColorStandardBT601_525, { CA::PrimariesBT601_6_525, CA::MatrixBT2020Constant } }, 418 419 { CU::kColorStandardBT2020Constant, 420 { CA::PrimariesGenericFilm, CA::MatrixBT2020Constant } }, 421 } 422}; 423 424const static 425ALookup<CU::ColorStandard, CA::Primaries> sStandardPrimariesFallbacks { 426 { 427 { CU::kColorStandardFilm, CA::PrimariesGenericFilm }, 428 { CU::kColorStandardBT470M, CA::PrimariesBT470_6M }, 429 { CU::kColorStandardBT2020, CA::PrimariesBT2020 }, 430 { CU::kColorStandardBT601_525_Unadjusted, CA::PrimariesBT601_6_525 }, 431 { CU::kColorStandardBT601_625_Unadjusted, CA::PrimariesBT601_6_625 }, 432 } 433}; 434 435const static 436ALookup<android_dataspace, android_dataspace> sLegacyDataSpaceToV0 { 437 { 438 { HAL_DATASPACE_SRGB, HAL_DATASPACE_V0_SRGB }, 439 { HAL_DATASPACE_BT709, HAL_DATASPACE_V0_BT709 }, 440 { HAL_DATASPACE_SRGB_LINEAR, HAL_DATASPACE_V0_SRGB_LINEAR }, 441 { HAL_DATASPACE_BT601_525, HAL_DATASPACE_V0_BT601_525 }, 442 { HAL_DATASPACE_BT601_625, HAL_DATASPACE_V0_BT601_625 }, 443 { HAL_DATASPACE_JFIF, HAL_DATASPACE_V0_JFIF }, 444 } 445}; 446 447#define GET_HAL_ENUM(class, name) HAL_DATASPACE_##class##name 448#define GET_HAL_BITFIELD(class, name) (GET_HAL_ENUM(class, _##name) >> GET_HAL_ENUM(class, _SHIFT)) 449 450const static 451ALookup<CU::ColorStandard, uint32_t> sGfxStandards { 452 { 453 { CU::kColorStandardUnspecified, GET_HAL_BITFIELD(STANDARD, UNSPECIFIED) }, 454 { CU::kColorStandardBT709, GET_HAL_BITFIELD(STANDARD, BT709) }, 455 { CU::kColorStandardBT601_625, GET_HAL_BITFIELD(STANDARD, BT601_625) }, 456 { CU::kColorStandardBT601_625_Unadjusted, GET_HAL_BITFIELD(STANDARD, BT601_625_UNADJUSTED) }, 457 { CU::kColorStandardBT601_525, GET_HAL_BITFIELD(STANDARD, BT601_525) }, 458 { CU::kColorStandardBT601_525_Unadjusted, GET_HAL_BITFIELD(STANDARD, BT601_525_UNADJUSTED) }, 459 { CU::kColorStandardBT2020, GET_HAL_BITFIELD(STANDARD, BT2020) }, 460 { CU::kColorStandardBT2020Constant, GET_HAL_BITFIELD(STANDARD, BT2020_CONSTANT_LUMINANCE) }, 461 { CU::kColorStandardBT470M, GET_HAL_BITFIELD(STANDARD, BT470M) }, 462 { CU::kColorStandardFilm, GET_HAL_BITFIELD(STANDARD, FILM) }, 463 { CU::kColorStandardDCI_P3, GET_HAL_BITFIELD(STANDARD, DCI_P3) }, 464 } 465}; 466 467// verify public values are stable 468static_assert(CU::kColorStandardUnspecified == 0, "SDK mismatch"); // N 469static_assert(CU::kColorStandardBT709 == 1, "SDK mismatch"); // N 470static_assert(CU::kColorStandardBT601_625 == 2, "SDK mismatch"); // N 471static_assert(CU::kColorStandardBT601_525 == 4, "SDK mismatch"); // N 472static_assert(CU::kColorStandardBT2020 == 6, "SDK mismatch"); // N 473 474const static 475ALookup<CU::ColorTransfer, uint32_t> sGfxTransfers { 476 { 477 { CU::kColorTransferUnspecified, GET_HAL_BITFIELD(TRANSFER, UNSPECIFIED) }, 478 { CU::kColorTransferLinear, GET_HAL_BITFIELD(TRANSFER, LINEAR) }, 479 { CU::kColorTransferSRGB, GET_HAL_BITFIELD(TRANSFER, SRGB) }, 480 { CU::kColorTransferSMPTE_170M, GET_HAL_BITFIELD(TRANSFER, SMPTE_170M) }, 481 { CU::kColorTransferGamma22, GET_HAL_BITFIELD(TRANSFER, GAMMA2_2) }, 482 { CU::kColorTransferGamma28, GET_HAL_BITFIELD(TRANSFER, GAMMA2_8) }, 483 { CU::kColorTransferST2084, GET_HAL_BITFIELD(TRANSFER, ST2084) }, 484 { CU::kColorTransferHLG, GET_HAL_BITFIELD(TRANSFER, HLG) }, 485 } 486}; 487 488// verify public values are stable 489static_assert(CU::kColorTransferUnspecified == 0, "SDK mismatch"); // N 490static_assert(CU::kColorTransferLinear == 1, "SDK mismatch"); // N 491static_assert(CU::kColorTransferSRGB == 2, "SDK mismatch"); // N 492static_assert(CU::kColorTransferSMPTE_170M == 3, "SDK mismatch"); // N 493static_assert(CU::kColorTransferST2084 == 6, "SDK mismatch"); // N 494static_assert(CU::kColorTransferHLG == 7, "SDK mismatch"); // N 495 496const static 497ALookup<CU::ColorRange, uint32_t> sGfxRanges { 498 { 499 { CU::kColorRangeUnspecified, GET_HAL_BITFIELD(RANGE, UNSPECIFIED) }, 500 { CU::kColorRangeFull, GET_HAL_BITFIELD(RANGE, FULL) }, 501 { CU::kColorRangeLimited, GET_HAL_BITFIELD(RANGE, LIMITED) }, 502 } 503}; 504 505// verify public values are stable 506static_assert(CU::kColorRangeUnspecified == 0, "SDK mismatch"); // N 507static_assert(CU::kColorRangeFull == 1, "SDK mismatch"); // N 508static_assert(CU::kColorRangeLimited == 2, "SDK mismatch"); // N 509 510#undef GET_HAL_BITFIELD 511#undef GET_HAL_ENUM 512 513 514bool ColorUtils::convertDataSpaceToV0(android_dataspace &dataSpace) { 515 (void)sLegacyDataSpaceToV0.lookup(dataSpace, &dataSpace); 516 return (dataSpace & 0xC000FFFF) == 0; 517} 518 519bool ColorUtils::checkIfAspectsChangedAndUnspecifyThem( 520 ColorAspects &aspects, const ColorAspects &orig, bool usePlatformAspects) { 521 // remove changed aspects (change them to Unspecified) 522 bool changed = false; 523 if (aspects.mRange && aspects.mRange != orig.mRange) { 524 aspects.mRange = ColorAspects::RangeUnspecified; 525 changed = true; 526 } 527 if (aspects.mPrimaries && aspects.mPrimaries != orig.mPrimaries) { 528 aspects.mPrimaries = ColorAspects::PrimariesUnspecified; 529 if (usePlatformAspects) { 530 aspects.mMatrixCoeffs = ColorAspects::MatrixUnspecified; 531 } 532 changed = true; 533 } 534 if (aspects.mMatrixCoeffs && aspects.mMatrixCoeffs != orig.mMatrixCoeffs) { 535 aspects.mMatrixCoeffs = ColorAspects::MatrixUnspecified; 536 if (usePlatformAspects) { 537 aspects.mPrimaries = ColorAspects::PrimariesUnspecified; 538 } 539 changed = true; 540 } 541 if (aspects.mTransfer && aspects.mTransfer != orig.mTransfer) { 542 aspects.mTransfer = ColorAspects::TransferUnspecified; 543 changed = true; 544 } 545 return changed; 546} 547 548// static 549android_dataspace ColorUtils::getDataSpaceForColorAspects(ColorAspects &aspects, bool mayExpand) { 550 // This platform implementation never expands color space (e.g. returns an expanded 551 // dataspace to use where the codec does in-the-background color space conversion) 552 mayExpand = false; 553 554 if (aspects.mRange == ColorAspects::RangeUnspecified 555 || aspects.mPrimaries == ColorAspects::PrimariesUnspecified 556 || aspects.mMatrixCoeffs == ColorAspects::MatrixUnspecified 557 || aspects.mTransfer == ColorAspects::TransferUnspecified) { 558 ALOGW("expected specified color aspects (%u:%u:%u:%u)", 559 aspects.mRange, aspects.mPrimaries, aspects.mMatrixCoeffs, aspects.mTransfer); 560 } 561 562 // default to video range and transfer 563 ColorRange range = kColorRangeLimited; 564 ColorTransfer transfer = kColorTransferSMPTE_170M; 565 (void)sRanges.map(aspects.mRange, &range); 566 (void)sTransfers.map(aspects.mTransfer, &transfer); 567 568 ColorStandard standard = kColorStandardBT709; 569 auto pair = std::make_pair(aspects.mPrimaries, aspects.mMatrixCoeffs); 570 if (!sStandards.map(pair, &standard)) { 571 if (!sStandardFallbacks.map(pair, &standard)) { 572 (void)sStandardPrimariesFallbacks.map(aspects.mPrimaries, &standard); 573 574 if (aspects.mMatrixCoeffs == ColorAspects::MatrixBT2020Constant) { 575 range = kColorRangeFull; 576 } 577 } 578 } 579 580 // assume 1-to-1 mapping to HAL values (to deal with potential vendor extensions) 581 uint32_t gfxRange = range; 582 uint32_t gfxStandard = standard; 583 uint32_t gfxTransfer = transfer; 584 // TRICKY: use & to ensure all three mappings are completed 585 if (!(sGfxRanges.map(range, &gfxRange) & sGfxStandards.map(standard, &gfxStandard) 586 & sGfxTransfers.map(transfer, &gfxTransfer))) { 587 ALOGW("could not safely map platform color aspects (R:%u(%s) S:%u(%s) T:%u(%s) to " 588 "graphics dataspace (R:%u S:%u T:%u)", 589 range, asString(range), standard, asString(standard), transfer, asString(transfer), 590 gfxRange, gfxStandard, gfxTransfer); 591 } 592 593 android_dataspace dataSpace = (android_dataspace)( 594 (gfxRange << HAL_DATASPACE_RANGE_SHIFT) | 595 (gfxStandard << HAL_DATASPACE_STANDARD_SHIFT) | 596 (gfxTransfer << HAL_DATASPACE_TRANSFER_SHIFT)); 597 (void)sLegacyDataSpaceToV0.rlookup(dataSpace, &dataSpace); 598 599 if (!mayExpand) { 600 // update codec aspects based on dataspace 601 convertPlatformColorAspectsToCodecAspects(range, standard, transfer, aspects); 602 } 603 return dataSpace; 604} 605 606// static 607void ColorUtils::getColorConfigFromFormat( 608 const sp<AMessage> &format, int32_t *range, int32_t *standard, int32_t *transfer) { 609 if (!format->findInt32("color-range", range)) { 610 *range = kColorRangeUnspecified; 611 } 612 if (!format->findInt32("color-standard", standard)) { 613 *standard = kColorStandardUnspecified; 614 } 615 if (!format->findInt32("color-transfer", transfer)) { 616 *transfer = kColorTransferUnspecified; 617 } 618} 619 620// static 621void ColorUtils::copyColorConfig(const sp<AMessage> &source, sp<AMessage> &target) { 622 // 0 values are unspecified 623 int32_t value; 624 if (source->findInt32("color-range", &value)) { 625 target->setInt32("color-range", value); 626 } 627 if (source->findInt32("color-standard", &value)) { 628 target->setInt32("color-standard", value); 629 } 630 if (source->findInt32("color-transfer", &value)) { 631 target->setInt32("color-transfer", value); 632 } 633} 634 635// static 636void ColorUtils::getColorAspectsFromFormat(const sp<AMessage> &format, ColorAspects &aspects) { 637 int32_t range, standard, transfer; 638 getColorConfigFromFormat(format, &range, &standard, &transfer); 639 640 if (convertPlatformColorAspectsToCodecAspects( 641 range, standard, transfer, aspects) != OK) { 642 ALOGW("Ignoring illegal color aspects(R:%d(%s), S:%d(%s), T:%d(%s))", 643 range, asString((ColorRange)range), 644 standard, asString((ColorStandard)standard), 645 transfer, asString((ColorTransfer)transfer)); 646 // Invalid values were converted to unspecified !params!, but otherwise were not changed 647 // For encoders, we leave these as is. For decoders, we will use default values. 648 } 649 ALOGV("Got color aspects (R:%d(%s), P:%d(%s), M:%d(%s), T:%d(%s)) " 650 "from format (out:R:%d(%s), S:%d(%s), T:%d(%s))", 651 aspects.mRange, asString(aspects.mRange), 652 aspects.mPrimaries, asString(aspects.mPrimaries), 653 aspects.mMatrixCoeffs, asString(aspects.mMatrixCoeffs), 654 aspects.mTransfer, asString(aspects.mTransfer), 655 range, asString((ColorRange)range), 656 standard, asString((ColorStandard)standard), 657 transfer, asString((ColorTransfer)transfer)); 658} 659 660// static 661void ColorUtils::setColorAspectsIntoFormat( 662 const ColorAspects &aspects, sp<AMessage> &format, bool force) { 663 int32_t range = 0, standard = 0, transfer = 0; 664 convertCodecColorAspectsToPlatformAspects(aspects, &range, &standard, &transfer); 665 // save set values to base output format 666 // (encoder input format will read back actually supported values by the codec) 667 if (range != 0 || force) { 668 format->setInt32("color-range", range); 669 } 670 if (standard != 0 || force) { 671 format->setInt32("color-standard", standard); 672 } 673 if (transfer != 0 || force) { 674 format->setInt32("color-transfer", transfer); 675 } 676 ALOGV("Setting color aspects (R:%d(%s), P:%d(%s), M:%d(%s), T:%d(%s)) " 677 "into format (out:R:%d(%s), S:%d(%s), T:%d(%s))", 678 aspects.mRange, asString(aspects.mRange), 679 aspects.mPrimaries, asString(aspects.mPrimaries), 680 aspects.mMatrixCoeffs, asString(aspects.mMatrixCoeffs), 681 aspects.mTransfer, asString(aspects.mTransfer), 682 range, asString((ColorRange)range), 683 standard, asString((ColorStandard)standard), 684 transfer, asString((ColorTransfer)transfer)); 685} 686 687// static 688void ColorUtils::setHDRStaticInfoIntoFormat( 689 const HDRStaticInfo &info, sp<AMessage> &format) { 690 sp<ABuffer> infoBuffer = new ABuffer(25); 691 692 // Convert the data in infoBuffer to little endian format as defined by CTA-861-3 693 uint8_t *data = infoBuffer->data(); 694 // Static_Metadata_Descriptor_ID 695 data[0] = info.mID; 696 697 // display primary 0 698 data[1] = LO_UINT16(info.sType1.mR.x); 699 data[2] = HI_UINT16(info.sType1.mR.x); 700 data[3] = LO_UINT16(info.sType1.mR.y); 701 data[4] = HI_UINT16(info.sType1.mR.y); 702 703 // display primary 1 704 data[5] = LO_UINT16(info.sType1.mG.x); 705 data[6] = HI_UINT16(info.sType1.mG.x); 706 data[7] = LO_UINT16(info.sType1.mG.y); 707 data[8] = HI_UINT16(info.sType1.mG.y); 708 709 // display primary 2 710 data[9] = LO_UINT16(info.sType1.mB.x); 711 data[10] = HI_UINT16(info.sType1.mB.x); 712 data[11] = LO_UINT16(info.sType1.mB.y); 713 data[12] = HI_UINT16(info.sType1.mB.y); 714 715 // white point 716 data[13] = LO_UINT16(info.sType1.mW.x); 717 data[14] = HI_UINT16(info.sType1.mW.x); 718 data[15] = LO_UINT16(info.sType1.mW.y); 719 data[16] = HI_UINT16(info.sType1.mW.y); 720 721 // MaxDisplayLuminance 722 data[17] = LO_UINT16(info.sType1.mMaxDisplayLuminance); 723 data[18] = HI_UINT16(info.sType1.mMaxDisplayLuminance); 724 725 // MinDisplayLuminance 726 data[19] = LO_UINT16(info.sType1.mMinDisplayLuminance); 727 data[20] = HI_UINT16(info.sType1.mMinDisplayLuminance); 728 729 // MaxContentLightLevel 730 data[21] = LO_UINT16(info.sType1.mMaxContentLightLevel); 731 data[22] = HI_UINT16(info.sType1.mMaxContentLightLevel); 732 733 // MaxFrameAverageLightLevel 734 data[23] = LO_UINT16(info.sType1.mMaxFrameAverageLightLevel); 735 data[24] = HI_UINT16(info.sType1.mMaxFrameAverageLightLevel); 736 737 format->setBuffer("hdr-static-info", infoBuffer); 738} 739 740// a simple method copied from Utils.cpp 741static uint16_t U16LE_AT(const uint8_t *ptr) { 742 return ptr[0] | (ptr[1] << 8); 743} 744 745// static 746bool ColorUtils::getHDRStaticInfoFromFormat(const sp<AMessage> &format, HDRStaticInfo *info) { 747 sp<ABuffer> buf; 748 if (!format->findBuffer("hdr-static-info", &buf)) { 749 return false; 750 } 751 752 // TODO: Make this more flexible when adding more members to HDRStaticInfo 753 if (buf->size() != 25 /* static Metadata Type 1 size */) { 754 ALOGW("Ignore invalid HDRStaticInfo with size: %zu", buf->size()); 755 return false; 756 } 757 758 const uint8_t *data = buf->data(); 759 if (*data != HDRStaticInfo::kType1) { 760 ALOGW("Unsupported static Metadata Type %u", *data); 761 return false; 762 } 763 764 info->mID = HDRStaticInfo::kType1; 765 info->sType1.mR.x = U16LE_AT(&data[1]); 766 info->sType1.mR.y = U16LE_AT(&data[3]); 767 info->sType1.mG.x = U16LE_AT(&data[5]); 768 info->sType1.mG.y = U16LE_AT(&data[7]); 769 info->sType1.mB.x = U16LE_AT(&data[9]); 770 info->sType1.mB.y = U16LE_AT(&data[11]); 771 info->sType1.mW.x = U16LE_AT(&data[13]); 772 info->sType1.mW.y = U16LE_AT(&data[15]); 773 info->sType1.mMaxDisplayLuminance = U16LE_AT(&data[17]); 774 info->sType1.mMinDisplayLuminance = U16LE_AT(&data[19]); 775 info->sType1.mMaxContentLightLevel = U16LE_AT(&data[21]); 776 info->sType1.mMaxFrameAverageLightLevel = U16LE_AT(&data[23]); 777 778 ALOGV("Got HDRStaticInfo from config (R: %u %u, G: %u %u, B: %u, %u, W: %u, %u, " 779 "MaxDispL: %u, MinDispL: %u, MaxContentL: %u, MaxFrameAvgL: %u)", 780 info->sType1.mR.x, info->sType1.mR.y, info->sType1.mG.x, info->sType1.mG.y, 781 info->sType1.mB.x, info->sType1.mB.y, info->sType1.mW.x, info->sType1.mW.y, 782 info->sType1.mMaxDisplayLuminance, info->sType1.mMinDisplayLuminance, 783 info->sType1.mMaxContentLightLevel, info->sType1.mMaxFrameAverageLightLevel); 784 return true; 785} 786 787} // namespace android 788 789