OMX.cpp revision 213addfaf4b359c69da4e9b4490c511d116845bb
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 138OMX::OMX() 139 : mMaster(new OMXMaster), 140 mDispatcher(new CallbackDispatcher(this)), 141 mNodeCounter(0) { 142} 143 144OMX::~OMX() { 145 delete mMaster; 146 mMaster = NULL; 147} 148 149void OMX::binderDied(const wp<IBinder> &the_late_who) { 150 OMXNodeInstance *instance; 151 152 { 153 Mutex::Autolock autoLock(mLock); 154 155 ssize_t index = mLiveNodes.indexOfKey(the_late_who); 156 CHECK(index >= 0); 157 158 instance = mLiveNodes.editValueAt(index); 159 mLiveNodes.removeItemsAt(index); 160 161 invalidateNodeID_l(instance->nodeID()); 162 } 163 164 instance->onObserverDied(mMaster); 165} 166 167bool OMX::livesLocally(pid_t pid) { 168 return pid == getpid(); 169} 170 171status_t OMX::listNodes(List<ComponentInfo> *list) { 172 list->clear(); 173 174 OMX_U32 index = 0; 175 char componentName[256]; 176 while (mMaster->enumerateComponents( 177 componentName, sizeof(componentName), index) == OMX_ErrorNone) { 178 list->push_back(ComponentInfo()); 179 ComponentInfo &info = *--list->end(); 180 181 info.mName = componentName; 182 183 Vector<String8> roles; 184 OMX_ERRORTYPE err = 185 mMaster->getRolesOfComponent(componentName, &roles); 186 187 if (err == OMX_ErrorNone) { 188 for (OMX_U32 i = 0; i < roles.size(); ++i) { 189 info.mRoles.push_back(roles[i]); 190 } 191 } 192 193 ++index; 194 } 195 196 return OK; 197} 198 199status_t OMX::allocateNode( 200 const char *name, const sp<IOMXObserver> &observer, node_id *node) { 201 Mutex::Autolock autoLock(mLock); 202 203 *node = 0; 204 205 OMXNodeInstance *instance = new OMXNodeInstance(this, observer); 206 207 OMX_COMPONENTTYPE *handle; 208 OMX_ERRORTYPE err = mMaster->makeComponentInstance( 209 name, &OMXNodeInstance::kCallbacks, 210 instance, &handle); 211 212 if (err != OMX_ErrorNone) { 213 LOGV("FAILED to allocate omx component '%s'", name); 214 215 instance->onGetHandleFailed(); 216 217 return UNKNOWN_ERROR; 218 } 219 220 *node = makeNodeID(instance); 221 222 instance->setHandle(*node, handle); 223 224 mLiveNodes.add(observer->asBinder(), instance); 225 observer->asBinder()->linkToDeath(this); 226 227 return OK; 228} 229 230status_t OMX::freeNode(node_id node) { 231 OMXNodeInstance *instance = findInstance(node); 232 233 ssize_t index = mLiveNodes.indexOfKey(instance->observer()->asBinder()); 234 CHECK(index >= 0); 235 mLiveNodes.removeItemsAt(index); 236 instance->observer()->asBinder()->unlinkToDeath(this); 237 238 return instance->freeNode(mMaster); 239} 240 241status_t OMX::sendCommand( 242 node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) { 243 return findInstance(node)->sendCommand(cmd, param); 244} 245 246status_t OMX::getParameter( 247 node_id node, OMX_INDEXTYPE index, 248 void *params, size_t size) { 249 return findInstance(node)->getParameter( 250 index, params, size); 251} 252 253status_t OMX::setParameter( 254 node_id node, OMX_INDEXTYPE index, 255 const void *params, size_t size) { 256 return findInstance(node)->setParameter( 257 index, params, size); 258} 259 260status_t OMX::getConfig( 261 node_id node, OMX_INDEXTYPE index, 262 void *params, size_t size) { 263 return findInstance(node)->getConfig( 264 index, params, size); 265} 266 267status_t OMX::setConfig( 268 node_id node, OMX_INDEXTYPE index, 269 const void *params, size_t size) { 270 return findInstance(node)->setConfig( 271 index, params, size); 272} 273 274status_t OMX::useBuffer( 275 node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, 276 buffer_id *buffer) { 277 return findInstance(node)->useBuffer( 278 port_index, params, buffer); 279} 280 281status_t OMX::allocateBuffer( 282 node_id node, OMX_U32 port_index, size_t size, 283 buffer_id *buffer, void **buffer_data) { 284 return findInstance(node)->allocateBuffer( 285 port_index, size, buffer, buffer_data); 286} 287 288status_t OMX::allocateBufferWithBackup( 289 node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, 290 buffer_id *buffer) { 291 return findInstance(node)->allocateBufferWithBackup( 292 port_index, params, buffer); 293} 294 295status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) { 296 return findInstance(node)->freeBuffer( 297 port_index, buffer); 298} 299 300status_t OMX::fillBuffer(node_id node, buffer_id buffer) { 301 return findInstance(node)->fillBuffer(buffer); 302} 303 304status_t OMX::emptyBuffer( 305 node_id node, 306 buffer_id buffer, 307 OMX_U32 range_offset, OMX_U32 range_length, 308 OMX_U32 flags, OMX_TICKS timestamp) { 309 return findInstance(node)->emptyBuffer( 310 buffer, range_offset, range_length, flags, timestamp); 311} 312 313status_t OMX::getExtensionIndex( 314 node_id node, 315 const char *parameter_name, 316 OMX_INDEXTYPE *index) { 317 return findInstance(node)->getExtensionIndex( 318 parameter_name, index); 319} 320 321OMX_ERRORTYPE OMX::OnEvent( 322 node_id node, 323 OMX_IN OMX_EVENTTYPE eEvent, 324 OMX_IN OMX_U32 nData1, 325 OMX_IN OMX_U32 nData2, 326 OMX_IN OMX_PTR pEventData) { 327 LOGV("OnEvent(%d, %ld, %ld)", eEvent, nData1, nData2); 328 329 omx_message msg; 330 msg.type = omx_message::EVENT; 331 msg.node = node; 332 msg.u.event_data.event = eEvent; 333 msg.u.event_data.data1 = nData1; 334 msg.u.event_data.data2 = nData2; 335 336 mDispatcher->post(msg); 337 338 return OMX_ErrorNone; 339} 340 341OMX_ERRORTYPE OMX::OnEmptyBufferDone( 342 node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) { 343 LOGV("OnEmptyBufferDone buffer=%p", pBuffer); 344 345 omx_message msg; 346 msg.type = omx_message::EMPTY_BUFFER_DONE; 347 msg.node = node; 348 msg.u.buffer_data.buffer = pBuffer; 349 350 mDispatcher->post(msg); 351 352 return OMX_ErrorNone; 353} 354 355OMX_ERRORTYPE OMX::OnFillBufferDone( 356 node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) { 357 LOGV("OnFillBufferDone buffer=%p", pBuffer); 358 359 omx_message msg; 360 msg.type = omx_message::FILL_BUFFER_DONE; 361 msg.node = node; 362 msg.u.extended_buffer_data.buffer = pBuffer; 363 msg.u.extended_buffer_data.range_offset = pBuffer->nOffset; 364 msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen; 365 msg.u.extended_buffer_data.flags = pBuffer->nFlags; 366 msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp; 367 msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate; 368 msg.u.extended_buffer_data.data_ptr = pBuffer->pBuffer; 369 370 mDispatcher->post(msg); 371 372 return OMX_ErrorNone; 373} 374 375OMX::node_id OMX::makeNodeID(OMXNodeInstance *instance) { 376 // mLock is already held. 377 378 node_id node = (node_id)++mNodeCounter; 379 mNodeIDToInstance.add(node, instance); 380 381 return node; 382} 383 384OMXNodeInstance *OMX::findInstance(node_id node) { 385 Mutex::Autolock autoLock(mLock); 386 387 ssize_t index = mNodeIDToInstance.indexOfKey(node); 388 389 return index < 0 ? NULL : mNodeIDToInstance.valueAt(index); 390} 391 392void OMX::invalidateNodeID(node_id node) { 393 Mutex::Autolock autoLock(mLock); 394 invalidateNodeID_l(node); 395} 396 397void OMX::invalidateNodeID_l(node_id node) { 398 // mLock is held. 399 mNodeIDToInstance.removeItem(node); 400} 401 402//////////////////////////////////////////////////////////////////////////////// 403 404sp<IOMXRenderer> OMX::createRenderer( 405 const sp<ISurface> &surface, 406 const char *componentName, 407 OMX_COLOR_FORMATTYPE colorFormat, 408 size_t encodedWidth, size_t encodedHeight, 409 size_t displayWidth, size_t displayHeight) { 410 Mutex::Autolock autoLock(mLock); 411 412 VideoRenderer *impl = NULL; 413 414 static void *libHandle = NULL; 415 416 if (!libHandle) { 417 libHandle = dlopen("libstagefrighthw.so", RTLD_NOW); 418 } 419 420 if (libHandle) { 421 typedef VideoRenderer *(*CreateRendererFunc)( 422 const sp<ISurface> &surface, 423 const char *componentName, 424 OMX_COLOR_FORMATTYPE colorFormat, 425 size_t displayWidth, size_t displayHeight, 426 size_t decodedWidth, size_t decodedHeight); 427 428 CreateRendererFunc func = 429 (CreateRendererFunc)dlsym( 430 libHandle, 431 "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20" 432 "OMX_COLOR_FORMATTYPEjjjj"); 433 434 if (func) { 435 impl = (*func)(surface, componentName, colorFormat, 436 displayWidth, displayHeight, encodedWidth, encodedHeight); 437 } 438 } 439 440 if (!impl) { 441 LOGW("Using software renderer."); 442 impl = new SoftwareRenderer( 443 colorFormat, 444 surface, 445 displayWidth, displayHeight, 446 encodedWidth, encodedHeight); 447 } 448 449 return new OMXRenderer(impl); 450} 451 452OMXRenderer::OMXRenderer(VideoRenderer *impl) 453 : mImpl(impl) { 454} 455 456OMXRenderer::~OMXRenderer() { 457 delete mImpl; 458 mImpl = NULL; 459} 460 461void OMXRenderer::render(IOMX::buffer_id buffer) { 462 OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer; 463 464 mImpl->render( 465 header->pBuffer + header->nOffset, 466 header->nFilledLen, 467 header->pPlatformPrivate); 468} 469 470} // namespace android 471 472