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->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 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::onPortEnable(OMX_U32 portIndex, bool enable) { 454 CHECK_LT(portIndex, mPorts.size()); 455 456 PortInfo *port = &mPorts.editItemAt(portIndex); 457 CHECK_EQ((int)port->mTransition, (int)PortInfo::NONE); 458 CHECK(port->mDef.bEnabled == !enable); 459 460 if (!enable) { 461 port->mDef.bEnabled = OMX_FALSE; 462 port->mTransition = PortInfo::DISABLING; 463 464 for (size_t i = 0; i < port->mBuffers.size(); ++i) { 465 BufferInfo *buffer = &port->mBuffers.editItemAt(i); 466 467 if (buffer->mOwnedByUs) { 468 buffer->mOwnedByUs = false; 469 470 if (port->mDef.eDir == OMX_DirInput) { 471 notifyEmptyBufferDone(buffer->mHeader); 472 } else { 473 CHECK_EQ(port->mDef.eDir, OMX_DirOutput); 474 notifyFillBufferDone(buffer->mHeader); 475 } 476 } 477 } 478 479 port->mQueue.clear(); 480 } else { 481 port->mTransition = PortInfo::ENABLING; 482 } 483 484 checkTransitions(); 485} 486 487void SimpleSoftOMXComponent::onPortFlush( 488 OMX_U32 portIndex, bool sendFlushComplete) { 489 if (portIndex == OMX_ALL) { 490 for (size_t i = 0; i < mPorts.size(); ++i) { 491 onPortFlush(i, sendFlushComplete); 492 } 493 494 if (sendFlushComplete) { 495 notify(OMX_EventCmdComplete, OMX_CommandFlush, OMX_ALL, NULL); 496 } 497 498 return; 499 } 500 501 CHECK_LT(portIndex, mPorts.size()); 502 503 PortInfo *port = &mPorts.editItemAt(portIndex); 504 CHECK_EQ((int)port->mTransition, (int)PortInfo::NONE); 505 506 for (size_t i = 0; i < port->mBuffers.size(); ++i) { 507 BufferInfo *buffer = &port->mBuffers.editItemAt(i); 508 509 if (!buffer->mOwnedByUs) { 510 continue; 511 } 512 513 buffer->mHeader->nFilledLen = 0; 514 buffer->mHeader->nOffset = 0; 515 buffer->mHeader->nFlags = 0; 516 517 buffer->mOwnedByUs = false; 518 519 if (port->mDef.eDir == OMX_DirInput) { 520 notifyEmptyBufferDone(buffer->mHeader); 521 } else { 522 CHECK_EQ(port->mDef.eDir, OMX_DirOutput); 523 524 notifyFillBufferDone(buffer->mHeader); 525 } 526 } 527 528 port->mQueue.clear(); 529 530 if (sendFlushComplete) { 531 notify(OMX_EventCmdComplete, OMX_CommandFlush, portIndex, NULL); 532 533 onPortFlushCompleted(portIndex); 534 } 535} 536 537void SimpleSoftOMXComponent::checkTransitions() { 538 if (mState != mTargetState) { 539 bool transitionComplete = true; 540 541 if (mState == OMX_StateLoaded) { 542 CHECK_EQ((int)mTargetState, (int)OMX_StateIdle); 543 544 for (size_t i = 0; i < mPorts.size(); ++i) { 545 const PortInfo &port = mPorts.itemAt(i); 546 if (port.mDef.bEnabled == OMX_FALSE) { 547 continue; 548 } 549 550 if (port.mDef.bPopulated == OMX_FALSE) { 551 transitionComplete = false; 552 break; 553 } 554 } 555 } else if (mTargetState == OMX_StateLoaded) { 556 CHECK_EQ((int)mState, (int)OMX_StateIdle); 557 558 for (size_t i = 0; i < mPorts.size(); ++i) { 559 const PortInfo &port = mPorts.itemAt(i); 560 if (port.mDef.bEnabled == OMX_FALSE) { 561 continue; 562 } 563 564 size_t n = port.mBuffers.size(); 565 566 if (n > 0) { 567 CHECK_LE(n, port.mDef.nBufferCountActual); 568 569 if (n == port.mDef.nBufferCountActual) { 570 CHECK_EQ((int)port.mDef.bPopulated, (int)OMX_TRUE); 571 } else { 572 CHECK_EQ((int)port.mDef.bPopulated, (int)OMX_FALSE); 573 } 574 575 transitionComplete = false; 576 break; 577 } 578 } 579 } 580 581 if (transitionComplete) { 582 mState = mTargetState; 583 584 notify(OMX_EventCmdComplete, OMX_CommandStateSet, mState, NULL); 585 } 586 } 587 588 for (size_t i = 0; i < mPorts.size(); ++i) { 589 PortInfo *port = &mPorts.editItemAt(i); 590 591 if (port->mTransition == PortInfo::DISABLING) { 592 if (port->mBuffers.empty()) { 593 ALOGV("Port %d now disabled.", i); 594 595 port->mTransition = PortInfo::NONE; 596 notify(OMX_EventCmdComplete, OMX_CommandPortDisable, i, NULL); 597 598 onPortEnableCompleted(i, false /* enabled */); 599 } 600 } else if (port->mTransition == PortInfo::ENABLING) { 601 if (port->mDef.bPopulated == OMX_TRUE) { 602 ALOGV("Port %d now enabled.", i); 603 604 port->mTransition = PortInfo::NONE; 605 port->mDef.bEnabled = OMX_TRUE; 606 notify(OMX_EventCmdComplete, OMX_CommandPortEnable, i, NULL); 607 608 onPortEnableCompleted(i, true /* enabled */); 609 } 610 } 611 } 612} 613 614void SimpleSoftOMXComponent::addPort(const OMX_PARAM_PORTDEFINITIONTYPE &def) { 615 CHECK_EQ(def.nPortIndex, mPorts.size()); 616 617 mPorts.push(); 618 PortInfo *info = &mPorts.editItemAt(mPorts.size() - 1); 619 info->mDef = def; 620 info->mTransition = PortInfo::NONE; 621} 622 623void SimpleSoftOMXComponent::onQueueFilled(OMX_U32 portIndex) { 624} 625 626void SimpleSoftOMXComponent::onPortFlushCompleted(OMX_U32 portIndex) { 627} 628 629void SimpleSoftOMXComponent::onPortEnableCompleted( 630 OMX_U32 portIndex, bool enabled) { 631} 632 633List<SimpleSoftOMXComponent::BufferInfo *> & 634SimpleSoftOMXComponent::getPortQueue(OMX_U32 portIndex) { 635 CHECK_LT(portIndex, mPorts.size()); 636 return mPorts.editItemAt(portIndex).mQueue; 637} 638 639SimpleSoftOMXComponent::PortInfo *SimpleSoftOMXComponent::editPortInfo( 640 OMX_U32 portIndex) { 641 CHECK_LT(portIndex, mPorts.size()); 642 return &mPorts.editItemAt(portIndex); 643} 644 645} // namespace android 646