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_decode.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;
26namespace {
27constexpr uint32_t FD_SIZE = sizeof(int);
28constexpr uint32_t FRAME = 30 << 16;
29constexpr uint32_t DENOMINATOR = 2;
30constexpr uint32_t NUMERATOR = 3;
31constexpr uint32_t MAX_WAIT_COUNT = 3;
32}  // namespace
33#define HDF_LOG_TAG codec_omx_hdi_dec
34IDisplayBuffer *CodecHdiDecode::buffer_ = nullptr;
35
36#define AV_COLOR_FORMAT OMX_COLOR_FormatYUV420SemiPlanar
37
38static CodecHdiDecode *g_core = nullptr;
39CodecHdiDecode::CodecHdiDecode()
40{
41    client_ = nullptr;
42    callback_ = nullptr;
43    omxMgr_ = nullptr;
44    exit_ = false;
45    width_ = 0;
46    height_ = 0;
47    codecMime_ = CodecMime::AVC;
48    count_ = 0;
49    useBufferHandle_ = false;
50    componentId_ = 0;
51    reader_ = nullptr;
52    color_ = ColorFormat::YUV420SP;
53    omxColorFormat_ = OMX_COLOR_FormatYUV420SemiPlanar;
54}
55
56CodecHdiDecode::~CodecHdiDecode()
57{
58    if (ioOut_.is_open()) {
59        ioOut_.close();
60    }
61    if (ioIn_.is_open()) {
62        ioIn_.close();
63    }
64}
65
66void CodecHdiDecode::WaitForStatusChanged()
67{
68    unique_lock<mutex> autoLock(statusLock_);
69    statusCondition_.wait(autoLock);
70}
71
72void CodecHdiDecode::OnStatusChanged()
73{
74    statusCondition_.notify_one();
75}
76
77int CodecHdiDecode::GetYuvSize()
78{
79    return width_ * height_ * NUMERATOR / DENOMINATOR;
80}
81
82bool CodecHdiDecode::Init(CommandOpt &opt)
83{
84    this->width_ = opt.width;
85    this->height_ = opt.height;
86    this->codecMime_ = opt.codec;
87    this->stride_ = AlignUp(opt.width);
88    this->useBufferHandle_ = opt.useBuffer;
89    color_ = opt.colorForamt;
90    if (color_ == ColorFormat::RGBA8888) {
91        omxColorFormat_ = static_cast<OMX_COLOR_FORMATTYPE>(CODEC_COLOR_FORMAT_RGBA8888);
92    } else if (color_ == ColorFormat::BGRA8888) {
93        omxColorFormat_ = OMX_COLOR_Format32bitBGRA8888;
94    }
95    HDF_LOGI("width[%{public}d], height[%{public}d],stride_[%{public}d],infile[%{public}s],outfile[%{public}s]", width_,
96             height_, stride_, opt.fileInput.c_str(), opt.fileOutput.c_str());
97
98    // gralloc init
99    buffer_ = IDisplayBuffer::Get();
100    reader_ = CodecPacketReader::GetPacketReader(opt.codec);
101    ioIn_.open(opt.fileInput, std::ios_base::binary);
102    ioOut_.open(opt.fileOutput, std::ios_base::binary | std::ios_base::trunc);
103    if (!ioOut_.is_open() || !ioIn_.is_open()) {
104        HDF_LOGE("%{public}s failed to open file %{public}s or %{public}s", __func__, opt.fileInput.c_str(),
105                 opt.fileOutput.c_str());
106        return false;
107    }
108
109    omxMgr_ = GetCodecComponentManager();
110
111    callback_ = CodecCallbackTypeGet(nullptr);
112    if ((omxMgr_ == nullptr) || (callback_ == nullptr)) {
113        HDF_LOGE("%{public}s omxMgr_ is null or callback_ is null", __func__);
114        return false;
115    }
116
117    callback_->EventHandler = &CodecHdiDecode::OnEvent;
118    callback_->EmptyBufferDone = &CodecHdiDecode::OnEmptyBufferDone;
119    callback_->FillBufferDone = &CodecHdiDecode::OnFillBufferDone;
120    int32_t err = GetComponent();
121    if (err != HDF_SUCCESS) {
122        HDF_LOGE("%{public}s failed to CreateComponent", __func__);
123        return false;
124    }
125
126    struct CompVerInfo verInfo;
127    err = memset_s(&verInfo, sizeof(verInfo), 0, sizeof(verInfo));
128    if (err != EOK) {
129        HDF_LOGE("%{public}s: memset_s verInfo err [%{public}d].", __func__, err);
130        return false;
131    }
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
141int32_t CodecHdiDecode::ConfigPortDefine()
142{
143    // set width and height on input port
144    OMX_PARAM_PORTDEFINITIONTYPE param;
145    InitParam(param);
146    param.nPortIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_INPUT);
147    auto err =
148        client_->GetParameter(client_, OMX_IndexParamPortDefinition, reinterpret_cast<int8_t *>(&param), sizeof(param));
149    if (err != HDF_SUCCESS) {
150        HDF_LOGE("%{public}s failed  PortIndex::PORT_INDEX_INPUT, index is OMX_IndexParamPortDefinition", __func__);
151        return err;
152    }
153    HDF_LOGI("PortIndex::PORT_INDEX_INPUT: eCompressionFormat = %{public}d, eColorFormat = %{public}d ",
154             param.format.video.eCompressionFormat, param.format.video.eColorFormat);
155    param.format.video.nFrameWidth = width_;
156    param.format.video.nFrameHeight = height_;
157    param.format.video.nStride = stride_;
158    param.format.video.nSliceHeight = height_;
159    err =
160        client_->SetParameter(client_, OMX_IndexParamPortDefinition, reinterpret_cast<int8_t *>(&param), sizeof(param));
161    if (err != HDF_SUCCESS) {
162        HDF_LOGE("%{public}s failed with PortIndex::PORT_INDEX_INPUT, index is OMX_IndexParamPortDefinition", __func__);
163        return err;
164    }
165
166    // set width, height and color format on output port
167    InitParam(param);
168    param.nPortIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_OUTPUT);
169    err =
170        client_->GetParameter(client_, OMX_IndexParamPortDefinition, reinterpret_cast<int8_t *>(&param), sizeof(param));
171    if (err != HDF_SUCCESS) {
172        HDF_LOGE("%{public}s failed with PortIndex::PORT_INDEX_OUTPUT, index is OMX_IndexParamPortDefinition",
173                 __func__);
174        return err;
175    }
176    HDF_LOGI("PortIndex::PORT_INDEX_OUTPUT eCompressionFormat = %{public}d, eColorFormat=%{public}d",
177             param.format.video.eCompressionFormat, param.format.video.eColorFormat);
178    param.format.video.nFrameWidth = width_;
179    param.format.video.nFrameHeight = height_;
180    param.format.video.nStride = stride_;
181    param.format.video.nSliceHeight = height_;
182    param.format.video.eColorFormat = omxColorFormat_;
183    err =
184        client_->SetParameter(client_, OMX_IndexParamPortDefinition, reinterpret_cast<int8_t *>(&param), sizeof(param));
185    if (err != HDF_SUCCESS) {
186        HDF_LOGE("%{public}s failed  with PortIndex::PORT_INDEX_OUTPUT, index is OMX_IndexParamPortDefinition",
187                 __func__);
188        return err;
189    }
190    return err;
191}
192bool CodecHdiDecode::Configure()
193{
194    if (ConfigPortDefine() != HDF_SUCCESS) {
195        return false;
196    }
197
198    OMX_VIDEO_PARAM_PORTFORMATTYPE param;
199    InitParam(param);
200    param.nPortIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_INPUT);
201    auto err = client_->GetParameter(client_, OMX_IndexParamVideoPortFormat, reinterpret_cast<int8_t *>(&param),
202                                     sizeof(param));
203    if (err != HDF_SUCCESS) {
204        HDF_LOGE("%{public}s failed with PortIndex::PORT_INDEX_INPUT", __func__);
205        return false;
206    }
207    HDF_LOGI("set Format PortIndex::PORT_INDEX_INPUT eCompressionFormat = %{public}d, eColorFormat=%{public}d",
208             param.eCompressionFormat, param.eColorFormat);
209    param.xFramerate = FRAME;  // 30fps,Q16 format
210    switch (codecMime_) {
211        case CodecMime::AVC:
212            param.eCompressionFormat = OMX_VIDEO_CodingAVC;  // H264
213            break;
214        case CodecMime::HEVC:
215            param.eCompressionFormat = (OMX_VIDEO_CODINGTYPE)CODEC_OMX_VIDEO_CodingHEVC;  // H265
216            break;
217        case CodecMime::MPEG4:
218            param.eCompressionFormat = OMX_VIDEO_CodingMPEG4;  // H264
219            break;
220        case CodecMime::VP9:
221            param.eCompressionFormat = (OMX_VIDEO_CODINGTYPE)CODEC_OMX_VIDEO_CodingVP9;  // H264
222            break;
223        default:
224            break;
225    }
226
227    err = client_->SetParameter(client_, OMX_IndexParamVideoPortFormat, reinterpret_cast<int8_t *>(&param),
228                                sizeof(param));
229    if (err != HDF_SUCCESS) {
230        HDF_LOGE("%{public}s failed  with PortIndex::PORT_INDEX_INPUT", __func__);
231        return false;
232    }
233
234    err = CheckAndUseBufferHandle();
235    if (err != HDF_SUCCESS) {
236        HDF_LOGE("%{public}s failed  with CheckAndUseBufferHandle", __func__);
237        return false;
238    }
239    return true;
240}
241
242int32_t CodecHdiDecode::CheckAndUseBufferHandle()
243{
244    if (!useBufferHandle_) {
245        return HDF_SUCCESS;
246    }
247    SupportBufferType param;
248    InitParamInOhos(param);
249    param.portIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_INPUT);
250
251    auto err = client_->GetParameter(client_, OMX_IndexParamSupportBufferType, reinterpret_cast<int8_t *>(&param),
252                                     sizeof(param));
253    HDF_LOGI(
254        "OMX_GetParameter:OMX_IndexParamSupportBufferType:kPortIndexInput, err [%{public}x], bufferTypes[%{public}d]",
255        err, param.bufferTypes);
256    if (err != HDF_SUCCESS) {
257        return err;
258    }
259    InitParamInOhos(param);
260    param.portIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_OUTPUT);
261    err = client_->GetParameter(client_, OMX_IndexParamSupportBufferType, reinterpret_cast<int8_t *>(&param),
262                                sizeof(param));
263    HDF_LOGI(
264        "OMX_GetParameter:OMX_IndexParamSupportBufferType:kPortIndexOutput, err [%{public}x], bufferTypes[%{public}d]",
265        err, param.bufferTypes);
266    if (err != HDF_SUCCESS) {
267        return err;
268    }
269    GetBufferHandleUsageParams usage;
270    InitParamInOhos(usage);
271    usage.portIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_OUTPUT);
272    err = client_->GetParameter(client_, OMX_IndexParamGetBufferHandleUsage, reinterpret_cast<int8_t *>(&usage),
273                                sizeof(usage));
274    HDF_LOGI("OMX_GetParameter:GetBufferHandleUsage:kPortIndexOutput, err [%{public}x], usage[%{public}" PRIu64 "]",
275             err, usage.usage);
276    if (err != HDF_SUCCESS) {
277        return err;
278    }
279    UseBufferType type;
280    InitParamInOhos(type);
281    type.portIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_OUTPUT);
282    type.bufferType = CODEC_BUFFER_TYPE_HANDLE;
283    err = client_->SetParameter(client_, OMX_IndexParamUseBufferType, reinterpret_cast<int8_t *>(&type), sizeof(type));
284    HDF_LOGI("OMX_SetParameter:OMX_IndexParamUseBufferType:kPortIndexOutput, err [%{public}x]", err);
285    return err;
286}
287
288bool CodecHdiDecode::UseBuffers()
289{
290    HDF_LOGI("...command to IDLE....");
291    auto err = client_->SendCommand(client_, OMX_CommandStateSet, OMX_StateIdle, NULL, 0);
292    if (err != HDF_SUCCESS) {
293        HDF_LOGE("%{public}s failed to SendCommand with OMX_CommandStateSet:OMX_StateIdle", __func__);
294        return false;
295    }
296
297    err = UseBufferOnPort(PortIndex::PORT_INDEX_INPUT);
298    if (err != HDF_SUCCESS) {
299        HDF_LOGE("%{public}s UseBufferOnPort PortIndex::PORT_INDEX_INPUT error", __func__);
300        return false;
301    }
302
303    err = UseBufferOnPort(PortIndex::PORT_INDEX_OUTPUT);
304    if (err != HDF_SUCCESS) {
305        HDF_LOGE("%{public}s UseBufferOnPort PortIndex::PORT_INDEX_OUTPUT error", __func__);
306        return false;
307    }
308
309    HDF_LOGI("Wait for OMX_StateIdle status");
310    OMX_STATETYPE status;
311    err = client_->GetState(client_, &status);
312    if (err != HDF_SUCCESS) {
313        HDF_LOGE("%{public}s GetState err [%{public}x]", __func__, err);
314        return false;
315    }
316    if (status != OMX_StateIdle) {
317        HDF_LOGI("Wait for OMX_StateLoaded status");
318        this->WaitForStatusChanged();
319    } else {
320        HDF_LOGI(" status is %{public}d", status);
321    }
322
323    return true;
324}
325
326int32_t CodecHdiDecode::UseBufferOnPort(PortIndex portIndex, int bufferCount, int bufferSize)
327{
328    if (bufferCount <= 0 || bufferSize <= 0) {
329        return HDF_ERR_INVALID_PARAM;
330    }
331    for (int i = 0; i < bufferCount; i++) {
332        std::shared_ptr<OmxCodecBuffer> omxBuffer = std::make_shared<OmxCodecBuffer>();
333        omxBuffer->size = sizeof(OmxCodecBuffer);
334        omxBuffer->version.s.nVersionMajor = 1;
335        omxBuffer->bufferType = CODEC_BUFFER_TYPE_AVSHARE_MEM_FD;
336        int fd = AshmemCreate(0, bufferSize);
337        shared_ptr<Ashmem> sharedMem = make_shared<Ashmem>(fd, bufferSize);
338        omxBuffer->bufferLen = FD_SIZE;
339        omxBuffer->buffer = reinterpret_cast<uint8_t *>(fd);
340        omxBuffer->allocLen = bufferSize;
341        omxBuffer->fenceFd = -1;
342        omxBuffer->pts = 0;
343        omxBuffer->flag = 0;
344
345        if (portIndex == PortIndex::PORT_INDEX_INPUT) {
346            omxBuffer->type = READ_ONLY_TYPE;
347            sharedMem->MapReadAndWriteAshmem();
348        } else {
349            omxBuffer->type = READ_WRITE_TYPE;
350            sharedMem->MapReadOnlyAshmem();
351        }
352        auto err = client_->UseBuffer(client_, static_cast<uint32_t>(portIndex), omxBuffer.get());
353        if (err != HDF_SUCCESS) {
354            HDF_LOGE("%{public}s failed to UseBuffer with  portIndex[%{public}d]", __func__, portIndex);
355            sharedMem->UnmapAshmem();
356            sharedMem->CloseAshmem();
357            sharedMem = nullptr;
358            return err;
359        }
360        omxBuffer->bufferLen = 0;
361        HDF_LOGI("UseBuffer returned bufferID [%{public}d]", omxBuffer->bufferId);
362
363        std::shared_ptr<BufferInfo> bufferInfo = std::make_shared<BufferInfo>();
364        bufferInfo->omxBuffer = omxBuffer;
365        bufferInfo->avSharedPtr = sharedMem;
366        bufferInfo->portIndex = portIndex;
367        omxBuffers_.emplace(std::make_pair(omxBuffer->bufferId, bufferInfo));
368        if (portIndex == PortIndex::PORT_INDEX_INPUT) {
369            unUsedInBuffers_.push_back(omxBuffer->bufferId);
370        } else {
371            unUsedOutBuffers_.push_back(omxBuffer->bufferId);
372        }
373    }
374
375    return HDF_SUCCESS;
376}
377
378int32_t CodecHdiDecode::UseBufferOnPort(PortIndex portIndex)
379{
380    HDF_LOGI("%{public}s enter, portIndex = %{public}d", __func__, portIndex);
381
382    OMX_PARAM_PORTDEFINITIONTYPE param;
383    InitParam(param);
384    param.nPortIndex = static_cast<OMX_U32>(portIndex);
385    auto err =
386        client_->GetParameter(client_, OMX_IndexParamPortDefinition, reinterpret_cast<int8_t *>(&param), sizeof(param));
387    if (err != HDF_SUCCESS) {
388        HDF_LOGE("%{public}s failed to GetParameter with OMX_IndexParamPortDefinition : portIndex[%{public}d]",
389                 __func__, portIndex);
390        return err;
391    }
392
393    int bufferSize = param.nBufferSize;
394    int bufferCount = param.nBufferCountActual;
395    bool portEnable = param.bEnabled;
396    HDF_LOGI("buffer index [%{public}d], buffer size [%{public}d], "
397             "buffer count [%{public}d], portEnable[%{public}d], err [%{public}d]",
398             portIndex, bufferSize, bufferCount, portEnable, err);
399
400    {
401        OMX_PARAM_BUFFERSUPPLIERTYPE param;
402        InitParam(param);
403        param.nPortIndex = static_cast<uint32_t>(portIndex);
404        err = client_->GetParameter(client_, OMX_IndexParamCompBufferSupplier, reinterpret_cast<int8_t *>(&param),
405                                    sizeof(param));
406        HDF_LOGI("param.eBufferSupplier[%{public}d] err [%{public}d]", param.eBufferSupplier, err);
407    }
408    if (useBufferHandle_ && portIndex == PortIndex::PORT_INDEX_OUTPUT) {
409        err = UseBufferHandle(bufferCount, bufferSize);
410    } else {
411        err = UseBufferOnPort(portIndex, bufferCount, bufferSize);
412    }
413
414    if (err != HDF_SUCCESS) {
415        HDF_LOGE("%{public}s UseBufferOnPort err[%{public}x]", __func__, err);
416        return err;
417    }
418    // set port enable
419    if (!portEnable) {
420        err = client_->SendCommand(client_, OMX_CommandPortEnable, static_cast<uint32_t>(portIndex), NULL, 0);
421        if (err != HDF_SUCCESS) {
422            HDF_LOGE("%{public}s SendCommand OMX_CommandPortEnable::PortIndex::PORT_INDEX_INPUT error", __func__);
423            return err;
424        }
425    }
426    return HDF_SUCCESS;
427}
428
429int32_t CodecHdiDecode::UseBufferHandle(int bufferCount, int bufferSize)
430{
431    if (bufferCount <= 0 || bufferSize <= 0 || buffer_ == nullptr) {
432        return HDF_ERR_INVALID_PARAM;
433    }
434    PixelFormat pixForamt = PIXEL_FMT_YCBCR_420_SP;
435    if (color_ == ColorFormat::RGBA8888) {
436        pixForamt = PIXEL_FMT_RGBA_8888;
437    } else if (color_ == ColorFormat::BGRA8888) {
438        pixForamt = PIXEL_FMT_BGRA_8888;
439    }
440    AllocInfo alloc = {.width = this->width_,
441        .height = this->height_,
442        .usage = HBM_USE_CPU_READ | HBM_USE_CPU_WRITE | HBM_USE_MEM_DMA,
443        .format = pixForamt};
444
445    for (int i = 0; i < bufferCount; i++) {
446        int32_t ret = HDF_SUCCESS;
447        std::shared_ptr<OmxCodecBuffer> omxBuffer = std::make_shared<OmxCodecBuffer>();
448        omxBuffer->size = sizeof(OmxCodecBuffer);
449        omxBuffer->version.s.nVersionMajor = 1;
450        omxBuffer->bufferType = CODEC_BUFFER_TYPE_HANDLE;
451        BufferHandle *bufferHandle = nullptr;
452        ret = buffer_->AllocMem(alloc, bufferHandle);
453        HDF_LOGI("%{public}s AlloceMem ret val err[%{public}d]", __func__, ret);
454        if (DISPLAY_SUCCESS != ret) {
455            HDF_LOGE("%{public}s AllocMem error", __func__);
456            return ret;
457        }
458        size_t handleSize =
459            sizeof(BufferHandle) + (sizeof(int32_t) * (bufferHandle->reserveFds + bufferHandle->reserveInts));
460        omxBuffer->bufferLen = handleSize;
461        omxBuffer->buffer = reinterpret_cast<uint8_t *>(bufferHandle);
462        omxBuffer->allocLen = bufferSize;
463        omxBuffer->fenceFd = -1;  // check use -1 first with no window
464        omxBuffer->pts = 0;
465        omxBuffer->flag = 0;
466        auto err = client_->UseBuffer(client_, static_cast<uint32_t>(PortIndex::PORT_INDEX_OUTPUT), omxBuffer.get());
467        if (err != HDF_SUCCESS) {
468            HDF_LOGE("%{public}s failed to UseBuffer with  output port]", __func__);
469            return err;
470        }
471        omxBuffer->bufferLen = 0;
472        HDF_LOGI("UseBuffer returned bufferID [%{public}d]", omxBuffer->bufferId);
473
474        std::shared_ptr<BufferInfo> bufferInfo = std::make_shared<BufferInfo>();
475        bufferInfo->omxBuffer = omxBuffer;
476        bufferInfo->setBufferHandle(bufferHandle);
477        bufferInfo->portIndex = PortIndex::PORT_INDEX_OUTPUT;
478        omxBuffers_.emplace(std::make_pair(omxBuffer->bufferId, bufferInfo));
479        unUsedOutBuffers_.push_back(omxBuffer->bufferId);
480    }
481    return HDF_SUCCESS;
482}
483
484void CodecHdiDecode::FreeBuffers()
485{
486    // command to loaded
487    (void)client_->SendCommand(client_, OMX_CommandStateSet, OMX_StateLoaded, nullptr, 0);
488
489    // release all the buffers
490    auto iter = omxBuffers_.begin();
491    while (iter != omxBuffers_.end()) {
492        auto bufferInfo = iter->second;
493        iter = omxBuffers_.erase(iter);
494        (void)client_->FreeBuffer(client_, static_cast<uint32_t>(bufferInfo->portIndex), bufferInfo->omxBuffer.get());
495        bufferInfo = nullptr;
496    }
497
498    unUsedInBuffers_.clear();
499    unUsedOutBuffers_.clear();
500
501    // wait loaded
502    OMX_STATETYPE status = OMX_StateLoaded;
503    int32_t tryCount = MAX_WAIT_COUNT;
504    do {
505        int32_t err = client_->GetState(client_, &status);
506        if (err != HDF_SUCCESS) {
507            HDF_LOGE("%s GetState error [%{public}x]", __func__, err);
508            break;
509        }
510        if (status != OMX_StateLoaded) {
511            HDF_LOGI("Wait for OMX_StateLoaded status");
512            this->WaitForStatusChanged();
513        }
514        tryCount--;
515    } while ((status != OMX_StateLoaded) && (tryCount > 0));
516}
517
518void CodecHdiDecode::Release()
519{
520    omxMgr_->DestroyComponent(componentId_);
521    CodecComponentTypeRelease(client_);
522    client_ = nullptr;
523    CodecComponentManagerRelease();
524}
525
526bool CodecHdiDecode::FillAllTheBuffer()
527{
528    for (auto bufferId : unUsedOutBuffers_) {
529        HDF_LOGI("fill bufferid [%{public}d]", bufferId);
530        auto iter = omxBuffers_.find(bufferId);
531        if (iter != omxBuffers_.end()) {
532            auto bufferInfo = iter->second;
533            auto buffer = bufferInfo->omxBuffer.get();
534            if (bufferInfo->bufferHandle != nullptr) {
535                buffer->buffer = reinterpret_cast<uint8_t *>(bufferInfo->bufferHandle);
536                buffer->bufferLen = sizeof(BufferHandle) + sizeof(int32_t) * (bufferInfo->bufferHandle->reserveFds +
537                                                                              bufferInfo->bufferHandle->reserveInts);
538            }
539
540            auto err = client_->FillThisBuffer(client_, buffer);
541            if (err != HDF_SUCCESS) {
542                HDF_LOGE("%{public}s FillThisBuffer error", __func__);
543                return false;
544            }
545        }
546    }
547    return true;
548}
549
550int CodecHdiDecode::GetFreeBufferId()
551{
552    int bufferID = -1;
553    unique_lock<mutex> ulk(lockInputBuffers_);
554    size_t nSize = this->unUsedInBuffers_.size();
555    if (nSize > 0) {
556        bufferID = unUsedInBuffers_.front();
557        unUsedInBuffers_.pop_front();
558    }
559    return bufferID;
560}
561
562int32_t CodecHdiDecode::GetComponent()
563{
564    int32_t count = omxMgr_->GetComponentNum();
565    if (count <= 0) {
566        HDF_LOGE("%{public}s: GetComponentNum ret %{public}d", __func__, count);
567        return HDF_FAILURE;
568    }
569    auto caps = std::make_unique<CodecCompCapability[]>(count);
570    auto err = omxMgr_->GetComponentCapabilityList(caps.get(), count);
571    if (err != HDF_SUCCESS) {
572        HDF_LOGE("%{public}s: GetComponentCapabilityList ret %{public}d", __func__, err);
573        return err;
574    }
575    std::string compName("");
576    for (int32_t i = 0; i < count; i++) {
577        if (caps[i].type != VIDEO_DECODER) {
578            continue;
579        }
580        if (((caps[i].role == MEDIA_ROLETYPE_VIDEO_AVC) && (codecMime_ == CodecMime::AVC)) ||
581            ((caps[i].role == MEDIA_ROLETYPE_VIDEO_HEVC) && (codecMime_ == CodecMime::HEVC)) ||
582            ((caps[i].role == MEDIA_ROLETYPE_VIDEO_VP9) && (codecMime_ == CodecMime::VP9)) ||
583            ((caps[i].role == MEDIA_ROLETYPE_VIDEO_MPEG4) && (codecMime_ == CodecMime::MPEG4))) {
584            compName = caps[i].compName;
585            break;
586        }
587    }
588    if (compName.empty()) {
589        HDF_LOGE("%{public}s: role is unexpected ", __func__);
590        return HDF_FAILURE;
591    }
592    return omxMgr_->CreateComponent(&client_, &componentId_, compName.data(), reinterpret_cast<int64_t>(this),
593                                    callback_);
594}
595
596void CodecHdiDecode::Run()
597{
598    HDF_LOGI("...command to OMX_StateExecuting....");
599    auto err = client_->SendCommand(client_, OMX_CommandStateSet, OMX_StateExecuting, NULL, 0);
600    if (err != HDF_SUCCESS) {
601        HDF_LOGE("%{public}s failed to SendCommand with OMX_CommandStateSet:OMX_StateIdle", __func__);
602        return;
603    }
604
605    if (!FillAllTheBuffer()) {
606        HDF_LOGE("%{public}s FillAllTheBuffer error", __func__);
607        return;
608    }
609
610    auto t1 = std::chrono::system_clock::now();
611    bool eosFlag = false;
612    while (!eosFlag) {
613        HDF_LOGI(" inputput run");
614        int bufferID = GetFreeBufferId();
615        if (this->exit_) {
616            break;
617        }
618        if (bufferID < 0) {
619            usleep(10000);  // 10000: sleep time 10ms
620            continue;
621        }
622        auto iter = omxBuffers_.find(bufferID);
623        if (iter == omxBuffers_.end()) {
624            continue;
625        }
626        auto bufferInfo = iter->second;
627        const char *sharedAddr = static_cast<const char *>(bufferInfo->avSharedPtr->ReadFromAshmem(0, 0));
628        eosFlag = reader_->ReadOnePacket(ioIn_, const_cast<char *>(sharedAddr), bufferInfo->omxBuffer->filledLen);
629        bufferInfo->omxBuffer->offset = 0;
630        if (eosFlag) {
631            bufferInfo->omxBuffer->flag = OMX_BUFFERFLAG_EOS;
632        }
633        err = client_->EmptyThisBuffer(client_, bufferInfo->omxBuffer.get());
634        if (err != HDF_SUCCESS) {
635            HDF_LOGE("%{public}s EmptyThisBuffer error", __func__);
636            return;
637        }
638    }
639    // wait
640    while (!this->exit_) {
641        usleep(10000);  // 10000: sleep time 10ms
642    }
643    auto t2 = std::chrono::system_clock::now();
644    std::chrono::duration<double> diff = t2 - t1;
645    HDF_LOGI("decoder costtime %{public}f, count=%{public}d", diff.count(), count_);
646    // command to IDLE
647    (void)client_->SendCommand(client_, OMX_CommandStateSet, OMX_StateIdle, NULL, 0);
648    return;
649}
650int32_t CodecHdiDecode::OnEvent(struct CodecCallbackType *self, OMX_EVENTTYPE event, struct EventInfo *info)
651{
652    HDF_LOGI("%{public}s: appData[%{public}" PRId64 "] eEvent [%{public}d], nData1[%{public}d]", __func__,
653             info->appData, event, info->data1);
654    if (event == OMX_EventCmdComplete) {
655        OMX_COMMANDTYPE cmd = static_cast<OMX_COMMANDTYPE>(info->data1);
656        if (OMX_CommandStateSet == cmd) {
657            HDF_LOGI("OMX_CommandStateSet reached, status is %{public}d", info->data2);
658            g_core->OnStatusChanged();
659        }
660    }
661    return HDF_SUCCESS;
662}
663
664int32_t CodecHdiDecode::OnEmptyBufferDone(struct CodecCallbackType *self, int64_t appData,
665                                          const struct OmxCodecBuffer *buffer)
666{
667    HDF_LOGI("onEmptyBufferDone: pBuffer.bufferID [%{public}d]", buffer->bufferId);
668    return g_core->OnEmptyBufferDone(*buffer);
669}
670
671int32_t CodecHdiDecode::OnFillBufferDone(struct CodecCallbackType *self, int64_t appData,
672                                         const struct OmxCodecBuffer *buffer)
673{
674    HDF_LOGI("onFillBufferDone: pBuffer.bufferID [%{public}d]", buffer->bufferId);
675    return g_core->OnFillBufferDone(*buffer);
676}
677
678int32_t CodecHdiDecode::OnEmptyBufferDone(const struct OmxCodecBuffer &buffer)
679{
680    unique_lock<mutex> ulk(lockInputBuffers_);
681    unUsedInBuffers_.push_back(buffer.bufferId);
682    return HDF_SUCCESS;
683}
684
685int32_t CodecHdiDecode::OnFillBufferDone(const struct OmxCodecBuffer &buffer)
686{
687    if (exit_) {
688        return HDF_SUCCESS;
689    }
690
691    auto iter = omxBuffers_.find(buffer.bufferId);
692    if ((iter == omxBuffers_.end()) || (iter->second == nullptr)) {
693        return HDF_SUCCESS;
694    }
695    count_++;
696    // read buffer
697    auto bufferInfo = iter->second;
698    if (bufferInfo->avSharedPtr != nullptr) {
699        void *addr = const_cast<void *>(bufferInfo->avSharedPtr->ReadFromAshmem(buffer.filledLen, buffer.offset));
700        ioOut_.write(static_cast<char *>(addr), buffer.filledLen);
701    } else if (bufferInfo->bufferHandle != nullptr && buffer_ != nullptr) {
702        buffer_->Mmap(*bufferInfo->bufferHandle);
703        ioOut_.write(static_cast<char *>(bufferInfo->bufferHandle->virAddr), bufferInfo->bufferHandle->size);
704        buffer_->Unmap(*bufferInfo->bufferHandle);
705    }
706
707    ioOut_.flush();
708    if (buffer.flag == OMX_BUFFERFLAG_EOS) {
709        // end
710        exit_ = true;
711        HDF_LOGI("OnFillBufferDone the END coming");
712        return HDF_SUCCESS;
713    }
714    // call fillthisbuffer again
715    auto err = client_->FillThisBuffer(client_, bufferInfo->omxBuffer.get());
716    if (err != HDF_SUCCESS) {
717        HDF_LOGE("%{public}s FillThisBuffer error", __func__);
718        return HDF_SUCCESS;
719    }
720    return HDF_SUCCESS;
721}
722
723int main(int argc, char *argv[])
724{
725    CommandOpt opt;
726    CommandParse parse;
727    if (!parse.Parse(argc, argv, opt)) {
728        return HDF_FAILURE;
729    }
730    if (g_core == nullptr) {
731        g_core = new CodecHdiDecode();
732    }
733    // Init width, height, input file
734    if (!g_core->Init(opt)) {
735        delete g_core;
736        g_core = nullptr;
737        return HDF_FAILURE;
738    }
739
740    if (!g_core->Configure()) {
741        delete g_core;
742        g_core = nullptr;
743        return HDF_FAILURE;
744    }
745
746    if (!g_core->UseBuffers()) {
747        delete g_core;
748        g_core = nullptr;
749        return HDF_FAILURE;
750    }
751
752    g_core->Run();
753    g_core->FreeBuffers();
754    g_core->Release();
755    delete g_core;
756    g_core = nullptr;
757}