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