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 <gtest/gtest.h>
36 #include <hidl/ServiceManagement.h>
37 #include <media/stagefright/foundation/ALooper.h>
38 #include <utils/Condition.h>
39 #include <utils/List.h>
40 #include <utils/Mutex.h>
41 
42 #include <media/openmax/OMX_Index.h>
43 #include <media/openmax/OMX_Core.h>
44 #include <media/openmax/OMX_Component.h>
45 #include <media/openmax/OMX_IndexExt.h>
46 #include <media/openmax/OMX_AudioExt.h>
47 #include <media/openmax/OMX_VideoExt.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 // List known and thus tested audio/video roles.
82 static std::set<std::string> kKnownRoles{
83         "audio_encoder.aac",      "audio_encoder.amrnb", "audio_encoder.amrwb",
84         "audio_encoder.flac",     "audio_decoder.aac",   "audio_decoder.amrnb",
85         "audio_decoder.amrwb",    "audio_decoder.flac",  "audio_decoder.g711alaw",
86         "audio_decoder.g711mlaw", "audio_decoder.gsm",   "audio_decoder.mp3",
87         "audio_decoder.opus",     "audio_decoder.raw",   "audio_decoder.vorbis",
88         "video_encoder.avc",      "video_encoder.h263",  "video_encoder.mpeg4",
89         "video_encoder.vp8",      "video_encoder.vp9",   "video_decoder.avc",
90         "video_decoder.h263",     "video_decoder.hevc",  "video_decoder.mpeg4",
91         "video_decoder.vp8",      "video_decoder.vp9"};
92 
93 static std::vector<std::tuple<std::string, std::string, std::string>> kTestParameters;
94 
95 /*
96  * TODO: below definitions are borrowed from Conversion.h.
97  * This is not the ideal way to do it. Loose these definitions once you
98  * include Conversion.h
99  */
toRawIndexType(OMX_INDEXTYPE l)100 inline uint32_t toRawIndexType(OMX_INDEXTYPE l) {
101     return static_cast<uint32_t>(l);
102 }
103 
toStatus(android::status_t l)104 inline android::hardware::media::omx::V1_0::Status toStatus(
105     android::status_t l) {
106     return static_cast<android::hardware::media::omx::V1_0::Status>(l);
107 }
108 
inHidlBytes(void const * l,size_t size)109 inline hidl_vec<uint8_t> inHidlBytes(void const* l, size_t size) {
110     hidl_vec<uint8_t> t;
111     t.setToExternal(static_cast<uint8_t*>(const_cast<void*>(l)), size, false);
112     return t;
113 }
114 
toRawCommandType(OMX_COMMANDTYPE l)115 inline uint32_t toRawCommandType(OMX_COMMANDTYPE l) {
116     return static_cast<uint32_t>(l);
117 }
118 
119 /*
120  * struct definitions
121  */
122 struct BufferInfo {
123     uint32_t id;
124     bufferOwner owner;
125     android::hardware::media::omx::V1_0::CodecBuffer omxBuffer;
126     ::android::sp<IMemory> mMemory;
127     int32_t slot;
128 };
129 
130 struct FrameData {
131     int bytesCount;
132     uint32_t flags;
133     uint32_t timestamp;
134 };
135 
136 /*
137  * Handle Callback functions EmptythisBuffer(), FillthisBuffer(),
138  * EventHandler()
139  */
140 struct CodecObserver : public IOmxObserver {
141    public:
CodecObserverCodecObserver142     CodecObserver(std::function<void(Message, const BufferInfo*)> fn)
143         : callBack(fn) {}
onMessagesCodecObserver144     Return<void> onMessages(const hidl_vec<Message>& messages) override {
145         android::Mutex::Autolock autoLock(msgLock);
146         for (hidl_vec<Message>::const_iterator it = messages.begin();
147              it != messages.end(); ++it) {
148             msgQueue.push_back(*it);
149         }
150         msgCondition.signal();
151         return Void();
152     }
153     android::hardware::media::omx::V1_0::Status dequeueMessage(
154         Message* msg, int64_t timeoutUs,
155         android::Vector<BufferInfo>* iBuffers = nullptr,
156         android::Vector<BufferInfo>* oBuffers = nullptr) {
157         int64_t finishBy = android::ALooper::GetNowUs() + timeoutUs;
158         for (;;) {
159             android::Mutex::Autolock autoLock(msgLock);
160             android::List<Message>::iterator it = msgQueue.begin();
161             while (it != msgQueue.end()) {
162                 if (it->type ==
163                     android::hardware::media::omx::V1_0::Message::Type::EVENT) {
164                     *msg = *it;
165                     if (callBack) callBack(*it, nullptr);
166                     it = msgQueue.erase(it);
167                     // OMX_EventBufferFlag event is sent when the component has
168                     // processed a buffer with its EOS flag set. This event is
169                     // not sent by soft omx components. Vendor components can
170                     // send this. From IOMX point of view, we will ignore this
171                     // event.
172                     if (msg->data.eventData.event == OMX_EventBufferFlag)
173                         continue;
174                     return ::android::hardware::media::omx::V1_0::Status::OK;
175                 } else if (it->type == android::hardware::media::omx::V1_0::
176                                            Message::Type::FILL_BUFFER_DONE) {
177                     if (oBuffers) {
178                         size_t i;
179                         for (i = 0; i < oBuffers->size(); ++i) {
180                             if ((*oBuffers)[i].id ==
181                                 it->data.bufferData.buffer) {
182                                 if (callBack) callBack(*it, &(*oBuffers)[i]);
183                                 oBuffers->editItemAt(i).owner = client;
184                                 it = msgQueue.erase(it);
185                                 break;
186                             }
187                         }
188                         EXPECT_LE(i, oBuffers->size());
189                     }
190                 } else if (it->type == android::hardware::media::omx::V1_0::
191                                            Message::Type::EMPTY_BUFFER_DONE) {
192                     if (iBuffers) {
193                         size_t i;
194                         for (i = 0; i < iBuffers->size(); ++i) {
195                             if ((*iBuffers)[i].id ==
196                                 it->data.bufferData.buffer) {
197                                 if (callBack) callBack(*it, &(*iBuffers)[i]);
198                                 iBuffers->editItemAt(i).owner = client;
199                                 it = msgQueue.erase(it);
200                                 break;
201                             }
202                         }
203                         EXPECT_LE(i, iBuffers->size());
204                     }
205                 } else {
206                     EXPECT_TRUE(false) << "Received unexpected message";
207                     ++it;
208                 }
209             }
210             int64_t delayUs = finishBy - android::ALooper::GetNowUs();
211             if (delayUs < 0) return toStatus(android::TIMED_OUT);
212             (timeoutUs < 0)
213                 ? msgCondition.wait(msgLock)
214                 : msgCondition.waitRelative(msgLock, delayUs * 1000ll);
215         }
216     }
217 
218     android::List<Message> msgQueue;
219     android::Mutex msgLock;
220     android::Condition msgCondition;
221     std::function<void(Message, const BufferInfo*)> callBack;
222 };
223 
224 /*
225  * Useful Wrapper utilities
226  */
227 template <class T>
InitOMXParams(T * params)228 void InitOMXParams(T* params) {
229     params->nSize = sizeof(T);
230     params->nVersion.s.nVersionMajor = 1;
231     params->nVersion.s.nVersionMinor = 0;
232     params->nVersion.s.nRevision = 0;
233     params->nVersion.s.nStep = 0;
234 }
235 
236 template <class T>
getParam(sp<IOmxNode> omxNode,OMX_INDEXTYPE omxIdx,T * params)237 Return<android::hardware::media::omx::V1_0::Status> getParam(
238     sp<IOmxNode> omxNode, OMX_INDEXTYPE omxIdx, T* params) {
239     android::hardware::media::omx::V1_0::Status status;
240     InitOMXParams(params);
241     omxNode->getParameter(
242         toRawIndexType(omxIdx), inHidlBytes(params, sizeof(*params)),
243         [&status, &params](android::hardware::media::omx::V1_0::Status _s,
244                            hidl_vec<uint8_t> const& outParams) {
245             status = _s;
246             std::copy(outParams.data(), outParams.data() + outParams.size(),
247                       static_cast<uint8_t*>(static_cast<void*>(params)));
248         });
249     return status;
250 }
251 
252 template <class T>
setParam(sp<IOmxNode> omxNode,OMX_INDEXTYPE omxIdx,T * params)253 Return<android::hardware::media::omx::V1_0::Status> setParam(
254     sp<IOmxNode> omxNode, OMX_INDEXTYPE omxIdx, T* params) {
255     InitOMXParams(params);
256     return omxNode->setParameter(toRawIndexType(omxIdx),
257                                  inHidlBytes(params, sizeof(*params)));
258 }
259 
260 template <class T>
getPortParam(sp<IOmxNode> omxNode,OMX_INDEXTYPE omxIdx,OMX_U32 nPortIndex,T * params)261 Return<android::hardware::media::omx::V1_0::Status> getPortParam(
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->getParameter(
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>
setPortParam(sp<IOmxNode> omxNode,OMX_INDEXTYPE omxIdx,OMX_U32 nPortIndex,T * params)278 Return<android::hardware::media::omx::V1_0::Status> setPortParam(
279     sp<IOmxNode> omxNode, OMX_INDEXTYPE omxIdx, OMX_U32 nPortIndex, T* params) {
280     InitOMXParams(params);
281     params->nPortIndex = nPortIndex;
282     return omxNode->setParameter(toRawIndexType(omxIdx),
283                                  inHidlBytes(params, sizeof(*params)));
284 }
285 
286 template <class T>
getPortConfig(sp<IOmxNode> omxNode,OMX_INDEXTYPE omxIdx,OMX_U32 nPortIndex,T * params)287 Return<android::hardware::media::omx::V1_0::Status> getPortConfig(
288     sp<IOmxNode> omxNode, OMX_INDEXTYPE omxIdx, OMX_U32 nPortIndex, T* params) {
289     android::hardware::media::omx::V1_0::Status status;
290     InitOMXParams(params);
291     params->nPortIndex = nPortIndex;
292     omxNode->getConfig(
293         toRawIndexType(omxIdx), inHidlBytes(params, sizeof(*params)),
294         [&status, &params](android::hardware::media::omx::V1_0::Status _s,
295                            hidl_vec<uint8_t> const& outParams) {
296             status = _s;
297             std::copy(outParams.data(), outParams.data() + outParams.size(),
298                       static_cast<uint8_t*>(static_cast<void*>(params)));
299         });
300     return status;
301 }
302 
303 template <class T>
setPortConfig(sp<IOmxNode> omxNode,OMX_INDEXTYPE omxIdx,OMX_U32 nPortIndex,T * params)304 Return<android::hardware::media::omx::V1_0::Status> setPortConfig(
305     sp<IOmxNode> omxNode, OMX_INDEXTYPE omxIdx, OMX_U32 nPortIndex, T* params) {
306     InitOMXParams(params);
307     params->nPortIndex = nPortIndex;
308     return omxNode->setConfig(toRawIndexType(omxIdx),
309                               inHidlBytes(params, sizeof(*params)));
310 }
311 
312 /*
313  * common functions declarations
314  */
315 struct GrallocV2 {
316     using Format = android::hardware::graphics::common::V1_0::PixelFormat;
317     using Usage = android::hardware::hidl_bitfield<
318             android::hardware::graphics::common::V1_0::BufferUsage>;
319 
320     using IAllocator = android::hardware::graphics::allocator::V2_0::IAllocator;
321 
322     using IMapper = android::hardware::graphics::mapper::V2_0::IMapper;
323     using Error = android::hardware::graphics::mapper::V2_0::Error;
324     using Descriptor = android::hardware::graphics::mapper::V2_0::BufferDescriptor;
325     using YCbCrLayout = android::hardware::graphics::mapper::V2_0::YCbCrLayout;
326     using DescriptorInfo = IMapper::BufferDescriptorInfo;
327     using Rect = IMapper::Rect;
328 };
329 
330 struct GrallocV3 {
331     using Format = android::hardware::graphics::common::V1_2::PixelFormat;
332     using Usage = android::hardware::hidl_bitfield<
333             android::hardware::graphics::common::V1_2::BufferUsage>;
334 
335     using IAllocator = android::hardware::graphics::allocator::V3_0::IAllocator;
336 
337     using IMapper = android::hardware::graphics::mapper::V3_0::IMapper;
338     using Error = android::hardware::graphics::mapper::V3_0::Error;
339     using Descriptor = android::hardware::graphics::mapper::V3_0::BufferDescriptor;
340     using YCbCrLayout = android::hardware::graphics::mapper::V3_0::YCbCrLayout;
341     using DescriptorInfo = IMapper::BufferDescriptorInfo;
342     using Rect = IMapper::Rect;
343 };
344 
345 Return<android::hardware::media::omx::V1_0::Status> setRole(sp<IOmxNode> omxNode,
346                                                             const std::string& role);
347 
348 Return<android::hardware::media::omx::V1_0::Status> setPortBufferSize(
349     sp<IOmxNode> omxNode, OMX_U32 portIndex, OMX_U32 size);
350 
351 Return<android::hardware::media::omx::V1_0::Status> setVideoPortFormat(
352     sp<IOmxNode> omxNode, OMX_U32 portIndex,
353     OMX_VIDEO_CODINGTYPE eCompressionFormat, OMX_COLOR_FORMATTYPE eColorFormat,
354     OMX_U32 xFramerate);
355 
356 Return<android::hardware::media::omx::V1_0::Status> setAudioPortFormat(
357     sp<IOmxNode> omxNode, OMX_U32 portIndex, OMX_AUDIO_CODINGTYPE eEncoding);
358 
359 void allocateBuffer(sp<IOmxNode> omxNode, BufferInfo* buffer, OMX_U32 portIndex,
360                     OMX_U32 nBufferSize, PortMode portMode);
361 
362 void allocatePortBuffers(sp<IOmxNode> omxNode,
363                          android::Vector<BufferInfo>* buffArray,
364                          OMX_U32 portIndex,
365                          PortMode portMode = PortMode::PRESET_BYTE_BUFFER,
366                          bool allocGrap = false);
367 
368 void changeStateLoadedtoIdle(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
369                              android::Vector<BufferInfo>* iBuffer,
370                              android::Vector<BufferInfo>* oBuffer,
371                              OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput,
372                              PortMode* portMode = nullptr,
373                              bool allocGrap = false);
374 
375 void changeStateIdletoLoaded(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
376                              android::Vector<BufferInfo>* iBuffer,
377                              android::Vector<BufferInfo>* oBuffer,
378                              OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput);
379 
380 void changeStateIdletoExecute(sp<IOmxNode> omxNode, sp<CodecObserver> observer);
381 
382 void changeStateExecutetoIdle(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
383                               android::Vector<BufferInfo>* iBuffer,
384                               android::Vector<BufferInfo>* oBuffer);
385 
386 size_t getEmptyBufferID(android::Vector<BufferInfo>* buffArray);
387 
388 void dispatchOutputBuffer(sp<IOmxNode> omxNode,
389                           android::Vector<BufferInfo>* buffArray,
390                           size_t bufferIndex,
391                           PortMode portMode = PortMode::PRESET_BYTE_BUFFER);
392 
393 void dispatchInputBuffer(sp<IOmxNode> omxNode,
394                          android::Vector<BufferInfo>* buffArray,
395                          size_t bufferIndex, int bytesCount, uint32_t flags,
396                          uint64_t timestamp,
397                          PortMode portMode = PortMode::PRESET_BYTE_BUFFER);
398 
399 void flushPorts(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
400                 android::Vector<BufferInfo>* iBuffer,
401                 android::Vector<BufferInfo>* oBuffer, OMX_U32 kPortIndexInput,
402                 OMX_U32 kPortIndexOutput,
403                 int64_t timeoutUs = DEFAULT_TIMEOUT_PE);
404 
405 typedef void (*portreconfig)(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
406                              android::Vector<BufferInfo>* iBuffer,
407                              android::Vector<BufferInfo>* oBuffer,
408                              OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput,
409                              Message msg, PortMode oPortMode, void* args);
410 void testEOS(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
411              android::Vector<BufferInfo>* iBuffer,
412              android::Vector<BufferInfo>* oBuffer, bool signalEOS,
413              bool& eosFlag, PortMode* portMode = nullptr,
414              portreconfig fptr = nullptr, OMX_U32 kPortIndexInput = 0,
415              OMX_U32 kPortIndexOutput = 1, void* args = nullptr);
416 
417 hidl_vec<IOmx::ComponentInfo> getComponentInfoList(sp<IOmx> omx);
418 
419 // Return all test parameters, a list of tuple of <instance, component, role>
420 const std::vector<std::tuple<std::string, std::string, std::string>>& getTestParameters(
421         const std::string& filter);
422 
423 #endif  // MEDIA_HIDL_TEST_COMMON_H
424