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 25using namespace std; 26using namespace OHOS::HDI::Codec::V3_0; 27using namespace OHOS::HDI::Display::Buffer::V1_0; 28using namespace OHOS::HDI::Display::Composer::V1_0; 29IDisplayBuffer *FunctionUtil::buffer_ = nullptr; 30 31FunctionUtil::FunctionUtil(CodecVersionType version) 32{ 33 buffer_ = IDisplayBuffer::Get(); 34 version_ = version; 35} 36 37FunctionUtil::~FunctionUtil() 38{ 39 buffer_ = nullptr; 40} 41 42uint32_t FunctionUtil::AlignUp(uint32_t width) 43{ 44 return (((width) + ALIGNMENT - 1) & (~(ALIGNMENT - 1))); 45} 46 47void 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 61void 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 76bool 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 119bool 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 140bool 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 169bool 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 198bool 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 229bool 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 268bool 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 286int32_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 300bool 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 319bool 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 353bool 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