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