stagefright: pass color aspects into codecs
Bug: 25975353
Change-Id: Ie2cdb845769f5ec3561a099f96e8f4dd406299ef
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index 4a7fc62..761f182 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -290,6 +290,8 @@
bool mTunneled;
+ OMX_INDEXTYPE mDescribeColorAspectsIndex;
+
status_t setCyclicIntraMacroblockRefresh(const sp<AMessage> &msg, int32_t mode);
status_t allocateBuffersOnPort(OMX_U32 portIndex);
status_t freeBuffersOnPort(OMX_U32 portIndex);
@@ -341,16 +343,22 @@
status_t setSupportedOutputFormat(bool getLegacyFlexibleFormat);
status_t setupVideoDecoder(
- const char *mime, const sp<AMessage> &msg, bool usingNativeBuffers);
+ const char *mime, const sp<AMessage> &msg, bool usingNativeBuffers,
+ sp<AMessage> &outputformat);
status_t setupVideoEncoder(
- const char *mime, const sp<AMessage> &msg);
+ const char *mime, const sp<AMessage> &msg, sp<AMessage> &outputformat);
status_t setVideoFormatOnPort(
OMX_U32 portIndex,
int32_t width, int32_t height,
OMX_VIDEO_CODINGTYPE compressionFormat, float frameRate = -1.0);
+ status_t setColorAspects(
+ OMX_U32 portIndex, int32_t width, int32_t height, const sp<AMessage> &msg,
+ sp<AMessage> &format);
+ status_t getColorAspects(OMX_U32 portIndex, sp<AMessage> &format);
+
typedef struct drcParams {
int32_t drcCut;
int32_t drcBoost;
diff --git a/include/media/stagefright/CodecBase.h b/include/media/stagefright/CodecBase.h
index 3131090..3de0d21 100644
--- a/include/media/stagefright/CodecBase.h
+++ b/include/media/stagefright/CodecBase.h
@@ -19,12 +19,16 @@
#define CODEC_BASE_H_
#include <stdint.h>
-#include <media/IOMX.h>
+#include <media/IOMX.h>
#include <media/MediaCodecInfo.h>
#include <media/stagefright/foundation/AHandler.h>
+#include <media/hardware/HardwareAPI.h>
+
#include <utils/NativeHandle.h>
+#include <system/graphics.h>
+
namespace android {
struct ABuffer;
@@ -89,6 +93,117 @@
DISALLOW_EVIL_CONSTRUCTORS(PortDescription);
};
+ /*
+ * Codec-related defines
+ */
+
+ /**********************************************************************************************/
+
+ /*
+ * Media-platform color constants. MediaCodec uses (an extended version of) platform-defined
+ * constants that are derived from HAL_DATASPACE, since these are directly exposed to the user.
+ * We extend the values to maintain the richer set of information defined inside media
+ * containers and bitstreams that are not supported by the platform. We also expect vendors
+ * to extend some of these values with vendor-specific values. These are separated into a
+ * vendor-extension section so they won't collide with future platform values.
+ */
+
+ enum ColorStandard : uint32_t {
+ kColorStandardUnspecified =
+ HAL_DATASPACE_STANDARD_UNSPECIFIED >> HAL_DATASPACE_STANDARD_SHIFT,
+ kColorStandardBT709 = HAL_DATASPACE_STANDARD_BT709 >> HAL_DATASPACE_STANDARD_SHIFT,
+ kColorStandardBT601_625 = HAL_DATASPACE_STANDARD_BT601_625 >> HAL_DATASPACE_STANDARD_SHIFT,
+ kColorStandardBT601_625_Unadjusted =
+ HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED >> HAL_DATASPACE_STANDARD_SHIFT,
+ kColorStandardBT601_525 = HAL_DATASPACE_STANDARD_BT601_525 >> HAL_DATASPACE_STANDARD_SHIFT,
+ kColorStandardBT601_525_Unadjusted =
+ HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED >> HAL_DATASPACE_STANDARD_SHIFT,
+ kColorStandardBT2020 = HAL_DATASPACE_STANDARD_BT2020 >> HAL_DATASPACE_STANDARD_SHIFT,
+ kColorStandardBT2020Constant =
+ HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE >> HAL_DATASPACE_STANDARD_SHIFT,
+ kColorStandardBT470M = HAL_DATASPACE_STANDARD_BT470M >> HAL_DATASPACE_STANDARD_SHIFT,
+ kColorStandardFilm = HAL_DATASPACE_STANDARD_FILM >> HAL_DATASPACE_STANDARD_SHIFT,
+ kColorStandardMax = HAL_DATASPACE_STANDARD_MASK >> HAL_DATASPACE_STANDARD_SHIFT,
+
+ /* This marks a section of color-standard values that are not supported by graphics HAL,
+ but track defined color primaries-matrix coefficient combinations in media.
+ These are stable for a given release. */
+ kColorStandardExtendedStart = kColorStandardMax + 1,
+
+ /* This marks a section of color-standard values that are not supported by graphics HAL
+ nor using media defined color primaries or matrix coefficients. These may differ per
+ device. */
+ kColorStandardVendorStart = 0x10000,
+ };
+
+ enum ColorTransfer : uint32_t {
+ kColorTransferUnspecified =
+ HAL_DATASPACE_TRANSFER_UNSPECIFIED >> HAL_DATASPACE_TRANSFER_SHIFT,
+ kColorTransferLinear = HAL_DATASPACE_TRANSFER_LINEAR >> HAL_DATASPACE_TRANSFER_SHIFT,
+ kColorTransferSRGB = HAL_DATASPACE_TRANSFER_SRGB >> HAL_DATASPACE_TRANSFER_SHIFT,
+ kColorTransferSMPTE_170M =
+ HAL_DATASPACE_TRANSFER_SMPTE_170M >> HAL_DATASPACE_TRANSFER_SHIFT,
+ kColorTransferGamma22 = HAL_DATASPACE_TRANSFER_GAMMA2_2 >> HAL_DATASPACE_TRANSFER_SHIFT,
+ kColorTransferGamma28 = HAL_DATASPACE_TRANSFER_GAMMA2_8 >> HAL_DATASPACE_TRANSFER_SHIFT,
+ kColorTransferST2084 = HAL_DATASPACE_TRANSFER_ST2084 >> HAL_DATASPACE_TRANSFER_SHIFT,
+ kColorTransferHLG = HAL_DATASPACE_TRANSFER_HLG >> HAL_DATASPACE_TRANSFER_SHIFT,
+ kColorTransferMax = HAL_DATASPACE_TRANSFER_MASK >> HAL_DATASPACE_TRANSFER_SHIFT,
+
+ /* This marks a section of color-transfer values that are not supported by graphics HAL,
+ but track media-defined color-transfer. These are stable for a given release. */
+ kColorTransferExtendedStart = kColorTransferMax + 1,
+
+ /* This marks a section of color-transfer values that are not supported by graphics HAL
+ nor defined by media. These may differ per device. */
+ kColorTransferVendorStart = 0x10000,
+ };
+
+ enum ColorRange : uint32_t {
+ kColorRangeUnspecified = HAL_DATASPACE_RANGE_UNSPECIFIED >> HAL_DATASPACE_RANGE_SHIFT,
+ kColorRangeFull = HAL_DATASPACE_RANGE_FULL >> HAL_DATASPACE_RANGE_SHIFT,
+ kColorRangeLimited = HAL_DATASPACE_RANGE_LIMITED >> HAL_DATASPACE_RANGE_SHIFT,
+ kColorRangeMax = HAL_DATASPACE_RANGE_MASK >> HAL_DATASPACE_RANGE_SHIFT,
+
+ /* This marks a section of color-transfer values that are not supported by graphics HAL,
+ but track media-defined color-transfer. These are stable for a given release. */
+ kColorRangeExtendedStart = kColorRangeMax + 1,
+
+ /* This marks a section of color-transfer values that are not supported by graphics HAL
+ nor defined by media. These may differ per device. */
+ kColorRangeVendorStart = 0x10000,
+ };
+
+ /*
+ * Static utilities for codec support
+ */
+
+ // using int32_t for media range/standard/transfers to denote extended ranges
+ static int32_t wrapColorAspectsIntoColorStandard(
+ ColorAspects::Primaries primaries, ColorAspects::MatrixCoeffs coeffs);
+ static int32_t wrapColorAspectsIntoColorRange(ColorAspects::Range range);
+ static int32_t wrapColorAspectsIntoColorTransfer(ColorAspects::Transfer transfer);
+
+ static status_t unwrapColorAspectsFromColorRange(
+ int32_t range, ColorAspects::Range *aspect);
+ static status_t unwrapColorAspectsFromColorTransfer(
+ int32_t transfer, ColorAspects::Transfer *aspect);
+ static status_t unwrapColorAspectsFromColorStandard(
+ int32_t standard,
+ ColorAspects::Primaries *primaries, ColorAspects::MatrixCoeffs *coeffs);
+
+ static status_t convertPlatformColorAspectsToCodecAspects(
+ int32_t range, int32_t standard, int32_t transfer, ColorAspects &aspects);
+ static status_t convertCodecColorAspectsToPlatformAspects(
+ const ColorAspects &aspects,
+ int32_t *range, int32_t *standard, int32_t *transfer);
+
+ // updates unspecified range, standard and transfer values to their defaults
+ static void setDefaultPlatformColorAspectsIfNeeded(
+ int32_t &range, int32_t &standard, int32_t &transfer,
+ int32_t width, int32_t height);
+ static void setDefaultCodecColorAspectsIfNeeded(
+ ColorAspects &aspects, int32_t width, int32_t height);
+
protected:
CodecBase();
virtual ~CodecBase();
diff --git a/include/media/stagefright/foundation/ALookup.h b/include/media/stagefright/foundation/ALookup.h
new file mode 100644
index 0000000..571eda2
--- /dev/null
+++ b/include/media/stagefright/foundation/ALookup.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef A_LOOKUP_H_
+
+#define A_LOOKUP_H_
+
+#include <utility>
+#include <vector>
+
+namespace android {
+
+template<typename T, typename U>
+struct ALookup {
+ ALookup(std::initializer_list<std::pair<T, U>> list);
+
+ bool lookup(const T& from, U *to);
+ bool rlookup(const U& from, T *to);
+ inline bool map(const T& from, U *to) { return lookup(from, to); }
+ inline bool map(const U& from, T *to) { return rlookup(from, to); }
+
+private:
+ std::vector<std::pair<T, U>> mTable;
+};
+
+template<typename T, typename U>
+ALookup<T, U>::ALookup(std::initializer_list<std::pair<T, U>> list)
+ : mTable(list) {
+}
+
+template<typename T, typename U>
+bool ALookup<T, U>::lookup(const T& from, U *to) {
+ for (auto elem : mTable) {
+ if (elem.first == from) {
+ *to = elem.second;
+ return true;
+ }
+ }
+ return false;
+}
+
+template<typename T, typename U>
+bool ALookup<T, U>::rlookup(const U& from, T *to) {
+ for (auto elem : mTable) {
+ if (elem.second == from) {
+ *to = elem.first;
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace android
+
+#endif // A_UTILS_H_
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index d0651f3..def9e25 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -511,7 +511,8 @@
mTimePerFrameUs(-1ll),
mTimePerCaptureUs(-1ll),
mCreateInputBuffersSuspended(false),
- mTunneled(false) {
+ mTunneled(false),
+ mDescribeColorAspectsIndex((OMX_INDEXTYPE)0) {
mUninitializedState = new UninitializedState(this);
mLoadedState = new LoadedState(this);
mLoadedToIdleState = new LoadedToIdleState(this);
@@ -1940,9 +1941,9 @@
}
if (encoder) {
- err = setupVideoEncoder(mime, msg);
+ err = setupVideoEncoder(mime, msg, outputFormat);
} else {
- err = setupVideoDecoder(mime, msg, haveNativeWindow);
+ err = setupVideoDecoder(mime, msg, haveNativeWindow, outputFormat);
}
if (err != OK) {
@@ -2003,7 +2004,7 @@
// fallback is not supported for protected playback
err = PERMISSION_DENIED;
} else if (err == OK) {
- err = setupVideoDecoder(mime, msg, false);
+ err = setupVideoDecoder(mime, msg, false, outputFormat);
}
}
}
@@ -3010,7 +3011,8 @@
}
status_t ACodec::setupVideoDecoder(
- const char *mime, const sp<AMessage> &msg, bool haveNativeWindow) {
+ const char *mime, const sp<AMessage> &msg, bool haveNativeWindow,
+ sp<AMessage> &outputFormat) {
int32_t width, height;
if (!msg->findInt32("width", &width)
|| !msg->findInt32("height", &height)) {
@@ -3073,10 +3075,113 @@
return err;
}
+ err = setColorAspects(
+ kPortIndexOutput, width, height, msg, outputFormat);
+ if (err != OK) {
+ ALOGI("Falling back to presets as component does not describe color aspects.");
+ err = OK;
+ }
+
+ return err;
+}
+
+status_t ACodec::setColorAspects(
+ OMX_U32 portIndex, int32_t width, int32_t height, const sp<AMessage> &msg,
+ sp<AMessage> &format) {
+ DescribeColorAspectsParams params;
+ InitOMXParams(¶ms);
+ params.nPortIndex = portIndex;
+
+ // 0 values are unspecified
+ int32_t range = 0, standard = 0, transfer = 0;
+ if (portIndex == kPortIndexInput) {
+ // Encoders allow overriding default aspects with 0 if specified by format. Decoders do not.
+ setDefaultPlatformColorAspectsIfNeeded(range, standard, transfer, width, height);
+ }
+ (void)msg->findInt32("color-range", &range);
+ (void)msg->findInt32("color-standard", &standard);
+ (void)msg->findInt32("color-transfer", &transfer);
+
+ if (convertPlatformColorAspectsToCodecAspects(
+ range, standard, transfer, params.sAspects) != OK) {
+ ALOGW("[%s] Ignoring illegal color aspects(range=%d, standard=%d, transfer=%d)",
+ mComponentName.c_str(), range, standard, transfer);
+ // Invalid values were converted to unspecified !params!, but otherwise were not changed
+ // For encoders, we leave these as is. For decoders, we will use default values.
+ }
+
+ // set defaults for decoders.
+ if (portIndex != kPortIndexInput) {
+ setDefaultCodecColorAspectsIfNeeded(params.sAspects, width, height);
+ convertCodecColorAspectsToPlatformAspects(params.sAspects, &range, &standard, &transfer);
+ }
+
+ // save updated values to base output format (encoder input format will read back actually
+ // supported values by the codec)
+ if (range != 0) {
+ format->setInt32("color-range", range);
+ }
+ if (standard != 0) {
+ format->setInt32("color-standard", standard);
+ }
+ if (transfer != 0) {
+ format->setInt32("color-transfer", transfer);
+ }
+
+ // communicate color aspects to codec
+ status_t err = mOMX->getExtensionIndex(
+ mNode, "OMX.google.android.index.describeColorAspects", &mDescribeColorAspectsIndex);
+ if (err != OK) {
+ mDescribeColorAspectsIndex = (OMX_INDEXTYPE)0;
+ return err;
+ }
+
+ return mOMX->setConfig(mNode, mDescribeColorAspectsIndex, ¶ms, sizeof(params));
+}
+
+status_t ACodec::getColorAspects(OMX_U32 portIndex, sp<AMessage> &format) {
+ if (!mDescribeColorAspectsIndex) {
+ return ERROR_UNSUPPORTED;
+ }
+
+ DescribeColorAspectsParams params;
+ InitOMXParams(¶ms);
+ params.nPortIndex = portIndex;
+ ColorAspects &aspects = params.sAspects;
+ aspects.mRange = ColorAspects::RangeUnspecified;
+ aspects.mPrimaries = ColorAspects::PrimariesUnspecified;
+ aspects.mMatrixCoeffs = ColorAspects::MatrixUnspecified;
+ aspects.mTransfer = ColorAspects::TransferUnspecified;
+
+ status_t err = mOMX->getConfig(mNode, mDescribeColorAspectsIndex, ¶ms, sizeof(params));
+ if (err != OK) {
+ return err;
+ }
+
+ // keep non-standard codec values in extension ranges
+ int32_t range, standard, transfer;
+ if (convertCodecColorAspectsToPlatformAspects(
+ params.sAspects, &range, &standard, &transfer) != OK) {
+ ALOGW("[%s] Ignoring invalid color aspects(range=%u, primaries=%u, coeffs=%u, transfer=%u)",
+ mComponentName.c_str(),
+ aspects.mRange, aspects.mPrimaries, aspects.mMatrixCoeffs, aspects.mTransfer);
+ }
+
+ // save specified values to format
+ if (range != 0) {
+ format->setInt32("color-range", range);
+ }
+ if (standard != 0) {
+ format->setInt32("color-standard", standard);
+ }
+ if (transfer != 0) {
+ format->setInt32("color-transfer", transfer);
+ }
return OK;
}
-status_t ACodec::setupVideoEncoder(const char *mime, const sp<AMessage> &msg) {
+status_t ACodec::setupVideoEncoder(
+ const char *mime, const sp<AMessage> &msg, sp<AMessage> &outputFormat) {
int32_t tmp;
if (!msg->findInt32("color-format", &tmp)) {
return INVALID_OPERATION;
@@ -3247,6 +3352,15 @@
break;
}
+ // Set up color aspects on input, but propagate them to the output format, as they will
+ // not be read back from encoder.
+ err = setColorAspects(
+ kPortIndexInput, width, height, msg, outputFormat);
+ if (err != OK) {
+ ALOGI("[%s] cannot encode color aspects. Ignoring.", mComponentName.c_str());
+ err = OK;
+ }
+
if (err == OK) {
ALOGI("setupVideoEncoder succeeded");
}
@@ -4220,6 +4334,8 @@
break;
}
+ (void)getColorAspects(portIndex, notify);
+
OMX_CONFIG_RECTTYPE rect;
InitOMXParams(&rect);
rect.nPortIndex = portIndex;
diff --git a/media/libstagefright/CodecBase.cpp b/media/libstagefright/CodecBase.cpp
index f729d4d..c9de2b0 100644
--- a/media/libstagefright/CodecBase.cpp
+++ b/media/libstagefright/CodecBase.cpp
@@ -20,6 +20,8 @@
#include <inttypes.h>
#include <media/stagefright/CodecBase.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALookup.h>
namespace android {
@@ -35,4 +37,277 @@
CodecBase::PortDescription::~PortDescription() {
}
+/***************************************** COLOR SUPPORT *****************************************/
+
+// shortcut names for brevity in the following tables
+typedef ColorAspects CA;
+typedef CodecBase CB;
+
+ALookup<CB::ColorRange, CA::Range> sRanges{
+ {
+ { CB::kColorRangeLimited, CA::RangeLimited },
+ { CB::kColorRangeFull, CA::RangeFull },
+ { CB::kColorRangeUnspecified, CA::RangeUnspecified },
+ }
+};
+
+ALookup<CB::ColorStandard, std::pair<CA::Primaries, CA::MatrixCoeffs>> sStandards {
+ {
+ { CB::kColorStandardUnspecified, { CA::PrimariesUnspecified, CA::MatrixUnspecified } },
+ { CB::kColorStandardBT709, { CA::PrimariesBT709_5, CA::MatrixBT709_5 } },
+ { CB::kColorStandardBT601_625, { CA::PrimariesBT601_6_625, CA::MatrixBT601_6 } },
+ { CB::kColorStandardBT601_625_Unadjusted,
+ // this is a really close match
+ { CA::PrimariesBT601_6_625, CA::MatrixBT709_5 } },
+ { CB::kColorStandardBT601_525, { CA::PrimariesBT601_6_525, CA::MatrixBT601_6 } },
+ { CB::kColorStandardBT601_525_Unadjusted,
+ { CA::PrimariesBT601_6_525, CA::MatrixSMPTE240M } },
+ { CB::kColorStandardBT2020, { CA::PrimariesBT2020, CA::MatrixBT2020 } },
+ { CB::kColorStandardBT2020Constant, { CA::PrimariesBT2020, CA::MatrixBT2020Constant } },
+ { CB::kColorStandardBT470M, { CA::PrimariesBT470_6M, CA::MatrixBT470_6M } },
+ // NOTE: there is no close match to the matrix used by standard film, chose closest
+ { CB::kColorStandardFilm, { CA::PrimariesGenericFilm, CA::MatrixBT2020 } },
+ }
+};
+
+ALookup<CB::ColorTransfer, CA::Transfer> sTransfers{
+ {
+ { CB::kColorTransferUnspecified, CA::TransferUnspecified },
+ { CB::kColorTransferLinear, CA::TransferLinear },
+ { CB::kColorTransferSRGB, CA::TransferSRGB },
+ { CB::kColorTransferSMPTE_170M, CA::TransferSMPTE170M },
+ { CB::kColorTransferGamma22, CA::TransferGamma22 },
+ { CB::kColorTransferGamma28, CA::TransferGamma28 },
+ { CB::kColorTransferST2084, CA::TransferST2084 },
+ { CB::kColorTransferHLG, CA::TransferHLG },
+ }
+};
+
+static bool isValid(ColorAspects::Primaries p) {
+ return p <= ColorAspects::PrimariesOther;
+}
+
+static bool isDefined(ColorAspects::Primaries p) {
+ return p <= ColorAspects::PrimariesBT2020;
+}
+
+static bool isValid(ColorAspects::MatrixCoeffs c) {
+ return c <= ColorAspects::MatrixOther;
+}
+
+static bool isDefined(ColorAspects::MatrixCoeffs c) {
+ return c <= ColorAspects::MatrixBT2020Constant;
+}
+
+//static
+int32_t CodecBase::wrapColorAspectsIntoColorStandard(
+ ColorAspects::Primaries primaries, ColorAspects::MatrixCoeffs coeffs) {
+ ColorStandard res;
+ if (sStandards.map(std::make_pair(primaries, coeffs), &res)) {
+ return res;
+ } else if (!isValid(primaries) || !isValid(coeffs)) {
+ return kColorStandardUnspecified;
+ }
+
+ // check platform media limits
+ uint32_t numPrimaries = ColorAspects::PrimariesBT2020 + 1;
+ if (isDefined(primaries) && isDefined(coeffs)) {
+ return kColorStandardExtendedStart + primaries + coeffs * numPrimaries;
+ } else {
+ return kColorStandardVendorStart + primaries + coeffs * 0x100;
+ }
+}
+
+//static
+status_t CodecBase::unwrapColorAspectsFromColorStandard(
+ int32_t standard,
+ ColorAspects::Primaries *primaries, ColorAspects::MatrixCoeffs *coeffs) {
+ std::pair<ColorAspects::Primaries, ColorAspects::MatrixCoeffs> res;
+ if (sStandards.map((ColorStandard)standard, &res)) {
+ *primaries = res.first;
+ *coeffs = res.second;
+ return OK;
+ }
+
+ int32_t start = kColorStandardExtendedStart;
+ int32_t numPrimaries = ColorAspects::PrimariesBT2020 + 1;
+ int32_t numCoeffs = ColorAspects::MatrixBT2020Constant + 1;
+ if (standard >= (int32_t)kColorStandardVendorStart) {
+ start = kColorStandardVendorStart;
+ numPrimaries = ColorAspects::PrimariesOther + 1; // 0x100
+ numCoeffs = ColorAspects::MatrixOther + 1; // 0x100;
+ }
+ if (standard >= start && standard < start + numPrimaries * numCoeffs) {
+ int32_t product = standard - start;
+ *primaries = (ColorAspects::Primaries)(product % numPrimaries);
+ *coeffs = (ColorAspects::MatrixCoeffs)(product / numPrimaries);
+ return OK;
+ }
+ *primaries = ColorAspects::PrimariesOther;
+ *coeffs = ColorAspects::MatrixOther;
+ return BAD_VALUE;
+}
+
+static bool isValid(ColorAspects::Range r) {
+ return r <= ColorAspects::RangeOther;
+}
+
+static bool isDefined(ColorAspects::Range r) {
+ return r <= ColorAspects::RangeLimited;
+}
+
+// static
+int32_t CodecBase::wrapColorAspectsIntoColorRange(ColorAspects::Range range) {
+ ColorRange res;
+ if (sRanges.map(range, &res)) {
+ return res;
+ } else if (!isValid(range)) {
+ return kColorRangeUnspecified;
+ } else {
+ CHECK(!isDefined(range));
+ // all platform values are in sRanges
+ return kColorRangeVendorStart + range;
+ }
+}
+
+//static
+status_t CodecBase::unwrapColorAspectsFromColorRange(
+ int32_t range, ColorAspects::Range *aspect) {
+ if (sRanges.map((ColorRange)range, aspect)) {
+ return OK;
+ }
+
+ int32_t start = kColorRangeVendorStart;
+ int32_t numRanges = ColorAspects::RangeOther + 1; // 0x100
+ if (range >= start && range < start + numRanges) {
+ *aspect = (ColorAspects::Range)(range - start);
+ return OK;
+ }
+ *aspect = ColorAspects::RangeOther;
+ return BAD_VALUE;
+}
+
+static bool isValid(ColorAspects::Transfer t) {
+ return t <= ColorAspects::TransferOther;
+}
+
+static bool isDefined(ColorAspects::Transfer t) {
+ return t <= ColorAspects::TransferHLG
+ || (t >= ColorAspects::TransferSMPTE240M && t <= ColorAspects::TransferST428);
+}
+
+// static
+int32_t CodecBase::wrapColorAspectsIntoColorTransfer(
+ ColorAspects::Transfer transfer) {
+ ColorTransfer res;
+ if (sTransfers.map(transfer, &res)) {
+ return res;
+ } else if (!isValid(transfer)) {
+ return kColorTransferUnspecified;
+ } else if (isDefined(transfer)) {
+ return kColorTransferExtendedStart + transfer;
+ } else {
+ // all platform values are in sRanges
+ return kColorTransferVendorStart + transfer;
+ }
+}
+
+//static
+status_t CodecBase::unwrapColorAspectsFromColorTransfer(
+ int32_t transfer, ColorAspects::Transfer *aspect) {
+ if (sTransfers.map((ColorTransfer)transfer, aspect)) {
+ return OK;
+ }
+
+ int32_t start = kColorTransferExtendedStart;
+ int32_t numTransfers = ColorAspects::TransferST428 + 1;
+ if (transfer >= (int32_t)kColorTransferVendorStart) {
+ start = kColorTransferVendorStart;
+ numTransfers = ColorAspects::TransferOther + 1; // 0x100
+ }
+ if (transfer >= start && transfer < start + numTransfers) {
+ *aspect = (ColorAspects::Transfer)(transfer - start);
+ return OK;
+ }
+ *aspect = ColorAspects::TransferOther;
+ return BAD_VALUE;
+}
+
+// static
+status_t CodecBase::convertPlatformColorAspectsToCodecAspects(
+ int32_t range, int32_t standard, int32_t transfer, ColorAspects &aspects) {
+ status_t res1 = unwrapColorAspectsFromColorRange(range, &aspects.mRange);
+ status_t res2 = unwrapColorAspectsFromColorStandard(
+ standard, &aspects.mPrimaries, &aspects.mMatrixCoeffs);
+ status_t res3 = unwrapColorAspectsFromColorTransfer(transfer, &aspects.mTransfer);
+ return res1 != OK ? res1 : (res2 != OK ? res2 : res3);
+}
+
+// static
+status_t CodecBase::convertCodecColorAspectsToPlatformAspects(
+ const ColorAspects &aspects, int32_t *range, int32_t *standard, int32_t *transfer) {
+ *range = wrapColorAspectsIntoColorRange(aspects.mRange);
+ *standard = wrapColorAspectsIntoColorStandard(aspects.mPrimaries, aspects.mMatrixCoeffs);
+ *transfer = wrapColorAspectsIntoColorTransfer(aspects.mTransfer);
+ if (isValid(aspects.mRange) && isValid(aspects.mPrimaries)
+ && isValid(aspects.mMatrixCoeffs) && isValid(aspects.mTransfer)) {
+ return OK;
+ } else {
+ return BAD_VALUE;
+ }
+}
+
+// static
+void CodecBase::setDefaultPlatformColorAspectsIfNeeded(
+ int32_t &range, int32_t &standard, int32_t &transfer,
+ int32_t width, int32_t height) {
+ if (range == CodecBase::kColorRangeUnspecified) {
+ range = CodecBase::kColorRangeLimited;
+ }
+
+ if (standard == CodecBase::kColorStandardUnspecified) {
+ // Default to BT2020, BT709 or BT601 based on size. Allow 2.35:1 aspect ratio. Limit BT601
+ // to PAL or smaller, BT2020 to 4K or larger, leaving BT709 for all resolutions in between.
+ if (width >= 3840 || height >= 3840 || width * (int64_t)height >= 3840 * 1634) {
+ standard = CodecBase::kColorStandardBT2020;
+ } else if ((width <= 720 && height > 480) || (height <= 720 && width > 480)) {
+ standard = CodecBase::kColorStandardBT601_625;
+ } else if ((width <= 720 && height <= 480) || (height <= 720 && width <= 480)) {
+ standard = CodecBase::kColorStandardBT601_525;
+ } else {
+ standard = CodecBase::kColorStandardBT709;
+ }
+ }
+
+ if (transfer == CodecBase::kColorTransferUnspecified) {
+ transfer = CodecBase::kColorTransferSMPTE_170M;
+ }
+}
+
+// static
+void CodecBase::setDefaultCodecColorAspectsIfNeeded(
+ ColorAspects &aspects, int32_t width, int32_t height) {
+ // reuse other method to get default aspects
+ int32_t range = 0, standard = 0, transfer = 0;
+ setDefaultPlatformColorAspectsIfNeeded(range, standard, transfer, width, height);
+ ColorAspects defaultAspects;
+ memset(&defaultAspects, 0, sizeof(defaultAspects));
+ convertPlatformColorAspectsToCodecAspects(range, standard, transfer, defaultAspects);
+
+ if (aspects.mRange == ColorAspects::RangeUnspecified) {
+ aspects.mRange = defaultAspects.mRange;
+ }
+ if (aspects.mPrimaries == ColorAspects::PrimariesUnspecified) {
+ aspects.mPrimaries = defaultAspects.mPrimaries;
+ }
+ if (aspects.mMatrixCoeffs == ColorAspects::MatrixUnspecified) {
+ aspects.mMatrixCoeffs = defaultAspects.mMatrixCoeffs;
+ }
+ if (aspects.mTransfer == ColorAspects::TransferUnspecified) {
+ aspects.mTransfer = defaultAspects.mTransfer;
+ }
+}
+
+/**************************************************************************************************/
+
} // namespace android