ColorUtils.cpp revision 58fb7c6e1a9244dd7215a647388c440d8d75851b
1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "ColorUtils"
19
20#include <inttypes.h>
21
22#include <media/stagefright/foundation/ADebug.h>
23#include <media/stagefright/foundation/ALookup.h>
24#include <media/stagefright/foundation/ColorUtils.h>
25
26namespace android {
27
28// shortcut names for brevity in the following tables
29typedef ColorAspects CA;
30typedef ColorUtils CU;
31
32const static
33ALookup<CU::ColorRange, CA::Range> sRanges{
34    {
35        { CU::kColorRangeLimited, CA::RangeLimited },
36        { CU::kColorRangeFull, CA::RangeFull },
37        { CU::kColorRangeUnspecified, CA::RangeUnspecified },
38    }
39};
40
41const static
42ALookup<CU::ColorStandard, std::pair<CA::Primaries, CA::MatrixCoeffs>> sStandards {
43    {
44        { CU::kColorStandardUnspecified,    { CA::PrimariesUnspecified, CA::MatrixUnspecified } },
45        { CU::kColorStandardBT709,          { CA::PrimariesBT709_5, CA::MatrixBT709_5 } },
46        { CU::kColorStandardBT601_625,      { CA::PrimariesBT601_6_625, CA::MatrixBT601_6 } },
47        { CU::kColorStandardBT601_625_Unadjusted,
48                                            // this is a really close match
49                                            { CA::PrimariesBT601_6_625, CA::MatrixBT709_5 } },
50        { CU::kColorStandardBT601_525,      { CA::PrimariesBT601_6_525, CA::MatrixBT601_6 } },
51        { CU::kColorStandardBT601_525_Unadjusted,
52                                            { CA::PrimariesBT601_6_525, CA::MatrixSMPTE240M } },
53        { CU::kColorStandardBT2020,         { CA::PrimariesBT2020, CA::MatrixBT2020 } },
54        { CU::kColorStandardBT2020Constant, { CA::PrimariesBT2020, CA::MatrixBT2020Constant } },
55        { CU::kColorStandardBT470M,         { CA::PrimariesBT470_6M, CA::MatrixBT470_6M } },
56        // NOTE: there is no close match to the matrix used by standard film, chose closest
57        { CU::kColorStandardFilm,           { CA::PrimariesGenericFilm, CA::MatrixBT2020 } },
58    }
59};
60
61const static
62ALookup<CU::ColorTransfer, CA::Transfer> sTransfers{
63    {
64        { CU::kColorTransferUnspecified,    CA::TransferUnspecified },
65        { CU::kColorTransferLinear,         CA::TransferLinear },
66        { CU::kColorTransferSRGB,           CA::TransferSRGB },
67        { CU::kColorTransferSMPTE_170M,     CA::TransferSMPTE170M },
68        { CU::kColorTransferGamma22,        CA::TransferGamma22 },
69        { CU::kColorTransferGamma28,        CA::TransferGamma28 },
70        { CU::kColorTransferST2084,         CA::TransferST2084 },
71        { CU::kColorTransferHLG,            CA::TransferHLG },
72    }
73};
74
75static bool isValid(ColorAspects::Primaries p) {
76    return p <= ColorAspects::PrimariesOther;
77}
78
79static bool isDefined(ColorAspects::Primaries p) {
80    return p <= ColorAspects::PrimariesBT2020;
81}
82
83static bool isValid(ColorAspects::MatrixCoeffs c) {
84    return c <= ColorAspects::MatrixOther;
85}
86
87static bool isDefined(ColorAspects::MatrixCoeffs c) {
88    return c <= ColorAspects::MatrixBT2020Constant;
89}
90
91//static
92int32_t ColorUtils::wrapColorAspectsIntoColorStandard(
93        ColorAspects::Primaries primaries, ColorAspects::MatrixCoeffs coeffs) {
94    ColorStandard res;
95    if (sStandards.map(std::make_pair(primaries, coeffs), &res)) {
96        return res;
97    } else if (!isValid(primaries) || !isValid(coeffs)) {
98        return kColorStandardUnspecified;
99    }
100
101    // check platform media limits
102    uint32_t numPrimaries = ColorAspects::PrimariesBT2020 + 1;
103    if (isDefined(primaries) && isDefined(coeffs)) {
104        return kColorStandardExtendedStart + primaries + coeffs * numPrimaries;
105    } else {
106        return kColorStandardVendorStart + primaries + coeffs * 0x100;
107    }
108}
109
110//static
111status_t ColorUtils::unwrapColorAspectsFromColorStandard(
112        int32_t standard,
113        ColorAspects::Primaries *primaries, ColorAspects::MatrixCoeffs *coeffs) {
114    std::pair<ColorAspects::Primaries, ColorAspects::MatrixCoeffs> res;
115    if (sStandards.map((ColorStandard)standard, &res)) {
116        *primaries = res.first;
117        *coeffs = res.second;
118        return OK;
119    }
120
121    int32_t start = kColorStandardExtendedStart;
122    int32_t numPrimaries = ColorAspects::PrimariesBT2020 + 1;
123    int32_t numCoeffs = ColorAspects::MatrixBT2020Constant + 1;
124    if (standard >= (int32_t)kColorStandardVendorStart) {
125        start = kColorStandardVendorStart;
126        numPrimaries = ColorAspects::PrimariesOther + 1; // 0x100
127        numCoeffs = ColorAspects::MatrixOther + 1; // 0x100;
128    }
129    if (standard >= start && standard < start + numPrimaries * numCoeffs) {
130        int32_t product = standard - start;
131        *primaries = (ColorAspects::Primaries)(product % numPrimaries);
132        *coeffs = (ColorAspects::MatrixCoeffs)(product / numPrimaries);
133        return OK;
134    }
135    *primaries = ColorAspects::PrimariesOther;
136    *coeffs = ColorAspects::MatrixOther;
137    return BAD_VALUE;
138}
139
140static bool isValid(ColorAspects::Range r) {
141    return r <= ColorAspects::RangeOther;
142}
143
144static bool isDefined(ColorAspects::Range r) {
145    return r <= ColorAspects::RangeLimited;
146}
147
148//  static
149int32_t ColorUtils::wrapColorAspectsIntoColorRange(ColorAspects::Range range) {
150    ColorRange res;
151    if (sRanges.map(range, &res)) {
152        return res;
153    } else if (!isValid(range)) {
154        return kColorRangeUnspecified;
155    } else {
156        CHECK(!isDefined(range));
157        // all platform values are in sRanges
158        return kColorRangeVendorStart + range;
159    }
160}
161
162//static
163status_t ColorUtils::unwrapColorAspectsFromColorRange(
164        int32_t range, ColorAspects::Range *aspect) {
165    if (sRanges.map((ColorRange)range, aspect)) {
166        return OK;
167    }
168
169    int32_t start = kColorRangeVendorStart;
170    int32_t numRanges = ColorAspects::RangeOther + 1; // 0x100
171    if (range >= start && range < start + numRanges) {
172        *aspect = (ColorAspects::Range)(range - start);
173        return OK;
174    }
175    *aspect = ColorAspects::RangeOther;
176    return BAD_VALUE;
177}
178
179static bool isValid(ColorAspects::Transfer t) {
180    return t <= ColorAspects::TransferOther;
181}
182
183static bool isDefined(ColorAspects::Transfer t) {
184    return t <= ColorAspects::TransferHLG
185            || (t >= ColorAspects::TransferSMPTE240M && t <= ColorAspects::TransferST428);
186}
187
188//  static
189int32_t ColorUtils::wrapColorAspectsIntoColorTransfer(
190        ColorAspects::Transfer transfer) {
191    ColorTransfer res;
192    if (sTransfers.map(transfer, &res)) {
193        return res;
194    } else if (!isValid(transfer)) {
195        return kColorTransferUnspecified;
196    } else if (isDefined(transfer)) {
197        return kColorTransferExtendedStart + transfer;
198    } else {
199        // all platform values are in sRanges
200        return kColorTransferVendorStart + transfer;
201    }
202}
203
204//static
205status_t ColorUtils::unwrapColorAspectsFromColorTransfer(
206        int32_t transfer, ColorAspects::Transfer *aspect) {
207    if (sTransfers.map((ColorTransfer)transfer, aspect)) {
208        return OK;
209    }
210
211    int32_t start = kColorTransferExtendedStart;
212    int32_t numTransfers = ColorAspects::TransferST428 + 1;
213    if (transfer >= (int32_t)kColorTransferVendorStart) {
214        start = kColorTransferVendorStart;
215        numTransfers = ColorAspects::TransferOther + 1; // 0x100
216    }
217    if (transfer >= start && transfer < start + numTransfers) {
218        *aspect = (ColorAspects::Transfer)(transfer - start);
219        return OK;
220    }
221    *aspect = ColorAspects::TransferOther;
222    return BAD_VALUE;
223}
224
225// static
226status_t ColorUtils::convertPlatformColorAspectsToCodecAspects(
227    int32_t range, int32_t standard, int32_t transfer, ColorAspects &aspects) {
228    status_t res1 = unwrapColorAspectsFromColorRange(range, &aspects.mRange);
229    status_t res2 = unwrapColorAspectsFromColorStandard(
230            standard, &aspects.mPrimaries, &aspects.mMatrixCoeffs);
231    status_t res3 = unwrapColorAspectsFromColorTransfer(transfer, &aspects.mTransfer);
232    return res1 != OK ? res1 : (res2 != OK ? res2 : res3);
233}
234
235// static
236status_t ColorUtils::convertCodecColorAspectsToPlatformAspects(
237    const ColorAspects &aspects, int32_t *range, int32_t *standard, int32_t *transfer) {
238    *range = wrapColorAspectsIntoColorRange(aspects.mRange);
239    *standard = wrapColorAspectsIntoColorStandard(aspects.mPrimaries, aspects.mMatrixCoeffs);
240    *transfer = wrapColorAspectsIntoColorTransfer(aspects.mTransfer);
241    if (isValid(aspects.mRange) && isValid(aspects.mPrimaries)
242            && isValid(aspects.mMatrixCoeffs) && isValid(aspects.mTransfer)) {
243        return OK;
244    } else {
245        return BAD_VALUE;
246    }
247}
248
249const static
250ALookup<int32_t, ColorAspects::Primaries> sIsoPrimaries {
251    {
252        { 1, ColorAspects::PrimariesBT709_5 },
253        { 2, ColorAspects::PrimariesUnspecified },
254        { 4, ColorAspects::PrimariesBT470_6M },
255        { 5, ColorAspects::PrimariesBT601_6_625 },
256        { 6, ColorAspects::PrimariesBT601_6_525 /* main */},
257        { 7, ColorAspects::PrimariesBT601_6_525 },
258        // -- ITU T.832 201201 ends here
259        { 8, ColorAspects::PrimariesGenericFilm },
260        { 9, ColorAspects::PrimariesBT2020 },
261        { 10, ColorAspects::PrimariesOther /* XYZ */ },
262    }
263};
264
265const static
266ALookup<int32_t, ColorAspects::Transfer> sIsoTransfers {
267    {
268        { 1, ColorAspects::TransferSMPTE170M /* main */},
269        { 2, ColorAspects::TransferUnspecified },
270        { 4, ColorAspects::TransferGamma22 },
271        { 5, ColorAspects::TransferGamma28 },
272        { 6, ColorAspects::TransferSMPTE170M },
273        { 7, ColorAspects::TransferSMPTE240M },
274        { 8, ColorAspects::TransferLinear },
275        { 9, ColorAspects::TransferOther /* log 100:1 */ },
276        { 10, ColorAspects::TransferOther /* log 316:1 */ },
277        { 11, ColorAspects::TransferXvYCC },
278        { 12, ColorAspects::TransferBT1361 },
279        { 13, ColorAspects::TransferSRGB },
280        // -- ITU T.832 201201 ends here
281        { 14, ColorAspects::TransferSMPTE170M },
282        { 15, ColorAspects::TransferSMPTE170M },
283        { 16, ColorAspects::TransferST2084 },
284        { 17, ColorAspects::TransferST428 },
285    }
286};
287
288const static
289ALookup<int32_t, ColorAspects::MatrixCoeffs> sIsoMatrixCoeffs {
290    {
291        { 0, ColorAspects::MatrixOther },
292        { 1, ColorAspects::MatrixBT709_5 },
293        { 2, ColorAspects::MatrixUnspecified },
294        { 4, ColorAspects::MatrixBT470_6M },
295        { 6, ColorAspects::MatrixBT601_6 /* main */ },
296        { 5, ColorAspects::MatrixBT601_6 },
297        { 7, ColorAspects::MatrixSMPTE240M },
298        { 8, ColorAspects::MatrixOther /* YCgCo */ },
299        // -- ITU T.832 201201 ends here
300        { 9, ColorAspects::MatrixBT2020 },
301        { 10, ColorAspects::MatrixBT2020Constant },
302    }
303};
304
305// static
306void ColorUtils::convertCodecColorAspectsToIsoAspects(
307        const ColorAspects &aspects,
308        int32_t *primaries, int32_t *transfer, int32_t *coeffs, bool *fullRange) {
309    if (aspects.mPrimaries == ColorAspects::PrimariesOther ||
310            !sIsoPrimaries.map(aspects.mPrimaries, primaries)) {
311        CHECK(sIsoPrimaries.map(ColorAspects::PrimariesUnspecified, primaries));
312    }
313    if (aspects.mTransfer == ColorAspects::TransferOther ||
314            !sIsoTransfers.map(aspects.mTransfer, transfer)) {
315        CHECK(sIsoTransfers.map(ColorAspects::TransferUnspecified, transfer));
316    }
317    if (aspects.mMatrixCoeffs == ColorAspects::MatrixOther ||
318            !sIsoMatrixCoeffs.map(aspects.mMatrixCoeffs, coeffs)) {
319        CHECK(sIsoMatrixCoeffs.map(ColorAspects::MatrixUnspecified, coeffs));
320    }
321    *fullRange = aspects.mRange == ColorAspects::RangeFull;
322}
323
324// static
325void ColorUtils::convertIsoColorAspectsToCodecAspects(
326        int32_t primaries, int32_t transfer, int32_t coeffs, bool fullRange,
327        ColorAspects &aspects) {
328    if (!sIsoPrimaries.map(primaries, &aspects.mPrimaries)) {
329        aspects.mPrimaries = ColorAspects::PrimariesUnspecified;
330    }
331    if (!sIsoTransfers.map(transfer, &aspects.mTransfer)) {
332        aspects.mTransfer = ColorAspects::TransferUnspecified;
333    }
334    if (!sIsoMatrixCoeffs.map(coeffs, &aspects.mMatrixCoeffs)) {
335        aspects.mMatrixCoeffs = ColorAspects::MatrixUnspecified;
336    }
337    aspects.mRange = fullRange ? ColorAspects::RangeFull : ColorAspects::RangeLimited;
338}
339
340// static
341void ColorUtils::setDefaultCodecColorAspectsIfNeeded(
342        ColorAspects &aspects, int32_t width, int32_t height) {
343    ColorAspects::MatrixCoeffs coeffs;
344    ColorAspects::Primaries primaries;
345
346    // Default to BT2020, BT709 or BT601 based on size. Allow 2.35:1 aspect ratio. Limit BT601
347    // to PAL or smaller, BT2020 to 4K or larger, leaving BT709 for all resolutions in between.
348    if (width >= 3840 || height >= 3840 || width * (int64_t)height >= 3840 * 1634) {
349        primaries = ColorAspects::PrimariesBT2020;
350        coeffs = ColorAspects::MatrixBT2020;
351    } else if ((width <= 720 && height > 480 && height <= 576)
352            || (height <= 720 && width > 480 && width <= 576)) {
353        primaries = ColorAspects::PrimariesBT601_6_625;
354        coeffs = ColorAspects::MatrixBT601_6;
355    } else if ((width <= 720 && height <= 480) || (height <= 720 && width <= 480)) {
356        primaries = ColorAspects::PrimariesBT601_6_525;
357        coeffs = ColorAspects::MatrixBT601_6;
358    } else {
359        primaries = ColorAspects::PrimariesBT709_5;
360        coeffs = ColorAspects::MatrixBT709_5;
361    }
362
363    if (aspects.mRange == ColorAspects::RangeUnspecified) {
364        aspects.mRange = ColorAspects::RangeLimited;
365    }
366
367    if (aspects.mPrimaries == ColorAspects::PrimariesUnspecified) {
368        aspects.mPrimaries = primaries;
369    }
370    if (aspects.mMatrixCoeffs == ColorAspects::MatrixUnspecified) {
371        aspects.mMatrixCoeffs = coeffs;
372    }
373    if (aspects.mTransfer == ColorAspects::TransferUnspecified) {
374        aspects.mTransfer = ColorAspects::TransferSMPTE170M;
375    }
376}
377
378// TODO: move this into a Video HAL
379ALookup<CU::ColorStandard, std::pair<CA::Primaries, CA::MatrixCoeffs>> sStandardFallbacks {
380    {
381        { CU::kColorStandardBT601_625, { CA::PrimariesBT709_5, CA::MatrixBT470_6M } },
382        { CU::kColorStandardBT601_625, { CA::PrimariesBT709_5, CA::MatrixBT601_6 } },
383        { CU::kColorStandardBT709,     { CA::PrimariesBT709_5, CA::MatrixSMPTE240M } },
384        { CU::kColorStandardBT709,     { CA::PrimariesBT709_5, CA::MatrixBT2020 } },
385        { CU::kColorStandardBT601_525, { CA::PrimariesBT709_5, CA::MatrixBT2020Constant } },
386
387        { CU::kColorStandardBT2020Constant,
388                                       { CA::PrimariesBT470_6M, CA::MatrixBT2020Constant } },
389
390        { CU::kColorStandardBT601_625, { CA::PrimariesBT601_6_625, CA::MatrixBT470_6M } },
391        { CU::kColorStandardBT601_525, { CA::PrimariesBT601_6_625, CA::MatrixBT2020Constant } },
392
393        { CU::kColorStandardBT601_525, { CA::PrimariesBT601_6_525, CA::MatrixBT470_6M } },
394        { CU::kColorStandardBT601_525, { CA::PrimariesBT601_6_525, CA::MatrixBT2020Constant } },
395
396        { CU::kColorStandardBT2020Constant,
397                                       { CA::PrimariesGenericFilm, CA::MatrixBT2020Constant } },
398    }
399};
400
401ALookup<CU::ColorStandard, CA::Primaries> sStandardPrimariesFallbacks {
402    {
403        { CU::kColorStandardFilm,                 CA::PrimariesGenericFilm },
404        { CU::kColorStandardBT470M,               CA::PrimariesBT470_6M },
405        { CU::kColorStandardBT2020,               CA::PrimariesBT2020 },
406        { CU::kColorStandardBT601_525_Unadjusted, CA::PrimariesBT601_6_525 },
407        { CU::kColorStandardBT601_625_Unadjusted, CA::PrimariesBT601_6_625 },
408    }
409};
410
411static ALookup<android_dataspace, android_dataspace> sLegacyDataSpaceToV0 {
412    {
413        { HAL_DATASPACE_SRGB, HAL_DATASPACE_V0_SRGB },
414        { HAL_DATASPACE_BT709, HAL_DATASPACE_V0_BT709 },
415        { HAL_DATASPACE_SRGB_LINEAR, HAL_DATASPACE_V0_SRGB_LINEAR },
416        { HAL_DATASPACE_BT601_525, HAL_DATASPACE_V0_BT601_525 },
417        { HAL_DATASPACE_BT601_625, HAL_DATASPACE_V0_BT601_625 },
418        { HAL_DATASPACE_JFIF, HAL_DATASPACE_V0_JFIF },
419    }
420};
421
422bool ColorUtils::convertDataSpaceToV0(android_dataspace &dataSpace) {
423    (void)sLegacyDataSpaceToV0.lookup(dataSpace, &dataSpace);
424    return (dataSpace & 0xC000FFFF) == 0;
425}
426
427bool ColorUtils::checkIfAspectsChangedAndUnspecifyThem(
428        ColorAspects &aspects, const ColorAspects &orig, bool usePlatformAspects) {
429    // remove changed aspects (change them to Unspecified)
430    bool changed = false;
431    if (aspects.mRange && aspects.mRange != orig.mRange) {
432        aspects.mRange = ColorAspects::RangeUnspecified;
433        changed = true;
434    }
435    if (aspects.mPrimaries && aspects.mPrimaries != orig.mPrimaries) {
436        aspects.mPrimaries = ColorAspects::PrimariesUnspecified;
437        if (usePlatformAspects) {
438            aspects.mMatrixCoeffs = ColorAspects::MatrixUnspecified;
439        }
440        changed = true;
441    }
442    if (aspects.mMatrixCoeffs && aspects.mMatrixCoeffs != orig.mMatrixCoeffs) {
443        aspects.mMatrixCoeffs = ColorAspects::MatrixUnspecified;
444        if (usePlatformAspects) {
445            aspects.mPrimaries = ColorAspects::PrimariesUnspecified;
446        }
447        changed = true;
448    }
449    if (aspects.mTransfer && aspects.mTransfer != orig.mTransfer) {
450        aspects.mTransfer = ColorAspects::TransferUnspecified;
451        changed = true;
452    }
453    return changed;
454}
455
456// static
457android_dataspace ColorUtils::getDataSpaceForColorAspects(ColorAspects &aspects, bool mayExpand) {
458    // This platform implementation never expands color space (e.g. returns an expanded
459    // dataspace to use where the codec does in-the-background color space conversion)
460    mayExpand = false;
461
462    if (aspects.mRange == ColorAspects::RangeUnspecified
463            || aspects.mPrimaries == ColorAspects::PrimariesUnspecified
464            || aspects.mMatrixCoeffs == ColorAspects::MatrixUnspecified
465            || aspects.mTransfer == ColorAspects::TransferUnspecified) {
466        ALOGW("expected specified color aspects (%u:%u:%u:%u)",
467                aspects.mRange, aspects.mPrimaries, aspects.mMatrixCoeffs, aspects.mTransfer);
468    }
469
470    // default to video range and transfer
471    ColorRange range = kColorRangeLimited;
472    ColorTransfer transfer = kColorTransferSMPTE_170M;
473    (void)sRanges.map(aspects.mRange, &range);
474    (void)sTransfers.map(aspects.mTransfer, &transfer);
475
476    ColorStandard standard = kColorStandardBT709;
477    auto pair = std::make_pair(aspects.mPrimaries, aspects.mMatrixCoeffs);
478    if (!sStandards.map(pair, &standard)) {
479        if (!sStandardFallbacks.map(pair, &standard)) {
480            (void)sStandardPrimariesFallbacks.map(aspects.mPrimaries, &standard);
481
482            if (aspects.mMatrixCoeffs == ColorAspects::MatrixBT2020Constant) {
483                range = kColorRangeFull;
484            }
485        }
486    }
487
488    android_dataspace dataSpace = (android_dataspace)(
489            (range << HAL_DATASPACE_RANGE_SHIFT) | (standard << HAL_DATASPACE_STANDARD_SHIFT) |
490            (transfer << HAL_DATASPACE_TRANSFER_SHIFT));
491    (void)sLegacyDataSpaceToV0.rlookup(dataSpace, &dataSpace);
492
493    if (!mayExpand) {
494        // update codec aspects based on dataspace
495        convertPlatformColorAspectsToCodecAspects(range, standard, transfer, aspects);
496    }
497    return dataSpace;
498}
499
500// static
501void ColorUtils::getColorConfigFromFormat(
502        const sp<AMessage> &format, int32_t *range, int32_t *standard, int32_t *transfer) {
503    if (!format->findInt32("color-range", range)) {
504        *range = kColorRangeUnspecified;
505    }
506    if (!format->findInt32("color-standard", standard)) {
507        *standard = kColorStandardUnspecified;
508    }
509    if (!format->findInt32("color-transfer", transfer)) {
510        *transfer = kColorTransferUnspecified;
511    }
512}
513
514// static
515void ColorUtils::copyColorConfig(const sp<AMessage> &source, sp<AMessage> &target) {
516    // 0 values are unspecified
517    int32_t value;
518    if (source->findInt32("color-range", &value)) {
519        target->setInt32("color-range", value);
520    }
521    if (source->findInt32("color-standard", &value)) {
522        target->setInt32("color-standard", value);
523    }
524    if (source->findInt32("color-transfer", &value)) {
525        target->setInt32("color-transfer", value);
526    }
527}
528
529// static
530void ColorUtils::getColorAspectsFromFormat(const sp<AMessage> &format, ColorAspects &aspects) {
531    int32_t range, standard, transfer;
532    getColorConfigFromFormat(format, &range, &standard, &transfer);
533
534    if (convertPlatformColorAspectsToCodecAspects(
535            range, standard, transfer, aspects) != OK) {
536        ALOGW("Ignoring illegal color aspects(R:%d(%s), S:%d(%s), T:%d(%s))",
537                range, asString((ColorRange)range),
538                standard, asString((ColorStandard)standard),
539                transfer, asString((ColorTransfer)transfer));
540        // Invalid values were converted to unspecified !params!, but otherwise were not changed
541        // For encoders, we leave these as is. For decoders, we will use default values.
542    }
543    ALOGV("Got color aspects (R:%d(%s), P:%d(%s), M:%d(%s), T:%d(%s)) "
544          "from format (out:R:%d(%s), S:%d(%s), T:%d(%s))",
545            aspects.mRange, asString(aspects.mRange),
546            aspects.mPrimaries, asString(aspects.mPrimaries),
547            aspects.mMatrixCoeffs, asString(aspects.mMatrixCoeffs),
548            aspects.mTransfer, asString(aspects.mTransfer),
549            range, asString((ColorRange)range),
550            standard, asString((ColorStandard)standard),
551            transfer, asString((ColorTransfer)transfer));
552}
553
554// static
555void ColorUtils::setColorAspectsIntoFormat(
556        const ColorAspects &aspects, sp<AMessage> &format, bool force) {
557    int32_t range = 0, standard = 0, transfer = 0;
558    convertCodecColorAspectsToPlatformAspects(aspects, &range, &standard, &transfer);
559    // save set values to base output format
560    // (encoder input format will read back actually supported values by the codec)
561    if (range != 0 || force) {
562        format->setInt32("color-range", range);
563    }
564    if (standard != 0 || force) {
565        format->setInt32("color-standard", standard);
566    }
567    if (transfer != 0 || force) {
568        format->setInt32("color-transfer", transfer);
569    }
570    ALOGV("Setting color aspects (R:%d(%s), P:%d(%s), M:%d(%s), T:%d(%s)) "
571          "into format (out:R:%d(%s), S:%d(%s), T:%d(%s))",
572            aspects.mRange, asString(aspects.mRange),
573            aspects.mPrimaries, asString(aspects.mPrimaries),
574            aspects.mMatrixCoeffs, asString(aspects.mMatrixCoeffs),
575            aspects.mTransfer, asString(aspects.mTransfer),
576            range, asString((ColorRange)range),
577            standard, asString((ColorStandard)standard),
578            transfer, asString((ColorTransfer)transfer));
579}
580
581}  // namespace android
582
583