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