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