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