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