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 37namespace android { 38 39//////////////////////////////////////////////////////////////////////////////// 40 41// This provides the underlying Thread used by CallbackDispatcher. 42// Note that deriving CallbackDispatcher from Thread does not work. 43 44struct OMX::CallbackDispatcherThread : public Thread { 45 CallbackDispatcherThread(CallbackDispatcher *dispatcher) 46 : mDispatcher(dispatcher) { 47 } 48 49private: 50 CallbackDispatcher *mDispatcher; 51 52 bool threadLoop(); 53 54 CallbackDispatcherThread(const CallbackDispatcherThread &); 55 CallbackDispatcherThread &operator=(const CallbackDispatcherThread &); 56}; 57 58//////////////////////////////////////////////////////////////////////////////// 59 60struct OMX::CallbackDispatcher : public RefBase { 61 CallbackDispatcher(OMXNodeInstance *owner); 62 63 void post(const omx_message &msg); 64 65 bool loop(); 66 67protected: 68 virtual ~CallbackDispatcher(); 69 70private: 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 86OMX::CallbackDispatcher::CallbackDispatcher(OMXNodeInstance *owner) 87 : mOwner(owner), 88 mDone(false) { 89 mThread = new CallbackDispatcherThread(this); 90 mThread->run("OMXCallbackDisp", ANDROID_PRIORITY_FOREGROUND); 91} 92 93OMX::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 111void OMX::CallbackDispatcher::post(const omx_message &msg) { 112 Mutex::Autolock autoLock(mLock); 113 114 mQueue.push_back(msg); 115 mQueueChanged.signal(); 116} 117 118void 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 126bool 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 152bool OMX::CallbackDispatcherThread::threadLoop() { 153 return mDispatcher->loop(); 154} 155 156//////////////////////////////////////////////////////////////////////////////// 157 158OMX::OMX() 159 : mMaster(new OMXMaster), 160 mNodeCounter(0) { 161} 162 163OMX::~OMX() { 164 delete mMaster; 165 mMaster = NULL; 166} 167 168void 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 190bool OMX::livesLocally(node_id /* node */, pid_t pid) { 191 return pid == getpid(); 192} 193 194status_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 222status_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, name); 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 254status_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 282status_t OMX::sendCommand( 283 node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) { 284 return findInstance(node)->sendCommand(cmd, param); 285} 286 287status_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 295status_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 303status_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 310status_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 317status_t OMX::getState( 318 node_id node, OMX_STATETYPE* state) { 319 return findInstance(node)->getState( 320 state); 321} 322 323status_t OMX::enableGraphicBuffers( 324 node_id node, OMX_U32 port_index, OMX_BOOL enable) { 325 return findInstance(node)->enableGraphicBuffers(port_index, enable); 326} 327 328status_t OMX::getGraphicBufferUsage( 329 node_id node, OMX_U32 port_index, OMX_U32* usage) { 330 return findInstance(node)->getGraphicBufferUsage(port_index, usage); 331} 332 333status_t OMX::storeMetaDataInBuffers( 334 node_id node, OMX_U32 port_index, OMX_BOOL enable) { 335 return findInstance(node)->storeMetaDataInBuffers(port_index, enable); 336} 337 338status_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 345status_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 352status_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 359status_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 366status_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 373status_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 380status_t OMX::signalEndOfInputStream(node_id node) { 381 return findInstance(node)->signalEndOfInputStream(); 382} 383 384status_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 391status_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 398status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) { 399 return findInstance(node)->freeBuffer( 400 port_index, buffer); 401} 402 403status_t OMX::fillBuffer(node_id node, buffer_id buffer) { 404 return findInstance(node)->fillBuffer(buffer); 405} 406 407status_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 416status_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 424status_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 433OMX_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 456OMX_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 470OMX_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 488OMX::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 497OMXNodeInstance *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 505sp<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 513void OMX::invalidateNodeID(node_id node) { 514 Mutex::Autolock autoLock(mLock); 515 invalidateNodeID_l(node); 516} 517 518void OMX::invalidateNodeID_l(node_id node) { 519 // mLock is held. 520 mNodeIDToInstance.removeItem(node); 521} 522 523} // namespace android 524