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