SimpleSoftOMXComponent.cpp revision 5a65e30064dc8dffa4f3d868f1c46038972c40c5
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 PRIORITY_AUDIO); 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->id()); 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 || 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 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->id()); 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->id()); 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 337 switch (msg->what()) { 338 case kWhatSendCommand: 339 { 340 int32_t cmd, param; 341 CHECK(msg->findInt32("cmd", &cmd)); 342 CHECK(msg->findInt32("param", ¶m)); 343 344 onSendCommand((OMX_COMMANDTYPE)cmd, (OMX_U32)param); 345 break; 346 } 347 348 case kWhatEmptyThisBuffer: 349 case kWhatFillThisBuffer: 350 { 351 OMX_BUFFERHEADERTYPE *header; 352 CHECK(msg->findPointer("header", (void **)&header)); 353 354 CHECK(mState == OMX_StateExecuting && mTargetState == mState); 355 356 bool found = false; 357 for (size_t i = 0; i < mPorts.size(); ++i) { 358 PortInfo *port = &mPorts.editItemAt(i); 359 360 for (size_t j = 0; j < port->mBuffers.size(); ++j) { 361 BufferInfo *buffer = &port->mBuffers.editItemAt(j); 362 363 if (buffer->mHeader == header) { 364 CHECK(!buffer->mOwnedByUs); 365 366 buffer->mOwnedByUs = true; 367 368 CHECK((msg->what() == kWhatEmptyThisBuffer 369 && port->mDef.eDir == OMX_DirInput) 370 || (port->mDef.eDir == OMX_DirOutput)); 371 372 port->mQueue.push_back(buffer); 373 onQueueFilled(i); 374 375 found = true; 376 break; 377 } 378 } 379 } 380 381 CHECK(found); 382 break; 383 } 384 385 default: 386 TRESPASS(); 387 break; 388 } 389} 390 391void SimpleSoftOMXComponent::onSendCommand( 392 OMX_COMMANDTYPE cmd, OMX_U32 param) { 393 switch (cmd) { 394 case OMX_CommandStateSet: 395 { 396 onChangeState((OMX_STATETYPE)param); 397 break; 398 } 399 400 case OMX_CommandPortEnable: 401 case OMX_CommandPortDisable: 402 { 403 onPortEnable(param, cmd == OMX_CommandPortEnable); 404 break; 405 } 406 407 case OMX_CommandFlush: 408 { 409 onPortFlush(param, true /* sendFlushComplete */); 410 break; 411 } 412 413 default: 414 TRESPASS(); 415 break; 416 } 417} 418 419void SimpleSoftOMXComponent::onChangeState(OMX_STATETYPE state) { 420 // We shouldn't be in a state transition already. 421 CHECK_EQ((int)mState, (int)mTargetState); 422 423 switch (mState) { 424 case OMX_StateLoaded: 425 CHECK_EQ((int)state, (int)OMX_StateIdle); 426 break; 427 case OMX_StateIdle: 428 CHECK(state == OMX_StateLoaded || state == OMX_StateExecuting); 429 break; 430 case OMX_StateExecuting: 431 { 432 CHECK_EQ((int)state, (int)OMX_StateIdle); 433 434 for (size_t i = 0; i < mPorts.size(); ++i) { 435 onPortFlush(i, false /* sendFlushComplete */); 436 } 437 438 mState = OMX_StateIdle; 439 notify(OMX_EventCmdComplete, OMX_CommandStateSet, state, NULL); 440 break; 441 } 442 443 default: 444 TRESPASS(); 445 } 446 447 mTargetState = state; 448 449 checkTransitions(); 450} 451 452void SimpleSoftOMXComponent::onPortEnable(OMX_U32 portIndex, bool enable) { 453 CHECK_LT(portIndex, mPorts.size()); 454 455 PortInfo *port = &mPorts.editItemAt(portIndex); 456 CHECK_EQ((int)port->mTransition, (int)PortInfo::NONE); 457 CHECK(port->mDef.bEnabled == !enable); 458 459 if (!enable) { 460 port->mDef.bEnabled = OMX_FALSE; 461 port->mTransition = PortInfo::DISABLING; 462 463 for (size_t i = 0; i < port->mBuffers.size(); ++i) { 464 BufferInfo *buffer = &port->mBuffers.editItemAt(i); 465 466 if (buffer->mOwnedByUs) { 467 buffer->mOwnedByUs = false; 468 469 if (port->mDef.eDir == OMX_DirInput) { 470 notifyEmptyBufferDone(buffer->mHeader); 471 } else { 472 CHECK_EQ(port->mDef.eDir, OMX_DirOutput); 473 notifyFillBufferDone(buffer->mHeader); 474 } 475 } 476 } 477 478 port->mQueue.clear(); 479 } else { 480 port->mTransition = PortInfo::ENABLING; 481 } 482 483 checkTransitions(); 484} 485 486void SimpleSoftOMXComponent::onPortFlush( 487 OMX_U32 portIndex, bool sendFlushComplete) { 488 if (portIndex == OMX_ALL) { 489 for (size_t i = 0; i < mPorts.size(); ++i) { 490 onPortFlush(i, sendFlushComplete); 491 } 492 493 if (sendFlushComplete) { 494 notify(OMX_EventCmdComplete, OMX_CommandFlush, OMX_ALL, NULL); 495 } 496 497 return; 498 } 499 500 CHECK_LT(portIndex, mPorts.size()); 501 502 PortInfo *port = &mPorts.editItemAt(portIndex); 503 CHECK_EQ((int)port->mTransition, (int)PortInfo::NONE); 504 505 for (size_t i = 0; i < port->mBuffers.size(); ++i) { 506 BufferInfo *buffer = &port->mBuffers.editItemAt(i); 507 508 if (!buffer->mOwnedByUs) { 509 continue; 510 } 511 512 buffer->mHeader->nFilledLen = 0; 513 buffer->mHeader->nOffset = 0; 514 buffer->mHeader->nFlags = 0; 515 516 buffer->mOwnedByUs = false; 517 518 if (port->mDef.eDir == OMX_DirInput) { 519 notifyEmptyBufferDone(buffer->mHeader); 520 } else { 521 CHECK_EQ(port->mDef.eDir, OMX_DirOutput); 522 523 notifyFillBufferDone(buffer->mHeader); 524 } 525 } 526 527 port->mQueue.clear(); 528 529 if (sendFlushComplete) { 530 notify(OMX_EventCmdComplete, OMX_CommandFlush, portIndex, NULL); 531 532 onPortFlushCompleted(portIndex); 533 } 534} 535 536void SimpleSoftOMXComponent::checkTransitions() { 537 if (mState != mTargetState) { 538 bool transitionComplete = true; 539 540 if (mState == OMX_StateLoaded) { 541 CHECK_EQ((int)mTargetState, (int)OMX_StateIdle); 542 543 for (size_t i = 0; i < mPorts.size(); ++i) { 544 const PortInfo &port = mPorts.itemAt(i); 545 if (port.mDef.bEnabled == OMX_FALSE) { 546 continue; 547 } 548 549 if (port.mDef.bPopulated == OMX_FALSE) { 550 transitionComplete = false; 551 break; 552 } 553 } 554 } else if (mTargetState == OMX_StateLoaded) { 555 CHECK_EQ((int)mState, (int)OMX_StateIdle); 556 557 for (size_t i = 0; i < mPorts.size(); ++i) { 558 const PortInfo &port = mPorts.itemAt(i); 559 if (port.mDef.bEnabled == OMX_FALSE) { 560 continue; 561 } 562 563 size_t n = port.mBuffers.size(); 564 565 if (n > 0) { 566 CHECK_LE(n, port.mDef.nBufferCountActual); 567 568 if (n == port.mDef.nBufferCountActual) { 569 CHECK_EQ((int)port.mDef.bPopulated, (int)OMX_TRUE); 570 } else { 571 CHECK_EQ((int)port.mDef.bPopulated, (int)OMX_FALSE); 572 } 573 574 transitionComplete = false; 575 break; 576 } 577 } 578 } 579 580 if (transitionComplete) { 581 mState = mTargetState; 582 583 notify(OMX_EventCmdComplete, OMX_CommandStateSet, mState, NULL); 584 } 585 } 586 587 for (size_t i = 0; i < mPorts.size(); ++i) { 588 PortInfo *port = &mPorts.editItemAt(i); 589 590 if (port->mTransition == PortInfo::DISABLING) { 591 if (port->mBuffers.empty()) { 592 LOGV("Port %d now disabled.", i); 593 594 port->mTransition = PortInfo::NONE; 595 notify(OMX_EventCmdComplete, OMX_CommandPortDisable, i, NULL); 596 597 onPortEnableCompleted(i, false /* enabled */); 598 } 599 } else if (port->mTransition == PortInfo::ENABLING) { 600 if (port->mDef.bPopulated == OMX_TRUE) { 601 LOGV("Port %d now enabled.", i); 602 603 port->mTransition = PortInfo::NONE; 604 port->mDef.bEnabled = OMX_TRUE; 605 notify(OMX_EventCmdComplete, OMX_CommandPortEnable, i, NULL); 606 607 onPortEnableCompleted(i, true /* enabled */); 608 } 609 } 610 } 611} 612 613void SimpleSoftOMXComponent::addPort(const OMX_PARAM_PORTDEFINITIONTYPE &def) { 614 CHECK_EQ(def.nPortIndex, mPorts.size()); 615 616 mPorts.push(); 617 PortInfo *info = &mPorts.editItemAt(mPorts.size() - 1); 618 info->mDef = def; 619 info->mTransition = PortInfo::NONE; 620} 621 622void SimpleSoftOMXComponent::onQueueFilled(OMX_U32 portIndex) { 623} 624 625void SimpleSoftOMXComponent::onPortFlushCompleted(OMX_U32 portIndex) { 626} 627 628void SimpleSoftOMXComponent::onPortEnableCompleted( 629 OMX_U32 portIndex, bool enabled) { 630} 631 632List<SimpleSoftOMXComponent::BufferInfo *> & 633SimpleSoftOMXComponent::getPortQueue(OMX_U32 portIndex) { 634 CHECK_LT(portIndex, mPorts.size()); 635 return mPorts.editItemAt(portIndex).mQueue; 636} 637 638SimpleSoftOMXComponent::PortInfo *SimpleSoftOMXComponent::editPortInfo( 639 OMX_U32 portIndex) { 640 CHECK_LT(portIndex, mPorts.size()); 641 return &mPorts.editItemAt(portIndex); 642} 643 644} // namespace android 645