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