ColorUtils.cpp revision 3a09d8d6f909063990a5681b15a442b2ba8ce54a
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 22#include <media/stagefright/foundation/ADebug.h> 23#include <media/stagefright/foundation/ALookup.h> 24#include <media/stagefright/foundation/ColorUtils.h> 25 26namespace android { 27 28// shortcut names for brevity in the following tables 29typedef ColorAspects CA; 30typedef ColorUtils CU; 31 32ALookup<CU::ColorRange, CA::Range> sRanges{ 33 { 34 { CU::kColorRangeLimited, CA::RangeLimited }, 35 { CU::kColorRangeFull, CA::RangeFull }, 36 { CU::kColorRangeUnspecified, CA::RangeUnspecified }, 37 } 38}; 39 40ALookup<CU::ColorStandard, std::pair<CA::Primaries, CA::MatrixCoeffs>> sStandards { 41 { 42 { CU::kColorStandardUnspecified, { CA::PrimariesUnspecified, CA::MatrixUnspecified } }, 43 { CU::kColorStandardBT709, { CA::PrimariesBT709_5, CA::MatrixBT709_5 } }, 44 { CU::kColorStandardBT601_625, { CA::PrimariesBT601_6_625, CA::MatrixBT601_6 } }, 45 { CU::kColorStandardBT601_625_Unadjusted, 46 // this is a really close match 47 { CA::PrimariesBT601_6_625, CA::MatrixBT709_5 } }, 48 { CU::kColorStandardBT601_525, { CA::PrimariesBT601_6_525, CA::MatrixBT601_6 } }, 49 { CU::kColorStandardBT601_525_Unadjusted, 50 { CA::PrimariesBT601_6_525, CA::MatrixSMPTE240M } }, 51 { CU::kColorStandardBT2020, { CA::PrimariesBT2020, CA::MatrixBT2020 } }, 52 { CU::kColorStandardBT2020Constant, { CA::PrimariesBT2020, CA::MatrixBT2020Constant } }, 53 { CU::kColorStandardBT470M, { CA::PrimariesBT470_6M, CA::MatrixBT470_6M } }, 54 // NOTE: there is no close match to the matrix used by standard film, chose closest 55 { CU::kColorStandardFilm, { CA::PrimariesGenericFilm, CA::MatrixBT2020 } }, 56 } 57}; 58 59ALookup<CU::ColorTransfer, CA::Transfer> sTransfers{ 60 { 61 { CU::kColorTransferUnspecified, CA::TransferUnspecified }, 62 { CU::kColorTransferLinear, CA::TransferLinear }, 63 { CU::kColorTransferSRGB, CA::TransferSRGB }, 64 { CU::kColorTransferSMPTE_170M, CA::TransferSMPTE170M }, 65 { CU::kColorTransferGamma22, CA::TransferGamma22 }, 66 { CU::kColorTransferGamma28, CA::TransferGamma28 }, 67 { CU::kColorTransferST2084, CA::TransferST2084 }, 68 { CU::kColorTransferHLG, CA::TransferHLG }, 69 } 70}; 71 72static bool isValid(ColorAspects::Primaries p) { 73 return p <= ColorAspects::PrimariesOther; 74} 75 76static bool isDefined(ColorAspects::Primaries p) { 77 return p <= ColorAspects::PrimariesBT2020; 78} 79 80static bool isValid(ColorAspects::MatrixCoeffs c) { 81 return c <= ColorAspects::MatrixOther; 82} 83 84static bool isDefined(ColorAspects::MatrixCoeffs c) { 85 return c <= ColorAspects::MatrixBT2020Constant; 86} 87 88//static 89int32_t ColorUtils::wrapColorAspectsIntoColorStandard( 90 ColorAspects::Primaries primaries, ColorAspects::MatrixCoeffs coeffs) { 91 ColorStandard res; 92 if (sStandards.map(std::make_pair(primaries, coeffs), &res)) { 93 return res; 94 } else if (!isValid(primaries) || !isValid(coeffs)) { 95 return kColorStandardUnspecified; 96 } 97 98 // check platform media limits 99 uint32_t numPrimaries = ColorAspects::PrimariesBT2020 + 1; 100 if (isDefined(primaries) && isDefined(coeffs)) { 101 return kColorStandardExtendedStart + primaries + coeffs * numPrimaries; 102 } else { 103 return kColorStandardVendorStart + primaries + coeffs * 0x100; 104 } 105} 106 107//static 108status_t ColorUtils::unwrapColorAspectsFromColorStandard( 109 int32_t standard, 110 ColorAspects::Primaries *primaries, ColorAspects::MatrixCoeffs *coeffs) { 111 std::pair<ColorAspects::Primaries, ColorAspects::MatrixCoeffs> res; 112 if (sStandards.map((ColorStandard)standard, &res)) { 113 *primaries = res.first; 114 *coeffs = res.second; 115 return OK; 116 } 117 118 int32_t start = kColorStandardExtendedStart; 119 int32_t numPrimaries = ColorAspects::PrimariesBT2020 + 1; 120 int32_t numCoeffs = ColorAspects::MatrixBT2020Constant + 1; 121 if (standard >= (int32_t)kColorStandardVendorStart) { 122 start = kColorStandardVendorStart; 123 numPrimaries = ColorAspects::PrimariesOther + 1; // 0x100 124 numCoeffs = ColorAspects::MatrixOther + 1; // 0x100; 125 } 126 if (standard >= start && standard < start + numPrimaries * numCoeffs) { 127 int32_t product = standard - start; 128 *primaries = (ColorAspects::Primaries)(product % numPrimaries); 129 *coeffs = (ColorAspects::MatrixCoeffs)(product / numPrimaries); 130 return OK; 131 } 132 *primaries = ColorAspects::PrimariesOther; 133 *coeffs = ColorAspects::MatrixOther; 134 return BAD_VALUE; 135} 136 137static bool isValid(ColorAspects::Range r) { 138 return r <= ColorAspects::RangeOther; 139} 140 141static bool isDefined(ColorAspects::Range r) { 142 return r <= ColorAspects::RangeLimited; 143} 144 145// static 146int32_t ColorUtils::wrapColorAspectsIntoColorRange(ColorAspects::Range range) { 147 ColorRange res; 148 if (sRanges.map(range, &res)) { 149 return res; 150 } else if (!isValid(range)) { 151 return kColorRangeUnspecified; 152 } else { 153 CHECK(!isDefined(range)); 154 // all platform values are in sRanges 155 return kColorRangeVendorStart + range; 156 } 157} 158 159//static 160status_t ColorUtils::unwrapColorAspectsFromColorRange( 161 int32_t range, ColorAspects::Range *aspect) { 162 if (sRanges.map((ColorRange)range, aspect)) { 163 return OK; 164 } 165 166 int32_t start = kColorRangeVendorStart; 167 int32_t numRanges = ColorAspects::RangeOther + 1; // 0x100 168 if (range >= start && range < start + numRanges) { 169 *aspect = (ColorAspects::Range)(range - start); 170 return OK; 171 } 172 *aspect = ColorAspects::RangeOther; 173 return BAD_VALUE; 174} 175 176static bool isValid(ColorAspects::Transfer t) { 177 return t <= ColorAspects::TransferOther; 178} 179 180static bool isDefined(ColorAspects::Transfer t) { 181 return t <= ColorAspects::TransferHLG 182 || (t >= ColorAspects::TransferSMPTE240M && t <= ColorAspects::TransferST428); 183} 184 185// static 186int32_t ColorUtils::wrapColorAspectsIntoColorTransfer( 187 ColorAspects::Transfer transfer) { 188 ColorTransfer res; 189 if (sTransfers.map(transfer, &res)) { 190 return res; 191 } else if (!isValid(transfer)) { 192 return kColorTransferUnspecified; 193 } else if (isDefined(transfer)) { 194 return kColorTransferExtendedStart + transfer; 195 } else { 196 // all platform values are in sRanges 197 return kColorTransferVendorStart + transfer; 198 } 199} 200 201//static 202status_t ColorUtils::unwrapColorAspectsFromColorTransfer( 203 int32_t transfer, ColorAspects::Transfer *aspect) { 204 if (sTransfers.map((ColorTransfer)transfer, aspect)) { 205 return OK; 206 } 207 208 int32_t start = kColorTransferExtendedStart; 209 int32_t numTransfers = ColorAspects::TransferST428 + 1; 210 if (transfer >= (int32_t)kColorTransferVendorStart) { 211 start = kColorTransferVendorStart; 212 numTransfers = ColorAspects::TransferOther + 1; // 0x100 213 } 214 if (transfer >= start && transfer < start + numTransfers) { 215 *aspect = (ColorAspects::Transfer)(transfer - start); 216 return OK; 217 } 218 *aspect = ColorAspects::TransferOther; 219 return BAD_VALUE; 220} 221 222// static 223status_t ColorUtils::convertPlatformColorAspectsToCodecAspects( 224 int32_t range, int32_t standard, int32_t transfer, ColorAspects &aspects) { 225 status_t res1 = unwrapColorAspectsFromColorRange(range, &aspects.mRange); 226 status_t res2 = unwrapColorAspectsFromColorStandard( 227 standard, &aspects.mPrimaries, &aspects.mMatrixCoeffs); 228 status_t res3 = unwrapColorAspectsFromColorTransfer(transfer, &aspects.mTransfer); 229 return res1 != OK ? res1 : (res2 != OK ? res2 : res3); 230} 231 232// static 233status_t ColorUtils::convertCodecColorAspectsToPlatformAspects( 234 const ColorAspects &aspects, int32_t *range, int32_t *standard, int32_t *transfer) { 235 *range = wrapColorAspectsIntoColorRange(aspects.mRange); 236 *standard = wrapColorAspectsIntoColorStandard(aspects.mPrimaries, aspects.mMatrixCoeffs); 237 *transfer = wrapColorAspectsIntoColorTransfer(aspects.mTransfer); 238 if (isValid(aspects.mRange) && isValid(aspects.mPrimaries) 239 && isValid(aspects.mMatrixCoeffs) && isValid(aspects.mTransfer)) { 240 return OK; 241 } else { 242 return BAD_VALUE; 243 } 244} 245 246// static 247void ColorUtils::setDefaultPlatformColorAspectsIfNeeded( 248 int32_t &range, int32_t &standard, int32_t &transfer, 249 int32_t width, int32_t height) { 250 if (range == ColorUtils::kColorRangeUnspecified) { 251 range = ColorUtils::kColorRangeLimited; 252 } 253 254 if (standard == ColorUtils::kColorStandardUnspecified) { 255 // Default to BT2020, BT709 or BT601 based on size. Allow 2.35:1 aspect ratio. Limit BT601 256 // to PAL or smaller, BT2020 to 4K or larger, leaving BT709 for all resolutions in between. 257 if (width >= 3840 || height >= 3840 || width * (int64_t)height >= 3840 * 1634) { 258 standard = ColorUtils::kColorStandardBT2020; 259 } else if ((width <= 720 && height > 480) || (height <= 720 && width > 480)) { 260 standard = ColorUtils::kColorStandardBT601_625; 261 } else if ((width <= 720 && height <= 480) || (height <= 720 && width <= 480)) { 262 standard = ColorUtils::kColorStandardBT601_525; 263 } else { 264 standard = ColorUtils::kColorStandardBT709; 265 } 266 } 267 268 if (transfer == ColorUtils::kColorTransferUnspecified) { 269 transfer = ColorUtils::kColorTransferSMPTE_170M; 270 } 271} 272 273// static 274void ColorUtils::setDefaultCodecColorAspectsIfNeeded( 275 ColorAspects &aspects, int32_t width, int32_t height) { 276 ColorAspects::MatrixCoeffs coeffs; 277 ColorAspects::Primaries primaries; 278 279 // Default to BT2020, BT709 or BT601 based on size. Allow 2.35:1 aspect ratio. Limit BT601 280 // to PAL or smaller, BT2020 to 4K or larger, leaving BT709 for all resolutions in between. 281 if (width >= 3840 || height >= 3840 || width * (int64_t)height >= 3840 * 1634) { 282 primaries = ColorAspects::PrimariesBT2020; 283 coeffs = ColorAspects::MatrixBT2020; 284 } else if ((width <= 720 && height > 480 && height <= 576) 285 || (height <= 720 && width > 480 && width <= 576)) { 286 primaries = ColorAspects::PrimariesBT601_6_625; 287 coeffs = ColorAspects::MatrixBT601_6; 288 } else if ((width <= 720 && height <= 480) || (height <= 720 && width <= 480)) { 289 primaries = ColorAspects::PrimariesBT601_6_525; 290 coeffs = ColorAspects::MatrixBT601_6; 291 } else { 292 primaries = ColorAspects::PrimariesBT709_5; 293 coeffs = ColorAspects::MatrixBT709_5; 294 } 295 296 if (aspects.mRange == ColorAspects::RangeUnspecified) { 297 aspects.mRange = ColorAspects::RangeLimited; 298 } 299 300 if (aspects.mPrimaries == ColorAspects::PrimariesUnspecified) { 301 aspects.mPrimaries = primaries; 302 } 303 if (aspects.mMatrixCoeffs == ColorAspects::MatrixUnspecified) { 304 aspects.mMatrixCoeffs = coeffs; 305 } 306 if (aspects.mTransfer == ColorAspects::TransferUnspecified) { 307 aspects.mTransfer = ColorAspects::TransferSMPTE170M; 308 } 309} 310 311} // namespace android 312 313