Home | History | Annotate | Download | only in omx
      1 /*
      2  * Copyright (C) 2011 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 "SimpleSoftOMXComponent"
     19 #include <utils/Log.h>
     20 
     21 #include "include/SimpleSoftOMXComponent.h"
     22 
     23 #include <media/stagefright/foundation/ADebug.h>
     24 #include <media/stagefright/foundation/ALooper.h>
     25 #include <media/stagefright/foundation/AMessage.h>
     26 
     27 namespace android {
     28 
     29 SimpleSoftOMXComponent::SimpleSoftOMXComponent(
     30         const char *name,
     31         const OMX_CALLBACKTYPE *callbacks,
     32         OMX_PTR appData,
     33         OMX_COMPONENTTYPE **component)
     34     : SoftOMXComponent(name, callbacks, appData, component),
     35       mLooper(new ALooper),
     36       mHandler(new AHandlerReflector<SimpleSoftOMXComponent>(this)),
     37       mState(OMX_StateLoaded),
     38       mTargetState(OMX_StateLoaded) {
     39     mLooper->setName(name);
     40     mLooper->registerHandler(mHandler);
     41 
     42     mLooper->start(
     43             false, // runOnCallingThread
     44             false, // canCallJava
     45             ANDROID_PRIORITY_FOREGROUND);
     46 }
     47 
     48 void SimpleSoftOMXComponent::prepareForDestruction() {
     49     // The looper's queue may still contain messages referencing this
     50     // object. Make sure those are flushed before returning so that
     51     // a subsequent dlunload() does not pull out the rug from under us.
     52 
     53     mLooper->unregisterHandler(mHandler->id());
     54     mLooper->stop();
     55 }
     56 
     57 OMX_ERRORTYPE SimpleSoftOMXComponent::sendCommand(
     58         OMX_COMMANDTYPE cmd, OMX_U32 param, OMX_PTR data) {
     59     CHECK(data == NULL);
     60 
     61     sp<AMessage> msg = new AMessage(kWhatSendCommand, mHandler->id());
     62     msg->setInt32("cmd", cmd);
     63     msg->setInt32("param", param);
     64     msg->post();
     65 
     66     return OMX_ErrorNone;
     67 }
     68 
     69 bool SimpleSoftOMXComponent::isSetParameterAllowed(
     70         OMX_INDEXTYPE index, const OMX_PTR params) const {
     71     if (mState == OMX_StateLoaded) {
     72         return true;
     73     }
     74 
     75     OMX_U32 portIndex;
     76 
     77     switch (index) {
     78         case OMX_IndexParamPortDefinition:
     79         {
     80             portIndex = ((OMX_PARAM_PORTDEFINITIONTYPE *)params)->nPortIndex;
     81             break;
     82         }
     83 
     84         case OMX_IndexParamAudioPcm:
     85         {
     86             portIndex = ((OMX_AUDIO_PARAM_PCMMODETYPE *)params)->nPortIndex;
     87             break;
     88         }
     89 
     90         case OMX_IndexParamAudioAac:
     91         {
     92             portIndex = ((OMX_AUDIO_PARAM_AACPROFILETYPE *)params)->nPortIndex;
     93             break;
     94         }
     95 
     96         default:
     97             return false;
     98     }
     99 
    100     CHECK(portIndex < mPorts.size());
    101 
    102     return !mPorts.itemAt(portIndex).mDef.bEnabled;
    103 }
    104 
    105 OMX_ERRORTYPE SimpleSoftOMXComponent::getParameter(
    106         OMX_INDEXTYPE index, OMX_PTR params) {
    107     Mutex::Autolock autoLock(mLock);
    108     return internalGetParameter(index, params);
    109 }
    110 
    111 OMX_ERRORTYPE SimpleSoftOMXComponent::setParameter(
    112         OMX_INDEXTYPE index, const OMX_PTR params) {
    113     Mutex::Autolock autoLock(mLock);
    114 
    115     CHECK(isSetParameterAllowed(index, params));
    116 
    117     return internalSetParameter(index, params);
    118 }
    119 
    120 OMX_ERRORTYPE SimpleSoftOMXComponent::internalGetParameter(
    121         OMX_INDEXTYPE index, OMX_PTR params) {
    122     switch (index) {
    123         case OMX_IndexParamPortDefinition:
    124         {
    125             OMX_PARAM_PORTDEFINITIONTYPE *defParams =
    126                 (OMX_PARAM_PORTDEFINITIONTYPE *)params;
    127 
    128             if (defParams->nPortIndex >= mPorts.size()
    129                     || defParams->nSize
    130                             != sizeof(OMX_PARAM_PORTDEFINITIONTYPE)) {
    131                 return OMX_ErrorUndefined;
    132             }
    133 
    134             const PortInfo *port =
    135                 &mPorts.itemAt(defParams->nPortIndex);
    136 
    137             memcpy(defParams, &port->mDef, sizeof(port->mDef));
    138 
    139             return OMX_ErrorNone;
    140         }
    141 
    142         default:
    143             return OMX_ErrorUnsupportedIndex;
    144     }
    145 }
    146 
    147 OMX_ERRORTYPE SimpleSoftOMXComponent::internalSetParameter(
    148         OMX_INDEXTYPE index, const OMX_PTR params) {
    149     switch (index) {
    150         case OMX_IndexParamPortDefinition:
    151         {
    152             OMX_PARAM_PORTDEFINITIONTYPE *defParams =
    153                 (OMX_PARAM_PORTDEFINITIONTYPE *)params;
    154 
    155             if (defParams->nPortIndex >= mPorts.size()
    156                     || defParams->nSize
    157                             != sizeof(OMX_PARAM_PORTDEFINITIONTYPE)) {
    158                 return OMX_ErrorUndefined;
    159             }
    160 
    161             PortInfo *port =
    162                 &mPorts.editItemAt(defParams->nPortIndex);
    163 
    164             if (defParams->nBufferSize != port->mDef.nBufferSize) {
    165                 CHECK_GE(defParams->nBufferSize, port->mDef.nBufferSize);
    166                 port->mDef.nBufferSize = defParams->nBufferSize;
    167             }
    168 
    169             if (defParams->nBufferCountActual
    170                     != port->mDef.nBufferCountActual) {
    171                 CHECK_GE(defParams->nBufferCountActual,
    172                          port->mDef.nBufferCountMin);
    173 
    174                 port->mDef.nBufferCountActual = defParams->nBufferCountActual;
    175             }
    176 
    177             return OMX_ErrorNone;
    178         }
    179 
    180         default:
    181             return OMX_ErrorUnsupportedIndex;
    182     }
    183 }
    184 
    185 OMX_ERRORTYPE SimpleSoftOMXComponent::useBuffer(
    186         OMX_BUFFERHEADERTYPE **header,
    187         OMX_U32 portIndex,
    188         OMX_PTR appPrivate,
    189         OMX_U32 size,
    190         OMX_U8 *ptr) {
    191     Mutex::Autolock autoLock(mLock);
    192     CHECK_LT(portIndex, mPorts.size());
    193 
    194     *header = new OMX_BUFFERHEADERTYPE;
    195     (*header)->nSize = sizeof(OMX_BUFFERHEADERTYPE);
    196     (*header)->nVersion.s.nVersionMajor = 1;
    197     (*header)->nVersion.s.nVersionMinor = 0;
    198     (*header)->nVersion.s.nRevision = 0;
    199     (*header)->nVersion.s.nStep = 0;
    200     (*header)->pBuffer = ptr;
    201     (*header)->nAllocLen = size;
    202     (*header)->nFilledLen = 0;
    203     (*header)->nOffset = 0;
    204     (*header)->pAppPrivate = appPrivate;
    205     (*header)->pPlatformPrivate = NULL;
    206     (*header)->pInputPortPrivate = NULL;
    207     (*header)->pOutputPortPrivate = NULL;
    208     (*header)->hMarkTargetComponent = NULL;
    209     (*header)->pMarkData = NULL;
    210     (*header)->nTickCount = 0;
    211     (*header)->nTimeStamp = 0;
    212     (*header)->nFlags = 0;
    213     (*header)->nOutputPortIndex = portIndex;
    214     (*header)->nInputPortIndex = portIndex;
    215 
    216     PortInfo *port = &mPorts.editItemAt(portIndex);
    217 
    218     CHECK(mState == OMX_StateLoaded || port->mDef.bEnabled == OMX_FALSE);
    219 
    220     CHECK_LT(port->mBuffers.size(), port->mDef.nBufferCountActual);
    221 
    222     port->mBuffers.push();
    223 
    224     BufferInfo *buffer =
    225         &port->mBuffers.editItemAt(port->mBuffers.size() - 1);
    226 
    227     buffer->mHeader = *header;
    228     buffer->mOwnedByUs = false;
    229 
    230     if (port->mBuffers.size() == port->mDef.nBufferCountActual) {
    231         port->mDef.bPopulated = OMX_TRUE;
    232         checkTransitions();
    233     }
    234 
    235     return OMX_ErrorNone;
    236 }
    237 
    238 OMX_ERRORTYPE SimpleSoftOMXComponent::allocateBuffer(
    239         OMX_BUFFERHEADERTYPE **header,
    240         OMX_U32 portIndex,
    241         OMX_PTR appPrivate,
    242         OMX_U32 size) {
    243     OMX_U8 *ptr = new OMX_U8[size];
    244 
    245     OMX_ERRORTYPE err =
    246         useBuffer(header, portIndex, appPrivate, size, ptr);
    247 
    248     if (err != OMX_ErrorNone) {
    249         delete[] ptr;
    250         ptr = NULL;
    251 
    252         return err;
    253     }
    254 
    255     CHECK((*header)->pPlatformPrivate == NULL);
    256     (*header)->pPlatformPrivate = ptr;
    257 
    258     return OMX_ErrorNone;
    259 }
    260 
    261 OMX_ERRORTYPE SimpleSoftOMXComponent::freeBuffer(
    262         OMX_U32 portIndex,
    263         OMX_BUFFERHEADERTYPE *header) {
    264     Mutex::Autolock autoLock(mLock);
    265 
    266     CHECK_LT(portIndex, mPorts.size());
    267 
    268     PortInfo *port = &mPorts.editItemAt(portIndex);
    269 
    270 #if 0 // XXX
    271     CHECK((mState == OMX_StateIdle && mTargetState == OMX_StateLoaded)
    272             || port->mDef.bEnabled == OMX_FALSE);
    273 #endif
    274 
    275     bool found = false;
    276     for (size_t i = 0; i < port->mBuffers.size(); ++i) {
    277         BufferInfo *buffer = &port->mBuffers.editItemAt(i);
    278 
    279         if (buffer->mHeader == header) {
    280             CHECK(!buffer->mOwnedByUs);
    281 
    282             if (header->pPlatformPrivate != NULL) {
    283                 // This buffer's data was allocated by us.
    284                 CHECK(header->pPlatformPrivate == header->pBuffer);
    285 
    286                 delete[] header->pBuffer;
    287                 header->pBuffer = NULL;
    288             }
    289 
    290             delete header;
    291             header = NULL;
    292 
    293             port->mBuffers.removeAt(i);
    294             port->mDef.bPopulated = OMX_FALSE;
    295 
    296             checkTransitions();
    297 
    298             found = true;
    299             break;
    300         }
    301     }
    302 
    303     CHECK(found);
    304 
    305     return OMX_ErrorNone;
    306 }
    307 
    308 OMX_ERRORTYPE SimpleSoftOMXComponent::emptyThisBuffer(
    309         OMX_BUFFERHEADERTYPE *buffer) {
    310     sp<AMessage> msg = new AMessage(kWhatEmptyThisBuffer, mHandler->id());
    311     msg->setPointer("header", buffer);
    312     msg->post();
    313 
    314     return OMX_ErrorNone;
    315 }
    316 
    317 OMX_ERRORTYPE SimpleSoftOMXComponent::fillThisBuffer(
    318         OMX_BUFFERHEADERTYPE *buffer) {
    319     sp<AMessage> msg = new AMessage(kWhatFillThisBuffer, mHandler->id());
    320     msg->setPointer("header", buffer);
    321     msg->post();
    322 
    323     return OMX_ErrorNone;
    324 }
    325 
    326 OMX_ERRORTYPE SimpleSoftOMXComponent::getState(OMX_STATETYPE *state) {
    327     Mutex::Autolock autoLock(mLock);
    328 
    329     *state = mState;
    330 
    331     return OMX_ErrorNone;
    332 }
    333 
    334 void SimpleSoftOMXComponent::onMessageReceived(const sp<AMessage> &msg) {
    335     Mutex::Autolock autoLock(mLock);
    336     uint32_t msgType = msg->what();
    337     ALOGV("msgType = %d", msgType);
    338     switch (msgType) {
    339         case kWhatSendCommand:
    340         {
    341             int32_t cmd, param;
    342             CHECK(msg->findInt32("cmd", &cmd));
    343             CHECK(msg->findInt32("param", &param));
    344 
    345             onSendCommand((OMX_COMMANDTYPE)cmd, (OMX_U32)param);
    346             break;
    347         }
    348 
    349         case kWhatEmptyThisBuffer:
    350         case kWhatFillThisBuffer:
    351         {
    352             OMX_BUFFERHEADERTYPE *header;
    353             CHECK(msg->findPointer("header", (void **)&header));
    354 
    355             CHECK(mState == OMX_StateExecuting && mTargetState == mState);
    356 
    357             bool found = false;
    358             size_t portIndex = (kWhatEmptyThisBuffer == msgType)?
    359                     header->nInputPortIndex: header->nOutputPortIndex;
    360             PortInfo *port = &mPorts.editItemAt(portIndex);
    361 
    362             for (size_t j = 0; j < port->mBuffers.size(); ++j) {
    363                 BufferInfo *buffer = &port->mBuffers.editItemAt(j);
    364 
    365                 if (buffer->mHeader == header) {
    366                     CHECK(!buffer->mOwnedByUs);
    367 
    368                     buffer->mOwnedByUs = true;
    369 
    370                     CHECK((msgType == kWhatEmptyThisBuffer
    371                             && port->mDef.eDir == OMX_DirInput)
    372                             || (port->mDef.eDir == OMX_DirOutput));
    373 
    374                     port->mQueue.push_back(buffer);
    375                     onQueueFilled(portIndex);
    376 
    377                     found = true;
    378                     break;
    379                 }
    380             }
    381 
    382             CHECK(found);
    383             break;
    384         }
    385 
    386         default:
    387             TRESPASS();
    388             break;
    389     }
    390 }
    391 
    392 void SimpleSoftOMXComponent::onSendCommand(
    393         OMX_COMMANDTYPE cmd, OMX_U32 param) {
    394     switch (cmd) {
    395         case OMX_CommandStateSet:
    396         {
    397             onChangeState((OMX_STATETYPE)param);
    398             break;
    399         }
    400 
    401         case OMX_CommandPortEnable:
    402         case OMX_CommandPortDisable:
    403         {
    404             onPortEnable(param, cmd == OMX_CommandPortEnable);
    405             break;
    406         }
    407 
    408         case OMX_CommandFlush:
    409         {
    410             onPortFlush(param, true /* sendFlushComplete */);
    411             break;
    412         }
    413 
    414         default:
    415             TRESPASS();
    416             break;
    417     }
    418 }
    419 
    420 void SimpleSoftOMXComponent::onChangeState(OMX_STATETYPE state) {
    421     // We shouldn't be in a state transition already.
    422     CHECK_EQ((int)mState, (int)mTargetState);
    423 
    424     switch (mState) {
    425         case OMX_StateLoaded:
    426             CHECK_EQ((int)state, (int)OMX_StateIdle);
    427             break;
    428         case OMX_StateIdle:
    429             CHECK(state == OMX_StateLoaded || state == OMX_StateExecuting);
    430             break;
    431         case OMX_StateExecuting:
    432         {
    433             CHECK_EQ((int)state, (int)OMX_StateIdle);
    434 
    435             for (size_t i = 0; i < mPorts.size(); ++i) {
    436                 onPortFlush(i, false /* sendFlushComplete */);
    437             }
    438 
    439             mState = OMX_StateIdle;
    440             notify(OMX_EventCmdComplete, OMX_CommandStateSet, state, NULL);
    441             break;
    442         }
    443 
    444         default:
    445             TRESPASS();
    446     }
    447 
    448     mTargetState = state;
    449 
    450     checkTransitions();
    451 }
    452 
    453 void SimpleSoftOMXComponent::onReset() {
    454     // no-op
    455 }
    456 
    457 void SimpleSoftOMXComponent::onPortEnable(OMX_U32 portIndex, bool enable) {
    458     CHECK_LT(portIndex, mPorts.size());
    459 
    460     PortInfo *port = &mPorts.editItemAt(portIndex);
    461     CHECK_EQ((int)port->mTransition, (int)PortInfo::NONE);
    462     CHECK(port->mDef.bEnabled == !enable);
    463 
    464     if (!enable) {
    465         port->mDef.bEnabled = OMX_FALSE;
    466         port->mTransition = PortInfo::DISABLING;
    467 
    468         for (size_t i = 0; i < port->mBuffers.size(); ++i) {
    469             BufferInfo *buffer = &port->mBuffers.editItemAt(i);
    470 
    471             if (buffer->mOwnedByUs) {
    472                 buffer->mOwnedByUs = false;
    473 
    474                 if (port->mDef.eDir == OMX_DirInput) {
    475                     notifyEmptyBufferDone(buffer->mHeader);
    476                 } else {
    477                     CHECK_EQ(port->mDef.eDir, OMX_DirOutput);
    478                     notifyFillBufferDone(buffer->mHeader);
    479                 }
    480             }
    481         }
    482 
    483         port->mQueue.clear();
    484     } else {
    485         port->mTransition = PortInfo::ENABLING;
    486     }
    487 
    488     checkTransitions();
    489 }
    490 
    491 void SimpleSoftOMXComponent::onPortFlush(
    492         OMX_U32 portIndex, bool sendFlushComplete) {
    493     if (portIndex == OMX_ALL) {
    494         for (size_t i = 0; i < mPorts.size(); ++i) {
    495             onPortFlush(i, sendFlushComplete);
    496         }
    497 
    498         if (sendFlushComplete) {
    499             notify(OMX_EventCmdComplete, OMX_CommandFlush, OMX_ALL, NULL);
    500         }
    501 
    502         return;
    503     }
    504 
    505     CHECK_LT(portIndex, mPorts.size());
    506 
    507     PortInfo *port = &mPorts.editItemAt(portIndex);
    508     CHECK_EQ((int)port->mTransition, (int)PortInfo::NONE);
    509 
    510     for (size_t i = 0; i < port->mBuffers.size(); ++i) {
    511         BufferInfo *buffer = &port->mBuffers.editItemAt(i);
    512 
    513         if (!buffer->mOwnedByUs) {
    514             continue;
    515         }
    516 
    517         buffer->mHeader->nFilledLen = 0;
    518         buffer->mHeader->nOffset = 0;
    519         buffer->mHeader->nFlags = 0;
    520 
    521         buffer->mOwnedByUs = false;
    522 
    523         if (port->mDef.eDir == OMX_DirInput) {
    524             notifyEmptyBufferDone(buffer->mHeader);
    525         } else {
    526             CHECK_EQ(port->mDef.eDir, OMX_DirOutput);
    527 
    528             notifyFillBufferDone(buffer->mHeader);
    529         }
    530     }
    531 
    532     port->mQueue.clear();
    533 
    534     if (sendFlushComplete) {
    535         notify(OMX_EventCmdComplete, OMX_CommandFlush, portIndex, NULL);
    536 
    537         onPortFlushCompleted(portIndex);
    538     }
    539 }
    540 
    541 void SimpleSoftOMXComponent::checkTransitions() {
    542     if (mState != mTargetState) {
    543         bool transitionComplete = true;
    544 
    545         if (mState == OMX_StateLoaded) {
    546             CHECK_EQ((int)mTargetState, (int)OMX_StateIdle);
    547 
    548             for (size_t i = 0; i < mPorts.size(); ++i) {
    549                 const PortInfo &port = mPorts.itemAt(i);
    550                 if (port.mDef.bEnabled == OMX_FALSE) {
    551                     continue;
    552                 }
    553 
    554                 if (port.mDef.bPopulated == OMX_FALSE) {
    555                     transitionComplete = false;
    556                     break;
    557                 }
    558             }
    559         } else if (mTargetState == OMX_StateLoaded) {
    560             CHECK_EQ((int)mState, (int)OMX_StateIdle);
    561 
    562             for (size_t i = 0; i < mPorts.size(); ++i) {
    563                 const PortInfo &port = mPorts.itemAt(i);
    564                 if (port.mDef.bEnabled == OMX_FALSE) {
    565                     continue;
    566                 }
    567 
    568                 size_t n = port.mBuffers.size();
    569 
    570                 if (n > 0) {
    571                     CHECK_LE(n, port.mDef.nBufferCountActual);
    572 
    573                     if (n == port.mDef.nBufferCountActual) {
    574                         CHECK_EQ((int)port.mDef.bPopulated, (int)OMX_TRUE);
    575                     } else {
    576                         CHECK_EQ((int)port.mDef.bPopulated, (int)OMX_FALSE);
    577                     }
    578 
    579                     transitionComplete = false;
    580                     break;
    581                 }
    582             }
    583         }
    584 
    585         if (transitionComplete) {
    586             mState = mTargetState;
    587 
    588             if (mState == OMX_StateLoaded) {
    589                 onReset();
    590             }
    591 
    592             notify(OMX_EventCmdComplete, OMX_CommandStateSet, mState, NULL);
    593         }
    594     }
    595 
    596     for (size_t i = 0; i < mPorts.size(); ++i) {
    597         PortInfo *port = &mPorts.editItemAt(i);
    598 
    599         if (port->mTransition == PortInfo::DISABLING) {
    600             if (port->mBuffers.empty()) {
    601                 ALOGV("Port %d now disabled.", i);
    602 
    603                 port->mTransition = PortInfo::NONE;
    604                 notify(OMX_EventCmdComplete, OMX_CommandPortDisable, i, NULL);
    605 
    606                 onPortEnableCompleted(i, false /* enabled */);
    607             }
    608         } else if (port->mTransition == PortInfo::ENABLING) {
    609             if (port->mDef.bPopulated == OMX_TRUE) {
    610                 ALOGV("Port %d now enabled.", i);
    611 
    612                 port->mTransition = PortInfo::NONE;
    613                 port->mDef.bEnabled = OMX_TRUE;
    614                 notify(OMX_EventCmdComplete, OMX_CommandPortEnable, i, NULL);
    615 
    616                 onPortEnableCompleted(i, true /* enabled */);
    617             }
    618         }
    619     }
    620 }
    621 
    622 void SimpleSoftOMXComponent::addPort(const OMX_PARAM_PORTDEFINITIONTYPE &def) {
    623     CHECK_EQ(def.nPortIndex, mPorts.size());
    624 
    625     mPorts.push();
    626     PortInfo *info = &mPorts.editItemAt(mPorts.size() - 1);
    627     info->mDef = def;
    628     info->mTransition = PortInfo::NONE;
    629 }
    630 
    631 void SimpleSoftOMXComponent::onQueueFilled(OMX_U32 portIndex) {
    632 }
    633 
    634 void SimpleSoftOMXComponent::onPortFlushCompleted(OMX_U32 portIndex) {
    635 }
    636 
    637 void SimpleSoftOMXComponent::onPortEnableCompleted(
    638         OMX_U32 portIndex, bool enabled) {
    639 }
    640 
    641 List<SimpleSoftOMXComponent::BufferInfo *> &
    642 SimpleSoftOMXComponent::getPortQueue(OMX_U32 portIndex) {
    643     CHECK_LT(portIndex, mPorts.size());
    644     return mPorts.editItemAt(portIndex).mQueue;
    645 }
    646 
    647 SimpleSoftOMXComponent::PortInfo *SimpleSoftOMXComponent::editPortInfo(
    648         OMX_U32 portIndex) {
    649     CHECK_LT(portIndex, mPorts.size());
    650     return &mPorts.editItemAt(portIndex);
    651 }
    652 
    653 }  // namespace android
    654