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
22using namespace std;
23using namespace OHOS;
24using namespace OHOS::HDI::Display::Buffer::V1_0;
25using namespace OHOS::HDI::Display::Composer::V1_0;
26#define HDF_LOG_TAG codec_omx_hdi_enc
27IDisplayBuffer *CodecHdiEncode::buffer_ = nullptr;
28
29namespace {
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
39static CodecHdiEncode *g_core = nullptr;
40CodecHdiEncode::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
56CodecHdiEncode::~CodecHdiEncode()
57{
58    if (ioOut_.is_open()) {
59        ioOut_.close();
60    }
61    if (ioIn_.is_open()) {
62        ioIn_.close();
63    }
64}
65
66void CodecHdiEncode::WaitForStatusChanged()
67{
68    unique_lock<mutex> autoLock(statusLock_);
69    statusCondition_.wait(autoLock);
70}
71
72void CodecHdiEncode::OnStatusChanged()
73{
74    statusCondition_.notify_one();
75}
76
77bool 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
87bool 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
141bool 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
163int32_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
211bool 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
257int32_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
309int32_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
361int32_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
397void 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
429void CodecHdiEncode::Release()
430{
431    omxMgr_->DestroyComponent(componentId_);
432    CodecComponentTypeRelease(client_);
433    client_ = nullptr;
434    CodecComponentManagerRelease();
435}
436
437bool 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
454int 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
466void 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
512bool 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
550int32_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
582int32_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
596int32_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
603int32_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
610uint32_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
619int32_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
631int32_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
661int32_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}
713int32_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
745OMX_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}
766int32_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
813int 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}