1/* 2 * Copyright 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_decode.h" 17#include <securec.h> 18#include <unistd.h> 19#include "codec_omx_ext.h" 20#include "hdf_log.h" 21#include "v1_0/display_composer_type.h" 22#include "v1_0/display_buffer_type.h" 23#include "v1_0/include/idisplay_buffer.h" 24using namespace std; 25using namespace OHOS; 26using OHOS::sptr; 27using OHOS::HDI::Base::NativeBuffer; 28using namespace OHOS::HDI::Codec::V3_0; 29using namespace OHOS::HDI::Display::Buffer::V1_0; 30using namespace OHOS::HDI::Display::Composer::V1_0; 31#define HDF_LOG_TAG codec_omx_hdi_dec 32#define AV_COLOR_FORMAT OMX_COLOR_FormatYUV420SemiPlanar 33IDisplayBuffer *CodecHdiDecode::gralloc_ = nullptr; 34CodecUtil *CodecHdiDecode::util_; 35namespace { 36constexpr int32_t FRAME = 30 << 16; 37constexpr int32_t DENOMINATOR = 2; 38constexpr int32_t NUMERATOR = 3; 39constexpr int32_t START_CODE_OFFSET_ONE = -1; 40constexpr int32_t INIT_BUFFER_CODE = -1; 41constexpr int32_t START_CODE_OFFSET_SEC = -2; 42constexpr int32_t START_CODE_OFFSET_THIRD = -3; 43constexpr int32_t START_CODE_SIZE_FRAME = 4; 44constexpr int32_t START_CODE_SIZE_SLICE = 3; 45constexpr char START_CODE = 0x1; 46} // namespace 47 48CodecHdiDecode::CodecHdiDecode() : fpIn_(nullptr), fpOut_(nullptr) 49{ 50 client_ = nullptr; 51 callback_ = nullptr; 52 omxMgr_ = nullptr; 53 exit_ = false; 54 width_ = 0; 55 height_ = 0; 56 codecMime_ = codecMime::AVC; 57 count_ = 0; 58 useBufferHandle_ = false; 59 useDMABuffer_ = false; 60 componentId_ = 0; 61} 62 63CodecHdiDecode::~CodecHdiDecode() 64{ 65 if (fpOut_ != nullptr) { 66 fclose(fpOut_); 67 fpOut_ = nullptr; 68 } 69 70 if (fpIn_ != nullptr) { 71 fclose(fpIn_); 72 fpIn_ = nullptr; 73 } 74} 75 76void CodecHdiDecode::WaitForStatusChanged() 77{ 78 unique_lock<mutex> autoLock(statusLock_); 79 statusCondition_.wait(autoLock); 80} 81 82void CodecHdiDecode::OnStatusChanged() 83{ 84 statusCondition_.notify_one(); 85} 86 87int CodecHdiDecode::GetYuvSize() 88{ 89 return width_ * height_ * NUMERATOR / DENOMINATOR; 90} 91 92bool CodecHdiDecode::ReadOnePacket(FILE *fp, char *buf, uint32_t &filledCount) 93{ 94 // read start code first 95 size_t t = fread(buf, 1, START_CODE_SIZE_FRAME, fp); 96 if (t < START_CODE_SIZE_FRAME) { 97 return true; 98 } 99 char *temp = buf; 100 temp += START_CODE_SIZE_FRAME; 101 bool ret = true; 102 while (!feof(fp)) { 103 (void)fread(temp, 1, 1, fp); 104 if (*temp != START_CODE) { 105 temp++; 106 continue; 107 } 108 // check start code 109 if ((temp[START_CODE_OFFSET_ONE] == 0) && (temp[START_CODE_OFFSET_SEC] == 0) && 110 (temp[START_CODE_OFFSET_THIRD] == 0)) { 111 fseek(fp, -START_CODE_SIZE_FRAME, SEEK_CUR); 112 temp -= (START_CODE_SIZE_FRAME - 1); 113 ret = false; 114 break; 115 } 116 if ((temp[START_CODE_OFFSET_ONE] == 0) && (temp[START_CODE_OFFSET_SEC] == 0)) { 117 fseek(fp, -START_CODE_SIZE_SLICE, SEEK_CUR); 118 temp -= (START_CODE_SIZE_SLICE - 1); 119 ret = false; 120 break; 121 } 122 temp++; 123 } 124 filledCount = (temp - buf); 125 return ret; 126} 127 128bool CodecHdiDecode::Init(const CommandOpt &opt) 129{ 130 this->width_ = opt.width; 131 this->height_ = opt.height; 132 this->codecMime_ = opt.codec; 133 this->stride_ = AlignUp(opt.width); 134 this->useBufferHandle_ = opt.useBufferHandle; 135 this->useDMABuffer_ = opt.useDMABuffer; 136 gralloc_ = IDisplayBuffer::Get(); 137 fpIn_ = fopen(opt.fileInput.c_str(), "rb"); 138 fpOut_ = fopen(opt.fileOutput.c_str(), "wb+"); 139 if ((fpIn_ == nullptr) || (fpOut_ == nullptr)) { 140 HDF_LOGE("%{public}s failed to open file", __func__); 141 return false; 142 } 143 omxMgr_ = ICodecComponentManager::Get(false); 144 if ((omxMgr_ == nullptr)) { 145 HDF_LOGE("%{public}s omxMgr_ is null", __func__); 146 return false; 147 } 148 callback_ = new CodecHdiCallback(shared_from_this()); 149 if ((callback_ == nullptr)) { 150 HDF_LOGE("%{public}s callback_ is null", __func__); 151 return false; 152 } 153 std::string compName(""); 154 int32_t err = GetComponentName(compName); 155 if (err != HDF_SUCCESS) { 156 HDF_LOGE("%{public}s GetComponentName err", __func__); 157 return false; 158 } 159 err = omxMgr_->CreateComponent(client_, componentId_, compName, reinterpret_cast<int64_t>(this), callback_); 160 if (err != HDF_SUCCESS) { 161 HDF_LOGE("%{public}s failed to CreateComponent", __func__); 162 return false; 163 } 164 struct CompVerInfo verInfo; 165 err = memset_s(&verInfo, sizeof(verInfo), 0, sizeof(verInfo)); 166 if (err != EOK) { 167 HDF_LOGE("%{public}s: memset_s verInfo err [%{public}d].", __func__, err); 168 return false; 169 } 170 err = client_->GetComponentVersion(verInfo); 171 if (err != HDF_SUCCESS) { 172 HDF_LOGE("%{public}s failed to CreateComponent", __func__); 173 return false; 174 } 175 return true; 176} 177 178int32_t CodecHdiDecode::ConfigPortDefine() 179{ 180 // set width and height on input port 181 OMX_PARAM_PORTDEFINITIONTYPE param; 182 if (util_->InitParam(param) != HDF_SUCCESS) { 183 return HDF_FAILURE; 184 } 185 param.nPortIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_INPUT); 186 187 std::vector<int8_t> inVec, outVec; 188 util_->ObjectToVector(param, inVec); 189 auto err = client_->GetParameter(OMX_IndexParamPortDefinition, inVec, outVec); 190 if (err != HDF_SUCCESS) { 191 HDF_LOGE("%{public}s failed PortIndex::PORT_INDEX_INPUT, index is OMX_IndexParamPortDefinition", __func__); 192 return err; 193 } 194 util_->VectorToObject(outVec, param); 195 196 HDF_LOGI("PortIndex::PORT_INDEX_INPUT: eCompressionFormat = %{public}d, eColorFormat = %{public}d ", 197 param.format.video.eCompressionFormat, param.format.video.eColorFormat); 198 util_->setParmValue(param, width_, height_, stride_); 199 util_->ObjectToVector(param, inVec); 200 err = client_->SetParameter(OMX_IndexParamPortDefinition, inVec); 201 if (err != HDF_SUCCESS) { 202 HDF_LOGE("%{public}s failed with PortIndex::PORT_INDEX_INPUT, index is OMX_IndexParamPortDefinition", __func__); 203 return err; 204 } 205 206 // set width, height and color format on output port 207 if (util_->InitParam(param) != HDF_SUCCESS) { 208 return HDF_FAILURE; 209 } 210 param.nPortIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_OUTPUT); 211 util_->ObjectToVector(param, inVec); 212 err = client_->GetParameter(OMX_IndexParamPortDefinition, inVec, outVec); 213 if (err != HDF_SUCCESS) { 214 HDF_LOGE("%{public}s failed with PortIndex::PORT_INDEX_OUTPUT, index is OMX_IndexParamPortDefinition", 215 __func__); 216 return err; 217 } 218 util_->VectorToObject(outVec, param); 219 220 HDF_LOGI("PortIndex::PORT_INDEX_OUTPUT eCompressionFormat = %{public}d, eColorFormat=%{public}d", 221 param.format.video.eCompressionFormat, param.format.video.eColorFormat); 222 util_->setParmValue(param, width_, height_, stride_); 223 param.format.video.eColorFormat = AV_COLOR_FORMAT; // YUV420SP 224 util_->ObjectToVector(param, inVec); 225 err = client_->SetParameter(OMX_IndexParamPortDefinition, inVec); 226 if (err != HDF_SUCCESS) { 227 HDF_LOGE("%{public}s failed with PortIndex::PORT_INDEX_OUTPUT, index is OMX_IndexParamPortDefinition", 228 __func__); 229 return err; 230 } 231 232 return err; 233} 234bool CodecHdiDecode::Configure() 235{ 236 if (ConfigPortDefine() != HDF_SUCCESS) { 237 return false; 238 } 239 240 OMX_VIDEO_PARAM_PORTFORMATTYPE param; 241 if (util_->InitParam(param) != HDF_SUCCESS) { 242 return false; 243 } 244 param.nPortIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_INPUT); 245 std::vector<int8_t> inVec, outVec; 246 util_->ObjectToVector(param, inVec); 247 auto err = client_->GetParameter(OMX_IndexParamVideoPortFormat, inVec, outVec); 248 if (err != HDF_SUCCESS) { 249 HDF_LOGE("%{public}s failed with PortIndex::PORT_INDEX_INPUT", __func__); 250 return false; 251 } 252 util_->VectorToObject(outVec, param); 253 254 HDF_LOGI("set Format PortIndex::PORT_INDEX_INPUT eCompressionFormat = %{public}d, eColorFormat=%{public}d", 255 param.eCompressionFormat, param.eColorFormat); 256 param.xFramerate = FRAME; // 30fps,Q16 format 257 if (codecMime_ == codecMime::AVC) { 258 param.eCompressionFormat = OMX_VIDEO_CodingAVC; // H264 259 } else { 260 param.eCompressionFormat = static_cast<OMX_VIDEO_CODINGTYPE>(CODEC_OMX_VIDEO_CodingHEVC); // H265 261 } 262 263 util_->ObjectToVector(param, inVec); 264 err = client_->SetParameter(OMX_IndexParamVideoPortFormat, inVec); 265 if (err != HDF_SUCCESS) { 266 HDF_LOGE("%{public}s failed with PortIndex::PORT_INDEX_INPUT", __func__); 267 return false; 268 } 269 270 err = CheckAndUseBufferHandle(); 271 if (err != HDF_SUCCESS) { 272 HDF_LOGE("%{public}s failed with CheckAndUseBufferHandle", __func__); 273 return false; 274 } 275 276 err = CheckAndUseDMABuffer(); 277 if (err != HDF_SUCCESS) { 278 HDF_LOGE("%{public}s failed with CheckAndUseDMABuffer", __func__); 279 return false; 280 } 281 return true; 282} 283 284int32_t CodecHdiDecode::CheckSupportBufferType(PortIndex portIndex, CodecBufferType codecBufferType) 285{ 286 //get support buffer 287 SupportBufferType param; 288 std::vector<int8_t> inVec, outVec; 289 if (util_->InitParamInOhos(param) != HDF_SUCCESS) { 290 return HDF_FAILURE; 291 } 292 param.portIndex = static_cast<uint32_t>(portIndex); 293 294 util_->ObjectToVector(param, inVec); 295 auto err = client_->GetParameter(OMX_IndexParamSupportBufferType, inVec, outVec); 296 if (err != HDF_SUCCESS) { 297 HDF_LOGE("%{public}s failed get parameter with portIndex %{public}d and ret %{public}d ", 298 __func__, portIndex, err); 299 } 300 util_->VectorToObject(outVec, param); 301 if (!(param.bufferTypes & codecBufferType)) { 302 HDF_LOGE("%{public}s unSupport bufferType %{public}d ,ret is %{public}d", 303 __func__, codecBufferType, param.bufferTypes); 304 return HDF_FAILURE; 305 } 306 return HDF_SUCCESS; 307} 308 309int32_t CodecHdiDecode::CheckAndUseDMABuffer() 310{ 311 if (!useDMABuffer_) { 312 return HDF_SUCCESS; 313 } 314 return CheckSupportBufferType(PortIndex::PORT_INDEX_INPUT, CODEC_BUFFER_TYPE_DMA_MEM_FD); 315} 316 317int32_t CodecHdiDecode::CheckAndUseBufferHandle() 318{ 319 if (!useBufferHandle_) { 320 return HDF_SUCCESS; 321 } 322 SupportBufferType param; 323 if (util_->InitParamInOhos(param) != HDF_SUCCESS) { 324 return HDF_FAILURE; 325 } 326 param.portIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_INPUT); 327 std::vector<int8_t> inVec, outVec; 328 util_->ObjectToVector(param, inVec); 329 auto err = client_->GetParameter(OMX_IndexParamSupportBufferType, inVec, outVec); 330 if (err != HDF_SUCCESS) { 331 HDF_LOGE("OMX_GetParameter OMX_IndexParamSupportBufferType in err [%{public}x]", err); 332 return err; 333 } 334 util_->VectorToObject(outVec, param); 335 336 if (util_->InitParamInOhos(param) != HDF_SUCCESS) { 337 return HDF_FAILURE; 338 } 339 param.portIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_OUTPUT); 340 util_->ObjectToVector(param, inVec); 341 err = client_->GetParameter(OMX_IndexParamSupportBufferType, inVec, outVec); 342 if (err != HDF_SUCCESS) { 343 HDF_LOGE("OMX_GetParameter OMX_IndexParamSupportBufferType out err [%{public}x]", err); 344 return err; 345 } 346 util_->VectorToObject(outVec, param); 347 348 GetBufferHandleUsageParams usage; 349 if (util_->InitParamInOhos(usage) != HDF_SUCCESS) { 350 return HDF_FAILURE; 351 } 352 usage.portIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_OUTPUT); 353 util_->ObjectToVector(usage, inVec); 354 err = client_->GetParameter(OMX_IndexParamGetBufferHandleUsage, inVec, outVec); 355 if (err != HDF_SUCCESS) { 356 HDF_LOGE("OMX_GetParameter OMX_IndexParamGetBufferHandleUsage out err [%{public}x]", err); 357 return err; 358 } 359 util_->VectorToObject(outVec, usage); 360 361 UseBufferType type; 362 if (util_->InitParamInOhos(type) != HDF_SUCCESS) { 363 return HDF_FAILURE; 364 } 365 type.portIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_OUTPUT); 366 type.bufferType = CODEC_BUFFER_TYPE_HANDLE; 367 util_->ObjectToVector(type, inVec); 368 err = client_->SetParameter(OMX_IndexParamUseBufferType, inVec); 369 if (err != HDF_SUCCESS) { 370 HDF_LOGE("OMX_SetParameter OMX_IndexParamUseBufferType out, err [%{public}x]", err); 371 return err; 372 } 373 return err; 374} 375 376bool CodecHdiDecode::UseBuffers() 377{ 378 HDF_LOGI("...command to IDLE...."); 379 std::vector<int8_t> cmdData; 380 auto err = client_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_IDLE, cmdData); 381 if (err != HDF_SUCCESS) { 382 HDF_LOGE("%{public}s failed to SendCommand with CODEC_COMMAND_STATE_SET:CODEC_STATE_IDLE", __func__); 383 return false; 384 } 385 386 err = UseBufferOnPort(PortIndex::PORT_INDEX_INPUT); 387 if (err != HDF_SUCCESS) { 388 HDF_LOGE("%{public}s UseBufferOnPort PortIndex::PORT_INDEX_INPUT error", __func__); 389 return false; 390 } 391 392 err = UseBufferOnPort(PortIndex::PORT_INDEX_OUTPUT); 393 if (err != HDF_SUCCESS) { 394 HDF_LOGE("%{public}s UseBufferOnPort PortIndex::PORT_INDEX_OUTPUT error", __func__); 395 return false; 396 } 397 398 HDF_LOGI("Wait for CODEC_STATE_IDLE status"); 399 CodecStateType status = CODEC_STATE_INVALID; 400 err = client_->GetState(status); 401 if (err != HDF_SUCCESS) { 402 HDF_LOGE("%{public}s GetState err [%{public}x]", __func__, err); 403 return false; 404 } 405 if (status != CODEC_STATE_IDLE) { 406 HDF_LOGI("Wait for CODEC_STATE_LOADED status"); 407 this->WaitForStatusChanged(); 408 } else { 409 HDF_LOGI(" status is %{public}d", status); 410 } 411 412 return true; 413} 414 415int32_t CodecHdiDecode::UseBufferOnPort(PortIndex portIndex, int bufferCount, int bufferSize) 416{ 417 if (bufferCount <= 0 || bufferSize <= 0) { 418 HDF_LOGE("UseBufferOnPort bufferCount <= 0 or bufferSize <= 0"); 419 return HDF_ERR_INVALID_PARAM; 420 } 421 for (int i = 0; i < bufferCount; i++) { 422 std::shared_ptr<OmxCodecBuffer> omxBuffer = std::make_shared<OmxCodecBuffer>(); 423 omxBuffer->size = sizeof(OmxCodecBuffer); 424 omxBuffer->version.version.majorVersion = 1; 425 omxBuffer->bufferType = CODEC_BUFFER_TYPE_AVSHARE_MEM_FD; 426 int fd = AshmemCreate(0, bufferSize); 427 shared_ptr<Ashmem> sharedMem = make_shared<Ashmem>(fd, bufferSize); 428 omxBuffer->fd = fd; 429 omxBuffer->bufferhandle = nullptr; 430 omxBuffer->allocLen = bufferSize; 431 omxBuffer->fenceFd = -1; 432 omxBuffer->pts = 0; 433 omxBuffer->flag = 0; 434 435 if (portIndex == PortIndex::PORT_INDEX_INPUT) { 436 omxBuffer->type = READ_ONLY_TYPE; 437 sharedMem->MapReadAndWriteAshmem(); 438 } else { 439 omxBuffer->type = READ_WRITE_TYPE; 440 sharedMem->MapReadOnlyAshmem(); 441 } 442 OmxCodecBuffer outBuffer; 443 auto err = client_->UseBuffer(static_cast<uint32_t>(portIndex), *omxBuffer.get(), outBuffer); 444 if (err != HDF_SUCCESS) { 445 HDF_LOGE("%{public}s failed to UseBuffer with portIndex[%{public}d]", __func__, portIndex); 446 sharedMem->UnmapAshmem(); 447 sharedMem->CloseAshmem(); 448 sharedMem = nullptr; 449 return err; 450 } 451 omxBuffer->bufferId = outBuffer.bufferId; 452 omxBuffer->fd = -1; 453 HDF_LOGI("UseBuffer returned bufferID [%{public}d]", omxBuffer->bufferId); 454 455 std::shared_ptr<BufferInfo> bufferInfo = std::make_shared<BufferInfo>(); 456 bufferInfo->omxBuffer = omxBuffer; 457 bufferInfo->avSharedPtr = sharedMem; 458 bufferInfo->portIndex = portIndex; 459 omxBuffers_.emplace(std::make_pair(omxBuffer->bufferId, bufferInfo)); 460 if (portIndex == PortIndex::PORT_INDEX_INPUT) { 461 unUsedInBuffers_.push_back(omxBuffer->bufferId); 462 } else { 463 unUsedOutBuffers_.push_back(omxBuffer->bufferId); 464 } 465 } 466 467 return HDF_SUCCESS; 468} 469 470int32_t CodecHdiDecode::UseBufferOnPort(PortIndex portIndex) 471{ 472 HDF_LOGI("%{public}s enter, portIndex = %{public}d", __func__, portIndex); 473 int bufferSize = 0; 474 int bufferCount = 0; 475 bool portEnable = false; 476 477 OMX_PARAM_PORTDEFINITIONTYPE param; 478 if (util_->InitParam(param) != HDF_SUCCESS) { 479 return HDF_FAILURE; 480 } 481 param.nPortIndex = static_cast<OMX_U32>(portIndex); 482 483 std::vector<int8_t> inVec, outVec; 484 util_->ObjectToVector(param, inVec); 485 auto err = client_->GetParameter(OMX_IndexParamPortDefinition, inVec, outVec); 486 if (err != HDF_SUCCESS) { 487 HDF_LOGE("%{public}s failed to GetParameter with OMX_IndexParamPortDefinition : portIndex[%{public}d]", 488 __func__, portIndex); 489 return err; 490 } 491 util_->VectorToObject(outVec, param); 492 493 bufferSize = param.nBufferSize; 494 bufferCount = param.nBufferCountActual; 495 portEnable = param.bEnabled; 496 HDF_LOGI("buffer index [%{public}d], buffer size [%{public}d], " 497 "buffer count [%{public}d], portEnable[%{public}d], ret [%{public}d]", 498 portIndex, bufferSize, bufferCount, portEnable, err); 499 if (useBufferHandle_ && portIndex == PortIndex::PORT_INDEX_OUTPUT) { 500 err = UseBufferHandle(bufferCount, bufferSize); 501 } else if (useDMABuffer_ && portIndex == PortIndex::PORT_INDEX_INPUT) { 502 err = UseDMABuffer(portIndex, bufferCount, bufferSize); 503 } else { 504 err = UseBufferOnPort(portIndex, bufferCount, bufferSize); 505 } 506 507 if (err != HDF_SUCCESS) { 508 HDF_LOGE("%{public}s UseBufferOnPort err[%{public}x]", __func__, err); 509 return err; 510 } 511 // set port enable 512 if (!portEnable) { 513 err = client_->SendCommand(CODEC_COMMAND_PORT_ENABLE, static_cast<uint32_t>(portIndex), {}); 514 if (err != HDF_SUCCESS) { 515 HDF_LOGE("%{public}s SendCommand OMX_CommandPortEnable::PortIndex::PORT_INDEX_INPUT error", __func__); 516 return err; 517 } 518 } 519 return HDF_SUCCESS; 520} 521 522int32_t CodecHdiDecode::UseDMABuffer(PortIndex portIndex, int bufferCount, int bufferSize) 523{ 524 if (bufferCount <= 0 || bufferSize <= 0) { 525 HDF_LOGE("UseDMABuffer bufferCount <= 0 or bufferSize <= 0"); 526 return HDF_ERR_INVALID_PARAM; 527 } 528 for (int i = 0; i < bufferCount; i++) { 529 std::shared_ptr<OmxCodecBuffer> omxBuffer = std::make_shared<OmxCodecBuffer>(); 530 omxBuffer->size = sizeof(OmxCodecBuffer); 531 omxBuffer->version.version.majorVersion = 1; 532 omxBuffer->bufferType = CODEC_BUFFER_TYPE_DMA_MEM_FD; 533 omxBuffer->fd = INIT_BUFFER_CODE; 534 omxBuffer->bufferhandle = nullptr; 535 omxBuffer->allocLen = bufferSize; 536 omxBuffer->fenceFd = INIT_BUFFER_CODE; 537 omxBuffer->pts = 0; 538 omxBuffer->flag = 0; 539 omxBuffer->type = READ_WRITE_TYPE; 540 541 OmxCodecBuffer outBuffer; 542 auto err = client_->AllocateBuffer(static_cast<uint32_t>(portIndex), *omxBuffer.get(), outBuffer); 543 if (err != HDF_SUCCESS) { 544 HDF_LOGE("%{public}s failed to UseBuffer with portIndex[%{public}d]", __func__, portIndex); 545 return err; 546 } 547 omxBuffer->bufferId = outBuffer.bufferId; 548 HDF_LOGI("UseBuffer returned bufferID [%{public}d]", omxBuffer->bufferId); 549 550 std::shared_ptr<BufferInfo> bufferInfo = std::make_shared<BufferInfo>(); 551 bufferInfo->omxBuffer = omxBuffer; 552 bufferInfo->portIndex = portIndex; 553 bufferInfo->omxBuffer->fd = outBuffer.fd; 554 omxBuffers_.insert(std::make_pair(omxBuffer->bufferId, bufferInfo)); 555 unUsedInBuffers_.push_back(omxBuffer->bufferId); 556 557 void *addr = mmap(nullptr, static_cast<size_t>(bufferInfo->omxBuffer->allocLen), 558 PROT_READ | PROT_WRITE, MAP_SHARED, bufferInfo->omxBuffer->fd, 0); 559 if (addr == nullptr) { 560 HDF_LOGE("%{public}s mmap fail fd %{public}d", __func__, omxBuffer->fd); 561 return HDF_FAILURE; 562 } else { 563 addrs_[omxBuffer->bufferId] = addr; 564 } 565 } 566 return HDF_SUCCESS; 567} 568 569int32_t CodecHdiDecode::UseBufferHandle(int bufferCount, int bufferSize) 570{ 571 if (bufferCount <= 0 || bufferSize <= 0 || gralloc_ == nullptr) { 572 return HDF_ERR_INVALID_PARAM; 573 } 574 AllocInfo alloc = {.width = this->stride_, 575 .height = this->height_, 576 .usage = HBM_USE_CPU_READ | HBM_USE_CPU_WRITE | HBM_USE_MEM_DMA, 577 .format = PIXEL_FMT_YCBCR_420_SP}; 578 for (int i = 0; i < bufferCount; i++) { 579 std::shared_ptr<OmxCodecBuffer> omxBuffer = std::make_shared<OmxCodecBuffer>(); 580 omxBuffer->size = sizeof(OmxCodecBuffer); 581 omxBuffer->version.version.majorVersion = 1; 582 omxBuffer->bufferType = CODEC_BUFFER_TYPE_HANDLE; 583 BufferHandle *bufferHandle = nullptr; 584 int32_t err = gralloc_->AllocMem(alloc, bufferHandle); 585 HDF_LOGI("%{public}s AlloceMem ret val ret[%{public}d]", __func__, err); 586 if (DISPLAY_SUCCESS != err) { 587 HDF_LOGE("%{public}s AllocMem error", __func__); 588 return err; 589 } 590 omxBuffer->fd = -1; 591 omxBuffer->allocLen = bufferSize; 592 omxBuffer->fenceFd = -1; // check use -1 first with no window 593 omxBuffer->pts = 0; 594 omxBuffer->flag = 0; 595 omxBuffer->bufferhandle = new NativeBuffer(bufferHandle); 596 OmxCodecBuffer outBuffer; 597 err = client_->UseBuffer(static_cast<uint32_t>(PortIndex::PORT_INDEX_OUTPUT), 598 *omxBuffer.get(), outBuffer); 599 omxBuffer->bufferhandle = nullptr; 600 if (err != HDF_SUCCESS) { 601 HDF_LOGE("%{public}s failed to UseBuffer with output port]", __func__); 602 return err; 603 } 604 omxBuffer->bufferId = outBuffer.bufferId; 605 HDF_LOGI("UseBuffer returned bufferID [%{public}d]", omxBuffer->bufferId); 606 607 std::shared_ptr<BufferInfo> bufferInfo = std::make_shared<BufferInfo>(); 608 bufferInfo->omxBuffer = omxBuffer; 609 bufferInfo->setBufferHandle(bufferHandle); 610 bufferInfo->portIndex = PortIndex::PORT_INDEX_OUTPUT; 611 omxBuffers_.emplace(std::make_pair(omxBuffer->bufferId, bufferInfo)); 612 unUsedOutBuffers_.push_back(omxBuffer->bufferId); 613 } 614 return HDF_SUCCESS; 615} 616 617void CodecHdiDecode::FreeBuffers() 618{ 619 // command to loaded 620 (void)client_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_LOADED, {}); 621 622 // release all the buffers 623 auto iter = omxBuffers_.begin(); 624 while (iter != omxBuffers_.end()) { 625 auto bufferInfo = iter->second; 626 iter = omxBuffers_.erase(iter); 627 (void)client_->FreeBuffer(static_cast<uint32_t>(bufferInfo->portIndex), *bufferInfo->omxBuffer.get()); 628 bufferInfo = nullptr; 629 } 630 631 unUsedInBuffers_.clear(); 632 unUsedOutBuffers_.clear(); 633 634 CodecStateType status = CODEC_STATE_INVALID; 635 int32_t tryCount = 3; 636 do { 637 int32_t err = client_->GetState(status); 638 if (err != HDF_SUCCESS) { 639 HDF_LOGE("%s GetState error [%{public}x]", __func__, err); 640 break; 641 } 642 if (status != CODEC_STATE_LOADED) { 643 HDF_LOGI("Wait for OMX_StateLoaded status"); 644 this->WaitForStatusChanged(); 645 } 646 tryCount--; 647 } while ((status != CODEC_STATE_LOADED) && (tryCount > 0)); 648} 649 650void CodecHdiDecode::Release() 651{ 652 omxMgr_->DestroyComponent(componentId_); 653 client_ = nullptr; 654 callback_ = nullptr; 655 omxMgr_ = nullptr; 656} 657 658bool CodecHdiDecode::FillAllTheBuffer() 659{ 660 for (auto bufferId : unUsedOutBuffers_) { 661 HDF_LOGI("fillThisBUffer, bufferid [%{public}d]", bufferId); 662 auto iter = omxBuffers_.find(bufferId); 663 if (iter != omxBuffers_.end()) { 664 auto bufferInfo = iter->second; 665 auto buffer = bufferInfo->omxBuffer.get(); 666 auto err = client_->FillThisBuffer(*buffer); 667 if (err != HDF_SUCCESS) { 668 HDF_LOGE("%{public}s FillThisBuffer error", __func__); 669 return false; 670 } 671 } 672 } 673 return true; 674} 675 676int CodecHdiDecode::GetFreeBufferId() 677{ 678 int bufferID = -1; 679 unique_lock<mutex> ulk(lockInputBuffers_); 680 size_t nSize = this->unUsedInBuffers_.size(); 681 if (nSize != 0) { 682 bufferID = unUsedInBuffers_.front(); 683 unUsedInBuffers_.pop_front(); 684 } 685 return bufferID; 686} 687 688int32_t CodecHdiDecode::GetComponentName(std::string &compName) 689{ 690 AvCodecRole role = AvCodecRole::MEDIA_ROLETYPE_VIDEO_AVC; 691 if (codecMime_ == codecMime::HEVC) { 692 role = AvCodecRole::MEDIA_ROLETYPE_VIDEO_HEVC; 693 } 694 695 int32_t count = 0; 696 auto err = omxMgr_->GetComponentNum(count); 697 if (err != HDF_SUCCESS || count <= 0) { 698 HDF_LOGE("%{public}s GetComponentNum return %{public}d, count = %{public}d", __func__, err, count); 699 return HDF_FAILURE; 700 } 701 std::vector<CodecCompCapability> caps; 702 err = omxMgr_->GetComponentCapabilityList(caps, count); 703 if (err != HDF_SUCCESS) { 704 HDF_LOGE("%{public}s GetComponentCapabilityList return %{public}d", __func__, err); 705 return err; 706 } 707 err = HDF_FAILURE; 708 for (auto cap : caps) { 709 if (cap.type == CodecType::VIDEO_DECODER && cap.role == role) { 710 compName = cap.compName; 711 err = HDF_SUCCESS; 712 break; 713 } 714 } 715 return err; 716} 717void CodecHdiDecode::Run() 718{ 719 HDF_LOGI("...command to CODEC_STATE_EXECUTING...."); 720 auto err = client_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_EXECUTING, {}); 721 if (err != HDF_SUCCESS) { 722 HDF_LOGE("%{public}s failed to SendCommand with CODEC_COMMAND_STATE_SET:CODEC_STATE_IDLE", __func__); 723 return; 724 } 725 726 if (!FillAllTheBuffer()) { 727 HDF_LOGE("%{public}s FillAllTheBuffer error", __func__); 728 return; 729 } 730 731 auto t1 = std::chrono::system_clock::now(); 732 bool eosFlag = false; 733 while (!eosFlag) { 734 if (this->exit_) { 735 break; 736 } 737 int bufferID = GetFreeBufferId(); 738 if (bufferID < 0) { 739 usleep(10000); // 10000 for wait 10ms 740 continue; 741 } 742 auto iter = omxBuffers_.find(bufferID); 743 if (iter == omxBuffers_.end()) { 744 continue; 745 } 746 auto bufferInfo = iter->second; 747 748 if (!FillCodecBuffer(bufferInfo, eosFlag)) { 749 break; 750 } 751 if (eosFlag) { 752 bufferInfo->omxBuffer->flag = OMX_BUFFERFLAG_EOS; 753 } 754 err = client_->EmptyThisBuffer(*bufferInfo->omxBuffer.get()); 755 if (err != HDF_SUCCESS) { 756 HDF_LOGE("%{public}s EmptyThisBuffer error", __func__); 757 return; 758 } 759 } 760 // wait 761 while (!this->exit_) { 762 usleep(10000); // 10000 for wait 10ms 763 } 764 auto t2 = std::chrono::system_clock::now(); 765 std::chrono::duration<double> diff = t2 - t1; 766 HDF_LOGI("cost %{public}f, count=%{public}d", diff.count(), count_); 767 (void)client_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_IDLE, {}); 768 return; 769} 770 771bool CodecHdiDecode::FillCodecBuffer(std::shared_ptr<BufferInfo> bufferInfo, bool &eosFlag) 772{ 773 if (useDMABuffer_) { 774 auto ret = addrs_.find(bufferInfo->omxBuffer->bufferId); 775 if (ret != addrs_.end()) { 776 eosFlag = this->ReadOnePacket(fpIn_, static_cast<char *>(ret->second), bufferInfo->omxBuffer->filledLen); 777 bufferInfo->omxBuffer->offset = 0; 778 } 779 } else { 780 void *sharedAddr = const_cast<void *>(bufferInfo->avSharedPtr->ReadFromAshmem(0, 0)); 781 eosFlag = this->ReadOnePacket(fpIn_, static_cast<char *>(sharedAddr), bufferInfo->omxBuffer->filledLen); 782 bufferInfo->omxBuffer->offset = 0; 783 } 784 return true; 785} 786 787int32_t CodecHdiDecode::OnEmptyBufferDone(const struct OmxCodecBuffer &buffer) 788{ 789 HDF_LOGI("OnEmptyBufferDone, bufferId [%{public}d]", buffer.bufferId); 790 unique_lock<mutex> ulk(lockInputBuffers_); 791 unUsedInBuffers_.push_back(buffer.bufferId); 792 return HDF_SUCCESS; 793} 794 795int32_t CodecHdiDecode::OnFillBufferDone(const struct OmxCodecBuffer &buffer) 796{ 797 HDF_LOGI("OnFillBufferDone, bufferId [%{public}d]", buffer.bufferId); 798 if (exit_) { 799 return HDF_SUCCESS; 800 } 801 802 auto iter = omxBuffers_.find(buffer.bufferId); 803 if ((iter == omxBuffers_.end()) || (iter->second == nullptr)) { 804 return HDF_SUCCESS; 805 } 806 count_++; 807 // read buffer 808 auto bufferInfo = iter->second; 809 if (bufferInfo->avSharedPtr != nullptr) { 810 const void *addr = bufferInfo->avSharedPtr->ReadFromAshmem(buffer.filledLen, buffer.offset); 811 (void)fwrite(addr, 1, buffer.filledLen, fpOut_); 812 } else if (bufferInfo->bufferHandle != nullptr && gralloc_ != nullptr) { 813 gralloc_->Mmap(*bufferInfo->bufferHandle); 814 (void)fwrite(bufferInfo->bufferHandle->virAddr, 1, buffer.filledLen, fpOut_); 815 gralloc_->Unmap(*bufferInfo->bufferHandle); 816 } 817 818 (void)fflush(fpOut_); 819 if (buffer.flag == OMX_BUFFERFLAG_EOS) { 820 // end 821 exit_ = true; 822 HDF_LOGI("OnFillBufferDone the END coming"); 823 return HDF_SUCCESS; 824 } 825 // call fillthisbuffer again 826 auto err = client_->FillThisBuffer(*bufferInfo->omxBuffer.get()); 827 if (err != HDF_SUCCESS) { 828 HDF_LOGE("%{public}s FillThisBuffer error", __func__); 829 return HDF_SUCCESS; 830 } 831 return HDF_SUCCESS; 832} 833 834void CodecHdiDecode::FreeOutBuffer() 835{ 836 uint32_t port = static_cast<uint32_t>(PortIndex::PORT_INDEX_OUTPUT); 837 for (auto bufferId : unUsedOutBuffers_) { 838 HDF_LOGI("FreeOutBuffer, bufferid [%{public}d]", bufferId); 839 auto iter = omxBuffers_.find(bufferId); 840 if (iter == omxBuffers_.end()) { 841 break; 842 } 843 auto bufferInfo = iter->second; 844 auto err = client_->FreeBuffer(port, *bufferInfo->omxBuffer.get()); 845 if (err != HDF_SUCCESS) { 846 HDF_LOGE("%{public}s error", __func__); 847 return; 848 } 849 omxBuffers_.erase(iter); 850 } 851} 852 853void CodecHdiDecode::HandleEventPortSettingsChanged(uint32_t data1, uint32_t data2) 854{ 855 uint32_t port = static_cast<uint32_t>(PortIndex::PORT_INDEX_OUTPUT); 856 if (data2 == OMX_IndexParamPortDefinition) { 857 auto err = client_->SendCommand(CODEC_COMMAND_PORT_DISABLE, port, {}); 858 if (err != HDF_SUCCESS) { 859 HDF_LOGE("%{public}s error", __func__); 860 return; 861 } 862 FreeOutBuffer(); 863 err = client_->SendCommand(CODEC_COMMAND_PORT_ENABLE, port, {}); 864 if (err != HDF_SUCCESS) { 865 HDF_LOGE("%{public}s error", __func__); 866 return; 867 } 868 UseBufferOnPort(PortIndex::PORT_INDEX_OUTPUT); 869 FillAllTheBuffer(); 870 } 871} 872 873int32_t CodecHdiDecode::EventHandler(CodecEventType event, const EventInfo &info) 874{ 875 switch (event) { 876 case CODEC_EVENT_CMD_COMPLETE: { 877 CodecCommandType cmd = (CodecCommandType)info.data1; 878 if (CODEC_COMMAND_STATE_SET == cmd) { 879 HDF_LOGI("CODEC_COMMAND_STATE_SET reached, status is %{public}d", info.data2); 880 this->OnStatusChanged(); 881 } 882 break; 883 } 884 case OMX_EventPortSettingsChanged: { 885 HDF_LOGI("OMX_EventPortSeetingsChanged reached"); 886 this->HandleEventPortSettingsChanged(info.data1, info.data2); 887 } 888 889 default: 890 break; 891 } 892 893 return HDF_SUCCESS; 894} 895 896int main(int argc, char *argv[]) 897{ 898 CommandOpt opt; 899 CommandParse parse; 900 if (!parse.Parse(argc, argv, opt)) { 901 return HDF_FAILURE; 902 } 903 auto core = std::make_shared<CodecHdiDecode>(); 904 // Init width, height, input file 905 if (!core->Init(opt)) { 906 return HDF_FAILURE; 907 } 908 909 if (!core->Configure()) { 910 return HDF_FAILURE; 911 } 912 913 if (!core->UseBuffers()) { 914 return HDF_FAILURE; 915 } 916 917 core->Run(); 918 core->FreeBuffers(); 919 core->Release(); 920 core = nullptr; 921}