Home | History | Annotate | Download | only in common
      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  */
     74 inline uint32_t toRawIndexType(OMX_INDEXTYPE l) {
     75     return static_cast<uint32_t>(l);
     76 }
     77 
     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 
     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 
     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:
    116     CodecObserver(std::function<void(Message, const BufferInfo*)> fn)
    117         : callBack(fn) {}
    118     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>
    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>
    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>
    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>
    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>
    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>
    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>
    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:
    367     virtual void registerTestServices() override { registerTestService<IOmx>(); }
    368 
    369     ComponentTestEnvironment() : res("/sdcard/media/") {}
    370 
    371     void setComponent(const char* _component) { component = _component; }
    372 
    373     void setRole(const char* _role) { role = _role; }
    374 
    375     void setRes(const char* _res) { res = _res; }
    376 
    377     const hidl_string getInstance() { return Super::getServiceName<IOmx>(); }
    378 
    379     const hidl_string getComponent() const { return component; }
    380 
    381     const hidl_string getRole() const { return role; }
    382 
    383     const hidl_string getRes() const { return res; }
    384 
    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