• 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_enc_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 class GraphicBuffer : public C2Buffer {
39 public:
GraphicBuffer(const std::shared_ptr<C2GraphicBlock> & block)40   explicit GraphicBuffer(const std::shared_ptr<C2GraphicBlock> &block)
41       : C2Buffer({block->share(C2Rect(block->width(), block->height()),
42                                ::C2Fence())}) {}
43 };
44 
45 static ComponentTestEnvironment* gEnv = nullptr;
46 
47 namespace {
48 
49 class Codec2VideoEncHidlTest : public ::testing::VtsHalHidlTargetTestBase {
50    private:
51     typedef ::testing::VtsHalHidlTargetTestBase Super;
52 
53    public:
getTestCaseInfo() const54     ::std::string getTestCaseInfo() const override {
55         return ::std::string() +
56                 "Component: " + gEnv->getComponent().c_str() + " | " +
57                 "Instance: " + gEnv->getInstance().c_str() + " | " +
58                 "Res: " + gEnv->getRes().c_str();
59     }
60 
61     // google.codec2 Video test setup
SetUp()62     virtual void SetUp() override {
63         Super::SetUp();
64         mDisableTest = false;
65         ALOGV("Codec2VideoEncHidlTest SetUp");
66         mClient = android::Codec2Client::CreateFromService(
67             gEnv->getInstance().c_str());
68         ASSERT_NE(mClient, nullptr);
69         mListener.reset(new CodecListener(
70             [this](std::list<std::unique_ptr<C2Work>>& workItems) {
71                 handleWorkDone(workItems);
72             }));
73         ASSERT_NE(mListener, nullptr);
74         for (int i = 0; i < MAX_INPUT_BUFFERS; ++i) {
75             mWorkQueue.emplace_back(new C2Work);
76         }
77         mClient->createComponent(gEnv->getComponent().c_str(), mListener,
78                                  &mComponent);
79         ASSERT_NE(mComponent, nullptr);
80 
81         std::shared_ptr<C2AllocatorStore> store =
82             android::GetCodec2PlatformAllocatorStore();
83         CHECK_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_GRAPHIC,
84                                        &mGraphicAllocator),
85                  C2_OK);
86         mGraphicPool = std::make_shared<C2PooledBlockPool>(mGraphicAllocator,
87                                                            mBlockPoolId++);
88         ASSERT_NE(mGraphicPool, nullptr);
89 
90         mCompName = unknown_comp;
91         struct StringToName {
92             const char* Name;
93             standardComp CompName;
94         };
95 
96         const StringToName kStringToName[] = {
97             {"h263", h263}, {"avc", avc}, {"mpeg4", mpeg4},
98             {"hevc", hevc}, {"vp8", vp8}, {"vp9", vp9},
99         };
100 
101         const size_t kNumStringToName =
102             sizeof(kStringToName) / sizeof(kStringToName[0]);
103 
104         // Find the component type
105         std::string comp = std::string(gEnv->getComponent());
106         for (size_t i = 0; i < kNumStringToName; ++i) {
107             if (strcasestr(comp.c_str(), kStringToName[i].Name)) {
108                 mCompName = kStringToName[i].CompName;
109                 break;
110             }
111         }
112         mEos = false;
113         mCsd = false;
114         mFramesReceived = 0;
115         mFailedWorkReceived = 0;
116         mTimestampUs = 0u;
117         mTimestampDevTest = false;
118         if (mCompName == unknown_comp) mDisableTest = true;
119         if (mDisableTest) std::cout << "[   WARN   ] Test Disabled \n";
120     }
121 
TearDown()122     virtual void TearDown() override {
123         if (mComponent != nullptr) {
124             if (::testing::Test::HasFatalFailure()) return;
125             mComponent->release();
126             mComponent = nullptr;
127         }
128         Super::TearDown();
129     }
130 
131     bool setupConfigParam(int32_t nWidth, int32_t nHeight);
132 
133     // callback function to process onWorkDone received by Listener
handleWorkDone(std::list<std::unique_ptr<C2Work>> & workItems)134     void handleWorkDone(std::list<std::unique_ptr<C2Work>>& workItems) {
135         for (std::unique_ptr<C2Work>& work : workItems) {
136             if (!work->worklets.empty()) {
137                 // For encoder components current timestamp always exceeds
138                 // previous timestamp
139                 typedef std::unique_lock<std::mutex> ULock;
140                 if (!mTimestampUslist.empty()) {
141                     EXPECT_GE((work->worklets.front()
142                                    ->output.ordinal.timestamp.peeku()),
143                               mTimestampUs);
144                     mTimestampUs = work->worklets.front()
145                                        ->output.ordinal.timestamp.peeku();
146                     // Currently this lock is redundant as no mTimestampUslist is only initialized
147                     // before queuing any work to component. Once AdaptiveTest is added similar to
148                     // the one in video decoders, this is needed.
149                     ULock l(mQueueLock);
150 
151                     if (mTimestampDevTest) {
152                         bool tsHit = false;
153                         std::list<uint64_t>::iterator it =
154                             mTimestampUslist.begin();
155                         while (it != mTimestampUslist.end()) {
156                             if (*it == mTimestampUs) {
157                                 mTimestampUslist.erase(it);
158                                 tsHit = true;
159                                 break;
160                             }
161                             it++;
162                         }
163                         if (tsHit == false) {
164                             if (mTimestampUslist.empty() == false) {
165                                 EXPECT_EQ(tsHit, true)
166                                     << "TimeStamp not recognized";
167                             } else {
168                                 std::cout
169                                     << "[   INFO   ] Received non-zero "
170                                        "output / TimeStamp not recognized \n";
171                             }
172                         }
173                     }
174                 }
175 
176                 if (work->result != C2_OK) mFailedWorkReceived++;
177                 workDone(mComponent, work, mFlushedIndices, mQueueLock,
178                          mQueueCondition, mWorkQueue, mEos, mCsd,
179                          mFramesReceived);
180             }
181         }
182     }
183 
184     enum standardComp {
185         h263,
186         avc,
187         mpeg4,
188         hevc,
189         vp8,
190         vp9,
191         unknown_comp,
192     };
193 
194     bool mEos;
195     bool mCsd;
196     bool mDisableTest;
197     bool mConfig;
198     bool mTimestampDevTest;
199     standardComp mCompName;
200     uint32_t mFramesReceived;
201     uint32_t mFailedWorkReceived;
202     uint64_t mTimestampUs;
203 
204     std::list<uint64_t> mTimestampUslist;
205     std::list<uint64_t> mFlushedIndices;
206 
207     C2BlockPool::local_id_t mBlockPoolId;
208     std::shared_ptr<C2BlockPool> mGraphicPool;
209     std::shared_ptr<C2Allocator> mGraphicAllocator;
210 
211     std::mutex mQueueLock;
212     std::condition_variable mQueueCondition;
213     std::list<std::unique_ptr<C2Work>> mWorkQueue;
214 
215     std::shared_ptr<android::Codec2Client> mClient;
216     std::shared_ptr<android::Codec2Client::Listener> mListener;
217     std::shared_ptr<android::Codec2Client::Component> mComponent;
218 
219    protected:
description(const std::string & description)220     static void description(const std::string& description) {
221         RecordProperty("description", description);
222     }
223 };
224 
validateComponent(const std::shared_ptr<android::Codec2Client::Component> & component,Codec2VideoEncHidlTest::standardComp compName,bool & disableTest)225 void validateComponent(
226     const std::shared_ptr<android::Codec2Client::Component>& component,
227     Codec2VideoEncHidlTest::standardComp compName, bool& disableTest) {
228     // Validate its a C2 Component
229     if (component->getName().find("c2") == std::string::npos) {
230         ALOGE("Not a c2 component");
231         disableTest = true;
232         return;
233     }
234 
235     // Validate its not an encoder and the component to be tested is video
236     if (component->getName().find("decoder") != std::string::npos) {
237         ALOGE("Expected Encoder, given Decoder");
238         disableTest = true;
239         return;
240     }
241     std::vector<std::unique_ptr<C2Param>> queried;
242     c2_status_t c2err =
243         component->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE},
244                          C2_DONT_BLOCK, &queried);
245     if (c2err != C2_OK && queried.size() == 0) {
246         ALOGE("Query media type failed => %d", c2err);
247     } else {
248         std::string inputDomain =
249             ((C2StreamMediaTypeSetting::input*)queried[0].get())->m.value;
250         if (inputDomain.find("video/") == std::string::npos) {
251             ALOGE("Expected Video Component");
252             disableTest = true;
253             return;
254         }
255     }
256 
257     // Validates component name
258     if (compName == Codec2VideoEncHidlTest::unknown_comp) {
259         ALOGE("Component InValid");
260         disableTest = true;
261         return;
262     }
263     ALOGV("Component Valid");
264 }
265 
266 // Set Default config param.
setupConfigParam(int32_t nWidth,int32_t nHeight)267 bool Codec2VideoEncHidlTest::setupConfigParam(int32_t nWidth, int32_t nHeight) {
268     std::vector<std::unique_ptr<C2SettingResult>> failures;
269     C2StreamPictureSizeInfo::input inputSize(0u, nWidth, nHeight);
270     std::vector<C2Param*> configParam{&inputSize};
271     c2_status_t status =
272         mComponent->config(configParam, C2_DONT_BLOCK, &failures);
273     if (status == C2_OK && failures.size() == 0u) return true;
274     return false;
275 }
276 
277 // LookUpTable of clips for component testing
GetURLForComponent(char * URL)278 void GetURLForComponent(char* URL) {
279     strcat(URL, "bbb_352x288_420p_30fps_32frames.yuv");
280 }
281 
encodeNFrames(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> & graphicPool,std::ifstream & eleStream,bool & disableTest,uint32_t frameID,uint32_t nFrames,uint32_t nWidth,int32_t nHeight,bool flushed=false,bool signalEOS=true)282 void encodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& component,
283                    std::mutex &queueLock, std::condition_variable& queueCondition,
284                    std::list<std::unique_ptr<C2Work>>& workQueue,
285                    std::list<uint64_t>& flushedIndices,
286                    std::shared_ptr<C2BlockPool>& graphicPool,
287                    std::ifstream& eleStream, bool& disableTest,
288                    uint32_t frameID, uint32_t nFrames, uint32_t nWidth,
289                    int32_t nHeight, bool flushed = false, bool signalEOS = true) {
290     typedef std::unique_lock<std::mutex> ULock;
291 
292     uint32_t maxRetry = 0;
293     int bytesCount = nWidth * nHeight * 3 >> 1;
294     int32_t timestampIncr = ENCODER_TIMESTAMP_INCREMENT;
295     uint64_t timestamp = 0;
296     c2_status_t err = C2_OK;
297     while (1) {
298         if (nFrames == 0) break;
299         uint32_t flags = 0;
300         std::unique_ptr<C2Work> work;
301         // Prepare C2Work
302         while (!work && (maxRetry < MAX_RETRY)) {
303             ULock l(queueLock);
304             if (!workQueue.empty()) {
305                 work.swap(workQueue.front());
306                 workQueue.pop_front();
307             } else {
308                 queueCondition.wait_for(l, TIME_OUT);
309                 maxRetry++;
310             }
311         }
312         if (!work && (maxRetry >= MAX_RETRY)) {
313             ASSERT_TRUE(false) << "Wait for generating C2Work exceeded timeout";
314         }
315         if (signalEOS && (nFrames == 1))
316             flags |= C2FrameData::FLAG_END_OF_STREAM;
317         if (flushed) {
318             flags |= SYNC_FRAME;
319             flushed = false;
320         }
321 
322         work->input.flags = (C2FrameData::flags_t)flags;
323         work->input.ordinal.timestamp = timestamp;
324         work->input.ordinal.frameIndex = frameID;
325         {
326             ULock l(queueLock);
327             flushedIndices.emplace_back(frameID);
328         }
329         char* data = (char*)malloc(bytesCount);
330         ASSERT_NE(data, nullptr);
331         memset(data, 0, bytesCount);
332         if (eleStream.is_open()) {
333             eleStream.read(data, bytesCount);
334             ASSERT_EQ(eleStream.gcount(), bytesCount);
335         }
336         std::shared_ptr<C2GraphicBlock> block;
337         err = graphicPool->fetchGraphicBlock(
338                 nWidth, nHeight, HAL_PIXEL_FORMAT_YV12,
339                 {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}, &block);
340         if (err != C2_OK) {
341             fprintf(stderr, "fetchGraphicBlock failed : %d\n", err);
342             disableTest = true;
343             break;
344         }
345 
346         ASSERT_TRUE(block);
347         // Graphic View
348         C2GraphicView view = block->map().get();
349         if (view.error() != C2_OK) {
350             fprintf(stderr, "C2GraphicBlock::map() failed : %d", view.error());
351             disableTest = true;
352             break;
353         }
354 
355         uint8_t* pY = view.data()[C2PlanarLayout::PLANE_Y];
356         uint8_t* pU = view.data()[C2PlanarLayout::PLANE_U];
357         uint8_t* pV = view.data()[C2PlanarLayout::PLANE_V];
358 
359         memcpy(pY, data, nWidth * nHeight);
360         memcpy(pU, data + nWidth * nHeight, (nWidth * nHeight >> 2));
361         memcpy(pV, data + (nWidth * nHeight * 5 >> 2), nWidth * nHeight >> 2);
362 
363         work->input.buffers.clear();
364         work->input.buffers.emplace_back(new GraphicBuffer(block));
365         work->worklets.clear();
366         work->worklets.emplace_back(new C2Worklet);
367         free(data);
368 
369         std::list<std::unique_ptr<C2Work>> items;
370         items.push_back(std::move(work));
371 
372         // DO THE ENCODING
373         ASSERT_EQ(component->queue(&items), C2_OK);
374         ALOGV("Frame #%d size = %d queued", frameID, bytesCount);
375         nFrames--;
376         timestamp += timestampIncr;
377         frameID++;
378         maxRetry = 0;
379     }
380 }
381 
TEST_F(Codec2VideoEncHidlTest,validateCompName)382 TEST_F(Codec2VideoEncHidlTest, validateCompName) {
383     if (mDisableTest) return;
384     ALOGV("Checks if the given component is a valid video component");
385     validateComponent(mComponent, mCompName, mDisableTest);
386     ASSERT_EQ(mDisableTest, false);
387 }
388 
389 class Codec2VideoEncEncodeTest : public Codec2VideoEncHidlTest,
390                                  public ::testing::WithParamInterface<bool> {
391 };
392 
TEST_P(Codec2VideoEncEncodeTest,EncodeTest)393 TEST_P(Codec2VideoEncEncodeTest, EncodeTest) {
394     description("Encodes input file");
395     if (mDisableTest) return;
396 
397     char mURL[512];
398     int32_t nWidth = ENC_DEFAULT_FRAME_WIDTH;
399     int32_t nHeight = ENC_DEFAULT_FRAME_HEIGHT;
400     bool signalEOS = GetParam();
401 
402     strcpy(mURL, gEnv->getRes().c_str());
403     GetURLForComponent(mURL);
404 
405     std::ifstream eleStream;
406     eleStream.open(mURL, std::ifstream::binary);
407     ASSERT_EQ(eleStream.is_open(), true) << mURL << " file not found";
408     ALOGV("mURL : %s", mURL);
409 
410     mTimestampUs = 0;
411     mTimestampDevTest = true;
412     mFlushedIndices.clear();
413     mTimestampUslist.clear();
414     uint32_t inputFrames = ENC_NUM_FRAMES;
415     uint32_t timestamp = 0;
416     // Add input timestamp to timestampUslist
417     while (inputFrames) {
418         if (mTimestampDevTest) mTimestampUslist.push_back(timestamp);
419         timestamp += ENCODER_TIMESTAMP_INCREMENT;
420         inputFrames--;
421     }
422     if (!setupConfigParam(nWidth, nHeight)) {
423         std::cout << "[   WARN   ] Test Skipped \n";
424         return;
425     }
426     ASSERT_EQ(mComponent->start(), C2_OK);
427     ASSERT_NO_FATAL_FAILURE(
428         encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
429                       mFlushedIndices, mGraphicPool, eleStream, mDisableTest,
430                       0, ENC_NUM_FRAMES, nWidth, nHeight, false, signalEOS));
431     // mDisableTest will be set if buffer was not fetched properly.
432     // This may happen when resolution is not proper but config suceeded
433     // In this cases, we skip encoding the input stream
434     if (mDisableTest) {
435         std::cout << "[   WARN   ] Test Disabled \n";
436         ASSERT_EQ(mComponent->stop(), C2_OK);
437         return;
438     }
439 
440     // If EOS is not sent, sending empty input with EOS flag
441     inputFrames = ENC_NUM_FRAMES;
442     if (!signalEOS) {
443         ASSERT_NO_FATAL_FAILURE(
444             waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, 1));
445         ASSERT_NO_FATAL_FAILURE(
446             testInputBuffer(mComponent, mQueueLock, mWorkQueue,
447                             C2FrameData::FLAG_END_OF_STREAM, false));
448         inputFrames += 1;
449     }
450 
451     // blocking call to ensures application to Wait till all the inputs are
452     // consumed
453     ALOGD("Waiting for input consumption");
454     ASSERT_NO_FATAL_FAILURE(
455         waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
456 
457     eleStream.close();
458     if (mFramesReceived != inputFrames) {
459         ALOGE("Input buffer count and Output buffer count mismatch");
460         ALOGE("framesReceived : %d inputFrames : %d", mFramesReceived,
461               inputFrames);
462         ASSERT_TRUE(false);
463     }
464 
465     if (!mCsd && (mCompName != vp8 && mCompName != vp9)) {
466         ASSERT_TRUE(false) << "CSD Buffer not received";
467     }
468 
469     if (mCsd && (mCompName == vp8 || mCompName == vp9)) {
470         ASSERT_TRUE(false) << "CSD Buffer not expected";
471     }
472 
473     if (mTimestampDevTest) EXPECT_EQ(mTimestampUslist.empty(), true);
474     ASSERT_EQ(mComponent->stop(), C2_OK);
475 }
476 
477 // EncodeTest with EOS / No EOS
478 INSTANTIATE_TEST_CASE_P(EncodeTestwithEOS, Codec2VideoEncEncodeTest,
479                         ::testing::Values(true, false));
480 
TEST_F(Codec2VideoEncHidlTest,EOSTest)481 TEST_F(Codec2VideoEncHidlTest, EOSTest) {
482     description("Test empty input buffer with EOS flag");
483     if (mDisableTest) return;
484     ASSERT_EQ(mComponent->start(), C2_OK);
485 
486     typedef std::unique_lock<std::mutex> ULock;
487     std::unique_ptr<C2Work> work;
488     {
489         ULock l(mQueueLock);
490         if (!mWorkQueue.empty()) {
491             work.swap(mWorkQueue.front());
492             mWorkQueue.pop_front();
493         } else {
494             ALOGE("mWorkQueue Empty is not expected at the start of the test");
495             ASSERT_TRUE(false);
496         }
497     }
498     ASSERT_NE(work, nullptr);
499     work->input.flags = (C2FrameData::flags_t)C2FrameData::FLAG_END_OF_STREAM;
500     work->input.ordinal.timestamp = 0;
501     work->input.ordinal.frameIndex = 0;
502     work->input.buffers.clear();
503     work->worklets.clear();
504     work->worklets.emplace_back(new C2Worklet);
505 
506     std::list<std::unique_ptr<C2Work>> items;
507     items.push_back(std::move(work));
508     ASSERT_EQ(mComponent->queue(&items), C2_OK);
509     uint32_t queueSize;
510     {
511         ULock l(mQueueLock);
512         queueSize = mWorkQueue.size();
513         if (queueSize < MAX_INPUT_BUFFERS) {
514             mQueueCondition.wait_for(l, TIME_OUT);
515         }
516     }
517     ASSERT_EQ(mEos, true);
518     ASSERT_EQ(mComponent->stop(), C2_OK);
519 }
520 
TEST_F(Codec2VideoEncHidlTest,FlushTest)521 TEST_F(Codec2VideoEncHidlTest, FlushTest) {
522     description("Test Request for flush");
523     if (mDisableTest) return;
524 
525     typedef std::unique_lock<std::mutex> ULock;
526     char mURL[512];
527     int32_t nWidth = ENC_DEFAULT_FRAME_WIDTH;
528     int32_t nHeight = ENC_DEFAULT_FRAME_HEIGHT;
529     strcpy(mURL, gEnv->getRes().c_str());
530     GetURLForComponent(mURL);
531 
532     if (!setupConfigParam(nWidth, nHeight)) {
533         std::cout << "[   WARN   ] Test Skipped \n";
534         return;
535     }
536     ASSERT_EQ(mComponent->start(), C2_OK);
537 
538     // Setting default configuration
539     mFlushedIndices.clear();
540     std::ifstream eleStream;
541     uint32_t numFramesFlushed = 10;
542     uint32_t numFrames = ENC_NUM_FRAMES;
543     eleStream.open(mURL, std::ifstream::binary);
544     ASSERT_EQ(eleStream.is_open(), true);
545     ALOGV("mURL : %s", mURL);
546     ASSERT_NO_FATAL_FAILURE(
547         encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
548                       mFlushedIndices, mGraphicPool, eleStream, mDisableTest,
549                       0, numFramesFlushed, nWidth, nHeight));
550     // mDisableTest will be set if buffer was not fetched properly.
551     // This may happen when resolution is not proper but config suceeded
552     // In this cases, we skip encoding the input stream
553     if (mDisableTest) {
554         std::cout << "[   WARN   ] Test Disabled \n";
555         ASSERT_EQ(mComponent->stop(), C2_OK);
556         return;
557     }
558 
559     std::list<std::unique_ptr<C2Work>> flushedWork;
560     c2_status_t err =
561         mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
562     ASSERT_EQ(err, C2_OK);
563     ASSERT_NO_FATAL_FAILURE(
564         waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
565             (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
566     uint64_t frameIndex;
567     {
568         //Update mFlushedIndices based on the index received from flush()
569         ULock l(mQueueLock);
570         for (std::unique_ptr<C2Work>& work : flushedWork) {
571             ASSERT_NE(work, nullptr);
572             frameIndex = work->input.ordinal.frameIndex.peeku();
573             std::list<uint64_t>::iterator frameIndexIt = std::find(
574                 mFlushedIndices.begin(), mFlushedIndices.end(), frameIndex);
575             if (!mFlushedIndices.empty() &&
576                 (frameIndexIt != mFlushedIndices.end())) {
577                 mFlushedIndices.erase(frameIndexIt);
578                 work->input.buffers.clear();
579                 work->worklets.clear();
580                 mWorkQueue.push_back(std::move(work));
581             }
582         }
583     }
584     mFlushedIndices.clear();
585     ASSERT_NO_FATAL_FAILURE(
586         encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
587                       mFlushedIndices, mGraphicPool, eleStream, mDisableTest,
588                       numFramesFlushed, numFrames - numFramesFlushed,
589                       nWidth, nHeight, true));
590     eleStream.close();
591     // mDisableTest will be set if buffer was not fetched properly.
592     // This may happen when resolution is not proper but config suceeded
593     // In this cases, we skip encoding the input stream
594     if (mDisableTest) {
595         std::cout << "[   WARN   ] Test Disabled \n";
596         ASSERT_EQ(mComponent->stop(), C2_OK);
597         return;
598     }
599 
600     err = mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
601     ASSERT_EQ(err, C2_OK);
602     ASSERT_NO_FATAL_FAILURE(
603         waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
604             (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
605     {
606         //Update mFlushedIndices based on the index received from flush()
607         ULock l(mQueueLock);
608         for (std::unique_ptr<C2Work>& work : flushedWork) {
609             ASSERT_NE(work, nullptr);
610             frameIndex = work->input.ordinal.frameIndex.peeku();
611             std::list<uint64_t>::iterator frameIndexIt = std::find(
612                 mFlushedIndices.begin(), mFlushedIndices.end(), frameIndex);
613             if (!mFlushedIndices.empty() &&
614                 (frameIndexIt != mFlushedIndices.end())) {
615                 mFlushedIndices.erase(frameIndexIt);
616                 work->input.buffers.clear();
617                 work->worklets.clear();
618                 mWorkQueue.push_back(std::move(work));
619             }
620         }
621     }
622     ASSERT_EQ(mFlushedIndices.empty(), true);
623     ASSERT_EQ(mComponent->stop(), C2_OK);
624 }
625 
TEST_F(Codec2VideoEncHidlTest,InvalidBufferTest)626 TEST_F(Codec2VideoEncHidlTest, InvalidBufferTest) {
627     description("Tests feeding larger/smaller input buffer");
628     if (mDisableTest) return;
629 
630     std::ifstream eleStream;
631     int32_t nWidth = ENC_DEFAULT_FRAME_WIDTH / 2;
632     int32_t nHeight = ENC_DEFAULT_FRAME_HEIGHT / 2;
633 
634     if (!setupConfigParam(nWidth, nHeight)) {
635         std::cout << "[   WARN   ] Test Skipped \n";
636         return;
637     }
638     ASSERT_EQ(mComponent->start(), C2_OK);
639 
640     ASSERT_NO_FATAL_FAILURE(
641         encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
642                       mFlushedIndices, mGraphicPool, eleStream, mDisableTest,
643                       0, 1, nWidth, nHeight, false, false));
644 
645     // Feed larger input buffer.
646     ASSERT_NO_FATAL_FAILURE(
647         encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
648                       mFlushedIndices, mGraphicPool, eleStream, mDisableTest,
649                       1, 1, nWidth*2, nHeight*2, false, false));
650 
651     // Feed smaller input buffer.
652     ASSERT_NO_FATAL_FAILURE(
653         encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
654                       mFlushedIndices, mGraphicPool, eleStream, mDisableTest,
655                       2, 1, nWidth/2, nHeight/2, false, true));
656 
657     // blocking call to ensures application to Wait till all the inputs are
658     // consumed
659     ALOGD("Waiting for input consumption");
660     ASSERT_NO_FATAL_FAILURE(
661         waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
662 
663     if (mFramesReceived != 3) {
664         std::cout << "[   WARN   ] Component didn't receive all buffers back \n";
665         ALOGW("framesReceived : %d inputFrames : 3", mFramesReceived);
666     }
667 
668     if (mFailedWorkReceived == 0) {
669         std::cout << "[   WARN   ] Expected failed frame count mismatch \n";
670         ALOGW("failedFramesReceived : %d", mFailedWorkReceived);
671     }
672 
673     ASSERT_EQ(mComponent->stop(), C2_OK);
674 }
675 
676 class Codec2VideoEncResolutionTest : public Codec2VideoEncHidlTest,
677         public ::testing::WithParamInterface<std::pair<int32_t, int32_t> > {
678 };
679 
TEST_P(Codec2VideoEncResolutionTest,ResolutionTest)680 TEST_P(Codec2VideoEncResolutionTest, ResolutionTest) {
681     description("Tests encoding at different resolutions");
682     if (mDisableTest) return;
683 
684     std::ifstream eleStream;
685     int32_t nWidth = GetParam().first;
686     int32_t nHeight = GetParam().second;
687     ALOGD("Trying encode for width %d height %d", nWidth, nHeight);
688     mEos = false;
689 
690     if (!setupConfigParam(nWidth, nHeight)) {
691         std::cout << "[   WARN   ] Test Skipped \n";
692         return;
693     }
694     ASSERT_EQ(mComponent->start(), C2_OK);
695 
696     ASSERT_NO_FATAL_FAILURE(
697         encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
698                       mFlushedIndices, mGraphicPool, eleStream, mDisableTest,
699                       0, MAX_INPUT_BUFFERS, nWidth, nHeight, false, true));
700 
701     // mDisableTest will be set if buffer was not fetched properly.
702     // This may happen when resolution is not proper but config suceeded
703     // In this cases, we skip encoding the input stream
704     if (mDisableTest) {
705         std::cout << "[   WARN   ] Test Disabled \n";
706         ASSERT_EQ(mComponent->stop(), C2_OK);
707         return;
708     }
709 
710     ALOGD("Waiting for input consumption");
711     ASSERT_NO_FATAL_FAILURE(
712         waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
713 
714     ASSERT_EQ(mEos, true);
715     ASSERT_EQ(mComponent->stop(), C2_OK);
716     ASSERT_EQ(mComponent->reset(), C2_OK);
717 }
718 
719 INSTANTIATE_TEST_CASE_P(NonStdSizes, Codec2VideoEncResolutionTest, ::testing::Values(
720     std::make_pair(52, 18),
721     std::make_pair(365, 365),
722     std::make_pair(484, 362),
723     std::make_pair(244, 488)));
724 
725 }  // anonymous namespace
726 
main(int argc,char ** argv)727 int main(int argc, char** argv) {
728     gEnv = new ComponentTestEnvironment();
729     ::testing::AddGlobalTestEnvironment(gEnv);
730     ::testing::InitGoogleTest(&argc, argv);
731     gEnv->init(&argc, argv);
732     int status = gEnv->initFromOptions(argc, argv);
733     if (status == 0) {
734         int status = RUN_ALL_TESTS();
735         LOG(INFO) << "C2 Test result = " << status;
736     }
737     return status;
738 }
739