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 // Find the component type
121 std::string comp = std::string(gEnv->getComponent());
122 for (size_t i = 0; i < kNumStringToName; ++i) {
123 if (strcasestr(comp.c_str(), kStringToName[i].Name)) {
124 mCompName = kStringToName[i].CompName;
125 break;
126 }
127 }
128 mEos = false;
129 mFramesReceived = 0;
130 mTimestampUs = 0u;
131 mTimestampDevTest = false;
132 if (mCompName == unknown_comp) mDisableTest = true;
133 if (mDisableTest) std::cout << "[ WARN ] Test Disabled \n";
134 }
135
TearDown()136 virtual void TearDown() override {
137 if (mComponent != nullptr) {
138 if (::testing::Test::HasFatalFailure()) return;
139 mComponent->release();
140 mComponent = nullptr;
141 }
142 Super::TearDown();
143 }
144
145 struct outputMetaData {
146 uint64_t timestampUs;
147 uint32_t rangeLength;
148 };
149 // callback function to process onWorkDone received by Listener
handleWorkDone(std::list<std::unique_ptr<C2Work>> & workItems)150 void handleWorkDone(std::list<std::unique_ptr<C2Work>>& workItems) {
151 for (std::unique_ptr<C2Work>& work : workItems) {
152 if (!work->worklets.empty()) {
153 // For decoder components current timestamp always exceeds
154 // previous timestamp
155 bool codecConfig = ((work->worklets.front()->output.flags &
156 C2FrameData::FLAG_CODEC_CONFIG) != 0);
157 if (!codecConfig &&
158 !work->worklets.front()->output.buffers.empty()) {
159 EXPECT_GE(work->worklets.front()->output.ordinal.timestamp.peeku(),
160 mTimestampUs);
161 mTimestampUs =
162 work->worklets.front()->output.ordinal.timestamp.peeku();
163 uint32_t rangeLength =
164 work->worklets.front()->output.buffers[0]->data()
165 .linearBlocks().front().map().get().capacity();
166 //List of timestamp values and output size to calculate timestamp
167 if (mTimestampDevTest) {
168 outputMetaData meta = {mTimestampUs, rangeLength};
169 oBufferMetaData.push_back(meta);
170 }
171 }
172 bool mCsd = false;
173 workDone(mComponent, work, mFlushedIndices, mQueueLock,
174 mQueueCondition, mWorkQueue, mEos, mCsd,
175 mFramesReceived);
176 (void)mCsd;
177 }
178 }
179 }
180
181 enum standardComp {
182 xaac,
183 mp3,
184 amrnb,
185 amrwb,
186 aac,
187 vorbis,
188 opus,
189 pcm,
190 g711alaw,
191 g711mlaw,
192 gsm,
193 raw,
194 flac,
195 unknown_comp,
196 };
197
198 bool mEos;
199 bool mDisableTest;
200 bool mTimestampDevTest;
201 standardComp mCompName;
202 uint64_t mTimestampUs;
203 uint32_t mFramesReceived;
204 std::list<uint64_t> mFlushedIndices;
205 std::list<uint64_t> mTimestampUslist;
206 ::android::List<outputMetaData> oBufferMetaData;
207
208 C2BlockPool::local_id_t mBlockPoolId;
209 std::shared_ptr<C2BlockPool> mLinearPool;
210 std::shared_ptr<C2Allocator> mLinearAllocator;
211
212 std::mutex mQueueLock;
213 std::condition_variable mQueueCondition;
214 std::list<std::unique_ptr<C2Work>> mWorkQueue;
215
216 std::shared_ptr<android::Codec2Client> mClient;
217 std::shared_ptr<android::Codec2Client::Listener> mListener;
218 std::shared_ptr<android::Codec2Client::Component> mComponent;
219
220 protected:
description(const std::string & description)221 static void description(const std::string& description) {
222 RecordProperty("description", description);
223 }
224 };
225
validateComponent(const std::shared_ptr<android::Codec2Client::Component> & component,Codec2AudioDecHidlTest::standardComp compName,bool & disableTest)226 void validateComponent(
227 const std::shared_ptr<android::Codec2Client::Component>& component,
228 Codec2AudioDecHidlTest::standardComp compName, bool& disableTest) {
229 // Validate its a C2 Component
230 if (component->getName().find("c2") == std::string::npos) {
231 ALOGE("Not a c2 component");
232 disableTest = true;
233 return;
234 }
235
236 // Validate its not an encoder and the component to be tested is audio
237 if (component->getName().find("encoder") != std::string::npos) {
238 ALOGE("Expected Decoder, given Encoder");
239 disableTest = true;
240 return;
241 }
242 std::vector<std::unique_ptr<C2Param>> queried;
243 c2_status_t c2err =
244 component->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE},
245 C2_DONT_BLOCK, &queried);
246 if (c2err != C2_OK && queried.size() == 0) {
247 ALOGE("Query media type failed => %d", c2err);
248 } else {
249 std::string inputDomain =
250 ((C2StreamMediaTypeSetting::input*)queried[0].get())->m.value;
251 if (inputDomain.find("audio/") == std::string::npos) {
252 ALOGE("Expected Audio Component");
253 disableTest = true;
254 return;
255 }
256 }
257
258 // Validates component name
259 if (compName == Codec2AudioDecHidlTest::unknown_comp) {
260 ALOGE("Component InValid");
261 disableTest = true;
262 return;
263 }
264 ALOGV("Component Valid");
265 }
266
267 // Set Default config param.
setupConfigParam(const std::shared_ptr<android::Codec2Client::Component> & component,int32_t * bitStreamInfo)268 bool setupConfigParam(
269 const std::shared_ptr<android::Codec2Client::Component>& component,
270 int32_t* bitStreamInfo) {
271 std::vector<std::unique_ptr<C2SettingResult>> failures;
272 C2StreamSampleRateInfo::output sampleRateInfo(0u, bitStreamInfo[0]);
273 C2StreamChannelCountInfo::output channelCountInfo(0u, bitStreamInfo[1]);
274
275 std::vector<C2Param*> configParam{&sampleRateInfo, &channelCountInfo};
276 c2_status_t status =
277 component->config(configParam, C2_DONT_BLOCK, &failures);
278 if (status == C2_OK && failures.size() == 0u) return true;
279 return false;
280 }
281
282 // In decoder components, often the input parameters get updated upon
283 // parsing the header of elementary stream. Client needs to collect this
284 // information and reconfigure
getInputChannelInfo(const std::shared_ptr<android::Codec2Client::Component> & component,Codec2AudioDecHidlTest::standardComp compName,int32_t * bitStreamInfo)285 void getInputChannelInfo(
286 const std::shared_ptr<android::Codec2Client::Component>& component,
287 Codec2AudioDecHidlTest::standardComp compName, int32_t* bitStreamInfo) {
288 // query nSampleRate and nChannels
289 std::initializer_list<C2Param::Index> indices{
290 C2StreamSampleRateInfo::output::PARAM_TYPE,
291 C2StreamChannelCountInfo::output::PARAM_TYPE,
292 };
293 std::vector<std::unique_ptr<C2Param>> inParams;
294 c2_status_t status =
295 component->query({}, indices, C2_DONT_BLOCK, &inParams);
296 if (status != C2_OK && inParams.size() == 0) {
297 ALOGE("Query media type failed => %d", status);
298 ASSERT_TRUE(false);
299 } else {
300 size_t offset = sizeof(C2Param);
301 for (size_t i = 0; i < inParams.size(); ++i) {
302 C2Param* param = inParams[i].get();
303 bitStreamInfo[i] = *(int32_t*)((uint8_t*)param + offset);
304 }
305 switch (compName) {
306 case Codec2AudioDecHidlTest::amrnb: {
307 ASSERT_EQ(bitStreamInfo[0], 8000);
308 ASSERT_EQ(bitStreamInfo[1], 1);
309 break;
310 }
311 case Codec2AudioDecHidlTest::amrwb: {
312 ASSERT_EQ(bitStreamInfo[0], 16000);
313 ASSERT_EQ(bitStreamInfo[1], 1);
314 break;
315 }
316 case Codec2AudioDecHidlTest::gsm: {
317 ASSERT_EQ(bitStreamInfo[0], 8000);
318 break;
319 }
320 default:
321 break;
322 }
323 }
324 }
325
326 // number of elementary streams per component
327 #define STREAM_COUNT 2
328
329 // LookUpTable of clips and metadata for component testing
GetURLForComponent(Codec2AudioDecHidlTest::standardComp comp,char * mURL,char * info,size_t streamIndex=0)330 void GetURLForComponent(Codec2AudioDecHidlTest::standardComp comp, char* mURL,
331 char* info, size_t streamIndex = 0) {
332 struct CompToURL {
333 Codec2AudioDecHidlTest::standardComp comp;
334 const char mURL[STREAM_COUNT][512];
335 const char info[STREAM_COUNT][512];
336 };
337 ASSERT_TRUE(streamIndex < STREAM_COUNT);
338
339 static const CompToURL kCompToURL[] = {
340 {Codec2AudioDecHidlTest::standardComp::xaac,
341 {"bbb_aac_stereo_128kbps_48000hz.aac",
342 "bbb_aac_stereo_128kbps_48000hz.aac"},
343 {"bbb_aac_stereo_128kbps_48000hz.info",
344 "bbb_aac_stereo_128kbps_48000hz_multi_frame.info"}},
345 {Codec2AudioDecHidlTest::standardComp::mp3,
346 {"bbb_mp3_stereo_192kbps_48000hz.mp3",
347 "bbb_mp3_stereo_192kbps_48000hz.mp3"},
348 {"bbb_mp3_stereo_192kbps_48000hz.info",
349 "bbb_mp3_stereo_192kbps_48000hz_multi_frame.info"}},
350 {Codec2AudioDecHidlTest::standardComp::aac,
351 {"bbb_aac_stereo_128kbps_48000hz.aac",
352 "bbb_aac_stereo_128kbps_48000hz.aac"},
353 {"bbb_aac_stereo_128kbps_48000hz.info",
354 "bbb_aac_stereo_128kbps_48000hz_multi_frame.info"}},
355 {Codec2AudioDecHidlTest::standardComp::amrnb,
356 {"sine_amrnb_1ch_12kbps_8000hz.amrnb",
357 "sine_amrnb_1ch_12kbps_8000hz.amrnb"},
358 {"sine_amrnb_1ch_12kbps_8000hz.info",
359 "sine_amrnb_1ch_12kbps_8000hz_multi_frame.info"}},
360 {Codec2AudioDecHidlTest::standardComp::amrwb,
361 {"bbb_amrwb_1ch_14kbps_16000hz.amrwb",
362 "bbb_amrwb_1ch_14kbps_16000hz.amrwb"},
363 {"bbb_amrwb_1ch_14kbps_16000hz.info",
364 "bbb_amrwb_1ch_14kbps_16000hz_multi_frame.info"}},
365 {Codec2AudioDecHidlTest::standardComp::vorbis,
366 {"bbb_vorbis_stereo_128kbps_48000hz.vorbis", ""},
367 {"bbb_vorbis_stereo_128kbps_48000hz.info", ""}},
368 {Codec2AudioDecHidlTest::standardComp::opus,
369 {"bbb_opus_stereo_128kbps_48000hz.opus", ""},
370 {"bbb_opus_stereo_128kbps_48000hz.info", ""}},
371 {Codec2AudioDecHidlTest::standardComp::g711alaw,
372 {"bbb_g711alaw_1ch_8khz.raw", ""},
373 {"bbb_g711alaw_1ch_8khz.info", ""}},
374 {Codec2AudioDecHidlTest::standardComp::g711mlaw,
375 {"bbb_g711mulaw_1ch_8khz.raw", ""},
376 {"bbb_g711mulaw_1ch_8khz.info", ""}},
377 {Codec2AudioDecHidlTest::standardComp::gsm,
378 {"bbb_gsm_1ch_8khz_13kbps.raw", ""},
379 {"bbb_gsm_1ch_8khz_13kbps.info", ""}},
380 {Codec2AudioDecHidlTest::standardComp::raw,
381 {"bbb_raw_1ch_8khz_s32le.raw", ""},
382 {"bbb_raw_1ch_8khz_s32le.info", ""}},
383 {Codec2AudioDecHidlTest::standardComp::flac,
384 {"bbb_flac_stereo_680kbps_48000hz.flac", ""},
385 {"bbb_flac_stereo_680kbps_48000hz.info", ""}},
386 };
387
388 for (size_t i = 0; i < sizeof(kCompToURL) / sizeof(kCompToURL[0]); ++i) {
389 if (kCompToURL[i].comp == comp) {
390 strcat(mURL, kCompToURL[i].mURL[streamIndex]);
391 strcat(info, kCompToURL[i].info[streamIndex]);
392 return;
393 }
394 }
395 }
396
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)397 void decodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& component,
398 std::mutex &queueLock, std::condition_variable& queueCondition,
399 std::list<std::unique_ptr<C2Work>>& workQueue,
400 std::list<uint64_t>& flushedIndices,
401 std::shared_ptr<C2BlockPool>& linearPool,
402 std::ifstream& eleStream,
403 android::Vector<FrameInfo>* Info,
404 int offset, int range, bool signalEOS = true) {
405 typedef std::unique_lock<std::mutex> ULock;
406 int frameID = offset;
407 int maxRetry = 0;
408 while (1) {
409 if (frameID == (int)Info->size() || frameID == (offset + range)) break;
410 uint32_t flags = 0;
411 std::unique_ptr<C2Work> work;
412 // Prepare C2Work
413 while (!work && (maxRetry < MAX_RETRY)) {
414 ULock l(queueLock);
415 if (!workQueue.empty()) {
416 work.swap(workQueue.front());
417 workQueue.pop_front();
418 } else {
419 queueCondition.wait_for(l, TIME_OUT);
420 maxRetry++;
421 }
422 }
423 if (!work && (maxRetry >= MAX_RETRY)) {
424 ASSERT_TRUE(false) << "Wait for generating C2Work exceeded timeout";
425 }
426 int64_t timestamp = (*Info)[frameID].timestamp;
427 if ((*Info)[frameID].flags) flags = 1u << ((*Info)[frameID].flags - 1);
428 if (signalEOS && ((frameID == (int)Info->size() - 1) ||
429 (frameID == (offset + range - 1))))
430 flags |= C2FrameData::FLAG_END_OF_STREAM;
431
432 work->input.flags = (C2FrameData::flags_t)flags;
433 work->input.ordinal.timestamp = timestamp;
434 work->input.ordinal.frameIndex = frameID;
435 {
436 ULock l(queueLock);
437 flushedIndices.emplace_back(frameID);
438 }
439 int size = (*Info)[frameID].bytesCount;
440 char* data = (char*)malloc(size);
441 ASSERT_NE(data, nullptr);
442
443 eleStream.read(data, size);
444 ASSERT_EQ(eleStream.gcount(), size);
445
446 work->input.buffers.clear();
447 if (size) {
448 std::shared_ptr<C2LinearBlock> block;
449 ASSERT_EQ(C2_OK,
450 linearPool->fetchLinearBlock(
451 size, {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE},
452 &block));
453 ASSERT_TRUE(block);
454
455 // Write View
456 C2WriteView view = block->map().get();
457 if (view.error() != C2_OK) {
458 fprintf(stderr, "C2LinearBlock::map() failed : %d", view.error());
459 break;
460 }
461 ASSERT_EQ((size_t)size, view.capacity());
462 ASSERT_EQ(0u, view.offset());
463 ASSERT_EQ((size_t)size, view.size());
464
465 memcpy(view.base(), data, size);
466
467 work->input.buffers.emplace_back(new LinearBuffer(block));
468 free(data);
469 }
470 work->worklets.clear();
471 work->worklets.emplace_back(new C2Worklet);
472
473 std::list<std::unique_ptr<C2Work>> items;
474 items.push_back(std::move(work));
475
476 // DO THE DECODING
477 ASSERT_EQ(component->queue(&items), C2_OK);
478 ALOGV("Frame #%d size = %d queued", frameID, size);
479 frameID++;
480 maxRetry = 0;
481 }
482 }
483
TEST_F(Codec2AudioDecHidlTest,validateCompName)484 TEST_F(Codec2AudioDecHidlTest, validateCompName) {
485 if (mDisableTest) return;
486 ALOGV("Checks if the given component is a valid audio component");
487 validateComponent(mComponent, mCompName, mDisableTest);
488 ASSERT_EQ(mDisableTest, false);
489 }
490
TEST_F(Codec2AudioDecHidlTest,configComp)491 TEST_F(Codec2AudioDecHidlTest, configComp) {
492 description("Tests component specific configuration");
493 if (mDisableTest) return;
494 ASSERT_EQ(mComponent->start(), C2_OK);
495 int32_t bitStreamInfo[2] = {0};
496 ASSERT_NO_FATAL_FAILURE(
497 getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
498 setupConfigParam(mComponent, bitStreamInfo);
499 ASSERT_EQ(mComponent->stop(), C2_OK);
500 }
501
502 class Codec2AudioDecDecodeTest
503 : public Codec2AudioDecHidlTest,
504 public ::testing::WithParamInterface<std::pair<int32_t, bool>> {
505 };
506
TEST_P(Codec2AudioDecDecodeTest,DecodeTest)507 TEST_P(Codec2AudioDecDecodeTest, DecodeTest) {
508 description("Decodes input file");
509 if (mDisableTest) return;
510
511 uint32_t streamIndex = GetParam().first;
512 bool signalEOS = GetParam().second;
513 mTimestampDevTest = true;
514 char mURL[512], info[512];
515 std::ifstream eleStream, eleInfo;
516
517 strcpy(mURL, gEnv->getRes().c_str());
518 strcpy(info, gEnv->getRes().c_str());
519 GetURLForComponent(mCompName, mURL, info, streamIndex);
520 if (!strcmp(mURL, gEnv->getRes().c_str())) {
521 ALOGV("EMPTY INPUT gEnv->getRes().c_str() %s mURL %s ",
522 gEnv->getRes().c_str(), mURL);
523 return;
524 }
525
526 eleInfo.open(info);
527 ASSERT_EQ(eleInfo.is_open(), true);
528 android::Vector<FrameInfo> Info;
529 int bytesCount = 0;
530 uint32_t flags = 0;
531 uint32_t timestamp = 0;
532 while (1) {
533 if (!(eleInfo >> bytesCount)) break;
534 eleInfo >> flags;
535 eleInfo >> timestamp;
536 bool codecConfig =
537 ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0;
538 if (mTimestampDevTest && !codecConfig)
539 mTimestampUslist.push_back(timestamp);
540 Info.push_back({bytesCount, flags, timestamp});
541 }
542 eleInfo.close();
543 // Reset total no of frames received
544 mFramesReceived = 0;
545 mTimestampUs = 0;
546 int32_t bitStreamInfo[2] = {0};
547 if (mCompName == raw) {
548 bitStreamInfo[0] = 8000;
549 bitStreamInfo[1] = 1;
550 } else {
551 ASSERT_NO_FATAL_FAILURE(
552 getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
553 }
554 if (!setupConfigParam(mComponent, bitStreamInfo)) {
555 std::cout << "[ WARN ] Test Skipped \n";
556 return;
557 }
558 ASSERT_EQ(mComponent->start(), C2_OK);
559 ALOGV("mURL : %s", mURL);
560 eleStream.open(mURL, std::ifstream::binary);
561 ASSERT_EQ(eleStream.is_open(), true);
562 ASSERT_NO_FATAL_FAILURE(decodeNFrames(
563 mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices,
564 mLinearPool, eleStream, &Info, 0, (int)Info.size(), signalEOS));
565
566 // If EOS is not sent, sending empty input with EOS flag
567 size_t infoSize = Info.size();
568 if (!signalEOS) {
569 ASSERT_NO_FATAL_FAILURE(
570 waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, 1));
571 ASSERT_NO_FATAL_FAILURE(
572 testInputBuffer(mComponent, mQueueLock, mWorkQueue,
573 C2FrameData::FLAG_END_OF_STREAM, false));
574 infoSize += 1;
575 }
576 // blocking call to ensures application to Wait till all the inputs are
577 // consumed
578 ASSERT_NO_FATAL_FAILURE(
579 waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
580 eleStream.close();
581 if (mFramesReceived != infoSize) {
582 ALOGE("Input buffer count and Output buffer count mismatch");
583 ALOGE("framesReceived : %d inputFrames : %zu", mFramesReceived,
584 infoSize);
585 ASSERT_TRUE(false);
586 }
587 ASSERT_EQ(mEos, true);
588 if (mTimestampDevTest) {
589 uint64_t expTs;
590 uint32_t samplesReceived = 0;
591 // Update SampleRate and ChannelCount
592 ASSERT_NO_FATAL_FAILURE(
593 getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
594 int nSampleRate = bitStreamInfo[0];
595 int nChannels = bitStreamInfo[1];
596 std::list<uint64_t>::iterator itIn = mTimestampUslist.begin();
597 android::List<outputMetaData>::iterator itOut = oBufferMetaData.begin();
598 EXPECT_EQ(*itIn, itOut->timestampUs);
599 expTs = *itIn;
600 while (itOut != oBufferMetaData.end()) {
601 EXPECT_EQ(expTs, itOut->timestampUs);
602 if (expTs != itOut->timestampUs) break;
603 // buffer samples = ((total bytes) / (ac * (bits per sample / 8))
604 samplesReceived += ((itOut->rangeLength) / (nChannels * 2));
605 expTs = samplesReceived * 1000000ll / nSampleRate;
606 itOut++;
607 }
608 itIn = mTimestampUslist.end();
609 --itIn;
610 EXPECT_GT(expTs, *itIn);
611 oBufferMetaData.clear();
612 mTimestampUslist.clear();
613 }
614 ASSERT_EQ(mComponent->stop(), C2_OK);
615 }
616 // DecodeTest with StreamIndex and EOS / No EOS
617 INSTANTIATE_TEST_CASE_P(StreamIndexAndEOS, Codec2AudioDecDecodeTest,
618 ::testing::Values(std::make_pair(0, false),
619 std::make_pair(0, true),
620 std::make_pair(1, false),
621 std::make_pair(1, true)));
622
623 // thumbnail test
TEST_F(Codec2AudioDecHidlTest,ThumbnailTest)624 TEST_F(Codec2AudioDecHidlTest, ThumbnailTest) {
625 description("Test Request for thumbnail");
626 if (mDisableTest) return;
627
628 char mURL[512], info[512];
629 std::ifstream eleStream, eleInfo;
630
631 strcpy(mURL, gEnv->getRes().c_str());
632 strcpy(info, gEnv->getRes().c_str());
633 GetURLForComponent(mCompName, mURL, info);
634
635 eleInfo.open(info);
636 ASSERT_EQ(eleInfo.is_open(), true);
637 android::Vector<FrameInfo> Info;
638 int bytesCount = 0;
639 uint32_t flags = 0;
640 uint32_t timestamp = 0;
641 while (1) {
642 if (!(eleInfo >> bytesCount)) break;
643 eleInfo >> flags;
644 eleInfo >> timestamp;
645 Info.push_back({bytesCount, flags, timestamp});
646 }
647 eleInfo.close();
648 int32_t bitStreamInfo[2] = {0};
649 if (mCompName == raw) {
650 bitStreamInfo[0] = 8000;
651 bitStreamInfo[1] = 1;
652 } else {
653 ASSERT_NO_FATAL_FAILURE(
654 getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
655 }
656 if (!setupConfigParam(mComponent, bitStreamInfo)) {
657 std::cout << "[ WARN ] Test Skipped \n";
658 return;
659 }
660 ASSERT_EQ(mComponent->start(), C2_OK);
661 ALOGV("mURL : %s", mURL);
662
663 // request EOS for thumbnail
664 // signal EOS flag with last frame
665 size_t i = -1;
666 do {
667 i++;
668 flags = 0;
669 if (Info[i].flags) flags = 1u << (Info[i].flags - 1);
670
671 } while (!(flags & SYNC_FRAME));
672 eleStream.open(mURL, std::ifstream::binary);
673 ASSERT_EQ(eleStream.is_open(), true);
674 ASSERT_NO_FATAL_FAILURE(decodeNFrames(
675 mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices,
676 mLinearPool, eleStream, &Info, 0, i + 1));
677 ASSERT_NO_FATAL_FAILURE(
678 waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
679 eleStream.close();
680 EXPECT_GE(mFramesReceived, 1U);
681 ASSERT_EQ(mEos, true);
682 ASSERT_EQ(mComponent->stop(), C2_OK);
683 }
684
TEST_F(Codec2AudioDecHidlTest,EOSTest)685 TEST_F(Codec2AudioDecHidlTest, EOSTest) {
686 description("Test empty input buffer with EOS flag");
687 if (mDisableTest) return;
688 typedef std::unique_lock<std::mutex> ULock;
689 ASSERT_EQ(mComponent->start(), C2_OK);
690 std::unique_ptr<C2Work> work;
691 // Prepare C2Work
692 {
693 ULock l(mQueueLock);
694 if (!mWorkQueue.empty()) {
695 work.swap(mWorkQueue.front());
696 mWorkQueue.pop_front();
697 } else {
698 ASSERT_TRUE(false) << "mWorkQueue Empty at the start of test";
699 }
700 }
701 ASSERT_NE(work, nullptr);
702
703 work->input.flags = (C2FrameData::flags_t)C2FrameData::FLAG_END_OF_STREAM;
704 work->input.ordinal.timestamp = 0;
705 work->input.ordinal.frameIndex = 0;
706 work->input.buffers.clear();
707 work->worklets.clear();
708 work->worklets.emplace_back(new C2Worklet);
709
710 std::list<std::unique_ptr<C2Work>> items;
711 items.push_back(std::move(work));
712 ASSERT_EQ(mComponent->queue(&items), C2_OK);
713
714 {
715 ULock l(mQueueLock);
716 if (mWorkQueue.size() != MAX_INPUT_BUFFERS) {
717 mQueueCondition.wait_for(l, TIME_OUT);
718 }
719 }
720 ASSERT_EQ(mEos, true);
721 ASSERT_EQ(mWorkQueue.size(), (size_t)MAX_INPUT_BUFFERS);
722 ASSERT_EQ(mComponent->stop(), C2_OK);
723 }
724
TEST_F(Codec2AudioDecHidlTest,FlushTest)725 TEST_F(Codec2AudioDecHidlTest, FlushTest) {
726 description("Tests Flush calls");
727 if (mDisableTest) return;
728 typedef std::unique_lock<std::mutex> ULock;
729 char mURL[512], info[512];
730 std::ifstream eleStream, eleInfo;
731
732 strcpy(mURL, gEnv->getRes().c_str());
733 strcpy(info, gEnv->getRes().c_str());
734 GetURLForComponent(mCompName, mURL, info);
735
736 eleInfo.open(info);
737 ASSERT_EQ(eleInfo.is_open(), true);
738 android::Vector<FrameInfo> Info;
739 int bytesCount = 0;
740 uint32_t flags = 0;
741 uint32_t timestamp = 0;
742 mFlushedIndices.clear();
743 while (1) {
744 if (!(eleInfo >> bytesCount)) break;
745 eleInfo >> flags;
746 eleInfo >> timestamp;
747 Info.push_back({bytesCount, flags, timestamp});
748 }
749 eleInfo.close();
750 int32_t bitStreamInfo[2] = {0};
751 if (mCompName == raw) {
752 bitStreamInfo[0] = 8000;
753 bitStreamInfo[1] = 1;
754 } else {
755 ASSERT_NO_FATAL_FAILURE(
756 getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
757 }
758 if (!setupConfigParam(mComponent, bitStreamInfo)) {
759 std::cout << "[ WARN ] Test Skipped \n";
760 return;
761 }
762 ASSERT_EQ(mComponent->start(), C2_OK);
763 ALOGV("mURL : %s", mURL);
764 eleStream.open(mURL, std::ifstream::binary);
765 ASSERT_EQ(eleStream.is_open(), true);
766 // Decode 128 frames and flush. here 128 is chosen to ensure there is a key
767 // frame after this so that the below section can be covered for all
768 // components
769 uint32_t numFramesFlushed = 128;
770 ASSERT_NO_FATAL_FAILURE(decodeNFrames(
771 mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices,
772 mLinearPool, eleStream, &Info, 0, numFramesFlushed, false));
773 // flush
774 std::list<std::unique_ptr<C2Work>> flushedWork;
775 c2_status_t err =
776 mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
777 ASSERT_EQ(err, C2_OK);
778 ASSERT_NO_FATAL_FAILURE(
779 waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
780 (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
781 uint64_t frameIndex;
782 {
783 //Update mFlushedIndices based on the index received from flush()
784 ULock l(mQueueLock);
785 for (std::unique_ptr<C2Work>& work : flushedWork) {
786 ASSERT_NE(work, nullptr);
787 frameIndex = work->input.ordinal.frameIndex.peeku();
788 std::list<uint64_t>::iterator frameIndexIt =
789 std::find(mFlushedIndices.begin(), mFlushedIndices.end(),
790 frameIndex);
791 if (!mFlushedIndices.empty() &&
792 (frameIndexIt != mFlushedIndices.end())) {
793 mFlushedIndices.erase(frameIndexIt);
794 work->input.buffers.clear();
795 work->worklets.clear();
796 mWorkQueue.push_back(std::move(work));
797 }
798 }
799 }
800 // Seek to next key frame and start decoding till the end
801 mFlushedIndices.clear();
802 int index = numFramesFlushed;
803 bool keyFrame = false;
804 flags = 0;
805 while (index < (int)Info.size()) {
806 if (Info[index].flags) flags = 1u << (Info[index].flags - 1);
807 if ((flags & SYNC_FRAME) == SYNC_FRAME) {
808 keyFrame = true;
809 break;
810 }
811 flags = 0;
812 eleStream.ignore(Info[index].bytesCount);
813 index++;
814 }
815 if (keyFrame) {
816 ASSERT_NO_FATAL_FAILURE(
817 decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
818 mFlushedIndices, mLinearPool, eleStream, &Info, index,
819 (int)Info.size() - index));
820 }
821 eleStream.close();
822 err =
823 mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
824 ASSERT_EQ(err, C2_OK);
825 ASSERT_NO_FATAL_FAILURE(
826 waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
827 (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
828 {
829 //Update mFlushedIndices based on the index received from flush()
830 ULock l(mQueueLock);
831 for (std::unique_ptr<C2Work>& work : flushedWork) {
832 ASSERT_NE(work, nullptr);
833 frameIndex = work->input.ordinal.frameIndex.peeku();
834 std::list<uint64_t>::iterator frameIndexIt =
835 std::find(mFlushedIndices.begin(), mFlushedIndices.end(),
836 frameIndex);
837 if (!mFlushedIndices.empty() &&
838 (frameIndexIt != mFlushedIndices.end())) {
839 mFlushedIndices.erase(frameIndexIt);
840 work->input.buffers.clear();
841 work->worklets.clear();
842 mWorkQueue.push_back(std::move(work));
843 }
844 }
845 }
846 ASSERT_EQ(mFlushedIndices.empty(), true);
847 ASSERT_EQ(mComponent->stop(), C2_OK);
848 }
849
TEST_F(Codec2AudioDecHidlTest,DecodeTestEmptyBuffersInserted)850 TEST_F(Codec2AudioDecHidlTest, DecodeTestEmptyBuffersInserted) {
851 description("Decode with multiple empty input frames");
852 if (mDisableTest) return;
853
854 char mURL[512], info[512];
855 std::ifstream eleStream, eleInfo;
856
857 strcpy(mURL, gEnv->getRes().c_str());
858 strcpy(info, gEnv->getRes().c_str());
859 GetURLForComponent(mCompName, mURL, info);
860
861 eleInfo.open(info);
862 ASSERT_EQ(eleInfo.is_open(), true) << mURL << " - file not found";
863 android::Vector<FrameInfo> Info;
864 int bytesCount = 0;
865 uint32_t frameId = 0;
866 uint32_t flags = 0;
867 uint32_t timestamp = 0;
868 bool codecConfig = false;
869 // This test introduces empty CSD after every 20th frame
870 // and empty input frames at an interval of 5 frames.
871 while (1) {
872 if (!(frameId % 5)) {
873 if (!(frameId % 20)) flags = 32;
874 else flags = 0;
875 bytesCount = 0;
876 } else {
877 if (!(eleInfo >> bytesCount)) break;
878 eleInfo >> flags;
879 eleInfo >> timestamp;
880 codecConfig = flags ?
881 ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0 : 0;
882 }
883 Info.push_back({bytesCount, flags, timestamp});
884 frameId++;
885 }
886 eleInfo.close();
887 int32_t bitStreamInfo[2] = {0};
888 if (mCompName == raw) {
889 bitStreamInfo[0] = 8000;
890 bitStreamInfo[1] = 1;
891 } else {
892 ASSERT_NO_FATAL_FAILURE(
893 getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
894 }
895 if (!setupConfigParam(mComponent, bitStreamInfo)) {
896 std::cout << "[ WARN ] Test Skipped \n";
897 return;
898 }
899 ASSERT_EQ(mComponent->start(), C2_OK);
900 ALOGV("mURL : %s", mURL);
901 eleStream.open(mURL, std::ifstream::binary);
902 ASSERT_EQ(eleStream.is_open(), true);
903 ASSERT_NO_FATAL_FAILURE(decodeNFrames(
904 mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices,
905 mLinearPool, eleStream, &Info, 0, (int)Info.size()));
906
907 // blocking call to ensures application to Wait till all the inputs are
908 // consumed
909 if (!mEos) {
910 ALOGV("Waiting for input consumption");
911 ASSERT_NO_FATAL_FAILURE(
912 waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
913 }
914
915 eleStream.close();
916 if (mFramesReceived != Info.size()) {
917 ALOGE("Input buffer count and Output buffer count mismatch");
918 ALOGV("framesReceived : %d inputFrames : %zu", mFramesReceived,
919 Info.size());
920 ASSERT_TRUE(false);
921 }
922
923 ASSERT_EQ(mComponent->stop(), C2_OK);
924 }
925
926 } // anonymous namespace
927
main(int argc,char ** argv)928 int main(int argc, char** argv) {
929 gEnv = new ComponentTestEnvironment();
930 ::testing::AddGlobalTestEnvironment(gEnv);
931 ::testing::InitGoogleTest(&argc, argv);
932 gEnv->init(&argc, argv);
933 int status = gEnv->initFromOptions(argc, argv);
934 if (status == 0) {
935 int status = RUN_ALL_TESTS();
936 LOG(INFO) << "C2 Test result = " << status;
937 }
938 return status;
939 }
940