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 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 
convertDataSpaceToV0(android_dataspace & dataSpace)514 bool ColorUtils::convertDataSpaceToV0(android_dataspace &dataSpace) {
515     (void)sLegacyDataSpaceToV0.lookup(dataSpace, &dataSpace);
516     return (dataSpace & 0xC000FFFF) == 0;
517 }
518 
checkIfAspectsChangedAndUnspecifyThem(ColorAspects & aspects,const ColorAspects & orig,bool usePlatformAspects)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
getDataSpaceForColorAspects(ColorAspects & aspects,bool mayExpand)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
getColorConfigFromFormat(const sp<AMessage> & format,int32_t * range,int32_t * standard,int32_t * transfer)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
copyColorConfig(const sp<AMessage> & source,sp<AMessage> & target)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
getColorAspectsFromFormat(const sp<AMessage> & format,ColorAspects & aspects)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
setColorAspectsIntoFormat(const ColorAspects & aspects,sp<AMessage> & format,bool force)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
setHDRStaticInfoIntoFormat(const HDRStaticInfo & info,sp<AMessage> & format)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
U16LE_AT(const uint8_t * ptr)741 static uint16_t U16LE_AT(const uint8_t *ptr) {
742     return ptr[0] | (ptr[1] << 8);
743 }
744 
745 // static
getHDRStaticInfoFromFormat(const sp<AMessage> & format,HDRStaticInfo * info)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