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