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