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