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
isValid(ColorAspects::Primaries p)79 static bool isValid(ColorAspects::Primaries p) {
80 return p <= ColorAspects::PrimariesOther;
81 }
82
isDefined(ColorAspects::Primaries p)83 static bool isDefined(ColorAspects::Primaries p) {
84 return p <= ColorAspects::PrimariesBT2020;
85 }
86
isValid(ColorAspects::MatrixCoeffs c)87 static bool isValid(ColorAspects::MatrixCoeffs c) {
88 return c <= ColorAspects::MatrixOther;
89 }
90
isDefined(ColorAspects::MatrixCoeffs c)91 static bool isDefined(ColorAspects::MatrixCoeffs c) {
92 return c <= ColorAspects::MatrixBT2020Constant;
93 }
94
95 //static
wrapColorAspectsIntoColorStandard(ColorAspects::Primaries primaries,ColorAspects::MatrixCoeffs coeffs)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
unwrapColorAspectsFromColorStandard(int32_t standard,ColorAspects::Primaries * primaries,ColorAspects::MatrixCoeffs * coeffs)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
isValid(ColorAspects::Range r)144 static bool isValid(ColorAspects::Range r) {
145 return r <= ColorAspects::RangeOther;
146 }
147
isDefined(ColorAspects::Range r)148 static bool isDefined(ColorAspects::Range r) {
149 return r <= ColorAspects::RangeLimited;
150 }
151
152 // static
wrapColorAspectsIntoColorRange(ColorAspects::Range range)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
unwrapColorAspectsFromColorRange(int32_t range,ColorAspects::Range * aspect)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
isValid(ColorAspects::Transfer t)183 static bool isValid(ColorAspects::Transfer t) {
184 return t <= ColorAspects::TransferOther;
185 }
186
isDefined(ColorAspects::Transfer t)187 static bool isDefined(ColorAspects::Transfer t) {
188 return t <= ColorAspects::TransferHLG
189 || (t >= ColorAspects::TransferSMPTE240M && t <= ColorAspects::TransferST428);
190 }
191
192 // static
wrapColorAspectsIntoColorTransfer(ColorAspects::Transfer transfer)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
unwrapColorAspectsFromColorTransfer(int32_t transfer,ColorAspects::Transfer * aspect)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
convertPlatformColorAspectsToCodecAspects(int32_t range,int32_t standard,int32_t transfer,ColorAspects & aspects)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
convertCodecColorAspectsToPlatformAspects(const ColorAspects & aspects,int32_t * range,int32_t * standard,int32_t * transfer)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
convertCodecColorAspectsToIsoAspects(const ColorAspects & aspects,int32_t * primaries,int32_t * transfer,int32_t * coeffs,bool * fullRange)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
convertIsoColorAspectsToCodecAspects(int32_t primaries,int32_t transfer,int32_t coeffs,bool fullRange,ColorAspects & aspects)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
unpackToColorAspects(uint32_t packed)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
packToU32(const ColorAspects & aspects)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
setDefaultCodecColorAspectsIfNeeded(ColorAspects & aspects,int32_t width,int32_t height)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 ALookup<CU::ColorStandard, std::pair<CA::Primaries, CA::MatrixCoeffs>> sStandardFallbacks {
402 {
403 { CU::kColorStandardBT601_625, { CA::PrimariesBT709_5, CA::MatrixBT470_6M } },
404 { CU::kColorStandardBT601_625, { CA::PrimariesBT709_5, CA::MatrixBT601_6 } },
405 { CU::kColorStandardBT709, { CA::PrimariesBT709_5, CA::MatrixSMPTE240M } },
406 { CU::kColorStandardBT709, { CA::PrimariesBT709_5, CA::MatrixBT2020 } },
407 { CU::kColorStandardBT601_525, { CA::PrimariesBT709_5, CA::MatrixBT2020Constant } },
408
409 { CU::kColorStandardBT2020Constant,
410 { CA::PrimariesBT470_6M, CA::MatrixBT2020Constant } },
411
412 { CU::kColorStandardBT601_625, { CA::PrimariesBT601_6_625, CA::MatrixBT470_6M } },
413 { CU::kColorStandardBT601_525, { CA::PrimariesBT601_6_625, CA::MatrixBT2020Constant } },
414
415 { CU::kColorStandardBT601_525, { CA::PrimariesBT601_6_525, CA::MatrixBT470_6M } },
416 { CU::kColorStandardBT601_525, { CA::PrimariesBT601_6_525, CA::MatrixBT2020Constant } },
417
418 { CU::kColorStandardBT2020Constant,
419 { CA::PrimariesGenericFilm, CA::MatrixBT2020Constant } },
420 }
421 };
422
423 ALookup<CU::ColorStandard, CA::Primaries> sStandardPrimariesFallbacks {
424 {
425 { CU::kColorStandardFilm, CA::PrimariesGenericFilm },
426 { CU::kColorStandardBT470M, CA::PrimariesBT470_6M },
427 { CU::kColorStandardBT2020, CA::PrimariesBT2020 },
428 { CU::kColorStandardBT601_525_Unadjusted, CA::PrimariesBT601_6_525 },
429 { CU::kColorStandardBT601_625_Unadjusted, CA::PrimariesBT601_6_625 },
430 }
431 };
432
433 static ALookup<android_dataspace, android_dataspace> sLegacyDataSpaceToV0 {
434 {
435 { HAL_DATASPACE_SRGB, HAL_DATASPACE_V0_SRGB },
436 { HAL_DATASPACE_BT709, HAL_DATASPACE_V0_BT709 },
437 { HAL_DATASPACE_SRGB_LINEAR, HAL_DATASPACE_V0_SRGB_LINEAR },
438 { HAL_DATASPACE_BT601_525, HAL_DATASPACE_V0_BT601_525 },
439 { HAL_DATASPACE_BT601_625, HAL_DATASPACE_V0_BT601_625 },
440 { HAL_DATASPACE_JFIF, HAL_DATASPACE_V0_JFIF },
441 }
442 };
443
convertDataSpaceToV0(android_dataspace & dataSpace)444 bool ColorUtils::convertDataSpaceToV0(android_dataspace &dataSpace) {
445 (void)sLegacyDataSpaceToV0.lookup(dataSpace, &dataSpace);
446 return (dataSpace & 0xC000FFFF) == 0;
447 }
448
checkIfAspectsChangedAndUnspecifyThem(ColorAspects & aspects,const ColorAspects & orig,bool usePlatformAspects)449 bool ColorUtils::checkIfAspectsChangedAndUnspecifyThem(
450 ColorAspects &aspects, const ColorAspects &orig, bool usePlatformAspects) {
451 // remove changed aspects (change them to Unspecified)
452 bool changed = false;
453 if (aspects.mRange && aspects.mRange != orig.mRange) {
454 aspects.mRange = ColorAspects::RangeUnspecified;
455 changed = true;
456 }
457 if (aspects.mPrimaries && aspects.mPrimaries != orig.mPrimaries) {
458 aspects.mPrimaries = ColorAspects::PrimariesUnspecified;
459 if (usePlatformAspects) {
460 aspects.mMatrixCoeffs = ColorAspects::MatrixUnspecified;
461 }
462 changed = true;
463 }
464 if (aspects.mMatrixCoeffs && aspects.mMatrixCoeffs != orig.mMatrixCoeffs) {
465 aspects.mMatrixCoeffs = ColorAspects::MatrixUnspecified;
466 if (usePlatformAspects) {
467 aspects.mPrimaries = ColorAspects::PrimariesUnspecified;
468 }
469 changed = true;
470 }
471 if (aspects.mTransfer && aspects.mTransfer != orig.mTransfer) {
472 aspects.mTransfer = ColorAspects::TransferUnspecified;
473 changed = true;
474 }
475 return changed;
476 }
477
478 // static
getDataSpaceForColorAspects(ColorAspects & aspects,bool mayExpand)479 android_dataspace ColorUtils::getDataSpaceForColorAspects(ColorAspects &aspects, bool mayExpand) {
480 // This platform implementation never expands color space (e.g. returns an expanded
481 // dataspace to use where the codec does in-the-background color space conversion)
482 mayExpand = false;
483
484 if (aspects.mRange == ColorAspects::RangeUnspecified
485 || aspects.mPrimaries == ColorAspects::PrimariesUnspecified
486 || aspects.mMatrixCoeffs == ColorAspects::MatrixUnspecified
487 || aspects.mTransfer == ColorAspects::TransferUnspecified) {
488 ALOGW("expected specified color aspects (%u:%u:%u:%u)",
489 aspects.mRange, aspects.mPrimaries, aspects.mMatrixCoeffs, aspects.mTransfer);
490 }
491
492 // default to video range and transfer
493 ColorRange range = kColorRangeLimited;
494 ColorTransfer transfer = kColorTransferSMPTE_170M;
495 (void)sRanges.map(aspects.mRange, &range);
496 (void)sTransfers.map(aspects.mTransfer, &transfer);
497
498 ColorStandard standard = kColorStandardBT709;
499 auto pair = std::make_pair(aspects.mPrimaries, aspects.mMatrixCoeffs);
500 if (!sStandards.map(pair, &standard)) {
501 if (!sStandardFallbacks.map(pair, &standard)) {
502 (void)sStandardPrimariesFallbacks.map(aspects.mPrimaries, &standard);
503
504 if (aspects.mMatrixCoeffs == ColorAspects::MatrixBT2020Constant) {
505 range = kColorRangeFull;
506 }
507 }
508 }
509
510 android_dataspace dataSpace = (android_dataspace)(
511 (range << HAL_DATASPACE_RANGE_SHIFT) | (standard << HAL_DATASPACE_STANDARD_SHIFT) |
512 (transfer << HAL_DATASPACE_TRANSFER_SHIFT));
513 (void)sLegacyDataSpaceToV0.rlookup(dataSpace, &dataSpace);
514
515 if (!mayExpand) {
516 // update codec aspects based on dataspace
517 convertPlatformColorAspectsToCodecAspects(range, standard, transfer, aspects);
518 }
519 return dataSpace;
520 }
521
522 // static
getColorConfigFromFormat(const sp<AMessage> & format,int32_t * range,int32_t * standard,int32_t * transfer)523 void ColorUtils::getColorConfigFromFormat(
524 const sp<AMessage> &format, int32_t *range, int32_t *standard, int32_t *transfer) {
525 if (!format->findInt32("color-range", range)) {
526 *range = kColorRangeUnspecified;
527 }
528 if (!format->findInt32("color-standard", standard)) {
529 *standard = kColorStandardUnspecified;
530 }
531 if (!format->findInt32("color-transfer", transfer)) {
532 *transfer = kColorTransferUnspecified;
533 }
534 }
535
536 // static
copyColorConfig(const sp<AMessage> & source,sp<AMessage> & target)537 void ColorUtils::copyColorConfig(const sp<AMessage> &source, sp<AMessage> &target) {
538 // 0 values are unspecified
539 int32_t value;
540 if (source->findInt32("color-range", &value)) {
541 target->setInt32("color-range", value);
542 }
543 if (source->findInt32("color-standard", &value)) {
544 target->setInt32("color-standard", value);
545 }
546 if (source->findInt32("color-transfer", &value)) {
547 target->setInt32("color-transfer", value);
548 }
549 }
550
551 // static
getColorAspectsFromFormat(const sp<AMessage> & format,ColorAspects & aspects)552 void ColorUtils::getColorAspectsFromFormat(const sp<AMessage> &format, ColorAspects &aspects) {
553 int32_t range, standard, transfer;
554 getColorConfigFromFormat(format, &range, &standard, &transfer);
555
556 if (convertPlatformColorAspectsToCodecAspects(
557 range, standard, transfer, aspects) != OK) {
558 ALOGW("Ignoring illegal color aspects(R:%d(%s), S:%d(%s), T:%d(%s))",
559 range, asString((ColorRange)range),
560 standard, asString((ColorStandard)standard),
561 transfer, asString((ColorTransfer)transfer));
562 // Invalid values were converted to unspecified !params!, but otherwise were not changed
563 // For encoders, we leave these as is. For decoders, we will use default values.
564 }
565 ALOGV("Got color aspects (R:%d(%s), P:%d(%s), M:%d(%s), T:%d(%s)) "
566 "from format (out:R:%d(%s), S:%d(%s), T:%d(%s))",
567 aspects.mRange, asString(aspects.mRange),
568 aspects.mPrimaries, asString(aspects.mPrimaries),
569 aspects.mMatrixCoeffs, asString(aspects.mMatrixCoeffs),
570 aspects.mTransfer, asString(aspects.mTransfer),
571 range, asString((ColorRange)range),
572 standard, asString((ColorStandard)standard),
573 transfer, asString((ColorTransfer)transfer));
574 }
575
576 // static
setColorAspectsIntoFormat(const ColorAspects & aspects,sp<AMessage> & format,bool force)577 void ColorUtils::setColorAspectsIntoFormat(
578 const ColorAspects &aspects, sp<AMessage> &format, bool force) {
579 int32_t range = 0, standard = 0, transfer = 0;
580 convertCodecColorAspectsToPlatformAspects(aspects, &range, &standard, &transfer);
581 // save set values to base output format
582 // (encoder input format will read back actually supported values by the codec)
583 if (range != 0 || force) {
584 format->setInt32("color-range", range);
585 }
586 if (standard != 0 || force) {
587 format->setInt32("color-standard", standard);
588 }
589 if (transfer != 0 || force) {
590 format->setInt32("color-transfer", transfer);
591 }
592 ALOGV("Setting color aspects (R:%d(%s), P:%d(%s), M:%d(%s), T:%d(%s)) "
593 "into format (out:R:%d(%s), S:%d(%s), T:%d(%s))",
594 aspects.mRange, asString(aspects.mRange),
595 aspects.mPrimaries, asString(aspects.mPrimaries),
596 aspects.mMatrixCoeffs, asString(aspects.mMatrixCoeffs),
597 aspects.mTransfer, asString(aspects.mTransfer),
598 range, asString((ColorRange)range),
599 standard, asString((ColorStandard)standard),
600 transfer, asString((ColorTransfer)transfer));
601 }
602
603 // static
setHDRStaticInfoIntoFormat(const HDRStaticInfo & info,sp<AMessage> & format)604 void ColorUtils::setHDRStaticInfoIntoFormat(
605 const HDRStaticInfo &info, sp<AMessage> &format) {
606 sp<ABuffer> infoBuffer = new ABuffer(25);
607
608 // Convert the data in infoBuffer to little endian format as defined by CTA-861-3
609 uint8_t *data = infoBuffer->data();
610 // Static_Metadata_Descriptor_ID
611 data[0] = info.mID;
612
613 // display primary 0
614 data[1] = LO_UINT16(info.sType1.mR.x);
615 data[2] = HI_UINT16(info.sType1.mR.x);
616 data[3] = LO_UINT16(info.sType1.mR.y);
617 data[4] = HI_UINT16(info.sType1.mR.y);
618
619 // display primary 1
620 data[5] = LO_UINT16(info.sType1.mG.x);
621 data[6] = HI_UINT16(info.sType1.mG.x);
622 data[7] = LO_UINT16(info.sType1.mG.y);
623 data[8] = HI_UINT16(info.sType1.mG.y);
624
625 // display primary 2
626 data[9] = LO_UINT16(info.sType1.mB.x);
627 data[10] = HI_UINT16(info.sType1.mB.x);
628 data[11] = LO_UINT16(info.sType1.mB.y);
629 data[12] = HI_UINT16(info.sType1.mB.y);
630
631 // white point
632 data[13] = LO_UINT16(info.sType1.mW.x);
633 data[14] = HI_UINT16(info.sType1.mW.x);
634 data[15] = LO_UINT16(info.sType1.mW.y);
635 data[16] = HI_UINT16(info.sType1.mW.y);
636
637 // MaxDisplayLuminance
638 data[17] = LO_UINT16(info.sType1.mMaxDisplayLuminance);
639 data[18] = HI_UINT16(info.sType1.mMaxDisplayLuminance);
640
641 // MinDisplayLuminance
642 data[19] = LO_UINT16(info.sType1.mMinDisplayLuminance);
643 data[20] = HI_UINT16(info.sType1.mMinDisplayLuminance);
644
645 // MaxContentLightLevel
646 data[21] = LO_UINT16(info.sType1.mMaxContentLightLevel);
647 data[22] = HI_UINT16(info.sType1.mMaxContentLightLevel);
648
649 // MaxFrameAverageLightLevel
650 data[23] = LO_UINT16(info.sType1.mMaxFrameAverageLightLevel);
651 data[24] = HI_UINT16(info.sType1.mMaxFrameAverageLightLevel);
652
653 format->setBuffer("hdr-static-info", infoBuffer);
654 }
655
656 // a simple method copied from Utils.cpp
U16LE_AT(const uint8_t * ptr)657 static uint16_t U16LE_AT(const uint8_t *ptr) {
658 return ptr[0] | (ptr[1] << 8);
659 }
660
661 // static
getHDRStaticInfoFromFormat(const sp<AMessage> & format,HDRStaticInfo * info)662 bool ColorUtils::getHDRStaticInfoFromFormat(const sp<AMessage> &format, HDRStaticInfo *info) {
663 sp<ABuffer> buf;
664 if (!format->findBuffer("hdr-static-info", &buf)) {
665 return false;
666 }
667
668 // TODO: Make this more flexible when adding more members to HDRStaticInfo
669 if (buf->size() != 25 /* static Metadata Type 1 size */) {
670 ALOGW("Ignore invalid HDRStaticInfo with size: %zu", buf->size());
671 return false;
672 }
673
674 const uint8_t *data = buf->data();
675 if (*data != HDRStaticInfo::kType1) {
676 ALOGW("Unsupported static Metadata Type %u", *data);
677 return false;
678 }
679
680 info->mID = HDRStaticInfo::kType1;
681 info->sType1.mR.x = U16LE_AT(&data[1]);
682 info->sType1.mR.y = U16LE_AT(&data[3]);
683 info->sType1.mG.x = U16LE_AT(&data[5]);
684 info->sType1.mG.y = U16LE_AT(&data[7]);
685 info->sType1.mB.x = U16LE_AT(&data[9]);
686 info->sType1.mB.y = U16LE_AT(&data[11]);
687 info->sType1.mW.x = U16LE_AT(&data[13]);
688 info->sType1.mW.y = U16LE_AT(&data[15]);
689 info->sType1.mMaxDisplayLuminance = U16LE_AT(&data[17]);
690 info->sType1.mMinDisplayLuminance = U16LE_AT(&data[19]);
691 info->sType1.mMaxContentLightLevel = U16LE_AT(&data[21]);
692 info->sType1.mMaxFrameAverageLightLevel = U16LE_AT(&data[23]);
693
694 ALOGV("Got HDRStaticInfo from config (R: %u %u, G: %u %u, B: %u, %u, W: %u, %u, "
695 "MaxDispL: %u, MinDispL: %u, MaxContentL: %u, MaxFrameAvgL: %u)",
696 info->sType1.mR.x, info->sType1.mR.y, info->sType1.mG.x, info->sType1.mG.y,
697 info->sType1.mB.x, info->sType1.mB.y, info->sType1.mW.x, info->sType1.mW.y,
698 info->sType1.mMaxDisplayLuminance, info->sType1.mMinDisplayLuminance,
699 info->sType1.mMaxContentLightLevel, info->sType1.mMaxFrameAverageLightLevel);
700 return true;
701 }
702
703 } // namespace android
704
705