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