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