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 }