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