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