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