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) ? msgCondition.wait(msgLock)
207                             : msgCondition.waitRelative(msgLock, delayUs * 1000LL);
208         }
209     }
210 
211     android::List<Message> msgQueue;
212     android::Mutex msgLock;
213     android::Condition msgCondition;
214     std::function<void(Message, const BufferInfo*)> callBack;
215 };
216 
217 /*
218  * Useful Wrapper utilities
219  */
220 template <class T>
InitOMXParams(T * params)221 void InitOMXParams(T* params) {
222     params->nSize = sizeof(T);
223     params->nVersion.s.nVersionMajor = 1;
224     params->nVersion.s.nVersionMinor = 0;
225     params->nVersion.s.nRevision = 0;
226     params->nVersion.s.nStep = 0;
227 }
228 
229 template <class T>
getParam(sp<IOmxNode> omxNode,OMX_INDEXTYPE omxIdx,T * params)230 Return<android::hardware::media::omx::V1_0::Status> getParam(
231     sp<IOmxNode> omxNode, OMX_INDEXTYPE omxIdx, T* params) {
232     android::hardware::media::omx::V1_0::Status status;
233     InitOMXParams(params);
234     omxNode->getParameter(
235         toRawIndexType(omxIdx), inHidlBytes(params, sizeof(*params)),
236         [&status, &params](android::hardware::media::omx::V1_0::Status _s,
237                            hidl_vec<uint8_t> const& outParams) {
238             status = _s;
239             std::copy(outParams.data(), outParams.data() + outParams.size(),
240                       static_cast<uint8_t*>(static_cast<void*>(params)));
241         });
242     return status;
243 }
244 
245 template <class T>
setParam(sp<IOmxNode> omxNode,OMX_INDEXTYPE omxIdx,T * params)246 Return<android::hardware::media::omx::V1_0::Status> setParam(
247     sp<IOmxNode> omxNode, OMX_INDEXTYPE omxIdx, T* params) {
248     InitOMXParams(params);
249     return omxNode->setParameter(toRawIndexType(omxIdx),
250                                  inHidlBytes(params, sizeof(*params)));
251 }
252 
253 template <class T>
getPortParam(sp<IOmxNode> omxNode,OMX_INDEXTYPE omxIdx,OMX_U32 nPortIndex,T * params)254 Return<android::hardware::media::omx::V1_0::Status> getPortParam(
255     sp<IOmxNode> omxNode, OMX_INDEXTYPE omxIdx, OMX_U32 nPortIndex, T* params) {
256     android::hardware::media::omx::V1_0::Status status;
257     InitOMXParams(params);
258     params->nPortIndex = nPortIndex;
259     omxNode->getParameter(
260         toRawIndexType(omxIdx), inHidlBytes(params, sizeof(*params)),
261         [&status, &params](android::hardware::media::omx::V1_0::Status _s,
262                            hidl_vec<uint8_t> const& outParams) {
263             status = _s;
264             std::copy(outParams.data(), outParams.data() + outParams.size(),
265                       static_cast<uint8_t*>(static_cast<void*>(params)));
266         });
267     return status;
268 }
269 
270 template <class T>
setPortParam(sp<IOmxNode> omxNode,OMX_INDEXTYPE omxIdx,OMX_U32 nPortIndex,T * params)271 Return<android::hardware::media::omx::V1_0::Status> setPortParam(
272     sp<IOmxNode> omxNode, OMX_INDEXTYPE omxIdx, OMX_U32 nPortIndex, T* params) {
273     InitOMXParams(params);
274     params->nPortIndex = nPortIndex;
275     return omxNode->setParameter(toRawIndexType(omxIdx),
276                                  inHidlBytes(params, sizeof(*params)));
277 }
278 
279 template <class T>
getPortConfig(sp<IOmxNode> omxNode,OMX_INDEXTYPE omxIdx,OMX_U32 nPortIndex,T * params)280 Return<android::hardware::media::omx::V1_0::Status> getPortConfig(
281     sp<IOmxNode> omxNode, OMX_INDEXTYPE omxIdx, OMX_U32 nPortIndex, T* params) {
282     android::hardware::media::omx::V1_0::Status status;
283     InitOMXParams(params);
284     params->nPortIndex = nPortIndex;
285     omxNode->getConfig(
286         toRawIndexType(omxIdx), inHidlBytes(params, sizeof(*params)),
287         [&status, &params](android::hardware::media::omx::V1_0::Status _s,
288                            hidl_vec<uint8_t> const& outParams) {
289             status = _s;
290             std::copy(outParams.data(), outParams.data() + outParams.size(),
291                       static_cast<uint8_t*>(static_cast<void*>(params)));
292         });
293     return status;
294 }
295 
296 template <class T>
setPortConfig(sp<IOmxNode> omxNode,OMX_INDEXTYPE omxIdx,OMX_U32 nPortIndex,T * params)297 Return<android::hardware::media::omx::V1_0::Status> setPortConfig(
298     sp<IOmxNode> omxNode, OMX_INDEXTYPE omxIdx, OMX_U32 nPortIndex, T* params) {
299     InitOMXParams(params);
300     params->nPortIndex = nPortIndex;
301     return omxNode->setConfig(toRawIndexType(omxIdx),
302                               inHidlBytes(params, sizeof(*params)));
303 }
304 
305 /*
306  * common functions declarations
307  */
308 
309 Return<android::hardware::media::omx::V1_0::Status> setRole(sp<IOmxNode> omxNode,
310                                                             const std::string& role);
311 
312 Return<android::hardware::media::omx::V1_0::Status> setPortBufferSize(
313     sp<IOmxNode> omxNode, OMX_U32 portIndex, OMX_U32 size);
314 
315 Return<android::hardware::media::omx::V1_0::Status> setVideoPortFormat(
316     sp<IOmxNode> omxNode, OMX_U32 portIndex,
317     OMX_VIDEO_CODINGTYPE eCompressionFormat, OMX_COLOR_FORMATTYPE eColorFormat,
318     OMX_U32 xFramerate);
319 
320 Return<android::hardware::media::omx::V1_0::Status> setAudioPortFormat(
321     sp<IOmxNode> omxNode, OMX_U32 portIndex, OMX_AUDIO_CODINGTYPE eEncoding);
322 
323 void allocateBuffer(sp<IOmxNode> omxNode, BufferInfo* buffer, OMX_U32 portIndex,
324                     OMX_U32 nBufferSize, PortMode portMode);
325 
326 void allocatePortBuffers(sp<IOmxNode> omxNode,
327                          android::Vector<BufferInfo>* buffArray,
328                          OMX_U32 portIndex,
329                          PortMode portMode = PortMode::PRESET_BYTE_BUFFER,
330                          bool allocGrap = false);
331 
332 void freePortBuffers(android::Vector<BufferInfo>* buffArray, PortMode portMode,
333                      bool allocGrap = false);
334 
335 void changeStateLoadedtoIdle(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
336                              android::Vector<BufferInfo>* iBuffer,
337                              android::Vector<BufferInfo>* oBuffer,
338                              OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput,
339                              PortMode* portMode = nullptr,
340                              bool allocGrap = false);
341 
342 void changeStateIdletoLoaded(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
343                              android::Vector<BufferInfo>* iBuffer,
344                              android::Vector<BufferInfo>* oBuffer, OMX_U32 kPortIndexInput,
345                              OMX_U32 kPortIndexOutput, PortMode* portMode = nullptr,
346                              bool allocGrap = false);
347 
348 void changeStateIdletoExecute(sp<IOmxNode> omxNode, sp<CodecObserver> observer);
349 
350 void changeStateExecutetoIdle(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
351                               android::Vector<BufferInfo>* iBuffer,
352                               android::Vector<BufferInfo>* oBuffer);
353 
354 size_t getEmptyBufferID(android::Vector<BufferInfo>* buffArray);
355 
356 void dispatchOutputBuffer(sp<IOmxNode> omxNode,
357                           android::Vector<BufferInfo>* buffArray,
358                           size_t bufferIndex,
359                           PortMode portMode = PortMode::PRESET_BYTE_BUFFER);
360 
361 void dispatchInputBuffer(sp<IOmxNode> omxNode,
362                          android::Vector<BufferInfo>* buffArray,
363                          size_t bufferIndex, int bytesCount, uint32_t flags,
364                          uint64_t timestamp,
365                          PortMode portMode = PortMode::PRESET_BYTE_BUFFER);
366 
367 void flushPorts(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
368                 android::Vector<BufferInfo>* iBuffer,
369                 android::Vector<BufferInfo>* oBuffer, OMX_U32 kPortIndexInput,
370                 OMX_U32 kPortIndexOutput,
371                 int64_t timeoutUs = DEFAULT_TIMEOUT_PE);
372 
373 typedef void (*portreconfig)(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
374                              android::Vector<BufferInfo>* iBuffer,
375                              android::Vector<BufferInfo>* oBuffer,
376                              OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput,
377                              Message msg, PortMode oPortMode, void* args);
378 void testEOS(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
379              android::Vector<BufferInfo>* iBuffer,
380              android::Vector<BufferInfo>* oBuffer, bool signalEOS,
381              bool& eosFlag, PortMode* portMode = nullptr,
382              portreconfig fptr = nullptr, OMX_U32 kPortIndexInput = 0,
383              OMX_U32 kPortIndexOutput = 1, void* args = nullptr);
384 
385 hidl_vec<IOmx::ComponentInfo> getComponentInfoList(sp<IOmx> omx);
386 
387 // Return all test parameters, a list of tuple of <instance, component, role>
388 const std::vector<std::tuple<std::string, std::string, std::string>>& getTestParameters(
389         const std::string& filter);
390 
391 #endif  // MEDIA_HIDL_TEST_COMMON_H
392