1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "codec2_hidl_hal_video_dec_test"
19
20 #include <android-base/logging.h>
21 #include <gtest/gtest.h>
22 #include <stdio.h>
23 #include <fstream>
24
25 #include <codec2/hidl/client.h>
26 #include <C2AllocatorIon.h>
27 #include <C2Config.h>
28 #include <C2Debug.h>
29 #include <C2Buffer.h>
30 #include <C2BufferPriv.h>
31
32 using android::C2AllocatorIon;
33
34 #include <VtsHalHidlTargetTestBase.h>
35 #include "media_c2_video_hidl_test_common.h"
36 #include "media_c2_hidl_test_common.h"
37
38 struct FrameInfo {
39 int bytesCount;
40 uint32_t flags;
41 int64_t timestamp;
42 };
43
44 class LinearBuffer : public C2Buffer {
45 public:
LinearBuffer(const std::shared_ptr<C2LinearBlock> & block)46 explicit LinearBuffer(const std::shared_ptr<C2LinearBlock>& block)
47 : C2Buffer(
48 {block->share(block->offset(), block->size(), ::C2Fence())}) {}
49 };
50
51 static ComponentTestEnvironment* gEnv = nullptr;
52
53 namespace {
54
55 class Codec2VideoDecHidlTest : public ::testing::VtsHalHidlTargetTestBase {
56 private:
57 typedef ::testing::VtsHalHidlTargetTestBase Super;
58
59 public:
getTestCaseInfo() const60 ::std::string getTestCaseInfo() const override {
61 return ::std::string() +
62 "Component: " + gEnv->getComponent().c_str() + " | " +
63 "Instance: " + gEnv->getInstance().c_str() + " | " +
64 "Res: " + gEnv->getRes().c_str();
65 }
66
67 // google.codec2 Video test setup
SetUp()68 virtual void SetUp() override {
69 Super::SetUp();
70 mDisableTest = false;
71 ALOGV("Codec2VideoDecHidlTest SetUp");
72 mClient = android::Codec2Client::CreateFromService(
73 gEnv->getInstance().c_str());
74 ASSERT_NE(mClient, nullptr);
75 mListener.reset(new CodecListener(
76 [this](std::list<std::unique_ptr<C2Work>>& workItems) {
77 handleWorkDone(workItems);
78 }));
79 ASSERT_NE(mListener, nullptr);
80 for (int i = 0; i < MAX_INPUT_BUFFERS; ++i) {
81 mWorkQueue.emplace_back(new C2Work);
82 }
83 mClient->createComponent(gEnv->getComponent().c_str(), mListener,
84 &mComponent);
85 ASSERT_NE(mComponent, nullptr);
86
87 std::shared_ptr<C2AllocatorStore> store =
88 android::GetCodec2PlatformAllocatorStore();
89 CHECK_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR,
90 &mLinearAllocator),
91 C2_OK);
92 mLinearPool = std::make_shared<C2PooledBlockPool>(mLinearAllocator,
93 mBlockPoolId++);
94 ASSERT_NE(mLinearPool, nullptr);
95
96 mCompName = unknown_comp;
97 struct StringToName {
98 const char* Name;
99 standardComp CompName;
100 };
101
102 const StringToName kStringToName[] = {
103 {"h263", h263}, {"avc", avc}, {"mpeg2", mpeg2}, {"mpeg4", mpeg4},
104 {"hevc", hevc}, {"vp8", vp8}, {"vp9", vp9}, {"av1", av1},
105 };
106
107 const size_t kNumStringToName =
108 sizeof(kStringToName) / sizeof(kStringToName[0]);
109
110 std::string substring;
111 std::string comp;
112 substring = std::string(gEnv->getComponent());
113 /* TODO: better approach to find the component */
114 /* "c2.android." => 11th position */
115 size_t pos = 11;
116 size_t len = substring.find(".decoder", pos);
117 comp = substring.substr(pos, len - pos);
118
119 for (size_t i = 0; i < kNumStringToName; ++i) {
120 if (!strcasecmp(comp.c_str(), kStringToName[i].Name)) {
121 mCompName = kStringToName[i].CompName;
122 break;
123 }
124 }
125 mEos = false;
126 mFramesReceived = 0;
127 mTimestampUs = 0u;
128 mTimestampDevTest = false;
129 if (mCompName == unknown_comp) mDisableTest = true;
130 if (mDisableTest) std::cout << "[ WARN ] Test Disabled \n";
131 }
132
TearDown()133 virtual void TearDown() override {
134 if (mComponent != nullptr) {
135 if (::testing::Test::HasFatalFailure()) return;
136 mComponent->release();
137 mComponent = nullptr;
138 }
139 Super::TearDown();
140 }
141
142 // callback function to process onWorkDone received by Listener
handleWorkDone(std::list<std::unique_ptr<C2Work>> & workItems)143 void handleWorkDone(std::list<std::unique_ptr<C2Work>>& workItems) {
144 for (std::unique_ptr<C2Work>& work : workItems) {
145 if (!work->worklets.empty()) {
146 // For decoder components current timestamp always exceeds
147 // previous timestamp
148 typedef std::unique_lock<std::mutex> ULock;
149 bool codecConfig = ((work->worklets.front()->output.flags &
150 C2FrameData::FLAG_CODEC_CONFIG) != 0);
151 if (!codecConfig &&
152 !work->worklets.front()->output.buffers.empty()) {
153 EXPECT_GE(
154 (work->worklets.front()->output.ordinal.timestamp.peeku()),
155 mTimestampUs);
156 mTimestampUs =
157 work->worklets.front()->output.ordinal.timestamp.peeku();
158
159 ULock l(mQueueLock);
160 if (mTimestampDevTest) {
161 bool tsHit = false;
162 std::list<uint64_t>::iterator it = mTimestampUslist.begin();
163 while (it != mTimestampUslist.end()) {
164 if (*it == mTimestampUs) {
165 mTimestampUslist.erase(it);
166 tsHit = true;
167 break;
168 }
169 it++;
170 }
171 if (tsHit == false) {
172 if (mTimestampUslist.empty() == false) {
173 EXPECT_EQ(tsHit, true)
174 << "TimeStamp not recognized";
175 } else {
176 std::cout << "[ INFO ] Received non-zero "
177 "output / TimeStamp not recognized \n";
178 }
179 }
180 }
181 }
182 bool mCsd;
183 workDone(mComponent, work, mFlushedIndices, mQueueLock,
184 mQueueCondition, mWorkQueue, mEos, mCsd,
185 mFramesReceived);
186 (void)mCsd;
187 }
188 }
189 }
190
191 enum standardComp {
192 h263,
193 avc,
194 mpeg2,
195 mpeg4,
196 hevc,
197 vp8,
198 vp9,
199 av1,
200 unknown_comp,
201 };
202
203 bool mEos;
204 bool mDisableTest;
205 bool mTimestampDevTest;
206 uint64_t mTimestampUs;
207 std::list<uint64_t> mTimestampUslist;
208 std::list<uint64_t> mFlushedIndices;
209 standardComp mCompName;
210 uint32_t mFramesReceived;
211 C2BlockPool::local_id_t mBlockPoolId;
212 std::shared_ptr<C2BlockPool> mLinearPool;
213 std::shared_ptr<C2Allocator> mLinearAllocator;
214
215 std::mutex mQueueLock;
216 std::condition_variable mQueueCondition;
217 std::list<std::unique_ptr<C2Work>> mWorkQueue;
218
219 std::shared_ptr<android::Codec2Client> mClient;
220 std::shared_ptr<android::Codec2Client::Listener> mListener;
221 std::shared_ptr<android::Codec2Client::Component> mComponent;
222
223 protected:
description(const std::string & description)224 static void description(const std::string& description) {
225 RecordProperty("description", description);
226 }
227 };
228
validateComponent(const std::shared_ptr<android::Codec2Client::Component> & component,Codec2VideoDecHidlTest::standardComp compName,bool & disableTest)229 void validateComponent(
230 const std::shared_ptr<android::Codec2Client::Component>& component,
231 Codec2VideoDecHidlTest::standardComp compName, bool& disableTest) {
232 // Validate its a C2 Component
233 if (component->getName().find("c2") == std::string::npos) {
234 ALOGE("Not a c2 component");
235 disableTest = true;
236 return;
237 }
238
239 // Validate its not an encoder and the component to be tested is video
240 if (component->getName().find("encoder") != std::string::npos) {
241 ALOGE("Expected Decoder, given Encoder");
242 disableTest = true;
243 return;
244 }
245 std::vector<std::unique_ptr<C2Param>> queried;
246 c2_status_t c2err =
247 component->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE},
248 C2_DONT_BLOCK, &queried);
249 if (c2err != C2_OK && queried.size() == 0) {
250 ALOGE("Query media type failed => %d", c2err);
251 } else {
252 std::string inputDomain =
253 ((C2StreamMediaTypeSetting::input*)queried[0].get())->m.value;
254 if (inputDomain.find("video/") == std::string::npos) {
255 ALOGE("Expected Video Component");
256 disableTest = true;
257 return;
258 }
259 }
260
261 // Validates component name
262 if (compName == Codec2VideoDecHidlTest::unknown_comp) {
263 ALOGE("Component InValid");
264 disableTest = true;
265 return;
266 }
267 ALOGV("Component Valid");
268 }
269
270 // number of elementary streams per component
271 #define STREAM_COUNT 2
272 // LookUpTable of clips and metadata for component testing
GetURLForComponent(Codec2VideoDecHidlTest::standardComp comp,char * mURL,char * info,size_t streamIndex=1)273 void GetURLForComponent(Codec2VideoDecHidlTest::standardComp comp, char* mURL,
274 char* info, size_t streamIndex = 1) {
275 struct CompToURL {
276 Codec2VideoDecHidlTest::standardComp comp;
277 const char mURL[STREAM_COUNT][512];
278 const char info[STREAM_COUNT][512];
279 };
280 ASSERT_TRUE(streamIndex < STREAM_COUNT);
281
282 static const CompToURL kCompToURL[] = {
283 {Codec2VideoDecHidlTest::standardComp::avc,
284 {"bbb_avc_176x144_300kbps_60fps.h264",
285 "bbb_avc_640x360_768kbps_30fps.h264"},
286 {"bbb_avc_176x144_300kbps_60fps.info",
287 "bbb_avc_640x360_768kbps_30fps.info"}},
288 {Codec2VideoDecHidlTest::standardComp::hevc,
289 {"bbb_hevc_176x144_176kbps_60fps.hevc",
290 "bbb_hevc_640x360_1600kbps_30fps.hevc"},
291 {"bbb_hevc_176x144_176kbps_60fps.info",
292 "bbb_hevc_640x360_1600kbps_30fps.info"}},
293 {Codec2VideoDecHidlTest::standardComp::mpeg2,
294 {"bbb_mpeg2_176x144_105kbps_25fps.m2v",
295 "bbb_mpeg2_352x288_1mbps_60fps.m2v"},
296 {"bbb_mpeg2_176x144_105kbps_25fps.info",
297 "bbb_mpeg2_352x288_1mbps_60fps.info"}},
298 {Codec2VideoDecHidlTest::standardComp::h263,
299 {"", "bbb_h263_352x288_300kbps_12fps.h263"},
300 {"", "bbb_h263_352x288_300kbps_12fps.info"}},
301 {Codec2VideoDecHidlTest::standardComp::mpeg4,
302 {"", "bbb_mpeg4_352x288_512kbps_30fps.m4v"},
303 {"", "bbb_mpeg4_352x288_512kbps_30fps.info"}},
304 {Codec2VideoDecHidlTest::standardComp::vp8,
305 {"bbb_vp8_176x144_240kbps_60fps.vp8",
306 "bbb_vp8_640x360_2mbps_30fps.vp8"},
307 {"bbb_vp8_176x144_240kbps_60fps.info",
308 "bbb_vp8_640x360_2mbps_30fps.info"}},
309 {Codec2VideoDecHidlTest::standardComp::vp9,
310 {"bbb_vp9_176x144_285kbps_60fps.vp9",
311 "bbb_vp9_640x360_1600kbps_30fps.vp9"},
312 {"bbb_vp9_176x144_285kbps_60fps.info",
313 "bbb_vp9_640x360_1600kbps_30fps.info"}},
314 {Codec2VideoDecHidlTest::standardComp::av1,
315 {"bbb_av1_640_360.av1",
316 "bbb_av1_176_144.av1"},
317 {"bbb_av1_640_360.info",
318 "bbb_av1_176_144.info"}},
319 };
320
321 for (size_t i = 0; i < sizeof(kCompToURL) / sizeof(kCompToURL[0]); ++i) {
322 if (kCompToURL[i].comp == comp) {
323 strcat(mURL, kCompToURL[i].mURL[streamIndex]);
324 strcat(info, kCompToURL[i].info[streamIndex]);
325 return;
326 }
327 }
328 }
329
decodeNFrames(const std::shared_ptr<android::Codec2Client::Component> & component,std::mutex & queueLock,std::condition_variable & queueCondition,std::list<std::unique_ptr<C2Work>> & workQueue,std::list<uint64_t> & flushedIndices,std::shared_ptr<C2BlockPool> & linearPool,std::ifstream & eleStream,android::Vector<FrameInfo> * Info,int offset,int range,bool signalEOS=true)330 void decodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& component,
331 std::mutex &queueLock, std::condition_variable& queueCondition,
332 std::list<std::unique_ptr<C2Work>>& workQueue,
333 std::list<uint64_t>& flushedIndices,
334 std::shared_ptr<C2BlockPool>& linearPool,
335 std::ifstream& eleStream,
336 android::Vector<FrameInfo>* Info,
337 int offset, int range, bool signalEOS = true) {
338 typedef std::unique_lock<std::mutex> ULock;
339 int frameID = offset;
340 int maxRetry = 0;
341 while (1) {
342 if (frameID == (int)Info->size() || frameID == (offset + range)) break;
343 uint32_t flags = 0;
344 std::unique_ptr<C2Work> work;
345 // Prepare C2Work
346 while (!work && (maxRetry < MAX_RETRY)) {
347 ULock l(queueLock);
348 if (!workQueue.empty()) {
349 work.swap(workQueue.front());
350 workQueue.pop_front();
351 } else {
352 queueCondition.wait_for(l, TIME_OUT);
353 maxRetry++;
354 }
355 }
356 if (!work && (maxRetry >= MAX_RETRY)) {
357 ASSERT_TRUE(false) << "Wait for generating C2Work exceeded timeout";
358 }
359 int64_t timestamp = (*Info)[frameID].timestamp;
360 if ((*Info)[frameID].flags) flags = (1 << ((*Info)[frameID].flags - 1));
361 if (signalEOS && ((frameID == (int)Info->size() - 1) ||
362 (frameID == (offset + range - 1))))
363 flags |= C2FrameData::FLAG_END_OF_STREAM;
364
365 work->input.flags = (C2FrameData::flags_t)flags;
366 work->input.ordinal.timestamp = timestamp;
367 work->input.ordinal.frameIndex = frameID;
368 {
369 ULock l(queueLock);
370 flushedIndices.emplace_back(frameID);
371 }
372
373 int size = (*Info)[frameID].bytesCount;
374 char* data = (char*)malloc(size);
375 ASSERT_NE(data, nullptr);
376
377 eleStream.read(data, size);
378 ASSERT_EQ(eleStream.gcount(), size);
379
380 work->input.buffers.clear();
381 if (size) {
382 std::shared_ptr<C2LinearBlock> block;
383 ASSERT_EQ(C2_OK,
384 linearPool->fetchLinearBlock(
385 size, {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE},
386 &block));
387 ASSERT_TRUE(block);
388
389 // Write View
390 C2WriteView view = block->map().get();
391 if (view.error() != C2_OK) {
392 fprintf(stderr, "C2LinearBlock::map() failed : %d", view.error());
393 break;
394 }
395 ASSERT_EQ((size_t)size, view.capacity());
396 ASSERT_EQ(0u, view.offset());
397 ASSERT_EQ((size_t)size, view.size());
398
399 memcpy(view.base(), data, size);
400
401 work->input.buffers.emplace_back(new LinearBuffer(block));
402 free(data);
403 }
404 work->worklets.clear();
405 work->worklets.emplace_back(new C2Worklet);
406 std::list<std::unique_ptr<C2Work>> items;
407 items.push_back(std::move(work));
408
409 // DO THE DECODING
410 ASSERT_EQ(component->queue(&items), C2_OK);
411 ALOGV("Frame #%d size = %d queued", frameID, size);
412 frameID++;
413 maxRetry = 0;
414 }
415 }
416
TEST_F(Codec2VideoDecHidlTest,validateCompName)417 TEST_F(Codec2VideoDecHidlTest, validateCompName) {
418 if (mDisableTest) return;
419 ALOGV("Checks if the given component is a valid video component");
420 validateComponent(mComponent, mCompName, mDisableTest);
421 ASSERT_EQ(mDisableTest, false);
422 }
423
424 // Bitstream Test
TEST_F(Codec2VideoDecHidlTest,DecodeTest)425 TEST_F(Codec2VideoDecHidlTest, DecodeTest) {
426 description("Decodes input file");
427 if (mDisableTest) return;
428
429 char mURL[512], info[512];
430 std::ifstream eleStream, eleInfo;
431
432 strcpy(mURL, gEnv->getRes().c_str());
433 strcpy(info, gEnv->getRes().c_str());
434 GetURLForComponent(mCompName, mURL, info);
435
436 eleInfo.open(info);
437 ASSERT_EQ(eleInfo.is_open(), true) << mURL << " - file not found";
438 android::Vector<FrameInfo> Info;
439 int bytesCount = 0;
440 uint32_t flags = 0;
441 uint32_t timestamp = 0;
442 while (1) {
443 if (!(eleInfo >> bytesCount)) break;
444 eleInfo >> flags;
445 eleInfo >> timestamp;
446 bool codecConfig = flags ?
447 ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0 : 0;
448 if (mTimestampDevTest && !codecConfig)
449 mTimestampUslist.push_back(timestamp);
450 Info.push_back({bytesCount, flags, timestamp});
451 }
452 eleInfo.close();
453
454 ASSERT_EQ(mComponent->start(), C2_OK);
455 ALOGV("mURL : %s", mURL);
456 eleStream.open(mURL, std::ifstream::binary);
457 ASSERT_EQ(eleStream.is_open(), true);
458 ASSERT_NO_FATAL_FAILURE(decodeNFrames(
459 mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices,
460 mLinearPool, eleStream, &Info, 0, (int)Info.size()));
461
462 // blocking call to ensures application to Wait till all the inputs are
463 // consumed
464 if (!mEos) {
465 ALOGV("Waiting for input consumption");
466 ASSERT_NO_FATAL_FAILURE(
467 waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
468 }
469
470 eleStream.close();
471 if (mFramesReceived != Info.size()) {
472 ALOGE("Input buffer count and Output buffer count mismatch");
473 ALOGV("framesReceived : %d inputFrames : %zu", mFramesReceived,
474 Info.size());
475 ASSERT_TRUE(false);
476 }
477
478 if (mTimestampDevTest) EXPECT_EQ(mTimestampUslist.empty(), true);
479 }
480
481
482 // Adaptive Test
TEST_F(Codec2VideoDecHidlTest,AdaptiveDecodeTest)483 TEST_F(Codec2VideoDecHidlTest, AdaptiveDecodeTest) {
484 description("Adaptive Decode Test");
485 if (mDisableTest) return;
486 if (!(mCompName == avc || mCompName == hevc || mCompName == vp8 ||
487 mCompName == vp9 || mCompName == mpeg2))
488 return;
489
490 typedef std::unique_lock<std::mutex> ULock;
491 ASSERT_EQ(mComponent->start(), C2_OK);
492
493 mTimestampDevTest = true;
494 uint32_t timestampOffset = 0;
495 uint32_t offset = 0;
496 android::Vector<FrameInfo> Info;
497 for (uint32_t i = 0; i < STREAM_COUNT * 2; i++) {
498 char mURL[512], info[512];
499 std::ifstream eleStream, eleInfo;
500
501 strcpy(mURL, gEnv->getRes().c_str());
502 strcpy(info, gEnv->getRes().c_str());
503 GetURLForComponent(mCompName, mURL, info, i % STREAM_COUNT);
504
505 eleInfo.open(info);
506 ASSERT_EQ(eleInfo.is_open(), true) << mURL << " - file not found";
507 int bytesCount = 0;
508 uint32_t flags = 0;
509 uint32_t timestamp = 0;
510 uint32_t timestampMax = 0;
511 while (1) {
512 if (!(eleInfo >> bytesCount)) break;
513 eleInfo >> flags;
514 eleInfo >> timestamp;
515 timestamp += timestampOffset;
516 Info.push_back({bytesCount, flags, timestamp});
517 bool codecConfig = flags ?
518 ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0 : 0;
519
520 {
521 ULock l(mQueueLock);
522 if (mTimestampDevTest && !codecConfig)
523 mTimestampUslist.push_back(timestamp);
524 }
525 if (timestampMax < timestamp) timestampMax = timestamp;
526 }
527 timestampOffset = timestampMax;
528 eleInfo.close();
529
530 // Reset Total frames before second decode loop
531 // mFramesReceived = 0;
532 ALOGV("mURL : %s", mURL);
533 eleStream.open(mURL, std::ifstream::binary);
534 ASSERT_EQ(eleStream.is_open(), true);
535 ASSERT_NO_FATAL_FAILURE(
536 decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
537 mFlushedIndices, mLinearPool, eleStream, &Info,
538 offset, (int)(Info.size() - offset), false));
539
540 eleStream.close();
541 offset = (int)Info.size();
542 }
543
544 // Send EOS
545 // TODO Add function to send EOS work item
546 int maxRetry = 0;
547 std::unique_ptr<C2Work> work;
548 while (!work && (maxRetry < MAX_RETRY)) {
549 ULock l(mQueueLock);
550 if (!mWorkQueue.empty()) {
551 work.swap(mWorkQueue.front());
552 mWorkQueue.pop_front();
553 } else {
554 mQueueCondition.wait_for(l, TIME_OUT);
555 maxRetry++;
556 }
557 }
558 ASSERT_NE(work, nullptr);
559 work->input.flags = (C2FrameData::flags_t)C2FrameData::FLAG_END_OF_STREAM;
560 work->input.ordinal.timestamp = 0;
561 work->input.ordinal.frameIndex = 0;
562 work->input.buffers.clear();
563 work->worklets.clear();
564 work->worklets.emplace_back(new C2Worklet);
565
566 std::list<std::unique_ptr<C2Work>> items;
567 items.push_back(std::move(work));
568 ASSERT_EQ(mComponent->queue(&items), C2_OK);
569
570 // blocking call to ensures application to Wait till all the inputs are
571 // consumed
572 ALOGV("Waiting for input consumption");
573 ASSERT_NO_FATAL_FAILURE(
574 waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
575
576 if (mFramesReceived != ((Info.size()) + 1)) {
577 ALOGE("Input buffer count and Output buffer count mismatch");
578 ALOGV("framesReceived : %d inputFrames : %zu", mFramesReceived,
579 Info.size() + 1);
580 ASSERT_TRUE(false);
581 }
582
583 if (mTimestampDevTest) EXPECT_EQ(mTimestampUslist.empty(), true);
584 }
585
586 // thumbnail test
TEST_F(Codec2VideoDecHidlTest,ThumbnailTest)587 TEST_F(Codec2VideoDecHidlTest, ThumbnailTest) {
588 description("Test Request for thumbnail");
589 if (mDisableTest) return;
590
591 char mURL[512], info[512];
592 std::ifstream eleStream, eleInfo;
593
594 strcpy(mURL, gEnv->getRes().c_str());
595 strcpy(info, gEnv->getRes().c_str());
596 GetURLForComponent(mCompName, mURL, info);
597
598 eleInfo.open(info);
599 ASSERT_EQ(eleInfo.is_open(), true);
600 android::Vector<FrameInfo> Info;
601 int bytesCount = 0;
602 uint32_t flags = 0;
603 uint32_t timestamp = 0;
604 while (1) {
605 if (!(eleInfo >> bytesCount)) break;
606 eleInfo >> flags;
607 eleInfo >> timestamp;
608 Info.push_back({bytesCount, flags, timestamp});
609 }
610 eleInfo.close();
611
612 for (size_t i = 0; i < MAX_ITERATIONS; i++) {
613 ASSERT_EQ(mComponent->start(), C2_OK);
614
615 // request EOS for thumbnail
616 // signal EOS flag with last frame
617 size_t j = -1;
618 do {
619 j++;
620 flags = 0;
621 if (Info[j].flags) flags = 1u << (Info[j].flags - 1);
622
623 } while (!(flags & SYNC_FRAME));
624 eleStream.open(mURL, std::ifstream::binary);
625 ASSERT_EQ(eleStream.is_open(), true);
626 ASSERT_NO_FATAL_FAILURE(decodeNFrames(
627 mComponent, mQueueLock, mQueueCondition, mWorkQueue,
628 mFlushedIndices, mLinearPool, eleStream, &Info, 0, j + 1));
629 ASSERT_NO_FATAL_FAILURE(
630 waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
631 eleStream.close();
632 EXPECT_GE(mFramesReceived, 1U);
633 ASSERT_EQ(mEos, true);
634 ASSERT_EQ(mComponent->stop(), C2_OK);
635 }
636 ASSERT_EQ(mComponent->release(), C2_OK);
637 }
638
TEST_F(Codec2VideoDecHidlTest,EOSTest)639 TEST_F(Codec2VideoDecHidlTest, EOSTest) {
640 description("Test empty input buffer with EOS flag");
641 if (mDisableTest) return;
642 typedef std::unique_lock<std::mutex> ULock;
643 ASSERT_EQ(mComponent->start(), C2_OK);
644 std::unique_ptr<C2Work> work;
645 // Prepare C2Work
646 {
647 ULock l(mQueueLock);
648 if (!mWorkQueue.empty()) {
649 work.swap(mWorkQueue.front());
650 mWorkQueue.pop_front();
651 } else {
652 ASSERT_TRUE(false) << "mWorkQueue Empty at the start of test";
653 }
654 }
655 ASSERT_NE(work, nullptr);
656
657 work->input.flags = (C2FrameData::flags_t)C2FrameData::FLAG_END_OF_STREAM;
658 work->input.ordinal.timestamp = 0;
659 work->input.ordinal.frameIndex = 0;
660 work->input.buffers.clear();
661 work->worklets.clear();
662 work->worklets.emplace_back(new C2Worklet);
663
664 std::list<std::unique_ptr<C2Work>> items;
665 items.push_back(std::move(work));
666 ASSERT_EQ(mComponent->queue(&items), C2_OK);
667
668 {
669 ULock l(mQueueLock);
670 if (mWorkQueue.size() != MAX_INPUT_BUFFERS) {
671 mQueueCondition.wait_for(l, TIME_OUT);
672 }
673 }
674 ASSERT_EQ(mEos, true);
675 ASSERT_EQ(mWorkQueue.size(), (size_t)MAX_INPUT_BUFFERS);
676 ASSERT_EQ(mComponent->stop(), C2_OK);
677 }
678
TEST_F(Codec2VideoDecHidlTest,FlushTest)679 TEST_F(Codec2VideoDecHidlTest, FlushTest) {
680 description("Tests Flush calls");
681 if (mDisableTest) return;
682 typedef std::unique_lock<std::mutex> ULock;
683 ASSERT_EQ(mComponent->start(), C2_OK);
684 char mURL[512], info[512];
685 std::ifstream eleStream, eleInfo;
686
687 strcpy(mURL, gEnv->getRes().c_str());
688 strcpy(info, gEnv->getRes().c_str());
689 GetURLForComponent(mCompName, mURL, info);
690
691 eleInfo.open(info);
692 ASSERT_EQ(eleInfo.is_open(), true);
693 android::Vector<FrameInfo> Info;
694 int bytesCount = 0;
695 uint32_t flags = 0;
696 uint32_t timestamp = 0;
697 mFlushedIndices.clear();
698 while (1) {
699 if (!(eleInfo >> bytesCount)) break;
700 eleInfo >> flags;
701 eleInfo >> timestamp;
702 Info.push_back({bytesCount, flags, timestamp});
703 }
704 eleInfo.close();
705
706 ALOGV("mURL : %s", mURL);
707 eleStream.open(mURL, std::ifstream::binary);
708 ASSERT_EQ(eleStream.is_open(), true);
709 // Decode 128 frames and flush. here 128 is chosen to ensure there is a key
710 // frame after this so that the below section can be covered for all
711 // components
712 uint32_t numFramesFlushed = 128;
713 ASSERT_NO_FATAL_FAILURE(decodeNFrames(
714 mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices,
715 mLinearPool, eleStream, &Info, 0, numFramesFlushed, false));
716 // flush
717 std::list<std::unique_ptr<C2Work>> flushedWork;
718 c2_status_t err =
719 mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
720 ASSERT_EQ(err, C2_OK);
721 ASSERT_NO_FATAL_FAILURE(
722 waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
723 (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
724
725 {
726 // Update mFlushedIndices based on the index received from flush()
727 ULock l(mQueueLock);
728 for (std::unique_ptr<C2Work>& work : flushedWork) {
729 ASSERT_NE(work, nullptr);
730 auto frameIndexIt =
731 std::find(mFlushedIndices.begin(), mFlushedIndices.end(),
732 work->input.ordinal.frameIndex.peeku());
733 if (!mFlushedIndices.empty() &&
734 (frameIndexIt != mFlushedIndices.end())) {
735 mFlushedIndices.erase(frameIndexIt);
736 work->input.buffers.clear();
737 work->worklets.clear();
738 mWorkQueue.push_back(std::move(work));
739 }
740 }
741 }
742 // Seek to next key frame and start decoding till the end
743 mFlushedIndices.clear();
744 int index = numFramesFlushed;
745 bool keyFrame = false;
746 flags = 0;
747 while (index < (int)Info.size()) {
748 if (Info[index].flags) flags = 1u << (Info[index].flags - 1);
749 if ((flags & SYNC_FRAME) == SYNC_FRAME) {
750 keyFrame = true;
751 break;
752 }
753 flags = 0;
754 eleStream.ignore(Info[index].bytesCount);
755 index++;
756 }
757 if (keyFrame) {
758 ASSERT_NO_FATAL_FAILURE(
759 decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
760 mFlushedIndices, mLinearPool, eleStream, &Info, index,
761 (int)Info.size() - index));
762 }
763 eleStream.close();
764 err = mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
765 ASSERT_EQ(err, C2_OK);
766 ASSERT_NO_FATAL_FAILURE(
767 waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
768 (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
769 {
770 // Update mFlushedIndices based on the index received from flush()
771 ULock l(mQueueLock);
772 for (std::unique_ptr<C2Work>& work : flushedWork) {
773 ASSERT_NE(work, nullptr);
774 uint64_t frameIndex = work->input.ordinal.frameIndex.peeku();
775 std::list<uint64_t>::iterator frameIndexIt = std::find(
776 mFlushedIndices.begin(), mFlushedIndices.end(), frameIndex);
777 if (!mFlushedIndices.empty() &&
778 (frameIndexIt != mFlushedIndices.end())) {
779 mFlushedIndices.erase(frameIndexIt);
780 work->input.buffers.clear();
781 work->worklets.clear();
782 mWorkQueue.push_back(std::move(work));
783 }
784 }
785 }
786 ASSERT_EQ(mFlushedIndices.empty(), true);
787 ASSERT_EQ(mComponent->stop(), C2_OK);
788 }
789
TEST_F(Codec2VideoDecHidlTest,DecodeTestEmptyBuffersInserted)790 TEST_F(Codec2VideoDecHidlTest, DecodeTestEmptyBuffersInserted) {
791 description("Decode with multiple empty input frames");
792 if (mDisableTest) return;
793
794 char mURL[512], info[512];
795 std::ifstream eleStream, eleInfo;
796
797 strcpy(mURL, gEnv->getRes().c_str());
798 strcpy(info, gEnv->getRes().c_str());
799 GetURLForComponent(mCompName, mURL, info);
800
801 eleInfo.open(info);
802 ASSERT_EQ(eleInfo.is_open(), true) << mURL << " - file not found";
803 android::Vector<FrameInfo> Info;
804 int bytesCount = 0;
805 uint32_t frameId = 0;
806 uint32_t flags = 0;
807 uint32_t timestamp = 0;
808 bool codecConfig = false;
809 // This test introduces empty CSD after every 20th frame
810 // and empty input frames at an interval of 5 frames.
811 while (1) {
812 if (!(frameId % 5)) {
813 if (!(frameId % 20)) flags = 32;
814 else flags = 0;
815 bytesCount = 0;
816 } else {
817 if (!(eleInfo >> bytesCount)) break;
818 eleInfo >> flags;
819 eleInfo >> timestamp;
820 codecConfig = flags ?
821 ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0 : 0;
822 }
823 Info.push_back({bytesCount, flags, timestamp});
824 frameId++;
825 }
826 eleInfo.close();
827
828 ASSERT_EQ(mComponent->start(), C2_OK);
829 ALOGV("mURL : %s", mURL);
830 eleStream.open(mURL, std::ifstream::binary);
831 ASSERT_EQ(eleStream.is_open(), true);
832 ASSERT_NO_FATAL_FAILURE(decodeNFrames(
833 mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices,
834 mLinearPool, eleStream, &Info, 0, (int)Info.size()));
835
836 // blocking call to ensures application to Wait till all the inputs are
837 // consumed
838 if (!mEos) {
839 ALOGV("Waiting for input consumption");
840 ASSERT_NO_FATAL_FAILURE(
841 waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
842 }
843
844 eleStream.close();
845 if (mFramesReceived != Info.size()) {
846 ALOGE("Input buffer count and Output buffer count mismatch");
847 ALOGV("framesReceived : %d inputFrames : %zu", mFramesReceived,
848 Info.size());
849 ASSERT_TRUE(false);
850 }
851 }
852
853 } // anonymous namespace
854
855 // TODO : Video specific configuration Test
main(int argc,char ** argv)856 int main(int argc, char** argv) {
857 gEnv = new ComponentTestEnvironment();
858 ::testing::AddGlobalTestEnvironment(gEnv);
859 ::testing::InitGoogleTest(&argc, argv);
860 gEnv->init(&argc, argv);
861 int status = gEnv->initFromOptions(argc, argv);
862 if (status == 0) {
863 int status = RUN_ALL_TESTS();
864 LOG(INFO) << "C2 Test result = " << status;
865 }
866 return status;
867 }
868