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