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
22 using namespace std;
23 using namespace OHOS;
24 using namespace OHOS::HDI::Display::Buffer::V1_0;
25 using namespace OHOS::HDI::Display::Composer::V1_0;
26 #define HDF_LOG_TAG codec_omx_hdi_enc
27 IDisplayBuffer *CodecHdiEncode::buffer_ = nullptr;
28
29 namespace {
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
39 static CodecHdiEncode *g_core = nullptr;
CodecHdiEncode()40 CodecHdiEncode::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
~CodecHdiEncode()56 CodecHdiEncode::~CodecHdiEncode()
57 {
58 if (ioOut_.is_open()) {
59 ioOut_.close();
60 }
61 if (ioIn_.is_open()) {
62 ioIn_.close();
63 }
64 }
65
WaitForStatusChanged()66 void CodecHdiEncode::WaitForStatusChanged()
67 {
68 unique_lock<mutex> autoLock(statusLock_);
69 statusCondition_.wait(autoLock);
70 }
71
OnStatusChanged()72 void CodecHdiEncode::OnStatusChanged()
73 {
74 statusCondition_.notify_one();
75 }
76
ReadOneFrame(char * buf,uint32_t & filledCount)77 bool 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
Init(CommandOpt & opt)87 bool 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
Configure()141 bool 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
CheckAndUseBufferHandle()163 int32_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
UseBuffers()211 bool 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
UseBufferOnPort(PortIndex portIndex)257 int32_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
UseBufferOnPort(PortIndex portIndex,int bufferCount,int bufferSize)309 int32_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
UseDynaBuffer(int bufferCount,int bufferSize)361 int32_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
FreeBuffers()397 void 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
Release()429 void CodecHdiEncode::Release()
430 {
431 omxMgr_->DestroyComponent(componentId_);
432 CodecComponentTypeRelease(client_);
433 client_ = nullptr;
434 CodecComponentManagerRelease();
435 }
436
FillAllTheBuffer()437 bool 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
GetFreeBufferId()454 int 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
Run()466 void 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
FillCodecBuffer(std::shared_ptr<BufferInfo> bufferInfo,bool & endFlag)512 bool 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
CreateBufferHandle()550 int32_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
OnEvent(struct CodecCallbackType * self,enum OMX_EVENTTYPE event,struct EventInfo * info)582 int32_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
OnEmptyBufferDone(struct CodecCallbackType * self,int64_t appData,const struct OmxCodecBuffer * buffer)596 int32_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
OnFillBufferDone(struct CodecCallbackType * self,int64_t appData,const struct OmxCodecBuffer * buffer)603 int32_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
GetInputBufferSize()610 uint32_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
OnEmptyBufferDone(const struct OmxCodecBuffer & buffer)619 int32_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
OnFillBufferDone(const struct OmxCodecBuffer & buffer)631 int32_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
ConfigPortDefine()661 int32_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 }
GetComponent()713 int32_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
GetCompressFormat()745 OMX_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 }
ConfigBitMode()766 int32_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
main(int argc,char * argv[])813 int 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 }