OMX.cpp revision 52e71f87f1dac8d2f6bcaf77bb25b78cba664c43
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#include <linux/prctl.h> 23#include <sys/resource.h> 24 25#include "../include/OMX.h" 26#include "OMXRenderer.h" 27 28#include "../include/OMXNodeInstance.h" 29#include "../include/SoftwareRenderer.h" 30 31#include <binder/IMemory.h> 32#include <media/stagefright/MediaDebug.h> 33#include <media/stagefright/VideoRenderer.h> 34#include <utils/threads.h> 35 36#include "OMXMaster.h" 37 38#include <OMX_Component.h> 39 40namespace android { 41 42//////////////////////////////////////////////////////////////////////////////// 43 44struct OMX::CallbackDispatcher : public RefBase { 45 CallbackDispatcher(OMX *owner); 46 47 void post(const omx_message &msg); 48 49protected: 50 virtual ~CallbackDispatcher(); 51 52private: 53 Mutex mLock; 54 55 OMX *mOwner; 56 bool mDone; 57 Condition mQueueChanged; 58 List<omx_message> mQueue; 59 60 pthread_t mThread; 61 62 void dispatch(const omx_message &msg); 63 64 static void *ThreadWrapper(void *me); 65 void threadEntry(); 66 67 CallbackDispatcher(const CallbackDispatcher &); 68 CallbackDispatcher &operator=(const CallbackDispatcher &); 69}; 70 71OMX::CallbackDispatcher::CallbackDispatcher(OMX *owner) 72 : mOwner(owner), 73 mDone(false) { 74 pthread_attr_t attr; 75 pthread_attr_init(&attr); 76 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 77 78 pthread_create(&mThread, &attr, ThreadWrapper, this); 79 80 pthread_attr_destroy(&attr); 81} 82 83OMX::CallbackDispatcher::~CallbackDispatcher() { 84 { 85 Mutex::Autolock autoLock(mLock); 86 87 mDone = true; 88 mQueueChanged.signal(); 89 } 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 OMXNodeInstance *instance = mOwner->findInstance(msg.node); 104 if (instance == NULL) { 105 LOGV("Would have dispatched a message to a node that's already gone."); 106 return; 107 } 108 instance->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 mDispatcher(new CallbackDispatcher(this)), 148 mNodeCounter(0) { 149} 150 151OMX::~OMX() { 152 delete mMaster; 153 mMaster = NULL; 154} 155 156void OMX::binderDied(const wp<IBinder> &the_late_who) { 157 OMXNodeInstance *instance; 158 159 { 160 Mutex::Autolock autoLock(mLock); 161 162 ssize_t index = mLiveNodes.indexOfKey(the_late_who); 163 CHECK(index >= 0); 164 165 instance = mLiveNodes.editValueAt(index); 166 mLiveNodes.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 229 instance->setHandle(*node, handle); 230 231 mLiveNodes.add(observer->asBinder(), instance); 232 observer->asBinder()->linkToDeath(this); 233 234 return OK; 235} 236 237status_t OMX::freeNode(node_id node) { 238 OMXNodeInstance *instance = findInstance(node); 239 240 ssize_t index = mLiveNodes.indexOfKey(instance->observer()->asBinder()); 241 CHECK(index >= 0); 242 mLiveNodes.removeItemsAt(index); 243 instance->observer()->asBinder()->unlinkToDeath(this); 244 245 return instance->freeNode(mMaster); 246} 247 248status_t OMX::sendCommand( 249 node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) { 250 return findInstance(node)->sendCommand(cmd, param); 251} 252 253status_t OMX::getParameter( 254 node_id node, OMX_INDEXTYPE index, 255 void *params, size_t size) { 256 return findInstance(node)->getParameter( 257 index, params, size); 258} 259 260status_t OMX::setParameter( 261 node_id node, OMX_INDEXTYPE index, 262 const void *params, size_t size) { 263 return findInstance(node)->setParameter( 264 index, params, size); 265} 266 267status_t OMX::getConfig( 268 node_id node, OMX_INDEXTYPE index, 269 void *params, size_t size) { 270 return findInstance(node)->getConfig( 271 index, params, size); 272} 273 274status_t OMX::setConfig( 275 node_id node, OMX_INDEXTYPE index, 276 const void *params, size_t size) { 277 return findInstance(node)->setConfig( 278 index, params, size); 279} 280 281status_t OMX::useBuffer( 282 node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, 283 buffer_id *buffer) { 284 return findInstance(node)->useBuffer( 285 port_index, params, buffer); 286} 287 288status_t OMX::allocateBuffer( 289 node_id node, OMX_U32 port_index, size_t size, 290 buffer_id *buffer, void **buffer_data) { 291 return findInstance(node)->allocateBuffer( 292 port_index, size, buffer, buffer_data); 293} 294 295status_t OMX::allocateBufferWithBackup( 296 node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, 297 buffer_id *buffer) { 298 return findInstance(node)->allocateBufferWithBackup( 299 port_index, params, buffer); 300} 301 302status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) { 303 return findInstance(node)->freeBuffer( 304 port_index, buffer); 305} 306 307status_t OMX::fillBuffer(node_id node, buffer_id buffer) { 308 return findInstance(node)->fillBuffer(buffer); 309} 310 311status_t OMX::emptyBuffer( 312 node_id node, 313 buffer_id buffer, 314 OMX_U32 range_offset, OMX_U32 range_length, 315 OMX_U32 flags, OMX_TICKS timestamp) { 316 return findInstance(node)->emptyBuffer( 317 buffer, range_offset, range_length, flags, timestamp); 318} 319 320status_t OMX::getExtensionIndex( 321 node_id node, 322 const char *parameter_name, 323 OMX_INDEXTYPE *index) { 324 return findInstance(node)->getExtensionIndex( 325 parameter_name, index); 326} 327 328OMX_ERRORTYPE OMX::OnEvent( 329 node_id node, 330 OMX_IN OMX_EVENTTYPE eEvent, 331 OMX_IN OMX_U32 nData1, 332 OMX_IN OMX_U32 nData2, 333 OMX_IN OMX_PTR pEventData) { 334 LOGV("OnEvent(%d, %ld, %ld)", eEvent, nData1, nData2); 335 336 omx_message msg; 337 msg.type = omx_message::EVENT; 338 msg.node = node; 339 msg.u.event_data.event = eEvent; 340 msg.u.event_data.data1 = nData1; 341 msg.u.event_data.data2 = nData2; 342 343 mDispatcher->post(msg); 344 345 return OMX_ErrorNone; 346} 347 348OMX_ERRORTYPE OMX::OnEmptyBufferDone( 349 node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) { 350 LOGV("OnEmptyBufferDone buffer=%p", pBuffer); 351 352 omx_message msg; 353 msg.type = omx_message::EMPTY_BUFFER_DONE; 354 msg.node = node; 355 msg.u.buffer_data.buffer = pBuffer; 356 357 mDispatcher->post(msg); 358 359 return OMX_ErrorNone; 360} 361 362OMX_ERRORTYPE OMX::OnFillBufferDone( 363 node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) { 364 LOGV("OnFillBufferDone buffer=%p", pBuffer); 365 366 omx_message msg; 367 msg.type = omx_message::FILL_BUFFER_DONE; 368 msg.node = node; 369 msg.u.extended_buffer_data.buffer = pBuffer; 370 msg.u.extended_buffer_data.range_offset = pBuffer->nOffset; 371 msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen; 372 msg.u.extended_buffer_data.flags = pBuffer->nFlags; 373 msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp; 374 msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate; 375 msg.u.extended_buffer_data.data_ptr = pBuffer->pBuffer; 376 377 mDispatcher->post(msg); 378 379 return OMX_ErrorNone; 380} 381 382OMX::node_id OMX::makeNodeID(OMXNodeInstance *instance) { 383 // mLock is already held. 384 385 node_id node = (node_id)++mNodeCounter; 386 mNodeIDToInstance.add(node, instance); 387 388 return node; 389} 390 391OMXNodeInstance *OMX::findInstance(node_id node) { 392 Mutex::Autolock autoLock(mLock); 393 394 ssize_t index = mNodeIDToInstance.indexOfKey(node); 395 396 return index < 0 ? NULL : mNodeIDToInstance.valueAt(index); 397} 398 399void OMX::invalidateNodeID(node_id node) { 400 Mutex::Autolock autoLock(mLock); 401 invalidateNodeID_l(node); 402} 403 404void OMX::invalidateNodeID_l(node_id node) { 405 // mLock is held. 406 mNodeIDToInstance.removeItem(node); 407} 408 409//////////////////////////////////////////////////////////////////////////////// 410 411struct SharedVideoRenderer : public VideoRenderer { 412 SharedVideoRenderer(void *libHandle, VideoRenderer *obj) 413 : mLibHandle(libHandle), 414 mObj(obj) { 415 } 416 417 virtual ~SharedVideoRenderer() { 418 delete mObj; 419 mObj = NULL; 420 421 dlclose(mLibHandle); 422 mLibHandle = NULL; 423 } 424 425 virtual void render( 426 const void *data, size_t size, void *platformPrivate) { 427 return mObj->render(data, size, platformPrivate); 428 } 429 430private: 431 void *mLibHandle; 432 VideoRenderer *mObj; 433 434 SharedVideoRenderer(const SharedVideoRenderer &); 435 SharedVideoRenderer &operator=(const SharedVideoRenderer &); 436}; 437 438sp<IOMXRenderer> OMX::createRenderer( 439 const sp<ISurface> &surface, 440 const char *componentName, 441 OMX_COLOR_FORMATTYPE colorFormat, 442 size_t encodedWidth, size_t encodedHeight, 443 size_t displayWidth, size_t displayHeight) { 444 Mutex::Autolock autoLock(mLock); 445 446 VideoRenderer *impl = NULL; 447 448 void *libHandle = dlopen("libstagefrighthw.so", RTLD_NOW); 449 450 if (libHandle) { 451 typedef VideoRenderer *(*CreateRendererFunc)( 452 const sp<ISurface> &surface, 453 const char *componentName, 454 OMX_COLOR_FORMATTYPE colorFormat, 455 size_t displayWidth, size_t displayHeight, 456 size_t decodedWidth, size_t decodedHeight); 457 458 CreateRendererFunc func = 459 (CreateRendererFunc)dlsym( 460 libHandle, 461 "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20" 462 "OMX_COLOR_FORMATTYPEjjjj"); 463 464 if (func) { 465 impl = (*func)(surface, componentName, colorFormat, 466 displayWidth, displayHeight, encodedWidth, encodedHeight); 467 468 if (impl) { 469 impl = new SharedVideoRenderer(libHandle, impl); 470 libHandle = NULL; 471 } 472 } 473 474 if (libHandle) { 475 dlclose(libHandle); 476 libHandle = NULL; 477 } 478 } 479 480 if (!impl) { 481 LOGW("Using software renderer."); 482 impl = new SoftwareRenderer( 483 colorFormat, 484 surface, 485 displayWidth, displayHeight, 486 encodedWidth, encodedHeight); 487 } 488 489 return new OMXRenderer(impl); 490} 491 492OMXRenderer::OMXRenderer(VideoRenderer *impl) 493 : mImpl(impl) { 494} 495 496OMXRenderer::~OMXRenderer() { 497 delete mImpl; 498 mImpl = NULL; 499} 500 501void OMXRenderer::render(IOMX::buffer_id buffer) { 502 OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer; 503 504 mImpl->render( 505 header->pBuffer + header->nOffset, 506 header->nFilledLen, 507 header->pPlatformPrivate); 508} 509 510} // namespace android 511 512