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", ¶m));
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