/* * Copyright 2019 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. */ #include "CCodecConfig.h" #include #include #include #include #include #include #include namespace { enum ExtendedC2ParamIndexKind : C2Param::type_index_t { kParamIndexVendorInt32 = C2Param::TYPE_INDEX_VENDOR_START, kParamIndexVendorInt64, kParamIndexVendorString, }; typedef C2PortParam C2PortVendorInt32Info; constexpr char C2_PARAMKEY_VENDOR_INT32[] = "example.int32"; constexpr char KEY_VENDOR_INT32[] = "vendor.example.int32.value"; typedef C2StreamParam C2StreamVendorInt64Info; constexpr char C2_PARAMKEY_VENDOR_INT64[] = "example.int64"; constexpr char KEY_VENDOR_INT64[] = "vendor.example.int64.value"; typedef C2PortParam C2PortVendorStringInfo; constexpr char C2_PARAMKEY_VENDOR_STRING[] = "example.string"; constexpr char KEY_VENDOR_STRING[] = "vendor.example.string.value"; } // namespace namespace android { class CCodecConfigTest : public ::testing::Test { public: constexpr static int32_t kCodec2Int32 = 0xC0DEC2; constexpr static int64_t kCodec2Int64 = 0xC0DEC2C0DEC2ll; constexpr static char kCodec2Str[] = "codec2"; CCodecConfigTest() : mReflector{std::make_shared()} { } void init( C2Component::domain_t domain, C2Component::kind_t kind, const char *mediaType) { sp cachedConfigurable = new hardware::media::c2::V1_0::utils::CachedConfigurable( std::make_unique(mReflector, domain, kind, mediaType)); cachedConfigurable->init(std::make_shared()); mConfigurable = std::make_shared(cachedConfigurable); } struct Cache : public hardware::media::c2::V1_0::utils::ParameterCache { c2_status_t validate(const std::vector>&) override { return C2_OK; } }; class Configurable : public hardware::media::c2::V1_0::utils::ConfigurableC2Intf { public: Configurable( const std::shared_ptr &reflector, C2Component::domain_t domain, C2Component::kind_t kind, const char *mediaType) : ConfigurableC2Intf("name", 0u), mImpl(reflector, domain, kind, mediaType) { } c2_status_t query( const std::vector &indices, c2_blocking_t mayBlock, std::vector>* const params) const override { return mImpl.query({}, indices, mayBlock, params); } c2_status_t config( const std::vector ¶ms, c2_blocking_t mayBlock, std::vector>* const failures) override { return mImpl.config(params, mayBlock, failures); } c2_status_t querySupportedParams( std::vector>* const params) const override { return mImpl.querySupportedParams(params); } c2_status_t querySupportedValues( std::vector& fields, c2_blocking_t mayBlock) const override { return mImpl.querySupportedValues(fields, mayBlock); } private: class Impl : public C2InterfaceHelper { public: Impl(const std::shared_ptr &reflector, C2Component::domain_t domain, C2Component::kind_t kind, const char *mediaType) : C2InterfaceHelper{reflector} { setDerivedInstance(this); addParameter( DefineParam(mDomain, C2_PARAMKEY_COMPONENT_DOMAIN) .withConstValue(new C2ComponentDomainSetting(domain)) .build()); addParameter( DefineParam(mKind, C2_PARAMKEY_COMPONENT_KIND) .withConstValue(new C2ComponentKindSetting(kind)) .build()); addParameter( DefineParam(mInputStreamCount, C2_PARAMKEY_INPUT_STREAM_COUNT) .withConstValue(new C2PortStreamCountTuning::input(1)) .build()); addParameter( DefineParam(mOutputStreamCount, C2_PARAMKEY_OUTPUT_STREAM_COUNT) .withConstValue(new C2PortStreamCountTuning::output(1)) .build()); const char *rawMediaType = ""; switch (domain) { case C2Component::DOMAIN_IMAGE: [[fallthrough]]; case C2Component::DOMAIN_VIDEO: rawMediaType = MIMETYPE_VIDEO_RAW; break; case C2Component::DOMAIN_AUDIO: rawMediaType = MIMETYPE_AUDIO_RAW; break; default: break; } bool isEncoder = kind == C2Component::KIND_ENCODER; std::string inputMediaType{isEncoder ? rawMediaType : mediaType}; std::string outputMediaType{isEncoder ? mediaType : rawMediaType}; auto allocSharedString = [](const auto ¶m, const std::string &str) { typedef typename std::remove_reference::type::element_type T; std::shared_ptr ret = T::AllocShared(str.length() + 1); strcpy(ret->m.value, str.c_str()); return ret; }; addParameter( DefineParam(mInputMediaType, C2_PARAMKEY_INPUT_MEDIA_TYPE) .withConstValue(allocSharedString(mInputMediaType, inputMediaType)) .build()); addParameter( DefineParam(mOutputMediaType, C2_PARAMKEY_OUTPUT_MEDIA_TYPE) .withConstValue(allocSharedString(mOutputMediaType, outputMediaType)) .build()); addParameter( DefineParam(mInt32Input, C2_PARAMKEY_VENDOR_INT32) .withDefault(new C2PortVendorInt32Info::input(0)) .withFields({C2F(mInt32Input, value).any()}) .withSetter(Setter) .build()); addParameter( DefineParam(mInt64Output, C2_PARAMKEY_VENDOR_INT64) .withDefault(new C2StreamVendorInt64Info::output(0u, 0)) .withFields({C2F(mInt64Output, value).any()}) .withSetter(Setter) .build()); addParameter( DefineParam(mStringInput, C2_PARAMKEY_VENDOR_STRING) .withDefault(decltype(mStringInput)::element_type::AllocShared(1, "")) .withFields({C2F(mStringInput, m.value).any()}) .withSetter(Setter) .build()); addParameter( DefineParam(mPixelAspectRatio, C2_PARAMKEY_PIXEL_ASPECT_RATIO) .withDefault(new C2StreamPixelAspectRatioInfo::output(0u, 1, 1)) .withFields({ C2F(mPixelAspectRatio, width).any(), C2F(mPixelAspectRatio, height).any(), }) .withSetter(Setter) .build()); if (isEncoder) { addParameter( DefineParam(mInputBitrate, C2_PARAMKEY_BITRATE) .withDefault(new C2StreamBitrateInfo::input(0u)) .withFields({C2F(mInputBitrate, value).any()}) .withSetter(Setter) .build()); addParameter( DefineParam(mOutputBitrate, C2_PARAMKEY_BITRATE) .withDefault(new C2StreamBitrateInfo::output(0u)) .withFields({C2F(mOutputBitrate, value).any()}) .calculatedAs( Copy, mInputBitrate) .build()); addParameter( DefineParam(mOutputProfileLevel, C2_PARAMKEY_PROFILE_LEVEL) .withDefault(new C2StreamProfileLevelInfo::output( 0u, PROFILE_UNUSED, LEVEL_UNUSED)) .withFields({ C2F(mOutputProfileLevel, profile).any(), C2F(mOutputProfileLevel, level).any(), }) .withSetter(Setter) .build()); std::vector c2QpOffsetRectsInfo; addParameter( DefineParam(mInputQpOffsetRects, C2_PARAMKEY_QP_OFFSET_RECTS) .withDefault(C2StreamQpOffsetRects::output::AllocShared( c2QpOffsetRectsInfo.size(), 0, c2QpOffsetRectsInfo)) .withFields({ C2F(mInputQpOffsetRects, m.values[0].qpOffset) .inRange(-128, 127), C2F(mInputQpOffsetRects, m.values[0].left).any(), C2F(mInputQpOffsetRects, m.values[0].top).any(), C2F(mInputQpOffsetRects, m.values[0].width).any(), C2F(mInputQpOffsetRects, m.values[0].height).any(), }) .withSetter(Setter) .build()); } // TODO: more SDK params } private: std::shared_ptr mDomain; std::shared_ptr mKind; std::shared_ptr mInputStreamCount; std::shared_ptr mOutputStreamCount; std::shared_ptr mInputMediaType; std::shared_ptr mOutputMediaType; std::shared_ptr mInt32Input; std::shared_ptr mInt64Output; std::shared_ptr mStringInput; std::shared_ptr mPixelAspectRatio; std::shared_ptr mInputBitrate; std::shared_ptr mOutputBitrate; std::shared_ptr mInputProfileLevel; std::shared_ptr mOutputProfileLevel; std::shared_ptr mInputQpOffsetRects; template static C2R Setter(bool, C2P &) { return C2R::Ok(); } template static C2R Copy(bool, C2P &me, const C2P &dep) { me.set().value = dep.v.value; return C2R::Ok(); } }; Impl mImpl; }; std::shared_ptr mReflector; std::shared_ptr mConfigurable; CCodecConfig mConfig; }; using D = CCodecConfig::Domain; template T *FindParam(const std::vector> &vec) { for (const std::unique_ptr ¶m : vec) { if (param->coreIndex() == T::CORE_INDEX) { return static_cast(param.get()); } } return nullptr; } TEST_F(CCodecConfigTest, SetVendorParam) { // Test at audio domain, as video domain has a few local parameters that // interfere with the testing. init(C2Component::DOMAIN_AUDIO, C2Component::KIND_DECODER, MIMETYPE_AUDIO_AAC); ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable)); sp format{new AMessage}; format->setInt32(KEY_VENDOR_INT32, kCodec2Int32); format->setInt64(KEY_VENDOR_INT64, kCodec2Int64); format->setString(KEY_VENDOR_STRING, kCodec2Str); std::vector> configUpdate; ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams( mConfigurable, format, D::ALL, C2_MAY_BLOCK, &configUpdate)); ASSERT_EQ(3u, configUpdate.size()); C2PortVendorInt32Info::input *i32 = FindParam::type>(configUpdate); ASSERT_NE(nullptr, i32); ASSERT_EQ(kCodec2Int32, i32->value); C2StreamVendorInt64Info::output *i64 = FindParam::type>(configUpdate); ASSERT_NE(nullptr, i64); ASSERT_EQ(kCodec2Int64, i64->value); C2PortVendorStringInfo::input *str = FindParam::type>(configUpdate); ASSERT_NE(nullptr, str); ASSERT_STREQ(kCodec2Str, str->m.value); } TEST_F(CCodecConfigTest, VendorParamUpdate_Unsubscribed) { // Test at audio domain, as video domain has a few local parameters that // interfere with the testing. init(C2Component::DOMAIN_AUDIO, C2Component::KIND_DECODER, MIMETYPE_AUDIO_AAC); ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable)); std::vector> configUpdate; C2PortVendorInt32Info::input i32(kCodec2Int32); C2StreamVendorInt64Info::output i64(0u, kCodec2Int64); std::unique_ptr str = C2PortVendorStringInfo::input::AllocUnique(strlen(kCodec2Str) + 1, kCodec2Str); configUpdate.push_back(C2Param::Copy(i32)); configUpdate.push_back(C2Param::Copy(i64)); configUpdate.push_back(std::move(str)); // The vendor parameters are not yet subscribed ASSERT_FALSE(mConfig.updateConfiguration(configUpdate, D::ALL)); int32_t vendorInt32{0}; ASSERT_FALSE(mConfig.mInputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32)) << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str(); ASSERT_FALSE(mConfig.mOutputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32)) << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str(); int64_t vendorInt64{0}; ASSERT_FALSE(mConfig.mInputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64)) << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str(); ASSERT_FALSE(mConfig.mOutputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64)) << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str(); AString vendorString; ASSERT_FALSE(mConfig.mInputFormat->findString(KEY_VENDOR_STRING, &vendorString)) << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str(); ASSERT_FALSE(mConfig.mOutputFormat->findString(KEY_VENDOR_STRING, &vendorString)) << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str(); } TEST_F(CCodecConfigTest, VendorParamUpdate_AllSubscribed) { // Test at audio domain, as video domain has a few local parameters that // interfere with the testing. init(C2Component::DOMAIN_AUDIO, C2Component::KIND_DECODER, MIMETYPE_AUDIO_AAC); ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable)); // Force subscribe to all vendor params ASSERT_EQ(OK, mConfig.subscribeToAllVendorParams(mConfigurable, C2_MAY_BLOCK)); std::vector> configUpdate; C2PortVendorInt32Info::input i32(kCodec2Int32); C2StreamVendorInt64Info::output i64(0u, kCodec2Int64); std::unique_ptr str = C2PortVendorStringInfo::input::AllocUnique(strlen(kCodec2Str) + 1, kCodec2Str); configUpdate.push_back(C2Param::Copy(i32)); configUpdate.push_back(C2Param::Copy(i64)); configUpdate.push_back(std::move(str)); ASSERT_TRUE(mConfig.updateConfiguration(configUpdate, D::ALL)); int32_t vendorInt32{0}; ASSERT_TRUE(mConfig.mInputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32)) << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str(); ASSERT_EQ(kCodec2Int32, vendorInt32); ASSERT_FALSE(mConfig.mOutputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32)) << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str(); int64_t vendorInt64{0}; ASSERT_FALSE(mConfig.mInputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64)) << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str(); ASSERT_TRUE(mConfig.mOutputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64)) << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str(); ASSERT_EQ(kCodec2Int64, vendorInt64); AString vendorString; ASSERT_TRUE(mConfig.mInputFormat->findString(KEY_VENDOR_STRING, &vendorString)) << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str(); ASSERT_STREQ(kCodec2Str, vendorString.c_str()); ASSERT_FALSE(mConfig.mOutputFormat->findString(KEY_VENDOR_STRING, &vendorString)) << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str(); } TEST_F(CCodecConfigTest, VendorParamUpdate_PartiallySubscribed) { // Test at audio domain, as video domain has a few local parameters that // interfere with the testing. init(C2Component::DOMAIN_AUDIO, C2Component::KIND_DECODER, MIMETYPE_AUDIO_AAC); ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable)); // Subscribe to example.int32 only std::vector> configUpdate; sp format{new AMessage}; format->setInt32(KEY_VENDOR_INT32, 0); configUpdate.clear(); ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams( mConfigurable, format, D::ALL, C2_MAY_BLOCK, &configUpdate)); ASSERT_EQ(OK, mConfig.setParameters(mConfigurable, configUpdate, C2_MAY_BLOCK)); C2PortVendorInt32Info::input i32(kCodec2Int32); C2StreamVendorInt64Info::output i64(0u, kCodec2Int64); std::unique_ptr str = C2PortVendorStringInfo::input::AllocUnique(strlen(kCodec2Str) + 1, kCodec2Str); configUpdate.clear(); configUpdate.push_back(C2Param::Copy(i32)); configUpdate.push_back(C2Param::Copy(i64)); configUpdate.push_back(std::move(str)); // Only example.i32 should be updated ASSERT_TRUE(mConfig.updateConfiguration(configUpdate, D::ALL)); int32_t vendorInt32{0}; ASSERT_TRUE(mConfig.mInputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32)) << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str(); ASSERT_EQ(kCodec2Int32, vendorInt32); ASSERT_FALSE(mConfig.mOutputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32)) << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str(); int64_t vendorInt64{0}; ASSERT_FALSE(mConfig.mInputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64)) << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str(); ASSERT_FALSE(mConfig.mOutputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64)) << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str(); AString vendorString; ASSERT_FALSE(mConfig.mInputFormat->findString(KEY_VENDOR_STRING, &vendorString)) << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str(); ASSERT_FALSE(mConfig.mOutputFormat->findString(KEY_VENDOR_STRING, &vendorString)) << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str(); } TEST_F(CCodecConfigTest, SetPixelAspectRatio) { init(C2Component::DOMAIN_VIDEO, C2Component::KIND_DECODER, MIMETYPE_VIDEO_AVC); ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable)); sp format{new AMessage}; format->setInt32(KEY_PIXEL_ASPECT_RATIO_WIDTH, 12); format->setInt32(KEY_PIXEL_ASPECT_RATIO_HEIGHT, 11); std::vector> configUpdate; ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams( mConfigurable, format, D::ALL, C2_MAY_BLOCK, &configUpdate)); ASSERT_EQ(1u, configUpdate.size()); C2StreamPixelAspectRatioInfo::output *par = FindParam::type>(configUpdate); ASSERT_NE(nullptr, par); ASSERT_EQ(12, par->width); ASSERT_EQ(11, par->height); } TEST_F(CCodecConfigTest, PixelAspectRatioUpdate) { init(C2Component::DOMAIN_VIDEO, C2Component::KIND_DECODER, MIMETYPE_VIDEO_AVC); ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable)); std::vector> configUpdate; C2StreamPixelAspectRatioInfo::output par(0u, 12, 11); configUpdate.push_back(C2Param::Copy(par)); ASSERT_TRUE(mConfig.updateConfiguration(configUpdate, D::ALL)); int32_t parWidth{0}; ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_PIXEL_ASPECT_RATIO_WIDTH, &parWidth)) << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str(); ASSERT_EQ(12, parWidth); ASSERT_FALSE(mConfig.mInputFormat->findInt32(KEY_PIXEL_ASPECT_RATIO_WIDTH, &parWidth)) << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str(); int32_t parHeight{0}; ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_PIXEL_ASPECT_RATIO_HEIGHT, &parHeight)) << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str(); ASSERT_EQ(11, parHeight); ASSERT_FALSE(mConfig.mInputFormat->findInt32(KEY_PIXEL_ASPECT_RATIO_HEIGHT, &parHeight)) << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str(); } TEST_F(CCodecConfigTest, DataspaceUpdate) { init(C2Component::DOMAIN_VIDEO, C2Component::KIND_ENCODER, MIMETYPE_VIDEO_AVC); ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable)); class InputSurfaceStub : public InputSurfaceWrapper { public: ~InputSurfaceStub() override = default; status_t connect(const std::shared_ptr &) override { return OK; } void disconnect() override {} status_t start() override { return OK; } status_t signalEndOfInputStream() override { return OK; } status_t configure(Config &) override { return OK; } }; mConfig.mInputSurface = std::make_shared(); sp format{new AMessage}; format->setInt32(KEY_COLOR_RANGE, COLOR_RANGE_LIMITED); format->setInt32(KEY_COLOR_STANDARD, COLOR_STANDARD_BT709); format->setInt32(KEY_COLOR_TRANSFER, COLOR_TRANSFER_SDR_VIDEO); format->setInt32(KEY_BIT_RATE, 100); std::vector> configUpdate; ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams( mConfigurable, format, D::ALL, C2_MAY_BLOCK, &configUpdate)); ASSERT_TRUE(mConfig.updateConfiguration(configUpdate, D::ALL)); int32_t range{0}; ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_RANGE, &range)) << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str(); EXPECT_EQ(COLOR_RANGE_LIMITED, range) << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str(); int32_t standard{0}; ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_STANDARD, &standard)) << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str(); EXPECT_EQ(COLOR_STANDARD_BT709, standard) << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str(); int32_t transfer{0}; ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_TRANSFER, &transfer)) << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str(); EXPECT_EQ(COLOR_TRANSFER_SDR_VIDEO, transfer) << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str(); mConfig.mInputSurface->setDataSpace(HAL_DATASPACE_BT2020_PQ); // Dataspace from input surface should override the configured setting mConfig.updateFormats(D::ALL); ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_RANGE, &range)) << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str(); EXPECT_EQ(COLOR_RANGE_FULL, range) << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str(); ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_STANDARD, &standard)) << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str(); EXPECT_EQ(COLOR_STANDARD_BT2020, standard) << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str(); ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_TRANSFER, &transfer)) << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str(); EXPECT_EQ(COLOR_TRANSFER_ST2084, transfer) << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str(); // Simulate bitrate update format = new AMessage; format->setInt32(KEY_BIT_RATE, 200); configUpdate.clear(); ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams( mConfigurable, format, D::ALL, C2_MAY_BLOCK, &configUpdate)); ASSERT_EQ(OK, mConfig.setParameters(mConfigurable, configUpdate, C2_MAY_BLOCK)); // Color information should remain the same mConfig.updateFormats(D::ALL); ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_RANGE, &range)) << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str(); EXPECT_EQ(COLOR_RANGE_FULL, range) << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str(); ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_STANDARD, &standard)) << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str(); EXPECT_EQ(COLOR_STANDARD_BT2020, standard) << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str(); ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_TRANSFER, &transfer)) << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str(); EXPECT_EQ(COLOR_TRANSFER_ST2084, transfer) << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str(); } typedef std::tuple HdrProfilesParams; class HdrProfilesTest : public CCodecConfigTest, public ::testing::WithParamInterface { }; TEST_P(HdrProfilesTest, SetFromSdk) { HdrProfilesParams params = GetParam(); std::string mediaType = std::get<0>(params); C2Config::profile_t c2Profile = std::get<1>(params); int32_t sdkProfile = std::get<2>(params); init(C2Component::DOMAIN_VIDEO, C2Component::KIND_ENCODER, mediaType.c_str()); ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable)); sp format{new AMessage}; format->setInt32(KEY_PROFILE, sdkProfile); std::vector> configUpdate; ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams( mConfigurable, format, D::ALL, C2_MAY_BLOCK, &configUpdate)); ASSERT_EQ(1u, configUpdate.size()); C2StreamProfileLevelInfo::input *pl = FindParam::type>(configUpdate); ASSERT_NE(nullptr, pl); ASSERT_EQ(c2Profile, pl->profile); } HdrProfilesParams kHdrProfilesParams[] = { std::make_tuple(MIMETYPE_VIDEO_HEVC, PROFILE_HEVC_MAIN_10, HEVCProfileMain10HDR10), std::make_tuple(MIMETYPE_VIDEO_HEVC, PROFILE_HEVC_MAIN_10, HEVCProfileMain10HDR10Plus), std::make_tuple(MIMETYPE_VIDEO_VP9, PROFILE_VP9_2, VP9Profile2HDR), std::make_tuple(MIMETYPE_VIDEO_VP9, PROFILE_VP9_2, VP9Profile2HDR10Plus), std::make_tuple(MIMETYPE_VIDEO_VP9, PROFILE_VP9_3, VP9Profile3HDR), std::make_tuple(MIMETYPE_VIDEO_VP9, PROFILE_VP9_3, VP9Profile3HDR10Plus), std::make_tuple(MIMETYPE_VIDEO_AV1, PROFILE_AV1_0, AV1ProfileMain10HDR10), std::make_tuple(MIMETYPE_VIDEO_AV1, PROFILE_AV1_0, AV1ProfileMain10HDR10Plus), }; INSTANTIATE_TEST_SUITE_P( CCodecConfig, HdrProfilesTest, ::testing::ValuesIn(kHdrProfilesParams)); TEST_F(CCodecConfigTest, SetRegionOfInterestParams) { if (!android::media::codec::provider_->region_of_interest() || !android::media::codec::provider_->region_of_interest_support()) { GTEST_SKIP() << "Skipping the test as region_of_interest flags are not enabled.\n"; } init(C2Component::DOMAIN_VIDEO, C2Component::KIND_ENCODER, MIMETYPE_VIDEO_VP9); ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable)); const int kWidth = 32; const int kHeight = 32; const int kNumBlocks = ((kWidth + 15) / 16) * ((kHeight + 15) / 16); int8_t mapInfo[kNumBlocks] = {-1, 0, 1, 1}; int top[kNumBlocks] = {0, 0, 16, 16}; int left[kNumBlocks] = {0, 16, 0, 16}; int bottom[kNumBlocks] = {16, 16, 32, 32}; int right[kNumBlocks] = {16, 32, 16, 32}; sp format{new AMessage}; format->setInt32(KEY_WIDTH, kWidth); format->setInt32(KEY_HEIGHT, kHeight); AString val; for (int i = 0; i < kNumBlocks; i++) { val.append(AStringPrintf("%d,%d-%d,%d=%d;", top[i], left[i], bottom[i], right[i], mapInfo[i])); } format->setString(PARAMETER_KEY_QP_OFFSET_RECTS, val); std::vector> configUpdate; ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams(mConfigurable, format, D::CONFIG, C2_MAY_BLOCK, &configUpdate)); EXPECT_EQ(1u, configUpdate.size()); C2StreamQpOffsetRects::output* qpRectParam = FindParam::type>(configUpdate); ASSERT_NE(nullptr, qpRectParam); ASSERT_EQ(kNumBlocks, qpRectParam->flexCount()); for (auto i = 0; i < kNumBlocks; i++) { EXPECT_EQ(mapInfo[i], (int8_t)qpRectParam->m.values[i].qpOffset) << "qp offset for index " << i << " is not as expected "; EXPECT_EQ(left[i], qpRectParam->m.values[i].left) << "left for index " << i << " is not as expected "; EXPECT_EQ(top[i], qpRectParam->m.values[i].top) << "top for index " << i << " is not as expected "; EXPECT_EQ(right[i] - left[i], qpRectParam->m.values[i].width) << "width for index " << i << " is not as expected "; EXPECT_EQ(bottom[i] - top[i], qpRectParam->m.values[i].height) << "height for index " << i << " is not as expected "; } } } // namespace android