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       mFrameConfig(false) {
39     mLooper->setName(name);
40     mLooper->registerHandler(mHandler);
41 
42     mLooper->start(
43             false, // runOnCallingThread
44             false, // canCallJava
45             ANDROID_PRIORITY_VIDEO);
46 }
47 
prepareForDestruction()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 
sendCommand(OMX_COMMANDTYPE cmd,OMX_U32 param,OMX_PTR data)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 
isSetParameterAllowed(OMX_INDEXTYPE index,const OMX_PTR params) const69 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 
getParameter(OMX_INDEXTYPE index,OMX_PTR params)120 OMX_ERRORTYPE SimpleSoftOMXComponent::getParameter(
121         OMX_INDEXTYPE index, OMX_PTR params) {
122     Mutex::Autolock autoLock(mLock);
123     return internalGetParameter(index, params);
124 }
125 
setParameter(OMX_INDEXTYPE index,const OMX_PTR params)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 
internalGetParameter(OMX_INDEXTYPE index,OMX_PTR params)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 
internalSetParameter(OMX_INDEXTYPE index,const OMX_PTR params)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 
internalSetConfig(OMX_INDEXTYPE index,const OMX_PTR params,bool * frameConfig)208 OMX_ERRORTYPE SimpleSoftOMXComponent::internalSetConfig(
209         OMX_INDEXTYPE index, const OMX_PTR params, bool *frameConfig) {
210     return OMX_ErrorUndefined;
211 }
212 
setConfig(OMX_INDEXTYPE index,const OMX_PTR params)213 OMX_ERRORTYPE SimpleSoftOMXComponent::setConfig(
214         OMX_INDEXTYPE index, const OMX_PTR params) {
215     bool frameConfig = mFrameConfig;
216     OMX_ERRORTYPE err = internalSetConfig(index, params, &frameConfig);
217     if (err == OMX_ErrorNone) {
218         mFrameConfig = frameConfig;
219     }
220     return err;
221 }
222 
useBuffer(OMX_BUFFERHEADERTYPE ** header,OMX_U32 portIndex,OMX_PTR appPrivate,OMX_U32 size,OMX_U8 * ptr)223 OMX_ERRORTYPE SimpleSoftOMXComponent::useBuffer(
224         OMX_BUFFERHEADERTYPE **header,
225         OMX_U32 portIndex,
226         OMX_PTR appPrivate,
227         OMX_U32 size,
228         OMX_U8 *ptr) {
229     Mutex::Autolock autoLock(mLock);
230     CHECK_LT(portIndex, mPorts.size());
231 
232     PortInfo *port = &mPorts.editItemAt(portIndex);
233     if (size < port->mDef.nBufferSize) {
234         ALOGE("b/63522430, Buffer size is too small.");
235         android_errorWriteLog(0x534e4554, "63522430");
236         return OMX_ErrorBadParameter;
237     }
238 
239     *header = new OMX_BUFFERHEADERTYPE;
240     (*header)->nSize = sizeof(OMX_BUFFERHEADERTYPE);
241     (*header)->nVersion.s.nVersionMajor = 1;
242     (*header)->nVersion.s.nVersionMinor = 0;
243     (*header)->nVersion.s.nRevision = 0;
244     (*header)->nVersion.s.nStep = 0;
245     (*header)->pBuffer = ptr;
246     (*header)->nAllocLen = size;
247     (*header)->nFilledLen = 0;
248     (*header)->nOffset = 0;
249     (*header)->pAppPrivate = appPrivate;
250     (*header)->pPlatformPrivate = NULL;
251     (*header)->pInputPortPrivate = NULL;
252     (*header)->pOutputPortPrivate = NULL;
253     (*header)->hMarkTargetComponent = NULL;
254     (*header)->pMarkData = NULL;
255     (*header)->nTickCount = 0;
256     (*header)->nTimeStamp = 0;
257     (*header)->nFlags = 0;
258     (*header)->nOutputPortIndex = portIndex;
259     (*header)->nInputPortIndex = portIndex;
260 
261     CHECK(mState == OMX_StateLoaded || port->mDef.bEnabled == OMX_FALSE);
262 
263     CHECK_LT(port->mBuffers.size(), port->mDef.nBufferCountActual);
264 
265     port->mBuffers.push();
266 
267     BufferInfo *buffer =
268         &port->mBuffers.editItemAt(port->mBuffers.size() - 1);
269 
270     buffer->mHeader = *header;
271     buffer->mOwnedByUs = false;
272 
273     if (port->mBuffers.size() == port->mDef.nBufferCountActual) {
274         port->mDef.bPopulated = OMX_TRUE;
275         checkTransitions();
276     }
277 
278     return OMX_ErrorNone;
279 }
280 
allocateBuffer(OMX_BUFFERHEADERTYPE ** header,OMX_U32 portIndex,OMX_PTR appPrivate,OMX_U32 size)281 OMX_ERRORTYPE SimpleSoftOMXComponent::allocateBuffer(
282         OMX_BUFFERHEADERTYPE **header,
283         OMX_U32 portIndex,
284         OMX_PTR appPrivate,
285         OMX_U32 size) {
286     OMX_U8 *ptr = new OMX_U8[size];
287 
288     OMX_ERRORTYPE err =
289         useBuffer(header, portIndex, appPrivate, size, ptr);
290 
291     if (err != OMX_ErrorNone) {
292         delete[] ptr;
293         ptr = NULL;
294 
295         return err;
296     }
297 
298     CHECK((*header)->pPlatformPrivate == NULL);
299     (*header)->pPlatformPrivate = ptr;
300 
301     return OMX_ErrorNone;
302 }
303 
freeBuffer(OMX_U32 portIndex,OMX_BUFFERHEADERTYPE * header)304 OMX_ERRORTYPE SimpleSoftOMXComponent::freeBuffer(
305         OMX_U32 portIndex,
306         OMX_BUFFERHEADERTYPE *header) {
307     Mutex::Autolock autoLock(mLock);
308 
309     CHECK_LT(portIndex, mPorts.size());
310 
311     PortInfo *port = &mPorts.editItemAt(portIndex);
312 
313 #if 0 // XXX
314     CHECK((mState == OMX_StateIdle && mTargetState == OMX_StateLoaded)
315             || port->mDef.bEnabled == OMX_FALSE);
316 #endif
317 
318     bool found = false;
319     for (size_t i = 0; i < port->mBuffers.size(); ++i) {
320         BufferInfo *buffer = &port->mBuffers.editItemAt(i);
321 
322         if (buffer->mHeader == header) {
323             CHECK(!buffer->mOwnedByUs);
324 
325             if (header->pPlatformPrivate != NULL) {
326                 // This buffer's data was allocated by us.
327                 CHECK(header->pPlatformPrivate == header->pBuffer);
328 
329                 delete[] header->pBuffer;
330                 header->pBuffer = NULL;
331             }
332 
333             delete header;
334             header = NULL;
335 
336             port->mBuffers.removeAt(i);
337             port->mDef.bPopulated = OMX_FALSE;
338 
339             checkTransitions();
340 
341             found = true;
342             break;
343         }
344     }
345 
346     CHECK(found);
347 
348     return OMX_ErrorNone;
349 }
350 
emptyThisBuffer(OMX_BUFFERHEADERTYPE * buffer)351 OMX_ERRORTYPE SimpleSoftOMXComponent::emptyThisBuffer(
352         OMX_BUFFERHEADERTYPE *buffer) {
353     sp<AMessage> msg = new AMessage(kWhatEmptyThisBuffer, mHandler);
354     msg->setPointer("header", buffer);
355     if (mFrameConfig) {
356         msg->setInt32("frame-config", mFrameConfig);
357         mFrameConfig = false;
358     }
359     msg->post();
360 
361     return OMX_ErrorNone;
362 }
363 
fillThisBuffer(OMX_BUFFERHEADERTYPE * buffer)364 OMX_ERRORTYPE SimpleSoftOMXComponent::fillThisBuffer(
365         OMX_BUFFERHEADERTYPE *buffer) {
366     sp<AMessage> msg = new AMessage(kWhatFillThisBuffer, mHandler);
367     msg->setPointer("header", buffer);
368     msg->post();
369 
370     return OMX_ErrorNone;
371 }
372 
getState(OMX_STATETYPE * state)373 OMX_ERRORTYPE SimpleSoftOMXComponent::getState(OMX_STATETYPE *state) {
374     Mutex::Autolock autoLock(mLock);
375 
376     *state = mState;
377 
378     return OMX_ErrorNone;
379 }
380 
onMessageReceived(const sp<AMessage> & msg)381 void SimpleSoftOMXComponent::onMessageReceived(const sp<AMessage> &msg) {
382     Mutex::Autolock autoLock(mLock);
383     uint32_t msgType = msg->what();
384     ALOGV("msgType = %d", msgType);
385     switch (msgType) {
386         case kWhatSendCommand:
387         {
388             int32_t cmd, param;
389             CHECK(msg->findInt32("cmd", &cmd));
390             CHECK(msg->findInt32("param", &param));
391 
392             onSendCommand((OMX_COMMANDTYPE)cmd, (OMX_U32)param);
393             break;
394         }
395 
396         case kWhatEmptyThisBuffer:
397         case kWhatFillThisBuffer:
398         {
399             OMX_BUFFERHEADERTYPE *header;
400             CHECK(msg->findPointer("header", (void **)&header));
401             int32_t frameConfig;
402             if (!msg->findInt32("frame-config", &frameConfig)) {
403                 frameConfig = 0;
404             }
405 
406             CHECK(mState == OMX_StateExecuting && mTargetState == mState);
407 
408             bool found = false;
409             size_t portIndex = (kWhatEmptyThisBuffer == msgType)?
410                     header->nInputPortIndex: header->nOutputPortIndex;
411             PortInfo *port = &mPorts.editItemAt(portIndex);
412 
413             for (size_t j = 0; j < port->mBuffers.size(); ++j) {
414                 BufferInfo *buffer = &port->mBuffers.editItemAt(j);
415 
416                 if (buffer->mHeader == header) {
417                     CHECK(!buffer->mOwnedByUs);
418 
419                     buffer->mOwnedByUs = true;
420                     buffer->mFrameConfig = (bool)frameConfig;
421 
422                     CHECK((msgType == kWhatEmptyThisBuffer
423                             && port->mDef.eDir == OMX_DirInput)
424                             || (port->mDef.eDir == OMX_DirOutput));
425 
426                     port->mQueue.push_back(buffer);
427                     onQueueFilled(portIndex);
428 
429                     found = true;
430                     break;
431                 }
432             }
433 
434             CHECK(found);
435             break;
436         }
437 
438         default:
439             TRESPASS();
440             break;
441     }
442 }
443 
onSendCommand(OMX_COMMANDTYPE cmd,OMX_U32 param)444 void SimpleSoftOMXComponent::onSendCommand(
445         OMX_COMMANDTYPE cmd, OMX_U32 param) {
446     switch (cmd) {
447         case OMX_CommandStateSet:
448         {
449             onChangeState((OMX_STATETYPE)param);
450             break;
451         }
452 
453         case OMX_CommandPortEnable:
454         case OMX_CommandPortDisable:
455         {
456             onPortEnable(param, cmd == OMX_CommandPortEnable);
457             break;
458         }
459 
460         case OMX_CommandFlush:
461         {
462             onPortFlush(param, true /* sendFlushComplete */);
463             break;
464         }
465 
466         default:
467             TRESPASS();
468             break;
469     }
470 }
471 
onChangeState(OMX_STATETYPE state)472 void SimpleSoftOMXComponent::onChangeState(OMX_STATETYPE state) {
473     ALOGV("%p requesting change from %d to %d", this, mState, state);
474     // We shouldn't be in a state transition already.
475 
476     if (mState == OMX_StateLoaded
477             && mTargetState == OMX_StateIdle
478             && state == OMX_StateLoaded) {
479         // OMX specifically allows "canceling" a state transition from loaded
480         // to idle. Pretend we made it to idle, and go back to loaded
481         ALOGV("load->idle canceled");
482         mState = mTargetState = OMX_StateIdle;
483         state = OMX_StateLoaded;
484     }
485 
486     if (mState != mTargetState) {
487         ALOGE("State change to state %d requested while still transitioning from state %d to %d",
488                 state, mState, mTargetState);
489         notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
490         return;
491     }
492 
493     switch (mState) {
494         case OMX_StateLoaded:
495             CHECK_EQ((int)state, (int)OMX_StateIdle);
496             break;
497         case OMX_StateIdle:
498             CHECK(state == OMX_StateLoaded || state == OMX_StateExecuting);
499             break;
500         case OMX_StateExecuting:
501         {
502             CHECK_EQ((int)state, (int)OMX_StateIdle);
503 
504             for (size_t i = 0; i < mPorts.size(); ++i) {
505                 onPortFlush(i, false /* sendFlushComplete */);
506             }
507 
508             mState = OMX_StateIdle;
509             notify(OMX_EventCmdComplete, OMX_CommandStateSet, state, NULL);
510             break;
511         }
512 
513         default:
514             TRESPASS();
515     }
516 
517     mTargetState = state;
518 
519     checkTransitions();
520 }
521 
onReset()522 void SimpleSoftOMXComponent::onReset() {
523     // no-op
524 }
525 
onPortEnable(OMX_U32 portIndex,bool enable)526 void SimpleSoftOMXComponent::onPortEnable(OMX_U32 portIndex, bool enable) {
527     CHECK_LT(portIndex, mPorts.size());
528 
529     PortInfo *port = &mPorts.editItemAt(portIndex);
530     CHECK_EQ((int)port->mTransition, (int)PortInfo::NONE);
531     CHECK(port->mDef.bEnabled == !enable);
532 
533     if (port->mDef.eDir != OMX_DirOutput) {
534         ALOGE("Port enable/disable allowed only on output ports.");
535         notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
536         android_errorWriteLog(0x534e4554, "29421804");
537         return;
538     }
539 
540     if (!enable) {
541         port->mDef.bEnabled = OMX_FALSE;
542         port->mTransition = PortInfo::DISABLING;
543 
544         for (size_t i = 0; i < port->mBuffers.size(); ++i) {
545             BufferInfo *buffer = &port->mBuffers.editItemAt(i);
546 
547             if (buffer->mOwnedByUs) {
548                 buffer->mOwnedByUs = false;
549 
550                 if (port->mDef.eDir == OMX_DirInput) {
551                     notifyEmptyBufferDone(buffer->mHeader);
552                 } else {
553                     CHECK_EQ(port->mDef.eDir, OMX_DirOutput);
554                     notifyFillBufferDone(buffer->mHeader);
555                 }
556             }
557         }
558 
559         port->mQueue.clear();
560     } else {
561         port->mTransition = PortInfo::ENABLING;
562     }
563 
564     checkTransitions();
565 }
566 
onPortFlush(OMX_U32 portIndex,bool sendFlushComplete)567 void SimpleSoftOMXComponent::onPortFlush(
568         OMX_U32 portIndex, bool sendFlushComplete) {
569     if (portIndex == OMX_ALL) {
570         for (size_t i = 0; i < mPorts.size(); ++i) {
571             onPortFlush(i, sendFlushComplete);
572         }
573 
574         if (sendFlushComplete) {
575             notify(OMX_EventCmdComplete, OMX_CommandFlush, OMX_ALL, NULL);
576         }
577 
578         return;
579     }
580 
581     CHECK_LT(portIndex, mPorts.size());
582 
583     PortInfo *port = &mPorts.editItemAt(portIndex);
584     // Ideally, the port should not in transitioning state when flushing.
585     // However, in error handling case, e.g., the client can't allocate buffers
586     // when it tries to re-enable the port, the port will be stuck in ENABLING.
587     // The client will then transition the component from Executing to Idle,
588     // which leads to flushing ports. At this time, it should be ok to notify
589     // the client of the error and still clear all buffers on the port.
590     if (port->mTransition != PortInfo::NONE) {
591         notify(OMX_EventError, OMX_ErrorUndefined, 0, 0);
592     }
593 
594     for (size_t i = 0; i < port->mBuffers.size(); ++i) {
595         BufferInfo *buffer = &port->mBuffers.editItemAt(i);
596 
597         if (!buffer->mOwnedByUs) {
598             continue;
599         }
600 
601         buffer->mHeader->nFilledLen = 0;
602         buffer->mHeader->nOffset = 0;
603         buffer->mHeader->nFlags = 0;
604 
605         buffer->mOwnedByUs = false;
606 
607         if (port->mDef.eDir == OMX_DirInput) {
608             notifyEmptyBufferDone(buffer->mHeader);
609         } else {
610             CHECK_EQ(port->mDef.eDir, OMX_DirOutput);
611 
612             notifyFillBufferDone(buffer->mHeader);
613         }
614     }
615 
616     port->mQueue.clear();
617 
618     if (sendFlushComplete) {
619         notify(OMX_EventCmdComplete, OMX_CommandFlush, portIndex, NULL);
620 
621         onPortFlushCompleted(portIndex);
622     }
623 }
624 
checkTransitions()625 void SimpleSoftOMXComponent::checkTransitions() {
626     if (mState != mTargetState) {
627         bool transitionComplete = true;
628 
629         if (mState == OMX_StateLoaded) {
630             CHECK_EQ((int)mTargetState, (int)OMX_StateIdle);
631 
632             for (size_t i = 0; i < mPorts.size(); ++i) {
633                 const PortInfo &port = mPorts.itemAt(i);
634                 if (port.mDef.bEnabled == OMX_FALSE) {
635                     continue;
636                 }
637 
638                 if (port.mDef.bPopulated == OMX_FALSE) {
639                     transitionComplete = false;
640                     break;
641                 }
642             }
643         } else if (mTargetState == OMX_StateLoaded) {
644             CHECK_EQ((int)mState, (int)OMX_StateIdle);
645 
646             for (size_t i = 0; i < mPorts.size(); ++i) {
647                 const PortInfo &port = mPorts.itemAt(i);
648                 if (port.mDef.bEnabled == OMX_FALSE) {
649                     continue;
650                 }
651 
652                 size_t n = port.mBuffers.size();
653 
654                 if (n > 0) {
655                     CHECK_LE(n, port.mDef.nBufferCountActual);
656 
657                     if (n == port.mDef.nBufferCountActual) {
658                         CHECK_EQ((int)port.mDef.bPopulated, (int)OMX_TRUE);
659                     } else {
660                         CHECK_EQ((int)port.mDef.bPopulated, (int)OMX_FALSE);
661                     }
662 
663                     transitionComplete = false;
664                     break;
665                 }
666             }
667         }
668 
669         if (transitionComplete) {
670             ALOGV("state transition from %d to %d complete", mState, mTargetState);
671             mState = mTargetState;
672 
673             if (mState == OMX_StateLoaded) {
674                 onReset();
675             }
676 
677             notify(OMX_EventCmdComplete, OMX_CommandStateSet, mState, NULL);
678         } else {
679             ALOGV("state transition from %d to %d not yet complete", mState, mTargetState);
680         }
681     }
682 
683     for (size_t i = 0; i < mPorts.size(); ++i) {
684         PortInfo *port = &mPorts.editItemAt(i);
685 
686         if (port->mTransition == PortInfo::DISABLING) {
687             if (port->mBuffers.empty()) {
688                 ALOGV("Port %zu now disabled.", i);
689 
690                 port->mTransition = PortInfo::NONE;
691                 notify(OMX_EventCmdComplete, OMX_CommandPortDisable, i, NULL);
692 
693                 onPortEnableCompleted(i, false /* enabled */);
694             }
695         } else if (port->mTransition == PortInfo::ENABLING) {
696             if (port->mDef.bPopulated == OMX_TRUE) {
697                 ALOGV("Port %zu now enabled.", i);
698 
699                 port->mTransition = PortInfo::NONE;
700                 port->mDef.bEnabled = OMX_TRUE;
701                 notify(OMX_EventCmdComplete, OMX_CommandPortEnable, i, NULL);
702 
703                 onPortEnableCompleted(i, true /* enabled */);
704             }
705         }
706     }
707 }
708 
addPort(const OMX_PARAM_PORTDEFINITIONTYPE & def)709 void SimpleSoftOMXComponent::addPort(const OMX_PARAM_PORTDEFINITIONTYPE &def) {
710     CHECK_EQ(def.nPortIndex, mPorts.size());
711 
712     mPorts.push();
713     PortInfo *info = &mPorts.editItemAt(mPorts.size() - 1);
714     info->mDef = def;
715     info->mTransition = PortInfo::NONE;
716 }
717 
onQueueFilled(OMX_U32 portIndex __unused)718 void SimpleSoftOMXComponent::onQueueFilled(OMX_U32 portIndex __unused) {
719 }
720 
onPortFlushCompleted(OMX_U32 portIndex __unused)721 void SimpleSoftOMXComponent::onPortFlushCompleted(OMX_U32 portIndex __unused) {
722 }
723 
onPortEnableCompleted(OMX_U32 portIndex __unused,bool enabled __unused)724 void SimpleSoftOMXComponent::onPortEnableCompleted(
725         OMX_U32 portIndex __unused, bool enabled __unused) {
726 }
727 
728 List<SimpleSoftOMXComponent::BufferInfo *> &
getPortQueue(OMX_U32 portIndex)729 SimpleSoftOMXComponent::getPortQueue(OMX_U32 portIndex) {
730     CHECK_LT(portIndex, mPorts.size());
731     return mPorts.editItemAt(portIndex).mQueue;
732 }
733 
editPortInfo(OMX_U32 portIndex)734 SimpleSoftOMXComponent::PortInfo *SimpleSoftOMXComponent::editPortInfo(
735         OMX_U32 portIndex) {
736     CHECK_LT(portIndex, mPorts.size());
737     return &mPorts.editItemAt(portIndex);
738 }
739 
740 }  // namespace android
741