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