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 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 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 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->id()); 62 msg->setInt32("cmd", cmd); 63 msg->setInt32("param", param); 64 msg->post(); 65 66 return OMX_ErrorNone; 67 } 68 69 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 105 OMX_ERRORTYPE SimpleSoftOMXComponent::getParameter( 106 OMX_INDEXTYPE index, OMX_PTR params) { 107 Mutex::Autolock autoLock(mLock); 108 return internalGetParameter(index, params); 109 } 110 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 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 (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 147 OMX_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 || defParams->nSize 157 != sizeof(OMX_PARAM_PORTDEFINITIONTYPE)) { 158 return OMX_ErrorUndefined; 159 } 160 161 PortInfo *port = 162 &mPorts.editItemAt(defParams->nPortIndex); 163 164 if (defParams->nBufferSize != port->mDef.nBufferSize) { 165 CHECK_GE(defParams->nBufferSize, port->mDef.nBufferSize); 166 port->mDef.nBufferSize = defParams->nBufferSize; 167 } 168 169 if (defParams->nBufferCountActual 170 != port->mDef.nBufferCountActual) { 171 CHECK_GE(defParams->nBufferCountActual, 172 port->mDef.nBufferCountMin); 173 174 port->mDef.nBufferCountActual = defParams->nBufferCountActual; 175 } 176 177 return OMX_ErrorNone; 178 } 179 180 default: 181 return OMX_ErrorUnsupportedIndex; 182 } 183 } 184 185 OMX_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 238 OMX_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 261 OMX_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 308 OMX_ERRORTYPE SimpleSoftOMXComponent::emptyThisBuffer( 309 OMX_BUFFERHEADERTYPE *buffer) { 310 sp<AMessage> msg = new AMessage(kWhatEmptyThisBuffer, mHandler->id()); 311 msg->setPointer("header", buffer); 312 msg->post(); 313 314 return OMX_ErrorNone; 315 } 316 317 OMX_ERRORTYPE SimpleSoftOMXComponent::fillThisBuffer( 318 OMX_BUFFERHEADERTYPE *buffer) { 319 sp<AMessage> msg = new AMessage(kWhatFillThisBuffer, mHandler->id()); 320 msg->setPointer("header", buffer); 321 msg->post(); 322 323 return OMX_ErrorNone; 324 } 325 326 OMX_ERRORTYPE SimpleSoftOMXComponent::getState(OMX_STATETYPE *state) { 327 Mutex::Autolock autoLock(mLock); 328 329 *state = mState; 330 331 return OMX_ErrorNone; 332 } 333 334 void 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 392 void 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 420 void 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 453 void SimpleSoftOMXComponent::onReset() { 454 // no-op 455 } 456 457 void 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 491 void 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 CHECK_EQ((int)port->mTransition, (int)PortInfo::NONE); 509 510 for (size_t i = 0; i < port->mBuffers.size(); ++i) { 511 BufferInfo *buffer = &port->mBuffers.editItemAt(i); 512 513 if (!buffer->mOwnedByUs) { 514 continue; 515 } 516 517 buffer->mHeader->nFilledLen = 0; 518 buffer->mHeader->nOffset = 0; 519 buffer->mHeader->nFlags = 0; 520 521 buffer->mOwnedByUs = false; 522 523 if (port->mDef.eDir == OMX_DirInput) { 524 notifyEmptyBufferDone(buffer->mHeader); 525 } else { 526 CHECK_EQ(port->mDef.eDir, OMX_DirOutput); 527 528 notifyFillBufferDone(buffer->mHeader); 529 } 530 } 531 532 port->mQueue.clear(); 533 534 if (sendFlushComplete) { 535 notify(OMX_EventCmdComplete, OMX_CommandFlush, portIndex, NULL); 536 537 onPortFlushCompleted(portIndex); 538 } 539 } 540 541 void SimpleSoftOMXComponent::checkTransitions() { 542 if (mState != mTargetState) { 543 bool transitionComplete = true; 544 545 if (mState == OMX_StateLoaded) { 546 CHECK_EQ((int)mTargetState, (int)OMX_StateIdle); 547 548 for (size_t i = 0; i < mPorts.size(); ++i) { 549 const PortInfo &port = mPorts.itemAt(i); 550 if (port.mDef.bEnabled == OMX_FALSE) { 551 continue; 552 } 553 554 if (port.mDef.bPopulated == OMX_FALSE) { 555 transitionComplete = false; 556 break; 557 } 558 } 559 } else if (mTargetState == OMX_StateLoaded) { 560 CHECK_EQ((int)mState, (int)OMX_StateIdle); 561 562 for (size_t i = 0; i < mPorts.size(); ++i) { 563 const PortInfo &port = mPorts.itemAt(i); 564 if (port.mDef.bEnabled == OMX_FALSE) { 565 continue; 566 } 567 568 size_t n = port.mBuffers.size(); 569 570 if (n > 0) { 571 CHECK_LE(n, port.mDef.nBufferCountActual); 572 573 if (n == port.mDef.nBufferCountActual) { 574 CHECK_EQ((int)port.mDef.bPopulated, (int)OMX_TRUE); 575 } else { 576 CHECK_EQ((int)port.mDef.bPopulated, (int)OMX_FALSE); 577 } 578 579 transitionComplete = false; 580 break; 581 } 582 } 583 } 584 585 if (transitionComplete) { 586 mState = mTargetState; 587 588 if (mState == OMX_StateLoaded) { 589 onReset(); 590 } 591 592 notify(OMX_EventCmdComplete, OMX_CommandStateSet, mState, NULL); 593 } 594 } 595 596 for (size_t i = 0; i < mPorts.size(); ++i) { 597 PortInfo *port = &mPorts.editItemAt(i); 598 599 if (port->mTransition == PortInfo::DISABLING) { 600 if (port->mBuffers.empty()) { 601 ALOGV("Port %d now disabled.", i); 602 603 port->mTransition = PortInfo::NONE; 604 notify(OMX_EventCmdComplete, OMX_CommandPortDisable, i, NULL); 605 606 onPortEnableCompleted(i, false /* enabled */); 607 } 608 } else if (port->mTransition == PortInfo::ENABLING) { 609 if (port->mDef.bPopulated == OMX_TRUE) { 610 ALOGV("Port %d now enabled.", i); 611 612 port->mTransition = PortInfo::NONE; 613 port->mDef.bEnabled = OMX_TRUE; 614 notify(OMX_EventCmdComplete, OMX_CommandPortEnable, i, NULL); 615 616 onPortEnableCompleted(i, true /* enabled */); 617 } 618 } 619 } 620 } 621 622 void SimpleSoftOMXComponent::addPort(const OMX_PARAM_PORTDEFINITIONTYPE &def) { 623 CHECK_EQ(def.nPortIndex, mPorts.size()); 624 625 mPorts.push(); 626 PortInfo *info = &mPorts.editItemAt(mPorts.size() - 1); 627 info->mDef = def; 628 info->mTransition = PortInfo::NONE; 629 } 630 631 void SimpleSoftOMXComponent::onQueueFilled(OMX_U32 portIndex) { 632 } 633 634 void SimpleSoftOMXComponent::onPortFlushCompleted(OMX_U32 portIndex) { 635 } 636 637 void SimpleSoftOMXComponent::onPortEnableCompleted( 638 OMX_U32 portIndex, bool enabled) { 639 } 640 641 List<SimpleSoftOMXComponent::BufferInfo *> & 642 SimpleSoftOMXComponent::getPortQueue(OMX_U32 portIndex) { 643 CHECK_LT(portIndex, mPorts.size()); 644 return mPorts.editItemAt(portIndex).mQueue; 645 } 646 647 SimpleSoftOMXComponent::PortInfo *SimpleSoftOMXComponent::editPortInfo( 648 OMX_U32 portIndex) { 649 CHECK_LT(portIndex, mPorts.size()); 650 return &mPorts.editItemAt(portIndex); 651 } 652 653 } // namespace android 654