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