OMX.cpp revision 5b65c7043dada0c89d3a941742666ac40ea35746
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 28#include <binder/IMemory.h> 29#include <media/stagefright/MediaDebug.h> 30#include <media/stagefright/QComHardwareRenderer.h> 31#include <media/stagefright/SoftwareRenderer.h> 32#include <media/stagefright/TIHardwareRenderer.h> 33#include <media/stagefright/VideoRenderer.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 : mDispatcher(new CallbackDispatcher(this)), 184 mNodeCounter(0) { 185} 186 187void OMX::binderDied(const wp<IBinder> &the_late_who) { 188 OMXNodeInstance *instance; 189 190 { 191 Mutex::Autolock autoLock(mLock); 192 193 ssize_t index = mLiveNodes.indexOfKey(the_late_who); 194 CHECK(index >= 0); 195 196 instance = mLiveNodes.editValueAt(index); 197 mLiveNodes.removeItemsAt(index); 198 199 invalidateNodeID_l(instance->nodeID()); 200 } 201 202 instance->onObserverDied(); 203} 204 205status_t OMX::listNodes(List<String8> *list) { 206 OMX_MasterInit(); // XXX Put this somewhere else. 207 208 list->clear(); 209 210 OMX_U32 index = 0; 211 char componentName[256]; 212 while (OMX_MasterComponentNameEnum(componentName, sizeof(componentName), index) 213 == OMX_ErrorNone) { 214 list->push_back(String8(componentName)); 215 216 ++index; 217 } 218 219 return OK; 220} 221 222status_t OMX::allocateNode( 223 const char *name, const sp<IOMXObserver> &observer, node_id *node) { 224 Mutex::Autolock autoLock(mLock); 225 226 *node = 0; 227 228 OMX_MasterInit(); // XXX Put this somewhere else. 229 230 OMXNodeInstance *instance = new OMXNodeInstance(this, observer); 231 232 OMX_HANDLETYPE handle; 233 OMX_ERRORTYPE err = OMX_MasterGetHandle( 234 &handle, const_cast<char *>(name), instance, 235 &OMXNodeInstance::kCallbacks); 236 237 if (err != OMX_ErrorNone) { 238 LOGE("FAILED to allocate omx component '%s'", name); 239 240 instance->onGetHandleFailed(); 241 242 return UNKNOWN_ERROR; 243 } 244 245 *node = makeNodeID(instance); 246 247 instance->setHandle(*node, handle); 248 249 mLiveNodes.add(observer->asBinder(), instance); 250 observer->asBinder()->linkToDeath(this); 251 252 return OK; 253} 254 255status_t OMX::freeNode(node_id node) { 256 OMXNodeInstance *instance = findInstance(node); 257 258 ssize_t index = mLiveNodes.indexOfKey(instance->observer()->asBinder()); 259 CHECK(index >= 0); 260 mLiveNodes.removeItemsAt(index); 261 instance->observer()->asBinder()->unlinkToDeath(this); 262 263 return instance->freeNode(); 264} 265 266status_t OMX::sendCommand( 267 node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) { 268 return findInstance(node)->sendCommand(cmd, param); 269} 270 271status_t OMX::getParameter( 272 node_id node, OMX_INDEXTYPE index, 273 void *params, size_t size) { 274 return findInstance(node)->getParameter( 275 index, params, size); 276} 277 278status_t OMX::setParameter( 279 node_id node, OMX_INDEXTYPE index, 280 const void *params, size_t size) { 281 return findInstance(node)->setParameter( 282 index, params, size); 283} 284 285status_t OMX::getConfig( 286 node_id node, OMX_INDEXTYPE index, 287 void *params, size_t size) { 288 return findInstance(node)->getConfig( 289 index, params, size); 290} 291 292status_t OMX::setConfig( 293 node_id node, OMX_INDEXTYPE index, 294 const void *params, size_t size) { 295 return findInstance(node)->setConfig( 296 index, params, size); 297} 298 299status_t OMX::useBuffer( 300 node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, 301 buffer_id *buffer) { 302 return findInstance(node)->useBuffer( 303 port_index, params, buffer); 304} 305 306status_t OMX::allocateBuffer( 307 node_id node, OMX_U32 port_index, size_t size, 308 buffer_id *buffer) { 309 return findInstance(node)->allocateBuffer( 310 port_index, size, buffer); 311} 312 313status_t OMX::allocateBufferWithBackup( 314 node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, 315 buffer_id *buffer) { 316 return findInstance(node)->allocateBufferWithBackup( 317 port_index, params, buffer); 318} 319 320status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) { 321 return findInstance(node)->freeBuffer( 322 port_index, buffer); 323} 324 325status_t OMX::fillBuffer(node_id node, buffer_id buffer) { 326 return findInstance(node)->fillBuffer(buffer); 327} 328 329status_t OMX::emptyBuffer( 330 node_id node, 331 buffer_id buffer, 332 OMX_U32 range_offset, OMX_U32 range_length, 333 OMX_U32 flags, OMX_TICKS timestamp) { 334 return findInstance(node)->emptyBuffer( 335 buffer, range_offset, range_length, flags, timestamp); 336} 337 338status_t OMX::getExtensionIndex( 339 node_id node, 340 const char *parameter_name, 341 OMX_INDEXTYPE *index) { 342 return findInstance(node)->getExtensionIndex( 343 parameter_name, index); 344} 345 346OMX_ERRORTYPE OMX::OnEvent( 347 node_id node, 348 OMX_IN OMX_EVENTTYPE eEvent, 349 OMX_IN OMX_U32 nData1, 350 OMX_IN OMX_U32 nData2, 351 OMX_IN OMX_PTR pEventData) { 352 LOGV("OnEvent(%d, %ld, %ld)", eEvent, nData1, nData2); 353 354 omx_message msg; 355 msg.type = omx_message::EVENT; 356 msg.node = node; 357 msg.u.event_data.event = eEvent; 358 msg.u.event_data.data1 = nData1; 359 msg.u.event_data.data2 = nData2; 360 361 mDispatcher->post(msg); 362 363 return OMX_ErrorNone; 364} 365 366OMX_ERRORTYPE OMX::OnEmptyBufferDone( 367 node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) { 368 LOGV("OnEmptyBufferDone buffer=%p", pBuffer); 369 370 omx_message msg; 371 msg.type = omx_message::EMPTY_BUFFER_DONE; 372 msg.node = node; 373 msg.u.buffer_data.buffer = pBuffer; 374 375 mDispatcher->post(msg); 376 377 return OMX_ErrorNone; 378} 379 380OMX_ERRORTYPE OMX::OnFillBufferDone( 381 node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) { 382 LOGV("OnFillBufferDone buffer=%p", pBuffer); 383 384 omx_message msg; 385 msg.type = omx_message::FILL_BUFFER_DONE; 386 msg.node = node; 387 msg.u.extended_buffer_data.buffer = pBuffer; 388 msg.u.extended_buffer_data.range_offset = pBuffer->nOffset; 389 msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen; 390 msg.u.extended_buffer_data.flags = pBuffer->nFlags; 391 msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp; 392 msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate; 393 394 mDispatcher->post(msg); 395 396 return OMX_ErrorNone; 397} 398 399OMX::node_id OMX::makeNodeID(OMXNodeInstance *instance) { 400 // mLock is already held. 401 402 node_id node = (node_id)++mNodeCounter; 403 mNodeIDToInstance.add(node, instance); 404 405 return node; 406} 407 408OMXNodeInstance *OMX::findInstance(node_id node) { 409 Mutex::Autolock autoLock(mLock); 410 411 ssize_t index = mNodeIDToInstance.indexOfKey(node); 412 413 return index < 0 ? NULL : mNodeIDToInstance.valueAt(index); 414} 415 416void OMX::invalidateNodeID(node_id node) { 417 Mutex::Autolock autoLock(mLock); 418 invalidateNodeID_l(node); 419} 420 421void OMX::invalidateNodeID_l(node_id node) { 422 // mLock is held. 423 mNodeIDToInstance.removeItem(node); 424} 425 426//////////////////////////////////////////////////////////////////////////////// 427 428sp<IOMXRenderer> OMX::createRenderer( 429 const sp<ISurface> &surface, 430 const char *componentName, 431 OMX_COLOR_FORMATTYPE colorFormat, 432 size_t encodedWidth, size_t encodedHeight, 433 size_t displayWidth, size_t displayHeight) { 434 VideoRenderer *impl = NULL; 435 436 static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00; 437 438 if (colorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar 439 && !strncmp(componentName, "OMX.qcom.video.decoder.", 23)) { 440 LOGW("Using QComHardwareRenderer."); 441 impl = 442 new QComHardwareRenderer( 443 surface, 444 displayWidth, displayHeight, 445 encodedWidth, encodedHeight); 446 } else if (colorFormat == OMX_COLOR_FormatCbYCrY 447 && !strcmp(componentName, "OMX.TI.Video.Decoder")) { 448 LOGW("Using TIHardwareRenderer."); 449 impl = 450 new TIHardwareRenderer( 451 surface, 452 displayWidth, displayHeight, 453 encodedWidth, encodedHeight); 454 } else { 455 LOGW("Using software renderer."); 456 impl = new SoftwareRenderer( 457 colorFormat, 458 surface, 459 displayWidth, displayHeight, 460 encodedWidth, encodedHeight); 461 } 462 463 return new OMXRenderer(impl); 464} 465 466OMXRenderer::OMXRenderer(VideoRenderer *impl) 467 : mImpl(impl) { 468} 469 470OMXRenderer::~OMXRenderer() { 471 delete mImpl; 472 mImpl = NULL; 473} 474 475void OMXRenderer::render(IOMX::buffer_id buffer) { 476 OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer; 477 478 mImpl->render( 479 header->pBuffer + header->nOffset, 480 header->nFilledLen, 481 header->pPlatformPrivate); 482} 483 484} // namespace android 485 486