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