1 // Copyright 2017 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 //#define LOG_NDEBUG 0 6 #define LOG_TAG "C2VDACompIntf_test" 7 8 #include <C2VDAComponent.h> 9 10 #include <C2PlatformSupport.h> 11 12 #include <gtest/gtest.h> 13 #include <utils/Log.h> 14 15 #include <inttypes.h> 16 #include <stdio.h> 17 #include <limits> 18 19 #define UNUSED(expr) \ 20 do { \ 21 (void)(expr); \ 22 } while (0) 23 24 namespace android { 25 26 const C2String testCompName = "c2.vda.avc.decoder"; 27 const c2_node_id_t testCompNodeId = 12345; 28 29 const char* MEDIA_MIMETYPE_VIDEO_RAW = "video/raw"; 30 const char* MEDIA_MIMETYPE_VIDEO_AVC = "video/avc"; 31 32 const C2Allocator::id_t kInputAllocators[] = {C2PlatformAllocatorStore::ION}; 33 const C2Allocator::id_t kOutputAllocators[] = {C2PlatformAllocatorStore::GRALLOC}; 34 const C2BlockPool::local_id_t kDefaultOutputBlockPool = C2BlockPool::BASIC_GRAPHIC; 35 36 class C2VDACompIntfTest : public ::testing::Test { 37 protected: 38 C2VDACompIntfTest() { 39 mReflector = std::make_shared<C2ReflectorHelper>(); 40 mIntf = std::shared_ptr<C2ComponentInterface>(new SimpleInterface<C2VDAComponent::IntfImpl>( 41 testCompName.c_str(), testCompNodeId, 42 std::make_shared<C2VDAComponent::IntfImpl>(testCompName, mReflector))); 43 } 44 ~C2VDACompIntfTest() override {} 45 46 template <typename T> 47 void testReadOnlyParam(const T* expected, T* invalid); 48 49 template <typename T> 50 void checkReadOnlyFailureOnConfig(T* param); 51 52 template <typename T> 53 void testReadOnlyParamOnStack(const T* expected, T* invalid); 54 55 template <typename T> 56 void testReadOnlyParamOnHeap(const T* expected, T* invalid); 57 58 template <typename T> 59 void testWritableParam(T* newParam); 60 61 template <typename T> 62 void testInvalidWritableParam(T* invalidParam); 63 64 template <typename T> 65 void testWritableVideoSizeParam(int32_t widthMin, int32_t widthMax, int32_t widthStep, 66 int32_t heightMin, int32_t heightMax, int32_t heightStep); 67 68 std::shared_ptr<C2ComponentInterface> mIntf; 69 std::shared_ptr<C2ReflectorHelper> mReflector; 70 }; 71 72 template <typename T> 73 void C2VDACompIntfTest::testReadOnlyParam(const T* expected, T* invalid) { 74 testReadOnlyParamOnStack(expected, invalid); 75 testReadOnlyParamOnHeap(expected, invalid); 76 } 77 78 template <typename T> 79 void C2VDACompIntfTest::checkReadOnlyFailureOnConfig(T* param) { 80 std::vector<C2Param*> params{param}; 81 std::vector<std::unique_ptr<C2SettingResult>> failures; 82 83 // TODO: do not assert on checking return value since it is not consistent for 84 // C2InterfaceHelper now. (b/79720928) 85 // 1) if config same value, it returns C2_OK 86 // 2) if config different value, it returns C2_CORRUPTED. But when you config again, it 87 // returns C2_OK 88 //ASSERT_EQ(C2_BAD_VALUE, mIntf->config_vb(params, C2_DONT_BLOCK, &failures)); 89 mIntf->config_vb(params, C2_DONT_BLOCK, &failures); 90 91 // TODO: failure is not yet supported for C2InterfaceHelper 92 //ASSERT_EQ(1u, failures.size()); 93 //EXPECT_EQ(C2SettingResult::READ_ONLY, failures[0]->failure); 94 } 95 96 template <typename T> 97 void C2VDACompIntfTest::testReadOnlyParamOnStack(const T* expected, T* invalid) { 98 T param; 99 std::vector<C2Param*> stackParams{¶m}; 100 ASSERT_EQ(C2_OK, mIntf->query_vb(stackParams, {}, C2_DONT_BLOCK, nullptr)); 101 EXPECT_EQ(*expected, param); 102 103 checkReadOnlyFailureOnConfig(¶m); 104 checkReadOnlyFailureOnConfig(invalid); 105 106 // The param must not change after failed config. 107 ASSERT_EQ(C2_OK, mIntf->query_vb(stackParams, {}, C2_DONT_BLOCK, nullptr)); 108 EXPECT_EQ(*expected, param); 109 } 110 111 template <typename T> 112 void C2VDACompIntfTest::testReadOnlyParamOnHeap(const T* expected, T* invalid) { 113 std::vector<std::unique_ptr<C2Param>> heapParams; 114 115 uint32_t index = expected->index(); 116 117 ASSERT_EQ(C2_OK, mIntf->query_vb({}, {index}, C2_DONT_BLOCK, &heapParams)); 118 ASSERT_EQ(1u, heapParams.size()); 119 EXPECT_EQ(*expected, *heapParams[0]); 120 121 checkReadOnlyFailureOnConfig(heapParams[0].get()); 122 checkReadOnlyFailureOnConfig(invalid); 123 124 // The param must not change after failed config. 125 heapParams.clear(); 126 ASSERT_EQ(C2_OK, mIntf->query_vb({}, {index}, C2_DONT_BLOCK, &heapParams)); 127 ASSERT_EQ(1u, heapParams.size()); 128 EXPECT_EQ(*expected, *heapParams[0]); 129 } 130 131 template <typename T> 132 void C2VDACompIntfTest::testWritableParam(T* newParam) { 133 std::vector<C2Param*> params{newParam}; 134 std::vector<std::unique_ptr<C2SettingResult>> failures; 135 ASSERT_EQ(C2_OK, mIntf->config_vb(params, C2_DONT_BLOCK, &failures)); 136 EXPECT_EQ(0u, failures.size()); 137 138 // The param must change to newParam 139 // Check like param on stack 140 T param; 141 std::vector<C2Param*> stackParams{¶m}; 142 ASSERT_EQ(C2_OK, mIntf->query_vb(stackParams, {}, C2_DONT_BLOCK, nullptr)); 143 EXPECT_EQ(*newParam, param); 144 145 // Check also like param on heap 146 std::vector<std::unique_ptr<C2Param>> heapParams; 147 ASSERT_EQ(C2_OK, mIntf->query_vb({}, {newParam->index()}, C2_DONT_BLOCK, &heapParams)); 148 ASSERT_EQ(1u, heapParams.size()); 149 EXPECT_EQ(*newParam, *heapParams[0]); 150 } 151 152 template <typename T> 153 void C2VDACompIntfTest::testInvalidWritableParam(T* invalidParam) { 154 // Get the current parameter info 155 T preParam; 156 std::vector<C2Param*> stackParams{&preParam}; 157 ASSERT_EQ(C2_OK, mIntf->query_vb(stackParams, {}, C2_DONT_BLOCK, nullptr)); 158 159 // Config invalid value. The failure is expected 160 std::vector<C2Param*> params{invalidParam}; 161 std::vector<std::unique_ptr<C2SettingResult>> failures; 162 ASSERT_EQ(C2_BAD_VALUE, mIntf->config_vb(params, C2_DONT_BLOCK, &failures)); 163 EXPECT_EQ(1u, failures.size()); 164 165 //The param must not change after config failed 166 T param; 167 std::vector<C2Param*> stackParams2{¶m}; 168 ASSERT_EQ(C2_OK, mIntf->query_vb(stackParams2, {}, C2_DONT_BLOCK, nullptr)); 169 EXPECT_EQ(preParam, param); 170 171 // Check also like param on heap 172 std::vector<std::unique_ptr<C2Param>> heapParams; 173 ASSERT_EQ(C2_OK, mIntf->query_vb({}, {invalidParam->index()}, C2_DONT_BLOCK, &heapParams)); 174 ASSERT_EQ(1u, heapParams.size()); 175 EXPECT_EQ(preParam, *heapParams[0]); 176 } 177 178 bool isUnderflowSubstract(int32_t a, int32_t b) { 179 return a < 0 && b > a - std::numeric_limits<int32_t>::min(); 180 } 181 182 bool isOverflowAdd(int32_t a, int32_t b) { 183 return a > 0 && b > std::numeric_limits<int32_t>::max() - a; 184 } 185 186 template <typename T> 187 void C2VDACompIntfTest::testWritableVideoSizeParam(int32_t widthMin, int32_t widthMax, 188 int32_t widthStep, int32_t heightMin, 189 int32_t heightMax, int32_t heightStep) { 190 // Test supported values of video size 191 T valid; 192 for (int32_t h = heightMin; h <= heightMax; h += heightStep) { 193 for (int32_t w = widthMin; w <= widthMax; w += widthStep) { 194 valid.width = w; 195 valid.height = h; 196 { 197 SCOPED_TRACE("testWritableParam"); 198 testWritableParam(&valid); 199 if (HasFailure()) { 200 printf("Failed while config width = %d, height = %d\n", valid.width, 201 valid.height); 202 } 203 if (HasFatalFailure()) return; 204 } 205 } 206 } 207 208 // TODO: validate possible values in C2InterfaceHelper is not implemented yet. 209 //// Test invalid values video size 210 //T invalid; 211 //// Width or height is smaller than min values 212 //if (!isUnderflowSubstract(widthMin, widthStep)) { 213 // invalid.width = widthMin - widthStep; 214 // invalid.height = heightMin; 215 // testInvalidWritableParam(&invalid); 216 //} 217 //if (!isUnderflowSubstract(heightMin, heightStep)) { 218 // invalid.width = widthMin; 219 // invalid.height = heightMin - heightStep; 220 // testInvalidWritableParam(&invalid); 221 //} 222 223 //// Width or height is bigger than max values 224 //if (!isOverflowAdd(widthMax, widthStep)) { 225 // invalid.width = widthMax + widthStep; 226 // invalid.height = heightMax; 227 // testInvalidWritableParam(&invalid); 228 //} 229 //if (!isOverflowAdd(heightMax, heightStep)) { 230 // invalid.width = widthMax; 231 // invalid.height = heightMax + heightStep; 232 // testInvalidWritableParam(&invalid); 233 //} 234 235 //// Invalid width/height within the range 236 //if (widthStep != 1) { 237 // invalid.width = widthMin + 1; 238 // invalid.height = heightMin; 239 // testInvalidWritableParam(&invalid); 240 //} 241 //if (heightStep != 1) { 242 // invalid.width = widthMin; 243 // invalid.height = heightMin + 1; 244 // testInvalidWritableParam(&invalid); 245 //} 246 } 247 248 #define TRACED_FAILURE(func) \ 249 do { \ 250 SCOPED_TRACE(#func); \ 251 func; \ 252 if (::testing::Test::HasFatalFailure()) return; \ 253 } while (false) 254 255 TEST_F(C2VDACompIntfTest, CreateInstance) { 256 auto name = mIntf->getName(); 257 auto id = mIntf->getId(); 258 printf("name = %s\n", name.c_str()); 259 printf("node_id = %u\n", id); 260 EXPECT_STREQ(name.c_str(), testCompName.c_str()); 261 EXPECT_EQ(id, testCompNodeId); 262 } 263 264 TEST_F(C2VDACompIntfTest, TestInputFormat) { 265 C2StreamBufferTypeSetting::input expected(0u, C2FormatCompressed); 266 expected.setStream(0); // only support single stream 267 C2StreamBufferTypeSetting::input invalid(0u, C2FormatVideo); 268 invalid.setStream(0); // only support single stream 269 TRACED_FAILURE(testReadOnlyParam(&expected, &invalid)); 270 } 271 272 TEST_F(C2VDACompIntfTest, TestOutputFormat) { 273 C2StreamBufferTypeSetting::output expected(0u, C2FormatVideo); 274 expected.setStream(0); // only support single stream 275 C2StreamBufferTypeSetting::output invalid(0u, C2FormatCompressed); 276 invalid.setStream(0); // only support single stream 277 TRACED_FAILURE(testReadOnlyParam(&expected, &invalid)); 278 } 279 280 TEST_F(C2VDACompIntfTest, TestInputPortMime) { 281 std::shared_ptr<C2PortMediaTypeSetting::input> expected( 282 AllocSharedString<C2PortMediaTypeSetting::input>(MEDIA_MIMETYPE_VIDEO_AVC)); 283 std::shared_ptr<C2PortMediaTypeSetting::input> invalid( 284 AllocSharedString<C2PortMediaTypeSetting::input>(MEDIA_MIMETYPE_VIDEO_RAW)); 285 TRACED_FAILURE(testReadOnlyParamOnHeap(expected.get(), invalid.get())); 286 } 287 288 TEST_F(C2VDACompIntfTest, TestOutputPortMime) { 289 std::shared_ptr<C2PortMediaTypeSetting::output> expected( 290 AllocSharedString<C2PortMediaTypeSetting::output>(MEDIA_MIMETYPE_VIDEO_RAW)); 291 std::shared_ptr<C2PortMediaTypeSetting::output> invalid( 292 AllocSharedString<C2PortMediaTypeSetting::output>(MEDIA_MIMETYPE_VIDEO_AVC)); 293 TRACED_FAILURE(testReadOnlyParamOnHeap(expected.get(), invalid.get())); 294 } 295 296 TEST_F(C2VDACompIntfTest, TestVideoSize) { 297 C2StreamPictureSizeInfo::output videoSize; 298 videoSize.setStream(0); // only support single stream 299 std::vector<C2FieldSupportedValuesQuery> widthC2FSV = { 300 {C2ParamField(&videoSize, &C2StreamPictureSizeInfo::width), 301 C2FieldSupportedValuesQuery::CURRENT}, 302 }; 303 ASSERT_EQ(C2_OK, mIntf->querySupportedValues_vb(widthC2FSV, C2_DONT_BLOCK)); 304 std::vector<C2FieldSupportedValuesQuery> heightC2FSV = { 305 {C2ParamField(&videoSize, &C2StreamPictureSizeInfo::height), 306 C2FieldSupportedValuesQuery::CURRENT}, 307 }; 308 ASSERT_EQ(C2_OK, mIntf->querySupportedValues_vb(heightC2FSV, C2_DONT_BLOCK)); 309 ASSERT_EQ(1u, widthC2FSV.size()); 310 ASSERT_EQ(C2_OK, widthC2FSV[0].status); 311 ASSERT_EQ(C2FieldSupportedValues::RANGE, widthC2FSV[0].values.type); 312 auto& widthFSVRange = widthC2FSV[0].values.range; 313 int32_t widthMin = widthFSVRange.min.i32; 314 int32_t widthMax = widthFSVRange.max.i32; 315 int32_t widthStep = widthFSVRange.step.i32; 316 317 ASSERT_EQ(1u, heightC2FSV.size()); 318 ASSERT_EQ(C2_OK, heightC2FSV[0].status); 319 ASSERT_EQ(C2FieldSupportedValues::RANGE, heightC2FSV[0].values.type); 320 auto& heightFSVRange = heightC2FSV[0].values.range; 321 int32_t heightMin = heightFSVRange.min.i32; 322 int32_t heightMax = heightFSVRange.max.i32; 323 int32_t heightStep = heightFSVRange.step.i32; 324 325 // test updating valid and invalid values 326 TRACED_FAILURE(testWritableVideoSizeParam<C2StreamPictureSizeInfo::output>( 327 widthMin, widthMax, widthStep, heightMin, heightMax, heightStep)); 328 } 329 330 TEST_F(C2VDACompIntfTest, TestInputAllocatorIds) { 331 std::shared_ptr<C2PortAllocatorsTuning::input> expected( 332 C2PortAllocatorsTuning::input::AllocShared(kInputAllocators)); 333 std::shared_ptr<C2PortAllocatorsTuning::input> invalid( 334 C2PortAllocatorsTuning::input::AllocShared(kOutputAllocators)); 335 TRACED_FAILURE(testReadOnlyParamOnHeap(expected.get(), invalid.get())); 336 } 337 338 TEST_F(C2VDACompIntfTest, TestOutputAllocatorIds) { 339 std::shared_ptr<C2PortAllocatorsTuning::output> expected( 340 C2PortAllocatorsTuning::output::AllocShared(kOutputAllocators)); 341 std::shared_ptr<C2PortAllocatorsTuning::output> invalid( 342 C2PortAllocatorsTuning::output::AllocShared(kInputAllocators)); 343 TRACED_FAILURE(testReadOnlyParamOnHeap(expected.get(), invalid.get())); 344 } 345 346 TEST_F(C2VDACompIntfTest, TestOutputBlockPoolIds) { 347 std::vector<std::unique_ptr<C2Param>> heapParams; 348 C2Param::Index index = C2PortBlockPoolsTuning::output::PARAM_TYPE; 349 350 // Query the param and check the default value. 351 ASSERT_EQ(C2_OK, mIntf->query_vb({}, {index}, C2_DONT_BLOCK, &heapParams)); 352 ASSERT_EQ(1u, heapParams.size()); 353 C2BlockPool::local_id_t value = ((C2PortBlockPoolsTuning*)heapParams[0].get())->m.values[0]; 354 ASSERT_EQ(kDefaultOutputBlockPool, value); 355 356 // Configure the param. 357 C2BlockPool::local_id_t configBlockPools[] = {C2BlockPool::PLATFORM_START + 1}; 358 std::shared_ptr<C2PortBlockPoolsTuning::output> newParam( 359 C2PortBlockPoolsTuning::output::AllocShared(configBlockPools)); 360 361 std::vector<C2Param*> params{newParam.get()}; 362 std::vector<std::unique_ptr<C2SettingResult>> failures; 363 ASSERT_EQ(C2_OK, mIntf->config_vb(params, C2_DONT_BLOCK, &failures)); 364 EXPECT_EQ(0u, failures.size()); 365 366 // Query the param again and check the value is as configured 367 heapParams.clear(); 368 ASSERT_EQ(C2_OK, mIntf->query_vb({}, {index}, C2_DONT_BLOCK, &heapParams)); 369 ASSERT_EQ(1u, heapParams.size()); 370 value = ((C2PortBlockPoolsTuning*)heapParams[0].get())->m.values[0]; 371 ASSERT_EQ(configBlockPools[0], value); 372 } 373 374 TEST_F(C2VDACompIntfTest, TestUnsupportedParam) { 375 C2ComponentTemporalInfo unsupportedParam; 376 std::vector<C2Param*> stackParams{&unsupportedParam}; 377 ASSERT_EQ(C2_BAD_INDEX, mIntf->query_vb(stackParams, {}, C2_DONT_BLOCK, nullptr)); 378 EXPECT_EQ(0u, unsupportedParam.size()); // invalidated 379 } 380 381 void dumpType(const C2FieldDescriptor::type_t type) { 382 switch (type) { 383 case C2FieldDescriptor::INT32: 384 printf("int32_t"); 385 break; 386 case C2FieldDescriptor::UINT32: 387 printf("uint32_t"); 388 break; 389 case C2FieldDescriptor::INT64: 390 printf("int64_t"); 391 break; 392 case C2FieldDescriptor::UINT64: 393 printf("uint64_t"); 394 break; 395 case C2FieldDescriptor::FLOAT: 396 printf("float"); 397 break; 398 default: 399 printf("<flex>"); 400 break; 401 } 402 } 403 404 void dumpStruct(const C2StructDescriptor& sd) { 405 printf(" struct: { "); 406 for (const C2FieldDescriptor& f : sd) { 407 printf("%s:", f.name().c_str()); 408 dumpType(f.type()); 409 printf(", "); 410 } 411 printf("}\n"); 412 } 413 414 TEST_F(C2VDACompIntfTest, ParamReflector) { 415 std::vector<std::shared_ptr<C2ParamDescriptor>> params; 416 417 ASSERT_EQ(mIntf->querySupportedParams_nb(¶ms), C2_OK); 418 for (const auto& paramDesc : params) { 419 printf("name: %s\n", paramDesc->name().c_str()); 420 printf(" required: %s\n", paramDesc->isRequired() ? "yes" : "no"); 421 printf(" type: %x\n", paramDesc->index().type()); 422 std::unique_ptr<C2StructDescriptor> desc{mReflector->describe(paramDesc->index().type())}; 423 if (desc.get()) dumpStruct(*desc); 424 } 425 } 426 } // namespace android 427