OMX.cpp revision 26a48f304a8754d655e554178ffb6d7ba4c5aac3
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 35#include <OMX_AsString.h> 36#include <OMX_Component.h> 37 38namespace android { 39 40//////////////////////////////////////////////////////////////////////////////// 41 42// This provides the underlying Thread used by CallbackDispatcher. 43// Note that deriving CallbackDispatcher from Thread does not work. 44 45struct OMX::CallbackDispatcherThread : public Thread { 46 CallbackDispatcherThread(CallbackDispatcher *dispatcher) 47 : mDispatcher(dispatcher) { 48 } 49 50private: 51 CallbackDispatcher *mDispatcher; 52 53 bool threadLoop(); 54 55 CallbackDispatcherThread(const CallbackDispatcherThread &); 56 CallbackDispatcherThread &operator=(const CallbackDispatcherThread &); 57}; 58 59//////////////////////////////////////////////////////////////////////////////// 60 61struct OMX::CallbackDispatcher : public RefBase { 62 CallbackDispatcher(OMXNodeInstance *owner); 63 64 // Posts |msg| to the listener's queue. If |realTime| is true, the listener thread is notified 65 // that a new message is available on the queue. Otherwise, the message stays on the queue, but 66 // the listener is not notified of it. It will process this message when a subsequent message 67 // is posted with |realTime| set to true. 68 void post(const omx_message &msg, bool realTime = true); 69 70 bool loop(); 71 72protected: 73 virtual ~CallbackDispatcher(); 74 75private: 76 Mutex mLock; 77 78 OMXNodeInstance *mOwner; 79 bool mDone; 80 Condition mQueueChanged; 81 std::list<omx_message> mQueue; 82 83 sp<CallbackDispatcherThread> mThread; 84 85 void dispatch(std::list<omx_message> &messages); 86 87 CallbackDispatcher(const CallbackDispatcher &); 88 CallbackDispatcher &operator=(const CallbackDispatcher &); 89}; 90 91OMX::CallbackDispatcher::CallbackDispatcher(OMXNodeInstance *owner) 92 : mOwner(owner), 93 mDone(false) { 94 mThread = new CallbackDispatcherThread(this); 95 mThread->run("OMXCallbackDisp", ANDROID_PRIORITY_FOREGROUND); 96} 97 98OMX::CallbackDispatcher::~CallbackDispatcher() { 99 { 100 Mutex::Autolock autoLock(mLock); 101 102 mDone = true; 103 mQueueChanged.signal(); 104 } 105 106 // A join on self can happen if the last ref to CallbackDispatcher 107 // is released within the CallbackDispatcherThread loop 108 status_t status = mThread->join(); 109 if (status != WOULD_BLOCK) { 110 // Other than join to self, the only other error return codes are 111 // whatever readyToRun() returns, and we don't override that 112 CHECK_EQ(status, (status_t)NO_ERROR); 113 } 114} 115 116void OMX::CallbackDispatcher::post(const omx_message &msg, bool realTime) { 117 Mutex::Autolock autoLock(mLock); 118 119 mQueue.push_back(msg); 120 if (realTime) { 121 mQueueChanged.signal(); 122 } 123} 124 125void OMX::CallbackDispatcher::dispatch(std::list<omx_message> &messages) { 126 if (mOwner == NULL) { 127 ALOGV("Would have dispatched a message to a node that's already gone."); 128 return; 129 } 130 mOwner->onMessages(messages); 131} 132 133bool OMX::CallbackDispatcher::loop() { 134 for (;;) { 135 std::list<omx_message> messages; 136 137 { 138 Mutex::Autolock autoLock(mLock); 139 while (!mDone && mQueue.empty()) { 140 mQueueChanged.wait(mLock); 141 } 142 143 if (mDone) { 144 break; 145 } 146 147 messages.swap(mQueue); 148 } 149 150 dispatch(messages); 151 } 152 153 return false; 154} 155 156//////////////////////////////////////////////////////////////////////////////// 157 158bool OMX::CallbackDispatcherThread::threadLoop() { 159 return mDispatcher->loop(); 160} 161 162//////////////////////////////////////////////////////////////////////////////// 163 164OMX::OMX() 165 : mMaster(new OMXMaster), 166 mNodeCounter(0) { 167} 168 169OMX::~OMX() { 170 delete mMaster; 171 mMaster = NULL; 172} 173 174void OMX::binderDied(const wp<IBinder> &the_late_who) { 175 OMXNodeInstance *instance; 176 177 { 178 Mutex::Autolock autoLock(mLock); 179 180 ssize_t index = mLiveNodes.indexOfKey(the_late_who); 181 CHECK(index >= 0); 182 183 instance = mLiveNodes.editValueAt(index); 184 mLiveNodes.removeItemsAt(index); 185 186 index = mDispatchers.indexOfKey(instance->nodeID()); 187 CHECK(index >= 0); 188 mDispatchers.removeItemsAt(index); 189 190 invalidateNodeID_l(instance->nodeID()); 191 } 192 193 instance->onObserverDied(mMaster); 194} 195 196bool OMX::livesLocally(node_id /* node */, pid_t pid) { 197 return pid == getpid(); 198} 199 200status_t OMX::listNodes(List<ComponentInfo> *list) { 201 list->clear(); 202 203 OMX_U32 index = 0; 204 char componentName[256]; 205 while (mMaster->enumerateComponents( 206 componentName, sizeof(componentName), index) == OMX_ErrorNone) { 207 list->push_back(ComponentInfo()); 208 ComponentInfo &info = *--list->end(); 209 210 info.mName = componentName; 211 212 Vector<String8> roles; 213 OMX_ERRORTYPE err = 214 mMaster->getRolesOfComponent(componentName, &roles); 215 216 if (err == OMX_ErrorNone) { 217 for (OMX_U32 i = 0; i < roles.size(); ++i) { 218 info.mRoles.push_back(roles[i]); 219 } 220 } 221 222 ++index; 223 } 224 225 return OK; 226} 227 228status_t OMX::allocateNode( 229 const char *name, const sp<IOMXObserver> &observer, node_id *node) { 230 Mutex::Autolock autoLock(mLock); 231 232 *node = 0; 233 234 OMXNodeInstance *instance = new OMXNodeInstance(this, observer, name); 235 236 OMX_COMPONENTTYPE *handle; 237 OMX_ERRORTYPE err = mMaster->makeComponentInstance( 238 name, &OMXNodeInstance::kCallbacks, 239 instance, &handle); 240 241 if (err != OMX_ErrorNone) { 242 ALOGE("FAILED to allocate omx component '%s' err=%s(%#x)", name, asString(err), err); 243 244 instance->onGetHandleFailed(); 245 246 return StatusFromOMXError(err); 247 } 248 249 *node = makeNodeID(instance); 250 mDispatchers.add(*node, new CallbackDispatcher(instance)); 251 252 instance->setHandle(*node, handle); 253 254 mLiveNodes.add(IInterface::asBinder(observer), instance); 255 IInterface::asBinder(observer)->linkToDeath(this); 256 257 return OK; 258} 259 260status_t OMX::freeNode(node_id node) { 261 OMXNodeInstance *instance = findInstance(node); 262 263 { 264 Mutex::Autolock autoLock(mLock); 265 ssize_t index = mLiveNodes.indexOfKey(IInterface::asBinder(instance->observer())); 266 if (index < 0) { 267 // This could conceivably happen if the observer dies at roughly the 268 // same time that a client attempts to free the node explicitly. 269 return OK; 270 } 271 mLiveNodes.removeItemsAt(index); 272 } 273 274 IInterface::asBinder(instance->observer())->unlinkToDeath(this); 275 276 status_t err = instance->freeNode(mMaster); 277 278 { 279 Mutex::Autolock autoLock(mLock); 280 ssize_t index = mDispatchers.indexOfKey(node); 281 CHECK(index >= 0); 282 mDispatchers.removeItemsAt(index); 283 } 284 285 return err; 286} 287 288status_t OMX::sendCommand( 289 node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) { 290 return findInstance(node)->sendCommand(cmd, param); 291} 292 293status_t OMX::getParameter( 294 node_id node, OMX_INDEXTYPE index, 295 void *params, size_t size) { 296 ALOGV("getParameter(%u %#x %p %zd)", node, index, params, size); 297 return findInstance(node)->getParameter( 298 index, params, size); 299} 300 301status_t OMX::setParameter( 302 node_id node, OMX_INDEXTYPE index, 303 const void *params, size_t size) { 304 ALOGV("setParameter(%u %#x %p %zd)", node, index, params, size); 305 return findInstance(node)->setParameter( 306 index, params, size); 307} 308 309status_t OMX::getConfig( 310 node_id node, OMX_INDEXTYPE index, 311 void *params, size_t size) { 312 return findInstance(node)->getConfig( 313 index, params, size); 314} 315 316status_t OMX::setConfig( 317 node_id node, OMX_INDEXTYPE index, 318 const void *params, size_t size) { 319 return findInstance(node)->setConfig( 320 index, params, size); 321} 322 323status_t OMX::getState( 324 node_id node, OMX_STATETYPE* state) { 325 return findInstance(node)->getState( 326 state); 327} 328 329status_t OMX::enableGraphicBuffers( 330 node_id node, OMX_U32 port_index, OMX_BOOL enable) { 331 return findInstance(node)->enableGraphicBuffers(port_index, enable); 332} 333 334status_t OMX::getGraphicBufferUsage( 335 node_id node, OMX_U32 port_index, OMX_U32* usage) { 336 return findInstance(node)->getGraphicBufferUsage(port_index, usage); 337} 338 339status_t OMX::storeMetaDataInBuffers( 340 node_id node, OMX_U32 port_index, OMX_BOOL enable, MetadataBufferType *type) { 341 return findInstance(node)->storeMetaDataInBuffers(port_index, enable, type); 342} 343 344status_t OMX::prepareForAdaptivePlayback( 345 node_id node, OMX_U32 portIndex, OMX_BOOL enable, 346 OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight) { 347 return findInstance(node)->prepareForAdaptivePlayback( 348 portIndex, enable, maxFrameWidth, maxFrameHeight); 349} 350 351status_t OMX::configureVideoTunnelMode( 352 node_id node, OMX_U32 portIndex, OMX_BOOL tunneled, 353 OMX_U32 audioHwSync, native_handle_t **sidebandHandle) { 354 return findInstance(node)->configureVideoTunnelMode( 355 portIndex, tunneled, audioHwSync, sidebandHandle); 356} 357 358status_t OMX::useBuffer( 359 node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, 360 buffer_id *buffer, OMX_U32 allottedSize) { 361 return findInstance(node)->useBuffer( 362 port_index, params, buffer, allottedSize); 363} 364 365status_t OMX::useGraphicBuffer( 366 node_id node, OMX_U32 port_index, 367 const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer) { 368 return findInstance(node)->useGraphicBuffer( 369 port_index, graphicBuffer, buffer); 370} 371 372status_t OMX::updateGraphicBufferInMeta( 373 node_id node, OMX_U32 port_index, 374 const sp<GraphicBuffer> &graphicBuffer, buffer_id buffer) { 375 return findInstance(node)->updateGraphicBufferInMeta( 376 port_index, graphicBuffer, buffer); 377} 378 379status_t OMX::createInputSurface( 380 node_id node, OMX_U32 port_index, 381 sp<IGraphicBufferProducer> *bufferProducer, MetadataBufferType *type) { 382 return findInstance(node)->createInputSurface( 383 port_index, bufferProducer, type); 384} 385 386status_t OMX::createPersistentInputSurface( 387 sp<IGraphicBufferProducer> *bufferProducer, 388 sp<IGraphicBufferConsumer> *bufferConsumer) { 389 return OMXNodeInstance::createPersistentInputSurface( 390 bufferProducer, bufferConsumer); 391} 392 393status_t OMX::setInputSurface( 394 node_id node, OMX_U32 port_index, 395 const sp<IGraphicBufferConsumer> &bufferConsumer, MetadataBufferType *type) { 396 return findInstance(node)->setInputSurface(port_index, bufferConsumer, type); 397} 398 399 400status_t OMX::signalEndOfInputStream(node_id node) { 401 return findInstance(node)->signalEndOfInputStream(); 402} 403 404status_t OMX::allocateBuffer( 405 node_id node, OMX_U32 port_index, size_t size, 406 buffer_id *buffer, void **buffer_data) { 407 return findInstance(node)->allocateBuffer( 408 port_index, size, buffer, buffer_data); 409} 410 411status_t OMX::allocateBufferWithBackup( 412 node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, 413 buffer_id *buffer, OMX_U32 allottedSize) { 414 return findInstance(node)->allocateBufferWithBackup( 415 port_index, params, buffer, allottedSize); 416} 417 418status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) { 419 return findInstance(node)->freeBuffer( 420 port_index, buffer); 421} 422 423status_t OMX::fillBuffer(node_id node, buffer_id buffer, int fenceFd) { 424 return findInstance(node)->fillBuffer(buffer, fenceFd); 425} 426 427status_t OMX::emptyBuffer( 428 node_id node, 429 buffer_id buffer, 430 OMX_U32 range_offset, OMX_U32 range_length, 431 OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) { 432 return findInstance(node)->emptyBuffer( 433 buffer, range_offset, range_length, flags, timestamp, fenceFd); 434} 435 436status_t OMX::getExtensionIndex( 437 node_id node, 438 const char *parameter_name, 439 OMX_INDEXTYPE *index) { 440 return findInstance(node)->getExtensionIndex( 441 parameter_name, index); 442} 443 444status_t OMX::setInternalOption( 445 node_id node, 446 OMX_U32 port_index, 447 InternalOptionType type, 448 const void *data, 449 size_t size) { 450 return findInstance(node)->setInternalOption(port_index, type, data, size); 451} 452 453OMX_ERRORTYPE OMX::OnEvent( 454 node_id node, 455 OMX_IN OMX_EVENTTYPE eEvent, 456 OMX_IN OMX_U32 nData1, 457 OMX_IN OMX_U32 nData2, 458 OMX_IN OMX_PTR /* pEventData */) { 459 ALOGV("OnEvent(%d, %" PRIu32", %" PRIu32 ")", eEvent, nData1, nData2); 460 461 // Forward to OMXNodeInstance. 462 findInstance(node)->onEvent(eEvent, nData1, nData2); 463 464 omx_message msg; 465 msg.type = omx_message::EVENT; 466 msg.node = node; 467 msg.fenceFd = -1; 468 msg.u.event_data.event = eEvent; 469 msg.u.event_data.data1 = nData1; 470 msg.u.event_data.data2 = nData2; 471 472 findDispatcher(node)->post(msg); 473 474 return OMX_ErrorNone; 475} 476 477OMX_ERRORTYPE OMX::OnEmptyBufferDone( 478 node_id node, buffer_id buffer, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer, int fenceFd) { 479 ALOGV("OnEmptyBufferDone buffer=%p", pBuffer); 480 481 omx_message msg; 482 msg.type = omx_message::EMPTY_BUFFER_DONE; 483 msg.node = node; 484 msg.fenceFd = fenceFd; 485 msg.u.buffer_data.buffer = buffer; 486 487 findDispatcher(node)->post(msg); 488 489 return OMX_ErrorNone; 490} 491 492OMX_ERRORTYPE OMX::OnFillBufferDone( 493 node_id node, buffer_id buffer, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer, int fenceFd) { 494 ALOGV("OnFillBufferDone buffer=%p", pBuffer); 495 496 omx_message msg; 497 msg.type = omx_message::FILL_BUFFER_DONE; 498 msg.node = node; 499 msg.fenceFd = fenceFd; 500 msg.u.extended_buffer_data.buffer = buffer; 501 msg.u.extended_buffer_data.range_offset = pBuffer->nOffset; 502 msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen; 503 msg.u.extended_buffer_data.flags = pBuffer->nFlags; 504 msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp; 505 506 findDispatcher(node)->post(msg); 507 508 return OMX_ErrorNone; 509} 510 511OMX::node_id OMX::makeNodeID(OMXNodeInstance *instance) { 512 // mLock is already held. 513 514 node_id node = (node_id)++mNodeCounter; 515 mNodeIDToInstance.add(node, instance); 516 517 return node; 518} 519 520OMXNodeInstance *OMX::findInstance(node_id node) { 521 Mutex::Autolock autoLock(mLock); 522 523 ssize_t index = mNodeIDToInstance.indexOfKey(node); 524 525 return index < 0 ? NULL : mNodeIDToInstance.valueAt(index); 526} 527 528sp<OMX::CallbackDispatcher> OMX::findDispatcher(node_id node) { 529 Mutex::Autolock autoLock(mLock); 530 531 ssize_t index = mDispatchers.indexOfKey(node); 532 533 return index < 0 ? NULL : mDispatchers.valueAt(index); 534} 535 536void OMX::invalidateNodeID(node_id node) { 537 Mutex::Autolock autoLock(mLock); 538 invalidateNodeID_l(node); 539} 540 541void OMX::invalidateNodeID_l(node_id node) { 542 // mLock is held. 543 mNodeIDToInstance.removeItem(node); 544} 545 546} // namespace android 547