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     {
    256         Mutex::Autolock autoLock(mLock);
    257         ssize_t index = mLiveNodes.indexOfKey(instance->observer()->asBinder());
    258         if (index < 0) {
    259             // This could conceivably happen if the observer dies at roughly the
    260             // same time that a client attempts to free the node explicitly.
    261             return OK;
    262         }
    263         mLiveNodes.removeItemsAt(index);
    264     }
    265 
    266     instance->observer()->asBinder()->unlinkToDeath(this);
    267 
    268     status_t err = instance->freeNode(mMaster);
    269 
    270     {
    271         Mutex::Autolock autoLock(mLock);
    272         ssize_t index = mDispatchers.indexOfKey(node);
    273         CHECK(index >= 0);
    274         mDispatchers.removeItemsAt(index);
    275     }
    276 
    277     return err;
    278 }
    279 
    280 status_t OMX::sendCommand(
    281         node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
    282     return findInstance(node)->sendCommand(cmd, param);
    283 }
    284 
    285 status_t OMX::getParameter(
    286         node_id node, OMX_INDEXTYPE index,
    287         void *params, size_t size) {
    288     return findInstance(node)->getParameter(
    289             index, params, size);
    290 }
    291 
    292 status_t OMX::setParameter(
    293         node_id node, OMX_INDEXTYPE index,
    294         const void *params, size_t size) {
    295     return findInstance(node)->setParameter(
    296             index, params, size);
    297 }
    298 
    299 status_t OMX::getConfig(
    300         node_id node, OMX_INDEXTYPE index,
    301         void *params, size_t size) {
    302     return findInstance(node)->getConfig(
    303             index, params, size);
    304 }
    305 
    306 status_t OMX::setConfig(
    307         node_id node, OMX_INDEXTYPE index,
    308         const void *params, size_t size) {
    309     return findInstance(node)->setConfig(
    310             index, params, size);
    311 }
    312 
    313 status_t OMX::getState(
    314         node_id node, OMX_STATETYPE* state) {
    315     return findInstance(node)->getState(
    316             state);
    317 }
    318 
    319 status_t OMX::enableGraphicBuffers(
    320         node_id node, OMX_U32 port_index, OMX_BOOL enable) {
    321     return findInstance(node)->enableGraphicBuffers(port_index, enable);
    322 }
    323 
    324 status_t OMX::getGraphicBufferUsage(
    325         node_id node, OMX_U32 port_index, OMX_U32* usage) {
    326     return findInstance(node)->getGraphicBufferUsage(port_index, usage);
    327 }
    328 
    329 status_t OMX::storeMetaDataInBuffers(
    330         node_id node, OMX_U32 port_index, OMX_BOOL enable) {
    331     return findInstance(node)->storeMetaDataInBuffers(port_index, enable);
    332 }
    333 
    334 status_t OMX::useBuffer(
    335         node_id node, OMX_U32 port_index, const sp<IMemory> &params,
    336         buffer_id *buffer) {
    337     return findInstance(node)->useBuffer(
    338             port_index, params, buffer);
    339 }
    340 
    341 status_t OMX::useGraphicBuffer(
    342         node_id node, OMX_U32 port_index,
    343         const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer) {
    344     return findInstance(node)->useGraphicBuffer(
    345             port_index, graphicBuffer, buffer);
    346 }
    347 
    348 status_t OMX::createInputSurface(
    349         node_id node, OMX_U32 port_index,
    350         sp<IGraphicBufferProducer> *bufferProducer) {
    351     return findInstance(node)->createInputSurface(
    352             port_index, bufferProducer);
    353 }
    354 
    355 status_t OMX::signalEndOfInputStream(node_id node) {
    356     return findInstance(node)->signalEndOfInputStream();
    357 }
    358 
    359 status_t OMX::allocateBuffer(
    360         node_id node, OMX_U32 port_index, size_t size,
    361         buffer_id *buffer, void **buffer_data) {
    362     return findInstance(node)->allocateBuffer(
    363             port_index, size, buffer, buffer_data);
    364 }
    365 
    366 status_t OMX::allocateBufferWithBackup(
    367         node_id node, OMX_U32 port_index, const sp<IMemory> &params,
    368         buffer_id *buffer) {
    369     return findInstance(node)->allocateBufferWithBackup(
    370             port_index, params, buffer);
    371 }
    372 
    373 status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) {
    374     return findInstance(node)->freeBuffer(
    375             port_index, buffer);
    376 }
    377 
    378 status_t OMX::fillBuffer(node_id node, buffer_id buffer) {
    379     return findInstance(node)->fillBuffer(buffer);
    380 }
    381 
    382 status_t OMX::emptyBuffer(
    383         node_id node,
    384         buffer_id buffer,
    385         OMX_U32 range_offset, OMX_U32 range_length,
    386         OMX_U32 flags, OMX_TICKS timestamp) {
    387     return findInstance(node)->emptyBuffer(
    388             buffer, range_offset, range_length, flags, timestamp);
    389 }
    390 
    391 status_t OMX::getExtensionIndex(
    392         node_id node,
    393         const char *parameter_name,
    394         OMX_INDEXTYPE *index) {
    395     return findInstance(node)->getExtensionIndex(
    396             parameter_name, index);
    397 }
    398 
    399 OMX_ERRORTYPE OMX::OnEvent(
    400         node_id node,
    401         OMX_IN OMX_EVENTTYPE eEvent,
    402         OMX_IN OMX_U32 nData1,
    403         OMX_IN OMX_U32 nData2,
    404         OMX_IN OMX_PTR pEventData) {
    405     ALOGV("OnEvent(%d, %ld, %ld)", eEvent, nData1, nData2);
    406 
    407     // Forward to OMXNodeInstance.
    408     findInstance(node)->onEvent(eEvent, nData1, nData2);
    409 
    410     omx_message msg;
    411     msg.type = omx_message::EVENT;
    412     msg.node = node;
    413     msg.u.event_data.event = eEvent;
    414     msg.u.event_data.data1 = nData1;
    415     msg.u.event_data.data2 = nData2;
    416 
    417     findDispatcher(node)->post(msg);
    418 
    419     return OMX_ErrorNone;
    420 }
    421 
    422 OMX_ERRORTYPE OMX::OnEmptyBufferDone(
    423         node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
    424     ALOGV("OnEmptyBufferDone buffer=%p", pBuffer);
    425 
    426     omx_message msg;
    427     msg.type = omx_message::EMPTY_BUFFER_DONE;
    428     msg.node = node;
    429     msg.u.buffer_data.buffer = pBuffer;
    430 
    431     findDispatcher(node)->post(msg);
    432 
    433     return OMX_ErrorNone;
    434 }
    435 
    436 OMX_ERRORTYPE OMX::OnFillBufferDone(
    437         node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
    438     ALOGV("OnFillBufferDone buffer=%p", pBuffer);
    439 
    440     omx_message msg;
    441     msg.type = omx_message::FILL_BUFFER_DONE;
    442     msg.node = node;
    443     msg.u.extended_buffer_data.buffer = pBuffer;
    444     msg.u.extended_buffer_data.range_offset = pBuffer->nOffset;
    445     msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen;
    446     msg.u.extended_buffer_data.flags = pBuffer->nFlags;
    447     msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp;
    448     msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate;
    449     msg.u.extended_buffer_data.data_ptr = pBuffer->pBuffer;
    450 
    451     findDispatcher(node)->post(msg);
    452 
    453     return OMX_ErrorNone;
    454 }
    455 
    456 OMX::node_id OMX::makeNodeID(OMXNodeInstance *instance) {
    457     // mLock is already held.
    458 
    459     node_id node = (node_id)++mNodeCounter;
    460     mNodeIDToInstance.add(node, instance);
    461 
    462     return node;
    463 }
    464 
    465 OMXNodeInstance *OMX::findInstance(node_id node) {
    466     Mutex::Autolock autoLock(mLock);
    467 
    468     ssize_t index = mNodeIDToInstance.indexOfKey(node);
    469 
    470     return index < 0 ? NULL : mNodeIDToInstance.valueAt(index);
    471 }
    472 
    473 sp<OMX::CallbackDispatcher> OMX::findDispatcher(node_id node) {
    474     Mutex::Autolock autoLock(mLock);
    475 
    476     ssize_t index = mDispatchers.indexOfKey(node);
    477 
    478     return index < 0 ? NULL : mDispatchers.valueAt(index);
    479 }
    480 
    481 void OMX::invalidateNodeID(node_id node) {
    482     Mutex::Autolock autoLock(mLock);
    483     invalidateNodeID_l(node);
    484 }
    485 
    486 void OMX::invalidateNodeID_l(node_id node) {
    487     // mLock is held.
    488     mNodeIDToInstance.removeItem(node);
    489 }
    490 
    491 }  // namespace android
    492