OMX.cpp revision 8ae1d0bdcef22f2bdd8d283e0e615f3ba6c3f4cd
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 211#if 0 212static void dumpRoles(OMXMaster *master, const char *name) { 213 Vector<String8> roles; 214 OMX_ERRORTYPE err = master->getRolesOfComponent(name, &roles); 215 216 if (err != OMX_ErrorNone) { 217 LOGE("Could not get roles for component '%s'.", name); 218 return; 219 } 220 221 if (roles.isEmpty()) { 222 LOGE("Component '%s' has NO roles!", name); 223 return; 224 } 225 226 LOGI("Component '%s' has the following roles:", name); 227 228 for (size_t i = 0; i < roles.size(); ++i) { 229 LOGI("%d) %s", i + 1, roles[i].string()); 230 } 231} 232#endif 233 234status_t OMX::listNodes(List<String8> *list) { 235 list->clear(); 236 237 OMX_U32 index = 0; 238 char componentName[256]; 239 while (mMaster->enumerateComponents( 240 componentName, sizeof(componentName), index) == OMX_ErrorNone) { 241 list->push_back(String8(componentName)); 242 243 // dumpRoles(mMaster, componentName); 244 245 ++index; 246 } 247 248 return OK; 249} 250 251status_t OMX::allocateNode( 252 const char *name, const sp<IOMXObserver> &observer, node_id *node) { 253 Mutex::Autolock autoLock(mLock); 254 255 *node = 0; 256 257 OMXNodeInstance *instance = new OMXNodeInstance(this, observer); 258 259 OMX_COMPONENTTYPE *handle; 260 OMX_ERRORTYPE err = mMaster->makeComponentInstance( 261 name, &OMXNodeInstance::kCallbacks, 262 instance, &handle); 263 264 if (err != OMX_ErrorNone) { 265 LOGV("FAILED to allocate omx component '%s'", name); 266 267 instance->onGetHandleFailed(); 268 269 return UNKNOWN_ERROR; 270 } 271 272 *node = makeNodeID(instance); 273 274 instance->setHandle(*node, handle); 275 276 mLiveNodes.add(observer->asBinder(), instance); 277 observer->asBinder()->linkToDeath(this); 278 279 return OK; 280} 281 282status_t OMX::freeNode(node_id node) { 283 OMXNodeInstance *instance = findInstance(node); 284 285 ssize_t index = mLiveNodes.indexOfKey(instance->observer()->asBinder()); 286 CHECK(index >= 0); 287 mLiveNodes.removeItemsAt(index); 288 instance->observer()->asBinder()->unlinkToDeath(this); 289 290 return instance->freeNode(mMaster); 291} 292 293status_t OMX::sendCommand( 294 node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) { 295 return findInstance(node)->sendCommand(cmd, param); 296} 297 298status_t OMX::getParameter( 299 node_id node, OMX_INDEXTYPE index, 300 void *params, size_t size) { 301 return findInstance(node)->getParameter( 302 index, params, size); 303} 304 305status_t OMX::setParameter( 306 node_id node, OMX_INDEXTYPE index, 307 const void *params, size_t size) { 308 return findInstance(node)->setParameter( 309 index, params, size); 310} 311 312status_t OMX::getConfig( 313 node_id node, OMX_INDEXTYPE index, 314 void *params, size_t size) { 315 return findInstance(node)->getConfig( 316 index, params, size); 317} 318 319status_t OMX::setConfig( 320 node_id node, OMX_INDEXTYPE index, 321 const void *params, size_t size) { 322 return findInstance(node)->setConfig( 323 index, params, size); 324} 325 326status_t OMX::useBuffer( 327 node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, 328 buffer_id *buffer) { 329 return findInstance(node)->useBuffer( 330 port_index, params, buffer); 331} 332 333status_t OMX::allocateBuffer( 334 node_id node, OMX_U32 port_index, size_t size, 335 buffer_id *buffer) { 336 return findInstance(node)->allocateBuffer( 337 port_index, size, buffer); 338} 339 340status_t OMX::allocateBufferWithBackup( 341 node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, 342 buffer_id *buffer) { 343 return findInstance(node)->allocateBufferWithBackup( 344 port_index, params, buffer); 345} 346 347status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) { 348 return findInstance(node)->freeBuffer( 349 port_index, buffer); 350} 351 352status_t OMX::fillBuffer(node_id node, buffer_id buffer) { 353 return findInstance(node)->fillBuffer(buffer); 354} 355 356status_t OMX::emptyBuffer( 357 node_id node, 358 buffer_id buffer, 359 OMX_U32 range_offset, OMX_U32 range_length, 360 OMX_U32 flags, OMX_TICKS timestamp) { 361 return findInstance(node)->emptyBuffer( 362 buffer, range_offset, range_length, flags, timestamp); 363} 364 365status_t OMX::getExtensionIndex( 366 node_id node, 367 const char *parameter_name, 368 OMX_INDEXTYPE *index) { 369 return findInstance(node)->getExtensionIndex( 370 parameter_name, index); 371} 372 373OMX_ERRORTYPE OMX::OnEvent( 374 node_id node, 375 OMX_IN OMX_EVENTTYPE eEvent, 376 OMX_IN OMX_U32 nData1, 377 OMX_IN OMX_U32 nData2, 378 OMX_IN OMX_PTR pEventData) { 379 LOGV("OnEvent(%d, %ld, %ld)", eEvent, nData1, nData2); 380 381 omx_message msg; 382 msg.type = omx_message::EVENT; 383 msg.node = node; 384 msg.u.event_data.event = eEvent; 385 msg.u.event_data.data1 = nData1; 386 msg.u.event_data.data2 = nData2; 387 388 mDispatcher->post(msg); 389 390 return OMX_ErrorNone; 391} 392 393OMX_ERRORTYPE OMX::OnEmptyBufferDone( 394 node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) { 395 LOGV("OnEmptyBufferDone buffer=%p", pBuffer); 396 397 omx_message msg; 398 msg.type = omx_message::EMPTY_BUFFER_DONE; 399 msg.node = node; 400 msg.u.buffer_data.buffer = pBuffer; 401 402 mDispatcher->post(msg); 403 404 return OMX_ErrorNone; 405} 406 407OMX_ERRORTYPE OMX::OnFillBufferDone( 408 node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) { 409 LOGV("OnFillBufferDone buffer=%p", pBuffer); 410 411 omx_message msg; 412 msg.type = omx_message::FILL_BUFFER_DONE; 413 msg.node = node; 414 msg.u.extended_buffer_data.buffer = pBuffer; 415 msg.u.extended_buffer_data.range_offset = pBuffer->nOffset; 416 msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen; 417 msg.u.extended_buffer_data.flags = pBuffer->nFlags; 418 msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp; 419 msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate; 420 421 mDispatcher->post(msg); 422 423 return OMX_ErrorNone; 424} 425 426OMX::node_id OMX::makeNodeID(OMXNodeInstance *instance) { 427 // mLock is already held. 428 429 node_id node = (node_id)++mNodeCounter; 430 mNodeIDToInstance.add(node, instance); 431 432 return node; 433} 434 435OMXNodeInstance *OMX::findInstance(node_id node) { 436 Mutex::Autolock autoLock(mLock); 437 438 ssize_t index = mNodeIDToInstance.indexOfKey(node); 439 440 return index < 0 ? NULL : mNodeIDToInstance.valueAt(index); 441} 442 443void OMX::invalidateNodeID(node_id node) { 444 Mutex::Autolock autoLock(mLock); 445 invalidateNodeID_l(node); 446} 447 448void OMX::invalidateNodeID_l(node_id node) { 449 // mLock is held. 450 mNodeIDToInstance.removeItem(node); 451} 452 453//////////////////////////////////////////////////////////////////////////////// 454 455sp<IOMXRenderer> OMX::createRenderer( 456 const sp<ISurface> &surface, 457 const char *componentName, 458 OMX_COLOR_FORMATTYPE colorFormat, 459 size_t encodedWidth, size_t encodedHeight, 460 size_t displayWidth, size_t displayHeight) { 461 Mutex::Autolock autoLock(mLock); 462 463 VideoRenderer *impl = NULL; 464 465 static void *libHandle = NULL; 466 467 if (!libHandle) { 468 libHandle = dlopen("libstagefrighthw.so", RTLD_NOW); 469 } 470 471 if (libHandle) { 472 typedef VideoRenderer *(*CreateRendererFunc)( 473 const sp<ISurface> &surface, 474 const char *componentName, 475 OMX_COLOR_FORMATTYPE colorFormat, 476 size_t displayWidth, size_t displayHeight, 477 size_t decodedWidth, size_t decodedHeight); 478 479 CreateRendererFunc func = 480 (CreateRendererFunc)dlsym( 481 libHandle, 482 "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20" 483 "OMX_COLOR_FORMATTYPEjjjj"); 484 485 if (func) { 486 impl = (*func)(surface, componentName, colorFormat, 487 displayWidth, displayHeight, encodedWidth, encodedHeight); 488 } 489 } 490 491 if (!impl) { 492 LOGW("Using software renderer."); 493 impl = new SoftwareRenderer( 494 colorFormat, 495 surface, 496 displayWidth, displayHeight, 497 encodedWidth, encodedHeight); 498 } 499 500 return new OMXRenderer(impl); 501} 502 503OMXRenderer::OMXRenderer(VideoRenderer *impl) 504 : mImpl(impl) { 505} 506 507OMXRenderer::~OMXRenderer() { 508 delete mImpl; 509 mImpl = NULL; 510} 511 512void OMXRenderer::render(IOMX::buffer_id buffer) { 513 OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer; 514 515 mImpl->render( 516 header->pBuffer + header->nOffset, 517 header->nFilledLen, 518 header->pPlatformPrivate); 519} 520 521} // namespace android 522 523