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 ¶m,
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 ¶m)
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