Home | History | Annotate | Download | only in common
      1 /*
      2  * Copyright (C) 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 #define LOG_TAG "media_omx_hidl_video_test_common"
     18 
     19 #ifdef __LP64__
     20 #define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
     21 #endif
     22 
     23 #include <android-base/logging.h>
     24 
     25 #include <android/hardware/media/omx/1.0/IOmx.h>
     26 #include <android/hardware/media/omx/1.0/IOmxNode.h>
     27 #include <android/hardware/media/omx/1.0/IOmxObserver.h>
     28 #include <android/hardware/media/omx/1.0/types.h>
     29 #include <android/hidl/allocator/1.0/IAllocator.h>
     30 #include <android/hidl/memory/1.0/IMapper.h>
     31 #include <android/hidl/memory/1.0/IMemory.h>
     32 
     33 using ::android::hardware::media::omx::V1_0::IOmx;
     34 using ::android::hardware::media::omx::V1_0::IOmxObserver;
     35 using ::android::hardware::media::omx::V1_0::IOmxNode;
     36 using ::android::hardware::media::omx::V1_0::Message;
     37 using ::android::hardware::media::omx::V1_0::CodecBuffer;
     38 using ::android::hardware::media::omx::V1_0::PortMode;
     39 using ::android::hardware::media::omx::V1_0::Status;
     40 using ::android::hidl::allocator::V1_0::IAllocator;
     41 using ::android::hidl::memory::V1_0::IMemory;
     42 using ::android::hidl::memory::V1_0::IMapper;
     43 using ::android::hardware::Return;
     44 using ::android::hardware::Void;
     45 using ::android::hardware::hidl_vec;
     46 using ::android::hardware::hidl_string;
     47 using ::android::sp;
     48 
     49 #include <VtsHalHidlTargetTestBase.h>
     50 #include <hidlmemory/mapping.h>
     51 #include <media/hardware/HardwareAPI.h>
     52 #include <media_hidl_test_common.h>
     53 #include <memory>
     54 
     55 // set component role
     56 Return<android::hardware::media::omx::V1_0::Status> setRole(
     57     sp<IOmxNode> omxNode, const char* role) {
     58     OMX_PARAM_COMPONENTROLETYPE params;
     59     strcpy((char*)params.cRole, role);
     60     return setParam(omxNode, OMX_IndexParamStandardComponentRole, &params);
     61 }
     62 
     63 // allocate buffers needed on a component port
     64 void allocatePortBuffers(sp<IOmxNode> omxNode,
     65                          android::Vector<BufferInfo>* buffArray,
     66                          OMX_U32 portIndex, PortMode portMode) {
     67     android::hardware::media::omx::V1_0::Status status;
     68     OMX_PARAM_PORTDEFINITIONTYPE portDef;
     69 
     70     buffArray->clear();
     71 
     72     status = getPortParam(omxNode, OMX_IndexParamPortDefinition, portIndex,
     73                           &portDef);
     74     ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
     75 
     76     if (portMode == PortMode::PRESET_SECURE_BUFFER) {
     77         for (size_t i = 0; i < portDef.nBufferCountActual; i++) {
     78             BufferInfo buffer;
     79             buffer.owner = client;
     80             buffer.omxBuffer.type = CodecBuffer::Type::NATIVE_HANDLE;
     81             omxNode->allocateSecureBuffer(
     82                 portIndex, portDef.nBufferSize,
     83                 [&status, &buffer](
     84                     android::hardware::media::omx::V1_0::Status _s, uint32_t id,
     85                     ::android::hardware::hidl_handle const& nativeHandle) {
     86                     status = _s;
     87                     buffer.id = id;
     88                     buffer.omxBuffer.nativeHandle = nativeHandle;
     89                 });
     90             buffArray->push(buffer);
     91             ASSERT_EQ(status,
     92                       ::android::hardware::media::omx::V1_0::Status::OK);
     93         }
     94     } else if (portMode == PortMode::PRESET_BYTE_BUFFER ||
     95                portMode == PortMode::DYNAMIC_ANW_BUFFER) {
     96         sp<IAllocator> allocator = IAllocator::getService("ashmem");
     97         EXPECT_NE(allocator.get(), nullptr);
     98 
     99         for (size_t i = 0; i < portDef.nBufferCountActual; i++) {
    100             BufferInfo buffer;
    101             buffer.owner = client;
    102             buffer.omxBuffer.type = CodecBuffer::Type::SHARED_MEM;
    103             buffer.omxBuffer.attr.preset.rangeOffset = 0;
    104             buffer.omxBuffer.attr.preset.rangeLength = 0;
    105             bool success = false;
    106             if (portMode != PortMode::PRESET_BYTE_BUFFER) {
    107                 portDef.nBufferSize = sizeof(android::VideoNativeMetadata);
    108             }
    109             allocator->allocate(
    110                 portDef.nBufferSize,
    111                 [&success, &buffer](
    112                     bool _s, ::android::hardware::hidl_memory const& mem) {
    113                     success = _s;
    114                     buffer.omxBuffer.sharedMemory = mem;
    115                 });
    116             ASSERT_EQ(success, true);
    117             ASSERT_EQ(buffer.omxBuffer.sharedMemory.size(),
    118                       portDef.nBufferSize);
    119             buffer.mMemory = mapMemory(buffer.omxBuffer.sharedMemory);
    120             ASSERT_NE(buffer.mMemory, nullptr);
    121             if (portMode == PortMode::DYNAMIC_ANW_BUFFER) {
    122                 android::VideoNativeMetadata* metaData =
    123                     static_cast<android::VideoNativeMetadata*>(
    124                         static_cast<void*>(buffer.mMemory->getPointer()));
    125                 metaData->nFenceFd = -1;
    126                 buffer.slot = -1;
    127             }
    128             omxNode->useBuffer(
    129                 portIndex, buffer.omxBuffer,
    130                 [&status, &buffer](
    131                     android::hardware::media::omx::V1_0::Status _s,
    132                     uint32_t id) {
    133                     status = _s;
    134                     buffer.id = id;
    135                 });
    136             buffArray->push(buffer);
    137             ASSERT_EQ(status,
    138                       ::android::hardware::media::omx::V1_0::Status::OK);
    139         }
    140     }
    141 }
    142 
    143 // State Transition : Loaded -> Idle
    144 // Note: This function does not make any background checks for this transition.
    145 // The callee holds the reponsibility to ensure the legality of the transition.
    146 void changeStateLoadedtoIdle(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
    147                              android::Vector<BufferInfo>* iBuffer,
    148                              android::Vector<BufferInfo>* oBuffer,
    149                              OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput,
    150                              PortMode* portMode) {
    151     android::hardware::media::omx::V1_0::Status status;
    152     Message msg;
    153     PortMode defaultPortMode[2], *pm;
    154 
    155     defaultPortMode[0] = PortMode::PRESET_BYTE_BUFFER;
    156     defaultPortMode[1] = PortMode::PRESET_BYTE_BUFFER;
    157     pm = portMode ? portMode : defaultPortMode;
    158 
    159     // set state to idle
    160     status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
    161                                   OMX_StateIdle);
    162     ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
    163 
    164     // Dont switch states until the ports are populated
    165     status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer);
    166     ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT);
    167 
    168     // allocate buffers on input port
    169     allocatePortBuffers(omxNode, iBuffer, kPortIndexInput, pm[0]);
    170 
    171     // Dont switch states until the ports are populated
    172     status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer);
    173     ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT);
    174 
    175     // allocate buffers on output port
    176     allocatePortBuffers(omxNode, oBuffer, kPortIndexOutput, pm[1]);
    177 
    178     // As the ports are populated, check if the state transition is complete
    179     status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer);
    180     ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
    181     ASSERT_EQ(msg.type, Message::Type::EVENT);
    182     ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
    183     ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
    184     ASSERT_EQ(msg.data.eventData.data2, OMX_StateIdle);
    185 
    186     return;
    187 }
    188 
    189 // State Transition : Idle -> Loaded
    190 // Note: This function does not make any background checks for this transition.
    191 // The callee holds the reponsibility to ensure the legality of the transition.
    192 void changeStateIdletoLoaded(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
    193                              android::Vector<BufferInfo>* iBuffer,
    194                              android::Vector<BufferInfo>* oBuffer,
    195                              OMX_U32 kPortIndexInput,
    196                              OMX_U32 kPortIndexOutput) {
    197     android::hardware::media::omx::V1_0::Status status;
    198     Message msg;
    199 
    200     // set state to Loaded
    201     status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
    202                                   OMX_StateLoaded);
    203     ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
    204 
    205     // dont change state until all buffers are freed
    206     status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer);
    207     ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT);
    208 
    209     for (size_t i = 0; i < iBuffer->size(); ++i) {
    210         status = omxNode->freeBuffer(kPortIndexInput, (*iBuffer)[i].id);
    211         ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
    212     }
    213 
    214     // dont change state until all buffers are freed
    215     status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer);
    216     ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT);
    217 
    218     for (size_t i = 0; i < oBuffer->size(); ++i) {
    219         status = omxNode->freeBuffer(kPortIndexOutput, (*oBuffer)[i].id);
    220         ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
    221     }
    222 
    223     status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer);
    224     ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
    225     ASSERT_EQ(msg.type, Message::Type::EVENT);
    226     ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
    227     ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
    228     ASSERT_EQ(msg.data.eventData.data2, OMX_StateLoaded);
    229 
    230     return;
    231 }
    232 
    233 // State Transition : Idle -> Execute
    234 // Note: This function does not make any background checks for this transition.
    235 // The callee holds the reponsibility to ensure the legality of the transition.
    236 void changeStateIdletoExecute(sp<IOmxNode> omxNode,
    237                               sp<CodecObserver> observer) {
    238     android::hardware::media::omx::V1_0::Status status;
    239     Message msg;
    240 
    241     // set state to execute
    242     status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
    243                                   OMX_StateExecuting);
    244     ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
    245     status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT);
    246     ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
    247     ASSERT_EQ(msg.type, Message::Type::EVENT);
    248     ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
    249     ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
    250     ASSERT_EQ(msg.data.eventData.data2, OMX_StateExecuting);
    251 
    252     return;
    253 }
    254 
    255 // State Transition : Execute -> Idle
    256 // Note: This function does not make any background checks for this transition.
    257 // The callee holds the reponsibility to ensure the legality of the transition.
    258 void changeStateExecutetoIdle(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
    259                               android::Vector<BufferInfo>* iBuffer,
    260                               android::Vector<BufferInfo>* oBuffer) {
    261     android::hardware::media::omx::V1_0::Status status;
    262     Message msg;
    263 
    264     // set state to Idle
    265     status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
    266                                   OMX_StateIdle);
    267     ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
    268     status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer);
    269     ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
    270     ASSERT_EQ(msg.type, Message::Type::EVENT);
    271     ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
    272     ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
    273     ASSERT_EQ(msg.data.eventData.data2, OMX_StateIdle);
    274 
    275     // test if client got all its buffers back
    276     for (size_t i = 0; i < oBuffer->size(); ++i) {
    277         EXPECT_EQ((*oBuffer)[i].owner, client);
    278     }
    279     for (size_t i = 0; i < iBuffer->size(); ++i) {
    280         EXPECT_EQ((*iBuffer)[i].owner, client);
    281     }
    282 }
    283 
    284 // get empty buffer index
    285 size_t getEmptyBufferID(android::Vector<BufferInfo>* buffArray) {
    286     android::Vector<BufferInfo>::iterator it = buffArray->begin();
    287     while (it != buffArray->end()) {
    288         if (it->owner == client) {
    289             // This block of code ensures that all buffers allocated at init
    290             // time are utilized
    291             BufferInfo backup = *it;
    292             buffArray->erase(it);
    293             buffArray->push_back(backup);
    294             return buffArray->size() - 1;
    295         }
    296         it++;
    297     }
    298     return buffArray->size();
    299 }
    300 
    301 // dispatch buffer to output port
    302 void dispatchOutputBuffer(sp<IOmxNode> omxNode,
    303                           android::Vector<BufferInfo>* buffArray,
    304                           size_t bufferIndex, PortMode portMode) {
    305     android::hardware::media::omx::V1_0::Status status;
    306     CodecBuffer t;
    307     native_handle_t* fenceNh = native_handle_create(0, 0);
    308     ASSERT_NE(fenceNh, nullptr);
    309     switch (portMode) {
    310         case PortMode::DYNAMIC_ANW_BUFFER:
    311             t = (*buffArray)[bufferIndex].omxBuffer;
    312             t.type = CodecBuffer::Type::ANW_BUFFER;
    313             status =
    314                 omxNode->fillBuffer((*buffArray)[bufferIndex].id, t, fenceNh);
    315             break;
    316         case PortMode::PRESET_SECURE_BUFFER:
    317         case PortMode::PRESET_BYTE_BUFFER:
    318             t.sharedMemory = android::hardware::hidl_memory();
    319             t.nativeHandle = android::hardware::hidl_handle();
    320             t.type = CodecBuffer::Type::PRESET;
    321             t.attr.preset.rangeOffset = 0;
    322             t.attr.preset.rangeLength = 0;
    323             status =
    324                 omxNode->fillBuffer((*buffArray)[bufferIndex].id, t, fenceNh);
    325             break;
    326         default:
    327             status = Status::NAME_NOT_FOUND;
    328     }
    329     native_handle_close(fenceNh);
    330     native_handle_delete(fenceNh);
    331     ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
    332     buffArray->editItemAt(bufferIndex).owner = component;
    333 }
    334 
    335 // dispatch buffer to input port
    336 void dispatchInputBuffer(sp<IOmxNode> omxNode,
    337                          android::Vector<BufferInfo>* buffArray,
    338                          size_t bufferIndex, int bytesCount, uint32_t flags,
    339                          uint64_t timestamp, PortMode portMode) {
    340     android::hardware::media::omx::V1_0::Status status;
    341     CodecBuffer t;
    342     native_handle_t* fenceNh = native_handle_create(0, 0);
    343     ASSERT_NE(fenceNh, nullptr);
    344     switch (portMode) {
    345         case PortMode::PRESET_SECURE_BUFFER:
    346         case PortMode::PRESET_BYTE_BUFFER:
    347             t.sharedMemory = android::hardware::hidl_memory();
    348             t.nativeHandle = android::hardware::hidl_handle();
    349             t.type = CodecBuffer::Type::PRESET;
    350             t.attr.preset.rangeOffset = 0;
    351             t.attr.preset.rangeLength = bytesCount;
    352             status = omxNode->emptyBuffer((*buffArray)[bufferIndex].id, t,
    353                                           flags, timestamp, fenceNh);
    354             break;
    355         default:
    356             status = Status::NAME_NOT_FOUND;
    357     }
    358     native_handle_close(fenceNh);
    359     native_handle_delete(fenceNh);
    360     ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
    361     buffArray->editItemAt(bufferIndex).owner = component;
    362 }
    363 
    364 // Flush input and output ports
    365 void flushPorts(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
    366                 android::Vector<BufferInfo>* iBuffer,
    367                 android::Vector<BufferInfo>* oBuffer, OMX_U32 kPortIndexInput,
    368                 OMX_U32 kPortIndexOutput, int64_t timeoutUs) {
    369     android::hardware::media::omx::V1_0::Status status;
    370     Message msg;
    371 
    372     // Flush input port
    373     status = omxNode->sendCommand(toRawCommandType(OMX_CommandFlush),
    374                                   kPortIndexInput);
    375     ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
    376     status = observer->dequeueMessage(&msg, timeoutUs, iBuffer, oBuffer);
    377     ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
    378     ASSERT_EQ(msg.type, Message::Type::EVENT);
    379     ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
    380     ASSERT_EQ(msg.data.eventData.data1, OMX_CommandFlush);
    381     ASSERT_EQ(msg.data.eventData.data2, kPortIndexInput);
    382     // test if client got all its buffers back
    383     for (size_t i = 0; i < iBuffer->size(); ++i) {
    384         EXPECT_EQ((*iBuffer)[i].owner, client);
    385     }
    386 
    387     // Flush output port
    388     status = omxNode->sendCommand(toRawCommandType(OMX_CommandFlush),
    389                                   kPortIndexOutput);
    390     ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
    391     status = observer->dequeueMessage(&msg, timeoutUs, iBuffer, oBuffer);
    392     ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
    393     ASSERT_EQ(msg.type, Message::Type::EVENT);
    394     ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
    395     ASSERT_EQ(msg.data.eventData.data1, OMX_CommandFlush);
    396     ASSERT_EQ(msg.data.eventData.data2, kPortIndexOutput);
    397     // test if client got all its buffers back
    398     for (size_t i = 0; i < oBuffer->size(); ++i) {
    399         EXPECT_EQ((*oBuffer)[i].owner, client);
    400     }
    401 }
    402 
    403 // dispatch an empty input buffer with eos flag set if requested.
    404 // This call assumes that all input buffers are processed completely.
    405 // feed output buffers till we receive a buffer with eos flag set
    406 void testEOS(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
    407              android::Vector<BufferInfo>* iBuffer,
    408              android::Vector<BufferInfo>* oBuffer, bool signalEOS,
    409              bool& eosFlag, PortMode* portMode) {
    410     android::hardware::media::omx::V1_0::Status status;
    411     PortMode defaultPortMode[2], *pm;
    412 
    413     defaultPortMode[0] = PortMode::PRESET_BYTE_BUFFER;
    414     defaultPortMode[1] = PortMode::PRESET_BYTE_BUFFER;
    415     pm = portMode ? portMode : defaultPortMode;
    416 
    417     size_t i = 0;
    418     if (signalEOS) {
    419         if ((i = getEmptyBufferID(iBuffer)) < iBuffer->size()) {
    420             // signal an empty buffer with flag set to EOS
    421             dispatchInputBuffer(omxNode, iBuffer, i, 0, OMX_BUFFERFLAG_EOS, 0);
    422         } else {
    423             ASSERT_TRUE(false);
    424         }
    425     }
    426 
    427     int timeOut = TIMEOUT_COUNTER;
    428     while (timeOut--) {
    429         // Dispatch all client owned output buffers to recover remaining frames
    430         while (1) {
    431             if ((i = getEmptyBufferID(oBuffer)) < oBuffer->size()) {
    432                 dispatchOutputBuffer(omxNode, oBuffer, i, pm[1]);
    433                 // if dispatch is successful, perhaps there is a latency
    434                 // in the component. Dont be in a haste to leave. reset timeout
    435                 // counter
    436                 timeOut = TIMEOUT_COUNTER;
    437             } else {
    438                 break;
    439             }
    440         }
    441 
    442         Message msg;
    443         status =
    444             observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer);
    445         if (status == android::hardware::media::omx::V1_0::Status::OK) {
    446             if (msg.data.eventData.event == OMX_EventBufferFlag) {
    447                 // soft omx components donot send this, we will just ignore it
    448                 // for now
    449             } else {
    450                 // something unexpected happened
    451                 EXPECT_TRUE(false);
    452             }
    453         }
    454         if (eosFlag == true) break;
    455     }
    456     // test for flag
    457     EXPECT_EQ(eosFlag, true);
    458     eosFlag = false;
    459 }
    460