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