Home | History | Annotate | Download | only in foundation
      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         { 18, ColorAspects::TransferHLG },
    290     }
    291 };
    292 
    293 const static
    294 ALookup<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
    311 void 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
    330 void 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
    346 ColorAspects 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
    357 uint32_t ColorUtils::packToU32(const ColorAspects &aspects) {
    358     return (aspects.mRange << 24) | (aspects.mPrimaries << 16)
    359             | (aspects.mMatrixCoeffs << 8) | aspects.mTransfer;
    360 }
    361 
    362 // static
    363 void 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
    401 const static
    402 ALookup<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 
    424 const static
    425 ALookup<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 
    435 const static
    436 ALookup<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 
    450 const static
    451 ALookup<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
    468 static_assert(CU::kColorStandardUnspecified == 0, "SDK mismatch"); // N
    469 static_assert(CU::kColorStandardBT709 == 1, "SDK mismatch"); // N
    470 static_assert(CU::kColorStandardBT601_625 == 2, "SDK mismatch"); // N
    471 static_assert(CU::kColorStandardBT601_525 == 4, "SDK mismatch"); // N
    472 static_assert(CU::kColorStandardBT2020 == 6, "SDK mismatch"); // N
    473 
    474 const static
    475 ALookup<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
    489 static_assert(CU::kColorTransferUnspecified == 0, "SDK mismatch"); // N
    490 static_assert(CU::kColorTransferLinear == 1, "SDK mismatch"); // N
    491 static_assert(CU::kColorTransferSRGB == 2, "SDK mismatch"); // N
    492 static_assert(CU::kColorTransferSMPTE_170M == 3, "SDK mismatch"); // N
    493 static_assert(CU::kColorTransferST2084 == 6, "SDK mismatch"); // N
    494 static_assert(CU::kColorTransferHLG == 7, "SDK mismatch"); // N
    495 
    496 const static
    497 ALookup<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
    506 static_assert(CU::kColorRangeUnspecified == 0, "SDK mismatch"); // N
    507 static_assert(CU::kColorRangeFull == 1, "SDK mismatch"); // N
    508 static_assert(CU::kColorRangeLimited == 2, "SDK mismatch"); // N
    509 
    510 #undef GET_HAL_BITFIELD
    511 #undef GET_HAL_ENUM
    512 
    513 
    514 bool ColorUtils::convertDataSpaceToV0(android_dataspace &dataSpace) {
    515     (void)sLegacyDataSpaceToV0.lookup(dataSpace, &dataSpace);
    516     return (dataSpace & 0xC000FFFF) == 0;
    517 }
    518 
    519 bool 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
    549 android_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
    607 void 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
    621 void 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
    636 void 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
    661 void 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
    688 void 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
    741 static uint16_t U16LE_AT(const uint8_t *ptr) {
    742     return ptr[0] | (ptr[1] << 8);
    743 }
    744 
    745 // static
    746 bool 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