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