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 *>(¶m), 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 *>(¶m), 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 *>(¶m), 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 *>(¶m), 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 *>(¶m),
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 *>(¶m),
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 *>(¶m),
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 *>(¶m),
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 *>(¶m), 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 *>(¶m),
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 }