1 /*
2 * Copyright (C) 2017 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_TAG "media_omx_hidl_video_enc_test"
18 #ifdef __LP64__
19 #define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
20 #endif
21
22 #include <android-base/logging.h>
23
24 #include <android/hardware/graphics/bufferqueue/1.0/IGraphicBufferProducer.h>
25 #include <android/hardware/graphics/bufferqueue/1.0/IProducerListener.h>
26 #include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
27 #include <android/hardware/media/omx/1.0/IOmx.h>
28 #include <android/hardware/media/omx/1.0/IOmxBufferSource.h>
29 #include <android/hardware/media/omx/1.0/IOmxNode.h>
30 #include <android/hardware/media/omx/1.0/IOmxObserver.h>
31 #include <android/hardware/media/omx/1.0/types.h>
32 #include <android/hidl/allocator/1.0/IAllocator.h>
33 #include <android/hidl/memory/1.0/IMapper.h>
34 #include <android/hidl/memory/1.0/IMemory.h>
35 #include <gtest/gtest.h>
36 #include <hidl/GtestPrinter.h>
37
38 using ::android::hardware::graphics::bufferqueue::V1_0::IGraphicBufferProducer;
39 using ::android::hardware::graphics::bufferqueue::V1_0::IProducerListener;
40 using ::android::hardware::graphics::common::V1_0::BufferUsage;
41 using ::android::hardware::graphics::common::V1_0::PixelFormat;
42 using ::android::hardware::media::omx::V1_0::IGraphicBufferSource;
43 using ::android::hardware::media::omx::V1_0::IOmxBufferSource;
44 using ::android::hardware::media::omx::V1_0::IOmx;
45 using ::android::hardware::media::omx::V1_0::IOmxObserver;
46 using ::android::hardware::media::omx::V1_0::IOmxNode;
47 using ::android::hardware::media::omx::V1_0::Message;
48 using ::android::hardware::media::omx::V1_0::CodecBuffer;
49 using ::android::hardware::media::omx::V1_0::PortMode;
50 using ::android::hidl::allocator::V1_0::IAllocator;
51 using ::android::hidl::memory::V1_0::IMemory;
52 using ::android::hidl::memory::V1_0::IMapper;
53 using ::android::hardware::Return;
54 using ::android::hardware::Void;
55 using ::android::hardware::hidl_vec;
56 using ::android::hardware::hidl_string;
57 using ::android::sp;
58
59 #include <getopt.h>
60 #include <media/hardware/HardwareAPI.h>
61 #include <media_video_hidl_test_common.h>
62 #include <system/window.h>
63 #include <fstream>
64 #include <variant>
65
66 // Resource directory
67 std::string sResourceDir = "";
68
69 // video encoder test fixture class
70 class VideoEncHidlTest
71 : public ::testing::TestWithParam<std::tuple<std::string, std::string, std::string>> {
72 public:
getTestCaseInfo() const73 ::std::string getTestCaseInfo() const {
74 return ::std::string() + "Component: " + component_ + " | " + "Role: " + role_ + " | " +
75 "Instance: " + instance_ + " | " + "Res: " + sResourceDir;
76 }
77
SetUp()78 virtual void SetUp() override {
79 instance_ = std::get<0>(GetParam());
80 component_ = std::get<1>(GetParam());
81 role_ = std::get<2>(GetParam());
82 ASSERT_NE(sResourceDir.empty(), true);
83
84 disableTest = false;
85 android::hardware::media::omx::V1_0::Status status;
86 omx = IOmx::getService(instance_);
87 ASSERT_NE(omx, nullptr);
88 observer =
89 new CodecObserver([this](Message msg, const BufferInfo* buffer) {
90 handleMessage(msg, buffer);
91 });
92 ASSERT_NE(observer, nullptr);
93 if (component_.find("OMX.") != 0) disableTest = true;
94 EXPECT_TRUE(omx->allocateNode(component_, observer,
95 [&](android::hardware::media::omx::V1_0::Status _s,
96 sp<IOmxNode> const& _nl) {
97 status = _s;
98 this->omxNode = _nl;
99 })
100 .isOk());
101 if (status == android::hardware::media::omx::V1_0::Status::NAME_NOT_FOUND) {
102 disableTest = true;
103 std::cout << "[ WARN ] Test Disabled, component not present\n";
104 return;
105 }
106 ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
107 ASSERT_NE(omxNode, nullptr);
108 ASSERT_NE(role_.empty(), true) << "Invalid Component Role";
109 struct StringToName {
110 const char* Name;
111 standardComp CompName;
112 };
113 const StringToName kStringToName[] = {
114 {"h263", h263}, {"avc", avc}, {"mpeg4", mpeg4},
115 {"hevc", hevc}, {"vp8", vp8}, {"vp9", vp9},
116 };
117 const size_t kNumStringToName =
118 sizeof(kStringToName) / sizeof(kStringToName[0]);
119 const char* pch;
120 char substring[OMX_MAX_STRINGNAME_SIZE];
121 strcpy(substring, role_.c_str());
122 pch = strchr(substring, '.');
123 ASSERT_NE(pch, nullptr);
124 compName = unknown_comp;
125 for (size_t i = 0; i < kNumStringToName; ++i) {
126 if (!strcasecmp(pch + 1, kStringToName[i].Name)) {
127 compName = kStringToName[i].CompName;
128 break;
129 }
130 }
131 if (compName == unknown_comp) disableTest = true;
132 struct CompToCompression {
133 standardComp CompName;
134 OMX_VIDEO_CODINGTYPE eCompressionFormat;
135 };
136 static const CompToCompression kCompToCompression[] = {
137 {h263, OMX_VIDEO_CodingH263}, {avc, OMX_VIDEO_CodingAVC},
138 {mpeg4, OMX_VIDEO_CodingMPEG4}, {hevc, OMX_VIDEO_CodingHEVC},
139 {vp8, OMX_VIDEO_CodingVP8}, {vp9, OMX_VIDEO_CodingVP9},
140 };
141 static const size_t kNumCompToCompression =
142 sizeof(kCompToCompression) / sizeof(kCompToCompression[0]);
143 size_t i;
144 for (i = 0; i < kNumCompToCompression; ++i) {
145 if (kCompToCompression[i].CompName == compName) {
146 eCompressionFormat = kCompToCompression[i].eCompressionFormat;
147 break;
148 }
149 }
150 if (i == kNumCompToCompression) disableTest = true;
151 eosFlag = false;
152 prependSPSPPS = false;
153 timestampDevTest = false;
154 producer = nullptr;
155 source = nullptr;
156 isSecure = false;
157 size_t suffixLen = strlen(".secure");
158 if (component_.rfind(".secure") == component_.length() - suffixLen) {
159 isSecure = true;
160 }
161 if (isSecure) disableTest = true;
162 if (disableTest) std::cout << "[ WARN ] Test Disabled \n";
163 }
164
TearDown()165 virtual void TearDown() override {
166 if (omxNode != nullptr) {
167 // If you have encountered a fatal failure, it is possible that
168 // freeNode() will not go through. Instead of hanging the app.
169 // let it pass through and report errors
170 if (::testing::Test::HasFatalFailure()) return;
171 EXPECT_TRUE((omxNode->freeNode()).isOk());
172 omxNode = nullptr;
173 }
174 }
175
176 // callback function to process messages received by onMessages() from IL
177 // client.
handleMessage(Message msg,const BufferInfo * buffer)178 void handleMessage(Message msg, const BufferInfo* buffer) {
179 (void)buffer;
180
181 if (msg.type == Message::Type::FILL_BUFFER_DONE) {
182 if (msg.data.extendedBufferData.flags & OMX_BUFFERFLAG_EOS) {
183 eosFlag = true;
184 }
185 if (msg.data.extendedBufferData.rangeLength != 0) {
186 // Test if current timestamp is among the list of queued
187 // timestamps
188 if (timestampDevTest && ((msg.data.extendedBufferData.flags &
189 OMX_BUFFERFLAG_CODECCONFIG) == 0)) {
190 bool tsHit = false;
191 android::List<uint64_t>::iterator it =
192 timestampUslist.begin();
193 while (it != timestampUslist.end()) {
194 if (*it == msg.data.extendedBufferData.timestampUs) {
195 timestampUslist.erase(it);
196 tsHit = true;
197 break;
198 }
199 it++;
200 }
201 if (tsHit == false) {
202 if (timestampUslist.empty() == false) {
203 EXPECT_EQ(tsHit, true)
204 << "TimeStamp not recognized";
205 } else {
206 std::cout << "[ INFO ] Received non-zero "
207 "output / TimeStamp not recognized \n";
208 }
209 }
210 }
211 #define WRITE_OUTPUT 0
212 #if WRITE_OUTPUT
213 static int count = 0;
214 FILE* ofp = nullptr;
215 if (count)
216 ofp = fopen("out.bin", "ab");
217 else
218 ofp = fopen("out.bin", "wb");
219 if (ofp != nullptr) {
220 fwrite(static_cast<void*>(buffer->mMemory->getPointer()),
221 sizeof(char),
222 msg.data.extendedBufferData.rangeLength, ofp);
223 fclose(ofp);
224 count++;
225 }
226 #endif
227 }
228 }
229 }
230
231 enum standardComp {
232 h263,
233 avc,
234 mpeg4,
235 hevc,
236 vp8,
237 vp9,
238 unknown_comp,
239 };
240
241 std::string component_;
242 std::string role_;
243 std::string instance_;
244
245 sp<IOmx> omx;
246 sp<CodecObserver> observer;
247 sp<IOmxNode> omxNode;
248 standardComp compName;
249 OMX_VIDEO_CODINGTYPE eCompressionFormat;
250 bool disableTest;
251 bool eosFlag;
252 bool prependSPSPPS;
253 ::android::List<uint64_t> timestampUslist;
254 bool timestampDevTest;
255 bool isSecure;
256 sp<IGraphicBufferProducer> producer;
257 sp<IGraphicBufferSource> source;
258
259 protected:
description(const std::string & description)260 static void description(const std::string& description) {
261 RecordProperty("description", description);
262 }
263 };
264
265 // CodecProducerListener class
266 struct CodecProducerListener : public IProducerListener {
267 public:
CodecProducerListenerCodecProducerListener268 CodecProducerListener(int a, int b)
269 : freeBuffers(a), minUnDequeuedCount(b) {}
onBufferReleasedCodecProducerListener270 virtual ::android::hardware::Return<void> onBufferReleased() override {
271 android::Mutex::Autolock autoLock(bufferLock);
272 freeBuffers += 1;
273 return Void();
274 }
needsReleaseNotifyCodecProducerListener275 virtual ::android::hardware::Return<bool> needsReleaseNotify() override {
276 return true;
277 }
reduceCountCodecProducerListener278 void reduceCount() {
279 android::Mutex::Autolock autoLock(bufferLock);
280 freeBuffers -= 1;
281 EXPECT_GE(freeBuffers, minUnDequeuedCount);
282 }
283
284 size_t freeBuffers;
285 size_t minUnDequeuedCount;
286 android::Mutex bufferLock;
287 };
288
289 // Mock IOmxBufferSource class. GraphicBufferSource.cpp in libstagefright/omx/
290 // implements this class. Below class is introduced to test if callback
291 // functions are actually being called or not
292 struct MockBufferSource : public IOmxBufferSource {
293 public:
MockBufferSourceMockBufferSource294 MockBufferSource(sp<IOmxNode> node) {
295 callback = 0;
296 executing = false;
297 omxNode = node;
298 }
299 virtual Return<void> onOmxExecuting();
300 virtual Return<void> onOmxIdle();
301 virtual Return<void> onOmxLoaded();
302 virtual Return<void> onInputBufferAdded(uint32_t buffer);
303 virtual Return<void> onInputBufferEmptied(
304 uint32_t buffer, const ::android::hardware::hidl_handle& fence);
305
306 int callback;
307 bool executing;
308 sp<IOmxNode> omxNode;
309 android::Vector<BufferInfo> iBuffer, oBuffer;
310 };
311
onOmxExecuting()312 Return<void> MockBufferSource::onOmxExecuting() {
313 executing = true;
314 callback |= 0x1;
315 size_t index;
316 // Fetch a client owned input buffer and send an EOS
317 if ((index = getEmptyBufferID(&iBuffer)) < iBuffer.size()) {
318 android::hardware::media::omx::V1_0::Status status;
319 CodecBuffer t = iBuffer[index].omxBuffer;
320 t.type = CodecBuffer::Type::ANW_BUFFER;
321 native_handle_t* fenceNh = native_handle_create(0, 0);
322 EXPECT_NE(fenceNh, nullptr);
323 status = omxNode->emptyBuffer(iBuffer[index].id, t, OMX_BUFFERFLAG_EOS,
324 0, fenceNh);
325 native_handle_close(fenceNh);
326 native_handle_delete(fenceNh);
327 EXPECT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
328 iBuffer.editItemAt(index).owner = component;
329 }
330 return Void();
331 };
332
onOmxIdle()333 Return<void> MockBufferSource::onOmxIdle() {
334 callback |= 0x2;
335 executing = false;
336 return Void();
337 };
338
onOmxLoaded()339 Return<void> MockBufferSource::onOmxLoaded() {
340 callback |= 0x4;
341 return Void();
342 };
343
onInputBufferAdded(uint32_t buffer)344 Return<void> MockBufferSource::onInputBufferAdded(uint32_t buffer) {
345 (void)buffer;
346 EXPECT_EQ(executing, false);
347 callback |= 0x8;
348 return Void();
349 };
350
onInputBufferEmptied(uint32_t buffer,const::android::hardware::hidl_handle & fence)351 Return<void> MockBufferSource::onInputBufferEmptied(
352 uint32_t buffer, const ::android::hardware::hidl_handle& fence) {
353 (void)fence;
354 callback |= 0x10;
355 size_t i;
356 for (i = 0; i < iBuffer.size(); i++) {
357 if (iBuffer[i].id == buffer) {
358 iBuffer.editItemAt(i).owner = client;
359 break;
360 }
361 }
362 return Void();
363 };
364
365 // request VOP refresh
requestIDR(sp<IOmxNode> omxNode,OMX_U32 portIndex)366 void requestIDR(sp<IOmxNode> omxNode, OMX_U32 portIndex) {
367 android::hardware::media::omx::V1_0::Status status;
368 OMX_CONFIG_INTRAREFRESHVOPTYPE param;
369 param.IntraRefreshVOP = OMX_TRUE;
370 status = setPortConfig(omxNode, OMX_IndexConfigVideoIntraVOPRefresh,
371 portIndex, ¶m);
372 if (status != ::android::hardware::media::omx::V1_0::Status::OK)
373 std::cout << "[ INFO ] unable to request IDR \n";
374 }
375
376 // modify bitrate
changeBitrate(sp<IOmxNode> omxNode,OMX_U32 portIndex,uint32_t nBitrate)377 void changeBitrate(sp<IOmxNode> omxNode, OMX_U32 portIndex, uint32_t nBitrate) {
378 android::hardware::media::omx::V1_0::Status status;
379 OMX_VIDEO_CONFIG_BITRATETYPE param;
380 param.nEncodeBitrate = nBitrate;
381 status =
382 setPortConfig(omxNode, OMX_IndexConfigVideoBitrate, portIndex, ¶m);
383 if (status != ::android::hardware::media::omx::V1_0::Status::OK)
384 std::cout << "[ INFO ] unable to change Bitrate \n";
385 }
386
387 // modify framerate
changeFrameRate(sp<IOmxNode> omxNode,OMX_U32 portIndex,uint32_t xFramerate)388 Return<android::hardware::media::omx::V1_0::Status> changeFrameRate(
389 sp<IOmxNode> omxNode, OMX_U32 portIndex, uint32_t xFramerate) {
390 android::hardware::media::omx::V1_0::Status status;
391 OMX_CONFIG_FRAMERATETYPE param;
392 param.xEncodeFramerate = xFramerate;
393 status = setPortConfig(omxNode, OMX_IndexConfigVideoFramerate, portIndex,
394 ¶m);
395 if (status != ::android::hardware::media::omx::V1_0::Status::OK)
396 std::cout << "[ INFO ] unable to change Framerate \n";
397 return status;
398 }
399
400 // modify intra refresh interval
changeRefreshPeriod(sp<IOmxNode> omxNode,OMX_U32 portIndex,uint32_t nRefreshPeriod)401 void changeRefreshPeriod(sp<IOmxNode> omxNode, OMX_U32 portIndex,
402 uint32_t nRefreshPeriod) {
403 android::hardware::media::omx::V1_0::Status status;
404 OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE param;
405 param.nRefreshPeriod = nRefreshPeriod;
406 status = setPortConfig(omxNode,
407 (OMX_INDEXTYPE)OMX_IndexConfigAndroidIntraRefresh,
408 portIndex, ¶m);
409 if (status != ::android::hardware::media::omx::V1_0::Status::OK)
410 std::cout << "[ INFO ] unable to change Refresh Period\n";
411 }
412
413 // set intra refresh interval
setRefreshPeriod(sp<IOmxNode> omxNode,OMX_U32 portIndex,uint32_t nRefreshPeriod)414 void setRefreshPeriod(sp<IOmxNode> omxNode, OMX_U32 portIndex,
415 uint32_t nRefreshPeriod) {
416 android::hardware::media::omx::V1_0::Status status;
417 OMX_VIDEO_PARAM_INTRAREFRESHTYPE param;
418 param.eRefreshMode = OMX_VIDEO_IntraRefreshCyclic;
419 param.nCirMBs = 0;
420 if (nRefreshPeriod == 0)
421 param.nCirMBs = 0;
422 else {
423 OMX_PARAM_PORTDEFINITIONTYPE portDef;
424 status = getPortParam(omxNode, OMX_IndexParamPortDefinition, portIndex,
425 &portDef);
426 if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
427 param.nCirMBs =
428 ((portDef.format.video.nFrameWidth + 15) >>
429 4 * (portDef.format.video.nFrameHeight + 15) >> 4) /
430 nRefreshPeriod;
431 }
432 }
433 status = setPortParam(omxNode, OMX_IndexParamVideoIntraRefresh, portIndex,
434 ¶m);
435 if (status != ::android::hardware::media::omx::V1_0::Status::OK)
436 std::cout << "[ INFO ] unable to set Refresh Period \n";
437 }
438
setLatency(sp<IOmxNode> omxNode,OMX_U32 portIndex,uint32_t latency)439 void setLatency(sp<IOmxNode> omxNode, OMX_U32 portIndex, uint32_t latency) {
440 android::hardware::media::omx::V1_0::Status status;
441 OMX_PARAM_U32TYPE param;
442 param.nU32 = (OMX_U32)latency;
443 status = setPortConfig(omxNode, (OMX_INDEXTYPE)OMX_IndexConfigLatency,
444 portIndex, ¶m);
445 if (status != ::android::hardware::media::omx::V1_0::Status::OK)
446 std::cout << "[ INFO ] unable to set latency\n";
447 }
448
getLatency(sp<IOmxNode> omxNode,OMX_U32 portIndex,uint32_t * latency)449 void getLatency(sp<IOmxNode> omxNode, OMX_U32 portIndex, uint32_t* latency) {
450 android::hardware::media::omx::V1_0::Status status;
451 OMX_PARAM_U32TYPE param;
452 status = getPortConfig(omxNode, (OMX_INDEXTYPE)OMX_IndexConfigLatency,
453 portIndex, ¶m);
454 if (status != ::android::hardware::media::omx::V1_0::Status::OK)
455 std::cout << "[ INFO ] unable to get latency\n";
456 else
457 *latency = param.nU32;
458 }
459
460 // Set Default port param.
setDefaultPortParam(sp<IOmxNode> omxNode,OMX_U32 portIndex,OMX_VIDEO_CODINGTYPE eCompressionFormat,OMX_U32 nFrameWidth,OMX_U32 nFrameHeight,OMX_U32 nBitrate,OMX_U32 xFramerate)461 void setDefaultPortParam(sp<IOmxNode> omxNode, OMX_U32 portIndex,
462 OMX_VIDEO_CODINGTYPE eCompressionFormat,
463 OMX_U32 nFrameWidth, OMX_U32 nFrameHeight,
464 OMX_U32 nBitrate, OMX_U32 xFramerate) {
465 android::hardware::media::omx::V1_0::Status status;
466 OMX_PARAM_PORTDEFINITIONTYPE portDef;
467 status = getPortParam(omxNode, OMX_IndexParamPortDefinition, portIndex,
468 &portDef);
469 EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
470 portDef.format.video.nFrameWidth = nFrameWidth;
471 portDef.format.video.nFrameHeight = nFrameHeight;
472 portDef.format.video.nBitrate = nBitrate;
473 portDef.format.video.xFramerate = xFramerate;
474 portDef.format.video.bFlagErrorConcealment = OMX_TRUE;
475 portDef.format.video.eCompressionFormat = eCompressionFormat;
476 portDef.format.video.eColorFormat = OMX_COLOR_FormatUnused;
477 status = setPortParam(omxNode, OMX_IndexParamPortDefinition, portIndex,
478 &portDef);
479 EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
480
481 std::vector<int32_t> arrProfile;
482 std::vector<int32_t> arrLevel;
483 enumerateProfileAndLevel(omxNode, portIndex, &arrProfile, &arrLevel);
484 if (arrProfile.empty() == true || arrLevel.empty() == true)
485 ASSERT_TRUE(false);
486 int32_t profile = arrProfile[0];
487 int32_t level = arrLevel[0];
488
489 switch ((int)eCompressionFormat) {
490 case OMX_VIDEO_CodingAVC:
491 setupAVCPort(omxNode, portIndex,
492 static_cast<OMX_VIDEO_AVCPROFILETYPE>(profile),
493 static_cast<OMX_VIDEO_AVCLEVELTYPE>(level),
494 xFramerate);
495 break;
496 case OMX_VIDEO_CodingHEVC:
497 setupHEVCPort(omxNode, portIndex,
498 static_cast<OMX_VIDEO_HEVCPROFILETYPE>(profile),
499 static_cast<OMX_VIDEO_HEVCLEVELTYPE>(level));
500 break;
501 case OMX_VIDEO_CodingH263:
502 setupH263Port(omxNode, portIndex,
503 static_cast<OMX_VIDEO_H263PROFILETYPE>(profile),
504 static_cast<OMX_VIDEO_H263LEVELTYPE>(level),
505 xFramerate);
506 break;
507 case OMX_VIDEO_CodingMPEG4:
508 setupMPEG4Port(omxNode, portIndex,
509 static_cast<OMX_VIDEO_MPEG4PROFILETYPE>(profile),
510 static_cast<OMX_VIDEO_MPEG4LEVELTYPE>(level),
511 xFramerate);
512 break;
513 case OMX_VIDEO_CodingVP8:
514 setupVPXPort(omxNode, portIndex, xFramerate);
515 setupVP8Port(omxNode, portIndex,
516 static_cast<OMX_VIDEO_VP8PROFILETYPE>(profile),
517 static_cast<OMX_VIDEO_VP8LEVELTYPE>(level));
518 break;
519 case OMX_VIDEO_CodingVP9:
520 setupVPXPort(omxNode, portIndex, xFramerate);
521 setupVP9Port(omxNode, portIndex,
522 static_cast<OMX_VIDEO_VP9PROFILETYPE>(profile),
523 static_cast<OMX_VIDEO_VP9LEVELTYPE>(level));
524 break;
525 default:
526 break;
527 }
528 }
529
530 // LookUpTable of clips and metadata for component testing
GetURLForComponent(char * URL)531 void GetURLForComponent(char* URL) {
532 strcat(URL, "bbb_352x288_420p_30fps_32frames.yuv");
533 }
534
535 // blocking call to ensures application to Wait till all the inputs are consumed
waitOnInputConsumption(sp<IOmxNode> omxNode,sp<CodecObserver> observer,android::Vector<BufferInfo> * iBuffer,android::Vector<BufferInfo> * oBuffer,bool inputDataIsMeta=false,sp<CodecProducerListener> listener=nullptr)536 void waitOnInputConsumption(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
537 android::Vector<BufferInfo>* iBuffer,
538 android::Vector<BufferInfo>* oBuffer,
539 bool inputDataIsMeta = false,
540 sp<CodecProducerListener> listener = nullptr) {
541 android::hardware::media::omx::V1_0::Status status;
542 Message msg;
543 int timeOut = TIMEOUT_COUNTER_Q;
544
545 while (timeOut--) {
546 size_t i = 0;
547 status =
548 observer->dequeueMessage(&msg, DEFAULT_TIMEOUT_Q, iBuffer, oBuffer);
549 ASSERT_EQ(status,
550 android::hardware::media::omx::V1_0::Status::TIMED_OUT);
551 // status == TIMED_OUT, it could be due to process time being large
552 // than DEFAULT_TIMEOUT or component needs output buffers to start
553 // processing.
554 if (inputDataIsMeta) {
555 if (listener->freeBuffers == iBuffer->size()) break;
556 } else {
557 for (; i < iBuffer->size(); i++) {
558 if ((*iBuffer)[i].owner != client) break;
559 }
560 if (i == iBuffer->size()) break;
561 }
562
563 // Dispatch an output buffer assuming outQueue.empty() is true
564 size_t index;
565 if ((index = getEmptyBufferID(oBuffer)) < oBuffer->size()) {
566 ASSERT_NO_FATAL_FAILURE(
567 dispatchOutputBuffer(omxNode, oBuffer, index));
568 timeOut = TIMEOUT_COUNTER_Q;
569 }
570 }
571 }
572
colorFormatConversion(BufferInfo * buffer,buffer_handle_t buff,PixelFormat format,std::ifstream & eleStream)573 int colorFormatConversion(BufferInfo* buffer, buffer_handle_t buff, PixelFormat format,
574 std::ifstream& eleStream) {
575 android::GraphicBufferMapper& gbmapper = android::GraphicBufferMapper::get();
576
577 android::Rect rect(0, 0, buffer->omxBuffer.attr.anwBuffer.width,
578 buffer->omxBuffer.attr.anwBuffer.height);
579 android_ycbcr ycbcrLayout;
580 android::status_t error = android::NO_ERROR;
581
582 if (format == PixelFormat::YV12 || format == PixelFormat::YCRCB_420_SP ||
583 format == PixelFormat::YCBCR_420_888) {
584 error = gbmapper.lockYCbCr(buff, buffer->omxBuffer.attr.anwBuffer.usage, rect,
585 &ycbcrLayout);
586 EXPECT_EQ(error, android::NO_ERROR);
587 if (error != android::NO_ERROR) return 1;
588
589 int size = ((rect.getWidth() * rect.getHeight() * 3) >> 1);
590 char* img = new char[size];
591 if (img == nullptr) return 1;
592 eleStream.read(img, size);
593 if (eleStream.gcount() != size) {
594 delete[] img;
595 return 1;
596 }
597
598 char* imgTmp = img;
599 char* ipBuffer = static_cast<char*>(ycbcrLayout.y);
600 for (size_t y = rect.getHeight(); y > 0; --y) {
601 memcpy(ipBuffer, imgTmp, rect.getWidth());
602 ipBuffer += ycbcrLayout.ystride;
603 imgTmp += rect.getWidth();
604 }
605
606 if (format == PixelFormat::YV12)
607 EXPECT_EQ(ycbcrLayout.chroma_step, 1U);
608 else if (format == PixelFormat::YCRCB_420_SP)
609 EXPECT_EQ(ycbcrLayout.chroma_step, 2U);
610
611 ipBuffer = static_cast<char*>(ycbcrLayout.cb);
612 for (size_t y = rect.getHeight() >> 1; y > 0; --y) {
613 for (int32_t x = 0; x < (rect.getWidth() >> 1); ++x) {
614 ipBuffer[ycbcrLayout.chroma_step * x] = *imgTmp++;
615 }
616 ipBuffer += ycbcrLayout.cstride;
617 }
618 ipBuffer = static_cast<char*>(ycbcrLayout.cr);
619 for (size_t y = rect.getHeight() >> 1; y > 0; --y) {
620 for (int32_t x = 0; x < (rect.getWidth() >> 1); ++x) {
621 ipBuffer[ycbcrLayout.chroma_step * x] = *imgTmp++;
622 }
623 ipBuffer += ycbcrLayout.cstride;
624 }
625
626 delete[] img;
627
628 error = gbmapper.unlock(buff);
629 EXPECT_EQ(error, android::NO_ERROR);
630 if (error != android::NO_ERROR) return 1;
631 } else {
632 void* data;
633 int32_t outBytesPerPixel;
634 int32_t outBytesPerStride;
635 error = gbmapper.lock(buff, buffer->omxBuffer.attr.anwBuffer.usage, rect, &data,
636 &outBytesPerPixel, &outBytesPerStride);
637 EXPECT_EQ(error, android::NO_ERROR);
638 if (error != android::NO_ERROR) return 1;
639
640 if (format == PixelFormat::BGRA_8888) {
641 char* ipBuffer = static_cast<char*>(data);
642 for (size_t y = rect.getHeight(); y > 0; --y) {
643 eleStream.read(ipBuffer, rect.getWidth() * 4);
644 if (eleStream.gcount() != rect.getWidth() * 4) return 1;
645 ipBuffer += buffer->omxBuffer.attr.anwBuffer.stride * 4;
646 }
647 } else {
648 EXPECT_TRUE(false) << "un expected pixel format";
649 return 1;
650 }
651
652 error = gbmapper.unlock(buff);
653 EXPECT_EQ(error, android::NO_ERROR);
654 if (error != android::NO_ERROR) return 1;
655 }
656
657 return 0;
658 }
659
fillGraphicBuffer(BufferInfo * buffer,PixelFormat format,std::ifstream & eleStream)660 int fillGraphicBuffer(BufferInfo* buffer, PixelFormat format,
661 std::ifstream& eleStream) {
662 android::GraphicBufferMapper& gbmapper = android::GraphicBufferMapper::get();
663 buffer_handle_t buff;
664 android::status_t error = android::NO_ERROR;
665 gbmapper.importBuffer(
666 buffer->omxBuffer.nativeHandle, buffer->omxBuffer.attr.anwBuffer.width,
667 buffer->omxBuffer.attr.anwBuffer.height, buffer->omxBuffer.attr.anwBuffer.layerCount,
668 static_cast<android::PixelFormat>(format), buffer->omxBuffer.attr.anwBuffer.usage,
669 buffer->omxBuffer.attr.anwBuffer.stride, &buff);
670 EXPECT_EQ(error, android::NO_ERROR);
671 if (error != android::NO_ERROR) return 1;
672
673 if (colorFormatConversion(buffer, buff, format, eleStream)) return 1;
674
675 error = gbmapper.freeBuffer(buff);
676 EXPECT_EQ(error, android::NO_ERROR);
677 if (error != android::NO_ERROR) return 1;
678
679 return 0;
680 }
681
dispatchGraphicBuffer(sp<IOmxNode> omxNode,sp<IGraphicBufferProducer> producer,sp<CodecProducerListener> listener,android::Vector<BufferInfo> * buffArray,OMX_U32 portIndex,std::ifstream & eleStream,uint64_t timestamp)682 int dispatchGraphicBuffer(sp<IOmxNode> omxNode,
683 sp<IGraphicBufferProducer> producer,
684 sp<CodecProducerListener> listener,
685 android::Vector<BufferInfo>* buffArray,
686 OMX_U32 portIndex, std::ifstream& eleStream,
687 uint64_t timestamp) {
688 android::hardware::media::omx::V1_0::Status status;
689 OMX_PARAM_PORTDEFINITIONTYPE portDef;
690
691 status = getPortParam(omxNode, OMX_IndexParamPortDefinition, portIndex,
692 &portDef);
693 EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
694 if (status != ::android::hardware::media::omx::V1_0::Status::OK) return 1;
695
696 enum {
697 // A flag returned by dequeueBuffer when the client needs to call
698 // requestBuffer immediately thereafter.
699 BUFFER_NEEDS_REALLOCATION = 0x1,
700 // A flag returned by dequeueBuffer when all mirrored slots should be
701 // released by the client. This flag should always be processed first.
702 RELEASE_ALL_BUFFERS = 0x2,
703 };
704
705 int32_t slot;
706 int32_t result;
707 ::android::hardware::hidl_handle fence;
708 IGraphicBufferProducer::FrameEventHistoryDelta outTimestamps;
709 ::android::hardware::media::V1_0::AnwBuffer AnwBuffer;
710 PixelFormat format = PixelFormat::YCBCR_420_888;
711 producer->dequeueBuffer(
712 portDef.format.video.nFrameWidth, portDef.format.video.nFrameHeight,
713 format, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
714 true, [&](int32_t _s, int32_t const& _n1,
715 ::android::hardware::hidl_handle const& _n2,
716 IGraphicBufferProducer::FrameEventHistoryDelta const& _n3) {
717 result = _s;
718 slot = _n1;
719 fence = _n2;
720 outTimestamps = _n3;
721 });
722 if (result & BUFFER_NEEDS_REALLOCATION) {
723 producer->requestBuffer(
724 slot, [&](int32_t _s,
725 ::android::hardware::media::V1_0::AnwBuffer const& _n1) {
726 result = _s;
727 AnwBuffer = _n1;
728 });
729 EXPECT_EQ(result, 0);
730 if (result != 0) return 1;
731 size_t i;
732 for (i = 0; i < buffArray->size(); i++) {
733 if ((*buffArray)[i].slot == -1) {
734 buffArray->editItemAt(i).slot = slot;
735 buffArray->editItemAt(i).omxBuffer.nativeHandle =
736 AnwBuffer.nativeHandle;
737 buffArray->editItemAt(i).omxBuffer.attr.anwBuffer =
738 AnwBuffer.attr;
739 break;
740 }
741 }
742 EXPECT_NE(i, buffArray->size());
743 if (i == buffArray->size()) return 1;
744 }
745 EXPECT_EQ(result, 0);
746 if (result != 0) return 1;
747
748 // fill Buffer
749 BufferInfo buffer;
750 size_t i;
751 for (i = 0; i < buffArray->size(); i++) {
752 if ((*buffArray)[i].slot == slot) {
753 buffer = (*buffArray)[i];
754 break;
755 }
756 }
757 EXPECT_NE(i, buffArray->size());
758 if (i == buffArray->size()) return 1;
759 if (fillGraphicBuffer(&buffer, format, eleStream)) return 1;
760
761 // queue Buffer
762 IGraphicBufferProducer::QueueBufferOutput output;
763 IGraphicBufferProducer::QueueBufferInput input;
764 android::hardware::media::V1_0::Rect rect;
765 rect.left = 0;
766 rect.top = 0;
767 rect.right = buffer.omxBuffer.attr.anwBuffer.width;
768 rect.bottom = buffer.omxBuffer.attr.anwBuffer.height;
769 input.timestamp = timestamp;
770 input.isAutoTimestamp = false;
771 input.dataSpace =
772 android::hardware::graphics::common::V1_0::Dataspace::UNKNOWN;
773 input.crop = rect;
774 input.scalingMode = 0;
775 input.transform = 0;
776 input.stickyTransform = 0;
777 input.fence = android::hardware::hidl_handle();
778 input.surfaceDamage =
779 android::hardware::hidl_vec<android::hardware::media::V1_0::Rect>{rect};
780 input.getFrameTimestamps = false;
781 producer->queueBuffer(
782 buffer.slot, input,
783 [&](int32_t _s, const IGraphicBufferProducer::QueueBufferOutput& _n1) {
784 result = _s;
785 output = _n1;
786 });
787 EXPECT_EQ(result, 0);
788 if (result != 0) return 1;
789
790 listener->reduceCount();
791
792 return 0;
793 }
794
fillByteBuffer(sp<IOmxNode> omxNode,char * ipBuffer,OMX_U32 portIndexInput,std::ifstream & eleStream)795 int fillByteBuffer(sp<IOmxNode> omxNode, char* ipBuffer, OMX_U32 portIndexInput,
796 std::ifstream& eleStream) {
797 android::hardware::media::omx::V1_0::Status status;
798 OMX_PARAM_PORTDEFINITIONTYPE portDef;
799 uint32_t i, j;
800
801 status = getPortParam(omxNode, OMX_IndexParamPortDefinition, portIndexInput,
802 &portDef);
803 EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
804
805 int size = ((portDef.format.video.nFrameWidth *
806 portDef.format.video.nFrameHeight * 3) >>
807 1);
808 char* img = new char[size];
809 if (img == nullptr) return 1;
810 eleStream.read(img, size);
811 if (eleStream.gcount() != size) {
812 delete[] img;
813 return 1;
814 }
815
816 char* Y = ipBuffer;
817 char* imgTmp = img;
818 for (j = 0; j < portDef.format.video.nFrameHeight; ++j) {
819 memcpy(Y, imgTmp, portDef.format.video.nFrameWidth);
820 Y += portDef.format.video.nStride;
821 imgTmp += portDef.format.video.nFrameWidth;
822 }
823
824 if (portDef.format.video.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) {
825 char* Cb = ipBuffer + (portDef.format.video.nFrameHeight *
826 portDef.format.video.nStride);
827 char* Cr = Cb + 1;
828 for (j = 0; j<portDef.format.video.nFrameHeight>> 1; ++j) {
829 for (i = 0; i < (portDef.format.video.nFrameWidth >> 1); ++i) {
830 Cb[2 * i] = *imgTmp++;
831 }
832 Cb += portDef.format.video.nStride;
833 }
834 for (j = 0; j<portDef.format.video.nFrameHeight>> 1; ++j) {
835 for (i = 0; i < (portDef.format.video.nFrameWidth >> 1); ++i) {
836 Cr[2 * i] = *imgTmp++;
837 }
838 Cr += portDef.format.video.nStride;
839 }
840 } else if (portDef.format.video.eColorFormat ==
841 OMX_COLOR_FormatYUV420Planar) {
842 char* Cb = ipBuffer + (portDef.format.video.nFrameHeight *
843 portDef.format.video.nStride);
844 char* Cr = Cb + ((portDef.format.video.nFrameHeight *
845 portDef.format.video.nStride) >>
846 2);
847 for (j = 0; j<portDef.format.video.nFrameHeight>> 1; ++j) {
848 memcpy(Cb, imgTmp, (portDef.format.video.nFrameWidth >> 1));
849 Cb += (portDef.format.video.nStride >> 1);
850 imgTmp += (portDef.format.video.nFrameWidth >> 1);
851 }
852 for (j = 0; j<portDef.format.video.nFrameHeight>> 1; ++j) {
853 memcpy(Cr, imgTmp, (portDef.format.video.nFrameWidth >> 1));
854 Cr += (portDef.format.video.nStride >> 1);
855 imgTmp += (portDef.format.video.nFrameWidth >> 1);
856 }
857 }
858
859 delete[] img;
860 return 0;
861 }
862
863 // Encode N Frames
encodeNFrames(sp<IOmxNode> omxNode,sp<CodecObserver> observer,OMX_U32 portIndexInput,OMX_U32 portIndexOutput,android::Vector<BufferInfo> * iBuffer,android::Vector<BufferInfo> * oBuffer,uint32_t nFrames,uint32_t xFramerate,int bytesCount,std::ifstream & eleStream,::android::List<uint64_t> * timestampUslist=nullptr,bool signalEOS=true,bool inputDataIsMeta=false,sp<IGraphicBufferProducer> producer=nullptr,sp<CodecProducerListener> listener=nullptr)864 void encodeNFrames(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
865 OMX_U32 portIndexInput, OMX_U32 portIndexOutput,
866 android::Vector<BufferInfo>* iBuffer,
867 android::Vector<BufferInfo>* oBuffer, uint32_t nFrames,
868 uint32_t xFramerate, int bytesCount,
869 std::ifstream& eleStream,
870 ::android::List<uint64_t>* timestampUslist = nullptr,
871 bool signalEOS = true, bool inputDataIsMeta = false,
872 sp<IGraphicBufferProducer> producer = nullptr,
873 sp<CodecProducerListener> listener = nullptr) {
874 android::hardware::media::omx::V1_0::Status status;
875 Message msg;
876 uint64_t timestamp = 0;
877 uint32_t flags = 0;
878 int timeOut = TIMEOUT_COUNTER_Q;
879 bool iQueued, oQueued;
880
881 uint32_t ipCount = 0;
882 if (ipCount == 0) {
883 status = changeFrameRate(omxNode, portIndexOutput, (24U << 16));
884 if (status == ::android::hardware::media::omx::V1_0::Status::OK)
885 xFramerate = (24U << 16);
886 }
887 int32_t timestampIncr = (int)((float)1000000 / (xFramerate >> 16));
888 if (inputDataIsMeta) timestampIncr *= 1000; // timestamp scale: Nano sec
889
890 while (1) {
891 iQueued = oQueued = false;
892 status =
893 observer->dequeueMessage(&msg, DEFAULT_TIMEOUT_Q, iBuffer, oBuffer);
894 // Port Reconfiguration
895 if (status == android::hardware::media::omx::V1_0::Status::OK) {
896 ASSERT_EQ(msg.type, Message::Type::EVENT);
897 if (msg.data.eventData.event == OMX_EventPortSettingsChanged) {
898 ASSERT_EQ(msg.data.eventData.data1, portIndexOutput);
899 ASSERT_EQ(msg.data.eventData.data2,
900 OMX_IndexConfigAndroidIntraRefresh);
901 } else if (msg.data.eventData.event == OMX_EventError) {
902 ASSERT_TRUE(false) << "Received OMX_EventError, not sure why";
903 } else if (msg.data.eventData.event == OMX_EventDataSpaceChanged) {
904 // TODO: how am i supposed to respond now?
905 std::cout << "[ INFO ] OMX_EventDataSpaceChanged \n";
906 } else {
907 ASSERT_TRUE(false);
908 }
909 }
910
911 if (nFrames == 0) break;
912
913 // Dispatch input buffer
914 size_t index = 0;
915 if (inputDataIsMeta) {
916 if (listener->freeBuffers > listener->minUnDequeuedCount) {
917 if (dispatchGraphicBuffer(omxNode, producer, listener, iBuffer,
918 portIndexInput, eleStream,
919 timestamp)) {
920 if (::testing::Test::HasFailure())
921 ASSERT_TRUE(false);
922 else
923 break;
924 }
925 timestamp += timestampIncr;
926 nFrames--;
927 ipCount++;
928 iQueued = true;
929 }
930 } else {
931 if ((index = getEmptyBufferID(iBuffer)) < iBuffer->size()) {
932 char* ipBuffer = static_cast<char*>(static_cast<void*>(
933 (*iBuffer)[index].mMemory->getPointer()));
934 ASSERT_LE(
935 bytesCount,
936 static_cast<int>((*iBuffer)[index].mMemory->getSize()));
937 if (fillByteBuffer(omxNode, ipBuffer, portIndexInput,
938 eleStream))
939 break;
940 flags = OMX_BUFFERFLAG_ENDOFFRAME;
941 if (signalEOS && (nFrames == 1)) flags |= OMX_BUFFERFLAG_EOS;
942 ASSERT_NO_FATAL_FAILURE(dispatchInputBuffer(
943 omxNode, iBuffer, index, bytesCount, flags, timestamp));
944 if (timestampUslist) timestampUslist->push_back(timestamp);
945 timestamp += timestampIncr;
946 nFrames--;
947 ipCount++;
948 iQueued = true;
949 }
950 }
951 // Dispatch output buffer
952 if ((index = getEmptyBufferID(oBuffer)) < oBuffer->size()) {
953 ASSERT_NO_FATAL_FAILURE(
954 dispatchOutputBuffer(omxNode, oBuffer, index));
955 oQueued = true;
956 }
957 // Reset Counters when either input or output buffer is dispatched
958 if (iQueued || oQueued)
959 timeOut = TIMEOUT_COUNTER_Q;
960 else
961 timeOut--;
962 if (timeOut == 0) {
963 ASSERT_TRUE(false) << "Wait on Input/Output is found indefinite";
964 }
965 // Runtime Param Configuration
966 if (ipCount == 15) {
967 changeBitrate(omxNode, portIndexOutput, 768000);
968 requestIDR(omxNode, portIndexOutput);
969 changeRefreshPeriod(omxNode, portIndexOutput, 15);
970 }
971 }
972 }
973
974 // set component role
TEST_P(VideoEncHidlTest,SetRole)975 TEST_P(VideoEncHidlTest, SetRole) {
976 description("Test Set Component Role");
977 if (disableTest) return;
978 android::hardware::media::omx::V1_0::Status status;
979 status = setRole(omxNode, role_);
980 ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
981 }
982
983 // port format enumeration
TEST_P(VideoEncHidlTest,EnumeratePortFormat)984 TEST_P(VideoEncHidlTest, EnumeratePortFormat) {
985 description("Test Component on Mandatory Port Parameters (Port Format)");
986 if (disableTest) return;
987 android::hardware::media::omx::V1_0::Status status;
988 uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
989 OMX_COLOR_FORMATTYPE eColorFormat = OMX_COLOR_FormatYUV420Planar;
990 OMX_U32 xFramerate = (30U << 16);
991 status = setRole(omxNode, role_);
992 ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
993 OMX_PORT_PARAM_TYPE params;
994 status = getParam(omxNode, OMX_IndexParamVideoInit, ¶ms);
995 if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
996 ASSERT_EQ(params.nPorts, 2U);
997 kPortIndexInput = params.nStartPortNumber;
998 kPortIndexOutput = kPortIndexInput + 1;
999 }
1000 status =
1001 setVideoPortFormat(omxNode, kPortIndexInput, OMX_VIDEO_CodingUnused,
1002 eColorFormat, xFramerate);
1003 EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1004
1005 status = setVideoPortFormat(omxNode, kPortIndexOutput, eCompressionFormat,
1006 OMX_COLOR_FormatUnused, 0U);
1007 EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1008 }
1009
1010 // Test IOmxBufferSource CallBacks
TEST_P(VideoEncHidlTest,BufferSourceCallBacks)1011 TEST_P(VideoEncHidlTest, BufferSourceCallBacks) {
1012 description("Test IOmxBufferSource CallBacks");
1013 if (disableTest) return;
1014 android::hardware::media::omx::V1_0::Status status;
1015 uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
1016 status = setRole(omxNode, role_);
1017 ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1018 OMX_PORT_PARAM_TYPE params;
1019 status = getParam(omxNode, OMX_IndexParamVideoInit, ¶ms);
1020 if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
1021 ASSERT_EQ(params.nPorts, 2U);
1022 kPortIndexInput = params.nStartPortNumber;
1023 kPortIndexOutput = kPortIndexInput + 1;
1024 }
1025
1026 // Configure input port
1027 uint32_t nFrameWidth = 352;
1028 uint32_t nFrameHeight = 288;
1029 uint32_t xFramerate = (30U << 16);
1030 OMX_COLOR_FORMATTYPE eColorFormat = OMX_COLOR_FormatAndroidOpaque;
1031 setupRAWPort(omxNode, kPortIndexInput, nFrameWidth, nFrameHeight, 0,
1032 xFramerate, eColorFormat);
1033
1034 sp<MockBufferSource> buffersource = new MockBufferSource(omxNode);
1035 ASSERT_NE(buffersource, nullptr);
1036 status = omxNode->setInputSurface(buffersource);
1037 ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1038
1039 // set port mode
1040 PortMode portMode[2];
1041 portMode[0] = PortMode::DYNAMIC_ANW_BUFFER;
1042 portMode[1] = PortMode::PRESET_BYTE_BUFFER;
1043 status = omxNode->setPortMode(kPortIndexInput, portMode[0]);
1044 ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1045 status = omxNode->setPortMode(kPortIndexOutput, portMode[1]);
1046 ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1047
1048 // set state to idle
1049 ASSERT_NO_FATAL_FAILURE(changeStateLoadedtoIdle(
1050 omxNode, observer, &buffersource->iBuffer, &buffersource->oBuffer,
1051 kPortIndexInput, kPortIndexOutput, portMode));
1052 // set state to executing
1053 ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer));
1054 ASSERT_NO_FATAL_FAILURE(testEOS(omxNode, observer, &buffersource->iBuffer,
1055 &buffersource->oBuffer, false, eosFlag));
1056 // set state to idle
1057 ASSERT_NO_FATAL_FAILURE(changeStateExecutetoIdle(
1058 omxNode, observer, &buffersource->iBuffer, &buffersource->oBuffer));
1059 // set state to executing
1060 ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded(omxNode, observer, &buffersource->iBuffer,
1061 &buffersource->oBuffer, kPortIndexInput,
1062 kPortIndexOutput, portMode));
1063 // test for callbacks
1064 EXPECT_EQ(buffersource->callback, 31);
1065 }
1066
1067 // test raw stream encode (input is byte buffers)
TEST_P(VideoEncHidlTest,EncodeTest)1068 TEST_P(VideoEncHidlTest, EncodeTest) {
1069 description("Test Encode");
1070 if (disableTest) return;
1071 android::hardware::media::omx::V1_0::Status status;
1072 uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
1073 status = setRole(omxNode, role_);
1074 ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1075 OMX_PORT_PARAM_TYPE params;
1076 status = getParam(omxNode, OMX_IndexParamVideoInit, ¶ms);
1077 if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
1078 ASSERT_EQ(params.nPorts, 2U);
1079 kPortIndexInput = params.nStartPortNumber;
1080 kPortIndexOutput = kPortIndexInput + 1;
1081 }
1082 char mURL[512];
1083 strcpy(mURL, sResourceDir.c_str());
1084 GetURLForComponent(mURL);
1085
1086 std::ifstream eleStream;
1087
1088 timestampDevTest = true;
1089
1090 // Configure input port
1091 uint32_t nFrameWidth = 352;
1092 uint32_t nFrameHeight = 288;
1093 uint32_t xFramerate = (30U << 16);
1094 OMX_COLOR_FORMATTYPE eColorFormat = OMX_COLOR_FormatUnused;
1095 OMX_VIDEO_PARAM_PORTFORMATTYPE portFormat;
1096 portFormat.nIndex = 0;
1097 while (1) {
1098 status = getPortParam(omxNode, OMX_IndexParamVideoPortFormat,
1099 kPortIndexInput, &portFormat);
1100 if (status != ::android::hardware::media::omx::V1_0::Status::OK) break;
1101 EXPECT_EQ(portFormat.eCompressionFormat, OMX_VIDEO_CodingUnused);
1102 if (OMX_COLOR_FormatYUV420SemiPlanar == portFormat.eColorFormat ||
1103 OMX_COLOR_FormatYUV420Planar == portFormat.eColorFormat) {
1104 eColorFormat = portFormat.eColorFormat;
1105 break;
1106 }
1107 portFormat.nIndex++;
1108 if (portFormat.nIndex == 512) break;
1109 }
1110 ASSERT_NE(eColorFormat, OMX_COLOR_FormatUnused);
1111 setupRAWPort(omxNode, kPortIndexInput, nFrameWidth, nFrameHeight, 0,
1112 xFramerate, eColorFormat);
1113
1114 // Configure output port
1115 uint32_t nBitRate = 512000;
1116 ASSERT_NO_FATAL_FAILURE(
1117 setDefaultPortParam(omxNode, kPortIndexOutput, eCompressionFormat,
1118 nFrameWidth, nFrameHeight, nBitRate, xFramerate));
1119 setRefreshPeriod(omxNode, kPortIndexOutput, 0);
1120
1121 unsigned int index;
1122 omxNode->getExtensionIndex(
1123 "OMX.google.android.index.prependSPSPPSToIDRFrames",
1124 [&status, &index](android::hardware::media::omx::V1_0::Status _s,
1125 unsigned int _nl) {
1126 status = _s;
1127 index = _nl;
1128 });
1129 if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
1130 android::PrependSPSPPSToIDRFramesParams param;
1131 param.bEnable = OMX_TRUE;
1132 status = setParam(omxNode, static_cast<OMX_INDEXTYPE>(index), ¶m);
1133 }
1134 if (status != ::android::hardware::media::omx::V1_0::Status::OK)
1135 std::cout << "[ INFO ] unable to prependSPSPPSToIDRFrames\n";
1136 else
1137 prependSPSPPS = true;
1138
1139 // set port mode
1140 PortMode portMode[2];
1141 portMode[0] = portMode[1] = PortMode::PRESET_BYTE_BUFFER;
1142 status = omxNode->setPortMode(kPortIndexInput, portMode[0]);
1143 ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1144 status = omxNode->setPortMode(kPortIndexOutput, portMode[1]);
1145 ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1146
1147 uint32_t latency = 0;
1148 setLatency(omxNode, kPortIndexInput, latency);
1149 getLatency(omxNode, kPortIndexInput, &latency);
1150
1151 android::Vector<BufferInfo> iBuffer, oBuffer;
1152
1153 // set state to idle
1154 ASSERT_NO_FATAL_FAILURE(
1155 changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer,
1156 kPortIndexInput, kPortIndexOutput, portMode));
1157 // set state to executing
1158 ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer));
1159
1160 eleStream.open(mURL, std::ifstream::binary);
1161 ASSERT_EQ(eleStream.is_open(), true);
1162 ASSERT_NO_FATAL_FAILURE(encodeNFrames(
1163 omxNode, observer, kPortIndexInput, kPortIndexOutput, &iBuffer,
1164 &oBuffer, 32, xFramerate, (nFrameWidth * nFrameHeight * 3) >> 1,
1165 eleStream, ×tampUslist));
1166 eleStream.close();
1167 ASSERT_NO_FATAL_FAILURE(
1168 waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer));
1169 ASSERT_NO_FATAL_FAILURE(
1170 testEOS(omxNode, observer, &iBuffer, &oBuffer, false, eosFlag));
1171 if (timestampDevTest) EXPECT_EQ(timestampUslist.empty(), true);
1172
1173 // set state to idle
1174 ASSERT_NO_FATAL_FAILURE(
1175 changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer));
1176 // set state to executing
1177 ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded(omxNode, observer, &iBuffer, &oBuffer,
1178 kPortIndexInput, kPortIndexOutput, portMode));
1179 }
1180
1181 // test raw stream encode (input is ANW buffers)
TEST_P(VideoEncHidlTest,EncodeTestBufferMetaModes)1182 TEST_P(VideoEncHidlTest, EncodeTestBufferMetaModes) {
1183 description("Test Encode Input buffer metamodes");
1184 if (disableTest) return;
1185 android::hardware::media::omx::V1_0::Status status;
1186 uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
1187 status = setRole(omxNode, role_);
1188 ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1189 OMX_PORT_PARAM_TYPE params;
1190 status = getParam(omxNode, OMX_IndexParamVideoInit, ¶ms);
1191 if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
1192 ASSERT_EQ(params.nPorts, 2U);
1193 kPortIndexInput = params.nStartPortNumber;
1194 kPortIndexOutput = kPortIndexInput + 1;
1195 }
1196
1197 // Configure input port
1198 uint32_t nFrameWidth = 352;
1199 uint32_t nFrameHeight = 288;
1200 uint32_t xFramerate = (30U << 16);
1201 OMX_COLOR_FORMATTYPE eColorFormat = OMX_COLOR_FormatAndroidOpaque;
1202 setupRAWPort(omxNode, kPortIndexInput, nFrameWidth, nFrameHeight, 0,
1203 xFramerate, eColorFormat);
1204
1205 // Configure output port
1206 uint32_t nBitRate = 512000;
1207 ASSERT_NO_FATAL_FAILURE(
1208 setDefaultPortParam(omxNode, kPortIndexOutput, eCompressionFormat,
1209 nFrameWidth, nFrameHeight, nBitRate, xFramerate));
1210 // CreateInputSurface
1211 EXPECT_TRUE(omx->createInputSurface(
1212 [&](android::hardware::media::omx::V1_0::Status _s,
1213 sp<IGraphicBufferProducer> const& _nl,
1214 sp<IGraphicBufferSource> const& _n2) {
1215 status = _s;
1216 producer = _nl;
1217 source = _n2;
1218 })
1219 .isOk());
1220 ASSERT_NE(producer, nullptr);
1221 ASSERT_NE(source, nullptr);
1222
1223 // setMaxDequeuedBufferCount
1224 int32_t returnval;
1225 int32_t value;
1226 producer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
1227 [&returnval, &value](int32_t _s, int32_t _n1) {
1228 returnval = _s;
1229 value = _n1;
1230 });
1231 ASSERT_EQ(returnval, 0);
1232 OMX_PARAM_PORTDEFINITIONTYPE portDef;
1233 status = getPortParam(omxNode, OMX_IndexParamPortDefinition,
1234 kPortIndexInput, &portDef);
1235 ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1236 ASSERT_EQ(::android::OK,
1237 producer->setMaxDequeuedBufferCount(portDef.nBufferCountActual));
1238
1239 // Connect :: Mock Producer Listener
1240 IGraphicBufferProducer::QueueBufferOutput qbo;
1241 sp<CodecProducerListener> listener =
1242 new CodecProducerListener(portDef.nBufferCountActual + value, value);
1243 producer->connect(
1244 listener, NATIVE_WINDOW_API_CPU, false,
1245 [&](int32_t _s, IGraphicBufferProducer::QueueBufferOutput const& _n1) {
1246 returnval = _s;
1247 qbo = _n1;
1248 });
1249 ASSERT_EQ(returnval, 0);
1250
1251 portDef.nBufferCountActual = portDef.nBufferCountActual + value;
1252 status = setPortParam(omxNode, OMX_IndexParamPortDefinition,
1253 kPortIndexInput, &portDef);
1254 ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1255
1256 // Do setInputSurface()
1257 // enable MetaMode on input port
1258 status = source->configure(
1259 omxNode, android::hardware::graphics::common::V1_0::Dataspace::UNKNOWN);
1260 ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1261
1262 // set port mode
1263 PortMode portMode[2];
1264 portMode[0] = PortMode::DYNAMIC_ANW_BUFFER;
1265 portMode[1] = PortMode::PRESET_BYTE_BUFFER;
1266 status = omxNode->setPortMode(kPortIndexInput, portMode[0]);
1267 ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1268 status = omxNode->setPortMode(kPortIndexOutput, portMode[1]);
1269 ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1270
1271 char mURL[512];
1272 strcpy(mURL, sResourceDir.c_str());
1273 GetURLForComponent(mURL);
1274
1275 uint32_t latency = 0;
1276 setLatency(omxNode, kPortIndexInput, latency);
1277 getLatency(omxNode, kPortIndexInput, &latency);
1278
1279 std::ifstream eleStream;
1280
1281 status = source->setSuspend(false, 0);
1282 EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1283 status = source->setRepeatPreviousFrameDelayUs(100000);
1284 EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1285 status = source->setMaxFps(24.0f);
1286 EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1287 status = source->setTimeLapseConfig(24.0, 24.0);
1288 EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1289 status = source->setTimeOffsetUs(-100);
1290 EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1291 status = source->setStartTimeUs(10);
1292 EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1293 status = source->setStopTimeUs(1000000);
1294 EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1295 ::android::hardware::media::omx::V1_0::ColorAspects aspects;
1296 aspects.range =
1297 ::android::hardware::media::omx::V1_0::ColorAspects::Range::UNSPECIFIED;
1298 aspects.primaries = ::android::hardware::media::omx::V1_0::ColorAspects::
1299 Primaries::UNSPECIFIED;
1300 aspects.transfer = ::android::hardware::media::omx::V1_0::ColorAspects::
1301 Transfer::UNSPECIFIED;
1302 aspects.matrixCoeffs = ::android::hardware::media::omx::V1_0::ColorAspects::
1303 MatrixCoeffs::UNSPECIFIED;
1304 status = source->setColorAspects(aspects);
1305 EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1306 int64_t stopTimeOffsetUs;
1307 source->getStopTimeOffsetUs(
1308 [&](android::hardware::media::omx::V1_0::Status _s, int64_t _n1) {
1309 status = _s;
1310 stopTimeOffsetUs = _n1;
1311 });
1312 EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1313
1314 android::Vector<BufferInfo> iBuffer, oBuffer;
1315 // set state to idle
1316 ASSERT_NO_FATAL_FAILURE(
1317 changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer,
1318 kPortIndexInput, kPortIndexOutput, portMode));
1319 // set state to executing
1320 ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer));
1321
1322 eleStream.open(mURL, std::ifstream::binary);
1323 ASSERT_EQ(eleStream.is_open(), true);
1324 ASSERT_NO_FATAL_FAILURE(encodeNFrames(
1325 omxNode, observer, kPortIndexInput, kPortIndexOutput, &iBuffer,
1326 &oBuffer, 1024, xFramerate, (nFrameWidth * nFrameHeight * 3) >> 1,
1327 eleStream, nullptr, false, true, producer, listener));
1328 eleStream.close();
1329 ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(omxNode, observer, &iBuffer,
1330 &oBuffer, true, listener));
1331 ASSERT_NO_FATAL_FAILURE(
1332 testEOS(omxNode, observer, &iBuffer, &oBuffer, false, eosFlag));
1333
1334 // set state to idle
1335 ASSERT_NO_FATAL_FAILURE(
1336 changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer));
1337 EXPECT_EQ(portDef.nBufferCountActual, listener->freeBuffers);
1338 // set state to executing
1339 ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded(omxNode, observer, &iBuffer, &oBuffer,
1340 kPortIndexInput, kPortIndexOutput, portMode));
1341
1342 returnval = producer->disconnect(
1343 NATIVE_WINDOW_API_CPU, IGraphicBufferProducer::DisconnectMode::API);
1344 ASSERT_EQ(returnval, 0);
1345 }
1346
1347 // Test end of stream
TEST_P(VideoEncHidlTest,EncodeTestEOS)1348 TEST_P(VideoEncHidlTest, EncodeTestEOS) {
1349 description("Test EOS");
1350 if (disableTest) return;
1351 android::hardware::media::omx::V1_0::Status status;
1352 uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
1353 status = setRole(omxNode, role_);
1354 ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1355 OMX_PORT_PARAM_TYPE params;
1356 status = getParam(omxNode, OMX_IndexParamVideoInit, ¶ms);
1357 if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
1358 ASSERT_EQ(params.nPorts, 2U);
1359 kPortIndexInput = params.nStartPortNumber;
1360 kPortIndexOutput = kPortIndexInput + 1;
1361 }
1362
1363 // Configure input port
1364 uint32_t nFrameWidth = 352;
1365 uint32_t nFrameHeight = 288;
1366 uint32_t xFramerate = (30U << 16);
1367 OMX_COLOR_FORMATTYPE eColorFormat = OMX_COLOR_FormatAndroidOpaque;
1368 setupRAWPort(omxNode, kPortIndexInput, nFrameWidth, nFrameHeight, 0,
1369 xFramerate, eColorFormat);
1370
1371 // CreateInputSurface
1372 EXPECT_TRUE(omx->createInputSurface(
1373 [&](android::hardware::media::omx::V1_0::Status _s,
1374 sp<IGraphicBufferProducer> const& _nl,
1375 sp<IGraphicBufferSource> const& _n2) {
1376 status = _s;
1377 producer = _nl;
1378 source = _n2;
1379 })
1380 .isOk());
1381 ASSERT_NE(producer, nullptr);
1382 ASSERT_NE(source, nullptr);
1383
1384 // setMaxDequeuedBufferCount
1385 int32_t returnval;
1386 int32_t value;
1387 producer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
1388 [&returnval, &value](int32_t _s, int32_t _n1) {
1389 returnval = _s;
1390 value = _n1;
1391 });
1392 ASSERT_EQ(returnval, 0);
1393 OMX_PARAM_PORTDEFINITIONTYPE portDef;
1394 status = getPortParam(omxNode, OMX_IndexParamPortDefinition,
1395 kPortIndexInput, &portDef);
1396 ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1397 ASSERT_EQ(::android::OK,
1398 producer->setMaxDequeuedBufferCount(portDef.nBufferCountActual));
1399
1400 // Connect :: Mock Producer Listener
1401 IGraphicBufferProducer::QueueBufferOutput qbo;
1402 sp<CodecProducerListener> listener =
1403 new CodecProducerListener(portDef.nBufferCountActual + value, value);
1404 producer->connect(
1405 listener, NATIVE_WINDOW_API_CPU, false,
1406 [&](int32_t _s, IGraphicBufferProducer::QueueBufferOutput const& _n1) {
1407 returnval = _s;
1408 qbo = _n1;
1409 });
1410 ASSERT_EQ(returnval, 0);
1411
1412 portDef.nBufferCountActual = portDef.nBufferCountActual + value;
1413 status = setPortParam(omxNode, OMX_IndexParamPortDefinition,
1414 kPortIndexInput, &portDef);
1415 ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1416
1417 // Do setInputSurface()
1418 // enable MetaMode on input port
1419 status = source->configure(
1420 omxNode, android::hardware::graphics::common::V1_0::Dataspace::UNKNOWN);
1421 ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1422
1423 // set port mode
1424 PortMode portMode[2];
1425 portMode[0] = PortMode::DYNAMIC_ANW_BUFFER;
1426 portMode[1] = PortMode::PRESET_BYTE_BUFFER;
1427 status = omxNode->setPortMode(kPortIndexInput, portMode[0]);
1428 ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1429 status = omxNode->setPortMode(kPortIndexOutput, portMode[1]);
1430 ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1431
1432 android::Vector<BufferInfo> iBuffer, oBuffer;
1433 // set state to idle
1434 ASSERT_NO_FATAL_FAILURE(
1435 changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer,
1436 kPortIndexInput, kPortIndexOutput, portMode));
1437 // set state to executing
1438 ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer));
1439
1440 // send EOS
1441 status = source->signalEndOfInputStream();
1442 ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1443 ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(omxNode, observer, &iBuffer,
1444 &oBuffer, true, listener));
1445 ASSERT_NO_FATAL_FAILURE(
1446 testEOS(omxNode, observer, &iBuffer, &oBuffer, false, eosFlag));
1447
1448 // set state to idle
1449 ASSERT_NO_FATAL_FAILURE(
1450 changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer));
1451 EXPECT_EQ(portDef.nBufferCountActual, listener->freeBuffers);
1452 // set state to executing
1453 ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded(omxNode, observer, &iBuffer, &oBuffer,
1454 kPortIndexInput, kPortIndexOutput, portMode));
1455
1456 returnval = producer->disconnect(
1457 NATIVE_WINDOW_API_CPU, IGraphicBufferProducer::DisconnectMode::API);
1458 ASSERT_EQ(returnval, 0);
1459 }
1460
1461 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VideoEncHidlTest);
1462 INSTANTIATE_TEST_SUITE_P(PerInstance, VideoEncHidlTest, testing::ValuesIn(kTestParameters),
1463 android::hardware::PrintInstanceTupleNameToString<>);
1464
main(int argc,char ** argv)1465 int main(int argc, char** argv) {
1466 kTestParameters = getTestParameters("video_encoder");
1467 ::testing::InitGoogleTest(&argc, argv);
1468
1469 // Set the resource directory based on command line args.
1470 // Test will fail to set up if the argument is not set.
1471 for (int i = 1; i < argc; i++) {
1472 if (strcmp(argv[i], "-P") == 0 && i < argc - 1) {
1473 sResourceDir = argv[i + 1];
1474 break;
1475 }
1476 }
1477
1478 return RUN_ALL_TESTS();
1479 }