OMX.cpp revision ca9718b81d1edb3d094a11502737293dcb7526e7
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/MediaDebug.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_AUDIO); 89} 90 91OMX::CallbackDispatcher::~CallbackDispatcher() { 92 { 93 Mutex::Autolock autoLock(mLock); 94 95 mDone = true; 96 mQueueChanged.signal(); 97 } 98 99 // Don't call join on myself 100 status_t status = mThread->join(); 101 CHECK(status == NO_ERROR); 102} 103 104void OMX::CallbackDispatcher::post(const omx_message &msg) { 105 Mutex::Autolock autoLock(mLock); 106 107 mQueue.push_back(msg); 108 mQueueChanged.signal(); 109} 110 111void OMX::CallbackDispatcher::dispatch(const omx_message &msg) { 112 if (mOwner == NULL) { 113 LOGV("Would have dispatched a message to a node that's already gone."); 114 return; 115 } 116 mOwner->onMessage(msg); 117} 118 119bool OMX::CallbackDispatcher::loop() { 120 for (;;) { 121 omx_message msg; 122 123 { 124 Mutex::Autolock autoLock(mLock); 125 while (!mDone && mQueue.empty()) { 126 mQueueChanged.wait(mLock); 127 } 128 129 if (mDone) { 130 break; 131 } 132 133 msg = *mQueue.begin(); 134 mQueue.erase(mQueue.begin()); 135 } 136 137 dispatch(msg); 138 } 139 140 return false; 141} 142 143//////////////////////////////////////////////////////////////////////////////// 144 145bool OMX::CallbackDispatcherThread::threadLoop() { 146 return mDispatcher->loop(); 147} 148 149//////////////////////////////////////////////////////////////////////////////// 150 151OMX::OMX() 152 : mMaster(new OMXMaster), 153 mNodeCounter(0) { 154} 155 156OMX::~OMX() { 157 delete mMaster; 158 mMaster = NULL; 159} 160 161void OMX::binderDied(const wp<IBinder> &the_late_who) { 162 OMXNodeInstance *instance; 163 164 { 165 Mutex::Autolock autoLock(mLock); 166 167 ssize_t index = mLiveNodes.indexOfKey(the_late_who); 168 CHECK(index >= 0); 169 170 instance = mLiveNodes.editValueAt(index); 171 mLiveNodes.removeItemsAt(index); 172 173 index = mDispatchers.indexOfKey(instance->nodeID()); 174 CHECK(index >= 0); 175 mDispatchers.removeItemsAt(index); 176 177 invalidateNodeID_l(instance->nodeID()); 178 } 179 180 instance->onObserverDied(mMaster); 181} 182 183bool OMX::livesLocally(pid_t pid) { 184 return pid == getpid(); 185} 186 187status_t OMX::listNodes(List<ComponentInfo> *list) { 188 list->clear(); 189 190 OMX_U32 index = 0; 191 char componentName[256]; 192 while (mMaster->enumerateComponents( 193 componentName, sizeof(componentName), index) == OMX_ErrorNone) { 194 list->push_back(ComponentInfo()); 195 ComponentInfo &info = *--list->end(); 196 197 info.mName = componentName; 198 199 Vector<String8> roles; 200 OMX_ERRORTYPE err = 201 mMaster->getRolesOfComponent(componentName, &roles); 202 203 if (err == OMX_ErrorNone) { 204 for (OMX_U32 i = 0; i < roles.size(); ++i) { 205 info.mRoles.push_back(roles[i]); 206 } 207 } 208 209 ++index; 210 } 211 212 return OK; 213} 214 215status_t OMX::allocateNode( 216 const char *name, const sp<IOMXObserver> &observer, node_id *node) { 217 Mutex::Autolock autoLock(mLock); 218 219 *node = 0; 220 221 OMXNodeInstance *instance = new OMXNodeInstance(this, observer); 222 223 OMX_COMPONENTTYPE *handle; 224 OMX_ERRORTYPE err = mMaster->makeComponentInstance( 225 name, &OMXNodeInstance::kCallbacks, 226 instance, &handle); 227 228 if (err != OMX_ErrorNone) { 229 LOGV("FAILED to allocate omx component '%s'", name); 230 231 instance->onGetHandleFailed(); 232 233 return UNKNOWN_ERROR; 234 } 235 236 *node = makeNodeID(instance); 237 mDispatchers.add(*node, new CallbackDispatcher(instance)); 238 239 instance->setHandle(*node, handle); 240 241 mLiveNodes.add(observer->asBinder(), instance); 242 observer->asBinder()->linkToDeath(this); 243 244 return OK; 245} 246 247status_t OMX::freeNode(node_id node) { 248 OMXNodeInstance *instance = findInstance(node); 249 250 ssize_t index = mLiveNodes.indexOfKey(instance->observer()->asBinder()); 251 CHECK(index >= 0); 252 mLiveNodes.removeItemsAt(index); 253 254 instance->observer()->asBinder()->unlinkToDeath(this); 255 256 status_t err = instance->freeNode(mMaster); 257 258 { 259 Mutex::Autolock autoLock(mLock); 260 index = mDispatchers.indexOfKey(node); 261 CHECK(index >= 0); 262 mDispatchers.removeItemsAt(index); 263 } 264 265 return err; 266} 267 268status_t OMX::sendCommand( 269 node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) { 270 return findInstance(node)->sendCommand(cmd, param); 271} 272 273status_t OMX::getParameter( 274 node_id node, OMX_INDEXTYPE index, 275 void *params, size_t size) { 276 return findInstance(node)->getParameter( 277 index, params, size); 278} 279 280status_t OMX::setParameter( 281 node_id node, OMX_INDEXTYPE index, 282 const void *params, size_t size) { 283 return findInstance(node)->setParameter( 284 index, params, size); 285} 286 287status_t OMX::getConfig( 288 node_id node, OMX_INDEXTYPE index, 289 void *params, size_t size) { 290 return findInstance(node)->getConfig( 291 index, params, size); 292} 293 294status_t OMX::setConfig( 295 node_id node, OMX_INDEXTYPE index, 296 const void *params, size_t size) { 297 return findInstance(node)->setConfig( 298 index, params, size); 299} 300 301status_t OMX::enableGraphicBuffers( 302 node_id node, OMX_U32 port_index, OMX_BOOL enable) { 303 return findInstance(node)->enableGraphicBuffers(port_index, enable); 304} 305 306status_t OMX::getGraphicBufferUsage( 307 node_id node, OMX_U32 port_index, OMX_U32* usage) { 308 return findInstance(node)->getGraphicBufferUsage(port_index, usage); 309} 310 311status_t OMX::storeMetaDataInBuffers( 312 node_id node, OMX_U32 port_index, OMX_BOOL enable) { 313 return findInstance(node)->storeMetaDataInBuffers(port_index, enable); 314} 315 316status_t OMX::useBuffer( 317 node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, 318 buffer_id *buffer) { 319 return findInstance(node)->useBuffer( 320 port_index, params, buffer); 321} 322 323status_t OMX::useGraphicBuffer( 324 node_id node, OMX_U32 port_index, 325 const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer) { 326 return findInstance(node)->useGraphicBuffer( 327 port_index, graphicBuffer, buffer); 328} 329 330status_t OMX::allocateBuffer( 331 node_id node, OMX_U32 port_index, size_t size, 332 buffer_id *buffer, void **buffer_data) { 333 return findInstance(node)->allocateBuffer( 334 port_index, size, buffer, buffer_data); 335} 336 337status_t OMX::allocateBufferWithBackup( 338 node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, 339 buffer_id *buffer) { 340 return findInstance(node)->allocateBufferWithBackup( 341 port_index, params, buffer); 342} 343 344status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) { 345 return findInstance(node)->freeBuffer( 346 port_index, buffer); 347} 348 349status_t OMX::fillBuffer(node_id node, buffer_id buffer) { 350 return findInstance(node)->fillBuffer(buffer); 351} 352 353status_t OMX::emptyBuffer( 354 node_id node, 355 buffer_id buffer, 356 OMX_U32 range_offset, OMX_U32 range_length, 357 OMX_U32 flags, OMX_TICKS timestamp) { 358 return findInstance(node)->emptyBuffer( 359 buffer, range_offset, range_length, flags, timestamp); 360} 361 362status_t OMX::getExtensionIndex( 363 node_id node, 364 const char *parameter_name, 365 OMX_INDEXTYPE *index) { 366 return findInstance(node)->getExtensionIndex( 367 parameter_name, index); 368} 369 370OMX_ERRORTYPE OMX::OnEvent( 371 node_id node, 372 OMX_IN OMX_EVENTTYPE eEvent, 373 OMX_IN OMX_U32 nData1, 374 OMX_IN OMX_U32 nData2, 375 OMX_IN OMX_PTR pEventData) { 376 LOGV("OnEvent(%d, %ld, %ld)", eEvent, nData1, nData2); 377 378 omx_message msg; 379 msg.type = omx_message::EVENT; 380 msg.node = node; 381 msg.u.event_data.event = eEvent; 382 msg.u.event_data.data1 = nData1; 383 msg.u.event_data.data2 = nData2; 384 385 findDispatcher(node)->post(msg); 386 387 return OMX_ErrorNone; 388} 389 390OMX_ERRORTYPE OMX::OnEmptyBufferDone( 391 node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) { 392 LOGV("OnEmptyBufferDone buffer=%p", pBuffer); 393 394 omx_message msg; 395 msg.type = omx_message::EMPTY_BUFFER_DONE; 396 msg.node = node; 397 msg.u.buffer_data.buffer = pBuffer; 398 399 findDispatcher(node)->post(msg); 400 401 return OMX_ErrorNone; 402} 403 404OMX_ERRORTYPE OMX::OnFillBufferDone( 405 node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) { 406 LOGV("OnFillBufferDone buffer=%p", pBuffer); 407 408 omx_message msg; 409 msg.type = omx_message::FILL_BUFFER_DONE; 410 msg.node = node; 411 msg.u.extended_buffer_data.buffer = pBuffer; 412 msg.u.extended_buffer_data.range_offset = pBuffer->nOffset; 413 msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen; 414 msg.u.extended_buffer_data.flags = pBuffer->nFlags; 415 msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp; 416 msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate; 417 msg.u.extended_buffer_data.data_ptr = pBuffer->pBuffer; 418 419 findDispatcher(node)->post(msg); 420 421 return OMX_ErrorNone; 422} 423 424OMX::node_id OMX::makeNodeID(OMXNodeInstance *instance) { 425 // mLock is already held. 426 427 node_id node = (node_id)++mNodeCounter; 428 mNodeIDToInstance.add(node, instance); 429 430 return node; 431} 432 433OMXNodeInstance *OMX::findInstance(node_id node) { 434 Mutex::Autolock autoLock(mLock); 435 436 ssize_t index = mNodeIDToInstance.indexOfKey(node); 437 438 return index < 0 ? NULL : mNodeIDToInstance.valueAt(index); 439} 440 441sp<OMX::CallbackDispatcher> OMX::findDispatcher(node_id node) { 442 Mutex::Autolock autoLock(mLock); 443 444 ssize_t index = mDispatchers.indexOfKey(node); 445 446 return index < 0 ? NULL : mDispatchers.valueAt(index); 447} 448 449void OMX::invalidateNodeID(node_id node) { 450 Mutex::Autolock autoLock(mLock); 451 invalidateNodeID_l(node); 452} 453 454void OMX::invalidateNodeID_l(node_id node) { 455 // mLock is held. 456 mNodeIDToInstance.removeItem(node); 457} 458 459} // namespace android 460