1/*
2 * Copyright 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_decode.h"
17#include <securec.h>
18#include <unistd.h>
19#include "codec_omx_ext.h"
20#include "hdf_log.h"
21#include "v1_0/display_composer_type.h"
22#include "v1_0/display_buffer_type.h"
23#include "v1_0/include/idisplay_buffer.h"
24using namespace std;
25using namespace OHOS;
26using OHOS::sptr;
27using OHOS::HDI::Base::NativeBuffer;
28using namespace OHOS::HDI::Codec::V3_0;
29using namespace OHOS::HDI::Display::Buffer::V1_0;
30using namespace OHOS::HDI::Display::Composer::V1_0;
31#define HDF_LOG_TAG     codec_omx_hdi_dec
32#define AV_COLOR_FORMAT OMX_COLOR_FormatYUV420SemiPlanar
33IDisplayBuffer *CodecHdiDecode::gralloc_ = nullptr;
34CodecUtil *CodecHdiDecode::util_;
35namespace {
36constexpr int32_t FRAME = 30 << 16;
37constexpr int32_t DENOMINATOR = 2;
38constexpr int32_t NUMERATOR = 3;
39constexpr int32_t START_CODE_OFFSET_ONE = -1;
40constexpr int32_t INIT_BUFFER_CODE = -1;
41constexpr int32_t START_CODE_OFFSET_SEC = -2;
42constexpr int32_t START_CODE_OFFSET_THIRD = -3;
43constexpr int32_t START_CODE_SIZE_FRAME = 4;
44constexpr int32_t START_CODE_SIZE_SLICE = 3;
45constexpr char START_CODE = 0x1;
46}  // namespace
47
48CodecHdiDecode::CodecHdiDecode() : fpIn_(nullptr), fpOut_(nullptr)
49{
50    client_ = nullptr;
51    callback_ = nullptr;
52    omxMgr_ = nullptr;
53    exit_ = false;
54    width_ = 0;
55    height_ = 0;
56    codecMime_ = codecMime::AVC;
57    count_ = 0;
58    useBufferHandle_ = false;
59    useDMABuffer_ = false;
60    componentId_ = 0;
61}
62
63CodecHdiDecode::~CodecHdiDecode()
64{
65    if (fpOut_ != nullptr) {
66        fclose(fpOut_);
67        fpOut_ = nullptr;
68    }
69
70    if (fpIn_ != nullptr) {
71        fclose(fpIn_);
72        fpIn_ = nullptr;
73    }
74}
75
76void CodecHdiDecode::WaitForStatusChanged()
77{
78    unique_lock<mutex> autoLock(statusLock_);
79    statusCondition_.wait(autoLock);
80}
81
82void CodecHdiDecode::OnStatusChanged()
83{
84    statusCondition_.notify_one();
85}
86
87int CodecHdiDecode::GetYuvSize()
88{
89    return width_ * height_ * NUMERATOR / DENOMINATOR;
90}
91
92bool CodecHdiDecode::ReadOnePacket(FILE *fp, char *buf, uint32_t &filledCount)
93{
94    // read start code first
95    size_t t = fread(buf, 1, START_CODE_SIZE_FRAME, fp);
96    if (t < START_CODE_SIZE_FRAME) {
97        return true;
98    }
99    char *temp = buf;
100    temp += START_CODE_SIZE_FRAME;
101    bool ret = true;
102    while (!feof(fp)) {
103        (void)fread(temp, 1, 1, fp);
104        if (*temp != START_CODE) {
105            temp++;
106            continue;
107        }
108        // check start code
109        if ((temp[START_CODE_OFFSET_ONE] == 0) && (temp[START_CODE_OFFSET_SEC] == 0) &&
110            (temp[START_CODE_OFFSET_THIRD] == 0)) {
111            fseek(fp, -START_CODE_SIZE_FRAME, SEEK_CUR);
112            temp -= (START_CODE_SIZE_FRAME - 1);
113            ret = false;
114            break;
115            }
116        if ((temp[START_CODE_OFFSET_ONE] == 0) && (temp[START_CODE_OFFSET_SEC] == 0)) {
117            fseek(fp, -START_CODE_SIZE_SLICE, SEEK_CUR);
118            temp -= (START_CODE_SIZE_SLICE - 1);
119            ret = false;
120            break;
121        }
122        temp++;
123    }
124    filledCount = (temp - buf);
125    return ret;
126}
127
128bool CodecHdiDecode::Init(const CommandOpt &opt)
129{
130    this->width_ = opt.width;
131    this->height_ = opt.height;
132    this->codecMime_ = opt.codec;
133    this->stride_ = AlignUp(opt.width);
134    this->useBufferHandle_ = opt.useBufferHandle;
135    this->useDMABuffer_ = opt.useDMABuffer;
136    gralloc_ = IDisplayBuffer::Get();
137    fpIn_ = fopen(opt.fileInput.c_str(), "rb");
138    fpOut_ = fopen(opt.fileOutput.c_str(), "wb+");
139    if ((fpIn_ == nullptr) || (fpOut_ == nullptr)) {
140        HDF_LOGE("%{public}s failed to open file", __func__);
141        return false;
142    }
143    omxMgr_ = ICodecComponentManager::Get(false);
144    if ((omxMgr_ == nullptr)) {
145        HDF_LOGE("%{public}s omxMgr_ is null", __func__);
146        return false;
147    }
148    callback_ = new CodecHdiCallback(shared_from_this());
149    if ((callback_ == nullptr)) {
150        HDF_LOGE("%{public}s callback_ is null", __func__);
151        return false;
152    }
153    std::string compName("");
154    int32_t err = GetComponentName(compName);
155    if (err != HDF_SUCCESS) {
156        HDF_LOGE("%{public}s GetComponentName err", __func__);
157        return false;
158    }
159    err = omxMgr_->CreateComponent(client_, componentId_, compName, reinterpret_cast<int64_t>(this), callback_);
160    if (err != HDF_SUCCESS) {
161        HDF_LOGE("%{public}s failed to CreateComponent", __func__);
162        return false;
163    }
164    struct CompVerInfo verInfo;
165    err = memset_s(&verInfo, sizeof(verInfo), 0, sizeof(verInfo));
166    if (err != EOK) {
167        HDF_LOGE("%{public}s: memset_s verInfo err [%{public}d].", __func__, err);
168        return false;
169    }
170    err = client_->GetComponentVersion(verInfo);
171    if (err != HDF_SUCCESS) {
172        HDF_LOGE("%{public}s failed to CreateComponent", __func__);
173        return false;
174    }
175    return true;
176}
177
178int32_t CodecHdiDecode::ConfigPortDefine()
179{
180    // set width and height on input port
181    OMX_PARAM_PORTDEFINITIONTYPE param;
182    if (util_->InitParam(param) != HDF_SUCCESS) {
183        return HDF_FAILURE;
184    }
185    param.nPortIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_INPUT);
186
187    std::vector<int8_t> inVec, outVec;
188    util_->ObjectToVector(param, inVec);
189    auto err = client_->GetParameter(OMX_IndexParamPortDefinition, inVec, outVec);
190    if (err != HDF_SUCCESS) {
191        HDF_LOGE("%{public}s failed  PortIndex::PORT_INDEX_INPUT, index is OMX_IndexParamPortDefinition", __func__);
192        return err;
193    }
194    util_->VectorToObject(outVec, param);
195
196    HDF_LOGI("PortIndex::PORT_INDEX_INPUT: eCompressionFormat = %{public}d, eColorFormat = %{public}d ",
197             param.format.video.eCompressionFormat, param.format.video.eColorFormat);
198    util_->setParmValue(param, width_, height_, stride_);
199    util_->ObjectToVector(param, inVec);
200    err = client_->SetParameter(OMX_IndexParamPortDefinition, inVec);
201    if (err != HDF_SUCCESS) {
202        HDF_LOGE("%{public}s failed with PortIndex::PORT_INDEX_INPUT, index is OMX_IndexParamPortDefinition", __func__);
203        return err;
204    }
205
206    // set width, height and color format on output port
207    if (util_->InitParam(param) != HDF_SUCCESS) {
208        return HDF_FAILURE;
209    }
210    param.nPortIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_OUTPUT);
211    util_->ObjectToVector(param, inVec);
212    err = client_->GetParameter(OMX_IndexParamPortDefinition, inVec, outVec);
213    if (err != HDF_SUCCESS) {
214        HDF_LOGE("%{public}s failed with PortIndex::PORT_INDEX_OUTPUT, index is OMX_IndexParamPortDefinition",
215                 __func__);
216        return err;
217    }
218    util_->VectorToObject(outVec, param);
219
220    HDF_LOGI("PortIndex::PORT_INDEX_OUTPUT eCompressionFormat = %{public}d, eColorFormat=%{public}d",
221             param.format.video.eCompressionFormat, param.format.video.eColorFormat);
222    util_->setParmValue(param, width_, height_, stride_);
223    param.format.video.eColorFormat = AV_COLOR_FORMAT;  // YUV420SP
224    util_->ObjectToVector(param, inVec);
225    err = client_->SetParameter(OMX_IndexParamPortDefinition, inVec);
226    if (err != HDF_SUCCESS) {
227        HDF_LOGE("%{public}s failed  with PortIndex::PORT_INDEX_OUTPUT, index is OMX_IndexParamPortDefinition",
228                 __func__);
229        return err;
230    }
231
232    return err;
233}
234bool CodecHdiDecode::Configure()
235{
236    if (ConfigPortDefine() != HDF_SUCCESS) {
237        return false;
238    }
239
240    OMX_VIDEO_PARAM_PORTFORMATTYPE param;
241    if (util_->InitParam(param) != HDF_SUCCESS) {
242        return false;
243    }
244    param.nPortIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_INPUT);
245    std::vector<int8_t> inVec, outVec;
246    util_->ObjectToVector(param, inVec);
247    auto err = client_->GetParameter(OMX_IndexParamVideoPortFormat, inVec, outVec);
248    if (err != HDF_SUCCESS) {
249        HDF_LOGE("%{public}s failed with PortIndex::PORT_INDEX_INPUT", __func__);
250        return false;
251    }
252    util_->VectorToObject(outVec, param);
253
254    HDF_LOGI("set Format PortIndex::PORT_INDEX_INPUT eCompressionFormat = %{public}d, eColorFormat=%{public}d",
255             param.eCompressionFormat, param.eColorFormat);
256    param.xFramerate = FRAME;  // 30fps,Q16 format
257    if (codecMime_ == codecMime::AVC) {
258        param.eCompressionFormat = OMX_VIDEO_CodingAVC;  // H264
259    } else {
260        param.eCompressionFormat = static_cast<OMX_VIDEO_CODINGTYPE>(CODEC_OMX_VIDEO_CodingHEVC);  // H265
261    }
262
263    util_->ObjectToVector(param, inVec);
264    err = client_->SetParameter(OMX_IndexParamVideoPortFormat, inVec);
265    if (err != HDF_SUCCESS) {
266        HDF_LOGE("%{public}s failed  with PortIndex::PORT_INDEX_INPUT", __func__);
267        return false;
268    }
269
270    err = CheckAndUseBufferHandle();
271    if (err != HDF_SUCCESS) {
272        HDF_LOGE("%{public}s failed  with CheckAndUseBufferHandle", __func__);
273        return false;
274    }
275
276    err = CheckAndUseDMABuffer();
277    if (err != HDF_SUCCESS) {
278        HDF_LOGE("%{public}s failed  with CheckAndUseDMABuffer", __func__);
279        return false;
280    }
281    return true;
282}
283
284int32_t CodecHdiDecode::CheckSupportBufferType(PortIndex portIndex, CodecBufferType codecBufferType)
285{
286    //get support buffer
287    SupportBufferType param;
288    std::vector<int8_t> inVec, outVec;
289    if (util_->InitParamInOhos(param) != HDF_SUCCESS) {
290        return HDF_FAILURE;
291    }
292    param.portIndex = static_cast<uint32_t>(portIndex);
293
294    util_->ObjectToVector(param, inVec);
295    auto err = client_->GetParameter(OMX_IndexParamSupportBufferType, inVec, outVec);
296    if (err != HDF_SUCCESS) {
297        HDF_LOGE("%{public}s failed get parameter with portIndex %{public}d and ret %{public}d ",
298                 __func__, portIndex, err);
299    }
300    util_->VectorToObject(outVec, param);
301    if (!(param.bufferTypes & codecBufferType)) {
302        HDF_LOGE("%{public}s unSupport bufferType %{public}d ,ret is  %{public}d",
303                 __func__, codecBufferType,  param.bufferTypes);
304        return HDF_FAILURE;
305    }
306    return HDF_SUCCESS;
307}
308
309int32_t CodecHdiDecode::CheckAndUseDMABuffer()
310{
311    if (!useDMABuffer_) {
312        return HDF_SUCCESS;
313    }
314    return CheckSupportBufferType(PortIndex::PORT_INDEX_INPUT, CODEC_BUFFER_TYPE_DMA_MEM_FD);
315}
316
317int32_t CodecHdiDecode::CheckAndUseBufferHandle()
318{
319    if (!useBufferHandle_) {
320        return HDF_SUCCESS;
321    }
322    SupportBufferType param;
323    if (util_->InitParamInOhos(param) != HDF_SUCCESS) {
324        return HDF_FAILURE;
325    }
326    param.portIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_INPUT);
327    std::vector<int8_t> inVec, outVec;
328    util_->ObjectToVector(param, inVec);
329    auto err = client_->GetParameter(OMX_IndexParamSupportBufferType, inVec, outVec);
330    if (err != HDF_SUCCESS) {
331        HDF_LOGE("OMX_GetParameter OMX_IndexParamSupportBufferType in err [%{public}x]", err);
332        return err;
333    }
334    util_->VectorToObject(outVec, param);
335
336    if (util_->InitParamInOhos(param) != HDF_SUCCESS) {
337        return HDF_FAILURE;
338    }
339    param.portIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_OUTPUT);
340    util_->ObjectToVector(param, inVec);
341    err = client_->GetParameter(OMX_IndexParamSupportBufferType, inVec, outVec);
342    if (err != HDF_SUCCESS) {
343        HDF_LOGE("OMX_GetParameter OMX_IndexParamSupportBufferType out err [%{public}x]", err);
344        return err;
345    }
346    util_->VectorToObject(outVec, param);
347
348    GetBufferHandleUsageParams usage;
349    if (util_->InitParamInOhos(usage) != HDF_SUCCESS) {
350        return HDF_FAILURE;
351    }
352    usage.portIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_OUTPUT);
353    util_->ObjectToVector(usage, inVec);
354    err = client_->GetParameter(OMX_IndexParamGetBufferHandleUsage, inVec, outVec);
355    if (err != HDF_SUCCESS) {
356        HDF_LOGE("OMX_GetParameter OMX_IndexParamGetBufferHandleUsage out err [%{public}x]", err);
357        return err;
358    }
359    util_->VectorToObject(outVec, usage);
360
361    UseBufferType type;
362    if (util_->InitParamInOhos(type) != HDF_SUCCESS) {
363        return HDF_FAILURE;
364    }
365    type.portIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_OUTPUT);
366    type.bufferType = CODEC_BUFFER_TYPE_HANDLE;
367    util_->ObjectToVector(type, inVec);
368    err = client_->SetParameter(OMX_IndexParamUseBufferType, inVec);
369    if (err != HDF_SUCCESS) {
370        HDF_LOGE("OMX_SetParameter OMX_IndexParamUseBufferType out, err [%{public}x]", err);
371        return err;
372    }
373    return err;
374}
375
376bool CodecHdiDecode::UseBuffers()
377{
378    HDF_LOGI("...command to IDLE....");
379    std::vector<int8_t> cmdData;
380    auto err = client_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_IDLE, cmdData);
381    if (err != HDF_SUCCESS) {
382        HDF_LOGE("%{public}s failed to SendCommand with CODEC_COMMAND_STATE_SET:CODEC_STATE_IDLE", __func__);
383        return false;
384    }
385
386    err = UseBufferOnPort(PortIndex::PORT_INDEX_INPUT);
387    if (err != HDF_SUCCESS) {
388        HDF_LOGE("%{public}s UseBufferOnPort PortIndex::PORT_INDEX_INPUT error", __func__);
389        return false;
390    }
391
392    err = UseBufferOnPort(PortIndex::PORT_INDEX_OUTPUT);
393    if (err != HDF_SUCCESS) {
394        HDF_LOGE("%{public}s UseBufferOnPort PortIndex::PORT_INDEX_OUTPUT error", __func__);
395        return false;
396    }
397
398    HDF_LOGI("Wait for CODEC_STATE_IDLE status");
399    CodecStateType status = CODEC_STATE_INVALID;
400    err = client_->GetState(status);
401    if (err != HDF_SUCCESS) {
402        HDF_LOGE("%{public}s GetState err [%{public}x]", __func__, err);
403        return false;
404    }
405    if (status != CODEC_STATE_IDLE) {
406        HDF_LOGI("Wait for CODEC_STATE_LOADED status");
407        this->WaitForStatusChanged();
408    } else {
409        HDF_LOGI(" status is %{public}d", status);
410    }
411
412    return true;
413}
414
415int32_t CodecHdiDecode::UseBufferOnPort(PortIndex portIndex, int bufferCount, int bufferSize)
416{
417    if (bufferCount <= 0 || bufferSize <= 0) {
418        HDF_LOGE("UseBufferOnPort bufferCount <= 0 or bufferSize <= 0");
419        return HDF_ERR_INVALID_PARAM;
420    }
421    for (int i = 0; i < bufferCount; i++) {
422        std::shared_ptr<OmxCodecBuffer> omxBuffer = std::make_shared<OmxCodecBuffer>();
423        omxBuffer->size = sizeof(OmxCodecBuffer);
424        omxBuffer->version.version.majorVersion = 1;
425        omxBuffer->bufferType = CODEC_BUFFER_TYPE_AVSHARE_MEM_FD;
426        int fd = AshmemCreate(0, bufferSize);
427        shared_ptr<Ashmem> sharedMem = make_shared<Ashmem>(fd, bufferSize);
428        omxBuffer->fd = fd;
429        omxBuffer->bufferhandle = nullptr;
430        omxBuffer->allocLen = bufferSize;
431        omxBuffer->fenceFd = -1;
432        omxBuffer->pts = 0;
433        omxBuffer->flag = 0;
434
435        if (portIndex == PortIndex::PORT_INDEX_INPUT) {
436            omxBuffer->type = READ_ONLY_TYPE;
437            sharedMem->MapReadAndWriteAshmem();
438        } else {
439            omxBuffer->type = READ_WRITE_TYPE;
440            sharedMem->MapReadOnlyAshmem();
441        }
442        OmxCodecBuffer outBuffer;
443        auto err = client_->UseBuffer(static_cast<uint32_t>(portIndex), *omxBuffer.get(), outBuffer);
444        if (err != HDF_SUCCESS) {
445            HDF_LOGE("%{public}s failed to UseBuffer with  portIndex[%{public}d]", __func__, portIndex);
446            sharedMem->UnmapAshmem();
447            sharedMem->CloseAshmem();
448            sharedMem = nullptr;
449            return err;
450        }
451        omxBuffer->bufferId = outBuffer.bufferId;
452        omxBuffer->fd = -1;
453        HDF_LOGI("UseBuffer returned bufferID [%{public}d]", omxBuffer->bufferId);
454
455        std::shared_ptr<BufferInfo> bufferInfo = std::make_shared<BufferInfo>();
456        bufferInfo->omxBuffer = omxBuffer;
457        bufferInfo->avSharedPtr = sharedMem;
458        bufferInfo->portIndex = portIndex;
459        omxBuffers_.emplace(std::make_pair(omxBuffer->bufferId, bufferInfo));
460        if (portIndex == PortIndex::PORT_INDEX_INPUT) {
461            unUsedInBuffers_.push_back(omxBuffer->bufferId);
462        } else {
463            unUsedOutBuffers_.push_back(omxBuffer->bufferId);
464        }
465    }
466
467    return HDF_SUCCESS;
468}
469
470int32_t CodecHdiDecode::UseBufferOnPort(PortIndex portIndex)
471{
472    HDF_LOGI("%{public}s enter, portIndex = %{public}d", __func__, portIndex);
473    int bufferSize = 0;
474    int bufferCount = 0;
475    bool portEnable = false;
476
477    OMX_PARAM_PORTDEFINITIONTYPE param;
478    if (util_->InitParam(param) != HDF_SUCCESS) {
479        return HDF_FAILURE;
480    }
481    param.nPortIndex = static_cast<OMX_U32>(portIndex);
482
483    std::vector<int8_t> inVec, outVec;
484    util_->ObjectToVector(param, inVec);
485    auto err = client_->GetParameter(OMX_IndexParamPortDefinition, inVec, outVec);
486    if (err != HDF_SUCCESS) {
487        HDF_LOGE("%{public}s failed to GetParameter with OMX_IndexParamPortDefinition : portIndex[%{public}d]",
488                 __func__, portIndex);
489        return err;
490    }
491    util_->VectorToObject(outVec, param);
492
493    bufferSize = param.nBufferSize;
494    bufferCount = param.nBufferCountActual;
495    portEnable = param.bEnabled;
496    HDF_LOGI("buffer index [%{public}d], buffer size [%{public}d], "
497             "buffer count [%{public}d], portEnable[%{public}d], ret [%{public}d]",
498             portIndex, bufferSize, bufferCount, portEnable, err);
499    if (useBufferHandle_ && portIndex == PortIndex::PORT_INDEX_OUTPUT) {
500        err = UseBufferHandle(bufferCount, bufferSize);
501    } else if (useDMABuffer_ && portIndex == PortIndex::PORT_INDEX_INPUT) {
502        err = UseDMABuffer(portIndex, bufferCount, bufferSize);
503    } else {
504        err = UseBufferOnPort(portIndex, bufferCount, bufferSize);
505    }
506
507    if (err != HDF_SUCCESS) {
508        HDF_LOGE("%{public}s UseBufferOnPort err[%{public}x]", __func__, err);
509        return err;
510    }
511    // set port enable
512    if (!portEnable) {
513        err = client_->SendCommand(CODEC_COMMAND_PORT_ENABLE, static_cast<uint32_t>(portIndex), {});
514        if (err != HDF_SUCCESS) {
515            HDF_LOGE("%{public}s SendCommand OMX_CommandPortEnable::PortIndex::PORT_INDEX_INPUT error", __func__);
516            return err;
517        }
518    }
519    return HDF_SUCCESS;
520}
521
522int32_t CodecHdiDecode::UseDMABuffer(PortIndex portIndex, int bufferCount, int bufferSize)
523{
524    if (bufferCount <= 0 || bufferSize <= 0) {
525        HDF_LOGE("UseDMABuffer bufferCount <= 0 or bufferSize <= 0");
526        return HDF_ERR_INVALID_PARAM;
527    }
528    for (int i = 0; i < bufferCount; i++) {
529        std::shared_ptr<OmxCodecBuffer> omxBuffer = std::make_shared<OmxCodecBuffer>();
530        omxBuffer->size = sizeof(OmxCodecBuffer);
531        omxBuffer->version.version.majorVersion = 1;
532        omxBuffer->bufferType = CODEC_BUFFER_TYPE_DMA_MEM_FD;
533        omxBuffer->fd = INIT_BUFFER_CODE;
534        omxBuffer->bufferhandle = nullptr;
535        omxBuffer->allocLen = bufferSize;
536        omxBuffer->fenceFd = INIT_BUFFER_CODE;
537        omxBuffer->pts = 0;
538        omxBuffer->flag = 0;
539        omxBuffer->type = READ_WRITE_TYPE;
540
541        OmxCodecBuffer outBuffer;
542        auto err = client_->AllocateBuffer(static_cast<uint32_t>(portIndex), *omxBuffer.get(), outBuffer);
543        if (err != HDF_SUCCESS) {
544            HDF_LOGE("%{public}s failed to UseBuffer with  portIndex[%{public}d]", __func__, portIndex);
545            return err;
546        }
547        omxBuffer->bufferId = outBuffer.bufferId;
548        HDF_LOGI("UseBuffer returned bufferID [%{public}d]", omxBuffer->bufferId);
549
550        std::shared_ptr<BufferInfo> bufferInfo = std::make_shared<BufferInfo>();
551        bufferInfo->omxBuffer = omxBuffer;
552        bufferInfo->portIndex = portIndex;
553        bufferInfo->omxBuffer->fd = outBuffer.fd;
554        omxBuffers_.insert(std::make_pair(omxBuffer->bufferId, bufferInfo));
555        unUsedInBuffers_.push_back(omxBuffer->bufferId);
556
557        void *addr = mmap(nullptr, static_cast<size_t>(bufferInfo->omxBuffer->allocLen),
558                          PROT_READ | PROT_WRITE, MAP_SHARED, bufferInfo->omxBuffer->fd, 0);
559        if (addr == nullptr) {
560            HDF_LOGE("%{public}s mmap fail fd %{public}d", __func__, omxBuffer->fd);
561            return HDF_FAILURE;
562        } else {
563            addrs_[omxBuffer->bufferId] = addr;
564        }
565    }
566    return HDF_SUCCESS;
567}
568
569int32_t CodecHdiDecode::UseBufferHandle(int bufferCount, int bufferSize)
570{
571    if (bufferCount <= 0 || bufferSize <= 0 || gralloc_ == nullptr) {
572        return HDF_ERR_INVALID_PARAM;
573    }
574    AllocInfo alloc = {.width = this->stride_,
575                       .height = this->height_,
576                       .usage =  HBM_USE_CPU_READ | HBM_USE_CPU_WRITE | HBM_USE_MEM_DMA,
577                       .format = PIXEL_FMT_YCBCR_420_SP};
578    for (int i = 0; i < bufferCount; i++) {
579        std::shared_ptr<OmxCodecBuffer> omxBuffer = std::make_shared<OmxCodecBuffer>();
580        omxBuffer->size = sizeof(OmxCodecBuffer);
581        omxBuffer->version.version.majorVersion = 1;
582        omxBuffer->bufferType = CODEC_BUFFER_TYPE_HANDLE;
583        BufferHandle *bufferHandle = nullptr;
584        int32_t err = gralloc_->AllocMem(alloc, bufferHandle);
585        HDF_LOGI("%{public}s AlloceMem ret val ret[%{public}d]", __func__, err);
586        if (DISPLAY_SUCCESS != err) {
587            HDF_LOGE("%{public}s AllocMem error", __func__);
588            return err;
589        }
590        omxBuffer->fd = -1;
591        omxBuffer->allocLen = bufferSize;
592        omxBuffer->fenceFd = -1;  // check use -1 first with no window
593        omxBuffer->pts = 0;
594        omxBuffer->flag = 0;
595        omxBuffer->bufferhandle = new NativeBuffer(bufferHandle);
596        OmxCodecBuffer outBuffer;
597        err = client_->UseBuffer(static_cast<uint32_t>(PortIndex::PORT_INDEX_OUTPUT),
598            *omxBuffer.get(), outBuffer);
599        omxBuffer->bufferhandle = nullptr;
600        if (err != HDF_SUCCESS) {
601            HDF_LOGE("%{public}s failed to UseBuffer with  output port]", __func__);
602            return err;
603        }
604        omxBuffer->bufferId = outBuffer.bufferId;
605        HDF_LOGI("UseBuffer returned bufferID [%{public}d]", omxBuffer->bufferId);
606
607        std::shared_ptr<BufferInfo> bufferInfo = std::make_shared<BufferInfo>();
608        bufferInfo->omxBuffer = omxBuffer;
609        bufferInfo->setBufferHandle(bufferHandle);
610        bufferInfo->portIndex = PortIndex::PORT_INDEX_OUTPUT;
611        omxBuffers_.emplace(std::make_pair(omxBuffer->bufferId, bufferInfo));
612        unUsedOutBuffers_.push_back(omxBuffer->bufferId);
613    }
614    return HDF_SUCCESS;
615}
616
617void CodecHdiDecode::FreeBuffers()
618{
619    // command to loaded
620    (void)client_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_LOADED, {});
621
622    // release all the buffers
623    auto iter = omxBuffers_.begin();
624    while (iter != omxBuffers_.end()) {
625        auto bufferInfo = iter->second;
626        iter = omxBuffers_.erase(iter);
627        (void)client_->FreeBuffer(static_cast<uint32_t>(bufferInfo->portIndex), *bufferInfo->omxBuffer.get());
628        bufferInfo = nullptr;
629    }
630
631    unUsedInBuffers_.clear();
632    unUsedOutBuffers_.clear();
633
634    CodecStateType status = CODEC_STATE_INVALID;
635    int32_t tryCount = 3;
636    do {
637        int32_t err = client_->GetState(status);
638        if (err != HDF_SUCCESS) {
639            HDF_LOGE("%s GetState error [%{public}x]", __func__, err);
640            break;
641        }
642        if (status != CODEC_STATE_LOADED) {
643            HDF_LOGI("Wait for OMX_StateLoaded status");
644            this->WaitForStatusChanged();
645        }
646        tryCount--;
647    } while ((status != CODEC_STATE_LOADED) && (tryCount > 0));
648}
649
650void CodecHdiDecode::Release()
651{
652    omxMgr_->DestroyComponent(componentId_);
653    client_ = nullptr;
654    callback_ = nullptr;
655    omxMgr_ = nullptr;
656}
657
658bool CodecHdiDecode::FillAllTheBuffer()
659{
660    for (auto bufferId : unUsedOutBuffers_) {
661        HDF_LOGI("fillThisBUffer, bufferid [%{public}d]", bufferId);
662        auto iter = omxBuffers_.find(bufferId);
663        if (iter != omxBuffers_.end()) {
664            auto bufferInfo = iter->second;
665            auto buffer = bufferInfo->omxBuffer.get();
666            auto err = client_->FillThisBuffer(*buffer);
667            if (err != HDF_SUCCESS) {
668                HDF_LOGE("%{public}s FillThisBuffer error", __func__);
669                return false;
670            }
671        }
672    }
673    return true;
674}
675
676int CodecHdiDecode::GetFreeBufferId()
677{
678    int bufferID = -1;
679    unique_lock<mutex> ulk(lockInputBuffers_);
680    size_t nSize = this->unUsedInBuffers_.size();
681    if (nSize != 0) {
682        bufferID = unUsedInBuffers_.front();
683        unUsedInBuffers_.pop_front();
684    }
685    return bufferID;
686}
687
688int32_t CodecHdiDecode::GetComponentName(std::string &compName)
689{
690    AvCodecRole role = AvCodecRole::MEDIA_ROLETYPE_VIDEO_AVC;
691    if (codecMime_ == codecMime::HEVC) {
692        role = AvCodecRole::MEDIA_ROLETYPE_VIDEO_HEVC;
693    }
694
695    int32_t count = 0;
696    auto err = omxMgr_->GetComponentNum(count);
697    if (err != HDF_SUCCESS || count <= 0) {
698        HDF_LOGE("%{public}s GetComponentNum return %{public}d, count = %{public}d", __func__, err, count);
699        return HDF_FAILURE;
700    }
701    std::vector<CodecCompCapability> caps;
702    err = omxMgr_->GetComponentCapabilityList(caps, count);
703    if (err != HDF_SUCCESS) {
704        HDF_LOGE("%{public}s GetComponentCapabilityList return %{public}d", __func__, err);
705        return err;
706    }
707    err = HDF_FAILURE;
708    for (auto cap : caps) {
709        if (cap.type == CodecType::VIDEO_DECODER && cap.role == role) {
710            compName = cap.compName;
711            err = HDF_SUCCESS;
712            break;
713        }
714    }
715    return err;
716}
717void CodecHdiDecode::Run()
718{
719    HDF_LOGI("...command to CODEC_STATE_EXECUTING....");
720    auto err = client_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_EXECUTING, {});
721    if (err != HDF_SUCCESS) {
722        HDF_LOGE("%{public}s failed to SendCommand with CODEC_COMMAND_STATE_SET:CODEC_STATE_IDLE", __func__);
723        return;
724    }
725
726    if (!FillAllTheBuffer()) {
727        HDF_LOGE("%{public}s FillAllTheBuffer error", __func__);
728        return;
729    }
730
731    auto t1 = std::chrono::system_clock::now();
732    bool eosFlag = false;
733    while (!eosFlag) {
734        if (this->exit_) {
735            break;
736        }
737        int bufferID = GetFreeBufferId();
738        if (bufferID < 0) {
739            usleep(10000);  // 10000 for wait 10ms
740            continue;
741        }
742        auto iter = omxBuffers_.find(bufferID);
743        if (iter == omxBuffers_.end()) {
744            continue;
745        }
746        auto bufferInfo = iter->second;
747
748        if (!FillCodecBuffer(bufferInfo, eosFlag)) {
749            break;
750        }
751        if (eosFlag) {
752            bufferInfo->omxBuffer->flag = OMX_BUFFERFLAG_EOS;
753        }
754        err = client_->EmptyThisBuffer(*bufferInfo->omxBuffer.get());
755        if (err != HDF_SUCCESS) {
756            HDF_LOGE("%{public}s EmptyThisBuffer error", __func__);
757            return;
758        }
759    }
760    // wait
761    while (!this->exit_) {
762        usleep(10000);  // 10000 for wait 10ms
763    }
764    auto t2 = std::chrono::system_clock::now();
765    std::chrono::duration<double> diff = t2 - t1;
766    HDF_LOGI("cost %{public}f, count=%{public}d", diff.count(), count_);
767    (void)client_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_IDLE, {});
768    return;
769}
770
771bool CodecHdiDecode::FillCodecBuffer(std::shared_ptr<BufferInfo> bufferInfo, bool &eosFlag)
772{
773    if (useDMABuffer_) {
774        auto ret = addrs_.find(bufferInfo->omxBuffer->bufferId);
775        if (ret != addrs_.end()) {
776            eosFlag = this->ReadOnePacket(fpIn_, static_cast<char *>(ret->second), bufferInfo->omxBuffer->filledLen);
777            bufferInfo->omxBuffer->offset = 0;
778        }
779    } else {
780        void *sharedAddr = const_cast<void *>(bufferInfo->avSharedPtr->ReadFromAshmem(0, 0));
781        eosFlag = this->ReadOnePacket(fpIn_, static_cast<char *>(sharedAddr), bufferInfo->omxBuffer->filledLen);
782        bufferInfo->omxBuffer->offset = 0;
783    }
784    return true;
785}
786
787int32_t CodecHdiDecode::OnEmptyBufferDone(const struct OmxCodecBuffer &buffer)
788{
789    HDF_LOGI("OnEmptyBufferDone, bufferId [%{public}d]", buffer.bufferId);
790    unique_lock<mutex> ulk(lockInputBuffers_);
791    unUsedInBuffers_.push_back(buffer.bufferId);
792    return HDF_SUCCESS;
793}
794
795int32_t CodecHdiDecode::OnFillBufferDone(const struct OmxCodecBuffer &buffer)
796{
797    HDF_LOGI("OnFillBufferDone, bufferId [%{public}d]", buffer.bufferId);
798    if (exit_) {
799        return HDF_SUCCESS;
800    }
801
802    auto iter = omxBuffers_.find(buffer.bufferId);
803    if ((iter == omxBuffers_.end()) || (iter->second == nullptr)) {
804        return HDF_SUCCESS;
805    }
806    count_++;
807    // read buffer
808    auto bufferInfo = iter->second;
809    if (bufferInfo->avSharedPtr != nullptr) {
810        const void *addr = bufferInfo->avSharedPtr->ReadFromAshmem(buffer.filledLen, buffer.offset);
811        (void)fwrite(addr, 1, buffer.filledLen, fpOut_);
812    } else if (bufferInfo->bufferHandle != nullptr && gralloc_ != nullptr) {
813        gralloc_->Mmap(*bufferInfo->bufferHandle);
814        (void)fwrite(bufferInfo->bufferHandle->virAddr, 1, buffer.filledLen, fpOut_);
815        gralloc_->Unmap(*bufferInfo->bufferHandle);
816    }
817
818    (void)fflush(fpOut_);
819    if (buffer.flag == OMX_BUFFERFLAG_EOS) {
820        // end
821        exit_ = true;
822        HDF_LOGI("OnFillBufferDone the END coming");
823        return HDF_SUCCESS;
824    }
825    // call fillthisbuffer again
826    auto err = client_->FillThisBuffer(*bufferInfo->omxBuffer.get());
827    if (err != HDF_SUCCESS) {
828        HDF_LOGE("%{public}s FillThisBuffer error", __func__);
829        return HDF_SUCCESS;
830    }
831    return HDF_SUCCESS;
832}
833
834void CodecHdiDecode::FreeOutBuffer()
835{
836    uint32_t port = static_cast<uint32_t>(PortIndex::PORT_INDEX_OUTPUT);
837    for (auto bufferId : unUsedOutBuffers_) {
838        HDF_LOGI("FreeOutBuffer, bufferid [%{public}d]", bufferId);
839        auto iter = omxBuffers_.find(bufferId);
840        if (iter == omxBuffers_.end()) {
841            break;
842        }
843        auto bufferInfo = iter->second;
844        auto err = client_->FreeBuffer(port, *bufferInfo->omxBuffer.get());
845        if (err != HDF_SUCCESS) {
846            HDF_LOGE("%{public}s error", __func__);
847            return;
848        }
849        omxBuffers_.erase(iter);
850    }
851}
852
853void CodecHdiDecode::HandleEventPortSettingsChanged(uint32_t data1, uint32_t data2)
854{
855    uint32_t port = static_cast<uint32_t>(PortIndex::PORT_INDEX_OUTPUT);
856    if (data2 == OMX_IndexParamPortDefinition) {
857        auto err = client_->SendCommand(CODEC_COMMAND_PORT_DISABLE, port, {});
858        if (err != HDF_SUCCESS) {
859            HDF_LOGE("%{public}s error", __func__);
860            return;
861        }
862        FreeOutBuffer();
863        err = client_->SendCommand(CODEC_COMMAND_PORT_ENABLE, port, {});
864        if (err != HDF_SUCCESS) {
865            HDF_LOGE("%{public}s error", __func__);
866            return;
867        }
868        UseBufferOnPort(PortIndex::PORT_INDEX_OUTPUT);
869        FillAllTheBuffer();
870    }
871}
872
873int32_t CodecHdiDecode::EventHandler(CodecEventType event, const EventInfo &info)
874{
875    switch (event) {
876        case CODEC_EVENT_CMD_COMPLETE: {
877            CodecCommandType cmd = (CodecCommandType)info.data1;
878            if (CODEC_COMMAND_STATE_SET == cmd) {
879                HDF_LOGI("CODEC_COMMAND_STATE_SET reached, status is %{public}d", info.data2);
880                this->OnStatusChanged();
881            }
882            break;
883        }
884        case OMX_EventPortSettingsChanged: {
885            HDF_LOGI("OMX_EventPortSeetingsChanged reached");
886            this->HandleEventPortSettingsChanged(info.data1, info.data2);
887        }
888
889        default:
890            break;
891    }
892
893    return HDF_SUCCESS;
894}
895
896int main(int argc, char *argv[])
897{
898    CommandOpt opt;
899    CommandParse parse;
900    if (!parse.Parse(argc, argv, opt)) {
901        return HDF_FAILURE;
902    }
903    auto core = std::make_shared<CodecHdiDecode>();
904    // Init width, height, input file
905    if (!core->Init(opt)) {
906        return HDF_FAILURE;
907    }
908
909    if (!core->Configure()) {
910        return HDF_FAILURE;
911    }
912
913    if (!core->UseBuffers()) {
914        return HDF_FAILURE;
915    }
916
917    core->Run();
918    core->FreeBuffers();
919    core->Release();
920    core = nullptr;
921}