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