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