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_audio_dec_test"
19
20 #include <android-base/logging.h>
21 #include <gtest/gtest.h>
22 #include <algorithm>
23 #include <stdio.h>
24 #include <fstream>
25
26 #include <codec2/hidl/client.h>
27 #include <C2AllocatorIon.h>
28 #include <C2Config.h>
29 #include <C2Debug.h>
30 #include <C2Buffer.h>
31 #include <C2BufferPriv.h>
32
33 using android::C2AllocatorIon;
34
35 #include <VtsHalHidlTargetTestBase.h>
36 #include "media_c2_audio_hidl_test_common.h"
37 #include "media_c2_hidl_test_common.h"
38
39 struct FrameInfo {
40 int bytesCount;
41 uint32_t flags;
42 int64_t timestamp;
43 };
44
45 class LinearBuffer : public C2Buffer {
46 public:
LinearBuffer(const std::shared_ptr<C2LinearBlock> & block)47 explicit LinearBuffer(const std::shared_ptr<C2LinearBlock>& block)
48 : C2Buffer(
49 {block->share(block->offset(), block->size(), ::C2Fence())}) {}
50 };
51
52 static ComponentTestEnvironment* gEnv = nullptr;
53
54 namespace {
55
56 class Codec2AudioDecHidlTest : public ::testing::VtsHalHidlTargetTestBase {
57 private:
58 typedef ::testing::VtsHalHidlTargetTestBase Super;
59
60 public:
getTestCaseInfo() const61 ::std::string getTestCaseInfo() const override {
62 return ::std::string() +
63 "Component: " + gEnv->getComponent().c_str() + " | " +
64 "Instance: " + gEnv->getInstance().c_str() + " | " +
65 "Res: " + gEnv->getRes().c_str();
66 }
67
68 // google.codec2 Audio test setup
SetUp()69 virtual void SetUp() override {
70 Super::SetUp();
71 mDisableTest = false;
72 ALOGV("Codec2AudioDecHidlTest SetUp");
73 mClient = android::Codec2Client::CreateFromService(
74 gEnv->getInstance().c_str());
75 ASSERT_NE(mClient, nullptr);
76 mListener.reset(new CodecListener(
77 [this](std::list<std::unique_ptr<C2Work>>& workItems) {
78 handleWorkDone(workItems);
79 }));
80 ASSERT_NE(mListener, nullptr);
81 for (int i = 0; i < MAX_INPUT_BUFFERS; ++i) {
82 mWorkQueue.emplace_back(new C2Work);
83 }
84 mClient->createComponent(gEnv->getComponent().c_str(), mListener,
85 &mComponent);
86 ASSERT_NE(mComponent, nullptr);
87
88 std::shared_ptr<C2AllocatorStore> store =
89 android::GetCodec2PlatformAllocatorStore();
90 CHECK_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR,
91 &mLinearAllocator),
92 C2_OK);
93 mLinearPool = std::make_shared<C2PooledBlockPool>(mLinearAllocator,
94 mBlockPoolId++);
95 ASSERT_NE(mLinearPool, nullptr);
96
97 mCompName = unknown_comp;
98 struct StringToName {
99 const char* Name;
100 standardComp CompName;
101 };
102 const StringToName kStringToName[] = {
103 {"xaac", xaac},
104 {"mp3", mp3},
105 {"amrnb", amrnb},
106 {"amrwb", amrwb},
107 {"aac", aac},
108 {"vorbis", vorbis},
109 {"opus", opus},
110 {"pcm", pcm},
111 {"g711.alaw", g711alaw},
112 {"g711.mlaw", g711mlaw},
113 {"gsm", gsm},
114 {"raw", raw},
115 {"flac", flac},
116 };
117 const size_t kNumStringToName =
118 sizeof(kStringToName) / sizeof(kStringToName[0]);
119
120 std::string substring;
121 std::string comp;
122 substring = std::string(gEnv->getComponent());
123 /* TODO: better approach to find the component */
124 /* "c2.android." => 11th position */
125 size_t pos = 11;
126 size_t len = substring.find(".decoder", pos);
127 comp = substring.substr(pos, len - pos);
128
129 for (size_t i = 0; i < kNumStringToName; ++i) {
130 if (!strcasecmp(comp.c_str(), kStringToName[i].Name)) {
131 mCompName = kStringToName[i].CompName;
132 break;
133 }
134 }
135 mEos = false;
136 mFramesReceived = 0;
137 mTimestampUs = 0u;
138 mTimestampDevTest = false;
139 if (mCompName == unknown_comp) mDisableTest = true;
140 if (mDisableTest) std::cout << "[ WARN ] Test Disabled \n";
141 }
142
TearDown()143 virtual void TearDown() override {
144 if (mComponent != nullptr) {
145 if (::testing::Test::HasFatalFailure()) return;
146 mComponent->release();
147 mComponent = nullptr;
148 }
149 Super::TearDown();
150 }
151
152 struct outputMetaData {
153 uint64_t timestampUs;
154 uint32_t rangeLength;
155 };
156 // callback function to process onWorkDone received by Listener
handleWorkDone(std::list<std::unique_ptr<C2Work>> & workItems)157 void handleWorkDone(std::list<std::unique_ptr<C2Work>>& workItems) {
158 for (std::unique_ptr<C2Work>& work : workItems) {
159 if (!work->worklets.empty()) {
160 // For decoder components current timestamp always exceeds
161 // previous timestamp
162 bool codecConfig = ((work->worklets.front()->output.flags &
163 C2FrameData::FLAG_CODEC_CONFIG) != 0);
164 if (!codecConfig &&
165 !work->worklets.front()->output.buffers.empty()) {
166 EXPECT_GE(work->worklets.front()->output.ordinal.timestamp.peeku(),
167 mTimestampUs);
168 mTimestampUs =
169 work->worklets.front()->output.ordinal.timestamp.peeku();
170 uint32_t rangeLength =
171 work->worklets.front()->output.buffers[0]->data()
172 .linearBlocks().front().map().get().capacity();
173 //List of timestamp values and output size to calculate timestamp
174 if (mTimestampDevTest) {
175 outputMetaData meta = {mTimestampUs, rangeLength};
176 oBufferMetaData.push_back(meta);
177 }
178 }
179 bool mCsd = false;
180 workDone(mComponent, work, mFlushedIndices, mQueueLock,
181 mQueueCondition, mWorkQueue, mEos, mCsd,
182 mFramesReceived);
183 (void)mCsd;
184 }
185 }
186 }
187
188 enum standardComp {
189 xaac,
190 mp3,
191 amrnb,
192 amrwb,
193 aac,
194 vorbis,
195 opus,
196 pcm,
197 g711alaw,
198 g711mlaw,
199 gsm,
200 raw,
201 flac,
202 unknown_comp,
203 };
204
205 bool mEos;
206 bool mDisableTest;
207 bool mTimestampDevTest;
208 standardComp mCompName;
209 uint64_t mTimestampUs;
210 uint32_t mFramesReceived;
211 std::list<uint64_t> mFlushedIndices;
212 std::list<uint64_t> mTimestampUslist;
213 ::android::List<outputMetaData> oBufferMetaData;
214
215 C2BlockPool::local_id_t mBlockPoolId;
216 std::shared_ptr<C2BlockPool> mLinearPool;
217 std::shared_ptr<C2Allocator> mLinearAllocator;
218
219 std::mutex mQueueLock;
220 std::condition_variable mQueueCondition;
221 std::list<std::unique_ptr<C2Work>> mWorkQueue;
222
223 std::shared_ptr<android::Codec2Client> mClient;
224 std::shared_ptr<android::Codec2Client::Listener> mListener;
225 std::shared_ptr<android::Codec2Client::Component> mComponent;
226
227 protected:
description(const std::string & description)228 static void description(const std::string& description) {
229 RecordProperty("description", description);
230 }
231 };
232
validateComponent(const std::shared_ptr<android::Codec2Client::Component> & component,Codec2AudioDecHidlTest::standardComp compName,bool & disableTest)233 void validateComponent(
234 const std::shared_ptr<android::Codec2Client::Component>& component,
235 Codec2AudioDecHidlTest::standardComp compName, bool& disableTest) {
236 // Validate its a C2 Component
237 if (component->getName().find("c2") == std::string::npos) {
238 ALOGE("Not a c2 component");
239 disableTest = true;
240 return;
241 }
242
243 // Validate its not an encoder and the component to be tested is audio
244 if (component->getName().find("encoder") != std::string::npos) {
245 ALOGE("Expected Decoder, given Encoder");
246 disableTest = true;
247 return;
248 }
249 std::vector<std::unique_ptr<C2Param>> queried;
250 c2_status_t c2err =
251 component->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE},
252 C2_DONT_BLOCK, &queried);
253 if (c2err != C2_OK && queried.size() == 0) {
254 ALOGE("Query media type failed => %d", c2err);
255 } else {
256 std::string inputDomain =
257 ((C2StreamMediaTypeSetting::input*)queried[0].get())->m.value;
258 if (inputDomain.find("audio/") == std::string::npos) {
259 ALOGE("Expected Audio Component");
260 disableTest = true;
261 return;
262 }
263 }
264
265 // Validates component name
266 if (compName == Codec2AudioDecHidlTest::unknown_comp) {
267 ALOGE("Component InValid");
268 disableTest = true;
269 return;
270 }
271 ALOGV("Component Valid");
272 }
273
274 // Set Default config param.
setupConfigParam(const std::shared_ptr<android::Codec2Client::Component> & component,int32_t * bitStreamInfo)275 void setupConfigParam(
276 const std::shared_ptr<android::Codec2Client::Component>& component,
277 int32_t* bitStreamInfo) {
278 std::vector<std::unique_ptr<C2SettingResult>> failures;
279 C2StreamSampleRateInfo::output sampleRateInfo(0u, bitStreamInfo[0]);
280 C2StreamChannelCountInfo::output channelCountInfo(0u, bitStreamInfo[1]);
281
282 std::vector<C2Param*> configParam{&sampleRateInfo, &channelCountInfo};
283 c2_status_t status =
284 component->config(configParam, C2_DONT_BLOCK, &failures);
285 ASSERT_EQ(failures.size(), 0u);
286 ASSERT_EQ(status, C2_OK);
287 }
288
289 // In decoder components, often the input parameters get updated upon
290 // parsing the header of elementary stream. Client needs to collect this
291 // information and reconfigure
getInputChannelInfo(const std::shared_ptr<android::Codec2Client::Component> & component,Codec2AudioDecHidlTest::standardComp compName,int32_t * bitStreamInfo)292 void getInputChannelInfo(
293 const std::shared_ptr<android::Codec2Client::Component>& component,
294 Codec2AudioDecHidlTest::standardComp compName, int32_t* bitStreamInfo) {
295 // query nSampleRate and nChannels
296 std::initializer_list<C2Param::Index> indices{
297 C2StreamSampleRateInfo::output::PARAM_TYPE,
298 C2StreamChannelCountInfo::output::PARAM_TYPE,
299 };
300 std::vector<std::unique_ptr<C2Param>> inParams;
301 c2_status_t status =
302 component->query({}, indices, C2_DONT_BLOCK, &inParams);
303 if (status != C2_OK && inParams.size() == 0) {
304 ALOGE("Query media type failed => %d", status);
305 ASSERT_TRUE(false);
306 } else {
307 size_t offset = sizeof(C2Param);
308 for (size_t i = 0; i < inParams.size(); ++i) {
309 C2Param* param = inParams[i].get();
310 bitStreamInfo[i] = *(int32_t*)((uint8_t*)param + offset);
311 }
312 switch (compName) {
313 case Codec2AudioDecHidlTest::amrnb: {
314 ASSERT_EQ(bitStreamInfo[0], 8000);
315 ASSERT_EQ(bitStreamInfo[1], 1);
316 break;
317 }
318 case Codec2AudioDecHidlTest::amrwb: {
319 ASSERT_EQ(bitStreamInfo[0], 16000);
320 ASSERT_EQ(bitStreamInfo[1], 1);
321 break;
322 }
323 case Codec2AudioDecHidlTest::gsm: {
324 ASSERT_EQ(bitStreamInfo[0], 8000);
325 break;
326 }
327 default:
328 break;
329 }
330 }
331 }
332
333 // LookUpTable of clips and metadata for component testing
GetURLForComponent(Codec2AudioDecHidlTest::standardComp comp,char * mURL,char * info)334 void GetURLForComponent(Codec2AudioDecHidlTest::standardComp comp, char* mURL,
335 char* info) {
336 struct CompToURL {
337 Codec2AudioDecHidlTest::standardComp comp;
338 const char* mURL;
339 const char* info;
340 };
341 static const CompToURL kCompToURL[] = {
342 {Codec2AudioDecHidlTest::standardComp::xaac,
343 "bbb_aac_stereo_128kbps_48000hz.aac",
344 "bbb_aac_stereo_128kbps_48000hz.info"},
345 {Codec2AudioDecHidlTest::standardComp::mp3,
346 "bbb_mp3_stereo_192kbps_48000hz.mp3",
347 "bbb_mp3_stereo_192kbps_48000hz.info"},
348 {Codec2AudioDecHidlTest::standardComp::aac,
349 "bbb_aac_stereo_128kbps_48000hz.aac",
350 "bbb_aac_stereo_128kbps_48000hz.info"},
351 {Codec2AudioDecHidlTest::standardComp::amrnb,
352 "sine_amrnb_1ch_12kbps_8000hz.amrnb",
353 "sine_amrnb_1ch_12kbps_8000hz.info"},
354 {Codec2AudioDecHidlTest::standardComp::amrwb,
355 "bbb_amrwb_1ch_14kbps_16000hz.amrwb",
356 "bbb_amrwb_1ch_14kbps_16000hz.info"},
357 {Codec2AudioDecHidlTest::standardComp::vorbis,
358 "bbb_vorbis_stereo_128kbps_48000hz.vorbis",
359 "bbb_vorbis_stereo_128kbps_48000hz.info"},
360 {Codec2AudioDecHidlTest::standardComp::opus,
361 "bbb_opus_stereo_128kbps_48000hz.opus",
362 "bbb_opus_stereo_128kbps_48000hz.info"},
363 {Codec2AudioDecHidlTest::standardComp::g711alaw,
364 "bbb_g711alaw_1ch_8khz.raw",
365 "bbb_g711alaw_1ch_8khz.info"},
366 {Codec2AudioDecHidlTest::standardComp::g711mlaw,
367 "bbb_g711mulaw_1ch_8khz.raw",
368 "bbb_g711mulaw_1ch_8khz.info"},
369 {Codec2AudioDecHidlTest::standardComp::gsm,
370 "bbb_gsm_1ch_8khz_13kbps.raw",
371 "bbb_gsm_1ch_8khz_13kbps.info"},
372 {Codec2AudioDecHidlTest::standardComp::raw,
373 "bbb_raw_1ch_8khz_s32le.raw",
374 "bbb_raw_1ch_8khz_s32le.info"},
375 {Codec2AudioDecHidlTest::standardComp::flac,
376 "bbb_flac_stereo_680kbps_48000hz.flac",
377 "bbb_flac_stereo_680kbps_48000hz.info"},
378 };
379
380 for (size_t i = 0; i < sizeof(kCompToURL) / sizeof(kCompToURL[0]); ++i) {
381 if (kCompToURL[i].comp == comp) {
382 strcat(mURL, kCompToURL[i].mURL);
383 strcat(info, kCompToURL[i].info);
384 return;
385 }
386 }
387 }
388
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)389 void decodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& component,
390 std::mutex &queueLock, std::condition_variable& queueCondition,
391 std::list<std::unique_ptr<C2Work>>& workQueue,
392 std::list<uint64_t>& flushedIndices,
393 std::shared_ptr<C2BlockPool>& linearPool,
394 std::ifstream& eleStream,
395 android::Vector<FrameInfo>* Info,
396 int offset, int range, bool signalEOS = true) {
397 typedef std::unique_lock<std::mutex> ULock;
398 int frameID = offset;
399 int maxRetry = 0;
400 while (1) {
401 if (frameID == (int)Info->size() || frameID == (offset + range)) break;
402 uint32_t flags = 0;
403 std::unique_ptr<C2Work> work;
404 // Prepare C2Work
405 while (!work && (maxRetry < MAX_RETRY)) {
406 ULock l(queueLock);
407 if (!workQueue.empty()) {
408 work.swap(workQueue.front());
409 workQueue.pop_front();
410 } else {
411 queueCondition.wait_for(l, TIME_OUT);
412 maxRetry++;
413 }
414 }
415 if (!work && (maxRetry >= MAX_RETRY)) {
416 ASSERT_TRUE(false) << "Wait for generating C2Work exceeded timeout";
417 }
418 int64_t timestamp = (*Info)[frameID].timestamp;
419 if ((*Info)[frameID].flags) flags = 1u << ((*Info)[frameID].flags - 1);
420 if (signalEOS && ((frameID == (int)Info->size() - 1) ||
421 (frameID == (offset + range - 1))))
422 flags |= C2FrameData::FLAG_END_OF_STREAM;
423
424 work->input.flags = (C2FrameData::flags_t)flags;
425 work->input.ordinal.timestamp = timestamp;
426 work->input.ordinal.frameIndex = frameID;
427 {
428 ULock l(queueLock);
429 flushedIndices.emplace_back(frameID);
430 }
431 int size = (*Info)[frameID].bytesCount;
432 char* data = (char*)malloc(size);
433 ASSERT_NE(data, nullptr);
434
435 eleStream.read(data, size);
436 ASSERT_EQ(eleStream.gcount(), size);
437
438 work->input.buffers.clear();
439 if (size) {
440 std::shared_ptr<C2LinearBlock> block;
441 ASSERT_EQ(C2_OK,
442 linearPool->fetchLinearBlock(
443 size, {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE},
444 &block));
445 ASSERT_TRUE(block);
446
447 // Write View
448 C2WriteView view = block->map().get();
449 if (view.error() != C2_OK) {
450 fprintf(stderr, "C2LinearBlock::map() failed : %d", view.error());
451 break;
452 }
453 ASSERT_EQ((size_t)size, view.capacity());
454 ASSERT_EQ(0u, view.offset());
455 ASSERT_EQ((size_t)size, view.size());
456
457 memcpy(view.base(), data, size);
458
459 work->input.buffers.emplace_back(new LinearBuffer(block));
460 free(data);
461 }
462 work->worklets.clear();
463 work->worklets.emplace_back(new C2Worklet);
464
465 std::list<std::unique_ptr<C2Work>> items;
466 items.push_back(std::move(work));
467
468 // DO THE DECODING
469 ASSERT_EQ(component->queue(&items), C2_OK);
470 ALOGV("Frame #%d size = %d queued", frameID, size);
471 frameID++;
472 maxRetry = 0;
473 }
474 }
475
TEST_F(Codec2AudioDecHidlTest,validateCompName)476 TEST_F(Codec2AudioDecHidlTest, validateCompName) {
477 if (mDisableTest) return;
478 ALOGV("Checks if the given component is a valid audio component");
479 validateComponent(mComponent, mCompName, mDisableTest);
480 ASSERT_EQ(mDisableTest, false);
481 }
482
TEST_F(Codec2AudioDecHidlTest,configComp)483 TEST_F(Codec2AudioDecHidlTest, configComp) {
484 description("Tests component specific configuration");
485 if (mDisableTest) return;
486 ASSERT_EQ(mComponent->start(), C2_OK);
487 int32_t bitStreamInfo[2] = {0};
488 ASSERT_NO_FATAL_FAILURE(
489 getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
490 setupConfigParam(mComponent, bitStreamInfo);
491 ASSERT_EQ(mComponent->stop(), C2_OK);
492 }
493
TEST_F(Codec2AudioDecHidlTest,DecodeTest)494 TEST_F(Codec2AudioDecHidlTest, DecodeTest) {
495 description("Decodes input file");
496 if (mDisableTest) return;
497
498 ASSERT_EQ(mComponent->start(), C2_OK);
499 mTimestampDevTest = true;
500 char mURL[512], info[512];
501 std::ifstream eleStream, eleInfo;
502
503 strcpy(mURL, gEnv->getRes().c_str());
504 strcpy(info, gEnv->getRes().c_str());
505 GetURLForComponent(mCompName, mURL, info);
506
507 eleInfo.open(info);
508 ASSERT_EQ(eleInfo.is_open(), true);
509 android::Vector<FrameInfo> Info;
510 int bytesCount = 0;
511 uint32_t flags = 0;
512 uint32_t timestamp = 0;
513 while (1) {
514 if (!(eleInfo >> bytesCount)) break;
515 eleInfo >> flags;
516 eleInfo >> timestamp;
517 bool codecConfig =
518 ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0;
519 if (mTimestampDevTest && !codecConfig)
520 mTimestampUslist.push_back(timestamp);
521 Info.push_back({bytesCount, flags, timestamp});
522 }
523 eleInfo.close();
524 int32_t bitStreamInfo[2] = {0};
525 if (mCompName == raw) {
526 bitStreamInfo[0] = 8000;
527 bitStreamInfo[1] = 1;
528 } else {
529 ASSERT_NO_FATAL_FAILURE(
530 getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
531 }
532 setupConfigParam(mComponent, bitStreamInfo);
533 ALOGV("mURL : %s", mURL);
534 eleStream.open(mURL, std::ifstream::binary);
535 ASSERT_EQ(eleStream.is_open(), true);
536 ASSERT_NO_FATAL_FAILURE(decodeNFrames(
537 mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices,
538 mLinearPool, eleStream, &Info, 0, (int)Info.size()));
539 // blocking call to ensures application to Wait till all the inputs are
540 // consumed
541 ASSERT_NO_FATAL_FAILURE(
542 waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
543 eleStream.close();
544 if (mFramesReceived != Info.size()) {
545 ALOGE("Input buffer count and Output buffer count mismatch");
546 ALOGE("framesReceived : %d inputFrames : %zu", mFramesReceived,
547 Info.size());
548 ASSERT_TRUE(false);
549 }
550 ASSERT_EQ(mEos, true);
551 if (mTimestampDevTest) {
552 uint64_t expTs;
553 uint32_t samplesReceived = 0;
554 // Update SampleRate and ChannelCount
555 ASSERT_NO_FATAL_FAILURE(
556 getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
557 int nSampleRate = bitStreamInfo[0];
558 int nChannels = bitStreamInfo[1];
559 std::list<uint64_t>::iterator itIn = mTimestampUslist.begin();
560 android::List<outputMetaData>::iterator itOut = oBufferMetaData.begin();
561 EXPECT_EQ(*itIn, itOut->timestampUs);
562 expTs = *itIn;
563 while (itOut != oBufferMetaData.end()) {
564 EXPECT_EQ(expTs, itOut->timestampUs);
565 if (expTs != itOut->timestampUs) break;
566 // buffer samples = ((total bytes) / (ac * (bits per sample / 8))
567 samplesReceived += ((itOut->rangeLength) / (nChannels * 2));
568 expTs = samplesReceived * 1000000ll / nSampleRate;
569 itOut++;
570 }
571 itIn = mTimestampUslist.end();
572 --itIn;
573 EXPECT_GT(expTs, *itIn);
574 oBufferMetaData.clear();
575 mTimestampUslist.clear();
576 }
577 ASSERT_EQ(mComponent->stop(), C2_OK);
578 }
579
580 // thumbnail test
TEST_F(Codec2AudioDecHidlTest,ThumbnailTest)581 TEST_F(Codec2AudioDecHidlTest, ThumbnailTest) {
582 description("Test Request for thumbnail");
583 if (mDisableTest) return;
584
585 ASSERT_EQ(mComponent->start(), C2_OK);
586 char mURL[512], info[512];
587 std::ifstream eleStream, eleInfo;
588
589 strcpy(mURL, gEnv->getRes().c_str());
590 strcpy(info, gEnv->getRes().c_str());
591 GetURLForComponent(mCompName, mURL, info);
592
593 eleInfo.open(info);
594 ASSERT_EQ(eleInfo.is_open(), true);
595 android::Vector<FrameInfo> Info;
596 int bytesCount = 0;
597 uint32_t flags = 0;
598 uint32_t timestamp = 0;
599 while (1) {
600 if (!(eleInfo >> bytesCount)) break;
601 eleInfo >> flags;
602 eleInfo >> timestamp;
603 Info.push_back({bytesCount, flags, timestamp});
604 }
605 eleInfo.close();
606 int32_t bitStreamInfo[2] = {0};
607 if (mCompName == raw) {
608 bitStreamInfo[0] = 8000;
609 bitStreamInfo[1] = 1;
610 } else {
611 ASSERT_NO_FATAL_FAILURE(
612 getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
613 }
614 setupConfigParam(mComponent, bitStreamInfo);
615 ALOGV("mURL : %s", mURL);
616
617 // request EOS for thumbnail
618 // signal EOS flag with last frame
619 size_t i = -1;
620 do {
621 i++;
622 flags = 0;
623 if (Info[i].flags) flags = 1u << (Info[i].flags - 1);
624
625 } while (!(flags & SYNC_FRAME));
626 eleStream.open(mURL, std::ifstream::binary);
627 ASSERT_EQ(eleStream.is_open(), true);
628 ASSERT_NO_FATAL_FAILURE(decodeNFrames(
629 mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices,
630 mLinearPool, eleStream, &Info, 0, i + 1));
631 ASSERT_NO_FATAL_FAILURE(
632 waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
633 eleStream.close();
634 EXPECT_GE(mFramesReceived, 1U);
635 ASSERT_EQ(mEos, true);
636 ASSERT_EQ(mComponent->stop(), C2_OK);
637 }
638
TEST_F(Codec2AudioDecHidlTest,EOSTest)639 TEST_F(Codec2AudioDecHidlTest, 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(Codec2AudioDecHidlTest,FlushTest)679 TEST_F(Codec2AudioDecHidlTest, 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 int32_t bitStreamInfo[2] = {0};
706 if (mCompName == raw) {
707 bitStreamInfo[0] = 8000;
708 bitStreamInfo[1] = 1;
709 } else {
710 ASSERT_NO_FATAL_FAILURE(
711 getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
712 }
713 setupConfigParam(mComponent, bitStreamInfo);
714 ALOGV("mURL : %s", mURL);
715 eleStream.open(mURL, std::ifstream::binary);
716 ASSERT_EQ(eleStream.is_open(), true);
717 // Decode 128 frames and flush. here 128 is chosen to ensure there is a key
718 // frame after this so that the below section can be covered for all
719 // components
720 uint32_t numFramesFlushed = 128;
721 ASSERT_NO_FATAL_FAILURE(decodeNFrames(
722 mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices,
723 mLinearPool, eleStream, &Info, 0, numFramesFlushed, false));
724 // flush
725 std::list<std::unique_ptr<C2Work>> flushedWork;
726 c2_status_t err =
727 mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
728 ASSERT_EQ(err, C2_OK);
729 ASSERT_NO_FATAL_FAILURE(
730 waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
731 (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
732 uint64_t frameIndex;
733 {
734 //Update mFlushedIndices based on the index received from flush()
735 ULock l(mQueueLock);
736 for (std::unique_ptr<C2Work>& work : flushedWork) {
737 ASSERT_NE(work, nullptr);
738 frameIndex = work->input.ordinal.frameIndex.peeku();
739 std::list<uint64_t>::iterator frameIndexIt =
740 std::find(mFlushedIndices.begin(), mFlushedIndices.end(),
741 frameIndex);
742 if (!mFlushedIndices.empty() &&
743 (frameIndexIt != mFlushedIndices.end())) {
744 mFlushedIndices.erase(frameIndexIt);
745 work->input.buffers.clear();
746 work->worklets.clear();
747 mWorkQueue.push_back(std::move(work));
748 }
749 }
750 }
751 // Seek to next key frame and start decoding till the end
752 mFlushedIndices.clear();
753 int index = numFramesFlushed;
754 bool keyFrame = false;
755 flags = 0;
756 while (index < (int)Info.size()) {
757 if (Info[index].flags) flags = 1u << (Info[index].flags - 1);
758 if ((flags & SYNC_FRAME) == SYNC_FRAME) {
759 keyFrame = true;
760 break;
761 }
762 flags = 0;
763 eleStream.ignore(Info[index].bytesCount);
764 index++;
765 }
766 if (keyFrame) {
767 ASSERT_NO_FATAL_FAILURE(
768 decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
769 mFlushedIndices, mLinearPool, eleStream, &Info, index,
770 (int)Info.size() - index));
771 }
772 eleStream.close();
773 err =
774 mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
775 ASSERT_EQ(err, C2_OK);
776 ASSERT_NO_FATAL_FAILURE(
777 waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
778 (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
779 {
780 //Update mFlushedIndices based on the index received from flush()
781 ULock l(mQueueLock);
782 for (std::unique_ptr<C2Work>& work : flushedWork) {
783 ASSERT_NE(work, nullptr);
784 frameIndex = work->input.ordinal.frameIndex.peeku();
785 std::list<uint64_t>::iterator frameIndexIt =
786 std::find(mFlushedIndices.begin(), mFlushedIndices.end(),
787 frameIndex);
788 if (!mFlushedIndices.empty() &&
789 (frameIndexIt != mFlushedIndices.end())) {
790 mFlushedIndices.erase(frameIndexIt);
791 work->input.buffers.clear();
792 work->worklets.clear();
793 mWorkQueue.push_back(std::move(work));
794 }
795 }
796 }
797 ASSERT_EQ(mFlushedIndices.empty(), true);
798 ASSERT_EQ(mComponent->stop(), C2_OK);
799 }
800
TEST_F(Codec2AudioDecHidlTest,DecodeTestEmptyBuffersInserted)801 TEST_F(Codec2AudioDecHidlTest, DecodeTestEmptyBuffersInserted) {
802 description("Decode with multiple empty input frames");
803 if (mDisableTest) return;
804
805 ASSERT_EQ(mComponent->start(), C2_OK);
806
807 char mURL[512], info[512];
808 std::ifstream eleStream, eleInfo;
809
810 strcpy(mURL, gEnv->getRes().c_str());
811 strcpy(info, gEnv->getRes().c_str());
812 GetURLForComponent(mCompName, mURL, info);
813
814 eleInfo.open(info);
815 ASSERT_EQ(eleInfo.is_open(), true) << mURL << " - file not found";
816 android::Vector<FrameInfo> Info;
817 int bytesCount = 0;
818 uint32_t frameId = 0;
819 uint32_t flags = 0;
820 uint32_t timestamp = 0;
821 bool codecConfig = false;
822 // This test introduces empty CSD after every 20th frame
823 // and empty input frames at an interval of 5 frames.
824 while (1) {
825 if (!(frameId % 5)) {
826 if (!(frameId % 20)) flags = 32;
827 else flags = 0;
828 bytesCount = 0;
829 } else {
830 if (!(eleInfo >> bytesCount)) break;
831 eleInfo >> flags;
832 eleInfo >> timestamp;
833 codecConfig = flags ?
834 ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0 : 0;
835 }
836 Info.push_back({bytesCount, flags, timestamp});
837 frameId++;
838 }
839 eleInfo.close();
840
841 ALOGV("mURL : %s", mURL);
842 eleStream.open(mURL, std::ifstream::binary);
843 ASSERT_EQ(eleStream.is_open(), true);
844 ASSERT_NO_FATAL_FAILURE(decodeNFrames(
845 mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices,
846 mLinearPool, eleStream, &Info, 0, (int)Info.size()));
847
848 // blocking call to ensures application to Wait till all the inputs are
849 // consumed
850 if (!mEos) {
851 ALOGV("Waiting for input consumption");
852 ASSERT_NO_FATAL_FAILURE(
853 waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
854 }
855
856 eleStream.close();
857 if (mFramesReceived != Info.size()) {
858 ALOGE("Input buffer count and Output buffer count mismatch");
859 ALOGV("framesReceived : %d inputFrames : %zu", mFramesReceived,
860 Info.size());
861 ASSERT_TRUE(false);
862 }
863
864 ASSERT_EQ(mComponent->stop(), C2_OK);
865 }
866
867 } // anonymous namespace
868
main(int argc,char ** argv)869 int main(int argc, char** argv) {
870 gEnv = new ComponentTestEnvironment();
871 ::testing::AddGlobalTestEnvironment(gEnv);
872 ::testing::InitGoogleTest(&argc, argv);
873 gEnv->init(&argc, argv);
874 int status = gEnv->initFromOptions(argc, argv);
875 if (status == 0) {
876 int status = RUN_ALL_TESTS();
877 LOG(INFO) << "C2 Test result = " << status;
878 }
879 return status;
880 }
881