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