• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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