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