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