SimpleSoftOMXComponent.cpp revision fd866b3aa0d97375de08f8888b95669026c83361
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 27namespace android { 28 29SimpleSoftOMXComponent::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 48void 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 57OMX_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 69bool 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 105OMX_ERRORTYPE SimpleSoftOMXComponent::getParameter( 106 OMX_INDEXTYPE index, OMX_PTR params) { 107 Mutex::Autolock autoLock(mLock); 108 return internalGetParameter(index, params); 109} 110 111OMX_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 120OMX_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 (defParams->nPortIndex >= mPorts.size() 129 || defParams->nSize 130 != sizeof(OMX_PARAM_PORTDEFINITIONTYPE)) { 131 return OMX_ErrorUndefined; 132 } 133 134 const PortInfo *port = 135 &mPorts.itemAt(defParams->nPortIndex); 136 137 memcpy(defParams, &port->mDef, sizeof(port->mDef)); 138 139 return OMX_ErrorNone; 140 } 141 142 default: 143 return OMX_ErrorUnsupportedIndex; 144 } 145} 146 147OMX_ERRORTYPE SimpleSoftOMXComponent::internalSetParameter( 148 OMX_INDEXTYPE index, const OMX_PTR params) { 149 switch (index) { 150 case OMX_IndexParamPortDefinition: 151 { 152 OMX_PARAM_PORTDEFINITIONTYPE *defParams = 153 (OMX_PARAM_PORTDEFINITIONTYPE *)params; 154 155 if (defParams->nPortIndex >= mPorts.size()) { 156 return OMX_ErrorBadPortIndex; 157 } 158 if (defParams->nSize != sizeof(OMX_PARAM_PORTDEFINITIONTYPE)) { 159 return OMX_ErrorUnsupportedSetting; 160 } 161 162 PortInfo *port = 163 &mPorts.editItemAt(defParams->nPortIndex); 164 165 // default behavior is that we only allow buffer size to increase 166 if (defParams->nBufferSize > port->mDef.nBufferSize) { 167 port->mDef.nBufferSize = defParams->nBufferSize; 168 } 169 170 if (defParams->nBufferCountActual < port->mDef.nBufferCountMin) { 171 ALOGW("component requires at least %u buffers (%u requested)", 172 port->mDef.nBufferCountMin, defParams->nBufferCountActual); 173 return OMX_ErrorUnsupportedSetting; 174 } 175 176 port->mDef.nBufferCountActual = defParams->nBufferCountActual; 177 return OMX_ErrorNone; 178 } 179 180 default: 181 return OMX_ErrorUnsupportedIndex; 182 } 183} 184 185OMX_ERRORTYPE SimpleSoftOMXComponent::useBuffer( 186 OMX_BUFFERHEADERTYPE **header, 187 OMX_U32 portIndex, 188 OMX_PTR appPrivate, 189 OMX_U32 size, 190 OMX_U8 *ptr) { 191 Mutex::Autolock autoLock(mLock); 192 CHECK_LT(portIndex, mPorts.size()); 193 194 *header = new OMX_BUFFERHEADERTYPE; 195 (*header)->nSize = sizeof(OMX_BUFFERHEADERTYPE); 196 (*header)->nVersion.s.nVersionMajor = 1; 197 (*header)->nVersion.s.nVersionMinor = 0; 198 (*header)->nVersion.s.nRevision = 0; 199 (*header)->nVersion.s.nStep = 0; 200 (*header)->pBuffer = ptr; 201 (*header)->nAllocLen = size; 202 (*header)->nFilledLen = 0; 203 (*header)->nOffset = 0; 204 (*header)->pAppPrivate = appPrivate; 205 (*header)->pPlatformPrivate = NULL; 206 (*header)->pInputPortPrivate = NULL; 207 (*header)->pOutputPortPrivate = NULL; 208 (*header)->hMarkTargetComponent = NULL; 209 (*header)->pMarkData = NULL; 210 (*header)->nTickCount = 0; 211 (*header)->nTimeStamp = 0; 212 (*header)->nFlags = 0; 213 (*header)->nOutputPortIndex = portIndex; 214 (*header)->nInputPortIndex = portIndex; 215 216 PortInfo *port = &mPorts.editItemAt(portIndex); 217 218 CHECK(mState == OMX_StateLoaded || port->mDef.bEnabled == OMX_FALSE); 219 220 CHECK_LT(port->mBuffers.size(), port->mDef.nBufferCountActual); 221 222 port->mBuffers.push(); 223 224 BufferInfo *buffer = 225 &port->mBuffers.editItemAt(port->mBuffers.size() - 1); 226 227 buffer->mHeader = *header; 228 buffer->mOwnedByUs = false; 229 230 if (port->mBuffers.size() == port->mDef.nBufferCountActual) { 231 port->mDef.bPopulated = OMX_TRUE; 232 checkTransitions(); 233 } 234 235 return OMX_ErrorNone; 236} 237 238OMX_ERRORTYPE SimpleSoftOMXComponent::allocateBuffer( 239 OMX_BUFFERHEADERTYPE **header, 240 OMX_U32 portIndex, 241 OMX_PTR appPrivate, 242 OMX_U32 size) { 243 OMX_U8 *ptr = new OMX_U8[size]; 244 245 OMX_ERRORTYPE err = 246 useBuffer(header, portIndex, appPrivate, size, ptr); 247 248 if (err != OMX_ErrorNone) { 249 delete[] ptr; 250 ptr = NULL; 251 252 return err; 253 } 254 255 CHECK((*header)->pPlatformPrivate == NULL); 256 (*header)->pPlatformPrivate = ptr; 257 258 return OMX_ErrorNone; 259} 260 261OMX_ERRORTYPE SimpleSoftOMXComponent::freeBuffer( 262 OMX_U32 portIndex, 263 OMX_BUFFERHEADERTYPE *header) { 264 Mutex::Autolock autoLock(mLock); 265 266 CHECK_LT(portIndex, mPorts.size()); 267 268 PortInfo *port = &mPorts.editItemAt(portIndex); 269 270#if 0 // XXX 271 CHECK((mState == OMX_StateIdle && mTargetState == OMX_StateLoaded) 272 || port->mDef.bEnabled == OMX_FALSE); 273#endif 274 275 bool found = false; 276 for (size_t i = 0; i < port->mBuffers.size(); ++i) { 277 BufferInfo *buffer = &port->mBuffers.editItemAt(i); 278 279 if (buffer->mHeader == header) { 280 CHECK(!buffer->mOwnedByUs); 281 282 if (header->pPlatformPrivate != NULL) { 283 // This buffer's data was allocated by us. 284 CHECK(header->pPlatformPrivate == header->pBuffer); 285 286 delete[] header->pBuffer; 287 header->pBuffer = NULL; 288 } 289 290 delete header; 291 header = NULL; 292 293 port->mBuffers.removeAt(i); 294 port->mDef.bPopulated = OMX_FALSE; 295 296 checkTransitions(); 297 298 found = true; 299 break; 300 } 301 } 302 303 CHECK(found); 304 305 return OMX_ErrorNone; 306} 307 308OMX_ERRORTYPE SimpleSoftOMXComponent::emptyThisBuffer( 309 OMX_BUFFERHEADERTYPE *buffer) { 310 sp<AMessage> msg = new AMessage(kWhatEmptyThisBuffer, mHandler); 311 msg->setPointer("header", buffer); 312 msg->post(); 313 314 return OMX_ErrorNone; 315} 316 317OMX_ERRORTYPE SimpleSoftOMXComponent::fillThisBuffer( 318 OMX_BUFFERHEADERTYPE *buffer) { 319 sp<AMessage> msg = new AMessage(kWhatFillThisBuffer, mHandler); 320 msg->setPointer("header", buffer); 321 msg->post(); 322 323 return OMX_ErrorNone; 324} 325 326OMX_ERRORTYPE SimpleSoftOMXComponent::getState(OMX_STATETYPE *state) { 327 Mutex::Autolock autoLock(mLock); 328 329 *state = mState; 330 331 return OMX_ErrorNone; 332} 333 334void SimpleSoftOMXComponent::onMessageReceived(const sp<AMessage> &msg) { 335 Mutex::Autolock autoLock(mLock); 336 uint32_t msgType = msg->what(); 337 ALOGV("msgType = %d", msgType); 338 switch (msgType) { 339 case kWhatSendCommand: 340 { 341 int32_t cmd, param; 342 CHECK(msg->findInt32("cmd", &cmd)); 343 CHECK(msg->findInt32("param", ¶m)); 344 345 onSendCommand((OMX_COMMANDTYPE)cmd, (OMX_U32)param); 346 break; 347 } 348 349 case kWhatEmptyThisBuffer: 350 case kWhatFillThisBuffer: 351 { 352 OMX_BUFFERHEADERTYPE *header; 353 CHECK(msg->findPointer("header", (void **)&header)); 354 355 CHECK(mState == OMX_StateExecuting && mTargetState == mState); 356 357 bool found = false; 358 size_t portIndex = (kWhatEmptyThisBuffer == msgType)? 359 header->nInputPortIndex: header->nOutputPortIndex; 360 PortInfo *port = &mPorts.editItemAt(portIndex); 361 362 for (size_t j = 0; j < port->mBuffers.size(); ++j) { 363 BufferInfo *buffer = &port->mBuffers.editItemAt(j); 364 365 if (buffer->mHeader == header) { 366 CHECK(!buffer->mOwnedByUs); 367 368 buffer->mOwnedByUs = true; 369 370 CHECK((msgType == kWhatEmptyThisBuffer 371 && port->mDef.eDir == OMX_DirInput) 372 || (port->mDef.eDir == OMX_DirOutput)); 373 374 port->mQueue.push_back(buffer); 375 onQueueFilled(portIndex); 376 377 found = true; 378 break; 379 } 380 } 381 382 CHECK(found); 383 break; 384 } 385 386 default: 387 TRESPASS(); 388 break; 389 } 390} 391 392void SimpleSoftOMXComponent::onSendCommand( 393 OMX_COMMANDTYPE cmd, OMX_U32 param) { 394 switch (cmd) { 395 case OMX_CommandStateSet: 396 { 397 onChangeState((OMX_STATETYPE)param); 398 break; 399 } 400 401 case OMX_CommandPortEnable: 402 case OMX_CommandPortDisable: 403 { 404 onPortEnable(param, cmd == OMX_CommandPortEnable); 405 break; 406 } 407 408 case OMX_CommandFlush: 409 { 410 onPortFlush(param, true /* sendFlushComplete */); 411 break; 412 } 413 414 default: 415 TRESPASS(); 416 break; 417 } 418} 419 420void SimpleSoftOMXComponent::onChangeState(OMX_STATETYPE state) { 421 // We shouldn't be in a state transition already. 422 CHECK_EQ((int)mState, (int)mTargetState); 423 424 switch (mState) { 425 case OMX_StateLoaded: 426 CHECK_EQ((int)state, (int)OMX_StateIdle); 427 break; 428 case OMX_StateIdle: 429 CHECK(state == OMX_StateLoaded || state == OMX_StateExecuting); 430 break; 431 case OMX_StateExecuting: 432 { 433 CHECK_EQ((int)state, (int)OMX_StateIdle); 434 435 for (size_t i = 0; i < mPorts.size(); ++i) { 436 onPortFlush(i, false /* sendFlushComplete */); 437 } 438 439 mState = OMX_StateIdle; 440 notify(OMX_EventCmdComplete, OMX_CommandStateSet, state, NULL); 441 break; 442 } 443 444 default: 445 TRESPASS(); 446 } 447 448 mTargetState = state; 449 450 checkTransitions(); 451} 452 453void SimpleSoftOMXComponent::onReset() { 454 // no-op 455} 456 457void SimpleSoftOMXComponent::onPortEnable(OMX_U32 portIndex, bool enable) { 458 CHECK_LT(portIndex, mPorts.size()); 459 460 PortInfo *port = &mPorts.editItemAt(portIndex); 461 CHECK_EQ((int)port->mTransition, (int)PortInfo::NONE); 462 CHECK(port->mDef.bEnabled == !enable); 463 464 if (!enable) { 465 port->mDef.bEnabled = OMX_FALSE; 466 port->mTransition = PortInfo::DISABLING; 467 468 for (size_t i = 0; i < port->mBuffers.size(); ++i) { 469 BufferInfo *buffer = &port->mBuffers.editItemAt(i); 470 471 if (buffer->mOwnedByUs) { 472 buffer->mOwnedByUs = false; 473 474 if (port->mDef.eDir == OMX_DirInput) { 475 notifyEmptyBufferDone(buffer->mHeader); 476 } else { 477 CHECK_EQ(port->mDef.eDir, OMX_DirOutput); 478 notifyFillBufferDone(buffer->mHeader); 479 } 480 } 481 } 482 483 port->mQueue.clear(); 484 } else { 485 port->mTransition = PortInfo::ENABLING; 486 } 487 488 checkTransitions(); 489} 490 491void SimpleSoftOMXComponent::onPortFlush( 492 OMX_U32 portIndex, bool sendFlushComplete) { 493 if (portIndex == OMX_ALL) { 494 for (size_t i = 0; i < mPorts.size(); ++i) { 495 onPortFlush(i, sendFlushComplete); 496 } 497 498 if (sendFlushComplete) { 499 notify(OMX_EventCmdComplete, OMX_CommandFlush, OMX_ALL, NULL); 500 } 501 502 return; 503 } 504 505 CHECK_LT(portIndex, mPorts.size()); 506 507 PortInfo *port = &mPorts.editItemAt(portIndex); 508 // Ideally, the port should not in transitioning state when flushing. 509 // However, in error handling case, e.g., the client can't allocate buffers 510 // when it tries to re-enable the port, the port will be stuck in ENABLING. 511 // The client will then transition the component from Executing to Idle, 512 // which leads to flushing ports. At this time, it should be ok to notify 513 // the client of the error and still clear all buffers on the port. 514 if (port->mTransition != PortInfo::NONE) { 515 notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); 516 } 517 518 for (size_t i = 0; i < port->mBuffers.size(); ++i) { 519 BufferInfo *buffer = &port->mBuffers.editItemAt(i); 520 521 if (!buffer->mOwnedByUs) { 522 continue; 523 } 524 525 buffer->mHeader->nFilledLen = 0; 526 buffer->mHeader->nOffset = 0; 527 buffer->mHeader->nFlags = 0; 528 529 buffer->mOwnedByUs = false; 530 531 if (port->mDef.eDir == OMX_DirInput) { 532 notifyEmptyBufferDone(buffer->mHeader); 533 } else { 534 CHECK_EQ(port->mDef.eDir, OMX_DirOutput); 535 536 notifyFillBufferDone(buffer->mHeader); 537 } 538 } 539 540 port->mQueue.clear(); 541 542 if (sendFlushComplete) { 543 notify(OMX_EventCmdComplete, OMX_CommandFlush, portIndex, NULL); 544 545 onPortFlushCompleted(portIndex); 546 } 547} 548 549void SimpleSoftOMXComponent::checkTransitions() { 550 if (mState != mTargetState) { 551 bool transitionComplete = true; 552 553 if (mState == OMX_StateLoaded) { 554 CHECK_EQ((int)mTargetState, (int)OMX_StateIdle); 555 556 for (size_t i = 0; i < mPorts.size(); ++i) { 557 const PortInfo &port = mPorts.itemAt(i); 558 if (port.mDef.bEnabled == OMX_FALSE) { 559 continue; 560 } 561 562 if (port.mDef.bPopulated == OMX_FALSE) { 563 transitionComplete = false; 564 break; 565 } 566 } 567 } else if (mTargetState == OMX_StateLoaded) { 568 CHECK_EQ((int)mState, (int)OMX_StateIdle); 569 570 for (size_t i = 0; i < mPorts.size(); ++i) { 571 const PortInfo &port = mPorts.itemAt(i); 572 if (port.mDef.bEnabled == OMX_FALSE) { 573 continue; 574 } 575 576 size_t n = port.mBuffers.size(); 577 578 if (n > 0) { 579 CHECK_LE(n, port.mDef.nBufferCountActual); 580 581 if (n == port.mDef.nBufferCountActual) { 582 CHECK_EQ((int)port.mDef.bPopulated, (int)OMX_TRUE); 583 } else { 584 CHECK_EQ((int)port.mDef.bPopulated, (int)OMX_FALSE); 585 } 586 587 transitionComplete = false; 588 break; 589 } 590 } 591 } 592 593 if (transitionComplete) { 594 mState = mTargetState; 595 596 if (mState == OMX_StateLoaded) { 597 onReset(); 598 } 599 600 notify(OMX_EventCmdComplete, OMX_CommandStateSet, mState, NULL); 601 } 602 } 603 604 for (size_t i = 0; i < mPorts.size(); ++i) { 605 PortInfo *port = &mPorts.editItemAt(i); 606 607 if (port->mTransition == PortInfo::DISABLING) { 608 if (port->mBuffers.empty()) { 609 ALOGV("Port %zu now disabled.", i); 610 611 port->mTransition = PortInfo::NONE; 612 notify(OMX_EventCmdComplete, OMX_CommandPortDisable, i, NULL); 613 614 onPortEnableCompleted(i, false /* enabled */); 615 } 616 } else if (port->mTransition == PortInfo::ENABLING) { 617 if (port->mDef.bPopulated == OMX_TRUE) { 618 ALOGV("Port %zu now enabled.", i); 619 620 port->mTransition = PortInfo::NONE; 621 port->mDef.bEnabled = OMX_TRUE; 622 notify(OMX_EventCmdComplete, OMX_CommandPortEnable, i, NULL); 623 624 onPortEnableCompleted(i, true /* enabled */); 625 } 626 } 627 } 628} 629 630void SimpleSoftOMXComponent::addPort(const OMX_PARAM_PORTDEFINITIONTYPE &def) { 631 CHECK_EQ(def.nPortIndex, mPorts.size()); 632 633 mPorts.push(); 634 PortInfo *info = &mPorts.editItemAt(mPorts.size() - 1); 635 info->mDef = def; 636 info->mTransition = PortInfo::NONE; 637} 638 639void SimpleSoftOMXComponent::onQueueFilled(OMX_U32 portIndex __unused) { 640} 641 642void SimpleSoftOMXComponent::onPortFlushCompleted(OMX_U32 portIndex __unused) { 643} 644 645void SimpleSoftOMXComponent::onPortEnableCompleted( 646 OMX_U32 portIndex __unused, bool enabled __unused) { 647} 648 649List<SimpleSoftOMXComponent::BufferInfo *> & 650SimpleSoftOMXComponent::getPortQueue(OMX_U32 portIndex) { 651 CHECK_LT(portIndex, mPorts.size()); 652 return mPorts.editItemAt(portIndex).mQueue; 653} 654 655SimpleSoftOMXComponent::PortInfo *SimpleSoftOMXComponent::editPortInfo( 656 OMX_U32 portIndex) { 657 CHECK_LT(portIndex, mPorts.size()); 658 return &mPorts.editItemAt(portIndex); 659} 660 661} // namespace android 662