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 }