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