| /* |
| * 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 <set> |
| |
| #include <gtest/gtest.h> |
| |
| #include <codec2/hidl/1.0/Configurable.h> |
| #include <codec2/hidl/client.h> |
| #include <util/C2InterfaceHelper.h> |
| |
| #include <media/stagefright/MediaCodecConstants.h> |
| |
| namespace { |
| |
| enum ExtendedC2ParamIndexKind : C2Param::type_index_t { |
| kParamIndexVendorInt32 = C2Param::TYPE_INDEX_VENDOR_START, |
| kParamIndexVendorInt64, |
| kParamIndexVendorString, |
| }; |
| |
| typedef C2PortParam<C2Info, C2Int32Value, kParamIndexVendorInt32> C2PortVendorInt32Info; |
| constexpr char C2_PARAMKEY_VENDOR_INT32[] = "example.int32"; |
| constexpr char KEY_VENDOR_INT32[] = "vendor.example.int32.value"; |
| |
| typedef C2StreamParam<C2Info, C2Int64Value, kParamIndexVendorInt64> C2StreamVendorInt64Info; |
| constexpr char C2_PARAMKEY_VENDOR_INT64[] = "example.int64"; |
| constexpr char KEY_VENDOR_INT64[] = "vendor.example.int64.value"; |
| |
| typedef C2PortParam<C2Info, C2StringValue, kParamIndexVendorString> 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<C2ReflectorHelper>()} { |
| } |
| |
| void init( |
| C2Component::domain_t domain, |
| C2Component::kind_t kind, |
| const char *mediaType) { |
| sp<hardware::media::c2::V1_0::utils::CachedConfigurable> cachedConfigurable = |
| new hardware::media::c2::V1_0::utils::CachedConfigurable( |
| std::make_unique<Configurable>(mReflector, domain, kind, mediaType)); |
| cachedConfigurable->init(std::make_shared<Cache>()); |
| mConfigurable = std::make_shared<Codec2Client::Configurable>(cachedConfigurable); |
| } |
| |
| struct Cache : public hardware::media::c2::V1_0::utils::ParameterCache { |
| c2_status_t validate(const std::vector<std::shared_ptr<C2ParamDescriptor>>&) override { |
| return C2_OK; |
| } |
| }; |
| |
| class Configurable : public hardware::media::c2::V1_0::utils::ConfigurableC2Intf { |
| public: |
| Configurable( |
| const std::shared_ptr<C2ReflectorHelper> &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<C2Param::Index> &indices, |
| c2_blocking_t mayBlock, |
| std::vector<std::unique_ptr<C2Param>>* const params) const override { |
| return mImpl.query({}, indices, mayBlock, params); |
| } |
| |
| c2_status_t config( |
| const std::vector<C2Param*> ¶ms, |
| c2_blocking_t mayBlock, |
| std::vector<std::unique_ptr<C2SettingResult>>* const failures) override { |
| return mImpl.config(params, mayBlock, failures); |
| } |
| |
| c2_status_t querySupportedParams( |
| std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const override { |
| return mImpl.querySupportedParams(params); |
| } |
| |
| c2_status_t querySupportedValues( |
| std::vector<C2FieldSupportedValuesQuery>& fields, |
| c2_blocking_t mayBlock) const override { |
| return mImpl.querySupportedValues(fields, mayBlock); |
| } |
| |
| private: |
| class Impl : public C2InterfaceHelper { |
| public: |
| Impl(const std::shared_ptr<C2ReflectorHelper> &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<decltype(param)>::type::element_type T; |
| std::shared_ptr<T> 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<decltype(mInt32Input)::element_type>) |
| .build()); |
| |
| addParameter( |
| DefineParam(mInt64Output, C2_PARAMKEY_VENDOR_INT64) |
| .withDefault(new C2StreamVendorInt64Info::output(0u, 0)) |
| .withFields({C2F(mInt64Output, value).any()}) |
| .withSetter(Setter<decltype(mInt64Output)::element_type>) |
| .build()); |
| |
| addParameter( |
| DefineParam(mStringInput, C2_PARAMKEY_VENDOR_STRING) |
| .withDefault(decltype(mStringInput)::element_type::AllocShared(1, "")) |
| .withFields({C2F(mStringInput, m.value).any()}) |
| .withSetter(Setter<decltype(mStringInput)::element_type>) |
| .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<C2StreamPixelAspectRatioInfo::output>) |
| .build()); |
| |
| if (isEncoder) { |
| addParameter( |
| DefineParam(mInputBitrate, C2_PARAMKEY_BITRATE) |
| .withDefault(new C2StreamBitrateInfo::input(0u)) |
| .withFields({C2F(mInputBitrate, value).any()}) |
| .withSetter(Setter<C2StreamBitrateInfo::input>) |
| .build()); |
| |
| addParameter( |
| DefineParam(mOutputBitrate, C2_PARAMKEY_BITRATE) |
| .withDefault(new C2StreamBitrateInfo::output(0u)) |
| .withFields({C2F(mOutputBitrate, value).any()}) |
| .calculatedAs( |
| Copy<C2StreamBitrateInfo::output, C2StreamBitrateInfo::input>, |
| 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<C2StreamProfileLevelInfo::output>) |
| .build()); |
| } |
| |
| // TODO: more SDK params |
| } |
| private: |
| std::shared_ptr<C2ComponentDomainSetting> mDomain; |
| std::shared_ptr<C2ComponentKindSetting> mKind; |
| std::shared_ptr<C2PortStreamCountTuning::input> mInputStreamCount; |
| std::shared_ptr<C2PortStreamCountTuning::output> mOutputStreamCount; |
| std::shared_ptr<C2PortMediaTypeSetting::input> mInputMediaType; |
| std::shared_ptr<C2PortMediaTypeSetting::output> mOutputMediaType; |
| std::shared_ptr<C2PortVendorInt32Info::input> mInt32Input; |
| std::shared_ptr<C2StreamVendorInt64Info::output> mInt64Output; |
| std::shared_ptr<C2PortVendorStringInfo::input> mStringInput; |
| std::shared_ptr<C2StreamPixelAspectRatioInfo::output> mPixelAspectRatio; |
| std::shared_ptr<C2StreamBitrateInfo::input> mInputBitrate; |
| std::shared_ptr<C2StreamBitrateInfo::output> mOutputBitrate; |
| std::shared_ptr<C2StreamProfileLevelInfo::input> mInputProfileLevel; |
| std::shared_ptr<C2StreamProfileLevelInfo::output> mOutputProfileLevel; |
| |
| template<typename T> |
| static C2R Setter(bool, C2P<T> &) { |
| return C2R::Ok(); |
| } |
| |
| template<typename ME, typename DEP> |
| static C2R Copy(bool, C2P<ME> &me, const C2P<DEP> &dep) { |
| me.set().value = dep.v.value; |
| return C2R::Ok(); |
| } |
| }; |
| |
| Impl mImpl; |
| }; |
| |
| std::shared_ptr<C2ReflectorHelper> mReflector; |
| std::shared_ptr<Codec2Client::Configurable> mConfigurable; |
| CCodecConfig mConfig; |
| }; |
| |
| using D = CCodecConfig::Domain; |
| |
| template<typename T> |
| T *FindParam(const std::vector<std::unique_ptr<C2Param>> &vec) { |
| for (const std::unique_ptr<C2Param> ¶m : vec) { |
| if (param->coreIndex() == T::CORE_INDEX) { |
| return static_cast<T *>(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<AMessage> format{new AMessage}; |
| format->setInt32(KEY_VENDOR_INT32, kCodec2Int32); |
| format->setInt64(KEY_VENDOR_INT64, kCodec2Int64); |
| format->setString(KEY_VENDOR_STRING, kCodec2Str); |
| |
| std::vector<std::unique_ptr<C2Param>> configUpdate; |
| ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams( |
| mConfigurable, format, D::ALL, C2_MAY_BLOCK, &configUpdate)); |
| |
| ASSERT_EQ(3u, configUpdate.size()); |
| C2PortVendorInt32Info::input *i32 = |
| FindParam<std::remove_pointer<decltype(i32)>::type>(configUpdate); |
| ASSERT_NE(nullptr, i32); |
| ASSERT_EQ(kCodec2Int32, i32->value); |
| |
| C2StreamVendorInt64Info::output *i64 = |
| FindParam<std::remove_pointer<decltype(i64)>::type>(configUpdate); |
| ASSERT_NE(nullptr, i64); |
| ASSERT_EQ(kCodec2Int64, i64->value); |
| |
| C2PortVendorStringInfo::input *str = |
| FindParam<std::remove_pointer<decltype(str)>::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<std::unique_ptr<C2Param>> configUpdate; |
| C2PortVendorInt32Info::input i32(kCodec2Int32); |
| C2StreamVendorInt64Info::output i64(0u, kCodec2Int64); |
| std::unique_ptr<C2PortVendorStringInfo::input> 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<std::unique_ptr<C2Param>> configUpdate; |
| C2PortVendorInt32Info::input i32(kCodec2Int32); |
| C2StreamVendorInt64Info::output i64(0u, kCodec2Int64); |
| std::unique_ptr<C2PortVendorStringInfo::input> 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<std::unique_ptr<C2Param>> configUpdate; |
| sp<AMessage> 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<C2PortVendorStringInfo::input> 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<AMessage> format{new AMessage}; |
| format->setInt32(KEY_PIXEL_ASPECT_RATIO_WIDTH, 12); |
| format->setInt32(KEY_PIXEL_ASPECT_RATIO_HEIGHT, 11); |
| |
| std::vector<std::unique_ptr<C2Param>> configUpdate; |
| ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams( |
| mConfigurable, format, D::ALL, C2_MAY_BLOCK, &configUpdate)); |
| |
| ASSERT_EQ(1u, configUpdate.size()); |
| C2StreamPixelAspectRatioInfo::output *par = |
| FindParam<std::remove_pointer<decltype(par)>::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<std::unique_ptr<C2Param>> 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<Codec2Client::Component> &) 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<InputSurfaceStub>(); |
| |
| sp<AMessage> 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<std::unique_ptr<C2Param>> 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<std::string, C2Config::profile_t, int32_t> HdrProfilesParams; |
| |
| class HdrProfilesTest |
| : public CCodecConfigTest, |
| public ::testing::WithParamInterface<HdrProfilesParams> { |
| }; |
| |
| 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<AMessage> format{new AMessage}; |
| format->setInt32(KEY_PROFILE, sdkProfile); |
| |
| std::vector<std::unique_ptr<C2Param>> configUpdate; |
| ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams( |
| mConfigurable, format, D::ALL, C2_MAY_BLOCK, &configUpdate)); |
| |
| ASSERT_EQ(1u, configUpdate.size()); |
| C2StreamProfileLevelInfo::input *pl = |
| FindParam<std::remove_pointer<decltype(pl)>::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)); |
| |
| } // namespace android |