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