1 /* 2 * Copyright 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 #ifndef MEDIA_HIDL_TEST_COMMON_H 18 #define MEDIA_HIDL_TEST_COMMON_H 19 20 #ifdef __LP64__ 21 #define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS 22 #endif 23 24 #include <getopt.h> 25 #include <media/stagefright/foundation/ALooper.h> 26 #include <utils/Condition.h> 27 #include <utils/List.h> 28 #include <utils/Mutex.h> 29 30 #include <media/openmax/OMX_Index.h> 31 #include <media/openmax/OMX_Core.h> 32 #include <media/openmax/OMX_Component.h> 33 #include <media/openmax/OMX_IndexExt.h> 34 #include <media/openmax/OMX_AudioExt.h> 35 #include <media/openmax/OMX_VideoExt.h> 36 37 #include <VtsHalHidlTargetTestEnvBase.h> 38 39 /* TIME OUTS (Wait time in dequeueMessage()) */ 40 41 /* As component is switching states (loaded<->idle<->execute), dequeueMessage() 42 * expects the events to be received within this duration */ 43 #define DEFAULT_TIMEOUT 100000 44 /* Time interval between successive Input/Output enqueues */ 45 #define DEFAULT_TIMEOUT_Q 2000 46 /* While the component is amidst a process call, asynchronous commands like 47 * flush, change states can get delayed (at max by process call time). Instead 48 * of waiting on DEFAULT_TIMEOUT, we give an additional leeway. */ 49 #define DEFAULT_TIMEOUT_PE 500000 50 51 /* Breakout Timeout :: 5 sec*/ 52 #define TIMEOUT_COUNTER_Q (5000000 / DEFAULT_TIMEOUT_Q) 53 #define TIMEOUT_COUNTER_PE (5000000 / DEFAULT_TIMEOUT_PE) 54 55 /* 56 * Random Index used for monkey testing while get/set parameters 57 */ 58 #define RANDOM_INDEX 1729 59 60 #define ALIGN_POWER_OF_TWO(value, n) \ 61 (((value) + ((1 << (n)) - 1)) & ~((1 << (n)) - 1)) 62 63 enum bufferOwner { 64 client, 65 component, 66 unknown, 67 }; 68 69 /* 70 * TODO: below definitions are borrowed from Conversion.h. 71 * This is not the ideal way to do it. Loose these definitions once you 72 * include Conversion.h 73 */ 74 inline uint32_t toRawIndexType(OMX_INDEXTYPE l) { 75 return static_cast<uint32_t>(l); 76 } 77 78 inline android::hardware::media::omx::V1_0::Status toStatus( 79 android::status_t l) { 80 return static_cast<android::hardware::media::omx::V1_0::Status>(l); 81 } 82 83 inline hidl_vec<uint8_t> inHidlBytes(void const* l, size_t size) { 84 hidl_vec<uint8_t> t; 85 t.setToExternal(static_cast<uint8_t*>(const_cast<void*>(l)), size, false); 86 return t; 87 } 88 89 inline uint32_t toRawCommandType(OMX_COMMANDTYPE l) { 90 return static_cast<uint32_t>(l); 91 } 92 93 /* 94 * struct definitions 95 */ 96 struct BufferInfo { 97 uint32_t id; 98 bufferOwner owner; 99 android::hardware::media::omx::V1_0::CodecBuffer omxBuffer; 100 ::android::sp<IMemory> mMemory; 101 int32_t slot; 102 }; 103 104 struct FrameData { 105 int bytesCount; 106 uint32_t flags; 107 uint32_t timestamp; 108 }; 109 110 /* 111 * Handle Callback functions EmptythisBuffer(), FillthisBuffer(), 112 * EventHandler() 113 */ 114 struct CodecObserver : public IOmxObserver { 115 public: 116 CodecObserver(std::function<void(Message, const BufferInfo*)> fn) 117 : callBack(fn) {} 118 Return<void> onMessages(const hidl_vec<Message>& messages) override { 119 android::Mutex::Autolock autoLock(msgLock); 120 for (hidl_vec<Message>::const_iterator it = messages.begin(); 121 it != messages.end(); ++it) { 122 msgQueue.push_back(*it); 123 } 124 msgCondition.signal(); 125 return Void(); 126 } 127 android::hardware::media::omx::V1_0::Status dequeueMessage( 128 Message* msg, int64_t timeoutUs, 129 android::Vector<BufferInfo>* iBuffers = nullptr, 130 android::Vector<BufferInfo>* oBuffers = nullptr) { 131 int64_t finishBy = android::ALooper::GetNowUs() + timeoutUs; 132 for (;;) { 133 android::Mutex::Autolock autoLock(msgLock); 134 android::List<Message>::iterator it = msgQueue.begin(); 135 while (it != msgQueue.end()) { 136 if (it->type == 137 android::hardware::media::omx::V1_0::Message::Type::EVENT) { 138 *msg = *it; 139 if (callBack) callBack(*it, nullptr); 140 it = msgQueue.erase(it); 141 // OMX_EventBufferFlag event is sent when the component has 142 // processed a buffer with its EOS flag set. This event is 143 // not sent by soft omx components. Vendor components can 144 // send this. From IOMX point of view, we will ignore this 145 // event. 146 if (msg->data.eventData.event == OMX_EventBufferFlag) 147 continue; 148 return ::android::hardware::media::omx::V1_0::Status::OK; 149 } else if (it->type == android::hardware::media::omx::V1_0:: 150 Message::Type::FILL_BUFFER_DONE) { 151 if (oBuffers) { 152 size_t i; 153 for (i = 0; i < oBuffers->size(); ++i) { 154 if ((*oBuffers)[i].id == 155 it->data.bufferData.buffer) { 156 if (callBack) callBack(*it, &(*oBuffers)[i]); 157 oBuffers->editItemAt(i).owner = client; 158 it = msgQueue.erase(it); 159 break; 160 } 161 } 162 EXPECT_LE(i, oBuffers->size()); 163 } 164 } else if (it->type == android::hardware::media::omx::V1_0:: 165 Message::Type::EMPTY_BUFFER_DONE) { 166 if (iBuffers) { 167 size_t i; 168 for (i = 0; i < iBuffers->size(); ++i) { 169 if ((*iBuffers)[i].id == 170 it->data.bufferData.buffer) { 171 if (callBack) callBack(*it, &(*iBuffers)[i]); 172 iBuffers->editItemAt(i).owner = client; 173 it = msgQueue.erase(it); 174 break; 175 } 176 } 177 EXPECT_LE(i, iBuffers->size()); 178 } 179 } else { 180 EXPECT_TRUE(false) << "Received unexpected message"; 181 ++it; 182 } 183 } 184 int64_t delayUs = finishBy - android::ALooper::GetNowUs(); 185 if (delayUs < 0) return toStatus(android::TIMED_OUT); 186 (timeoutUs < 0) 187 ? msgCondition.wait(msgLock) 188 : msgCondition.waitRelative(msgLock, delayUs * 1000ll); 189 } 190 } 191 192 android::List<Message> msgQueue; 193 android::Mutex msgLock; 194 android::Condition msgCondition; 195 std::function<void(Message, const BufferInfo*)> callBack; 196 }; 197 198 /* 199 * Useful Wrapper utilities 200 */ 201 template <class T> 202 void InitOMXParams(T* params) { 203 params->nSize = sizeof(T); 204 params->nVersion.s.nVersionMajor = 1; 205 params->nVersion.s.nVersionMinor = 0; 206 params->nVersion.s.nRevision = 0; 207 params->nVersion.s.nStep = 0; 208 } 209 210 template <class T> 211 Return<android::hardware::media::omx::V1_0::Status> getParam( 212 sp<IOmxNode> omxNode, OMX_INDEXTYPE omxIdx, T* params) { 213 android::hardware::media::omx::V1_0::Status status; 214 InitOMXParams(params); 215 omxNode->getParameter( 216 toRawIndexType(omxIdx), inHidlBytes(params, sizeof(*params)), 217 [&status, ¶ms](android::hardware::media::omx::V1_0::Status _s, 218 hidl_vec<uint8_t> const& outParams) { 219 status = _s; 220 std::copy(outParams.data(), outParams.data() + outParams.size(), 221 static_cast<uint8_t*>(static_cast<void*>(params))); 222 }); 223 return status; 224 } 225 226 template <class T> 227 Return<android::hardware::media::omx::V1_0::Status> setParam( 228 sp<IOmxNode> omxNode, OMX_INDEXTYPE omxIdx, T* params) { 229 InitOMXParams(params); 230 return omxNode->setParameter(toRawIndexType(omxIdx), 231 inHidlBytes(params, sizeof(*params))); 232 } 233 234 template <class T> 235 Return<android::hardware::media::omx::V1_0::Status> getPortParam( 236 sp<IOmxNode> omxNode, OMX_INDEXTYPE omxIdx, OMX_U32 nPortIndex, T* params) { 237 android::hardware::media::omx::V1_0::Status status; 238 InitOMXParams(params); 239 params->nPortIndex = nPortIndex; 240 omxNode->getParameter( 241 toRawIndexType(omxIdx), inHidlBytes(params, sizeof(*params)), 242 [&status, ¶ms](android::hardware::media::omx::V1_0::Status _s, 243 hidl_vec<uint8_t> const& outParams) { 244 status = _s; 245 std::copy(outParams.data(), outParams.data() + outParams.size(), 246 static_cast<uint8_t*>(static_cast<void*>(params))); 247 }); 248 return status; 249 } 250 251 template <class T> 252 Return<android::hardware::media::omx::V1_0::Status> setPortParam( 253 sp<IOmxNode> omxNode, OMX_INDEXTYPE omxIdx, OMX_U32 nPortIndex, T* params) { 254 InitOMXParams(params); 255 params->nPortIndex = nPortIndex; 256 return omxNode->setParameter(toRawIndexType(omxIdx), 257 inHidlBytes(params, sizeof(*params))); 258 } 259 260 template <class T> 261 Return<android::hardware::media::omx::V1_0::Status> getPortConfig( 262 sp<IOmxNode> omxNode, OMX_INDEXTYPE omxIdx, OMX_U32 nPortIndex, T* params) { 263 android::hardware::media::omx::V1_0::Status status; 264 InitOMXParams(params); 265 params->nPortIndex = nPortIndex; 266 omxNode->getConfig( 267 toRawIndexType(omxIdx), inHidlBytes(params, sizeof(*params)), 268 [&status, ¶ms](android::hardware::media::omx::V1_0::Status _s, 269 hidl_vec<uint8_t> const& outParams) { 270 status = _s; 271 std::copy(outParams.data(), outParams.data() + outParams.size(), 272 static_cast<uint8_t*>(static_cast<void*>(params))); 273 }); 274 return status; 275 } 276 277 template <class T> 278 Return<android::hardware::media::omx::V1_0::Status> setPortConfig( 279 sp<IOmxNode> omxNode, OMX_INDEXTYPE omxIdx, OMX_U32 nPortIndex, T* params) { 280 InitOMXParams(params); 281 params->nPortIndex = nPortIndex; 282 return omxNode->setConfig(toRawIndexType(omxIdx), 283 inHidlBytes(params, sizeof(*params))); 284 } 285 286 /* 287 * common functions declarations 288 */ 289 Return<android::hardware::media::omx::V1_0::Status> setRole( 290 sp<IOmxNode> omxNode, const char* role); 291 292 Return<android::hardware::media::omx::V1_0::Status> setPortBufferSize( 293 sp<IOmxNode> omxNode, OMX_U32 portIndex, OMX_U32 size); 294 295 Return<android::hardware::media::omx::V1_0::Status> setVideoPortFormat( 296 sp<IOmxNode> omxNode, OMX_U32 portIndex, 297 OMX_VIDEO_CODINGTYPE eCompressionFormat, OMX_COLOR_FORMATTYPE eColorFormat, 298 OMX_U32 xFramerate); 299 300 Return<android::hardware::media::omx::V1_0::Status> setAudioPortFormat( 301 sp<IOmxNode> omxNode, OMX_U32 portIndex, OMX_AUDIO_CODINGTYPE eEncoding); 302 303 void allocateBuffer(sp<IOmxNode> omxNode, BufferInfo* buffer, OMX_U32 portIndex, 304 OMX_U32 nBufferSize, PortMode portMode); 305 306 void allocatePortBuffers(sp<IOmxNode> omxNode, 307 android::Vector<BufferInfo>* buffArray, 308 OMX_U32 portIndex, 309 PortMode portMode = PortMode::PRESET_BYTE_BUFFER, 310 bool allocGrap = false); 311 312 void changeStateLoadedtoIdle(sp<IOmxNode> omxNode, sp<CodecObserver> observer, 313 android::Vector<BufferInfo>* iBuffer, 314 android::Vector<BufferInfo>* oBuffer, 315 OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput, 316 PortMode* portMode = nullptr, 317 bool allocGrap = false); 318 319 void changeStateIdletoLoaded(sp<IOmxNode> omxNode, sp<CodecObserver> observer, 320 android::Vector<BufferInfo>* iBuffer, 321 android::Vector<BufferInfo>* oBuffer, 322 OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput); 323 324 void changeStateIdletoExecute(sp<IOmxNode> omxNode, sp<CodecObserver> observer); 325 326 void changeStateExecutetoIdle(sp<IOmxNode> omxNode, sp<CodecObserver> observer, 327 android::Vector<BufferInfo>* iBuffer, 328 android::Vector<BufferInfo>* oBuffer); 329 330 size_t getEmptyBufferID(android::Vector<BufferInfo>* buffArray); 331 332 void dispatchOutputBuffer(sp<IOmxNode> omxNode, 333 android::Vector<BufferInfo>* buffArray, 334 size_t bufferIndex, 335 PortMode portMode = PortMode::PRESET_BYTE_BUFFER); 336 337 void dispatchInputBuffer(sp<IOmxNode> omxNode, 338 android::Vector<BufferInfo>* buffArray, 339 size_t bufferIndex, int bytesCount, uint32_t flags, 340 uint64_t timestamp, 341 PortMode portMode = PortMode::PRESET_BYTE_BUFFER); 342 343 void flushPorts(sp<IOmxNode> omxNode, sp<CodecObserver> observer, 344 android::Vector<BufferInfo>* iBuffer, 345 android::Vector<BufferInfo>* oBuffer, OMX_U32 kPortIndexInput, 346 OMX_U32 kPortIndexOutput, 347 int64_t timeoutUs = DEFAULT_TIMEOUT_PE); 348 349 typedef void (*portreconfig)(sp<IOmxNode> omxNode, sp<CodecObserver> observer, 350 android::Vector<BufferInfo>* iBuffer, 351 android::Vector<BufferInfo>* oBuffer, 352 OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput, 353 Message msg, PortMode oPortMode, void* args); 354 void testEOS(sp<IOmxNode> omxNode, sp<CodecObserver> observer, 355 android::Vector<BufferInfo>* iBuffer, 356 android::Vector<BufferInfo>* oBuffer, bool signalEOS, 357 bool& eosFlag, PortMode* portMode = nullptr, 358 portreconfig fptr = nullptr, OMX_U32 kPortIndexInput = 0, 359 OMX_U32 kPortIndexOutput = 1, void* args = nullptr); 360 361 // A class for test environment setup 362 class ComponentTestEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { 363 private: 364 typedef ::testing::VtsHalHidlTargetTestEnvBase Super; 365 366 public: 367 virtual void registerTestServices() override { registerTestService<IOmx>(); } 368 369 ComponentTestEnvironment() : res("/sdcard/media/") {} 370 371 void setComponent(const char* _component) { component = _component; } 372 373 void setRole(const char* _role) { role = _role; } 374 375 void setRes(const char* _res) { res = _res; } 376 377 const hidl_string getInstance() { return Super::getServiceName<IOmx>(); } 378 379 const hidl_string getComponent() const { return component; } 380 381 const hidl_string getRole() const { return role; } 382 383 const hidl_string getRes() const { return res; } 384 385 int initFromOptions(int argc, char** argv) { 386 static struct option options[] = {{"component", required_argument, 0, 'C'}, 387 {"role", required_argument, 0, 'R'}, 388 {"res", required_argument, 0, 'P'}, 389 {0, 0, 0, 0}}; 390 391 while (true) { 392 int index = 0; 393 int c = getopt_long(argc, argv, "C:R:P:", options, &index); 394 if (c == -1) { 395 break; 396 } 397 398 switch (c) { 399 case 'C': 400 setComponent(optarg); 401 break; 402 case 'R': 403 setRole(optarg); 404 break; 405 case 'P': 406 setRes(optarg); 407 break; 408 case '?': 409 break; 410 } 411 } 412 413 if (optind < argc) { 414 fprintf(stderr, 415 "unrecognized option: %s\n\n" 416 "usage: %s <gtest options> <test options>\n\n" 417 "test options are:\n\n" 418 "-C, --component: OMX component to test\n" 419 "-R, --role: OMX component Role\n" 420 "-P, --res: Resource files directory location\n", 421 argv[optind ?: 1], argv[0]); 422 return 2; 423 } 424 return 0; 425 } 426 427 private: 428 hidl_string instance; 429 hidl_string component; 430 hidl_string role; 431 hidl_string res; 432 }; 433 434 #endif // MEDIA_HIDL_TEST_COMMON_H 435