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