Home | History | Annotate | Download | only in omx
      1 /*
      2  * Copyright (C) 2009 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 #include <inttypes.h>
     18 
     19 //#define LOG_NDEBUG 0
     20 #define LOG_TAG "OMX"
     21 #include <utils/Log.h>
     22 
     23 #include <dlfcn.h>
     24 
     25 #include "../include/OMX.h"
     26 
     27 #include "../include/OMXNodeInstance.h"
     28 
     29 #include <binder/IMemory.h>
     30 #include <media/stagefright/foundation/ADebug.h>
     31 #include <utils/threads.h>
     32 
     33 #include "OMXMaster.h"
     34 
     35 #include <OMX_Component.h>
     36 
     37 namespace android {
     38 
     39 ////////////////////////////////////////////////////////////////////////////////
     40 
     41 // This provides the underlying Thread used by CallbackDispatcher.
     42 // Note that deriving CallbackDispatcher from Thread does not work.
     43 
     44 struct OMX::CallbackDispatcherThread : public Thread {
     45     CallbackDispatcherThread(CallbackDispatcher *dispatcher)
     46         : mDispatcher(dispatcher) {
     47     }
     48 
     49 private:
     50     CallbackDispatcher *mDispatcher;
     51 
     52     bool threadLoop();
     53 
     54     CallbackDispatcherThread(const CallbackDispatcherThread &);
     55     CallbackDispatcherThread &operator=(const CallbackDispatcherThread &);
     56 };
     57 
     58 ////////////////////////////////////////////////////////////////////////////////
     59 
     60 struct OMX::CallbackDispatcher : public RefBase {
     61     CallbackDispatcher(OMXNodeInstance *owner);
     62 
     63     void post(const omx_message &msg);
     64 
     65     bool loop();
     66 
     67 protected:
     68     virtual ~CallbackDispatcher();
     69 
     70 private:
     71     Mutex mLock;
     72 
     73     OMXNodeInstance *mOwner;
     74     bool mDone;
     75     Condition mQueueChanged;
     76     List<omx_message> mQueue;
     77 
     78     sp<CallbackDispatcherThread> mThread;
     79 
     80     void dispatch(const omx_message &msg);
     81 
     82     CallbackDispatcher(const CallbackDispatcher &);
     83     CallbackDispatcher &operator=(const CallbackDispatcher &);
     84 };
     85 
     86 OMX::CallbackDispatcher::CallbackDispatcher(OMXNodeInstance *owner)
     87     : mOwner(owner),
     88       mDone(false) {
     89     mThread = new CallbackDispatcherThread(this);
     90     mThread->run("OMXCallbackDisp", ANDROID_PRIORITY_FOREGROUND);
     91 }
     92 
     93 OMX::CallbackDispatcher::~CallbackDispatcher() {
     94     {
     95         Mutex::Autolock autoLock(mLock);
     96 
     97         mDone = true;
     98         mQueueChanged.signal();
     99     }
    100 
    101     // A join on self can happen if the last ref to CallbackDispatcher
    102     // is released within the CallbackDispatcherThread loop
    103     status_t status = mThread->join();
    104     if (status != WOULD_BLOCK) {
    105         // Other than join to self, the only other error return codes are
    106         // whatever readyToRun() returns, and we don't override that
    107         CHECK_EQ(status, (status_t)NO_ERROR);
    108     }
    109 }
    110 
    111 void OMX::CallbackDispatcher::post(const omx_message &msg) {
    112     Mutex::Autolock autoLock(mLock);
    113 
    114     mQueue.push_back(msg);
    115     mQueueChanged.signal();
    116 }
    117 
    118 void OMX::CallbackDispatcher::dispatch(const omx_message &msg) {
    119     if (mOwner == NULL) {
    120         ALOGV("Would have dispatched a message to a node that's already gone.");
    121         return;
    122     }
    123     mOwner->onMessage(msg);
    124 }
    125 
    126 bool OMX::CallbackDispatcher::loop() {
    127     for (;;) {
    128         omx_message msg;
    129 
    130         {
    131             Mutex::Autolock autoLock(mLock);
    132             while (!mDone && mQueue.empty()) {
    133                 mQueueChanged.wait(mLock);
    134             }
    135 
    136             if (mDone) {
    137                 break;
    138             }
    139 
    140             msg = *mQueue.begin();
    141             mQueue.erase(mQueue.begin());
    142         }
    143 
    144         dispatch(msg);
    145     }
    146 
    147     return false;
    148 }
    149 
    150 ////////////////////////////////////////////////////////////////////////////////
    151 
    152 bool OMX::CallbackDispatcherThread::threadLoop() {
    153     return mDispatcher->loop();
    154 }
    155 
    156 ////////////////////////////////////////////////////////////////////////////////
    157 
    158 OMX::OMX()
    159     : mMaster(new OMXMaster),
    160       mNodeCounter(0) {
    161 }
    162 
    163 OMX::~OMX() {
    164     delete mMaster;
    165     mMaster = NULL;
    166 }
    167 
    168 void OMX::binderDied(const wp<IBinder> &the_late_who) {
    169     OMXNodeInstance *instance;
    170 
    171     {
    172         Mutex::Autolock autoLock(mLock);
    173 
    174         ssize_t index = mLiveNodes.indexOfKey(the_late_who);
    175         CHECK(index >= 0);
    176 
    177         instance = mLiveNodes.editValueAt(index);
    178         mLiveNodes.removeItemsAt(index);
    179 
    180         index = mDispatchers.indexOfKey(instance->nodeID());
    181         CHECK(index >= 0);
    182         mDispatchers.removeItemsAt(index);
    183 
    184         invalidateNodeID_l(instance->nodeID());
    185     }
    186 
    187     instance->onObserverDied(mMaster);
    188 }
    189 
    190 bool OMX::livesLocally(node_id /* node */, pid_t pid) {
    191     return pid == getpid();
    192 }
    193 
    194 status_t OMX::listNodes(List<ComponentInfo> *list) {
    195     list->clear();
    196 
    197     OMX_U32 index = 0;
    198     char componentName[256];
    199     while (mMaster->enumerateComponents(
    200                 componentName, sizeof(componentName), index) == OMX_ErrorNone) {
    201         list->push_back(ComponentInfo());
    202         ComponentInfo &info = *--list->end();
    203 
    204         info.mName = componentName;
    205 
    206         Vector<String8> roles;
    207         OMX_ERRORTYPE err =
    208             mMaster->getRolesOfComponent(componentName, &roles);
    209 
    210         if (err == OMX_ErrorNone) {
    211             for (OMX_U32 i = 0; i < roles.size(); ++i) {
    212                 info.mRoles.push_back(roles[i]);
    213             }
    214         }
    215 
    216         ++index;
    217     }
    218 
    219     return OK;
    220 }
    221 
    222 status_t OMX::allocateNode(
    223         const char *name, const sp<IOMXObserver> &observer, node_id *node) {
    224     Mutex::Autolock autoLock(mLock);
    225 
    226     *node = 0;
    227 
    228     OMXNodeInstance *instance = new OMXNodeInstance(this, observer);
    229 
    230     OMX_COMPONENTTYPE *handle;
    231     OMX_ERRORTYPE err = mMaster->makeComponentInstance(
    232             name, &OMXNodeInstance::kCallbacks,
    233             instance, &handle);
    234 
    235     if (err != OMX_ErrorNone) {
    236         ALOGE("FAILED to allocate omx component '%s'", name);
    237 
    238         instance->onGetHandleFailed();
    239 
    240         return UNKNOWN_ERROR;
    241     }
    242 
    243     *node = makeNodeID(instance);
    244     mDispatchers.add(*node, new CallbackDispatcher(instance));
    245 
    246     instance->setHandle(*node, handle);
    247 
    248     mLiveNodes.add(observer->asBinder(), instance);
    249     observer->asBinder()->linkToDeath(this);
    250 
    251     return OK;
    252 }
    253 
    254 status_t OMX::freeNode(node_id node) {
    255     OMXNodeInstance *instance = findInstance(node);
    256 
    257     {
    258         Mutex::Autolock autoLock(mLock);
    259         ssize_t index = mLiveNodes.indexOfKey(instance->observer()->asBinder());
    260         if (index < 0) {
    261             // This could conceivably happen if the observer dies at roughly the
    262             // same time that a client attempts to free the node explicitly.
    263             return OK;
    264         }
    265         mLiveNodes.removeItemsAt(index);
    266     }
    267 
    268     instance->observer()->asBinder()->unlinkToDeath(this);
    269 
    270     status_t err = instance->freeNode(mMaster);
    271 
    272     {
    273         Mutex::Autolock autoLock(mLock);
    274         ssize_t index = mDispatchers.indexOfKey(node);
    275         CHECK(index >= 0);
    276         mDispatchers.removeItemsAt(index);
    277     }
    278 
    279     return err;
    280 }
    281 
    282 status_t OMX::sendCommand(
    283         node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
    284     return findInstance(node)->sendCommand(cmd, param);
    285 }
    286 
    287 status_t OMX::getParameter(
    288         node_id node, OMX_INDEXTYPE index,
    289         void *params, size_t size) {
    290     ALOGV("getParameter(%u %#x %p %zd)", node, index, params, size);
    291     return findInstance(node)->getParameter(
    292             index, params, size);
    293 }
    294 
    295 status_t OMX::setParameter(
    296         node_id node, OMX_INDEXTYPE index,
    297         const void *params, size_t size) {
    298     ALOGV("setParameter(%u %#x %p %zd)", node, index, params, size);
    299     return findInstance(node)->setParameter(
    300             index, params, size);
    301 }
    302 
    303 status_t OMX::getConfig(
    304         node_id node, OMX_INDEXTYPE index,
    305         void *params, size_t size) {
    306     return findInstance(node)->getConfig(
    307             index, params, size);
    308 }
    309 
    310 status_t OMX::setConfig(
    311         node_id node, OMX_INDEXTYPE index,
    312         const void *params, size_t size) {
    313     return findInstance(node)->setConfig(
    314             index, params, size);
    315 }
    316 
    317 status_t OMX::getState(
    318         node_id node, OMX_STATETYPE* state) {
    319     return findInstance(node)->getState(
    320             state);
    321 }
    322 
    323 status_t OMX::enableGraphicBuffers(
    324         node_id node, OMX_U32 port_index, OMX_BOOL enable) {
    325     return findInstance(node)->enableGraphicBuffers(port_index, enable);
    326 }
    327 
    328 status_t OMX::getGraphicBufferUsage(
    329         node_id node, OMX_U32 port_index, OMX_U32* usage) {
    330     return findInstance(node)->getGraphicBufferUsage(port_index, usage);
    331 }
    332 
    333 status_t OMX::storeMetaDataInBuffers(
    334         node_id node, OMX_U32 port_index, OMX_BOOL enable) {
    335     return findInstance(node)->storeMetaDataInBuffers(port_index, enable);
    336 }
    337 
    338 status_t OMX::prepareForAdaptivePlayback(
    339         node_id node, OMX_U32 portIndex, OMX_BOOL enable,
    340         OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight) {
    341     return findInstance(node)->prepareForAdaptivePlayback(
    342             portIndex, enable, maxFrameWidth, maxFrameHeight);
    343 }
    344 
    345 status_t OMX::configureVideoTunnelMode(
    346         node_id node, OMX_U32 portIndex, OMX_BOOL tunneled,
    347         OMX_U32 audioHwSync, native_handle_t **sidebandHandle) {
    348     return findInstance(node)->configureVideoTunnelMode(
    349             portIndex, tunneled, audioHwSync, sidebandHandle);
    350 }
    351 
    352 status_t OMX::useBuffer(
    353         node_id node, OMX_U32 port_index, const sp<IMemory> &params,
    354         buffer_id *buffer) {
    355     return findInstance(node)->useBuffer(
    356             port_index, params, buffer);
    357 }
    358 
    359 status_t OMX::useGraphicBuffer(
    360         node_id node, OMX_U32 port_index,
    361         const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer) {
    362     return findInstance(node)->useGraphicBuffer(
    363             port_index, graphicBuffer, buffer);
    364 }
    365 
    366 status_t OMX::updateGraphicBufferInMeta(
    367         node_id node, OMX_U32 port_index,
    368         const sp<GraphicBuffer> &graphicBuffer, buffer_id buffer) {
    369     return findInstance(node)->updateGraphicBufferInMeta(
    370             port_index, graphicBuffer, buffer);
    371 }
    372 
    373 status_t OMX::createInputSurface(
    374         node_id node, OMX_U32 port_index,
    375         sp<IGraphicBufferProducer> *bufferProducer) {
    376     return findInstance(node)->createInputSurface(
    377             port_index, bufferProducer);
    378 }
    379 
    380 status_t OMX::signalEndOfInputStream(node_id node) {
    381     return findInstance(node)->signalEndOfInputStream();
    382 }
    383 
    384 status_t OMX::allocateBuffer(
    385         node_id node, OMX_U32 port_index, size_t size,
    386         buffer_id *buffer, void **buffer_data) {
    387     return findInstance(node)->allocateBuffer(
    388             port_index, size, buffer, buffer_data);
    389 }
    390 
    391 status_t OMX::allocateBufferWithBackup(
    392         node_id node, OMX_U32 port_index, const sp<IMemory> &params,
    393         buffer_id *buffer) {
    394     return findInstance(node)->allocateBufferWithBackup(
    395             port_index, params, buffer);
    396 }
    397 
    398 status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) {
    399     return findInstance(node)->freeBuffer(
    400             port_index, buffer);
    401 }
    402 
    403 status_t OMX::fillBuffer(node_id node, buffer_id buffer) {
    404     return findInstance(node)->fillBuffer(buffer);
    405 }
    406 
    407 status_t OMX::emptyBuffer(
    408         node_id node,
    409         buffer_id buffer,
    410         OMX_U32 range_offset, OMX_U32 range_length,
    411         OMX_U32 flags, OMX_TICKS timestamp) {
    412     return findInstance(node)->emptyBuffer(
    413             buffer, range_offset, range_length, flags, timestamp);
    414 }
    415 
    416 status_t OMX::getExtensionIndex(
    417         node_id node,
    418         const char *parameter_name,
    419         OMX_INDEXTYPE *index) {
    420     return findInstance(node)->getExtensionIndex(
    421             parameter_name, index);
    422 }
    423 
    424 status_t OMX::setInternalOption(
    425         node_id node,
    426         OMX_U32 port_index,
    427         InternalOptionType type,
    428         const void *data,
    429         size_t size) {
    430     return findInstance(node)->setInternalOption(port_index, type, data, size);
    431 }
    432 
    433 OMX_ERRORTYPE OMX::OnEvent(
    434         node_id node,
    435         OMX_IN OMX_EVENTTYPE eEvent,
    436         OMX_IN OMX_U32 nData1,
    437         OMX_IN OMX_U32 nData2,
    438         OMX_IN OMX_PTR /* pEventData */) {
    439     ALOGV("OnEvent(%d, %" PRIu32", %" PRIu32 ")", eEvent, nData1, nData2);
    440 
    441     // Forward to OMXNodeInstance.
    442     findInstance(node)->onEvent(eEvent, nData1, nData2);
    443 
    444     omx_message msg;
    445     msg.type = omx_message::EVENT;
    446     msg.node = node;
    447     msg.u.event_data.event = eEvent;
    448     msg.u.event_data.data1 = nData1;
    449     msg.u.event_data.data2 = nData2;
    450 
    451     findDispatcher(node)->post(msg);
    452 
    453     return OMX_ErrorNone;
    454 }
    455 
    456 OMX_ERRORTYPE OMX::OnEmptyBufferDone(
    457         node_id node, buffer_id buffer, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
    458     ALOGV("OnEmptyBufferDone buffer=%p", pBuffer);
    459 
    460     omx_message msg;
    461     msg.type = omx_message::EMPTY_BUFFER_DONE;
    462     msg.node = node;
    463     msg.u.buffer_data.buffer = buffer;
    464 
    465     findDispatcher(node)->post(msg);
    466 
    467     return OMX_ErrorNone;
    468 }
    469 
    470 OMX_ERRORTYPE OMX::OnFillBufferDone(
    471         node_id node, buffer_id buffer, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
    472     ALOGV("OnFillBufferDone buffer=%p", pBuffer);
    473 
    474     omx_message msg;
    475     msg.type = omx_message::FILL_BUFFER_DONE;
    476     msg.node = node;
    477     msg.u.extended_buffer_data.buffer = buffer;
    478     msg.u.extended_buffer_data.range_offset = pBuffer->nOffset;
    479     msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen;
    480     msg.u.extended_buffer_data.flags = pBuffer->nFlags;
    481     msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp;
    482 
    483     findDispatcher(node)->post(msg);
    484 
    485     return OMX_ErrorNone;
    486 }
    487 
    488 OMX::node_id OMX::makeNodeID(OMXNodeInstance *instance) {
    489     // mLock is already held.
    490 
    491     node_id node = (node_id)++mNodeCounter;
    492     mNodeIDToInstance.add(node, instance);
    493 
    494     return node;
    495 }
    496 
    497 OMXNodeInstance *OMX::findInstance(node_id node) {
    498     Mutex::Autolock autoLock(mLock);
    499 
    500     ssize_t index = mNodeIDToInstance.indexOfKey(node);
    501 
    502     return index < 0 ? NULL : mNodeIDToInstance.valueAt(index);
    503 }
    504 
    505 sp<OMX::CallbackDispatcher> OMX::findDispatcher(node_id node) {
    506     Mutex::Autolock autoLock(mLock);
    507 
    508     ssize_t index = mDispatchers.indexOfKey(node);
    509 
    510     return index < 0 ? NULL : mDispatchers.valueAt(index);
    511 }
    512 
    513 void OMX::invalidateNodeID(node_id node) {
    514     Mutex::Autolock autoLock(mLock);
    515     invalidateNodeID_l(node);
    516 }
    517 
    518 void OMX::invalidateNodeID_l(node_id node) {
    519     // mLock is held.
    520     mNodeIDToInstance.removeItem(node);
    521 }
    522 
    523 }  // namespace android
    524