1/* 2 * Copyright (C) 2009 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#include <inttypes.h> 18 19//#define LOG_NDEBUG 0 20#define LOG_TAG "OMX" 21#include <utils/Log.h> 22 23#include <dlfcn.h> 24 25#include "../include/OMX.h" 26 27#include "../include/OMXNodeInstance.h" 28 29#include <binder/IMemory.h> 30#include <media/stagefright/foundation/ADebug.h> 31#include <utils/threads.h> 32 33#include "OMXMaster.h" 34#include "OMXUtils.h" 35 36#include <OMX_AsString.h> 37#include <OMX_Component.h> 38#include <OMX_VideoExt.h> 39 40namespace android { 41 42// node ids are created by concatenating the pid with a 16-bit counter 43static size_t kMaxNodeInstances = (1 << 16); 44 45//////////////////////////////////////////////////////////////////////////////// 46 47// This provides the underlying Thread used by CallbackDispatcher. 48// Note that deriving CallbackDispatcher from Thread does not work. 49 50struct OMX::CallbackDispatcherThread : public Thread { 51 CallbackDispatcherThread(CallbackDispatcher *dispatcher) 52 : mDispatcher(dispatcher) { 53 } 54 55private: 56 CallbackDispatcher *mDispatcher; 57 58 bool threadLoop(); 59 60 CallbackDispatcherThread(const CallbackDispatcherThread &); 61 CallbackDispatcherThread &operator=(const CallbackDispatcherThread &); 62}; 63 64//////////////////////////////////////////////////////////////////////////////// 65 66struct OMX::CallbackDispatcher : public RefBase { 67 CallbackDispatcher(OMXNodeInstance *owner); 68 69 // Posts |msg| to the listener's queue. If |realTime| is true, the listener thread is notified 70 // that a new message is available on the queue. Otherwise, the message stays on the queue, but 71 // the listener is not notified of it. It will process this message when a subsequent message 72 // is posted with |realTime| set to true. 73 void post(const omx_message &msg, bool realTime = true); 74 75 bool loop(); 76 77protected: 78 virtual ~CallbackDispatcher(); 79 80private: 81 Mutex mLock; 82 83 OMXNodeInstance *mOwner; 84 bool mDone; 85 Condition mQueueChanged; 86 std::list<omx_message> mQueue; 87 88 sp<CallbackDispatcherThread> mThread; 89 90 void dispatch(std::list<omx_message> &messages); 91 92 CallbackDispatcher(const CallbackDispatcher &); 93 CallbackDispatcher &operator=(const CallbackDispatcher &); 94}; 95 96OMX::CallbackDispatcher::CallbackDispatcher(OMXNodeInstance *owner) 97 : mOwner(owner), 98 mDone(false) { 99 mThread = new CallbackDispatcherThread(this); 100 mThread->run("OMXCallbackDisp", ANDROID_PRIORITY_FOREGROUND); 101} 102 103OMX::CallbackDispatcher::~CallbackDispatcher() { 104 { 105 Mutex::Autolock autoLock(mLock); 106 107 mDone = true; 108 mQueueChanged.signal(); 109 } 110 111 // A join on self can happen if the last ref to CallbackDispatcher 112 // is released within the CallbackDispatcherThread loop 113 status_t status = mThread->join(); 114 if (status != WOULD_BLOCK) { 115 // Other than join to self, the only other error return codes are 116 // whatever readyToRun() returns, and we don't override that 117 CHECK_EQ(status, (status_t)NO_ERROR); 118 } 119} 120 121void OMX::CallbackDispatcher::post(const omx_message &msg, bool realTime) { 122 Mutex::Autolock autoLock(mLock); 123 124 mQueue.push_back(msg); 125 if (realTime) { 126 mQueueChanged.signal(); 127 } 128} 129 130void OMX::CallbackDispatcher::dispatch(std::list<omx_message> &messages) { 131 if (mOwner == NULL) { 132 ALOGV("Would have dispatched a message to a node that's already gone."); 133 return; 134 } 135 mOwner->onMessages(messages); 136} 137 138bool OMX::CallbackDispatcher::loop() { 139 for (;;) { 140 std::list<omx_message> messages; 141 142 { 143 Mutex::Autolock autoLock(mLock); 144 while (!mDone && mQueue.empty()) { 145 mQueueChanged.wait(mLock); 146 } 147 148 if (mDone) { 149 break; 150 } 151 152 messages.swap(mQueue); 153 } 154 155 dispatch(messages); 156 } 157 158 return false; 159} 160 161//////////////////////////////////////////////////////////////////////////////// 162 163bool OMX::CallbackDispatcherThread::threadLoop() { 164 return mDispatcher->loop(); 165} 166 167//////////////////////////////////////////////////////////////////////////////// 168 169OMX::OMX() 170 : mMaster(new OMXMaster), 171 mNodeCounter(0) { 172} 173 174OMX::~OMX() { 175 delete mMaster; 176 mMaster = NULL; 177} 178 179void OMX::binderDied(const wp<IBinder> &the_late_who) { 180 OMXNodeInstance *instance; 181 182 { 183 Mutex::Autolock autoLock(mLock); 184 185 ssize_t index = mLiveNodes.indexOfKey(the_late_who); 186 187 if (index < 0) { 188 ALOGE("b/27597103, nonexistent observer on binderDied"); 189 android_errorWriteLog(0x534e4554, "27597103"); 190 return; 191 } 192 193 instance = mLiveNodes.editValueAt(index); 194 mLiveNodes.removeItemsAt(index); 195 196 index = mDispatchers.indexOfKey(instance->nodeID()); 197 CHECK(index >= 0); 198 mDispatchers.removeItemsAt(index); 199 200 invalidateNodeID_l(instance->nodeID()); 201 } 202 203 instance->onObserverDied(mMaster); 204} 205 206bool OMX::isSecure(node_id node) { 207 OMXNodeInstance *instance = findInstance(node); 208 return (instance == NULL ? false : instance->isSecure()); 209} 210 211bool OMX::livesLocally(node_id /* node */, pid_t pid) { 212 return pid == getpid(); 213} 214 215status_t OMX::listNodes(List<ComponentInfo> *list) { 216 list->clear(); 217 218 OMX_U32 index = 0; 219 char componentName[256]; 220 while (mMaster->enumerateComponents( 221 componentName, sizeof(componentName), index) == OMX_ErrorNone) { 222 list->push_back(ComponentInfo()); 223 ComponentInfo &info = *--list->end(); 224 225 info.mName = componentName; 226 227 Vector<String8> roles; 228 OMX_ERRORTYPE err = 229 mMaster->getRolesOfComponent(componentName, &roles); 230 231 if (err == OMX_ErrorNone) { 232 for (OMX_U32 i = 0; i < roles.size(); ++i) { 233 info.mRoles.push_back(roles[i]); 234 } 235 } 236 237 ++index; 238 } 239 240 return OK; 241} 242 243status_t OMX::allocateNode( 244 const char *name, const sp<IOMXObserver> &observer, 245 sp<IBinder> *nodeBinder, node_id *node) { 246 Mutex::Autolock autoLock(mLock); 247 248 *node = 0; 249 if (nodeBinder != NULL) { 250 *nodeBinder = NULL; 251 } 252 253 if (mNodeIDToInstance.size() == kMaxNodeInstances) { 254 // all possible node IDs are in use 255 return NO_MEMORY; 256 } 257 258 OMXNodeInstance *instance = new OMXNodeInstance(this, observer, name); 259 260 OMX_COMPONENTTYPE *handle; 261 OMX_ERRORTYPE err = mMaster->makeComponentInstance( 262 name, &OMXNodeInstance::kCallbacks, 263 instance, &handle); 264 265 if (err != OMX_ErrorNone) { 266 ALOGE("FAILED to allocate omx component '%s' err=%s(%#x)", name, asString(err), err); 267 268 instance->onGetHandleFailed(); 269 270 return StatusFromOMXError(err); 271 } 272 273 *node = makeNodeID_l(instance); 274 mDispatchers.add(*node, new CallbackDispatcher(instance)); 275 276 instance->setHandle(*node, handle); 277 278 mLiveNodes.add(IInterface::asBinder(observer), instance); 279 IInterface::asBinder(observer)->linkToDeath(this); 280 281 return OK; 282} 283 284status_t OMX::freeNode(node_id node) { 285 OMXNodeInstance *instance = findInstance(node); 286 287 if (instance == NULL) { 288 return OK; 289 } 290 291 { 292 Mutex::Autolock autoLock(mLock); 293 ssize_t index = mLiveNodes.indexOfKey(IInterface::asBinder(instance->observer())); 294 if (index < 0) { 295 // This could conceivably happen if the observer dies at roughly the 296 // same time that a client attempts to free the node explicitly. 297 return OK; 298 } 299 mLiveNodes.removeItemsAt(index); 300 } 301 302 IInterface::asBinder(instance->observer())->unlinkToDeath(this); 303 304 status_t err = instance->freeNode(mMaster); 305 306 { 307 Mutex::Autolock autoLock(mLock); 308 ssize_t index = mDispatchers.indexOfKey(node); 309 CHECK(index >= 0); 310 mDispatchers.removeItemsAt(index); 311 } 312 313 return err; 314} 315 316status_t OMX::sendCommand( 317 node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) { 318 OMXNodeInstance *instance = findInstance(node); 319 320 if (instance == NULL) { 321 return NAME_NOT_FOUND; 322 } 323 324 return instance->sendCommand(cmd, param); 325} 326 327status_t OMX::getParameter( 328 node_id node, OMX_INDEXTYPE index, 329 void *params, size_t size) { 330 ALOGV("getParameter(%u %#x %p %zd)", node, index, params, size); 331 OMXNodeInstance *instance = findInstance(node); 332 333 if (instance == NULL) { 334 return NAME_NOT_FOUND; 335 } 336 337 return instance->getParameter( 338 index, params, size); 339} 340 341status_t OMX::setParameter( 342 node_id node, OMX_INDEXTYPE index, 343 const void *params, size_t size) { 344 ALOGV("setParameter(%u %#x %p %zd)", node, index, params, size); 345 OMXNodeInstance *instance = findInstance(node); 346 347 if (instance == NULL) { 348 return NAME_NOT_FOUND; 349 } 350 351 return instance->setParameter( 352 index, params, size); 353} 354 355status_t OMX::getConfig( 356 node_id node, OMX_INDEXTYPE index, 357 void *params, size_t size) { 358 OMXNodeInstance *instance = findInstance(node); 359 360 if (instance == NULL) { 361 return NAME_NOT_FOUND; 362 } 363 364 return instance->getConfig( 365 index, params, size); 366} 367 368status_t OMX::setConfig( 369 node_id node, OMX_INDEXTYPE index, 370 const void *params, size_t size) { 371 OMXNodeInstance *instance = findInstance(node); 372 373 if (instance == NULL) { 374 return NAME_NOT_FOUND; 375 } 376 377 return instance->setConfig( 378 index, params, size); 379} 380 381status_t OMX::getState( 382 node_id node, OMX_STATETYPE* state) { 383 OMXNodeInstance *instance = findInstance(node); 384 385 if (instance == NULL) { 386 return NAME_NOT_FOUND; 387 } 388 389 return instance->getState( 390 state); 391} 392 393status_t OMX::enableNativeBuffers( 394 node_id node, OMX_U32 port_index, OMX_BOOL graphic, OMX_BOOL enable) { 395 OMXNodeInstance *instance = findInstance(node); 396 397 if (instance == NULL) { 398 return NAME_NOT_FOUND; 399 } 400 401 return instance->enableNativeBuffers(port_index, graphic, enable); 402} 403 404status_t OMX::getGraphicBufferUsage( 405 node_id node, OMX_U32 port_index, OMX_U32* usage) { 406 OMXNodeInstance *instance = findInstance(node); 407 408 if (instance == NULL) { 409 return NAME_NOT_FOUND; 410 } 411 412 return instance->getGraphicBufferUsage(port_index, usage); 413} 414 415status_t OMX::storeMetaDataInBuffers( 416 node_id node, OMX_U32 port_index, OMX_BOOL enable, MetadataBufferType *type) { 417 OMXNodeInstance *instance = findInstance(node); 418 419 if (instance == NULL) { 420 return NAME_NOT_FOUND; 421 } 422 423 return instance->storeMetaDataInBuffers(port_index, enable, type); 424} 425 426status_t OMX::prepareForAdaptivePlayback( 427 node_id node, OMX_U32 portIndex, OMX_BOOL enable, 428 OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight) { 429 OMXNodeInstance *instance = findInstance(node); 430 431 if (instance == NULL) { 432 return NAME_NOT_FOUND; 433 } 434 435 return instance->prepareForAdaptivePlayback( 436 portIndex, enable, maxFrameWidth, maxFrameHeight); 437} 438 439status_t OMX::configureVideoTunnelMode( 440 node_id node, OMX_U32 portIndex, OMX_BOOL tunneled, 441 OMX_U32 audioHwSync, native_handle_t **sidebandHandle) { 442 OMXNodeInstance *instance = findInstance(node); 443 444 if (instance == NULL) { 445 return NAME_NOT_FOUND; 446 } 447 448 return instance->configureVideoTunnelMode( 449 portIndex, tunneled, audioHwSync, sidebandHandle); 450} 451 452status_t OMX::useBuffer( 453 node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, 454 buffer_id *buffer, OMX_U32 allottedSize) { 455 OMXNodeInstance *instance = findInstance(node); 456 457 if (instance == NULL) { 458 return NAME_NOT_FOUND; 459 } 460 461 return instance->useBuffer( 462 port_index, params, buffer, allottedSize); 463} 464 465status_t OMX::useGraphicBuffer( 466 node_id node, OMX_U32 port_index, 467 const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer) { 468 OMXNodeInstance *instance = findInstance(node); 469 470 if (instance == NULL) { 471 return NAME_NOT_FOUND; 472 } 473 474 return instance->useGraphicBuffer( 475 port_index, graphicBuffer, buffer); 476} 477 478status_t OMX::updateGraphicBufferInMeta( 479 node_id node, OMX_U32 port_index, 480 const sp<GraphicBuffer> &graphicBuffer, buffer_id buffer) { 481 OMXNodeInstance *instance = findInstance(node); 482 483 if (instance == NULL) { 484 return NAME_NOT_FOUND; 485 } 486 487 return instance->updateGraphicBufferInMeta( 488 port_index, graphicBuffer, buffer); 489} 490 491status_t OMX::updateNativeHandleInMeta( 492 node_id node, OMX_U32 port_index, 493 const sp<NativeHandle> &nativeHandle, buffer_id buffer) { 494 OMXNodeInstance *instance = findInstance(node); 495 496 if (instance == NULL) { 497 return NAME_NOT_FOUND; 498 } 499 500 return instance->updateNativeHandleInMeta( 501 port_index, nativeHandle, buffer); 502} 503 504status_t OMX::createInputSurface( 505 node_id node, OMX_U32 port_index, android_dataspace dataSpace, 506 sp<IGraphicBufferProducer> *bufferProducer, MetadataBufferType *type) { 507 OMXNodeInstance *instance = findInstance(node); 508 509 if (instance == NULL) { 510 return NAME_NOT_FOUND; 511 } 512 513 return instance->createInputSurface( 514 port_index, dataSpace, bufferProducer, type); 515} 516 517status_t OMX::createPersistentInputSurface( 518 sp<IGraphicBufferProducer> *bufferProducer, 519 sp<IGraphicBufferConsumer> *bufferConsumer) { 520 return OMXNodeInstance::createPersistentInputSurface( 521 bufferProducer, bufferConsumer); 522} 523 524status_t OMX::setInputSurface( 525 node_id node, OMX_U32 port_index, 526 const sp<IGraphicBufferConsumer> &bufferConsumer, MetadataBufferType *type) { 527 OMXNodeInstance *instance = findInstance(node); 528 529 if (instance == NULL) { 530 return NAME_NOT_FOUND; 531 } 532 533 return instance->setInputSurface(port_index, bufferConsumer, type); 534} 535 536 537status_t OMX::signalEndOfInputStream(node_id node) { 538 OMXNodeInstance *instance = findInstance(node); 539 540 if (instance == NULL) { 541 return NAME_NOT_FOUND; 542 } 543 544 return instance->signalEndOfInputStream(); 545} 546 547status_t OMX::allocateSecureBuffer( 548 node_id node, OMX_U32 port_index, size_t size, 549 buffer_id *buffer, void **buffer_data, sp<NativeHandle> *native_handle) { 550 OMXNodeInstance *instance = findInstance(node); 551 552 if (instance == NULL) { 553 return NAME_NOT_FOUND; 554 } 555 556 return instance->allocateSecureBuffer( 557 port_index, size, buffer, buffer_data, native_handle); 558} 559 560status_t OMX::allocateBufferWithBackup( 561 node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, 562 buffer_id *buffer, OMX_U32 allottedSize) { 563 OMXNodeInstance *instance = findInstance(node); 564 565 if (instance == NULL) { 566 return NAME_NOT_FOUND; 567 } 568 569 return instance->allocateBufferWithBackup( 570 port_index, params, buffer, allottedSize); 571} 572 573status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) { 574 OMXNodeInstance *instance = findInstance(node); 575 576 if (instance == NULL) { 577 return NAME_NOT_FOUND; 578 } 579 580 return instance->freeBuffer( 581 port_index, buffer); 582} 583 584status_t OMX::fillBuffer(node_id node, buffer_id buffer, int fenceFd) { 585 OMXNodeInstance *instance = findInstance(node); 586 587 if (instance == NULL) { 588 return NAME_NOT_FOUND; 589 } 590 591 return instance->fillBuffer(buffer, fenceFd); 592} 593 594status_t OMX::emptyBuffer( 595 node_id node, 596 buffer_id buffer, 597 OMX_U32 range_offset, OMX_U32 range_length, 598 OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) { 599 OMXNodeInstance *instance = findInstance(node); 600 601 if (instance == NULL) { 602 return NAME_NOT_FOUND; 603 } 604 605 return instance->emptyBuffer( 606 buffer, range_offset, range_length, flags, timestamp, fenceFd); 607} 608 609status_t OMX::getExtensionIndex( 610 node_id node, 611 const char *parameter_name, 612 OMX_INDEXTYPE *index) { 613 OMXNodeInstance *instance = findInstance(node); 614 615 if (instance == NULL) { 616 return NAME_NOT_FOUND; 617 } 618 619 return instance->getExtensionIndex( 620 parameter_name, index); 621} 622 623status_t OMX::setInternalOption( 624 node_id node, 625 OMX_U32 port_index, 626 InternalOptionType type, 627 const void *data, 628 size_t size) { 629 OMXNodeInstance *instance = findInstance(node); 630 631 if (instance == NULL) { 632 return NAME_NOT_FOUND; 633 } 634 635 return instance->setInternalOption(port_index, type, data, size); 636} 637 638OMX_ERRORTYPE OMX::OnEvent( 639 node_id node, 640 OMX_IN OMX_EVENTTYPE eEvent, 641 OMX_IN OMX_U32 nData1, 642 OMX_IN OMX_U32 nData2, 643 OMX_IN OMX_PTR pEventData) { 644 ALOGV("OnEvent(%d, %" PRIu32", %" PRIu32 ")", eEvent, nData1, nData2); 645 OMXNodeInstance *instance = findInstance(node); 646 647 if (instance == NULL) { 648 return OMX_ErrorComponentNotFound; 649 } 650 651 // Forward to OMXNodeInstance. 652 instance->onEvent(eEvent, nData1, nData2); 653 654 sp<OMX::CallbackDispatcher> dispatcher = findDispatcher(node); 655 656 // output rendered events are not processed as regular events until they hit the observer 657 if (eEvent == OMX_EventOutputRendered) { 658 if (pEventData == NULL) { 659 return OMX_ErrorBadParameter; 660 } 661 662 // process data from array 663 OMX_VIDEO_RENDEREVENTTYPE *renderData = (OMX_VIDEO_RENDEREVENTTYPE *)pEventData; 664 for (size_t i = 0; i < nData1; ++i) { 665 omx_message msg; 666 msg.type = omx_message::FRAME_RENDERED; 667 msg.node = node; 668 msg.fenceFd = -1; 669 msg.u.render_data.timestamp = renderData[i].nMediaTimeUs; 670 msg.u.render_data.nanoTime = renderData[i].nSystemTimeNs; 671 672 dispatcher->post(msg, false /* realTime */); 673 } 674 return OMX_ErrorNone; 675 } 676 677 omx_message msg; 678 msg.type = omx_message::EVENT; 679 msg.node = node; 680 msg.fenceFd = -1; 681 msg.u.event_data.event = eEvent; 682 msg.u.event_data.data1 = nData1; 683 msg.u.event_data.data2 = nData2; 684 685 dispatcher->post(msg, true /* realTime */); 686 687 return OMX_ErrorNone; 688} 689 690OMX_ERRORTYPE OMX::OnEmptyBufferDone( 691 node_id node, buffer_id buffer, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer, int fenceFd) { 692 ALOGV("OnEmptyBufferDone buffer=%p", pBuffer); 693 694 omx_message msg; 695 msg.type = omx_message::EMPTY_BUFFER_DONE; 696 msg.node = node; 697 msg.fenceFd = fenceFd; 698 msg.u.buffer_data.buffer = buffer; 699 700 findDispatcher(node)->post(msg); 701 702 return OMX_ErrorNone; 703} 704 705OMX_ERRORTYPE OMX::OnFillBufferDone( 706 node_id node, buffer_id buffer, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer, int fenceFd) { 707 ALOGV("OnFillBufferDone buffer=%p", pBuffer); 708 709 omx_message msg; 710 msg.type = omx_message::FILL_BUFFER_DONE; 711 msg.node = node; 712 msg.fenceFd = fenceFd; 713 msg.u.extended_buffer_data.buffer = buffer; 714 msg.u.extended_buffer_data.range_offset = pBuffer->nOffset; 715 msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen; 716 msg.u.extended_buffer_data.flags = pBuffer->nFlags; 717 msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp; 718 719 findDispatcher(node)->post(msg); 720 721 return OMX_ErrorNone; 722} 723 724OMX::node_id OMX::makeNodeID_l(OMXNodeInstance *instance) { 725 // mLock is already held. 726 727 node_id prefix = node_id(getpid() << 16); 728 node_id node = 0; 729 do { 730 if (++mNodeCounter >= kMaxNodeInstances) { 731 mNodeCounter = 0; // OK to use because we're combining with the pid 732 } 733 node = node_id(prefix | mNodeCounter); 734 } while (mNodeIDToInstance.indexOfKey(node) >= 0); 735 mNodeIDToInstance.add(node, instance); 736 737 return node; 738} 739 740OMXNodeInstance *OMX::findInstance(node_id node) { 741 Mutex::Autolock autoLock(mLock); 742 743 ssize_t index = mNodeIDToInstance.indexOfKey(node); 744 745 return index < 0 ? NULL : mNodeIDToInstance.valueAt(index); 746} 747 748sp<OMX::CallbackDispatcher> OMX::findDispatcher(node_id node) { 749 Mutex::Autolock autoLock(mLock); 750 751 ssize_t index = mDispatchers.indexOfKey(node); 752 753 return index < 0 ? NULL : mDispatchers.valueAt(index); 754} 755 756void OMX::invalidateNodeID(node_id node) { 757 Mutex::Autolock autoLock(mLock); 758 invalidateNodeID_l(node); 759} 760 761void OMX::invalidateNodeID_l(node_id node) { 762 // mLock is held. 763 mNodeIDToInstance.removeItem(node); 764} 765 766} // namespace android 767