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 
22 using namespace std;
23 using namespace OHOS;
24 using namespace OHOS::HDI::Display::Buffer::V1_0;
25 using namespace OHOS::HDI::Display::Composer::V1_0;
26 namespace {
27 constexpr uint32_t FD_SIZE = sizeof(int);
28 constexpr uint32_t FRAME = 30 << 16;
29 constexpr uint32_t DENOMINATOR = 2;
30 constexpr uint32_t NUMERATOR = 3;
31 constexpr uint32_t MAX_WAIT_COUNT = 3;
32 }  // namespace
33 #define HDF_LOG_TAG codec_omx_hdi_dec
34 IDisplayBuffer *CodecHdiDecode::buffer_ = nullptr;
35 
36 #define AV_COLOR_FORMAT OMX_COLOR_FormatYUV420SemiPlanar
37 
38 static CodecHdiDecode *g_core = nullptr;
CodecHdiDecode()39 CodecHdiDecode::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 
~CodecHdiDecode()56 CodecHdiDecode::~CodecHdiDecode()
57 {
58     if (ioOut_.is_open()) {
59         ioOut_.close();
60     }
61     if (ioIn_.is_open()) {
62         ioIn_.close();
63     }
64 }
65 
WaitForStatusChanged()66 void CodecHdiDecode::WaitForStatusChanged()
67 {
68     unique_lock<mutex> autoLock(statusLock_);
69     statusCondition_.wait(autoLock);
70 }
71 
OnStatusChanged()72 void CodecHdiDecode::OnStatusChanged()
73 {
74     statusCondition_.notify_one();
75 }
76 
GetYuvSize()77 int CodecHdiDecode::GetYuvSize()
78 {
79     return width_ * height_ * NUMERATOR / DENOMINATOR;
80 }
81 
Init(CommandOpt & opt)82 bool 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 
ConfigPortDefine()141 int32_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 }
Configure()192 bool 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 
CheckAndUseBufferHandle()242 int32_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 
UseBuffers()288 bool 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 
UseBufferOnPort(PortIndex portIndex,int bufferCount,int bufferSize)326 int32_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 
UseBufferOnPort(PortIndex portIndex)378 int32_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 
UseBufferHandle(int bufferCount,int bufferSize)429 int32_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 
FreeBuffers()484 void 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 
Release()518 void CodecHdiDecode::Release()
519 {
520     omxMgr_->DestroyComponent(componentId_);
521     CodecComponentTypeRelease(client_);
522     client_ = nullptr;
523     CodecComponentManagerRelease();
524 }
525 
FillAllTheBuffer()526 bool 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 
GetFreeBufferId()550 int 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 
GetComponent()562 int32_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 
Run()596 void 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 }
OnEvent(struct CodecCallbackType * self,OMX_EVENTTYPE event,struct EventInfo * info)650 int32_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 
OnEmptyBufferDone(struct CodecCallbackType * self,int64_t appData,const struct OmxCodecBuffer * buffer)664 int32_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 
OnFillBufferDone(struct CodecCallbackType * self,int64_t appData,const struct OmxCodecBuffer * buffer)671 int32_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 
OnEmptyBufferDone(const struct OmxCodecBuffer & buffer)678 int32_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 
OnFillBufferDone(const struct OmxCodecBuffer & buffer)685 int32_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 
main(int argc,char * argv[])723 int 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 }