1 /*
2  * Copyright (c) 2024 Huawei Device 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 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 <cstdio>
17 #include <unistd.h>
18 #include "codec_function_utils.h"
19 #include <gtest/gtest.h>
20 #include <securec.h>
21 #include <servmgr_hdi.h>
22 
23 #define HDF_LOG_TAG codec_hdi_test
24 
25 using namespace std;
26 using namespace OHOS::HDI::Codec::V3_0;
27 using namespace OHOS::HDI::Display::Buffer::V1_0;
28 using namespace OHOS::HDI::Display::Composer::V1_0;
29 IDisplayBuffer *FunctionUtil::buffer_ = nullptr;
30 
FunctionUtil(CodecVersionType version)31 FunctionUtil::FunctionUtil(CodecVersionType version)
32 {
33     buffer_ = IDisplayBuffer::Get();
34     version_ = version;
35 }
36 
~FunctionUtil()37 FunctionUtil::~FunctionUtil()
38 {
39     buffer_ = nullptr;
40 }
41 
AlignUp(uint32_t width)42 uint32_t FunctionUtil::AlignUp(uint32_t width)
43 {
44     return (((width) + ALIGNMENT - 1) & (~(ALIGNMENT - 1)));
45 }
46 
InitOmxCodecBuffer(OmxCodecBuffer &buffer, CodecBufferType type)47 void FunctionUtil::InitOmxCodecBuffer(OmxCodecBuffer &buffer, CodecBufferType type)
48 {
49     buffer.bufferType = type;
50     buffer.fenceFd = ERROE_FENCEFD;
51     buffer.version = version_;
52     buffer.allocLen = BUFFER_SIZE;
53     buffer.fd = FD_DEFAULT;
54     buffer.bufferhandle = nullptr;
55     buffer.pts = 0;
56     buffer.flag = 0;
57     buffer.size = sizeof(OmxCodecBuffer);
58     buffer.type = READ_ONLY_TYPE;
59 }
60 
InitCodecBufferWithAshMem(enum PortIndex port, int bufferSize, shared_ptr<OmxCodecBuffer> omxBuffer, shared_ptr<OHOS::Ashmem> sharedMem)61 void FunctionUtil::InitCodecBufferWithAshMem(enum PortIndex port, int bufferSize, shared_ptr<OmxCodecBuffer> omxBuffer,
62     shared_ptr<OHOS::Ashmem> sharedMem)
63 {
64     InitOmxCodecBuffer(*omxBuffer.get(), CODEC_BUFFER_TYPE_AVSHARE_MEM_FD);
65     omxBuffer->fd = sharedMem->GetAshmemFd();
66     omxBuffer->allocLen = bufferSize;
67     if (port == PortIndex::INDEX_INPUT) {
68         omxBuffer->type = READ_ONLY_TYPE;
69         sharedMem->MapReadAndWriteAshmem();
70     } else {
71         omxBuffer->type = READ_WRITE_TYPE;
72         sharedMem->MapReadOnlyAshmem();
73     }
74 }
75 
InitBufferHandleParameter(sptr<ICodecComponent> component, OMX_PARAM_PORTDEFINITIONTYPE &param, uint32_t port, CodecBufferType bufferType)76 bool FunctionUtil::InitBufferHandleParameter(sptr<ICodecComponent> component, OMX_PARAM_PORTDEFINITIONTYPE &param,
77     uint32_t port, CodecBufferType bufferType)
78 {
79     InitParam(param);
80     param.nPortIndex = port;
81     std::vector<int8_t> inParam;
82     std::vector<int8_t> outParam;
83     ObjectToVector(param, inParam);
84     auto ret = component->GetParameter(OMX_IndexParamPortDefinition, inParam, outParam);
85     if (ret != HDF_SUCCESS) {
86         HDF_LOGE("GetParameter OMX_IndexParamPortDefinition error");
87         return false;
88     }
89 
90     VectorToObject(outParam, param);
91     param.format.video.nFrameWidth = WIDTH;
92     param.format.video.nFrameHeight = HEIGHT;
93     param.format.video.nStride = AlignUp(WIDTH);
94     param.format.video.nSliceHeight = HEIGHT;
95     param.format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
96     std::vector<int8_t> enc;
97     ObjectToVector(param, enc);
98     ret = component->SetParameter(OMX_IndexParamPortDefinition, enc);
99     if (ret != HDF_SUCCESS) {
100         HDF_LOGE("SetParameter OMX_IndexParamPortDefinition error");
101         return false;
102     }
103 
104     std::vector<int8_t> data;
105     UseBufferType type;
106     type.size = sizeof(UseBufferType);
107     type.version.s.nVersionMajor = 1;
108     type.portIndex = port;
109     type.bufferType = bufferType;
110     ObjectToVector(type, data);
111     ret = component->SetParameter(OMX_IndexParamUseBufferType, data);
112     if (ret != HDF_SUCCESS) {
113         HDF_LOGE("SetParameter OMX_IndexParamUseBufferType error");
114         return false;
115     }
116     return true;
117 }
118 
FillCodecBufferWithBufferHandle(shared_ptr<OmxCodecBuffer> omxBuffer)119 bool FunctionUtil::FillCodecBufferWithBufferHandle(shared_ptr<OmxCodecBuffer> omxBuffer)
120 {
121     AllocInfo alloc = {.width = WIDTH,
122                        .height = HEIGHT,
123                        .usage = HBM_USE_CPU_READ | HBM_USE_CPU_WRITE | HBM_USE_MEM_DMA,
124                        .format = PIXEL_FMT_YCBCR_420_SP};
125 
126     BufferHandle *bufferHandle = nullptr;
127     if (buffer_ == nullptr) {
128         HDF_LOGE("buffer_ is nullptr");
129         return false;
130     }
131     auto ret = buffer_->AllocMem(alloc, bufferHandle);
132     if (ret != HDF_SUCCESS) {
133         HDF_LOGE("AllocMem error");
134         return false;
135     }
136     omxBuffer->bufferhandle = new NativeBuffer(bufferHandle);
137     return true;
138 }
139 
UseDynaBuffer(sptr<ICodecComponent> component, enum PortIndex port, int bufferCount, int bufferSize)140 bool FunctionUtil::UseDynaBuffer(sptr<ICodecComponent> component, enum PortIndex port, int bufferCount,
141     int bufferSize)
142 {
143     if (bufferCount <= 0 || bufferSize <= 0) {
144         HDF_LOGE("bufferCount <= 0 or bufferSize <= 0");
145         return false;
146     }
147 
148     for (int i = 0; i < bufferCount; i++) {
149         auto omxBuffer = std::make_shared<OmxCodecBuffer>();
150         InitOmxCodecBuffer(*omxBuffer.get(), CODEC_BUFFER_TYPE_DYNAMIC_HANDLE);
151         FillCodecBufferWithBufferHandle(omxBuffer);
152         omxBuffer->allocLen = WIDTH * HEIGHT * NUMERATOR / DENOMINATOR;
153 
154         OmxCodecBuffer outBuffer;
155         auto ret = component->UseBuffer(static_cast<uint32_t>(port), *omxBuffer.get(), outBuffer);
156         if (ret != HDF_SUCCESS) {
157             HDF_LOGE("UseBuffer error");
158             return false;
159         }
160 
161         omxBuffer->bufferId = outBuffer.bufferId;
162         auto bufferInfo = std::make_shared<BufferInfo>();
163         bufferInfo->omxBuffer = omxBuffer;
164         inputBuffers_.emplace(std::make_pair(omxBuffer->bufferId, bufferInfo));
165     }
166     return true;
167 }
168 
UseHandleBuffer(sptr<ICodecComponent> component, enum PortIndex port, int bufferCount, int bufferSize)169 bool FunctionUtil::UseHandleBuffer(sptr<ICodecComponent> component, enum PortIndex port,
170     int bufferCount, int bufferSize)
171 {
172     if (bufferCount <= 0 || bufferSize <= 0) {
173         HDF_LOGE("bufferCount <= 0 or bufferSize <= 0");
174         return false;
175     }
176 
177     for (int i = 0; i < bufferCount; i++) {
178         auto omxBuffer = std::make_shared<OmxCodecBuffer>();
179         InitOmxCodecBuffer(*omxBuffer.get(), CODEC_BUFFER_TYPE_HANDLE);
180         FillCodecBufferWithBufferHandle(omxBuffer);
181         omxBuffer->allocLen = WIDTH * HEIGHT * NUMERATOR / DENOMINATOR;
182 
183         OmxCodecBuffer outBuffer;
184         int32_t ret = component->UseBuffer(static_cast<uint32_t>(port), *omxBuffer.get(), outBuffer);
185         if (ret != HDF_SUCCESS) {
186             HDF_LOGE("UseBuffer error");
187             return false;
188         }
189 
190         omxBuffer->bufferId = outBuffer.bufferId;
191         auto bufferInfo = std::make_shared<BufferInfo>();
192         bufferInfo->omxBuffer = omxBuffer;
193         outputBuffers_.emplace(std::make_pair(omxBuffer->bufferId, bufferInfo));
194     }
195     return true;
196 }
197 
UseBufferOnPort(sptr<ICodecComponent> component, enum PortIndex port, int32_t bufferCount, int32_t bufferSize)198 bool FunctionUtil::UseBufferOnPort(sptr<ICodecComponent> component, enum PortIndex port,
199     int32_t bufferCount, int32_t bufferSize)
200 {
201     for (int i = 0; i < bufferCount; i++) {
202         std::shared_ptr<OmxCodecBuffer> omxBuffer = std::make_shared<OmxCodecBuffer>();
203         int fd = OHOS::AshmemCreate(0, bufferSize);
204         shared_ptr<OHOS::Ashmem> sharedMem = make_shared<OHOS::Ashmem>(fd, bufferSize);
205         InitCodecBufferWithAshMem(port, bufferSize, omxBuffer, sharedMem);
206         OmxCodecBuffer outBuffer;
207         int32_t err = component->UseBuffer(static_cast<uint32_t>(port), *omxBuffer.get(), outBuffer);
208         if (err != HDF_SUCCESS) {
209             HDF_LOGE("UseBuffer error");
210             sharedMem->UnmapAshmem();
211             sharedMem->CloseAshmem();
212             return false;
213         }
214 
215         omxBuffer->bufferId = outBuffer.bufferId;
216         omxBuffer->fd = FD_DEFAULT;
217         std::shared_ptr<BufferInfo> bufferInfo = std::make_shared<BufferInfo>();
218         bufferInfo->omxBuffer = omxBuffer;
219         bufferInfo->sharedMem = sharedMem;
220         if (port == PortIndex::INDEX_INPUT) {
221             inputBuffers_.emplace(std::make_pair(omxBuffer->bufferId, bufferInfo));
222         } else {
223             outputBuffers_.emplace(std::make_pair(omxBuffer->bufferId, bufferInfo));
224         }
225     }
226     return true;
227 }
228 
AllocateBufferOnPort(sptr<ICodecComponent> component, enum PortIndex port, int32_t bufferCount, int32_t bufferSize)229 bool FunctionUtil::AllocateBufferOnPort(sptr<ICodecComponent> component, enum PortIndex port,
230     int32_t bufferCount, int32_t bufferSize)
231 {
232     for (int i = 0; i < bufferCount; i++) {
233         std::shared_ptr<OmxCodecBuffer> omxBuffer = std::make_shared<OmxCodecBuffer>();
234         InitOmxCodecBuffer(*omxBuffer.get(), CODEC_BUFFER_TYPE_AVSHARE_MEM_FD);
235         omxBuffer->allocLen = bufferSize;
236         if (port == PortIndex::INDEX_INPUT) {
237             omxBuffer->type = READ_ONLY_TYPE;
238         } else {
239             omxBuffer->type = READ_WRITE_TYPE;
240         }
241 
242         OmxCodecBuffer outBuffer;
243         auto err = component->AllocateBuffer(static_cast<uint32_t>(port), *omxBuffer.get(), outBuffer);
244         if (err != HDF_SUCCESS) {
245             HDF_LOGE("AllocateBuffer error");
246             return false;
247         }
248         omxBuffer->type = outBuffer.type;
249         omxBuffer->bufferId = outBuffer.bufferId;
250 
251         int fd = outBuffer.fd;
252         shared_ptr<OHOS::Ashmem> sharedMem = make_shared<OHOS::Ashmem>(fd, bufferSize);
253 
254         std::shared_ptr<BufferInfo> bufferInfo = std::make_shared<BufferInfo>();
255         bufferInfo->omxBuffer = omxBuffer;
256         bufferInfo->sharedMem = sharedMem;
257         if (port == PortIndex::INDEX_INPUT) {
258             sharedMem->MapReadAndWriteAshmem();
259             inputBuffers_.emplace(std::make_pair(omxBuffer->bufferId, bufferInfo));
260         } else {
261             sharedMem->MapReadOnlyAshmem();
262             outputBuffers_.emplace(std::make_pair(omxBuffer->bufferId, bufferInfo));
263         }
264     }
265     return true;
266 }
267 
FreeBufferOnPort(sptr<ICodecComponent> component, enum PortIndex port)268 bool FunctionUtil::FreeBufferOnPort(sptr<ICodecComponent> component, enum PortIndex port)
269 {
270     int32_t ret;
271     std::map<int32_t, std::shared_ptr<BufferInfo>> &buffer = inputBuffers_;
272     if (port == PortIndex::INDEX_OUTPUT) {
273         buffer = outputBuffers_;
274     }
275     for (auto [bufferId, bufferInfo] : buffer) {
276         ret = component->FreeBuffer(static_cast<uint32_t>(port), *bufferInfo->omxBuffer.get());
277         if (ret != HDF_SUCCESS) {
278             HDF_LOGE("FreeBuffer error");
279             return false;
280         }
281     }
282     buffer.clear();
283     return true;
284 }
285 
GetPortParameter(sptr<ICodecComponent> component, PortIndex index, OMX_PARAM_PORTDEFINITIONTYPE &param)286 int32_t FunctionUtil::GetPortParameter(sptr<ICodecComponent> component, PortIndex index,
287     OMX_PARAM_PORTDEFINITIONTYPE &param)
288 {
289     InitParam(param);
290     param.nPortIndex = static_cast<OMX_U32>(index);
291     std::vector<int8_t> inParam;
292     ObjectToVector(param, inParam);
293 
294     std::vector<int8_t> outParam;
295     auto ret = component->GetParameter(OMX_IndexParamPortDefinition, inParam, outParam);
296     VectorToObject(outParam, param);
297     return ret;
298 }
299 
PushAlongParam(OmxCodecBuffer &omxBuffer)300 bool FunctionUtil::PushAlongParam(OmxCodecBuffer &omxBuffer)
301 {
302     const std::string processName = "cast_engine_service";
303     ProcessNameParam nameParam;
304     this->InitExtParam(nameParam);
305     int32_t ret = strcpy_s(nameParam.processName, sizeof(nameParam.processName), processName.c_str());
306     if (ret != EOK) {
307         return false;
308     }
309 
310     uint32_t size = sizeof(nameParam);
311     uint8_t *ptr = reinterpret_cast<uint8_t*>(&nameParam);
312     for (uint32_t i = 0; i < size; i++) {
313         omxBuffer.alongParam.push_back(*(ptr + i));
314     }
315 
316     return true;
317 }
318 
FillAndEmptyAllBuffer(sptr<ICodecComponent> component, CodecBufferType type)319 bool FunctionUtil::FillAndEmptyAllBuffer(sptr<ICodecComponent> component, CodecBufferType type)
320 {
321     int32_t ret;
322     auto iter = outputBuffers_.begin();
323     for (; iter != outputBuffers_.end(); iter++) {
324         auto bufferInfo = iter->second;
325         if (type != bufferInfo->omxBuffer->bufferType) {
326             continue;
327         }
328         ret = component->FillThisBuffer(*bufferInfo->omxBuffer.get());
329         if (ret != HDF_SUCCESS) {
330             HDF_LOGE("FillThisBuffer error");
331             return false;
332         }
333     }
334     iter = inputBuffers_.begin();
335     for (; iter != inputBuffers_.end(); iter++) {
336         auto bufferInfo = iter->second;
337         if (type != bufferInfo->omxBuffer->bufferType) {
338             continue;
339         }
340         if (type == CODEC_BUFFER_TYPE_DYNAMIC_HANDLE && (!PushAlongParam(*bufferInfo->omxBuffer.get()))) {
341             HDF_LOGE("PushAlongParam error");
342             return false;
343         }
344         ret = component->EmptyThisBuffer(*bufferInfo->omxBuffer.get());
345         if (ret != HDF_SUCCESS) {
346             HDF_LOGE("EmptyThisBuffer error");
347             return false;
348         }
349     }
350     return true;
351 }
352 
WaitState(sptr<ICodecComponent> component, CodecStateType objState)353 bool FunctionUtil::WaitState(sptr<ICodecComponent> component, CodecStateType objState)
354 {
355     CodecStateType state = CODEC_STATE_INVALID;
356     uint32_t count = 0;
357     do {
358         usleep(WAIT_TIME);
359         auto ret = component->GetState(state);
360         if (ret != HDF_SUCCESS) {
361             HDF_LOGE("EmptyThisBuffer error");
362             return false;
363         }
364         count++;
365     } while (state != objState && count <= MAX_WAIT);
366     return true;
367 }
368 
369