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 ¶m, 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;
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 ¶m)286 int32_t FunctionUtil::GetPortParameter(sptr<ICodecComponent> component, PortIndex index,
287 OMX_PARAM_PORTDEFINITIONTYPE ¶m)
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