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 
SimpleSoftOMXComponent(const char * name,const OMX_CALLBACKTYPE * callbacks,OMX_PTR appData,OMX_COMPONENTTYPE ** component)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_VIDEO);
45 }
46 
prepareForDestruction()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 
sendCommand(OMX_COMMANDTYPE cmd,OMX_U32 param,OMX_PTR data)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 
isSetParameterAllowed(OMX_INDEXTYPE index,const OMX_PTR params) const68 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 
getParameter(OMX_INDEXTYPE index,OMX_PTR params)119 OMX_ERRORTYPE SimpleSoftOMXComponent::getParameter(
120         OMX_INDEXTYPE index, OMX_PTR params) {
121     Mutex::Autolock autoLock(mLock);
122     return internalGetParameter(index, params);
123 }
124 
setParameter(OMX_INDEXTYPE index,const OMX_PTR params)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 
internalGetParameter(OMX_INDEXTYPE index,OMX_PTR params)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 
internalSetParameter(OMX_INDEXTYPE index,const OMX_PTR params)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 
useBuffer(OMX_BUFFERHEADERTYPE ** header,OMX_U32 portIndex,OMX_PTR appPrivate,OMX_U32 size,OMX_U8 * ptr)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 
allocateBuffer(OMX_BUFFERHEADERTYPE ** header,OMX_U32 portIndex,OMX_PTR appPrivate,OMX_U32 size)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 
freeBuffer(OMX_U32 portIndex,OMX_BUFFERHEADERTYPE * header)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 
emptyThisBuffer(OMX_BUFFERHEADERTYPE * buffer)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 
fillThisBuffer(OMX_BUFFERHEADERTYPE * buffer)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 
getState(OMX_STATETYPE * state)353 OMX_ERRORTYPE SimpleSoftOMXComponent::getState(OMX_STATETYPE *state) {
354     Mutex::Autolock autoLock(mLock);
355 
356     *state = mState;
357 
358     return OMX_ErrorNone;
359 }
360 
onMessageReceived(const sp<AMessage> & msg)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 
onSendCommand(OMX_COMMANDTYPE cmd,OMX_U32 param)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 
onChangeState(OMX_STATETYPE state)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     if (mState != mTargetState) {
462         ALOGE("State change to state %d requested while still transitioning from state %d to %d",
463                 state, mState, mTargetState);
464         notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
465         return;
466     }
467 
468     switch (mState) {
469         case OMX_StateLoaded:
470             CHECK_EQ((int)state, (int)OMX_StateIdle);
471             break;
472         case OMX_StateIdle:
473             CHECK(state == OMX_StateLoaded || state == OMX_StateExecuting);
474             break;
475         case OMX_StateExecuting:
476         {
477             CHECK_EQ((int)state, (int)OMX_StateIdle);
478 
479             for (size_t i = 0; i < mPorts.size(); ++i) {
480                 onPortFlush(i, false /* sendFlushComplete */);
481             }
482 
483             mState = OMX_StateIdle;
484             notify(OMX_EventCmdComplete, OMX_CommandStateSet, state, NULL);
485             break;
486         }
487 
488         default:
489             TRESPASS();
490     }
491 
492     mTargetState = state;
493 
494     checkTransitions();
495 }
496 
onReset()497 void SimpleSoftOMXComponent::onReset() {
498     // no-op
499 }
500 
onPortEnable(OMX_U32 portIndex,bool enable)501 void SimpleSoftOMXComponent::onPortEnable(OMX_U32 portIndex, bool enable) {
502     CHECK_LT(portIndex, mPorts.size());
503 
504     PortInfo *port = &mPorts.editItemAt(portIndex);
505     CHECK_EQ((int)port->mTransition, (int)PortInfo::NONE);
506     CHECK(port->mDef.bEnabled == !enable);
507 
508     if (port->mDef.eDir != OMX_DirOutput) {
509         ALOGE("Port enable/disable allowed only on output ports.");
510         notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
511         android_errorWriteLog(0x534e4554, "29421804");
512         return;
513     }
514 
515     if (!enable) {
516         port->mDef.bEnabled = OMX_FALSE;
517         port->mTransition = PortInfo::DISABLING;
518 
519         for (size_t i = 0; i < port->mBuffers.size(); ++i) {
520             BufferInfo *buffer = &port->mBuffers.editItemAt(i);
521 
522             if (buffer->mOwnedByUs) {
523                 buffer->mOwnedByUs = false;
524 
525                 if (port->mDef.eDir == OMX_DirInput) {
526                     notifyEmptyBufferDone(buffer->mHeader);
527                 } else {
528                     CHECK_EQ(port->mDef.eDir, OMX_DirOutput);
529                     notifyFillBufferDone(buffer->mHeader);
530                 }
531             }
532         }
533 
534         port->mQueue.clear();
535     } else {
536         port->mTransition = PortInfo::ENABLING;
537     }
538 
539     checkTransitions();
540 }
541 
onPortFlush(OMX_U32 portIndex,bool sendFlushComplete)542 void SimpleSoftOMXComponent::onPortFlush(
543         OMX_U32 portIndex, bool sendFlushComplete) {
544     if (portIndex == OMX_ALL) {
545         for (size_t i = 0; i < mPorts.size(); ++i) {
546             onPortFlush(i, sendFlushComplete);
547         }
548 
549         if (sendFlushComplete) {
550             notify(OMX_EventCmdComplete, OMX_CommandFlush, OMX_ALL, NULL);
551         }
552 
553         return;
554     }
555 
556     CHECK_LT(portIndex, mPorts.size());
557 
558     PortInfo *port = &mPorts.editItemAt(portIndex);
559     // Ideally, the port should not in transitioning state when flushing.
560     // However, in error handling case, e.g., the client can't allocate buffers
561     // when it tries to re-enable the port, the port will be stuck in ENABLING.
562     // The client will then transition the component from Executing to Idle,
563     // which leads to flushing ports. At this time, it should be ok to notify
564     // the client of the error and still clear all buffers on the port.
565     if (port->mTransition != PortInfo::NONE) {
566         notify(OMX_EventError, OMX_ErrorUndefined, 0, 0);
567     }
568 
569     for (size_t i = 0; i < port->mBuffers.size(); ++i) {
570         BufferInfo *buffer = &port->mBuffers.editItemAt(i);
571 
572         if (!buffer->mOwnedByUs) {
573             continue;
574         }
575 
576         buffer->mHeader->nFilledLen = 0;
577         buffer->mHeader->nOffset = 0;
578         buffer->mHeader->nFlags = 0;
579 
580         buffer->mOwnedByUs = false;
581 
582         if (port->mDef.eDir == OMX_DirInput) {
583             notifyEmptyBufferDone(buffer->mHeader);
584         } else {
585             CHECK_EQ(port->mDef.eDir, OMX_DirOutput);
586 
587             notifyFillBufferDone(buffer->mHeader);
588         }
589     }
590 
591     port->mQueue.clear();
592 
593     if (sendFlushComplete) {
594         notify(OMX_EventCmdComplete, OMX_CommandFlush, portIndex, NULL);
595 
596         onPortFlushCompleted(portIndex);
597     }
598 }
599 
checkTransitions()600 void SimpleSoftOMXComponent::checkTransitions() {
601     if (mState != mTargetState) {
602         bool transitionComplete = true;
603 
604         if (mState == OMX_StateLoaded) {
605             CHECK_EQ((int)mTargetState, (int)OMX_StateIdle);
606 
607             for (size_t i = 0; i < mPorts.size(); ++i) {
608                 const PortInfo &port = mPorts.itemAt(i);
609                 if (port.mDef.bEnabled == OMX_FALSE) {
610                     continue;
611                 }
612 
613                 if (port.mDef.bPopulated == OMX_FALSE) {
614                     transitionComplete = false;
615                     break;
616                 }
617             }
618         } else if (mTargetState == OMX_StateLoaded) {
619             CHECK_EQ((int)mState, (int)OMX_StateIdle);
620 
621             for (size_t i = 0; i < mPorts.size(); ++i) {
622                 const PortInfo &port = mPorts.itemAt(i);
623                 if (port.mDef.bEnabled == OMX_FALSE) {
624                     continue;
625                 }
626 
627                 size_t n = port.mBuffers.size();
628 
629                 if (n > 0) {
630                     CHECK_LE(n, port.mDef.nBufferCountActual);
631 
632                     if (n == port.mDef.nBufferCountActual) {
633                         CHECK_EQ((int)port.mDef.bPopulated, (int)OMX_TRUE);
634                     } else {
635                         CHECK_EQ((int)port.mDef.bPopulated, (int)OMX_FALSE);
636                     }
637 
638                     transitionComplete = false;
639                     break;
640                 }
641             }
642         }
643 
644         if (transitionComplete) {
645             ALOGV("state transition from %d to %d complete", mState, mTargetState);
646             mState = mTargetState;
647 
648             if (mState == OMX_StateLoaded) {
649                 onReset();
650             }
651 
652             notify(OMX_EventCmdComplete, OMX_CommandStateSet, mState, NULL);
653         } else {
654             ALOGV("state transition from %d to %d not yet complete", mState, mTargetState);
655         }
656     }
657 
658     for (size_t i = 0; i < mPorts.size(); ++i) {
659         PortInfo *port = &mPorts.editItemAt(i);
660 
661         if (port->mTransition == PortInfo::DISABLING) {
662             if (port->mBuffers.empty()) {
663                 ALOGV("Port %zu now disabled.", i);
664 
665                 port->mTransition = PortInfo::NONE;
666                 notify(OMX_EventCmdComplete, OMX_CommandPortDisable, i, NULL);
667 
668                 onPortEnableCompleted(i, false /* enabled */);
669             }
670         } else if (port->mTransition == PortInfo::ENABLING) {
671             if (port->mDef.bPopulated == OMX_TRUE) {
672                 ALOGV("Port %zu now enabled.", i);
673 
674                 port->mTransition = PortInfo::NONE;
675                 port->mDef.bEnabled = OMX_TRUE;
676                 notify(OMX_EventCmdComplete, OMX_CommandPortEnable, i, NULL);
677 
678                 onPortEnableCompleted(i, true /* enabled */);
679             }
680         }
681     }
682 }
683 
addPort(const OMX_PARAM_PORTDEFINITIONTYPE & def)684 void SimpleSoftOMXComponent::addPort(const OMX_PARAM_PORTDEFINITIONTYPE &def) {
685     CHECK_EQ(def.nPortIndex, mPorts.size());
686 
687     mPorts.push();
688     PortInfo *info = &mPorts.editItemAt(mPorts.size() - 1);
689     info->mDef = def;
690     info->mTransition = PortInfo::NONE;
691 }
692 
onQueueFilled(OMX_U32 portIndex __unused)693 void SimpleSoftOMXComponent::onQueueFilled(OMX_U32 portIndex __unused) {
694 }
695 
onPortFlushCompleted(OMX_U32 portIndex __unused)696 void SimpleSoftOMXComponent::onPortFlushCompleted(OMX_U32 portIndex __unused) {
697 }
698 
onPortEnableCompleted(OMX_U32 portIndex __unused,bool enabled __unused)699 void SimpleSoftOMXComponent::onPortEnableCompleted(
700         OMX_U32 portIndex __unused, bool enabled __unused) {
701 }
702 
703 List<SimpleSoftOMXComponent::BufferInfo *> &
getPortQueue(OMX_U32 portIndex)704 SimpleSoftOMXComponent::getPortQueue(OMX_U32 portIndex) {
705     CHECK_LT(portIndex, mPorts.size());
706     return mPorts.editItemAt(portIndex).mQueue;
707 }
708 
editPortInfo(OMX_U32 portIndex)709 SimpleSoftOMXComponent::PortInfo *SimpleSoftOMXComponent::editPortInfo(
710         OMX_U32 portIndex) {
711     CHECK_LT(portIndex, mPorts.size());
712     return &mPorts.editItemAt(portIndex);
713 }
714 
715 }  // namespace android
716