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"
24 using namespace std;
25 using namespace OHOS;
26 using OHOS::sptr;
27 using OHOS::HDI::Base::NativeBuffer;
28 using namespace OHOS::HDI::Codec::V3_0;
29 using namespace OHOS::HDI::Display::Buffer::V1_0;
30 using namespace OHOS::HDI::Display::Composer::V1_0;
31 #define HDF_LOG_TAG     codec_omx_hdi_dec
32 #define AV_COLOR_FORMAT OMX_COLOR_FormatYUV420SemiPlanar
33 IDisplayBuffer *CodecHdiDecode::gralloc_ = nullptr;
34 CodecUtil *CodecHdiDecode::util_;
35 namespace {
36 constexpr int32_t FRAME = 30 << 16;
37 constexpr int32_t DENOMINATOR = 2;
38 constexpr int32_t NUMERATOR = 3;
39 constexpr int32_t START_CODE_OFFSET_ONE = -1;
40 constexpr int32_t INIT_BUFFER_CODE = -1;
41 constexpr int32_t START_CODE_OFFSET_SEC = -2;
42 constexpr int32_t START_CODE_OFFSET_THIRD = -3;
43 constexpr int32_t START_CODE_SIZE_FRAME = 4;
44 constexpr int32_t START_CODE_SIZE_SLICE = 3;
45 constexpr char START_CODE = 0x1;
46 }  // namespace
47 
CodecHdiDecode()48 CodecHdiDecode::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 
~CodecHdiDecode()63 CodecHdiDecode::~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 
WaitForStatusChanged()76 void CodecHdiDecode::WaitForStatusChanged()
77 {
78     unique_lock<mutex> autoLock(statusLock_);
79     statusCondition_.wait(autoLock);
80 }
81 
OnStatusChanged()82 void CodecHdiDecode::OnStatusChanged()
83 {
84     statusCondition_.notify_one();
85 }
86 
GetYuvSize()87 int CodecHdiDecode::GetYuvSize()
88 {
89     return width_ * height_ * NUMERATOR / DENOMINATOR;
90 }
91 
ReadOnePacket(FILE * fp,char * buf,uint32_t & filledCount)92 bool 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 
Init(const CommandOpt & opt)128 bool 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 
ConfigPortDefine()178 int32_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 }
Configure()234 bool 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 
CheckSupportBufferType(PortIndex portIndex,CodecBufferType codecBufferType)284 int32_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 
CheckAndUseDMABuffer()309 int32_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 
CheckAndUseBufferHandle()317 int32_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 
UseBuffers()376 bool 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 
UseBufferOnPort(PortIndex portIndex,int bufferCount,int bufferSize)415 int32_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 
UseBufferOnPort(PortIndex portIndex)470 int32_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 
UseDMABuffer(PortIndex portIndex,int bufferCount,int bufferSize)522 int32_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 
UseBufferHandle(int bufferCount,int bufferSize)569 int32_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 
FreeBuffers()617 void 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 
Release()650 void CodecHdiDecode::Release()
651 {
652     omxMgr_->DestroyComponent(componentId_);
653     client_ = nullptr;
654     callback_ = nullptr;
655     omxMgr_ = nullptr;
656 }
657 
FillAllTheBuffer()658 bool 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 
GetFreeBufferId()676 int 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 
GetComponentName(std::string & compName)688 int32_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 }
Run()717 void 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 
FillCodecBuffer(std::shared_ptr<BufferInfo> bufferInfo,bool & eosFlag)771 bool 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 
OnEmptyBufferDone(const struct OmxCodecBuffer & buffer)787 int32_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 
OnFillBufferDone(const struct OmxCodecBuffer & buffer)795 int32_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 
FreeOutBuffer()834 void 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 
HandleEventPortSettingsChanged(uint32_t data1,uint32_t data2)853 void 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 
EventHandler(CodecEventType event,const EventInfo & info)873 int32_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 
main(int argc,char * argv[])896 int 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 }