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_encode.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::V2_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_enc
32 #define AV_COLOR_FORMAT OMX_COLOR_FormatYUV420SemiPlanar
33 IDisplayBuffer *CodecHdiEncode::gralloc_ = nullptr;
34 CodecUtil *CodecHdiEncode::util_;
35 namespace {
36 constexpr uint32_t FRAME = 30 << 16;
37 constexpr uint32_t BUFFER_COUNT = 10;
38 constexpr uint32_t BITRATE = 3000000;
39 constexpr uint32_t DENOMINATOR = 2;
40 constexpr uint32_t NUMERATOR = 3;
41 constexpr int32_t INIT_BUFFER_CODE = -1;
42 } // namespace
CodecHdiEncode()43 CodecHdiEncode::CodecHdiEncode() : fpIn_(nullptr), fpOut_(nullptr)
44 {
45 client_ = nullptr;
46 callback_ = nullptr;
47 omxMgr_ = nullptr;
48 exit_ = false;
49 useBufferHandle_ = false;
50 useDMABuffer_ = false;
51 width_ = 0;
52 height_ = 0;
53 componentId_ = 0;
54 }
55
~CodecHdiEncode()56 CodecHdiEncode::~CodecHdiEncode()
57 {
58 if (fpOut_ != nullptr) {
59 fclose(fpOut_);
60 fpOut_ = nullptr;
61 }
62 if (fpIn_ != nullptr) {
63 fclose(fpIn_);
64 fpIn_ = nullptr;
65 }
66 }
67
WaitForStatusChanged()68 void CodecHdiEncode::WaitForStatusChanged()
69 {
70 unique_lock<mutex> autoLock(statusLock_);
71 statusCondition_.wait(autoLock);
72 }
73
OnStatusChanged()74 void CodecHdiEncode::OnStatusChanged()
75 {
76 statusCondition_.notify_one();
77 }
78
ReadOneFrame(FILE * fp,char * buf,uint32_t & filledCount)79 bool CodecHdiEncode::ReadOneFrame(FILE *fp, char *buf, uint32_t &filledCount)
80 {
81 bool ret = false;
82 size_t count = width_ * height_ * NUMERATOR / DENOMINATOR;
83 size_t t = fread(buf, 1, count, fp);
84 if (t < count) {
85 HDF_LOGE("fail to read file");
86 return false;
87 }
88 if (feof(fp)) {
89 ret = true;
90 }
91 filledCount = static_cast<uint32_t>(t);
92 return ret;
93 }
94
Init(const CommandOpt & opt)95 bool CodecHdiEncode::Init(const CommandOpt &opt)
96 {
97 this->width_ = opt.width;
98 this->height_ = opt.height;
99 this->stride_ = AlignUp(width_);
100 this->useBufferHandle_ = opt.useBufferHandle;
101 this->useDMABuffer_ = opt.useDMABuffer;
102 HDF_LOGI("width[%{public}d], height[%{public}d]", width_, height_);
103 // gralloc init
104 gralloc_ = IDisplayBuffer::Get();
105 fpIn_ = fopen(opt.fileInput.c_str(), "rb");
106 fpOut_ = fopen(opt.fileOutput.c_str(), "wb+");
107 if ((fpIn_ == nullptr) || (fpOut_ == nullptr)) {
108 HDF_LOGE("%{public}s:failed to open file %{public}s or %{public}s", __func__, opt.fileInput.c_str(),
109 opt.fileOutput.c_str());
110 return false;
111 }
112 // Interface init
113 omxMgr_ = OHOS::HDI::Codec::V2_0::ICodecComponentManager::Get();
114 callback_ = new CodecHdiCallback(shared_from_this());
115 if ((omxMgr_ == nullptr) || (callback_ == nullptr)) {
116 HDF_LOGE("%{public}s:omxMgr_ or callback_ is null", __func__);
117 return false;
118 }
119 std::string compName("");
120 auto err = GetComponentName(compName);
121 if (err != HDF_SUCCESS) {
122 HDF_LOGE("%{public}s failed to GetComponentName", __func__);
123 return false;
124 }
125 // create a component
126 err = omxMgr_->CreateComponent(client_, componentId_, compName, reinterpret_cast<int64_t>(this), callback_);
127 if (err != HDF_SUCCESS) {
128 HDF_LOGE("%{public}s failed to CreateComponent", __func__);
129 return false;
130 }
131 // get version
132 struct OHOS::HDI::Codec::V2_0::CompVerInfo verInfo;
133 err = memset_s(&verInfo, sizeof(verInfo), 0, sizeof(verInfo));
134 if (err != EOK) {
135 HDF_LOGE("%{public}s: memset_s verInfo err [%{public}d].", __func__, err);
136 return false;
137 }
138 err = client_->GetComponentVersion(verInfo);
139 if (err != HDF_SUCCESS) {
140 HDF_LOGE("%{public}s failed to CreateComponent", __func__);
141 return false;
142 }
143
144 return true;
145 }
146
Configure()147 bool CodecHdiEncode::Configure()
148 {
149 if (client_ == nullptr) {
150 return false;
151 }
152 // set input width, height and COLOR, set ouput port width and height
153 if (ConfigPortDefine() != HDF_SUCCESS) {
154 HDF_LOGE("%{public}s ConfigPortDefine error", __func__);
155 return false;
156 }
157 if (ConfigBitMode() != HDF_SUCCESS) {
158 HDF_LOGE("%{public}s ConfigBitMode error", __func__);
159 return false;
160 }
161 if (CheckAndUseBufferHandle() != HDF_SUCCESS) {
162 HDF_LOGE("%{public}s ConfigUseBufferHandle error", __func__);
163 return false;
164 }
165
166 if (CheckAndUseDMABuffer() != HDF_SUCCESS) {
167 HDF_LOGE("%{public}s ConfigUseBufferHandle error", __func__);
168 return false;
169 }
170 return true;
171 }
172
CheckSupportBufferType(PortIndex portIndex,CodecBufferType codecBufferType)173 int32_t CodecHdiEncode::CheckSupportBufferType(PortIndex portIndex, CodecBufferType codecBufferType)
174 {
175 //get support buffer
176 SupportBufferType param;
177 std::vector<int8_t> inVec, outVec;
178 if (util_->InitParamInOhos(param) != HDF_SUCCESS) {
179 return HDF_FAILURE;
180 }
181 param.portIndex = static_cast<uint32_t>(portIndex);
182 util_->ObjectToVector(param, inVec);
183 auto err = client_->GetParameter(OMX_IndexParamSupportBufferType, inVec, outVec);
184 if (err != HDF_SUCCESS) {
185 HDF_LOGE("%{public}s failed get parameter with portIndex %{public}d and ret %{public}d ",
186 __func__, portIndex, err);
187 }
188 util_->VectorToObject(outVec, param);
189 if (!(param.bufferTypes & codecBufferType)) {
190 HDF_LOGE("%{public}s unSupport bufferType %{public}d ,ret is %{public}d",
191 __func__, codecBufferType, param.bufferTypes);
192 return HDF_FAILURE;
193 }
194 return HDF_SUCCESS;
195 }
196
CheckAndUseDMABuffer()197 int32_t CodecHdiEncode::CheckAndUseDMABuffer()
198 {
199 if (!useDMABuffer_) {
200 return HDF_SUCCESS;
201 }
202 auto err = CheckSupportBufferType(PortIndex::PORT_INDEX_OUTPUT, CODEC_BUFFER_TYPE_DMA_MEM_FD);
203 if (err != HDF_SUCCESS) {
204 return HDF_FAILURE;
205 }
206 return err;
207 }
208
CheckAndUseBufferHandle()209 int32_t CodecHdiEncode::CheckAndUseBufferHandle()
210 {
211 if (!useBufferHandle_) {
212 return HDF_SUCCESS;
213 }
214
215 std::vector<int8_t> inVec, outVec;
216 auto err = GetParameterSupportBufferType(inVec, outVec);
217 if (err != HDF_SUCCESS) {
218 return err;
219 }
220
221 GetBufferHandleUsageParams usage;
222 if (util_->InitParamInOhos(usage) != HDF_SUCCESS) {
223 return HDF_FAILURE;
224 }
225 usage.portIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_INPUT);
226 util_->ObjectToVector(usage, inVec);
227 err = client_->GetParameter(OMX_IndexParamGetBufferHandleUsage, inVec, outVec);
228 if (err != HDF_SUCCESS) {
229 HDF_LOGE("%{public}s failed with PORT_INDEX_INPUT, index is OMX_IndexParamGetBufferHandleUsage", __func__);
230 return err;
231 }
232 util_->VectorToObject(outVec, usage);
233
234 UseBufferType type;
235 if (util_->InitParamInOhos(type) != HDF_SUCCESS) {
236 return HDF_FAILURE;
237 }
238 type.portIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_INPUT);
239 type.bufferType = CODEC_BUFFER_TYPE_DYNAMIC_HANDLE;
240 util_->ObjectToVector(type, inVec);
241 err = client_->SetParameter(OMX_IndexParamUseBufferType, inVec);
242 if (err != HDF_SUCCESS) {
243 HDF_LOGE("%{public}s failed with PORT_INDEX_INPUT, index is OMX_IndexParamUseBufferType", __func__);
244 return err;
245 }
246 return err;
247 }
248
GetParameterSupportBufferType(std::vector<int8_t> & inVec,std::vector<int8_t> & outVec)249 int32_t CodecHdiEncode::GetParameterSupportBufferType(std::vector<int8_t> &inVec, std::vector<int8_t> &outVec)
250 {
251 SupportBufferType param;
252 if (util_->InitParamInOhos(param) != HDF_SUCCESS) {
253 return HDF_FAILURE;
254 }
255 param.portIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_OUTPUT);
256 util_->ObjectToVector(param, inVec);
257
258 auto err = client_->GetParameter(OMX_IndexParamSupportBufferType, inVec, outVec);
259 if (err != HDF_SUCCESS) {
260 HDF_LOGE("%{public}s failed with PORT_INDEX_OUTPUT, index is OMX_IndexParamSupportBufferType", __func__);
261 return err;
262 }
263 util_->VectorToObject(outVec, param);
264
265 if (util_->InitParamInOhos(param) != HDF_SUCCESS) {
266 return HDF_FAILURE;
267 }
268 param.portIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_INPUT);
269 util_->ObjectToVector(param, inVec);
270 err = client_->GetParameter(OMX_IndexParamSupportBufferType, inVec, outVec);
271 if (err != HDF_SUCCESS) {
272 HDF_LOGE("%{public}s failed with PORT_INDEX_INPUT, index is OMX_IndexParamSupportBufferType", __func__);
273 return err;
274 }
275 util_->VectorToObject(outVec, param);
276 return err;
277 }
278
UseBuffers()279 bool CodecHdiEncode::UseBuffers()
280 {
281 // commad to IDLE
282 auto err = client_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_IDLE, {});
283 if (err != HDF_SUCCESS) {
284 HDF_LOGE("%{public}s failed to SendCommand with CODEC_COMMAND_STATE_SET:CODEC_STATE_IDLE", __func__);
285 return false;
286 }
287
288 // use buffer on input port
289 err = UseBufferOnPort(PortIndex::PORT_INDEX_INPUT);
290 if (err != HDF_SUCCESS) {
291 HDF_LOGE("%{public}s UseBufferOnPort PORT_INDEX_INPUT error", __func__);
292 return false;
293 }
294
295 // use buffer on output port
296 err = UseBufferOnPort(PortIndex::PORT_INDEX_OUTPUT);
297 if (err != HDF_SUCCESS) {
298 HDF_LOGE("%{public}s UseBufferOnPort PORT_INDEX_OUTPUT error", __func__);
299 return false;
300 }
301
302 if (useBufferHandle_ && CreateBufferHandle() != HDF_SUCCESS) {
303 HDF_LOGE("%{public}s CreateBufferHandle error", __func__);
304 return false;
305 }
306
307 // wait executing state
308 CodecStateType status = CODEC_STATE_INVALID;
309 err = client_->GetState(status);
310 if (err != HDF_SUCCESS) {
311 HDF_LOGE("%{public}s GetState err [%{public}x]", __func__, err);
312 return false;
313 }
314
315 // wait loaded
316 if (status != CODEC_STATE_IDLE) {
317 HDF_LOGI("Wait for CODEC_STATE_LOADED status");
318 this->WaitForStatusChanged();
319 } else {
320 HDF_LOGI(" status is %{public}d", status);
321 }
322 return true;
323 }
324
UseBufferOnPort(PortIndex portIndex)325 int32_t CodecHdiEncode::UseBufferOnPort(PortIndex portIndex)
326 {
327 HDF_LOGI("%{public}s enter, portIndex = %{public}d", __func__, portIndex);
328 int bufferSize = 0;
329 int bufferCount = 0;
330 bool portEnable = false;
331
332 OMX_PARAM_PORTDEFINITIONTYPE param;
333 if (util_->InitParam(param) != HDF_SUCCESS) {
334 return HDF_FAILURE;
335 }
336 param.nPortIndex = static_cast<uint32_t>(portIndex);
337 std::vector<int8_t> inVec, outVec;
338 util_->ObjectToVector(param, inVec);
339 auto err = client_->GetParameter(OMX_IndexParamPortDefinition, inVec, outVec);
340 if (err != HDF_SUCCESS) {
341 HDF_LOGE("%{public}s failed to GetParameter with OMX_IndexParamPortDefinition : portIndex[%{public}d]",
342 __func__, portIndex);
343 return err;
344 }
345 util_->VectorToObject(outVec, param);
346
347 bufferSize = param.nBufferSize;
348 bufferCount = param.nBufferCountActual;
349 portEnable = param.bEnabled;
350 HDF_LOGI("buffer index [%{public}d], buffer size [%{public}d], buffer count [%{public}d], "
351 "portEnable[%{public}d], ret [%{public}d]",
352 portIndex, bufferSize, bufferCount, portEnable, err);
353 if (portIndex == PortIndex::PORT_INDEX_INPUT) {
354 bufferSize = width_ * height_ * NUMERATOR / DENOMINATOR;
355 } else if (bufferSize == 0) {
356 bufferSize = width_ * height_;
357 HDF_LOGI("bufferSize[%{public}d], width[%{public}d], height[%{public}d]", bufferSize, width_, height_);
358 }
359 if (useBufferHandle_ && portIndex == PortIndex::PORT_INDEX_INPUT) {
360 err = UseDynaBuffer(bufferCount, bufferSize);
361 } else if (useDMABuffer_ && portIndex == PortIndex::PORT_INDEX_OUTPUT) {
362 err = UseDMABuffer(portIndex, bufferCount, bufferSize);
363 } else {
364 err = UseBufferOnPort(portIndex, bufferCount, bufferSize);
365 }
366
367 if (err != HDF_SUCCESS) {
368 return err;
369 }
370
371 // if port is disable, changed to enable
372 if (!portEnable) {
373 err = client_->SendCommand(CODEC_COMMAND_PORT_ENABLE, static_cast<uint32_t>(portIndex), {});
374 if (err != HDF_SUCCESS) {
375 HDF_LOGE("%{public}s SendCommand OMX_CommandPortEnable::PORT_INDEX_INPUT error", __func__);
376 return err;
377 }
378 }
379
380 return HDF_SUCCESS;
381 }
382
UseDMABuffer(PortIndex portIndex,int bufferCount,int bufferSize)383 int32_t CodecHdiEncode::UseDMABuffer(PortIndex portIndex, int bufferCount, int bufferSize)
384 {
385 if (bufferCount <= 0 || bufferSize <= 0) {
386 HDF_LOGE("UseDMABuffer bufferCount <= 0 or bufferSize <= 0");
387 return HDF_ERR_INVALID_PARAM;
388 }
389 for (int i = 0; i < bufferCount; i++) {
390 std::shared_ptr<OmxCodecBuffer> omxBuffer = std::make_shared<OmxCodecBuffer>();
391 omxBuffer->size = sizeof(OmxCodecBuffer);
392 omxBuffer->version.version.majorVersion = 1;
393 omxBuffer->bufferType = CODEC_BUFFER_TYPE_DMA_MEM_FD;
394 omxBuffer->fd = INIT_BUFFER_CODE;
395 omxBuffer->bufferhandle = nullptr;
396 omxBuffer->allocLen = bufferSize;
397 omxBuffer->fenceFd = INIT_BUFFER_CODE;
398 omxBuffer->pts = 0;
399 omxBuffer->flag = 0;
400
401 OmxCodecBuffer outBuffer;
402 auto err = client_->AllocateBuffer(static_cast<uint32_t>(portIndex), *omxBuffer.get(), outBuffer);
403 if (err != HDF_SUCCESS) {
404 HDF_LOGE("%{public}s failed to UseBuffer with portIndex[%{public}d]", __func__, portIndex);
405 return err;
406 }
407 omxBuffer->bufferId = outBuffer.bufferId;
408 HDF_LOGI("UseBuffer returned bufferID [%{public}d]", omxBuffer->bufferId);
409
410 std::shared_ptr<BufferInfo> bufferInfo = std::make_shared<BufferInfo>();
411 bufferInfo->omxBuffer = omxBuffer;
412 bufferInfo->portIndex = portIndex;
413 omxBuffers_.insert(std::make_pair(omxBuffer->bufferId, bufferInfo));
414 unUsedOutBuffers_.push_back(omxBuffer->bufferId);
415
416 const void *addr = mmap(nullptr, static_cast<size_t>(bufferInfo->omxBuffer->allocLen),
417 PROT_READ | PROT_WRITE, MAP_SHARED, outBuffer.fd, 0);
418 if (addr == nullptr) {
419 HDF_LOGE("%{public}s mmap fail fd %{public}d", __func__, outBuffer.fd);
420 return HDF_FAILURE;
421 } else {
422 addrs_[omxBuffer->bufferId] = addr;
423 }
424 }
425 return HDF_SUCCESS;
426 }
UseBufferOnPort(PortIndex portIndex,int bufferCount,int bufferSize)427 int32_t CodecHdiEncode::UseBufferOnPort(PortIndex portIndex, int bufferCount, int bufferSize)
428 {
429 if (bufferCount <= 0 || bufferSize <= 0) {
430 return HDF_ERR_INVALID_PARAM;
431 }
432
433 for (int i = 0; i < bufferCount; i++) {
434 auto omxBuffer = std::make_shared<OmxCodecBuffer>();
435 omxBuffer->size = sizeof(OmxCodecBuffer);
436 omxBuffer->version.version.majorVersion = 1;
437 omxBuffer->bufferType = CODEC_BUFFER_TYPE_AVSHARE_MEM_FD;
438 int fd = AshmemCreate(0, bufferSize);
439 shared_ptr<Ashmem> spSharedMem = make_shared<Ashmem>(fd, bufferSize);
440 omxBuffer->fd = fd;
441 omxBuffer->bufferhandle = nullptr;
442 omxBuffer->allocLen = bufferSize;
443 omxBuffer->fenceFd = -1;
444 omxBuffer->pts = 0;
445 omxBuffer->flag = 0;
446 if (portIndex == PortIndex::PORT_INDEX_INPUT) {
447 omxBuffer->type = OHOS::HDI::Codec::V2_0::READ_ONLY_TYPE;
448 spSharedMem->MapReadAndWriteAshmem();
449 } else {
450 omxBuffer->type = OHOS::HDI::Codec::V2_0::READ_WRITE_TYPE;
451 spSharedMem->MapReadOnlyAshmem();
452 }
453 OmxCodecBuffer outBuffer;
454 auto err = client_->UseBuffer(static_cast<uint32_t>(portIndex), *omxBuffer.get(), outBuffer);
455 if (err != HDF_SUCCESS) {
456 HDF_LOGE("%{public}s failed to UseBuffer with portIndex[%{public}d]", __func__, portIndex);
457 spSharedMem->UnmapAshmem();
458 spSharedMem->CloseAshmem();
459 spSharedMem = nullptr;
460 return err;
461 }
462
463 omxBuffer->bufferId = outBuffer.bufferId;
464 HDF_LOGI("UseBuffer returned bufferID [%{public}d]", omxBuffer->bufferId);
465
466 auto bufferInfo = std::make_shared<BufferInfo>();
467 bufferInfo->omxBuffer = omxBuffer;
468 bufferInfo->avSharedPtr = spSharedMem;
469 bufferInfo->portIndex = portIndex;
470 omxBuffers_.insert(std::make_pair(omxBuffer->bufferId, bufferInfo));
471 if (portIndex == PortIndex::PORT_INDEX_INPUT) {
472 unUsedInBuffers_.push_back(omxBuffer->bufferId);
473 } else {
474 unUsedOutBuffers_.push_back(omxBuffer->bufferId);
475 }
476 }
477 return HDF_SUCCESS;
478 }
479
UseDynaBuffer(int bufferCount,int bufferSize)480 int32_t CodecHdiEncode::UseDynaBuffer(int bufferCount, int bufferSize)
481 {
482 if (bufferCount <= 0 || bufferSize <= 0) {
483 return HDF_ERR_INVALID_PARAM;
484 }
485
486 for (int i = 0; i < bufferCount; i++) {
487 auto omxBuffer = std::make_shared<OmxCodecBuffer>();
488 omxBuffer->size = sizeof(OmxCodecBuffer);
489 omxBuffer->version.version.majorVersion = 1;
490 omxBuffer->bufferType = CODEC_BUFFER_TYPE_DYNAMIC_HANDLE;
491 omxBuffer->fd = -1;
492 omxBuffer->bufferhandle = nullptr;
493 omxBuffer->allocLen = bufferSize;
494 omxBuffer->fenceFd = -1;
495 omxBuffer->pts = 0;
496 omxBuffer->flag = 0;
497
498 OmxCodecBuffer outBuffer;
499 auto err = client_->UseBuffer(static_cast<uint32_t>(PortIndex::PORT_INDEX_INPUT),
500 *omxBuffer.get(), outBuffer);
501 if (err != HDF_SUCCESS) {
502 HDF_LOGE("%{public}s failed to UseBuffer with PORT_INDEX_INPUT", __func__);
503 return err;
504 }
505
506 omxBuffer->bufferId = outBuffer.bufferId;
507 HDF_LOGI("UseBuffer returned bufferID [%{public}d]", omxBuffer->bufferId);
508
509 auto bufferInfo = std::make_shared<BufferInfo>();
510 bufferInfo->omxBuffer = omxBuffer;
511 bufferInfo->portIndex = PortIndex::PORT_INDEX_INPUT;
512 omxBuffers_.insert(std::make_pair(omxBuffer->bufferId, bufferInfo));
513 unUsedInBuffers_.push_back(omxBuffer->bufferId);
514 }
515 return HDF_SUCCESS;
516 }
517
FreeBuffers()518 void CodecHdiEncode::FreeBuffers()
519 {
520 // send command to loaded state
521 (void)client_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_LOADED, {});
522
523 // All the buffer must be released, otherwise the component will wait
524 auto iter = omxBuffers_.begin();
525 while (iter != omxBuffers_.end()) {
526 auto bufferInfo = iter->second;
527 (void)client_->FreeBuffer(static_cast<uint32_t>(bufferInfo->portIndex), *bufferInfo->omxBuffer.get());
528 iter = omxBuffers_.erase(iter);
529 }
530 unUsedInBuffers_.clear();
531 unUsedOutBuffers_.clear();
532
533 CodecStateType status = CODEC_STATE_INVALID;
534 int32_t tryCount = 3;
535 do {
536 int32_t err = client_->GetState(status);
537 if (err != HDF_SUCCESS) {
538 HDF_LOGE("%s GetState error [%{public}x]", __func__, err);
539 break;
540 }
541 if (status != CODEC_STATE_LOADED) {
542 HDF_LOGI("Wait for OMX_StateLoaded status");
543 this->WaitForStatusChanged();
544 }
545 tryCount--;
546 } while ((status != CODEC_STATE_LOADED) && (tryCount > 0));
547 }
548
Release()549 void CodecHdiEncode::Release()
550 {
551 omxMgr_->DestroyComponent(componentId_);
552 client_ = nullptr;
553 callback_ = nullptr;
554 omxMgr_ = nullptr;
555 }
556
FillAllTheBuffer()557 bool CodecHdiEncode::FillAllTheBuffer()
558 {
559 for (auto bufferId : unUsedOutBuffers_) {
560 HDF_LOGI("fill bufferid [%{public}d]", bufferId);
561 auto iter = omxBuffers_.find(bufferId);
562 if (iter != omxBuffers_.end()) {
563 auto bufferInfo = iter->second;
564 auto err = client_->FillThisBuffer(*bufferInfo->omxBuffer.get());
565 if (err != HDF_SUCCESS) {
566 HDF_LOGE("%{public}s FillThisBuffer error", __func__);
567 return false;
568 }
569 }
570 }
571 return true;
572 }
573
GetFreeBufferId()574 int CodecHdiEncode::GetFreeBufferId()
575 {
576 int bufferID = -1;
577 unique_lock<mutex> ulk(lockInputBuffers_);
578 size_t nSize = this->unUsedInBuffers_.size();
579 if (nSize != 0) {
580 bufferID = unUsedInBuffers_.front();
581 unUsedInBuffers_.pop_front();
582 }
583 return bufferID;
584 }
585
GetComponentName(std::string & compName)586 int32_t CodecHdiEncode::GetComponentName(std::string &compName)
587 {
588 OHOS::HDI::Codec::V2_0::AvCodecRole role = OHOS::HDI::Codec::V2_0::AvCodecRole::MEDIA_ROLETYPE_VIDEO_AVC;
589 int32_t count = 0;
590 auto err = omxMgr_->GetComponentNum(count);
591 if (err != HDF_SUCCESS || count <= 0) {
592 HDF_LOGE("%{public}s GetComponentNum return %{public}d, count = %{public}d", __func__, err, count);
593 return HDF_FAILURE;
594 }
595 std::vector<CodecCompCapability> caps;
596 err = omxMgr_->GetComponentCapabilityList(caps, count);
597 if (err != HDF_SUCCESS) {
598 HDF_LOGE("%{public}s GetComponentCapabilityList return %{public}d", __func__, err);
599 return err;
600 }
601 err = HDF_FAILURE;
602 for (auto cap : caps) {
603 if (cap.type == OHOS::HDI::Codec::V2_0::CodecType::VIDEO_ENCODER && cap.role == role) {
604 compName = cap.compName;
605 err = HDF_SUCCESS;
606 }
607 }
608 return err;
609 }
610
Run()611 void CodecHdiEncode::Run()
612 {
613 auto err = client_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_EXECUTING, {});
614 if (err != HDF_SUCCESS) {
615 HDF_LOGE("%{public}s failed to SendCommand with CODEC_COMMAND_STATE_SET:CODEC_STATE_IDLE", __func__);
616 return;
617 }
618 if (!FillAllTheBuffer()) {
619 HDF_LOGE("%{public}s FillAllTheBuffer error", __func__);
620 return;
621 }
622 bool endFlag = false;
623 while (!endFlag) {
624 int bufferID = GetFreeBufferId();
625 if (this->exit_) {
626 break;
627 }
628 if (bufferID < 0) {
629 usleep(10000); // 10000 for wait 10ms
630 continue;
631 }
632 auto iter = omxBuffers_.find(bufferID);
633 if (iter == omxBuffers_.end()) {
634 continue;
635 }
636 auto bufferInfo = iter->second;
637 if (!FillCodecBuffer(bufferInfo, endFlag)) {
638 break;
639 }
640 err = client_->EmptyThisBuffer(*bufferInfo->omxBuffer.get());
641 bufferInfo->omxBuffer->bufferhandle = nullptr;
642 if (err != HDF_SUCCESS) {
643 HDF_LOGE("%{public}s EmptyThisBuffer error", __func__);
644 return;
645 }
646 }
647 while (!this->exit_) {
648 usleep(10000); // 10000 for wait 10ms
649 }
650 (void)client_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_IDLE, {});
651 return;
652 }
653
FillCodecBuffer(std::shared_ptr<BufferInfo> bufferInfo,bool & endFlag)654 bool CodecHdiEncode::FillCodecBuffer(std::shared_ptr<BufferInfo> bufferInfo, bool &endFlag)
655 {
656 if (gralloc_ == nullptr) {
657 HDF_LOGE("%{public}s gralloc_ is null", __func__);
658 return false;
659 }
660 if (useBufferHandle_) {
661 int bufferHandleId = freeBufferHandles_.front();
662 if (bufferHandleId < 0 || bufferHandleId >= BUFFER_COUNT) {
663 HDF_LOGE("%{public}s bufferHandleId [%{public}d]", __func__, bufferHandleId);
664 return false;
665 }
666 freeBufferHandles_.pop_front();
667 bufferInfo->bufferHandleId = bufferHandleId;
668 BufferHandle *bufferHandle = bufferHandles_[bufferHandleId];
669 if (bufferHandle != nullptr) {
670 gralloc_->Mmap(*bufferHandle);
671 endFlag = this->ReadOneFrame(fpIn_, static_cast<char *>(bufferHandle->virAddr),
672 bufferInfo->omxBuffer->filledLen);
673 gralloc_->Unmap(*bufferHandle);
674 bufferInfo->omxBuffer->bufferhandle = new NativeBuffer(bufferHandle);
675 }
676 } else {
677 // read data from ashmem
678 void *sharedAddr = const_cast<void *>(bufferInfo->avSharedPtr->ReadFromAshmem(0, 0));
679 endFlag = this->ReadOneFrame(fpIn_, static_cast<char *>(sharedAddr), bufferInfo->omxBuffer->filledLen);
680 }
681 bufferInfo->omxBuffer->offset = 0;
682 if (endFlag) {
683 bufferInfo->omxBuffer->flag = OMX_BUFFERFLAG_EOS;
684 }
685
686 return true;
687 }
688
CreateBufferHandle()689 int32_t CodecHdiEncode::CreateBufferHandle()
690 {
691 if (gralloc_ == nullptr) {
692 HDF_LOGE("%{public}s gralloc_ is null", __func__);
693 return HDF_ERR_INVALID_PARAM;
694 }
695
696 AllocInfo alloc = {.width = this->stride_,
697 .height = this->height_,
698 .usage = HBM_USE_CPU_READ | HBM_USE_CPU_WRITE | HBM_USE_MEM_DMA,
699 .format = PIXEL_FMT_YCBCR_420_SP};
700
701 int32_t err = HDF_SUCCESS;
702 for (uint32_t i = 0; i < BUFFER_COUNT; i++) {
703 BufferHandle *bufferHandle = nullptr;
704 err = gralloc_->AllocMem(alloc, bufferHandle);
705 if (err != HDF_SUCCESS) {
706 HDF_LOGE("%{public}s AllocMem fail", __func__);
707 return err;
708 }
709 bufferHandles_.emplace(std::make_pair(i, bufferHandle));
710 freeBufferHandles_.push_back(i);
711 }
712 return err;
713 }
714
EventHandler(OHOS::HDI::Codec::V2_0::CodecEventType event,const OHOS::HDI::Codec::V2_0::EventInfo & info)715 int32_t CodecHdiEncode::EventHandler(OHOS::HDI::Codec::V2_0::CodecEventType event,
716 const OHOS::HDI::Codec::V2_0::EventInfo &info)
717 {
718 if (event == CODEC_EVENT_CMD_COMPLETE) {
719 CodecCommandType cmd = (CodecCommandType)info.data1;
720 if (CODEC_COMMAND_STATE_SET == cmd) {
721 HDF_LOGI("CODEC_COMMAND_STATE_SET reached, status is %{public}d", info.data2);
722 this->OnStatusChanged();
723 }
724 }
725
726 return HDF_SUCCESS;
727 }
728
OnEmptyBufferDone(const struct OmxCodecBuffer & buffer)729 int32_t CodecHdiEncode::OnEmptyBufferDone(const struct OmxCodecBuffer &buffer)
730 {
731 HDF_LOGI("OnEmptyBufferDone, bufferId [%{public}d]", buffer.bufferId);
732 unique_lock<mutex> ulk(lockInputBuffers_);
733 unUsedInBuffers_.push_back(buffer.bufferId);
734 if (useBufferHandle_) {
735 auto bufferInfo = omxBuffers_[buffer.bufferId];
736 freeBufferHandles_.push_back(bufferInfo->bufferHandleId);
737 }
738
739 return HDF_SUCCESS;
740 }
741
OnFillBufferDone(const struct OmxCodecBuffer & buffer)742 int32_t CodecHdiEncode::OnFillBufferDone(const struct OmxCodecBuffer &buffer)
743 {
744 HDF_LOGI("OnFillBufferDone, bufferId [%{public}d]", buffer.bufferId);
745 if (exit_) {
746 return HDF_SUCCESS;
747 }
748
749 auto iter = omxBuffers_.find(buffer.bufferId);
750 if (iter == omxBuffers_.end() || !iter->second) {
751 return HDF_SUCCESS;
752 }
753
754 auto bufferInfo = iter->second;
755 const void *addr;
756 if (useDMABuffer_) {
757 auto ret = addrs_.find(buffer.bufferId);
758 if (ret != addrs_.end()) {
759 addr = ret->second;
760 } else {
761 HDF_LOGI("OnFillBufferDone, get addr fail [%{public}d]", buffer.bufferId);
762 return HDF_FAILURE;
763 }
764 } else {
765 addr = bufferInfo->avSharedPtr->ReadFromAshmem(buffer.filledLen, buffer.offset);
766 }
767 // save to file
768 (void)fwrite(addr, 1, buffer.filledLen, fpOut_);
769 (void)fflush(fpOut_);
770
771 if (buffer.flag & OMX_BUFFERFLAG_EOS) {
772 exit_ = true;
773 HDF_LOGI("OnFillBufferDone the END coming");
774 return HDF_SUCCESS;
775 }
776 auto err = client_->FillThisBuffer(*bufferInfo->omxBuffer.get());
777 if (err != HDF_SUCCESS) {
778 HDF_LOGE("FillThisBuffer error");
779 return HDF_SUCCESS;
780 }
781 return HDF_SUCCESS;
782 }
783
ConfigPortDefine()784 int32_t CodecHdiEncode::ConfigPortDefine()
785 {
786 OMX_PARAM_PORTDEFINITIONTYPE param;
787 if (util_->InitParam(param) != HDF_SUCCESS) {
788 return HDF_FAILURE;
789 }
790 param.nPortIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_INPUT);
791 std::vector<int8_t> inVec, outVec;
792 util_->ObjectToVector(param, inVec);
793 auto err = client_->GetParameter(OMX_IndexParamPortDefinition, inVec, outVec);
794 if (err != HDF_SUCCESS) {
795 HDF_LOGE("%{public}s failed to GetParameter with PORT_INDEX_INPUT, index is OMX_IndexParamPortDefinition",
796 __func__);
797 return err;
798 }
799 util_->VectorToObject(outVec, param);
800
801 HDF_LOGI("PORT_INDEX_INPUT: eCompressionFormat = %{public}d, eColorFormat=%{public}d",
802 param.format.video.eCompressionFormat, param.format.video.eColorFormat);
803 util_->setParmValue(param, width_, height_, stride_);
804 param.format.video.eColorFormat = AV_COLOR_FORMAT;
805 util_->ObjectToVector(param, inVec);
806 err = client_->SetParameter(OMX_IndexParamPortDefinition, inVec);
807 if (err != HDF_SUCCESS) {
808 HDF_LOGE("%{public}s failed to SetParameter with INPUT, OMX_IndexParamPortDefinition", __func__);
809 return err;
810 }
811
812 if (util_->InitParam(param) != HDF_SUCCESS) {
813 return HDF_FAILURE;
814 }
815 param.nPortIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_OUTPUT);
816 util_->ObjectToVector(param, inVec);
817 err = client_->GetParameter(OMX_IndexParamPortDefinition, inVec, outVec);
818 if (err != HDF_SUCCESS) {
819 HDF_LOGE("%{public}s failed to GetParameter with OUTPUT, OMX_IndexParamPortDefinition", __func__);
820 return err;
821 }
822 util_->VectorToObject(outVec, param);
823
824 HDF_LOGI("PORT_INDEX_OUTPUT eCompressionFormat = %{public}d, eColorFormat=%{public}d",
825 param.format.video.eCompressionFormat, param.format.video.eColorFormat);
826 util_->setParmValue(param, width_, height_, stride_);
827 util_->ObjectToVector(param, inVec);
828 err = client_->SetParameter(OMX_IndexParamPortDefinition, inVec);
829 if (err != HDF_SUCCESS) {
830 HDF_LOGE("%{public}s failed to SetParameter with PORT_INDEX_OUTPUT, index is OMX_IndexParamPortDefinition",
831 __func__);
832 return err;
833 }
834 return HDF_SUCCESS;
835 }
836
ConfigBitMode()837 int32_t CodecHdiEncode::ConfigBitMode()
838 {
839 OMX_VIDEO_PARAM_PORTFORMATTYPE param;
840 if (util_->InitParam(param) != HDF_SUCCESS) {
841 return HDF_FAILURE;
842 }
843 param.nPortIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_OUTPUT);
844 std::vector<int8_t> inVec, outVec;
845 util_->ObjectToVector(param, inVec);
846 auto err = client_->GetParameter(OMX_IndexParamVideoPortFormat, inVec, outVec);
847 if (err != HDF_SUCCESS) {
848 HDF_LOGE("failed to GetParameter with PORT_INDEX_OUTPUT, index is OMX_IndexParamVideoPortFormat");
849 return err;
850 }
851 util_->VectorToObject(outVec, param);
852
853 HDF_LOGI("set Format PORT_INDEX_INPUT eCompressionFormat = %{public}d, eColorFormat=%{public}d",
854 param.eCompressionFormat, param.eColorFormat);
855 param.xFramerate = FRAME;
856 param.eCompressionFormat = OMX_VIDEO_CodingAVC;
857
858 util_->ObjectToVector(param, inVec);
859 err = client_->SetParameter(OMX_IndexParamVideoPortFormat, inVec);
860 if (err != HDF_SUCCESS) {
861 HDF_LOGE("%{public}s failed to SetParameter with PORT_INDEX_INPUT, index is OMX_IndexParamVideoPortFormat",
862 __func__);
863 return err;
864 }
865
866 OMX_VIDEO_PARAM_BITRATETYPE bitRate;
867 util_->InitParam(bitRate);
868 bitRate.nPortIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_OUTPUT);
869 util_->ObjectToVector(bitRate, inVec);
870 err = client_->GetParameter(OMX_IndexParamVideoBitrate, inVec, outVec);
871 if (err != OMX_ErrorNone) {
872 HDF_LOGE("%{public}s OMX_GetParameter portindex = PORT_INDEX_OUTPUT, err[%{public}d]", __func__, err);
873 return err;
874 }
875 util_->VectorToObject(outVec, bitRate);
876 HDF_LOGI("get PORT_INDEX_OUTPUT:OMX_IndexParamVideoBitrate, bit_mode[%{public}d], biterate:[%{publicd}d]",
877 bitRate.eControlRate, bitRate.nTargetBitrate);
878
879 bitRate.eControlRate = OMX_Video_ControlRateConstant;
880 bitRate.nTargetBitrate = BITRATE;
881 util_->ObjectToVector(bitRate, inVec);
882 err = client_->SetParameter(OMX_IndexParamVideoBitrate, inVec);
883 if (err != HDF_SUCCESS) {
884 HDF_LOGE("%{public}s failed to SetParameter with PORT_INDEX_OUTPUT, index is OMX_IndexParamVideoPortFormat",
885 __func__);
886 return err;
887 }
888 return HDF_SUCCESS;
889 }
890
main(int argc,char * argv[])891 int main(int argc, char *argv[])
892 {
893 CommandOpt opt;
894 CommandParse parse;
895 if (!parse.Parse(argc, argv, opt)) {
896 return 0;
897 }
898 auto core = std::make_shared<CodecHdiEncode>();
899 if (!core->Init(opt)) {
900 core = nullptr;
901 return HDF_FAILURE;
902 }
903
904 if (!core->Configure()) {
905 core = nullptr;
906 return HDF_FAILURE;
907 }
908
909 if (!core->UseBuffers()) {
910 core = nullptr;
911 return HDF_FAILURE;
912 }
913
914 core->Run();
915
916 core->FreeBuffers();
917
918 core->Release();
919 core = nullptr;
920 }