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