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 
isValid(ColorAspects::Primaries p)80 static bool isValid(ColorAspects::Primaries p) {
81     return p <= ColorAspects::PrimariesOther;
82 }
83 
isDefined(ColorAspects::Primaries p)84 static bool isDefined(ColorAspects::Primaries p) {
85     return p <= ColorAspects::PrimariesBT2020;
86 }
87 
isValid(ColorAspects::MatrixCoeffs c)88 static bool isValid(ColorAspects::MatrixCoeffs c) {
89     return c <= ColorAspects::MatrixOther;
90 }
91 
isDefined(ColorAspects::MatrixCoeffs c)92 static bool isDefined(ColorAspects::MatrixCoeffs c) {
93     return c <= ColorAspects::MatrixBT2020Constant;
94 }
95 
96 //static
wrapColorAspectsIntoColorStandard(ColorAspects::Primaries primaries,ColorAspects::MatrixCoeffs coeffs)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
unwrapColorAspectsFromColorStandard(int32_t standard,ColorAspects::Primaries * primaries,ColorAspects::MatrixCoeffs * coeffs)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 
isValid(ColorAspects::Range r)145 static bool isValid(ColorAspects::Range r) {
146     return r <= ColorAspects::RangeOther;
147 }
148 
isDefined(ColorAspects::Range r)149 static bool isDefined(ColorAspects::Range r) {
150     return r <= ColorAspects::RangeLimited;
151 }
152 
153 //  static
wrapColorAspectsIntoColorRange(ColorAspects::Range range)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
unwrapColorAspectsFromColorRange(int32_t range,ColorAspects::Range * aspect)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 
isValid(ColorAspects::Transfer t)184 static bool isValid(ColorAspects::Transfer t) {
185     return t <= ColorAspects::TransferOther;
186 }
187 
isDefined(ColorAspects::Transfer t)188 static bool isDefined(ColorAspects::Transfer t) {
189     return t <= ColorAspects::TransferHLG
190             || (t >= ColorAspects::TransferSMPTE240M && t <= ColorAspects::TransferST428);
191 }
192 
193 //  static
wrapColorAspectsIntoColorTransfer(ColorAspects::Transfer transfer)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
unwrapColorAspectsFromColorTransfer(int32_t transfer,ColorAspects::Transfer * aspect)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
convertPlatformColorAspectsToCodecAspects(int32_t range,int32_t standard,int32_t transfer,ColorAspects & aspects)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
convertCodecColorAspectsToPlatformAspects(const ColorAspects & aspects,int32_t * range,int32_t * standard,int32_t * transfer)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
convertCodecColorAspectsToIsoAspects(const ColorAspects & aspects,int32_t * primaries,int32_t * transfer,int32_t * coeffs,bool * fullRange)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
convertIsoColorAspectsToCodecAspects(int32_t primaries,int32_t transfer,int32_t coeffs,bool fullRange,ColorAspects & aspects)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 
convertIsoColorAspectsToPlatformAspects(int32_t primaries,int32_t intransfer,int32_t coeffs,bool fullRange,int32_t * range,int32_t * standard,int32_t * outtransfer)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
unpackToColorAspects(uint32_t packed)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
packToU32(const ColorAspects & aspects)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
setDefaultCodecColorAspectsIfNeeded(ColorAspects & aspects,int32_t width,int32_t height)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 
convertDataSpaceToV0(android_dataspace & dataSpace)523 bool ColorUtils::convertDataSpaceToV0(android_dataspace &dataSpace) {
524     (void)sLegacyDataSpaceToV0.lookup(dataSpace, &dataSpace);
525     return (dataSpace & 0xC000FFFF) == 0;
526 }
527 
checkIfAspectsChangedAndUnspecifyThem(ColorAspects & aspects,const ColorAspects & orig,bool usePlatformAspects)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
getDataSpaceForColorAspects(ColorAspects & aspects,bool mayExpand)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
getColorConfigFromFormat(const sp<AMessage> & format,int32_t * range,int32_t * standard,int32_t * transfer)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
copyColorConfig(const sp<AMessage> & source,sp<AMessage> & target)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
getColorAspectsFromFormat(const sp<AMessage> & format,ColorAspects & aspects)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
setColorAspectsIntoFormat(const ColorAspects & aspects,sp<AMessage> & format,bool force)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
setHDRStaticInfoIntoAMediaFormat(const HDRStaticInfo & info,AMediaFormat * format)698 void ColorUtils::setHDRStaticInfoIntoAMediaFormat(
699         const HDRStaticInfo &info, AMediaFormat *format) {
700     setHDRStaticInfoIntoFormat(info, format->mFormat);
701 }
702 
703 // static
setHDRStaticInfoIntoFormat(const HDRStaticInfo & info,sp<AMessage> & format)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
U16LE_AT(const uint8_t * ptr)757 static uint16_t U16LE_AT(const uint8_t *ptr) {
758     return ptr[0] | (ptr[1] << 8);
759 }
760 
761 // static
getHDRStaticInfoFromFormat(const sp<AMessage> & format,HDRStaticInfo * info)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