• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 *)&param, 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(&param, 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 *)&param, 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(&param, 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 *)&param, 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(&param, 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 *)&param, 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(&param, 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 *)&param, 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(&param, sizeof(PassthroughParam), 0, sizeof(PassthroughParam));
801     param.key = KEY_EXT_ENC_VALIDATE_SETUP_RK;
802     ret = client_->SetParameter(client_, OMX_IndexParamPassthrough, (int8_t *)&param, 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 *)&param, 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 *)&param, 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 *)&param, 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 *)&param, 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