| // Copyright 2019 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| //#define LOG_NDEBUG 0 |
| #define LOG_TAG "C2VDEACompIntf_test" |
| |
| #include <C2CompIntfTest.h> |
| |
| #include <inttypes.h> |
| #include <stdio.h> |
| #include <limits> |
| |
| #include <C2PlatformSupport.h> |
| #include <SimpleC2Interface.h> |
| #include <gtest/gtest.h> |
| #include <utils/Log.h> |
| |
| #include <v4l2_codec2/components/V4L2EncodeComponent.h> |
| #include <v4l2_codec2/components/V4L2EncodeInterface.h> |
| |
| namespace android { |
| |
| constexpr const char* testCompName = "c2.v4l2.avc.encoder"; |
| constexpr c2_node_id_t testCompNodeId = 12345; |
| |
| constexpr const char* MEDIA_MIMETYPE_VIDEO_RAW = "video/raw"; |
| constexpr const char* MEDIA_MIMETYPE_VIDEO_AVC = "video/avc"; |
| |
| constexpr C2Allocator::id_t kInputAllocators[] = {C2PlatformAllocatorStore::GRALLOC}; |
| constexpr C2Allocator::id_t kOutputAllocators[] = {C2PlatformAllocatorStore::BLOB}; |
| constexpr C2BlockPool::local_id_t kDefaultOutputBlockPool = C2BlockPool::BASIC_LINEAR; |
| |
| class C2VEACompIntfTest: public C2CompIntfTest { |
| protected: |
| C2VEACompIntfTest() { |
| mReflector = std::make_shared<C2ReflectorHelper>(); |
| auto componentInterface = std::make_shared<V4L2EncodeInterface>(testCompName, mReflector); |
| mIntf = std::shared_ptr<C2ComponentInterface>(new SimpleInterface<V4L2EncodeInterface>( |
| testCompName, testCompNodeId, componentInterface)); |
| } |
| ~C2VEACompIntfTest() override { |
| } |
| }; |
| |
| #define TRACED_FAILURE(func) \ |
| do { \ |
| SCOPED_TRACE(#func); \ |
| func; \ |
| if (::testing::Test::HasFatalFailure()) return; \ |
| } while (false) |
| |
| TEST_F(C2VEACompIntfTest, CreateInstance) { |
| auto name = mIntf->getName(); |
| auto id = mIntf->getId(); |
| printf("name = %s\n", name.c_str()); |
| printf("node_id = %u\n", id); |
| EXPECT_STREQ(name.c_str(), testCompName); |
| EXPECT_EQ(id, testCompNodeId); |
| } |
| |
| TEST_F(C2VEACompIntfTest, TestInputFormat) { |
| C2StreamBufferTypeSetting::input expected(0u, C2BufferData::GRAPHIC); |
| C2StreamBufferTypeSetting::input invalid(0u, C2BufferData::LINEAR); |
| TRACED_FAILURE(testReadOnlyParam(&expected, &invalid)); |
| } |
| |
| TEST_F(C2VEACompIntfTest, TestOutputFormat) { |
| C2StreamBufferTypeSetting::output expected(0u, C2BufferData::LINEAR); |
| C2StreamBufferTypeSetting::output invalid(0u, C2BufferData::GRAPHIC); |
| TRACED_FAILURE(testReadOnlyParam(&expected, &invalid)); |
| } |
| |
| TEST_F(C2VEACompIntfTest, TestInputPortMime) { |
| std::shared_ptr<C2PortMediaTypeSetting::input> expected( |
| AllocSharedString<C2PortMediaTypeSetting::input>(MEDIA_MIMETYPE_VIDEO_RAW)); |
| std::shared_ptr<C2PortMediaTypeSetting::input> invalid( |
| AllocSharedString<C2PortMediaTypeSetting::input>(MEDIA_MIMETYPE_VIDEO_AVC)); |
| TRACED_FAILURE(testReadOnlyParamOnHeap(expected.get(), invalid.get())); |
| } |
| |
| TEST_F(C2VEACompIntfTest, TestOutputPortMime) { |
| std::shared_ptr<C2PortMediaTypeSetting::output> expected( |
| AllocSharedString<C2PortMediaTypeSetting::output>(MEDIA_MIMETYPE_VIDEO_AVC)); |
| std::shared_ptr<C2PortMediaTypeSetting::output> invalid( |
| AllocSharedString<C2PortMediaTypeSetting::output>(MEDIA_MIMETYPE_VIDEO_RAW)); |
| TRACED_FAILURE(testReadOnlyParamOnHeap(expected.get(), invalid.get())); |
| } |
| |
| TEST_F(C2VEACompIntfTest, TestProfileLevel) { |
| // Configure input size, framerate, and bitrate to values which are capable of the lowest |
| // profile and level. (176x144, 15fps, 64000bps) |
| C2StreamPictureSizeInfo::input videoSize(0u, 176, 144); |
| C2StreamFrameRateInfo::output frameRate(0u, 15.); |
| C2StreamBitrateInfo::output bitrate(0u, 64000); |
| |
| // Configure and check if value is configured. |
| TRACED_FAILURE(testWritableParam(&videoSize)); |
| TRACED_FAILURE(testWritableParam(&frameRate)); |
| TRACED_FAILURE(testWritableParam(&bitrate)); |
| |
| // Iterate all possible profile and level combination |
| TRACED_FAILURE(testWritableProfileLevelParam<C2StreamProfileLevelInfo::output>()); |
| } |
| |
| TEST_F(C2VEACompIntfTest, TestVideoSize) { |
| C2StreamPictureSizeInfo::input videoSize; |
| videoSize.setStream(0); // only support single stream |
| std::vector<C2FieldSupportedValuesQuery> widthC2FSV = { |
| {C2ParamField(&videoSize, &C2StreamPictureSizeInfo::width), |
| C2FieldSupportedValuesQuery::CURRENT}, |
| }; |
| ASSERT_EQ(C2_OK, mIntf->querySupportedValues_vb(widthC2FSV, C2_DONT_BLOCK)); |
| std::vector<C2FieldSupportedValuesQuery> heightC2FSV = { |
| {C2ParamField(&videoSize, &C2StreamPictureSizeInfo::height), |
| C2FieldSupportedValuesQuery::CURRENT}, |
| }; |
| ASSERT_EQ(C2_OK, mIntf->querySupportedValues_vb(heightC2FSV, C2_DONT_BLOCK)); |
| |
| // Configure input size may take more time since the profile level setter also depends on it. |
| // Just limit the test range to 1080p and step up to 16 to make test run faster. |
| ASSERT_EQ(1u, widthC2FSV.size()); |
| ASSERT_EQ(C2_OK, widthC2FSV[0].status); |
| ASSERT_EQ(C2FieldSupportedValues::RANGE, widthC2FSV[0].values.type); |
| auto& widthFSVRange = widthC2FSV[0].values.range; |
| int32_t widthMin = widthFSVRange.min.i32; |
| int32_t widthMax = std::min(widthFSVRange.max.i32, 1920); |
| int32_t widthStep = std::max(widthFSVRange.step.i32, 16); |
| |
| ASSERT_EQ(1u, heightC2FSV.size()); |
| ASSERT_EQ(C2_OK, heightC2FSV[0].status); |
| ASSERT_EQ(C2FieldSupportedValues::RANGE, heightC2FSV[0].values.type); |
| auto& heightFSVRange = heightC2FSV[0].values.range; |
| int32_t heightMin = heightFSVRange.min.i32; |
| int32_t heightMax = std::min(heightFSVRange.max.i32, 1080); |
| int32_t heightStep = std::max(heightFSVRange.step.i32, 16); |
| |
| // test updating valid and invalid values |
| TRACED_FAILURE(testWritableVideoSizeParam<C2StreamPictureSizeInfo::input>( |
| widthMin, widthMax, widthStep, heightMin, heightMax, heightStep)); |
| } |
| |
| TEST_F(C2VEACompIntfTest, TestBitrate) { |
| C2StreamBitrateInfo::output bitrate; |
| std::vector<C2FieldSupportedValuesQuery> valueC2FSV = { |
| {C2ParamField(&bitrate, &C2StreamBitrateInfo::value), |
| C2FieldSupportedValuesQuery::CURRENT}, |
| }; |
| ASSERT_EQ(C2_OK, mIntf->querySupportedValues_vb(valueC2FSV, C2_DONT_BLOCK)); |
| ASSERT_EQ(1u, valueC2FSV.size()); |
| ASSERT_EQ(C2_OK, valueC2FSV[0].status); |
| ASSERT_EQ(C2FieldSupportedValues::RANGE, valueC2FSV[0].values.type); |
| auto& valueFSVRange = valueC2FSV[0].values.range; |
| uint32_t bitrateMin = valueFSVRange.min.u32; |
| uint32_t bitrateMax = valueFSVRange.max.u32; |
| uint32_t bitrateStep = valueFSVRange.step.u32; |
| bitrate.value = bitrateMin; |
| TRACED_FAILURE(testWritableParam(&bitrate)); |
| bitrate.value = bitrateMax; |
| TRACED_FAILURE(testWritableParam(&bitrate)); |
| // Choose the value which is half steps from bitrateMin than bitrateMax. |
| uint32_t steps = (bitrateMax - bitrateMin) / bitrateStep; |
| bitrate.value = bitrateMin + steps / 2 * bitrateStep; |
| TRACED_FAILURE(testWritableParam(&bitrate)); |
| // TODO: Add invalid value test after validate possible values in C2InterfaceHelper is |
| // implemented. |
| } |
| |
| TEST_F(C2VEACompIntfTest, TestFrameRate) { |
| C2StreamFrameRateInfo::output frameRate; |
| frameRate.setStream(0); // only support single stream |
| std::vector<C2Param*> stackParams{&frameRate}; |
| ASSERT_EQ(C2_OK, mIntf->query_vb(stackParams, {}, C2_DONT_BLOCK, nullptr)); |
| |
| float defaultFrameRate = frameRate.value; |
| frameRate.value = defaultFrameRate / 2; |
| TRACED_FAILURE(testWritableParam(&frameRate)); |
| frameRate.value = defaultFrameRate; |
| TRACED_FAILURE(testWritableParam(&frameRate)); |
| // TODO: Add invalid value test after validate possible values in C2InterfaceHelper is |
| // implemented. |
| } |
| |
| TEST_F(C2VEACompIntfTest, TestIntraRefreshPeriod) { |
| C2StreamIntraRefreshTuning::output period(0u, C2Config::INTRA_REFRESH_ARBITRARY, 30.); |
| TRACED_FAILURE(testWritableParam(&period)); |
| period.mode = C2Config::INTRA_REFRESH_DISABLED; |
| period.period = 0; |
| TRACED_FAILURE(testWritableParam(&period)); |
| } |
| |
| TEST_F(C2VEACompIntfTest, TestRequestKeyFrame) { |
| C2StreamRequestSyncFrameTuning::output request(0u, C2_TRUE); |
| TRACED_FAILURE(testWritableParam(&request)); |
| request.value = C2_FALSE; |
| TRACED_FAILURE(testWritableParam(&request)); |
| } |
| |
| TEST_F(C2VEACompIntfTest, TestKeyFramePeriodUs) { |
| C2StreamSyncFrameIntervalTuning::output period(0u, 500000); |
| TRACED_FAILURE(testWritableParam(&period)); |
| period.value = 1500000; |
| TRACED_FAILURE(testWritableParam(&period)); |
| } |
| |
| TEST_F(C2VEACompIntfTest, TestInputAllocatorIds) { |
| std::shared_ptr<C2PortAllocatorsTuning::input> expected( |
| C2PortAllocatorsTuning::input::AllocShared(kInputAllocators)); |
| std::shared_ptr<C2PortAllocatorsTuning::input> invalid( |
| C2PortAllocatorsTuning::input::AllocShared(kOutputAllocators)); |
| TRACED_FAILURE(testReadOnlyParamOnHeap(expected.get(), invalid.get())); |
| } |
| |
| TEST_F(C2VEACompIntfTest, TestOutputAllocatorIds) { |
| std::shared_ptr<C2PortAllocatorsTuning::output> expected( |
| C2PortAllocatorsTuning::output::AllocShared(kOutputAllocators)); |
| std::shared_ptr<C2PortAllocatorsTuning::output> invalid( |
| C2PortAllocatorsTuning::output::AllocShared(kInputAllocators)); |
| TRACED_FAILURE(testReadOnlyParamOnHeap(expected.get(), invalid.get())); |
| } |
| |
| TEST_F(C2VEACompIntfTest, TestOutputBlockPoolIds) { |
| std::vector<std::unique_ptr<C2Param>> heapParams; |
| C2Param::Index index = C2PortBlockPoolsTuning::output::PARAM_TYPE; |
| |
| // Query the param and check the default value. |
| ASSERT_EQ(C2_OK, mIntf->query_vb({}, {index}, C2_DONT_BLOCK, &heapParams)); |
| ASSERT_EQ(1u, heapParams.size()); |
| C2BlockPool::local_id_t value = |
| reinterpret_cast<C2PortBlockPoolsTuning*>(heapParams[0].get())->m.values[0]; |
| ASSERT_EQ(kDefaultOutputBlockPool, value); |
| |
| // Configure the param. |
| C2BlockPool::local_id_t configBlockPools[] = {C2BlockPool::PLATFORM_START + 1}; |
| std::shared_ptr<C2PortBlockPoolsTuning::output> newParam( |
| C2PortBlockPoolsTuning::output::AllocShared(configBlockPools)); |
| |
| std::vector<C2Param*> params{newParam.get()}; |
| std::vector<std::unique_ptr<C2SettingResult>> failures; |
| ASSERT_EQ(C2_OK, mIntf->config_vb(params, C2_DONT_BLOCK, &failures)); |
| EXPECT_EQ(0u, failures.size()); |
| |
| // Query the param again and check the value is as configured |
| heapParams.clear(); |
| ASSERT_EQ(C2_OK, mIntf->query_vb({}, {index}, C2_DONT_BLOCK, &heapParams)); |
| ASSERT_EQ(1u, heapParams.size()); |
| value = ((C2PortBlockPoolsTuning*)heapParams[0].get())->m.values[0]; |
| ASSERT_EQ(configBlockPools[0], value); |
| } |
| |
| TEST_F(C2VEACompIntfTest, TestUnsupportedParam) { |
| C2ComponentTimeStretchTuning unsupportedParam; |
| std::vector<C2Param*> stackParams{&unsupportedParam}; |
| ASSERT_EQ(C2_BAD_INDEX, mIntf->query_vb(stackParams, {}, C2_DONT_BLOCK, nullptr)); |
| EXPECT_EQ(0u, unsupportedParam.size()); // invalidated |
| } |
| |
| TEST_F(C2VEACompIntfTest, TestAvcLevelDependency) { |
| C2StreamProfileLevelInfo::output info; |
| info.setStream(0); |
| |
| // Read out the default profile and level. |
| std::vector<C2Param*> stackParams{&info}; |
| ASSERT_EQ(C2_OK, mIntf->query_vb(stackParams, {}, C2_DONT_BLOCK, nullptr)); |
| |
| // The default profile should be the lowest one component could support, and we would expect |
| // either BASELINE or MAIN is supported. In addition, profiles higher than HIGH will have |
| // different bitrate limit for levels, we don't want to make this test too complicated. |
| ASSERT_LT(info.profile, PROFILE_AVC_HIGH); |
| |
| // Set AVC level to 1.2. |
| // Configure input size, framerate, and bitrate to values which are capable of level 1.2. |
| C2StreamPictureSizeInfo::input videoSize(0u, 320, 240); |
| C2StreamFrameRateInfo::output frameRate(0u, 15.); |
| C2StreamBitrateInfo::output bitrate(0u, 384000); |
| info.level = LEVEL_AVC_1_2; |
| |
| std::vector<C2Param*> params{&videoSize, &frameRate, &bitrate, &info}; |
| std::vector<std::unique_ptr<C2SettingResult>> failures; |
| ASSERT_EQ(C2_OK, mIntf->config_vb(params, C2_DONT_BLOCK, &failures)); |
| EXPECT_EQ(0u, failures.size()); |
| |
| // Check AVC level is 1.2. |
| std::vector<std::unique_ptr<C2Param>> heapParams; |
| C2Param::Index index = C2StreamProfileLevelInfo::output::PARAM_TYPE; |
| ASSERT_EQ(C2_OK, mIntf->query_vb({}, {index}, C2_DONT_BLOCK, &heapParams)); |
| ASSERT_EQ(1u, heapParams.size()); |
| EXPECT_EQ(((C2StreamProfileLevelInfo*)heapParams[0].get())->level, LEVEL_AVC_1_2); |
| |
| // Configure input size, framerate, and bitrate to values which are capable of level 4.0. |
| videoSize.width = 2048; |
| videoSize.height = 1024; |
| frameRate.value = 30; |
| bitrate.value = 20000000; |
| |
| failures.clear(); |
| ASSERT_EQ(C2_OK, mIntf->config_vb(params, C2_DONT_BLOCK, &failures)); |
| EXPECT_EQ(0u, failures.size()); |
| |
| // Check AVC level is adjusted to 4.0. |
| heapParams.clear(); |
| ASSERT_EQ(C2_OK, mIntf->query_vb({}, {index}, C2_DONT_BLOCK, &heapParams)); |
| ASSERT_EQ(1u, heapParams.size()); |
| EXPECT_EQ(((C2StreamProfileLevelInfo*)heapParams[0].get())->level, LEVEL_AVC_4); |
| } |
| |
| TEST_F(C2VEACompIntfTest, TestBug114332827) { |
| // Use at least PROFILE_AVC_MAIN for 1080p input video and up. b/114332827 |
| |
| // Config input video size to 1080p. |
| C2StreamPictureSizeInfo::input videoSize(0u, 1920, 1080); |
| |
| std::vector<C2Param*> params{&videoSize}; |
| std::vector<std::unique_ptr<C2SettingResult>> failures; |
| ASSERT_EQ(C2_OK, mIntf->config_vb(params, C2_DONT_BLOCK, &failures)); |
| EXPECT_EQ(0u, failures.size()); |
| |
| // Query video size back to check it is 1080p. |
| std::vector<std::unique_ptr<C2Param>> heapParams; |
| C2Param::Index index = C2StreamPictureSizeInfo::input::PARAM_TYPE; |
| ASSERT_EQ(C2_OK, mIntf->query_vb({}, {index}, C2_DONT_BLOCK, &heapParams)); |
| ASSERT_EQ(1u, heapParams.size()); |
| EXPECT_EQ(1920u, ((C2StreamPictureSizeInfo*)heapParams[0].get())->width); |
| EXPECT_EQ(1080u, ((C2StreamPictureSizeInfo*)heapParams[0].get())->height); |
| |
| // Check profile should be PROFILE_AVC_MAIN or higher. |
| heapParams.clear(); |
| index = C2StreamProfileLevelInfo::output::PARAM_TYPE; |
| ASSERT_EQ(C2_OK, mIntf->query_vb({}, {index}, C2_DONT_BLOCK, &heapParams)); |
| ASSERT_EQ(1u, heapParams.size()); |
| EXPECT_GE(((C2StreamProfileLevelInfo*)heapParams[0].get())->profile, PROFILE_AVC_MAIN); |
| } |
| |
| TEST_F(C2VEACompIntfTest, ParamReflector) { |
| dumpParamDescriptions(); |
| } |
| } // namespace android |