1/* 2 * Copyright (c) 2022-2023 Shenzhen Kaihong DID Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "codec_hdi_encode.h" 17#include <hdf_base.h> 18#include <unistd.h> 19#include "codec_component_manager.h" 20#include "codec_omx_ext.h" 21 22using namespace std; 23using namespace OHOS; 24using namespace OHOS::HDI::Display::Buffer::V1_0; 25using namespace OHOS::HDI::Display::Composer::V1_0; 26#define HDF_LOG_TAG codec_omx_hdi_enc 27IDisplayBuffer *CodecHdiEncode::buffer_ = nullptr; 28 29namespace { 30 constexpr int32_t FRAME = 30 << 16; 31 constexpr int32_t BUFFER_COUNT = 10; 32 constexpr int32_t BITRATE = 3000000; 33 constexpr int32_t FD_SIZE = sizeof(int); 34 constexpr uint32_t MAX_WAIT_COUNT = 3; 35} 36 37#define AV_COLOR_FORMAT (OMX_COLOR_FORMATTYPE) CODEC_COLOR_FORMAT_RGBA8888 38 39static CodecHdiEncode *g_core = nullptr; 40CodecHdiEncode::CodecHdiEncode() 41{ 42 client_ = nullptr; 43 callback_ = nullptr; 44 omxMgr_ = nullptr; 45 exit_ = false; 46 useBufferHandle_ = false; 47 width_ = 0; 48 height_ = 0; 49 count_ = 0; 50 componentId_ = 0; 51 color_ = ColorFormat::YUV420SP; 52 codecMime_ = CodecMime::AVC; 53 omxColorFormat_ = OMX_COLOR_FormatYUV420SemiPlanar; 54} 55 56CodecHdiEncode::~CodecHdiEncode() 57{ 58 if (ioOut_.is_open()) { 59 ioOut_.close(); 60 } 61 if (ioIn_.is_open()) { 62 ioIn_.close(); 63 } 64} 65 66void CodecHdiEncode::WaitForStatusChanged() 67{ 68 unique_lock<mutex> autoLock(statusLock_); 69 statusCondition_.wait(autoLock); 70} 71 72void CodecHdiEncode::OnStatusChanged() 73{ 74 statusCondition_.notify_one(); 75} 76 77bool CodecHdiEncode::ReadOneFrame(char *buf, uint32_t &filledCount) 78{ 79 bool ret = false; 80 filledCount = ioIn_.read(buf, GetInputBufferSize()).gcount(); 81 if (ioIn_.eof()) { 82 ret = true; 83 } 84 return ret; 85} 86 87bool CodecHdiEncode::Init(CommandOpt &opt) 88{ 89 this->width_ = opt.width; 90 this->height_ = opt.height; 91 this->stride_ = AlignUp(width_); 92 this->useBufferHandle_ = opt.useBuffer; 93 HDF_LOGI("width[%{public}d], height[%{public}d]", width_, height_); 94 // gralloc init 95 codecMime_ = opt.codec; 96 97 buffer_ = IDisplayBuffer::Get(); 98 color_ = opt.colorForamt; 99 if (color_ == ColorFormat::RGBA8888) { 100 omxColorFormat_ = AV_COLOR_FORMAT; 101 } else if (color_ == ColorFormat::BGRA8888) { 102 omxColorFormat_ = OMX_COLOR_Format32bitBGRA8888; 103 } 104 ioIn_.open(opt.fileInput, std::ios_base::binary); 105 ioOut_.open(opt.fileOutput, std::ios_base::binary | std::ios_base::trunc); 106 if (!ioOut_.is_open() || !ioIn_.is_open()) { 107 HDF_LOGE("%{public}s:failed to open file %{public}s or %{public}s", __func__, opt.fileInput.c_str(), 108 opt.fileOutput.c_str()); 109 return false; 110 } 111 // Interface init 112 omxMgr_ = GetCodecComponentManager(); 113 callback_ = CodecCallbackTypeGet(nullptr); 114 if ((omxMgr_ == nullptr) || (callback_ == nullptr)) { 115 HDF_LOGE("%{public}s:omxMgr_ or callback_ is null", __func__); 116 return false; 117 } 118 // set the callback 119 callback_->EventHandler = &CodecHdiEncode::OnEvent; 120 callback_->EmptyBufferDone = &CodecHdiEncode::OnEmptyBufferDone; 121 callback_->FillBufferDone = &CodecHdiEncode::OnFillBufferDone; 122 123 // create a component 124 auto err = GetComponent(); 125 if (err != HDF_SUCCESS) { 126 HDF_LOGE("%{public}s failed to CreateComponent", __func__); 127 return false; 128 } 129 // get version 130 struct CompVerInfo verInfo; 131 (void)memset_s(&verInfo, sizeof(verInfo), 0, sizeof(verInfo)); 132 err = client_->GetComponentVersion(client_, &verInfo); 133 if (err != HDF_SUCCESS) { 134 HDF_LOGE("%{public}s failed to CreateComponent", __func__); 135 return false; 136 } 137 138 return true; 139} 140 141bool CodecHdiEncode::Configure() 142{ 143 if (client_ == nullptr) { 144 return false; 145 } 146 // set input width, height and COLOR, set output port width and height 147 if (ConfigPortDefine() != HDF_SUCCESS) { 148 HDF_LOGE("%{public}s ConfigPortDefine error", __func__); 149 return false; 150 } 151 if (ConfigBitMode() != HDF_SUCCESS) { 152 HDF_LOGE("%{public}s ConfigBitMode error", __func__); 153 return false; 154 } 155 if (CheckAndUseBufferHandle() != HDF_SUCCESS) { 156 HDF_LOGE("%{public}s ConfigUseBufferHandle error", __func__); 157 return false; 158 } 159 160 return true; 161} 162 163int32_t CodecHdiEncode::CheckAndUseBufferHandle() 164{ 165 if (!useBufferHandle_) { 166 return HDF_SUCCESS; 167 } 168 169 SupportBufferType param; 170 InitParamInOhos(param); 171 param.portIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_OUTPUT); 172 173 auto err = client_->GetParameter(client_, OMX_IndexParamSupportBufferType, reinterpret_cast<int8_t *>(¶m), 174 sizeof(param)); 175 HDF_LOGI( 176 "OMX_GetParameter:OMX_IndexParamSupportBufferType:PORT_INDEX_OUTPUT, err [%{public}x], bufferTypes[%{public}d]", 177 err, param.bufferTypes); 178 if (err != HDF_SUCCESS) { 179 return err; 180 } 181 InitParamInOhos(param); 182 param.portIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_INPUT); 183 err = client_->GetParameter(client_, OMX_IndexParamSupportBufferType, reinterpret_cast<int8_t *>(¶m), 184 sizeof(param)); 185 HDF_LOGI( 186 "OMX_GetParameter:OMX_IndexParamSupportBufferType:PORT_INDEX_INPUT, err [%{public}x], bufferTypes[%{public}d]", 187 err, param.bufferTypes); 188 if (err != HDF_SUCCESS) { 189 return err; 190 } 191 GetBufferHandleUsageParams usage; 192 InitParamInOhos(usage); 193 usage.portIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_INPUT); 194 err = client_->GetParameter(client_, OMX_IndexParamGetBufferHandleUsage, reinterpret_cast<int8_t *>(&usage), 195 sizeof(usage)); 196 HDF_LOGI("OMX_GetParameter:GetBufferHandleUsage:PORT_INDEX_INPUT, err [%{public}x], usage[%{public}" PRIu64 "]", 197 err, usage.usage); 198 if (err != HDF_SUCCESS) { 199 return err; 200 } 201 202 UseBufferType type; 203 InitParamInOhos(type); 204 type.portIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_INPUT); 205 type.bufferType = CODEC_BUFFER_TYPE_DYNAMIC_HANDLE; 206 err = client_->SetParameter(client_, OMX_IndexParamUseBufferType, reinterpret_cast<int8_t *>(&type), sizeof(type)); 207 HDF_LOGI("OMX_SetParameter:OMX_IndexParamUseBufferType:PORT_INDEX_INPUT, err [%{public}x]", err); 208 return err; 209} 210 211bool CodecHdiEncode::UseBuffers() 212{ 213 // command to IDLE 214 auto err = client_->SendCommand(client_, OMX_CommandStateSet, OMX_StateIdle, NULL, 0); 215 if (err != HDF_SUCCESS) { 216 HDF_LOGE("%{public}s failed to SendCommand with OMX_CommandStateSet:OMX_StateIdle", __func__); 217 return false; 218 } 219 220 // use buffer on input port 221 err = UseBufferOnPort(PortIndex::PORT_INDEX_INPUT); 222 if (err != HDF_SUCCESS) { 223 HDF_LOGE("%{public}s UseBufferOnPort PORT_INDEX_INPUT error", __func__); 224 return false; 225 } 226 227 // use buffer on output port 228 err = UseBufferOnPort(PortIndex::PORT_INDEX_OUTPUT); 229 if (err != HDF_SUCCESS) { 230 HDF_LOGE("%{public}s UseBufferOnPort PORT_INDEX_OUTPUT error", __func__); 231 return false; 232 } 233 234 if (useBufferHandle_ && CreateBufferHandle() != HDF_SUCCESS) { 235 HDF_LOGE("%{public}s CreateBufferHandle error", __func__); 236 return false; 237 } 238 239 // wait executing state 240 OMX_STATETYPE status; 241 err = client_->GetState(client_, &status); 242 if (err != HDF_SUCCESS) { 243 HDF_LOGE("%{public}s GetState err [%{public}x]", __func__, err); 244 return false; 245 } 246 247 // wait loaded 248 if (status != OMX_StateIdle) { 249 HDF_LOGI("Wait for OMX_StateLoaded status"); 250 this->WaitForStatusChanged(); 251 } else { 252 HDF_LOGI(" status is %{public}d", status); 253 } 254 return true; 255} 256 257int32_t CodecHdiEncode::UseBufferOnPort(PortIndex portIndex) 258{ 259 int bufferSize = 0; 260 int bufferCount = 0; 261 bool portEnable = false; 262 263 OMX_PARAM_PORTDEFINITIONTYPE param; 264 InitParam(param); 265 param.nPortIndex = static_cast<uint32_t>(portIndex); 266 auto err = 267 client_->GetParameter(client_, OMX_IndexParamPortDefinition, reinterpret_cast<int8_t *>(¶m), sizeof(param)); 268 if (err != HDF_SUCCESS) { 269 HDF_LOGE("%{public}s failed to GetParameter with OMX_IndexParamPortDefinition : portIndex[%{public}d]", 270 __func__, portIndex); 271 return err; 272 } 273 bufferSize = param.nBufferSize; 274 bufferCount = param.nBufferCountActual; 275 portEnable = param.bEnabled; 276 { 277 OMX_PARAM_BUFFERSUPPLIERTYPE param; 278 InitParam(param); 279 param.nPortIndex = static_cast<uint32_t>(portIndex); 280 err = client_->GetParameter(client_, OMX_IndexParamCompBufferSupplier, reinterpret_cast<int8_t *>(¶m), 281 sizeof(param)); 282 HDF_LOGI("param.eBufferSupplier[%{public}d] err [%{public}d]", param.eBufferSupplier, err); 283 } 284 if (portIndex == PortIndex::PORT_INDEX_INPUT) { 285 bufferSize = GetInputBufferSize(); 286 } else if (bufferSize == 0) { 287 bufferSize = width_ * height_; 288 HDF_LOGI("bufferSize[%{public}d], width[%{public}d], height[%{public}d]", bufferSize, width_, height_); 289 } 290 if (useBufferHandle_ && portIndex == PortIndex::PORT_INDEX_INPUT) { 291 err = UseDynaBuffer(bufferCount, bufferSize); 292 } else { 293 err = UseBufferOnPort(portIndex, bufferCount, bufferSize); 294 } 295 if (err != HDF_SUCCESS) { 296 return err; 297 } 298 // if port is disable, changed to enable 299 if (!portEnable) { 300 err = client_->SendCommand(client_, OMX_CommandPortEnable, static_cast<uint32_t>(portIndex), NULL, 0); 301 if (err != HDF_SUCCESS) { 302 HDF_LOGE("%{public}s SendCommand OMX_CommandPortEnable::PORT_INDEX_INPUT error", __func__); 303 return err; 304 } 305 } 306 return HDF_SUCCESS; 307} 308 309int32_t CodecHdiEncode::UseBufferOnPort(PortIndex portIndex, int bufferCount, int bufferSize) 310{ 311 if (bufferCount <= 0 || bufferSize <= 0) { 312 return HDF_ERR_INVALID_PARAM; 313 } 314 315 for (int i = 0; i < bufferCount; i++) { 316 auto omxBuffer = std::make_shared<OmxCodecBuffer>(); 317 omxBuffer->size = sizeof(OmxCodecBuffer); 318 omxBuffer->version.s.nVersionMajor = 1; 319 omxBuffer->bufferType = CODEC_BUFFER_TYPE_AVSHARE_MEM_FD; 320 int fd = AshmemCreate(0, bufferSize); 321 shared_ptr<Ashmem> spSharedMem = make_shared<Ashmem>(fd, bufferSize); 322 omxBuffer->bufferLen = FD_SIZE; 323 omxBuffer->buffer = reinterpret_cast<uint8_t *>(fd); 324 omxBuffer->allocLen = bufferSize; 325 omxBuffer->fenceFd = -1; 326 omxBuffer->pts = 0; 327 omxBuffer->flag = 0; 328 if (portIndex == PortIndex::PORT_INDEX_INPUT) { 329 omxBuffer->type = READ_ONLY_TYPE; 330 spSharedMem->MapReadAndWriteAshmem(); 331 } else { 332 omxBuffer->type = READ_WRITE_TYPE; 333 spSharedMem->MapReadOnlyAshmem(); 334 } 335 auto err = client_->UseBuffer(client_, static_cast<uint32_t>(portIndex), omxBuffer.get()); 336 if (err != HDF_SUCCESS) { 337 HDF_LOGE("%{public}s failed to UseBuffer with portIndex[%{public}d]", __func__, portIndex); 338 spSharedMem->UnmapAshmem(); 339 spSharedMem->CloseAshmem(); 340 spSharedMem = nullptr; 341 return err; 342 } 343 344 omxBuffer->bufferLen = 0; 345 HDF_LOGI("UseBuffer returned bufferID [%{public}d]", omxBuffer->bufferId); 346 347 auto bufferInfo = std::make_shared<BufferInfo>(); 348 bufferInfo->omxBuffer = omxBuffer; 349 bufferInfo->avSharedPtr = spSharedMem; 350 bufferInfo->portIndex = portIndex; 351 omxBuffers_.insert(std::make_pair(omxBuffer->bufferId, bufferInfo)); 352 if (portIndex == PortIndex::PORT_INDEX_INPUT) { 353 unUsedInBuffers_.push_back(omxBuffer->bufferId); 354 } else { 355 unUsedOutBuffers_.push_back(omxBuffer->bufferId); 356 } 357 } 358 return HDF_SUCCESS; 359} 360 361int32_t CodecHdiEncode::UseDynaBuffer(int bufferCount, int bufferSize) 362{ 363 if (bufferCount <= 0 || bufferSize <= 0) { 364 return HDF_ERR_INVALID_PARAM; 365 } 366 367 for (int i = 0; i < bufferCount; i++) { 368 auto omxBuffer = std::make_shared<OmxCodecBuffer>(); 369 omxBuffer->size = sizeof(OmxCodecBuffer); 370 omxBuffer->version.s.nVersionMajor = 1; 371 omxBuffer->bufferType = CODEC_BUFFER_TYPE_DYNAMIC_HANDLE; 372 omxBuffer->bufferLen = 0; 373 omxBuffer->buffer = nullptr; 374 omxBuffer->allocLen = bufferSize; 375 omxBuffer->fenceFd = -1; 376 omxBuffer->pts = 0; 377 omxBuffer->flag = 0; 378 379 auto err = client_->UseBuffer(client_, static_cast<uint32_t>(PortIndex::PORT_INDEX_INPUT), omxBuffer.get()); 380 if (err != HDF_SUCCESS) { 381 HDF_LOGE("%{public}s failed to UseBuffer with PORT_INDEX_INPUT", __func__); 382 return err; 383 } 384 385 omxBuffer->bufferLen = 0; 386 HDF_LOGI("UseBuffer returned bufferID [%{public}d]", omxBuffer->bufferId); 387 388 auto bufferInfo = std::make_shared<BufferInfo>(); 389 bufferInfo->omxBuffer = omxBuffer; 390 bufferInfo->portIndex = PortIndex::PORT_INDEX_INPUT; 391 omxBuffers_.insert(std::make_pair(omxBuffer->bufferId, bufferInfo)); 392 unUsedInBuffers_.push_back(omxBuffer->bufferId); 393 } 394 return HDF_SUCCESS; 395} 396 397void CodecHdiEncode::FreeBuffers() 398{ 399 // send command to loaded state 400 (void)client_->SendCommand(client_, OMX_CommandStateSet, OMX_StateLoaded, nullptr, 0); 401 402 // All the buffer must be released, otherwise the component will wait 403 auto iter = omxBuffers_.begin(); 404 while (iter != omxBuffers_.end()) { 405 auto bufferInfo = iter->second; 406 (void)client_->FreeBuffer(client_, static_cast<uint32_t>(bufferInfo->portIndex), bufferInfo->omxBuffer.get()); 407 iter = omxBuffers_.erase(iter); 408 } 409 unUsedInBuffers_.clear(); 410 unUsedOutBuffers_.clear(); 411 412 // wait loaded 413 OMX_STATETYPE status = OMX_StateLoaded; 414 int32_t tryCount = MAX_WAIT_COUNT; 415 do { 416 int32_t err = client_->GetState(client_, &status); 417 if (err != HDF_SUCCESS) { 418 HDF_LOGE("%s GetState error [%{public}x]", __func__, err); 419 break; 420 } 421 if (status != OMX_StateLoaded) { 422 HDF_LOGI("Wait for OMX_StateLoaded status"); 423 this->WaitForStatusChanged(); 424 } 425 tryCount--; 426 } while ((status != OMX_StateLoaded) && (tryCount > 0)); 427} 428 429void CodecHdiEncode::Release() 430{ 431 omxMgr_->DestroyComponent(componentId_); 432 CodecComponentTypeRelease(client_); 433 client_ = nullptr; 434 CodecComponentManagerRelease(); 435} 436 437bool CodecHdiEncode::FillAllTheBuffer() 438{ 439 for (auto bufferId : unUsedOutBuffers_) { 440 HDF_LOGI("fill bufferid [%{public}d]", bufferId); 441 auto iter = omxBuffers_.find(bufferId); 442 if (iter != omxBuffers_.end()) { 443 auto bufferInfo = iter->second; 444 auto err = client_->FillThisBuffer(client_, bufferInfo->omxBuffer.get()); 445 if (err != HDF_SUCCESS) { 446 HDF_LOGE("%{public}s FillThisBuffer error", __func__); 447 return false; 448 } 449 } 450 } 451 return true; 452} 453 454int CodecHdiEncode::GetFreeBufferId() 455{ 456 int bufferID = -1; 457 unique_lock<mutex> ulk(lockInputBuffers_); 458 size_t nSize = this->unUsedInBuffers_.size(); 459 if (nSize > 0) { 460 bufferID = unUsedInBuffers_.front(); 461 unUsedInBuffers_.pop_front(); 462 } 463 return bufferID; 464} 465 466void CodecHdiEncode::Run() 467{ 468 auto err = client_->SendCommand(client_, OMX_CommandStateSet, OMX_StateExecuting, NULL, 0); 469 if (err != HDF_SUCCESS) { 470 HDF_LOGE("%{public}s failed to SendCommand with OMX_CommandStateSet:OMX_StateIdle", __func__); 471 return; 472 } 473 auto t1 = std::chrono::system_clock::now(); 474 if (!FillAllTheBuffer()) { 475 HDF_LOGE("%{public}s FillAllTheBuffer error", __func__); 476 return; 477 } 478 bool endFlag = false; 479 while (!endFlag) { 480 int bufferID = GetFreeBufferId(); 481 if (this->exit_) { 482 break; 483 } 484 if (bufferID < 0) { 485 usleep(10000); // 10000: sleep time 10ms 486 continue; 487 } 488 auto iter = omxBuffers_.find(bufferID); 489 if (iter == omxBuffers_.end()) { 490 continue; 491 } 492 auto bufferInfo = iter->second; 493 if (!FillCodecBuffer(bufferInfo, endFlag)) { 494 break; 495 } 496 err = client_->EmptyThisBuffer(client_, bufferInfo->omxBuffer.get()); 497 if (err != HDF_SUCCESS) { 498 HDF_LOGE("%{public}s EmptyThisBuffer error", __func__); 499 return; 500 } 501 } 502 while (!this->exit_) { 503 usleep(10000); // 10000: sleep time 10ms 504 } 505 (void)client_->SendCommand(client_, OMX_CommandStateSet, OMX_StateIdle, NULL, 0); 506 auto t2 = std::chrono::system_clock::now(); 507 std::chrono::duration<double> diff = t2 - t1; 508 HDF_LOGI("encoder costtime %{public}f, count=%{public}d", diff.count(), count_); 509 return; 510} 511 512bool CodecHdiEncode::FillCodecBuffer(std::shared_ptr<BufferInfo> bufferInfo, bool &endFlag) 513{ 514 if (buffer_ == nullptr) { 515 HDF_LOGE("%{public}s buffer_ is null", __func__); 516 return false; 517 } 518 if (useBufferHandle_) { 519 int bufferHandleId = freeBufferHandles_.front(); 520 if (bufferHandleId < 0 || bufferHandleId >= BUFFER_COUNT) { 521 HDF_LOGE("%{public}s bufferHandleId [%{public}d]", __func__, bufferHandleId); 522 return false; 523 } 524 freeBufferHandles_.pop_front(); 525 bufferInfo->bufferHandleId = bufferHandleId; 526 BufferHandle *bufferHandle = bufferHandles_[bufferHandleId]; 527 if (bufferHandle != nullptr) { 528 buffer_->Mmap(*bufferHandle); 529 endFlag = 530 this->ReadOneFrame(reinterpret_cast<char *>(bufferHandle->virAddr), bufferInfo->omxBuffer->filledLen); 531 bufferInfo->omxBuffer->filledLen = bufferHandle->stride * bufferHandle->height; 532 buffer_->Unmap(*bufferHandle); 533 bufferInfo->omxBuffer->buffer = reinterpret_cast<uint8_t *>(bufferHandle); 534 bufferInfo->omxBuffer->bufferLen = 535 sizeof(BufferHandle) + sizeof(int32_t) * (bufferHandle->reserveFds + bufferHandle->reserveInts); 536 } 537 } else { 538 // read data from ashmem 539 void *sharedAddr = const_cast<void *>(bufferInfo->avSharedPtr->ReadFromAshmem(0, 0)); 540 endFlag = this->ReadOneFrame(reinterpret_cast<char *>(sharedAddr), bufferInfo->omxBuffer->filledLen); 541 } 542 bufferInfo->omxBuffer->offset = 0; 543 if (endFlag) { 544 bufferInfo->omxBuffer->flag = OMX_BUFFERFLAG_EOS; 545 } 546 547 return true; 548} 549 550int32_t CodecHdiEncode::CreateBufferHandle() 551{ 552 if (buffer_ == nullptr) { 553 HDF_LOGE("%{public}s buffer_ is null", __func__); 554 return HDF_ERR_INVALID_PARAM; 555 } 556 PixelFormat pixForamt = PIXEL_FMT_YCBCR_420_SP; 557 if (color_ == ColorFormat::RGBA8888) { 558 pixForamt = PIXEL_FMT_RGBA_8888; 559 } else if (color_ == ColorFormat::BGRA8888) { 560 pixForamt = PIXEL_FMT_BGRA_8888; 561 } 562 563 AllocInfo alloc = {.width = this->stride_, 564 .height = this->height_, 565 .usage = HBM_USE_CPU_READ | HBM_USE_CPU_WRITE | HBM_USE_MEM_DMA, 566 .format = pixForamt}; 567 568 int32_t err = HDF_SUCCESS; 569 for (size_t i = 0; i < BUFFER_COUNT; i++) { 570 BufferHandle *bufferHandle = nullptr; 571 err = buffer_->AllocMem(alloc, bufferHandle); 572 if (err != HDF_SUCCESS) { 573 HDF_LOGE("%{public}s AllocMem fail", __func__); 574 return err; 575 } 576 bufferHandles_.emplace(std::make_pair(i, bufferHandle)); 577 freeBufferHandles_.push_back(i); 578 } 579 return err; 580} 581 582int32_t CodecHdiEncode::OnEvent(struct CodecCallbackType *self, enum OMX_EVENTTYPE event, struct EventInfo *info) 583{ 584 HDF_LOGI("OnEvent: pAppData[%{public} " PRId64 "], eEvent [%{public}d], nData1[%{public}d]", info->appData, event, 585 info->data1); 586 if (event == OMX_EventCmdComplete) { 587 OMX_COMMANDTYPE cmd = static_cast<OMX_COMMANDTYPE>(info->data1); 588 if (OMX_CommandStateSet == cmd) { 589 HDF_LOGI("OMX_CommandStateSet reached"); 590 g_core->OnStatusChanged(); 591 } 592 } 593 return HDF_SUCCESS; 594} 595 596int32_t CodecHdiEncode::OnEmptyBufferDone(struct CodecCallbackType *self, int64_t appData, 597 const struct OmxCodecBuffer *buffer) 598{ 599 HDF_LOGI("OnEmptyBufferDone: pBuffer.bufferID [%{public}d]", buffer->bufferId); 600 return g_core->OnEmptyBufferDone(*buffer); 601} 602 603int32_t CodecHdiEncode::OnFillBufferDone(struct CodecCallbackType *self, int64_t appData, 604 const struct OmxCodecBuffer *buffer) 605{ 606 HDF_LOGI("OnFillBufferDone: pBuffer.bufferID [%{public}d]", buffer->bufferId); 607 return g_core->OnFillBufferDone(*buffer); 608} 609 610uint32_t CodecHdiEncode::GetInputBufferSize() 611{ 612 if (color_ == ColorFormat::YUV420SP) { 613 return (width_ * height_ * 3 / 2); // 3:byte alignment, 2:byte alignment 614 } else { 615 return (width_ * height_ * 4); // 4: byte alignment for RGBA or BGRA 616 } 617} 618 619int32_t CodecHdiEncode::OnEmptyBufferDone(const struct OmxCodecBuffer &buffer) 620{ 621 unique_lock<mutex> ulk(lockInputBuffers_); 622 unUsedInBuffers_.push_back(buffer.bufferId); 623 if (useBufferHandle_) { 624 auto bufferInfo = omxBuffers_[buffer.bufferId]; 625 freeBufferHandles_.push_back(bufferInfo->bufferHandleId); 626 } 627 628 return HDF_SUCCESS; 629} 630 631int32_t CodecHdiEncode::OnFillBufferDone(const struct OmxCodecBuffer &buffer) 632{ 633 if (exit_) { 634 return HDF_SUCCESS; 635 } 636 637 auto iter = omxBuffers_.find(buffer.bufferId); 638 if (iter == omxBuffers_.end() || !iter->second) { 639 return HDF_SUCCESS; 640 } 641 642 auto bufferInfo = iter->second; 643 void *addr = const_cast<void *>(bufferInfo->avSharedPtr->ReadFromAshmem(buffer.filledLen, buffer.offset)); 644 // save to file 645 ioOut_.write(static_cast<char *>(addr), buffer.filledLen); 646 ioOut_.flush(); 647 count_++; 648 if ((buffer.flag & static_cast<uint32_t>(OMX_BUFFERFLAG_EOS)) != 0) { 649 exit_ = true; 650 HDF_LOGI("OnFillBufferDone the END coming"); 651 return HDF_SUCCESS; 652 } 653 auto err = client_->FillThisBuffer(client_, bufferInfo->omxBuffer.get()); 654 if (err != HDF_SUCCESS) { 655 HDF_LOGE("FillThisBuffer error"); 656 return HDF_SUCCESS; 657 } 658 return HDF_SUCCESS; 659} 660 661int32_t CodecHdiEncode::ConfigPortDefine() 662{ 663 OMX_PARAM_PORTDEFINITIONTYPE param; 664 InitParam(param); 665 param.nPortIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_INPUT); 666 auto err = 667 client_->GetParameter(client_, OMX_IndexParamPortDefinition, reinterpret_cast<int8_t *>(¶m), sizeof(param)); 668 if (err != HDF_SUCCESS) { 669 HDF_LOGE("%{public}s failed to GetParameter with PORT_INDEX_INPUT, index is OMX_IndexParamPortDefinition", 670 __func__); 671 return err; 672 } 673 HDF_LOGI("PORT_INDEX_INPUT: eCompressionFormat = %{public}d, eColorFormat=%{public}d", 674 param.format.video.eCompressionFormat, param.format.video.eColorFormat); 675 param.format.video.nFrameWidth = width_; 676 param.format.video.nFrameHeight = height_; 677 param.format.video.nStride = stride_; 678 param.format.video.nSliceHeight = height_; 679 680 param.format.video.eColorFormat = omxColorFormat_; 681 err = 682 client_->SetParameter(client_, OMX_IndexParamPortDefinition, reinterpret_cast<int8_t *>(¶m), sizeof(param)); 683 if (err != HDF_SUCCESS) { 684 HDF_LOGE("%{public}s failed to SetParameter with PORT_INDEX_INPUT, index is OMX_IndexParamPortDefinition", 685 __func__); 686 return err; 687 } 688 689 InitParam(param); 690 param.nPortIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_OUTPUT); 691 err = 692 client_->GetParameter(client_, OMX_IndexParamPortDefinition, reinterpret_cast<int8_t *>(¶m), sizeof(param)); 693 if (err != HDF_SUCCESS) { 694 HDF_LOGE("%{public}s failed to GetParameter with PORT_INDEX_OUTPUT, index is OMX_IndexParamPortDefinition", 695 __func__); 696 return err; 697 } 698 HDF_LOGI("PORT_INDEX_OUTPUT eCompressionFormat = %{public}d, eColorFormat=%{public}d", 699 param.format.video.eCompressionFormat, param.format.video.eColorFormat); 700 param.format.video.nFrameWidth = width_; 701 param.format.video.nFrameHeight = height_; 702 param.format.video.nStride = stride_; 703 param.format.video.nSliceHeight = height_; 704 err = 705 client_->SetParameter(client_, OMX_IndexParamPortDefinition, reinterpret_cast<int8_t *>(¶m), sizeof(param)); 706 if (err != HDF_SUCCESS) { 707 HDF_LOGE("%{public}s failed to SetParameter with PORT_INDEX_OUTPUT, index is OMX_IndexParamPortDefinition", 708 __func__); 709 return err; 710 } 711 return HDF_SUCCESS; 712} 713int32_t CodecHdiEncode::GetComponent() 714{ 715 int32_t count = omxMgr_->GetComponentNum(); 716 if (count <= 0) { 717 HDF_LOGE("%{public}s: GetComponentNum ret %{public}d", __func__, count); 718 return HDF_FAILURE; 719 } 720 auto caps = std::make_unique<CodecCompCapability[]>(count); 721 auto err = omxMgr_->GetComponentCapabilityList(caps.get(), count); 722 if (err != HDF_SUCCESS) { 723 HDF_LOGE("%{public}s: GetComponentCapabilityList ret %{public}d", __func__, err); 724 return err; 725 } 726 std::string compName(""); 727 for (int32_t i = 0; i < count; i++) { 728 if (caps[i].type != VIDEO_ENCODER) { 729 continue; 730 } 731 if (((caps[i].role == MEDIA_ROLETYPE_VIDEO_AVC) && (codecMime_ == CodecMime::AVC)) || 732 ((caps[i].role == MEDIA_ROLETYPE_VIDEO_HEVC) && (codecMime_ == CodecMime::HEVC))) { 733 compName = caps[i].compName; 734 break; 735 } 736 } 737 if (compName.empty()) { 738 HDF_LOGE("%{public}s: role is unexpected ", __func__); 739 return HDF_FAILURE; 740 } 741 return omxMgr_->CreateComponent(&client_, &componentId_, compName.data(), reinterpret_cast<int64_t>(this), 742 callback_); 743} 744 745OMX_VIDEO_CODINGTYPE CodecHdiEncode::GetCompressFormat() 746{ 747 OMX_VIDEO_CODINGTYPE compressFmt = OMX_VIDEO_CodingAVC; 748 switch (codecMime_) { 749 case CodecMime::AVC: 750 compressFmt = OMX_VIDEO_CodingAVC; 751 break; 752 case CodecMime::HEVC: 753 compressFmt = (OMX_VIDEO_CODINGTYPE)CODEC_OMX_VIDEO_CodingHEVC; 754 break; 755 case CodecMime::MPEG4: 756 compressFmt = OMX_VIDEO_CodingMPEG4; 757 break; 758 case CodecMime::VP9: 759 compressFmt = (OMX_VIDEO_CODINGTYPE)CODEC_OMX_VIDEO_CodingVP9; 760 break; 761 default: 762 break; 763 } 764 return compressFmt; 765} 766int32_t CodecHdiEncode::ConfigBitMode() 767{ 768 OMX_VIDEO_PARAM_PORTFORMATTYPE param; 769 InitParam(param); 770 param.nPortIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_OUTPUT); 771 auto err = client_->GetParameter(client_, OMX_IndexParamVideoPortFormat, reinterpret_cast<int8_t *>(¶m), 772 sizeof(param)); 773 if (err != HDF_SUCCESS) { 774 HDF_LOGE("failed to GetParameter with PORT_INDEX_OUTPUT, index is OMX_IndexParamVideoPortFormat"); 775 return err; 776 } 777 HDF_LOGI("set Format PORT_INDEX_INPUT eCompressionFormat = %{public}d, eColorFormat=%{public}d", 778 param.eCompressionFormat, param.eColorFormat); 779 param.xFramerate = FRAME; 780 param.eCompressionFormat = GetCompressFormat(); 781 err = client_->SetParameter(client_, OMX_IndexParamVideoPortFormat, reinterpret_cast<int8_t *>(¶m), 782 sizeof(param)); 783 if (err != HDF_SUCCESS) { 784 HDF_LOGE("%{public}s failed to SetParameter with PORT_INDEX_INPUT, index is OMX_IndexParamVideoPortFormat", 785 __func__); 786 return err; 787 } 788 789 OMX_VIDEO_PARAM_BITRATETYPE biteType; 790 InitParam(biteType); 791 biteType.nPortIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_OUTPUT); 792 err = client_->GetParameter(client_, OMX_IndexParamVideoBitrate, reinterpret_cast<int8_t *>(&biteType), 793 sizeof(biteType)); 794 if (err != OMX_ErrorNone) { 795 HDF_LOGE("%{public}s OMX_GetParameter portindex = PORT_INDEX_OUTPUT, err[%{public}d]", __func__, err); 796 return err; 797 } 798 HDF_LOGI("get PORT_INDEX_OUTPUT:OMX_IndexParamVideoBitrate, bit_mode[%{public}d], biterate:[%{publicd}d]", 799 biteType.eControlRate, biteType.nTargetBitrate); 800 801 biteType.eControlRate = OMX_Video_ControlRateConstant; 802 biteType.nTargetBitrate = BITRATE; 803 err = client_->SetParameter(client_, OMX_IndexParamVideoBitrate, reinterpret_cast<int8_t *>(&biteType), 804 sizeof(biteType)); 805 if (err != HDF_SUCCESS) { 806 HDF_LOGE("%{public}s failed to SetParameter with PORT_INDEX_OUTPUT, index is OMX_IndexParamVideoPortFormat", 807 __func__); 808 return err; 809 } 810 return HDF_SUCCESS; 811} 812 813int main(int argc, char *argv[]) 814{ 815 CommandOpt opt; 816 CommandParse parse; 817 if (!parse.Parse(argc, argv, opt)) { 818 return 0; 819 } 820 821 if (g_core == nullptr) { 822 g_core = new CodecHdiEncode(); 823 } 824 825 if (!g_core->Init(opt)) { 826 delete g_core; 827 g_core = nullptr; 828 return HDF_FAILURE; 829 } 830 831 if (!g_core->Configure()) { 832 delete g_core; 833 g_core = nullptr; 834 return HDF_FAILURE; 835 } 836 837 if (!g_core->UseBuffers()) { 838 delete g_core; 839 g_core = nullptr; 840 return HDF_FAILURE; 841 } 842 843 g_core->Run(); 844 845 g_core->FreeBuffers(); 846 847 g_core->Release(); 848 delete g_core; 849 g_core = nullptr; 850}