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