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