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::onPortEnable(OMX_U32 portIndex, bool enable) {
    454     CHECK_LT(portIndex, mPorts.size());
    455 
    456     PortInfo *port = &mPorts.editItemAt(portIndex);
    457     CHECK_EQ((int)port->mTransition, (int)PortInfo::NONE);
    458     CHECK(port->mDef.bEnabled == !enable);
    459 
    460     if (!enable) {
    461         port->mDef.bEnabled = OMX_FALSE;
    462         port->mTransition = PortInfo::DISABLING;
    463 
    464         for (size_t i = 0; i < port->mBuffers.size(); ++i) {
    465             BufferInfo *buffer = &port->mBuffers.editItemAt(i);
    466 
    467             if (buffer->mOwnedByUs) {
    468                 buffer->mOwnedByUs = false;
    469 
    470                 if (port->mDef.eDir == OMX_DirInput) {
    471                     notifyEmptyBufferDone(buffer->mHeader);
    472                 } else {
    473                     CHECK_EQ(port->mDef.eDir, OMX_DirOutput);
    474                     notifyFillBufferDone(buffer->mHeader);
    475                 }
    476             }
    477         }
    478 
    479         port->mQueue.clear();
    480     } else {
    481         port->mTransition = PortInfo::ENABLING;
    482     }
    483 
    484     checkTransitions();
    485 }
    486 
    487 void SimpleSoftOMXComponent::onPortFlush(
    488         OMX_U32 portIndex, bool sendFlushComplete) {
    489     if (portIndex == OMX_ALL) {
    490         for (size_t i = 0; i < mPorts.size(); ++i) {
    491             onPortFlush(i, sendFlushComplete);
    492         }
    493 
    494         if (sendFlushComplete) {
    495             notify(OMX_EventCmdComplete, OMX_CommandFlush, OMX_ALL, NULL);
    496         }
    497 
    498         return;
    499     }
    500 
    501     CHECK_LT(portIndex, mPorts.size());
    502 
    503     PortInfo *port = &mPorts.editItemAt(portIndex);
    504     CHECK_EQ((int)port->mTransition, (int)PortInfo::NONE);
    505 
    506     for (size_t i = 0; i < port->mBuffers.size(); ++i) {
    507         BufferInfo *buffer = &port->mBuffers.editItemAt(i);
    508 
    509         if (!buffer->mOwnedByUs) {
    510             continue;
    511         }
    512 
    513         buffer->mHeader->nFilledLen = 0;
    514         buffer->mHeader->nOffset = 0;
    515         buffer->mHeader->nFlags = 0;
    516 
    517         buffer->mOwnedByUs = false;
    518 
    519         if (port->mDef.eDir == OMX_DirInput) {
    520             notifyEmptyBufferDone(buffer->mHeader);
    521         } else {
    522             CHECK_EQ(port->mDef.eDir, OMX_DirOutput);
    523 
    524             notifyFillBufferDone(buffer->mHeader);
    525         }
    526     }
    527 
    528     port->mQueue.clear();
    529 
    530     if (sendFlushComplete) {
    531         notify(OMX_EventCmdComplete, OMX_CommandFlush, portIndex, NULL);
    532 
    533         onPortFlushCompleted(portIndex);
    534     }
    535 }
    536 
    537 void SimpleSoftOMXComponent::checkTransitions() {
    538     if (mState != mTargetState) {
    539         bool transitionComplete = true;
    540 
    541         if (mState == OMX_StateLoaded) {
    542             CHECK_EQ((int)mTargetState, (int)OMX_StateIdle);
    543 
    544             for (size_t i = 0; i < mPorts.size(); ++i) {
    545                 const PortInfo &port = mPorts.itemAt(i);
    546                 if (port.mDef.bEnabled == OMX_FALSE) {
    547                     continue;
    548                 }
    549 
    550                 if (port.mDef.bPopulated == OMX_FALSE) {
    551                     transitionComplete = false;
    552                     break;
    553                 }
    554             }
    555         } else if (mTargetState == OMX_StateLoaded) {
    556             CHECK_EQ((int)mState, (int)OMX_StateIdle);
    557 
    558             for (size_t i = 0; i < mPorts.size(); ++i) {
    559                 const PortInfo &port = mPorts.itemAt(i);
    560                 if (port.mDef.bEnabled == OMX_FALSE) {
    561                     continue;
    562                 }
    563 
    564                 size_t n = port.mBuffers.size();
    565 
    566                 if (n > 0) {
    567                     CHECK_LE(n, port.mDef.nBufferCountActual);
    568 
    569                     if (n == port.mDef.nBufferCountActual) {
    570                         CHECK_EQ((int)port.mDef.bPopulated, (int)OMX_TRUE);
    571                     } else {
    572                         CHECK_EQ((int)port.mDef.bPopulated, (int)OMX_FALSE);
    573                     }
    574 
    575                     transitionComplete = false;
    576                     break;
    577                 }
    578             }
    579         }
    580 
    581         if (transitionComplete) {
    582             mState = mTargetState;
    583 
    584             notify(OMX_EventCmdComplete, OMX_CommandStateSet, mState, NULL);
    585         }
    586     }
    587 
    588     for (size_t i = 0; i < mPorts.size(); ++i) {
    589         PortInfo *port = &mPorts.editItemAt(i);
    590 
    591         if (port->mTransition == PortInfo::DISABLING) {
    592             if (port->mBuffers.empty()) {
    593                 ALOGV("Port %d now disabled.", i);
    594 
    595                 port->mTransition = PortInfo::NONE;
    596                 notify(OMX_EventCmdComplete, OMX_CommandPortDisable, i, NULL);
    597 
    598                 onPortEnableCompleted(i, false /* enabled */);
    599             }
    600         } else if (port->mTransition == PortInfo::ENABLING) {
    601             if (port->mDef.bPopulated == OMX_TRUE) {
    602                 ALOGV("Port %d now enabled.", i);
    603 
    604                 port->mTransition = PortInfo::NONE;
    605                 port->mDef.bEnabled = OMX_TRUE;
    606                 notify(OMX_EventCmdComplete, OMX_CommandPortEnable, i, NULL);
    607 
    608                 onPortEnableCompleted(i, true /* enabled */);
    609             }
    610         }
    611     }
    612 }
    613 
    614 void SimpleSoftOMXComponent::addPort(const OMX_PARAM_PORTDEFINITIONTYPE &def) {
    615     CHECK_EQ(def.nPortIndex, mPorts.size());
    616 
    617     mPorts.push();
    618     PortInfo *info = &mPorts.editItemAt(mPorts.size() - 1);
    619     info->mDef = def;
    620     info->mTransition = PortInfo::NONE;
    621 }
    622 
    623 void SimpleSoftOMXComponent::onQueueFilled(OMX_U32 portIndex) {
    624 }
    625 
    626 void SimpleSoftOMXComponent::onPortFlushCompleted(OMX_U32 portIndex) {
    627 }
    628 
    629 void SimpleSoftOMXComponent::onPortEnableCompleted(
    630         OMX_U32 portIndex, bool enabled) {
    631 }
    632 
    633 List<SimpleSoftOMXComponent::BufferInfo *> &
    634 SimpleSoftOMXComponent::getPortQueue(OMX_U32 portIndex) {
    635     CHECK_LT(portIndex, mPorts.size());
    636     return mPorts.editItemAt(portIndex).mQueue;
    637 }
    638 
    639 SimpleSoftOMXComponent::PortInfo *SimpleSoftOMXComponent::editPortInfo(
    640         OMX_U32 portIndex) {
    641     CHECK_LT(portIndex, mPorts.size());
    642     return &mPorts.editItemAt(portIndex);
    643 }
    644 
    645 }  // namespace android
    646