Codec2: Properly support color aspects
- implement configure and reading color aspects
decoder: configure default aspects, read back final aspects
encoder: configure source aspects, read back source and coded aspects
- directly set final aspects for components that do not support color
aspects (via local param)
- set default color aspects for surface mode. Do this in getSdkParams
so that it can be shared by decoder and encoder. Note: this also
must update dataspace which again can be shared by decoder and encoder.
Bug: 110225406
Change-Id: I486600e4b6ca02def89c3e5b65a9b861362035c7
diff --git a/media/sfplugin/CCodec.cpp b/media/sfplugin/CCodec.cpp
index a24be2f..e1081e7 100644
--- a/media/sfplugin/CCodec.cpp
+++ b/media/sfplugin/CCodec.cpp
@@ -664,6 +664,7 @@
}
Mutexed<Config>::Locked config(mConfig);
+ config->mUsingSurface = surface != nullptr;
/*
* Handle input surface configuration
@@ -954,6 +955,7 @@
Mutexed<Config>::Locked config(mConfig);
config->mInputSurface = surface;
+ config->mUsingSurface = true;
if (config->mISConfig) {
surface->configure(*config->mISConfig);
} else {
@@ -1495,6 +1497,7 @@
const static std::vector<C2Param::Index> stdGfxInfos = {
C2StreamRotationInfo::output::PARAM_TYPE,
C2StreamColorAspectsInfo::output::PARAM_TYPE,
+ C2StreamDataSpaceInfo::output::PARAM_TYPE,
C2StreamHdrStaticInfo::output::PARAM_TYPE,
C2StreamPixelAspectRatioInfo::output::PARAM_TYPE,
C2StreamSurfaceScalingInfo::output::PARAM_TYPE
diff --git a/media/sfplugin/CCodecBufferChannel.cpp b/media/sfplugin/CCodecBufferChannel.cpp
index fd3e87d..781f7d3 100644
--- a/media/sfplugin/CCodecBufferChannel.cpp
+++ b/media/sfplugin/CCodecBufferChannel.cpp
@@ -1539,84 +1539,9 @@
videoScalingMode = surfaceScaling->value;
}
- // Use dataspace if component provides it. Otherwise, compose dataspace from color aspects
- std::shared_ptr<const C2StreamDataSpaceInfo::output> dataSpaceInfo =
- std::static_pointer_cast<const C2StreamDataSpaceInfo::output>(
- c2Buffer->getInfo(C2StreamDataSpaceInfo::output::PARAM_TYPE));
- uint32_t dataSpace = HAL_DATASPACE_UNKNOWN; // this is 0
- if (dataSpaceInfo) {
- dataSpace = dataSpaceInfo->value;
- } else {
- std::shared_ptr<const C2StreamColorAspectsInfo::output> colorAspects =
- std::static_pointer_cast<const C2StreamColorAspectsInfo::output>(
- c2Buffer->getInfo(C2StreamColorAspectsInfo::output::PARAM_TYPE));
- C2Color::range_t range =
- colorAspects == nullptr ? C2Color::RANGE_UNSPECIFIED : colorAspects->range;
- C2Color::primaries_t primaries =
- colorAspects == nullptr ? C2Color::PRIMARIES_UNSPECIFIED : colorAspects->primaries;
- C2Color::transfer_t transfer =
- colorAspects == nullptr ? C2Color::TRANSFER_UNSPECIFIED : colorAspects->transfer;
- C2Color::matrix_t matrix =
- colorAspects == nullptr ? C2Color::MATRIX_UNSPECIFIED : colorAspects->matrix;
-
- switch (range) {
- case C2Color::RANGE_FULL: dataSpace |= HAL_DATASPACE_RANGE_FULL; break;
- case C2Color::RANGE_LIMITED: dataSpace |= HAL_DATASPACE_RANGE_LIMITED; break;
- default: break;
- }
-
- switch (transfer) {
- case C2Color::TRANSFER_LINEAR: dataSpace |= HAL_DATASPACE_TRANSFER_LINEAR; break;
- case C2Color::TRANSFER_SRGB: dataSpace |= HAL_DATASPACE_TRANSFER_SRGB; break;
- case C2Color::TRANSFER_170M: dataSpace |= HAL_DATASPACE_TRANSFER_SMPTE_170M; break;
- case C2Color::TRANSFER_GAMMA22: dataSpace |= HAL_DATASPACE_TRANSFER_GAMMA2_2; break;
- case C2Color::TRANSFER_GAMMA28: dataSpace |= HAL_DATASPACE_TRANSFER_GAMMA2_8; break;
- case C2Color::TRANSFER_ST2084: dataSpace |= HAL_DATASPACE_TRANSFER_ST2084; break;
- case C2Color::TRANSFER_HLG: dataSpace |= HAL_DATASPACE_TRANSFER_HLG; break;
- default: break;
- }
-
- switch (primaries) {
- case C2Color::PRIMARIES_BT601_525:
- dataSpace |= (matrix == C2Color::MATRIX_SMPTE240M
- || matrix == C2Color::MATRIX_BT709)
- ? HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED
- : HAL_DATASPACE_STANDARD_BT601_525;
- break;
- case C2Color::PRIMARIES_BT601_625:
- dataSpace |= (matrix == C2Color::MATRIX_SMPTE240M
- || matrix == C2Color::MATRIX_BT709)
- ? HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED
- : HAL_DATASPACE_STANDARD_BT601_625;
- break;
- case C2Color::PRIMARIES_BT2020:
- dataSpace |= (matrix == C2Color::MATRIX_BT2020CONSTANT
- ? HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE
- : HAL_DATASPACE_STANDARD_BT2020);
- break;
- case C2Color::PRIMARIES_BT470_M:
- dataSpace |= HAL_DATASPACE_STANDARD_BT470M;
- break;
- case C2Color::PRIMARIES_BT709:
- dataSpace |= HAL_DATASPACE_STANDARD_BT709;
- break;
- default: break;
- }
- }
-
- // convert legacy dataspace values to v0 values
- const static
- ALookup<android_dataspace, android_dataspace> sLegacyDataSpaceToV0 {
- {
- { HAL_DATASPACE_SRGB, HAL_DATASPACE_V0_SRGB },
- { HAL_DATASPACE_BT709, HAL_DATASPACE_V0_BT709 },
- { HAL_DATASPACE_SRGB_LINEAR, HAL_DATASPACE_V0_SRGB_LINEAR },
- { HAL_DATASPACE_BT601_525, HAL_DATASPACE_V0_BT601_525 },
- { HAL_DATASPACE_BT601_625, HAL_DATASPACE_V0_BT601_625 },
- { HAL_DATASPACE_JFIF, HAL_DATASPACE_V0_JFIF },
- }
- };
- sLegacyDataSpaceToV0.lookup((android_dataspace_t)dataSpace, (android_dataspace_t*)&dataSpace);
+ // Use dataspace from format as it has the default aspects already applied
+ android_dataspace_t dataSpace = HAL_DATASPACE_UNKNOWN; // this is 0
+ (void)buffer->format()->findInt32("android._dataspace", (int32_t *)&dataSpace);
// HDR static info
std::shared_ptr<const C2StreamHdrStaticInfo::output> hdrStaticInfo =
@@ -1641,8 +1566,8 @@
// TODO: revisit this after C2Fence implementation.
android::IGraphicBufferProducer::QueueBufferInput qbi(
timestampNs,
- false,
- (android_dataspace_t)dataSpace,
+ false, // droppable
+ dataSpace,
Rect(blocks.front().crop().left,
blocks.front().crop().top,
blocks.front().crop().right(),
diff --git a/media/sfplugin/CCodecBufferChannel.h b/media/sfplugin/CCodecBufferChannel.h
index 92150f8..c043686 100644
--- a/media/sfplugin/CCodecBufferChannel.h
+++ b/media/sfplugin/CCodecBufferChannel.h
@@ -25,6 +25,7 @@
#include <C2Buffer.h>
#include <C2Component.h>
+#include <Codec2Mapper.h>
#include <codec2/hidl/client.h>
#include <media/stagefright/bqhelper/GraphicBufferSource.h>
diff --git a/media/sfplugin/CCodecConfig.cpp b/media/sfplugin/CCodecConfig.cpp
index e5d5fbb..51af6bc 100644
--- a/media/sfplugin/CCodecConfig.cpp
+++ b/media/sfplugin/CCodecConfig.cpp
@@ -22,6 +22,7 @@
#include <C2Component.h>
#include <C2Debug.h>
#include <C2Param.h>
+#include <util/C2InterfaceHelper.h>
#include <media/stagefright/MediaCodecConstants.h>
@@ -87,6 +88,31 @@
return *this;
}
+ /// Adds SDK <=> Codec 2.0 value mappers based on C2Mapper
+ template<typename C2Type, typename SdkType=int32_t>
+ ConfigMapper &withC2Mappers() {
+ C2_CHECK(!mMapper);
+ C2_CHECK(!mReverse);
+ mMapper = [](C2Value v) -> C2Value {
+ SdkType sdkValue;
+ C2Type c2Value;
+ if (v.get(&sdkValue) && C2Mapper::map(sdkValue, &c2Value)) {
+ return c2Value;
+ }
+ return C2Value();
+ };
+ mReverse = [](C2Value v) -> C2Value {
+ SdkType sdkValue;
+ C2Type c2Value;
+ using C2ValueType=typename _c2_reduce_enum_to_underlying_type<C2Type>::type;
+ if (v.get((C2ValueType*)&c2Value) && C2Mapper::map(c2Value, &sdkValue)) {
+ return sdkValue;
+ }
+ return C2Value();
+ };
+ return *this;
+ }
+
/// Maps from SDK values in an AMessage to a suitable C2Value.
C2Value mapFromMessage(const AMessage::ItemData &item) const {
C2Value value;
@@ -285,7 +311,8 @@
CCodecConfig::CCodecConfig()
: mInputFormat(new AMessage),
- mOutputFormat(new AMessage) { }
+ mOutputFormat(new AMessage),
+ mUsingSurface(false) { }
void CCodecConfig::initializeStandardParams() {
typedef Domain D;
@@ -366,6 +393,67 @@
.limitTo(D::VIDEO & D::RAW)
.withMappers(negate, negate));
+ // android 'video-scaling'
+ add(ConfigMapper("android._video-scaling", C2_PARAMKEY_SURFACE_SCALING_MODE, "value")
+ .limitTo(D::VIDEO & D::DECODER & D::RAW));
+
+ // Color Aspects
+ //
+ // configure default for decoders
+ add(ConfigMapper(KEY_COLOR_RANGE, C2_PARAMKEY_DEFAULT_COLOR_ASPECTS, "range")
+ .limitTo((D::VIDEO | D::IMAGE) & D::DECODER & D::CODED & (D::CONFIG | D::PARAM))
+ .withC2Mappers<C2Color::range_t>());
+ add(ConfigMapper(KEY_COLOR_TRANSFER, C2_PARAMKEY_DEFAULT_COLOR_ASPECTS, "transfer")
+ .limitTo((D::VIDEO | D::IMAGE) & D::DECODER & D::CODED & (D::CONFIG | D::PARAM))
+ .withC2Mappers<C2Color::transfer_t>());
+ add(ConfigMapper("color-primaries", C2_PARAMKEY_DEFAULT_COLOR_ASPECTS, "primaries")
+ .limitTo((D::VIDEO | D::IMAGE) & D::DECODER & D::CODED & (D::CONFIG | D::PARAM)));
+ add(ConfigMapper("color-matrix", C2_PARAMKEY_DEFAULT_COLOR_ASPECTS, "matrix")
+ .limitTo((D::VIDEO | D::IMAGE) & D::DECODER & D::CODED & (D::CONFIG | D::PARAM)));
+
+ // read back final for decoder output (also, configure final aspects as well. This should be
+ // overwritten based on coded/default values if component supports color aspects, but is used
+ // as final values if component does not support aspects at all)
+ add(ConfigMapper(KEY_COLOR_RANGE, C2_PARAMKEY_COLOR_ASPECTS, "range")
+ .limitTo((D::VIDEO | D::IMAGE) & D::DECODER & D::RAW)
+ .withC2Mappers<C2Color::range_t>());
+ add(ConfigMapper(KEY_COLOR_TRANSFER, C2_PARAMKEY_COLOR_ASPECTS, "transfer")
+ .limitTo((D::VIDEO | D::IMAGE) & D::DECODER & D::RAW)
+ .withC2Mappers<C2Color::transfer_t>());
+ add(ConfigMapper("color-primaries", C2_PARAMKEY_COLOR_ASPECTS, "primaries")
+ .limitTo((D::VIDEO | D::IMAGE) & D::DECODER & D::RAW));
+ add(ConfigMapper("color-matrix", C2_PARAMKEY_COLOR_ASPECTS, "matrix")
+ .limitTo((D::VIDEO | D::IMAGE) & D::DECODER & D::RAW));
+
+ // configure source aspects for encoders and read them back on the coded(!) port.
+ // This is to ensure muxing the desired aspects into the container.
+ add(ConfigMapper(KEY_COLOR_RANGE, C2_PARAMKEY_COLOR_ASPECTS, "range")
+ .limitTo((D::VIDEO | D::IMAGE) & D::ENCODER & D::CODED)
+ .withC2Mappers<C2Color::range_t>());
+ add(ConfigMapper(KEY_COLOR_TRANSFER, C2_PARAMKEY_COLOR_ASPECTS, "transfer")
+ .limitTo((D::VIDEO | D::IMAGE) & D::ENCODER & D::CODED)
+ .withC2Mappers<C2Color::transfer_t>());
+ add(ConfigMapper("color-primaries", C2_PARAMKEY_COLOR_ASPECTS, "primaries")
+ .limitTo((D::VIDEO | D::IMAGE) & D::ENCODER & D::CODED));
+ add(ConfigMapper("color-matrix", C2_PARAMKEY_COLOR_ASPECTS, "matrix")
+ .limitTo((D::VIDEO | D::IMAGE) & D::ENCODER & D::CODED));
+
+ // read back coded aspects for encoders (on the raw port)
+ add(ConfigMapper(KEY_COLOR_RANGE, C2_PARAMKEY_VUI_COLOR_ASPECTS, "range")
+ .limitTo((D::VIDEO | D::IMAGE) & D::ENCODER & D::RAW & D::READ)
+ .withC2Mappers<C2Color::range_t>());
+ add(ConfigMapper(KEY_COLOR_TRANSFER, C2_PARAMKEY_VUI_COLOR_ASPECTS, "transfer")
+ .limitTo((D::VIDEO | D::IMAGE) & D::ENCODER & D::RAW & D::READ)
+ .withC2Mappers<C2Color::transfer_t>());
+ add(ConfigMapper("color-primaries", C2_PARAMKEY_VUI_COLOR_ASPECTS, "primaries")
+ .limitTo((D::VIDEO | D::IMAGE) & D::ENCODER & D::RAW & D::READ));
+ add(ConfigMapper("color-matrix", C2_PARAMKEY_VUI_COLOR_ASPECTS, "matrix")
+ .limitTo((D::VIDEO | D::IMAGE) & D::ENCODER & D::RAW & D::READ));
+
+ // Dataspace
+ add(ConfigMapper("android._dataspace", C2_PARAMKEY_DATA_SPACE, "value")
+ .limitTo((D::VIDEO | D::IMAGE) & D::RAW));
+
add(ConfigMapper(std::string(KEY_FEATURE_) + FEATURE_SecurePlayback,
C2_PARAMKEY_SECURE_MODE, "value"));
@@ -751,19 +839,22 @@
if (kind.value == C2Component::KIND_ENCODER) {
mParamUpdater->addStandardParam<C2StreamInitDataInfo::output>(C2_PARAMKEY_INIT_DATA);
}
- if (kind.value != C2Component::KIND_ENCODER
- && (domain.value == C2Component::DOMAIN_IMAGE
- || domain.value == C2Component::DOMAIN_VIDEO)) {
- addLocalParam<C2StreamPictureSizeInfo::output>(C2_PARAMKEY_PICTURE_SIZE);
- addLocalParam<C2StreamCropRectInfo::output>(C2_PARAMKEY_CROP_RECT);
- addLocalParam(
- new C2StreamPixelAspectRatioInfo::output(0u, 1u, 1u),
- C2_PARAMKEY_PIXEL_ASPECT_RATIO);
- addLocalParam(new C2StreamRotationInfo::output(0u, 0), C2_PARAMKEY_ROTATION);
- addLocalParam(new C2StreamColorAspectsInfo::output(0u), C2_PARAMKEY_COLOR_ASPECTS);
- addLocalParam<C2StreamHdrStaticInfo::output>(C2_PARAMKEY_HDR_STATIC_INFO);
- addLocalParam<C2StreamDataSpaceInfo::output>(C2_PARAMKEY_DATA_SPACE);
- addLocalParam<C2StreamSurfaceScalingInfo::output>(C2_PARAMKEY_SURFACE_SCALING_MODE);
+ if (domain.value == C2Component::DOMAIN_IMAGE || domain.value == C2Component::DOMAIN_VIDEO) {
+ if (kind.value != C2Component::KIND_ENCODER) {
+ addLocalParam<C2StreamPictureSizeInfo::output>(C2_PARAMKEY_PICTURE_SIZE);
+ addLocalParam<C2StreamCropRectInfo::output>(C2_PARAMKEY_CROP_RECT);
+ addLocalParam(
+ new C2StreamPixelAspectRatioInfo::output(0u, 1u, 1u),
+ C2_PARAMKEY_PIXEL_ASPECT_RATIO);
+ addLocalParam(new C2StreamRotationInfo::output(0u, 0), C2_PARAMKEY_ROTATION);
+ addLocalParam(new C2StreamColorAspectsInfo::output(0u), C2_PARAMKEY_COLOR_ASPECTS);
+ addLocalParam<C2StreamDataSpaceInfo::output>(C2_PARAMKEY_DATA_SPACE);
+ addLocalParam<C2StreamHdrStaticInfo::output>(C2_PARAMKEY_HDR_STATIC_INFO);
+ addLocalParam(new C2StreamSurfaceScalingInfo::output(0u, VIDEO_SCALING_MODE_SCALE_TO_FIT),
+ C2_PARAMKEY_SURFACE_SCALING_MODE);
+ } else {
+ addLocalParam(new C2StreamColorAspectsInfo::input(0u), C2_PARAMKEY_COLOR_ASPECTS);
+ }
}
initializeStandardParams();
@@ -975,6 +1066,62 @@
}
}
+ { // convert color info
+ // TODO: apply platform default to decoder output
+
+ C2Color::primaries_t primaries;
+ C2Color::matrix_t matrix;
+ if (msg->findInt32("color-primaries", (int32_t*)&primaries)
+ && msg->findInt32("color-matrix", (int32_t*)&matrix)) {
+ int32_t standard;
+
+ if (C2Mapper::map(primaries, matrix, &standard)) {
+ msg->setInt32(KEY_COLOR_STANDARD, standard);
+ }
+
+ msg->removeEntryAt(msg->findEntryByName("color-primaries"));
+ msg->removeEntryAt(msg->findEntryByName("color-matrix"));
+ }
+
+
+ // calculate dataspace for raw graphic buffers if not specified by component, or if
+ // using surface with unspecified aspects (as those must be defaulted which may change
+ // the dataspace)
+ if ((portDomain & IS_RAW) && (mDomain & (IS_IMAGE | IS_VIDEO))) {
+ android_dataspace dataspace;
+ ColorAspects aspects = {
+ ColorAspects::RangeUnspecified, ColorAspects::PrimariesUnspecified,
+ ColorAspects::TransferUnspecified, ColorAspects::MatrixUnspecified
+ };
+ ColorUtils::getColorAspectsFromFormat(msg, aspects);
+ ColorAspects origAspects = aspects;
+ if (mUsingSurface) {
+ // get image size (default to HD)
+ int32_t width = 1280;
+ int32_t height = 720;
+ int32_t left, top, right, bottom;
+ if (msg->findRect("crop", &left, &top, &right, &bottom)) {
+ width = right - left + 1;
+ height = bottom - top + 1;
+ } else {
+ (void)msg->findInt32(KEY_WIDTH, &width);
+ (void)msg->findInt32(KEY_HEIGHT, &height);
+ }
+ ColorUtils::setDefaultCodecColorAspectsIfNeeded(aspects, width, height);
+ ColorUtils::setColorAspectsIntoFormat(aspects, msg);
+ }
+
+ if (!msg->findInt32("android._dataspace", (int32_t*)&dataspace)
+ || aspects.mRange != origAspects.mRange
+ || aspects.mPrimaries != origAspects.mPrimaries
+ || aspects.mTransfer != origAspects.mTransfer
+ || aspects.mMatrixCoeffs != origAspects.mMatrixCoeffs) {
+ dataspace = ColorUtils::getDataSpaceForColorAspects(aspects, true /* mayExpand */);
+ msg->setInt32("android._dataspace", dataspace);
+ }
+ }
+ }
+
ALOGV("converted to SDK values as %s", msg->debugString().c_str());
return msg;
}
@@ -1108,6 +1255,19 @@
}
}
+ { // convert color info
+ int32_t standard;
+ if (params->findInt32(KEY_COLOR_STANDARD, &standard)) {
+ C2Color::primaries_t primaries;
+ C2Color::matrix_t matrix;
+
+ if (C2Mapper::map(standard, &primaries, &matrix)) {
+ params->setInt32("color-primaries", primaries);
+ params->setInt32("color-matrix", matrix);
+ }
+ }
+ }
+
// this is to verify that we set proper signedness for standard parameters
bool beVeryStrict = property_get_bool("debug.stagefright.ccodec_strict_type", false);
// this is to allow vendors to use the wrong signedness for standard parameters
diff --git a/media/sfplugin/CCodecConfig.h b/media/sfplugin/CCodecConfig.h
index 12d6176..22a31f5 100644
--- a/media/sfplugin/CCodecConfig.h
+++ b/media/sfplugin/CCodecConfig.h
@@ -117,6 +117,8 @@
sp<AMessage> mInputFormat;
sp<AMessage> mOutputFormat;
+ bool mUsingSurface; ///< using input or output surface
+
std::shared_ptr<InputSurfaceWrapper> mInputSurface;
std::unique_ptr<InputSurfaceWrapper::Config> mISConfig;