OMX.cpp revision db43b34c3428e480f8c4c66e7e88f4001f37f91e
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); 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 ALOGV("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 return findInstance(node)->getParameter( 291 index, params, size); 292} 293 294status_t OMX::setParameter( 295 node_id node, OMX_INDEXTYPE index, 296 const void *params, size_t size) { 297 return findInstance(node)->setParameter( 298 index, params, size); 299} 300 301status_t OMX::getConfig( 302 node_id node, OMX_INDEXTYPE index, 303 void *params, size_t size) { 304 return findInstance(node)->getConfig( 305 index, params, size); 306} 307 308status_t OMX::setConfig( 309 node_id node, OMX_INDEXTYPE index, 310 const void *params, size_t size) { 311 return findInstance(node)->setConfig( 312 index, params, size); 313} 314 315status_t OMX::getState( 316 node_id node, OMX_STATETYPE* state) { 317 return findInstance(node)->getState( 318 state); 319} 320 321status_t OMX::enableGraphicBuffers( 322 node_id node, OMX_U32 port_index, OMX_BOOL enable) { 323 return findInstance(node)->enableGraphicBuffers(port_index, enable); 324} 325 326status_t OMX::getGraphicBufferUsage( 327 node_id node, OMX_U32 port_index, OMX_U32* usage) { 328 return findInstance(node)->getGraphicBufferUsage(port_index, usage); 329} 330 331status_t OMX::storeMetaDataInBuffers( 332 node_id node, OMX_U32 port_index, OMX_BOOL enable) { 333 return findInstance(node)->storeMetaDataInBuffers(port_index, enable); 334} 335 336status_t OMX::prepareForAdaptivePlayback( 337 node_id node, OMX_U32 portIndex, OMX_BOOL enable, 338 OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight) { 339 return findInstance(node)->prepareForAdaptivePlayback( 340 portIndex, enable, maxFrameWidth, maxFrameHeight); 341} 342 343status_t OMX::useBuffer( 344 node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, 345 buffer_id *buffer) { 346 return findInstance(node)->useBuffer( 347 port_index, params, buffer); 348} 349 350status_t OMX::useGraphicBuffer( 351 node_id node, OMX_U32 port_index, 352 const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer) { 353 return findInstance(node)->useGraphicBuffer( 354 port_index, graphicBuffer, buffer); 355} 356 357status_t OMX::updateGraphicBufferInMeta( 358 node_id node, OMX_U32 port_index, 359 const sp<GraphicBuffer> &graphicBuffer, buffer_id buffer) { 360 return findInstance(node)->updateGraphicBufferInMeta( 361 port_index, graphicBuffer, buffer); 362} 363 364status_t OMX::createInputSurface( 365 node_id node, OMX_U32 port_index, 366 sp<IGraphicBufferProducer> *bufferProducer) { 367 return findInstance(node)->createInputSurface( 368 port_index, bufferProducer); 369} 370 371status_t OMX::signalEndOfInputStream(node_id node) { 372 return findInstance(node)->signalEndOfInputStream(); 373} 374 375status_t OMX::allocateBuffer( 376 node_id node, OMX_U32 port_index, size_t size, 377 buffer_id *buffer, void **buffer_data) { 378 return findInstance(node)->allocateBuffer( 379 port_index, size, buffer, buffer_data); 380} 381 382status_t OMX::allocateBufferWithBackup( 383 node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, 384 buffer_id *buffer) { 385 return findInstance(node)->allocateBufferWithBackup( 386 port_index, params, buffer); 387} 388 389status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) { 390 return findInstance(node)->freeBuffer( 391 port_index, buffer); 392} 393 394status_t OMX::fillBuffer(node_id node, buffer_id buffer) { 395 return findInstance(node)->fillBuffer(buffer); 396} 397 398status_t OMX::emptyBuffer( 399 node_id node, 400 buffer_id buffer, 401 OMX_U32 range_offset, OMX_U32 range_length, 402 OMX_U32 flags, OMX_TICKS timestamp) { 403 return findInstance(node)->emptyBuffer( 404 buffer, range_offset, range_length, flags, timestamp); 405} 406 407status_t OMX::getExtensionIndex( 408 node_id node, 409 const char *parameter_name, 410 OMX_INDEXTYPE *index) { 411 return findInstance(node)->getExtensionIndex( 412 parameter_name, index); 413} 414 415status_t OMX::setInternalOption( 416 node_id node, 417 OMX_U32 port_index, 418 InternalOptionType type, 419 const void *data, 420 size_t size) { 421 return findInstance(node)->setInternalOption(port_index, type, data, size); 422} 423 424OMX_ERRORTYPE OMX::OnEvent( 425 node_id node, 426 OMX_IN OMX_EVENTTYPE eEvent, 427 OMX_IN OMX_U32 nData1, 428 OMX_IN OMX_U32 nData2, 429 OMX_IN OMX_PTR /* pEventData */) { 430 ALOGV("OnEvent(%d, %" PRIu32", %" PRIu32 ")", eEvent, nData1, nData2); 431 432 // Forward to OMXNodeInstance. 433 findInstance(node)->onEvent(eEvent, nData1, nData2); 434 435 omx_message msg; 436 msg.type = omx_message::EVENT; 437 msg.node = node; 438 msg.u.event_data.event = eEvent; 439 msg.u.event_data.data1 = nData1; 440 msg.u.event_data.data2 = nData2; 441 442 findDispatcher(node)->post(msg); 443 444 return OMX_ErrorNone; 445} 446 447OMX_ERRORTYPE OMX::OnEmptyBufferDone( 448 node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) { 449 ALOGV("OnEmptyBufferDone buffer=%p", pBuffer); 450 451 omx_message msg; 452 msg.type = omx_message::EMPTY_BUFFER_DONE; 453 msg.node = node; 454 msg.u.buffer_data.buffer = pBuffer; 455 456 findDispatcher(node)->post(msg); 457 458 return OMX_ErrorNone; 459} 460 461OMX_ERRORTYPE OMX::OnFillBufferDone( 462 node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) { 463 ALOGV("OnFillBufferDone buffer=%p", pBuffer); 464 465 omx_message msg; 466 msg.type = omx_message::FILL_BUFFER_DONE; 467 msg.node = node; 468 msg.u.extended_buffer_data.buffer = pBuffer; 469 msg.u.extended_buffer_data.range_offset = pBuffer->nOffset; 470 msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen; 471 msg.u.extended_buffer_data.flags = pBuffer->nFlags; 472 msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp; 473 msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate; 474 msg.u.extended_buffer_data.data_ptr = pBuffer->pBuffer; 475 476 findDispatcher(node)->post(msg); 477 478 return OMX_ErrorNone; 479} 480 481OMX::node_id OMX::makeNodeID(OMXNodeInstance *instance) { 482 // mLock is already held. 483 484 node_id node = (node_id)(uintptr_t)++mNodeCounter; 485 mNodeIDToInstance.add(node, instance); 486 487 return node; 488} 489 490OMXNodeInstance *OMX::findInstance(node_id node) { 491 Mutex::Autolock autoLock(mLock); 492 493 ssize_t index = mNodeIDToInstance.indexOfKey(node); 494 495 return index < 0 ? NULL : mNodeIDToInstance.valueAt(index); 496} 497 498sp<OMX::CallbackDispatcher> OMX::findDispatcher(node_id node) { 499 Mutex::Autolock autoLock(mLock); 500 501 ssize_t index = mDispatchers.indexOfKey(node); 502 503 return index < 0 ? NULL : mDispatchers.valueAt(index); 504} 505 506void OMX::invalidateNodeID(node_id node) { 507 Mutex::Autolock autoLock(mLock); 508 invalidateNodeID_l(node); 509} 510 511void OMX::invalidateNodeID_l(node_id node) { 512 // mLock is held. 513 mNodeIDToInstance.removeItem(node); 514} 515 516} // namespace android 517