1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define LOG_TAG "media_omx_hidl_video_test_common" 18 19 #ifdef __LP64__ 20 #define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS 21 #endif 22 23 #include <android-base/logging.h> 24 25 #include <android/hardware/media/omx/1.0/IOmx.h> 26 #include <android/hardware/media/omx/1.0/IOmxNode.h> 27 #include <android/hardware/media/omx/1.0/IOmxObserver.h> 28 #include <android/hardware/media/omx/1.0/types.h> 29 #include <android/hidl/allocator/1.0/IAllocator.h> 30 #include <android/hidl/memory/1.0/IMapper.h> 31 #include <android/hidl/memory/1.0/IMemory.h> 32 33 using ::android::hardware::media::omx::V1_0::IOmx; 34 using ::android::hardware::media::omx::V1_0::IOmxObserver; 35 using ::android::hardware::media::omx::V1_0::IOmxNode; 36 using ::android::hardware::media::omx::V1_0::Message; 37 using ::android::hardware::media::omx::V1_0::CodecBuffer; 38 using ::android::hardware::media::omx::V1_0::PortMode; 39 using ::android::hardware::media::omx::V1_0::Status; 40 using ::android::hidl::allocator::V1_0::IAllocator; 41 using ::android::hidl::memory::V1_0::IMemory; 42 using ::android::hidl::memory::V1_0::IMapper; 43 using ::android::hardware::Return; 44 using ::android::hardware::Void; 45 using ::android::hardware::hidl_vec; 46 using ::android::hardware::hidl_string; 47 using ::android::sp; 48 49 #include <VtsHalHidlTargetTestBase.h> 50 #include <hidlmemory/mapping.h> 51 #include <media/hardware/HardwareAPI.h> 52 #include <media_hidl_test_common.h> 53 #include <memory> 54 55 // set component role 56 Return<android::hardware::media::omx::V1_0::Status> setRole( 57 sp<IOmxNode> omxNode, const char* role) { 58 OMX_PARAM_COMPONENTROLETYPE params; 59 strcpy((char*)params.cRole, role); 60 return setParam(omxNode, OMX_IndexParamStandardComponentRole, ¶ms); 61 } 62 63 // allocate buffers needed on a component port 64 void allocatePortBuffers(sp<IOmxNode> omxNode, 65 android::Vector<BufferInfo>* buffArray, 66 OMX_U32 portIndex, PortMode portMode) { 67 android::hardware::media::omx::V1_0::Status status; 68 OMX_PARAM_PORTDEFINITIONTYPE portDef; 69 70 buffArray->clear(); 71 72 status = getPortParam(omxNode, OMX_IndexParamPortDefinition, portIndex, 73 &portDef); 74 ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); 75 76 if (portMode == PortMode::PRESET_SECURE_BUFFER) { 77 for (size_t i = 0; i < portDef.nBufferCountActual; i++) { 78 BufferInfo buffer; 79 buffer.owner = client; 80 buffer.omxBuffer.type = CodecBuffer::Type::NATIVE_HANDLE; 81 omxNode->allocateSecureBuffer( 82 portIndex, portDef.nBufferSize, 83 [&status, &buffer]( 84 android::hardware::media::omx::V1_0::Status _s, uint32_t id, 85 ::android::hardware::hidl_handle const& nativeHandle) { 86 status = _s; 87 buffer.id = id; 88 buffer.omxBuffer.nativeHandle = nativeHandle; 89 }); 90 buffArray->push(buffer); 91 ASSERT_EQ(status, 92 ::android::hardware::media::omx::V1_0::Status::OK); 93 } 94 } else if (portMode == PortMode::PRESET_BYTE_BUFFER || 95 portMode == PortMode::DYNAMIC_ANW_BUFFER) { 96 sp<IAllocator> allocator = IAllocator::getService("ashmem"); 97 EXPECT_NE(allocator.get(), nullptr); 98 99 for (size_t i = 0; i < portDef.nBufferCountActual; i++) { 100 BufferInfo buffer; 101 buffer.owner = client; 102 buffer.omxBuffer.type = CodecBuffer::Type::SHARED_MEM; 103 buffer.omxBuffer.attr.preset.rangeOffset = 0; 104 buffer.omxBuffer.attr.preset.rangeLength = 0; 105 bool success = false; 106 if (portMode != PortMode::PRESET_BYTE_BUFFER) { 107 portDef.nBufferSize = sizeof(android::VideoNativeMetadata); 108 } 109 allocator->allocate( 110 portDef.nBufferSize, 111 [&success, &buffer]( 112 bool _s, ::android::hardware::hidl_memory const& mem) { 113 success = _s; 114 buffer.omxBuffer.sharedMemory = mem; 115 }); 116 ASSERT_EQ(success, true); 117 ASSERT_EQ(buffer.omxBuffer.sharedMemory.size(), 118 portDef.nBufferSize); 119 buffer.mMemory = mapMemory(buffer.omxBuffer.sharedMemory); 120 ASSERT_NE(buffer.mMemory, nullptr); 121 if (portMode == PortMode::DYNAMIC_ANW_BUFFER) { 122 android::VideoNativeMetadata* metaData = 123 static_cast<android::VideoNativeMetadata*>( 124 static_cast<void*>(buffer.mMemory->getPointer())); 125 metaData->nFenceFd = -1; 126 buffer.slot = -1; 127 } 128 omxNode->useBuffer( 129 portIndex, buffer.omxBuffer, 130 [&status, &buffer]( 131 android::hardware::media::omx::V1_0::Status _s, 132 uint32_t id) { 133 status = _s; 134 buffer.id = id; 135 }); 136 buffArray->push(buffer); 137 ASSERT_EQ(status, 138 ::android::hardware::media::omx::V1_0::Status::OK); 139 } 140 } 141 } 142 143 // State Transition : Loaded -> Idle 144 // Note: This function does not make any background checks for this transition. 145 // The callee holds the reponsibility to ensure the legality of the transition. 146 void changeStateLoadedtoIdle(sp<IOmxNode> omxNode, sp<CodecObserver> observer, 147 android::Vector<BufferInfo>* iBuffer, 148 android::Vector<BufferInfo>* oBuffer, 149 OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput, 150 PortMode* portMode) { 151 android::hardware::media::omx::V1_0::Status status; 152 Message msg; 153 PortMode defaultPortMode[2], *pm; 154 155 defaultPortMode[0] = PortMode::PRESET_BYTE_BUFFER; 156 defaultPortMode[1] = PortMode::PRESET_BYTE_BUFFER; 157 pm = portMode ? portMode : defaultPortMode; 158 159 // set state to idle 160 status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet), 161 OMX_StateIdle); 162 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); 163 164 // Dont switch states until the ports are populated 165 status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer); 166 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT); 167 168 // allocate buffers on input port 169 allocatePortBuffers(omxNode, iBuffer, kPortIndexInput, pm[0]); 170 171 // Dont switch states until the ports are populated 172 status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer); 173 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT); 174 175 // allocate buffers on output port 176 allocatePortBuffers(omxNode, oBuffer, kPortIndexOutput, pm[1]); 177 178 // As the ports are populated, check if the state transition is complete 179 status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer); 180 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); 181 ASSERT_EQ(msg.type, Message::Type::EVENT); 182 ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete); 183 ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet); 184 ASSERT_EQ(msg.data.eventData.data2, OMX_StateIdle); 185 186 return; 187 } 188 189 // State Transition : Idle -> Loaded 190 // Note: This function does not make any background checks for this transition. 191 // The callee holds the reponsibility to ensure the legality of the transition. 192 void changeStateIdletoLoaded(sp<IOmxNode> omxNode, sp<CodecObserver> observer, 193 android::Vector<BufferInfo>* iBuffer, 194 android::Vector<BufferInfo>* oBuffer, 195 OMX_U32 kPortIndexInput, 196 OMX_U32 kPortIndexOutput) { 197 android::hardware::media::omx::V1_0::Status status; 198 Message msg; 199 200 // set state to Loaded 201 status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet), 202 OMX_StateLoaded); 203 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); 204 205 // dont change state until all buffers are freed 206 status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer); 207 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT); 208 209 for (size_t i = 0; i < iBuffer->size(); ++i) { 210 status = omxNode->freeBuffer(kPortIndexInput, (*iBuffer)[i].id); 211 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); 212 } 213 214 // dont change state until all buffers are freed 215 status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer); 216 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT); 217 218 for (size_t i = 0; i < oBuffer->size(); ++i) { 219 status = omxNode->freeBuffer(kPortIndexOutput, (*oBuffer)[i].id); 220 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); 221 } 222 223 status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer); 224 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); 225 ASSERT_EQ(msg.type, Message::Type::EVENT); 226 ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete); 227 ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet); 228 ASSERT_EQ(msg.data.eventData.data2, OMX_StateLoaded); 229 230 return; 231 } 232 233 // State Transition : Idle -> Execute 234 // Note: This function does not make any background checks for this transition. 235 // The callee holds the reponsibility to ensure the legality of the transition. 236 void changeStateIdletoExecute(sp<IOmxNode> omxNode, 237 sp<CodecObserver> observer) { 238 android::hardware::media::omx::V1_0::Status status; 239 Message msg; 240 241 // set state to execute 242 status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet), 243 OMX_StateExecuting); 244 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); 245 status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT); 246 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); 247 ASSERT_EQ(msg.type, Message::Type::EVENT); 248 ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete); 249 ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet); 250 ASSERT_EQ(msg.data.eventData.data2, OMX_StateExecuting); 251 252 return; 253 } 254 255 // State Transition : Execute -> Idle 256 // Note: This function does not make any background checks for this transition. 257 // The callee holds the reponsibility to ensure the legality of the transition. 258 void changeStateExecutetoIdle(sp<IOmxNode> omxNode, sp<CodecObserver> observer, 259 android::Vector<BufferInfo>* iBuffer, 260 android::Vector<BufferInfo>* oBuffer) { 261 android::hardware::media::omx::V1_0::Status status; 262 Message msg; 263 264 // set state to Idle 265 status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet), 266 OMX_StateIdle); 267 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); 268 status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer); 269 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); 270 ASSERT_EQ(msg.type, Message::Type::EVENT); 271 ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete); 272 ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet); 273 ASSERT_EQ(msg.data.eventData.data2, OMX_StateIdle); 274 275 // test if client got all its buffers back 276 for (size_t i = 0; i < oBuffer->size(); ++i) { 277 EXPECT_EQ((*oBuffer)[i].owner, client); 278 } 279 for (size_t i = 0; i < iBuffer->size(); ++i) { 280 EXPECT_EQ((*iBuffer)[i].owner, client); 281 } 282 } 283 284 // get empty buffer index 285 size_t getEmptyBufferID(android::Vector<BufferInfo>* buffArray) { 286 android::Vector<BufferInfo>::iterator it = buffArray->begin(); 287 while (it != buffArray->end()) { 288 if (it->owner == client) { 289 // This block of code ensures that all buffers allocated at init 290 // time are utilized 291 BufferInfo backup = *it; 292 buffArray->erase(it); 293 buffArray->push_back(backup); 294 return buffArray->size() - 1; 295 } 296 it++; 297 } 298 return buffArray->size(); 299 } 300 301 // dispatch buffer to output port 302 void dispatchOutputBuffer(sp<IOmxNode> omxNode, 303 android::Vector<BufferInfo>* buffArray, 304 size_t bufferIndex, PortMode portMode) { 305 android::hardware::media::omx::V1_0::Status status; 306 CodecBuffer t; 307 native_handle_t* fenceNh = native_handle_create(0, 0); 308 ASSERT_NE(fenceNh, nullptr); 309 switch (portMode) { 310 case PortMode::DYNAMIC_ANW_BUFFER: 311 t = (*buffArray)[bufferIndex].omxBuffer; 312 t.type = CodecBuffer::Type::ANW_BUFFER; 313 status = 314 omxNode->fillBuffer((*buffArray)[bufferIndex].id, t, fenceNh); 315 break; 316 case PortMode::PRESET_SECURE_BUFFER: 317 case PortMode::PRESET_BYTE_BUFFER: 318 t.sharedMemory = android::hardware::hidl_memory(); 319 t.nativeHandle = android::hardware::hidl_handle(); 320 t.type = CodecBuffer::Type::PRESET; 321 t.attr.preset.rangeOffset = 0; 322 t.attr.preset.rangeLength = 0; 323 status = 324 omxNode->fillBuffer((*buffArray)[bufferIndex].id, t, fenceNh); 325 break; 326 default: 327 status = Status::NAME_NOT_FOUND; 328 } 329 native_handle_close(fenceNh); 330 native_handle_delete(fenceNh); 331 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); 332 buffArray->editItemAt(bufferIndex).owner = component; 333 } 334 335 // dispatch buffer to input port 336 void dispatchInputBuffer(sp<IOmxNode> omxNode, 337 android::Vector<BufferInfo>* buffArray, 338 size_t bufferIndex, int bytesCount, uint32_t flags, 339 uint64_t timestamp, PortMode portMode) { 340 android::hardware::media::omx::V1_0::Status status; 341 CodecBuffer t; 342 native_handle_t* fenceNh = native_handle_create(0, 0); 343 ASSERT_NE(fenceNh, nullptr); 344 switch (portMode) { 345 case PortMode::PRESET_SECURE_BUFFER: 346 case PortMode::PRESET_BYTE_BUFFER: 347 t.sharedMemory = android::hardware::hidl_memory(); 348 t.nativeHandle = android::hardware::hidl_handle(); 349 t.type = CodecBuffer::Type::PRESET; 350 t.attr.preset.rangeOffset = 0; 351 t.attr.preset.rangeLength = bytesCount; 352 status = omxNode->emptyBuffer((*buffArray)[bufferIndex].id, t, 353 flags, timestamp, fenceNh); 354 break; 355 default: 356 status = Status::NAME_NOT_FOUND; 357 } 358 native_handle_close(fenceNh); 359 native_handle_delete(fenceNh); 360 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); 361 buffArray->editItemAt(bufferIndex).owner = component; 362 } 363 364 // Flush input and output ports 365 void flushPorts(sp<IOmxNode> omxNode, sp<CodecObserver> observer, 366 android::Vector<BufferInfo>* iBuffer, 367 android::Vector<BufferInfo>* oBuffer, OMX_U32 kPortIndexInput, 368 OMX_U32 kPortIndexOutput, int64_t timeoutUs) { 369 android::hardware::media::omx::V1_0::Status status; 370 Message msg; 371 372 // Flush input port 373 status = omxNode->sendCommand(toRawCommandType(OMX_CommandFlush), 374 kPortIndexInput); 375 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); 376 status = observer->dequeueMessage(&msg, timeoutUs, iBuffer, oBuffer); 377 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); 378 ASSERT_EQ(msg.type, Message::Type::EVENT); 379 ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete); 380 ASSERT_EQ(msg.data.eventData.data1, OMX_CommandFlush); 381 ASSERT_EQ(msg.data.eventData.data2, kPortIndexInput); 382 // test if client got all its buffers back 383 for (size_t i = 0; i < iBuffer->size(); ++i) { 384 EXPECT_EQ((*iBuffer)[i].owner, client); 385 } 386 387 // Flush output port 388 status = omxNode->sendCommand(toRawCommandType(OMX_CommandFlush), 389 kPortIndexOutput); 390 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); 391 status = observer->dequeueMessage(&msg, timeoutUs, iBuffer, oBuffer); 392 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); 393 ASSERT_EQ(msg.type, Message::Type::EVENT); 394 ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete); 395 ASSERT_EQ(msg.data.eventData.data1, OMX_CommandFlush); 396 ASSERT_EQ(msg.data.eventData.data2, kPortIndexOutput); 397 // test if client got all its buffers back 398 for (size_t i = 0; i < oBuffer->size(); ++i) { 399 EXPECT_EQ((*oBuffer)[i].owner, client); 400 } 401 } 402 403 // dispatch an empty input buffer with eos flag set if requested. 404 // This call assumes that all input buffers are processed completely. 405 // feed output buffers till we receive a buffer with eos flag set 406 void testEOS(sp<IOmxNode> omxNode, sp<CodecObserver> observer, 407 android::Vector<BufferInfo>* iBuffer, 408 android::Vector<BufferInfo>* oBuffer, bool signalEOS, 409 bool& eosFlag, PortMode* portMode) { 410 android::hardware::media::omx::V1_0::Status status; 411 PortMode defaultPortMode[2], *pm; 412 413 defaultPortMode[0] = PortMode::PRESET_BYTE_BUFFER; 414 defaultPortMode[1] = PortMode::PRESET_BYTE_BUFFER; 415 pm = portMode ? portMode : defaultPortMode; 416 417 size_t i = 0; 418 if (signalEOS) { 419 if ((i = getEmptyBufferID(iBuffer)) < iBuffer->size()) { 420 // signal an empty buffer with flag set to EOS 421 dispatchInputBuffer(omxNode, iBuffer, i, 0, OMX_BUFFERFLAG_EOS, 0); 422 } else { 423 ASSERT_TRUE(false); 424 } 425 } 426 427 int timeOut = TIMEOUT_COUNTER; 428 while (timeOut--) { 429 // Dispatch all client owned output buffers to recover remaining frames 430 while (1) { 431 if ((i = getEmptyBufferID(oBuffer)) < oBuffer->size()) { 432 dispatchOutputBuffer(omxNode, oBuffer, i, pm[1]); 433 // if dispatch is successful, perhaps there is a latency 434 // in the component. Dont be in a haste to leave. reset timeout 435 // counter 436 timeOut = TIMEOUT_COUNTER; 437 } else { 438 break; 439 } 440 } 441 442 Message msg; 443 status = 444 observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer); 445 if (status == android::hardware::media::omx::V1_0::Status::OK) { 446 if (msg.data.eventData.event == OMX_EventBufferFlag) { 447 // soft omx components donot send this, we will just ignore it 448 // for now 449 } else { 450 // something unexpected happened 451 EXPECT_TRUE(false); 452 } 453 } 454 if (eosFlag == true) break; 455 } 456 // test for flag 457 EXPECT_EQ(eosFlag, true); 458 eosFlag = false; 459 } 460