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