• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     int32_t tryCount = 3;
521     do {
522         int32_t err = client_->GetState(status);
523         if (err != HDF_SUCCESS) {
524             HDF_LOGE("%s GetState error [%{public}x]", __func__, err);
525             break;
526         }
527         if (status != CODEC_STATE_LOADED) {
528             HDF_LOGI("Wait for OMX_StateLoaded status");
529             this->WaitForStatusChanged();
530         }
531         tryCount--;
532     } while ((status != CODEC_STATE_LOADED) && (tryCount > 0));
533 }
534 
Release()535 void CodecHdiEncode::Release()
536 {
537     omxMgr_->DestroyComponent(componentId_);
538     client_ = nullptr;
539     callback_ = nullptr;
540     omxMgr_ = nullptr;
541 }
542 
FillAllTheBuffer()543 bool CodecHdiEncode::FillAllTheBuffer()
544 {
545     for (auto bufferId : unUsedOutBuffers_) {
546         HDF_LOGI("fill bufferid [%{public}d]", bufferId);
547         auto iter = omxBuffers_.find(bufferId);
548         if (iter != omxBuffers_.end()) {
549             auto bufferInfo = iter->second;
550             auto err = client_->FillThisBuffer(*bufferInfo->omxBuffer.get());
551             if (err != HDF_SUCCESS) {
552                 HDF_LOGE("%{public}s FillThisBuffer error", __func__);
553                 return false;
554             }
555         }
556     }
557     return true;
558 }
559 
GetFreeBufferId()560 int CodecHdiEncode::GetFreeBufferId()
561 {
562     int bufferID = -1;
563     unique_lock<mutex> ulk(lockInputBuffers_);
564     size_t nSize = this->unUsedInBuffers_.size();
565     if (nSize != 0) {
566         bufferID = unUsedInBuffers_.front();
567         unUsedInBuffers_.pop_front();
568     }
569     return bufferID;
570 }
571 
GetComponentName(std::string & compName)572 int32_t CodecHdiEncode::GetComponentName(std::string &compName)
573 {
574     OHOS::HDI::Codec::V3_0::AvCodecRole role = OHOS::HDI::Codec::V3_0::AvCodecRole::MEDIA_ROLETYPE_VIDEO_AVC;
575     int32_t count = 0;
576     auto err = omxMgr_->GetComponentNum(count);
577     if (err != HDF_SUCCESS || count <= 0) {
578         HDF_LOGE("%{public}s GetComponentNum return %{public}d, count = %{public}d", __func__, err, count);
579         return HDF_FAILURE;
580     }
581     std::vector<CodecCompCapability> caps;
582     err = omxMgr_->GetComponentCapabilityList(caps, count);
583     if (err != HDF_SUCCESS) {
584         HDF_LOGE("%{public}s GetComponentCapabilityList return %{public}d", __func__, err);
585         return err;
586     }
587     err = HDF_FAILURE;
588     for (auto cap : caps) {
589         if (cap.type == OHOS::HDI::Codec::V3_0::CodecType::VIDEO_ENCODER && cap.role == role) {
590             compName = cap.compName;
591             err = HDF_SUCCESS;
592         }
593     }
594     return err;
595 }
596 
Run()597 void CodecHdiEncode::Run()
598 {
599     auto err = client_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_EXECUTING, {});
600     if (err != HDF_SUCCESS) {
601         HDF_LOGE("%{public}s failed to SendCommand with CODEC_COMMAND_STATE_SET:CODEC_STATE_IDLE", __func__);
602         return;
603     }
604     if (!FillAllTheBuffer()) {
605         HDF_LOGE("%{public}s FillAllTheBuffer error", __func__);
606         return;
607     }
608     bool endFlag = false;
609     while (!endFlag) {
610         int bufferID = GetFreeBufferId();
611         if (this->exit_) {
612             break;
613         }
614         if (bufferID < 0) {
615             usleep(10000);  // 10000 for wait 10ms
616             continue;
617         }
618         auto iter = omxBuffers_.find(bufferID);
619         if (iter == omxBuffers_.end()) {
620             continue;
621         }
622         auto bufferInfo = iter->second;
623         if (!FillCodecBuffer(bufferInfo, endFlag)) {
624             break;
625         }
626         err = client_->EmptyThisBuffer(*bufferInfo->omxBuffer.get());
627         bufferInfo->omxBuffer->bufferhandle = nullptr;
628         if (err != HDF_SUCCESS) {
629             HDF_LOGE("%{public}s EmptyThisBuffer error", __func__);
630             return;
631         }
632     }
633     while (!this->exit_) {
634         usleep(10000);  // 10000 for wait 10ms
635     }
636     (void)client_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_IDLE, {});
637     return;
638 }
639 
FillCodecBuffer(std::shared_ptr<BufferInfo> bufferInfo,bool & endFlag)640 bool CodecHdiEncode::FillCodecBuffer(std::shared_ptr<BufferInfo> bufferInfo, bool &endFlag)
641 {
642     if (gralloc_ == nullptr) {
643         HDF_LOGE("%{public}s gralloc_ is null", __func__);
644         return false;
645     }
646     if (useBufferHandle_) {
647         int bufferHandleId = freeBufferHandles_.front();
648         if (bufferHandleId < 0 || bufferHandleId >= BUFFER_COUNT) {
649             HDF_LOGE("%{public}s bufferHandleId [%{public}d]", __func__, bufferHandleId);
650             return false;
651         }
652         freeBufferHandles_.pop_front();
653         bufferInfo->bufferHandleId = bufferHandleId;
654         BufferHandle *bufferHandle = bufferHandles_[bufferHandleId];
655         if (bufferHandle != nullptr) {
656             gralloc_->Mmap(*bufferHandle);
657             endFlag = this->ReadOneFrame(fpIn_, static_cast<char *>(bufferHandle->virAddr),
658                 bufferInfo->omxBuffer->filledLen);
659             gralloc_->Unmap(*bufferHandle);
660             bufferInfo->omxBuffer->bufferhandle = new NativeBuffer(bufferHandle);
661         }
662     } else {
663         // read data from ashmem
664         void *sharedAddr = const_cast<void *>(bufferInfo->avSharedPtr->ReadFromAshmem(0, 0));
665         endFlag = this->ReadOneFrame(fpIn_, static_cast<char *>(sharedAddr), bufferInfo->omxBuffer->filledLen);
666     }
667     bufferInfo->omxBuffer->offset = 0;
668     if (endFlag) {
669         bufferInfo->omxBuffer->flag = OMX_BUFFERFLAG_EOS;
670     }
671 
672     return true;
673 }
674 
CreateBufferHandle()675 int32_t CodecHdiEncode::CreateBufferHandle()
676 {
677     if (gralloc_ == nullptr) {
678         HDF_LOGE("%{public}s gralloc_ is null", __func__);
679         return HDF_ERR_INVALID_PARAM;
680     }
681 
682     AllocInfo alloc = {.width = this->stride_,
683                        .height = this->height_,
684                        .usage = HBM_USE_CPU_READ | HBM_USE_CPU_WRITE | HBM_USE_MEM_DMA,
685                        .format = PIXEL_FMT_YCBCR_420_SP};
686 
687     int32_t err = HDF_SUCCESS;
688     for (uint32_t i = 0; i < BUFFER_COUNT; i++) {
689         BufferHandle *bufferHandle = nullptr;
690         err = gralloc_->AllocMem(alloc, bufferHandle);
691         if (err != HDF_SUCCESS) {
692             HDF_LOGE("%{public}s AllocMem fail", __func__);
693             return err;
694         }
695         bufferHandles_.emplace(std::make_pair(i, bufferHandle));
696         freeBufferHandles_.push_back(i);
697     }
698     return err;
699 }
700 
EventHandler(OHOS::HDI::Codec::V3_0::CodecEventType event,const OHOS::HDI::Codec::V3_0::EventInfo & info)701 int32_t CodecHdiEncode::EventHandler(OHOS::HDI::Codec::V3_0::CodecEventType event,
702     const OHOS::HDI::Codec::V3_0::EventInfo &info)
703 {
704     if (event == CODEC_EVENT_CMD_COMPLETE) {
705         CodecCommandType cmd = (CodecCommandType)info.data1;
706         if (CODEC_COMMAND_STATE_SET == cmd) {
707             HDF_LOGI("CODEC_COMMAND_STATE_SET reached, status is %{public}d", info.data2);
708             this->OnStatusChanged();
709         }
710     }
711 
712     return HDF_SUCCESS;
713 }
714 
OnEmptyBufferDone(const struct OmxCodecBuffer & buffer)715 int32_t CodecHdiEncode::OnEmptyBufferDone(const struct OmxCodecBuffer &buffer)
716 {
717     HDF_LOGI("OnEmptyBufferDone, bufferId [%{public}d]", buffer.bufferId);
718     unique_lock<mutex> ulk(lockInputBuffers_);
719     unUsedInBuffers_.push_back(buffer.bufferId);
720     if (useBufferHandle_) {
721         auto bufferInfo = omxBuffers_[buffer.bufferId];
722         freeBufferHandles_.push_back(bufferInfo->bufferHandleId);
723     }
724 
725     return HDF_SUCCESS;
726 }
727 
OnFillBufferDone(const struct OmxCodecBuffer & buffer)728 int32_t CodecHdiEncode::OnFillBufferDone(const struct OmxCodecBuffer &buffer)
729 {
730     HDF_LOGI("OnFillBufferDone, bufferId [%{public}d]", buffer.bufferId);
731     if (exit_) {
732         return HDF_SUCCESS;
733     }
734 
735     auto iter = omxBuffers_.find(buffer.bufferId);
736     if (iter == omxBuffers_.end() || !iter->second) {
737         return HDF_SUCCESS;
738     }
739 
740     auto bufferInfo = iter->second;
741     const void *addr;
742     if (useDMABuffer_) {
743         auto ret = addrs_.find(buffer.bufferId);
744         if (ret != addrs_.end()) {
745             addr = ret->second;
746         } else {
747             HDF_LOGI("OnFillBufferDone, get addr fail [%{public}d]", buffer.bufferId);
748             return HDF_FAILURE;
749         }
750     } else {
751         addr = bufferInfo->avSharedPtr->ReadFromAshmem(buffer.filledLen, buffer.offset);
752     }
753     // save to file
754     (void)fwrite(addr, 1, buffer.filledLen, fpOut_);
755     (void)fflush(fpOut_);
756 
757     if (buffer.flag & OMX_BUFFERFLAG_EOS) {
758         exit_ = true;
759         HDF_LOGI("OnFillBufferDone the END coming");
760         return HDF_SUCCESS;
761     }
762     auto err = client_->FillThisBuffer(*bufferInfo->omxBuffer.get());
763     if (err != HDF_SUCCESS) {
764         HDF_LOGE("FillThisBuffer error");
765         return HDF_SUCCESS;
766     }
767     return HDF_SUCCESS;
768 }
769 
ConfigPortDefine()770 int32_t CodecHdiEncode::ConfigPortDefine()
771 {
772     OMX_PARAM_PORTDEFINITIONTYPE param;
773     if (util_->InitParam(param) != HDF_SUCCESS) {
774         return HDF_FAILURE;
775     }
776     param.nPortIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_INPUT);
777     std::vector<int8_t> inVec, outVec;
778     util_->ObjectToVector(param, inVec);
779     auto err = client_->GetParameter(OMX_IndexParamPortDefinition, inVec, outVec);
780     if (err != HDF_SUCCESS) {
781         HDF_LOGE("%{public}s failed to GetParameter with PORT_INDEX_INPUT, index is OMX_IndexParamPortDefinition",
782                  __func__);
783         return err;
784     }
785     util_->VectorToObject(outVec, param);
786 
787     HDF_LOGI("PORT_INDEX_INPUT: eCompressionFormat = %{public}d, eColorFormat=%{public}d",
788              param.format.video.eCompressionFormat, param.format.video.eColorFormat);
789     util_->setParmValue(param, width_, height_, stride_);
790     param.format.video.eColorFormat = AV_COLOR_FORMAT;
791     util_->ObjectToVector(param, inVec);
792     err = client_->SetParameter(OMX_IndexParamPortDefinition, inVec);
793     if (err != HDF_SUCCESS) {
794         HDF_LOGE("%{public}s failed to SetParameter with INPUT, OMX_IndexParamPortDefinition",  __func__);
795         return err;
796     }
797 
798     if (util_->InitParam(param) != HDF_SUCCESS) {
799         return HDF_FAILURE;
800     }
801     param.nPortIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_OUTPUT);
802     util_->ObjectToVector(param, inVec);
803     err = client_->GetParameter(OMX_IndexParamPortDefinition, inVec, outVec);
804     if (err != HDF_SUCCESS) {
805         HDF_LOGE("%{public}s failed to GetParameter with OUTPUT, OMX_IndexParamPortDefinition", __func__);
806         return err;
807     }
808     util_->VectorToObject(outVec, param);
809 
810     HDF_LOGI("PORT_INDEX_OUTPUT eCompressionFormat = %{public}d, eColorFormat=%{public}d",
811              param.format.video.eCompressionFormat, param.format.video.eColorFormat);
812     util_->setParmValue(param, width_, height_, stride_);
813     util_->ObjectToVector(param, inVec);
814     err = client_->SetParameter(OMX_IndexParamPortDefinition, inVec);
815     if (err != HDF_SUCCESS) {
816         HDF_LOGE("%{public}s failed to SetParameter with PORT_INDEX_OUTPUT, index is OMX_IndexParamPortDefinition",
817                  __func__);
818         return err;
819     }
820     return HDF_SUCCESS;
821 }
822 
ConfigBitMode()823 int32_t CodecHdiEncode::ConfigBitMode()
824 {
825     OMX_VIDEO_PARAM_PORTFORMATTYPE param;
826     if (util_->InitParam(param) != HDF_SUCCESS) {
827         return HDF_FAILURE;
828     }
829     param.nPortIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_OUTPUT);
830     std::vector<int8_t> inVec, outVec;
831     util_->ObjectToVector(param, inVec);
832     auto err = client_->GetParameter(OMX_IndexParamVideoPortFormat, inVec, outVec);
833     if (err != HDF_SUCCESS) {
834         HDF_LOGE("failed to GetParameter with PORT_INDEX_OUTPUT, index is OMX_IndexParamVideoPortFormat");
835         return err;
836     }
837     util_->VectorToObject(outVec, param);
838 
839     HDF_LOGI("set Format PORT_INDEX_INPUT eCompressionFormat = %{public}d, eColorFormat=%{public}d",
840              param.eCompressionFormat, param.eColorFormat);
841     param.xFramerate = FRAME;
842     param.eCompressionFormat = OMX_VIDEO_CodingAVC;
843 
844     util_->ObjectToVector(param, inVec);
845     err = client_->SetParameter(OMX_IndexParamVideoPortFormat, inVec);
846     if (err != HDF_SUCCESS) {
847         HDF_LOGE("%{public}s failed to SetParameter with PORT_INDEX_INPUT, index is OMX_IndexParamVideoPortFormat",
848                  __func__);
849         return err;
850     }
851 
852     OMX_VIDEO_PARAM_BITRATETYPE bitRate;
853     util_->InitParam(bitRate);
854     bitRate.nPortIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_OUTPUT);
855     util_->ObjectToVector(bitRate, inVec);
856     err = client_->GetParameter(OMX_IndexParamVideoBitrate, inVec, outVec);
857     if (err != OMX_ErrorNone) {
858         HDF_LOGE("%{public}s OMX_GetParameter portindex = PORT_INDEX_OUTPUT, err[%{public}d]", __func__, err);
859         return err;
860     }
861     util_->VectorToObject(outVec, bitRate);
862     HDF_LOGI("get PORT_INDEX_OUTPUT:OMX_IndexParamVideoBitrate, bit_mode[%{public}d], biterate:[%{publicd}d]",
863              bitRate.eControlRate, bitRate.nTargetBitrate);
864 
865     bitRate.eControlRate = OMX_Video_ControlRateConstant;
866     bitRate.nTargetBitrate = BITRATE;
867     util_->ObjectToVector(bitRate, inVec);
868     err = client_->SetParameter(OMX_IndexParamVideoBitrate, inVec);
869     if (err != HDF_SUCCESS) {
870         HDF_LOGE("%{public}s failed to SetParameter with PORT_INDEX_OUTPUT, index is OMX_IndexParamVideoPortFormat",
871                  __func__);
872         return err;
873     }
874     return HDF_SUCCESS;
875 }
876 
main(int argc,char * argv[])877 int main(int argc, char *argv[])
878 {
879     CommandOpt opt;
880     CommandParse parse;
881     if (!parse.Parse(argc, argv, opt)) {
882         return 0;
883     }
884     auto core = std::make_shared<CodecHdiEncode>();
885     if (!core->Init(opt)) {
886         core = nullptr;
887         return HDF_FAILURE;
888     }
889 
890     if (!core->Configure()) {
891         core = nullptr;
892         return HDF_FAILURE;
893     }
894 
895     if (!core->UseBuffers()) {
896         core = nullptr;
897         return HDF_FAILURE;
898     }
899 
900     core->Run();
901 
902     core->FreeBuffers();
903 
904     core->Release();
905     core = nullptr;
906 }