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