• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &params](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, &params](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, &params](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