// 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 #include #include #include #include #include #include #include #include #include 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(); auto componentInterface = std::make_shared(testCompName, mReflector); mIntf = std::shared_ptr(new SimpleInterface( 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 expected( AllocSharedString(MEDIA_MIMETYPE_VIDEO_RAW)); std::shared_ptr invalid( AllocSharedString(MEDIA_MIMETYPE_VIDEO_AVC)); TRACED_FAILURE(testReadOnlyParamOnHeap(expected.get(), invalid.get())); } TEST_F(C2VEACompIntfTest, TestOutputPortMime) { std::shared_ptr expected( AllocSharedString(MEDIA_MIMETYPE_VIDEO_AVC)); std::shared_ptr invalid( AllocSharedString(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()); } TEST_F(C2VEACompIntfTest, TestVideoSize) { C2StreamPictureSizeInfo::input videoSize; videoSize.setStream(0); // only support single stream std::vector widthC2FSV = { {C2ParamField(&videoSize, &C2StreamPictureSizeInfo::width), C2FieldSupportedValuesQuery::CURRENT}, }; ASSERT_EQ(C2_OK, mIntf->querySupportedValues_vb(widthC2FSV, C2_DONT_BLOCK)); std::vector 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( widthMin, widthMax, widthStep, heightMin, heightMax, heightStep)); } TEST_F(C2VEACompIntfTest, TestBitrate) { C2StreamBitrateInfo::output bitrate; std::vector 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 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 expected( C2PortAllocatorsTuning::input::AllocShared(kInputAllocators)); std::shared_ptr invalid( C2PortAllocatorsTuning::input::AllocShared(kOutputAllocators)); TRACED_FAILURE(testReadOnlyParamOnHeap(expected.get(), invalid.get())); } TEST_F(C2VEACompIntfTest, TestOutputAllocatorIds) { std::shared_ptr expected( C2PortAllocatorsTuning::output::AllocShared(kOutputAllocators)); std::shared_ptr invalid( C2PortAllocatorsTuning::output::AllocShared(kInputAllocators)); TRACED_FAILURE(testReadOnlyParamOnHeap(expected.get(), invalid.get())); } TEST_F(C2VEACompIntfTest, TestOutputBlockPoolIds) { std::vector> 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(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 newParam( C2PortBlockPoolsTuning::output::AllocShared(configBlockPools)); std::vector params{newParam.get()}; std::vector> 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 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 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 params{&videoSize, &frameRate, &bitrate, &info}; std::vector> 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> 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 params{&videoSize}; std::vector> 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> 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