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