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