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