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 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, 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 118bool 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 139bool 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 168bool 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 197bool 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 228bool 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 267bool 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 285int32_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 299bool 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 318bool 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 352bool 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