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  */
toRawIndexType(OMX_INDEXTYPE l)74 inline uint32_t toRawIndexType(OMX_INDEXTYPE l) {
75     return static_cast<uint32_t>(l);
76 }
77 
toStatus(android::status_t l)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 
inHidlBytes(void const * l,size_t size)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 
toRawCommandType(OMX_COMMANDTYPE l)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:
CodecObserverCodecObserver116     CodecObserver(std::function<void(Message, const BufferInfo*)> fn)
117         : callBack(fn) {}
onMessagesCodecObserver118     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>
InitOMXParams(T * params)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>
getParam(sp<IOmxNode> omxNode,OMX_INDEXTYPE omxIdx,T * params)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, &params](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>
setParam(sp<IOmxNode> omxNode,OMX_INDEXTYPE omxIdx,T * params)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>
getPortParam(sp<IOmxNode> omxNode,OMX_INDEXTYPE omxIdx,OMX_U32 nPortIndex,T * params)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, &params](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>
setPortParam(sp<IOmxNode> omxNode,OMX_INDEXTYPE omxIdx,OMX_U32 nPortIndex,T * params)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>
getPortConfig(sp<IOmxNode> omxNode,OMX_INDEXTYPE omxIdx,OMX_U32 nPortIndex,T * params)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, &params](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>
setPortConfig(sp<IOmxNode> omxNode,OMX_INDEXTYPE omxIdx,OMX_U32 nPortIndex,T * params)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:
registerTestServices()367     virtual void registerTestServices() override { registerTestService<IOmx>(); }
368 
ComponentTestEnvironment()369     ComponentTestEnvironment() : res("/sdcard/media/") {}
370 
setComponent(const char * _component)371     void setComponent(const char* _component) { component = _component; }
372 
setRole(const char * _role)373     void setRole(const char* _role) { role = _role; }
374 
setRes(const char * _res)375     void setRes(const char* _res) { res = _res; }
376 
getInstance()377     const hidl_string getInstance() { return Super::getServiceName<IOmx>(); }
378 
getComponent()379     const hidl_string getComponent() const { return component; }
380 
getRole()381     const hidl_string getRole() const { return role; }
382 
getRes()383     const hidl_string getRes() const { return res; }
384 
initFromOptions(int argc,char ** argv)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