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 }