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