OMX.cpp revision 89e69da4d86348409994c9dafbbb2634ccd7c196
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 <sys/socket.h> 22 23#include "OMX.h" 24#include "OMXRenderer.h" 25 26#include "pv_omxcore.h" 27 28#include "../include/QComHardwareRenderer.h" 29#include "../include/SoftwareRenderer.h" 30#include "../include/TIHardwareRenderer.h" 31 32#include <binder/IMemory.h> 33#include <media/stagefright/MediaDebug.h> 34#include <media/stagefright/VideoRenderer.h> 35 36#include <OMX_Component.h> 37 38namespace android { 39 40class NodeMeta { 41public: 42 NodeMeta(OMX *owner) 43 : mOwner(owner), 44 mHandle(NULL) { 45 } 46 47 OMX *owner() const { 48 return mOwner; 49 } 50 51 void setHandle(OMX_HANDLETYPE handle) { 52 CHECK_EQ(mHandle, NULL); 53 mHandle = handle; 54 } 55 56 OMX_HANDLETYPE handle() const { 57 return mHandle; 58 } 59 60 void setObserver(const sp<IOMXObserver> &observer) { 61 mObserver = observer; 62 } 63 64 sp<IOMXObserver> observer() { 65 return mObserver; 66 } 67 68private: 69 OMX *mOwner; 70 OMX_HANDLETYPE mHandle; 71 sp<IOMXObserver> mObserver; 72 73 NodeMeta(const NodeMeta &); 74 NodeMeta &operator=(const NodeMeta &); 75}; 76 77//////////////////////////////////////////////////////////////////////////////// 78 79struct OMX::CallbackDispatcher : public RefBase { 80 CallbackDispatcher(); 81 82 void post(const omx_message &msg); 83 84protected: 85 virtual ~CallbackDispatcher(); 86 87private: 88 Mutex mLock; 89 bool mDone; 90 Condition mQueueChanged; 91 List<omx_message> mQueue; 92 93 pthread_t mThread; 94 95 void dispatch(const omx_message &msg); 96 97 static void *ThreadWrapper(void *me); 98 void threadEntry(); 99 100 CallbackDispatcher(const CallbackDispatcher &); 101 CallbackDispatcher &operator=(const CallbackDispatcher &); 102}; 103 104OMX::CallbackDispatcher::CallbackDispatcher() 105 : mDone(false) { 106 pthread_attr_t attr; 107 pthread_attr_init(&attr); 108 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 109 110 pthread_create(&mThread, &attr, ThreadWrapper, this); 111 112 pthread_attr_destroy(&attr); 113} 114 115OMX::CallbackDispatcher::~CallbackDispatcher() { 116 { 117 Mutex::Autolock autoLock(mLock); 118 119 mDone = true; 120 mQueueChanged.signal(); 121 } 122 123 void *dummy; 124 pthread_join(mThread, &dummy); 125} 126 127void OMX::CallbackDispatcher::post(const omx_message &msg) { 128 Mutex::Autolock autoLock(mLock); 129 mQueue.push_back(msg); 130 mQueueChanged.signal(); 131} 132 133void OMX::CallbackDispatcher::dispatch(const omx_message &msg) { 134 NodeMeta *meta = static_cast<NodeMeta *>(msg.node); 135 136 sp<IOMXObserver> observer = meta->observer(); 137 if (observer.get() != NULL) { 138 observer->on_message(msg); 139 } 140} 141 142// static 143void *OMX::CallbackDispatcher::ThreadWrapper(void *me) { 144 static_cast<CallbackDispatcher *>(me)->threadEntry(); 145 146 return NULL; 147} 148 149void OMX::CallbackDispatcher::threadEntry() { 150 for (;;) { 151 omx_message msg; 152 153 { 154 Mutex::Autolock autoLock(mLock); 155 while (!mDone && mQueue.empty()) { 156 mQueueChanged.wait(mLock); 157 } 158 159 if (mDone) { 160 break; 161 } 162 163 msg = *mQueue.begin(); 164 mQueue.erase(mQueue.begin()); 165 } 166 167 dispatch(msg); 168 } 169} 170 171//////////////////////////////////////////////////////////////////////////////// 172 173class BufferMeta { 174public: 175 BufferMeta(OMX *owner, const sp<IMemory> &mem, bool is_backup = false) 176 : mOwner(owner), 177 mMem(mem), 178 mIsBackup(is_backup) { 179 } 180 181 BufferMeta(OMX *owner, size_t size) 182 : mOwner(owner), 183 mSize(size), 184 mIsBackup(false) { 185 } 186 187 void CopyFromOMX(const OMX_BUFFERHEADERTYPE *header) { 188 if (!mIsBackup) { 189 return; 190 } 191 192 memcpy((OMX_U8 *)mMem->pointer() + header->nOffset, 193 header->pBuffer + header->nOffset, 194 header->nFilledLen); 195 } 196 197 void CopyToOMX(const OMX_BUFFERHEADERTYPE *header) { 198 if (!mIsBackup) { 199 return; 200 } 201 202 memcpy(header->pBuffer + header->nOffset, 203 (const OMX_U8 *)mMem->pointer() + header->nOffset, 204 header->nFilledLen); 205 } 206 207private: 208 OMX *mOwner; 209 sp<IMemory> mMem; 210 size_t mSize; 211 bool mIsBackup; 212 213 BufferMeta(const BufferMeta &); 214 BufferMeta &operator=(const BufferMeta &); 215}; 216 217// static 218OMX_CALLBACKTYPE OMX::kCallbacks = { 219 &OnEvent, &OnEmptyBufferDone, &OnFillBufferDone 220}; 221 222// static 223OMX_ERRORTYPE OMX::OnEvent( 224 OMX_IN OMX_HANDLETYPE hComponent, 225 OMX_IN OMX_PTR pAppData, 226 OMX_IN OMX_EVENTTYPE eEvent, 227 OMX_IN OMX_U32 nData1, 228 OMX_IN OMX_U32 nData2, 229 OMX_IN OMX_PTR pEventData) { 230 NodeMeta *meta = static_cast<NodeMeta *>(pAppData); 231 return meta->owner()->OnEvent(meta, eEvent, nData1, nData2, pEventData); 232} 233 234// static 235OMX_ERRORTYPE OMX::OnEmptyBufferDone( 236 OMX_IN OMX_HANDLETYPE hComponent, 237 OMX_IN OMX_PTR pAppData, 238 OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) { 239 NodeMeta *meta = static_cast<NodeMeta *>(pAppData); 240 return meta->owner()->OnEmptyBufferDone(meta, pBuffer); 241} 242 243// static 244OMX_ERRORTYPE OMX::OnFillBufferDone( 245 OMX_IN OMX_HANDLETYPE hComponent, 246 OMX_IN OMX_PTR pAppData, 247 OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) { 248 NodeMeta *meta = static_cast<NodeMeta *>(pAppData); 249 return meta->owner()->OnFillBufferDone(meta, pBuffer); 250} 251 252OMX::OMX() 253 : mDispatcher(new CallbackDispatcher) { 254} 255 256status_t OMX::list_nodes(List<String8> *list) { 257 OMX_MasterInit(); // XXX Put this somewhere else. 258 259 list->clear(); 260 261 OMX_U32 index = 0; 262 char componentName[256]; 263 while (OMX_MasterComponentNameEnum(componentName, sizeof(componentName), index) 264 == OMX_ErrorNone) { 265 list->push_back(String8(componentName)); 266 267 ++index; 268 } 269 270 return OK; 271} 272 273status_t OMX::allocate_node(const char *name, node_id *node) { 274 Mutex::Autolock autoLock(mLock); 275 276 *node = 0; 277 278 OMX_MasterInit(); // XXX Put this somewhere else. 279 280 NodeMeta *meta = new NodeMeta(this); 281 282 OMX_HANDLETYPE handle; 283 OMX_ERRORTYPE err = OMX_MasterGetHandle( 284 &handle, const_cast<char *>(name), meta, &kCallbacks); 285 286 if (err != OMX_ErrorNone) { 287 LOGV("FAILED to allocate omx component '%s'", name); 288 289 delete meta; 290 meta = NULL; 291 292 return UNKNOWN_ERROR; 293 } 294 295 meta->setHandle(handle); 296 297 *node = meta; 298 299 return OK; 300} 301 302status_t OMX::free_node(node_id node) { 303 Mutex::Autolock autoLock(mLock); 304 305 NodeMeta *meta = static_cast<NodeMeta *>(node); 306 307 OMX_ERRORTYPE err = OMX_MasterFreeHandle(meta->handle()); 308 309 delete meta; 310 meta = NULL; 311 312 return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK; 313} 314 315status_t OMX::send_command( 316 node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) { 317 Mutex::Autolock autoLock(mLock); 318 319 NodeMeta *meta = static_cast<NodeMeta *>(node); 320 OMX_ERRORTYPE err = OMX_SendCommand(meta->handle(), cmd, param, NULL); 321 322 return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK; 323} 324 325status_t OMX::get_parameter( 326 node_id node, OMX_INDEXTYPE index, 327 void *params, size_t size) { 328 Mutex::Autolock autoLock(mLock); 329 330 NodeMeta *meta = static_cast<NodeMeta *>(node); 331 OMX_ERRORTYPE err = OMX_GetParameter(meta->handle(), index, params); 332 333 return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK; 334} 335 336status_t OMX::set_parameter( 337 node_id node, OMX_INDEXTYPE index, 338 const void *params, size_t size) { 339 Mutex::Autolock autoLock(mLock); 340 341 NodeMeta *meta = static_cast<NodeMeta *>(node); 342 OMX_ERRORTYPE err = 343 OMX_SetParameter(meta->handle(), index, const_cast<void *>(params)); 344 345 return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK; 346} 347 348status_t OMX::get_config( 349 node_id node, OMX_INDEXTYPE index, 350 void *params, size_t size) { 351 Mutex::Autolock autoLock(mLock); 352 353 NodeMeta *meta = static_cast<NodeMeta *>(node); 354 OMX_ERRORTYPE err = OMX_GetConfig(meta->handle(), index, params); 355 356 return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK; 357} 358 359status_t OMX::set_config( 360 node_id node, OMX_INDEXTYPE index, 361 const void *params, size_t size) { 362 Mutex::Autolock autoLock(mLock); 363 364 NodeMeta *meta = static_cast<NodeMeta *>(node); 365 OMX_ERRORTYPE err = 366 OMX_SetConfig(meta->handle(), index, const_cast<void *>(params)); 367 368 return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK; 369} 370 371status_t OMX::use_buffer( 372 node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, 373 buffer_id *buffer) { 374 Mutex::Autolock autoLock(mLock); 375 376 BufferMeta *buffer_meta = new BufferMeta(this, params); 377 378 OMX_BUFFERHEADERTYPE *header; 379 380 NodeMeta *node_meta = static_cast<NodeMeta *>(node); 381 OMX_ERRORTYPE err = 382 OMX_UseBuffer(node_meta->handle(), &header, port_index, buffer_meta, 383 params->size(), static_cast<OMX_U8 *>(params->pointer())); 384 385 if (err != OMX_ErrorNone) { 386 LOGE("OMX_UseBuffer failed with error %d (0x%08x)", err, err); 387 388 delete buffer_meta; 389 buffer_meta = NULL; 390 391 *buffer = 0; 392 return UNKNOWN_ERROR; 393 } 394 395 *buffer = header; 396 397 return OK; 398} 399 400status_t OMX::allocate_buffer( 401 node_id node, OMX_U32 port_index, size_t size, 402 buffer_id *buffer) { 403 Mutex::Autolock autoLock(mLock); 404 405 BufferMeta *buffer_meta = new BufferMeta(this, size); 406 407 OMX_BUFFERHEADERTYPE *header; 408 409 NodeMeta *node_meta = static_cast<NodeMeta *>(node); 410 OMX_ERRORTYPE err = 411 OMX_AllocateBuffer(node_meta->handle(), &header, port_index, 412 buffer_meta, size); 413 414 if (err != OMX_ErrorNone) { 415 delete buffer_meta; 416 buffer_meta = NULL; 417 418 *buffer = 0; 419 return UNKNOWN_ERROR; 420 } 421 422 *buffer = header; 423 424 return OK; 425} 426 427status_t OMX::allocate_buffer_with_backup( 428 node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, 429 buffer_id *buffer) { 430 Mutex::Autolock autoLock(mLock); 431 432 BufferMeta *buffer_meta = new BufferMeta(this, params, true); 433 434 OMX_BUFFERHEADERTYPE *header; 435 436 NodeMeta *node_meta = static_cast<NodeMeta *>(node); 437 OMX_ERRORTYPE err = 438 OMX_AllocateBuffer( 439 node_meta->handle(), &header, port_index, buffer_meta, 440 params->size()); 441 442 if (err != OMX_ErrorNone) { 443 delete buffer_meta; 444 buffer_meta = NULL; 445 446 *buffer = 0; 447 return UNKNOWN_ERROR; 448 } 449 450 *buffer = header; 451 452 return OK; 453} 454 455status_t OMX::free_buffer(node_id node, OMX_U32 port_index, buffer_id buffer) { 456 OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer; 457 BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate); 458 459 NodeMeta *node_meta = static_cast<NodeMeta *>(node); 460 OMX_ERRORTYPE err = 461 OMX_FreeBuffer(node_meta->handle(), port_index, header); 462 463 delete buffer_meta; 464 buffer_meta = NULL; 465 466 return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK; 467} 468 469OMX_ERRORTYPE OMX::OnEvent( 470 NodeMeta *meta, 471 OMX_IN OMX_EVENTTYPE eEvent, 472 OMX_IN OMX_U32 nData1, 473 OMX_IN OMX_U32 nData2, 474 OMX_IN OMX_PTR pEventData) { 475 LOGV("OnEvent(%d, %ld, %ld)", eEvent, nData1, nData2); 476 477 omx_message msg; 478 msg.type = omx_message::EVENT; 479 msg.node = meta; 480 msg.u.event_data.event = eEvent; 481 msg.u.event_data.data1 = nData1; 482 msg.u.event_data.data2 = nData2; 483 484 mDispatcher->post(msg); 485 486 return OMX_ErrorNone; 487} 488 489OMX_ERRORTYPE OMX::OnEmptyBufferDone( 490 NodeMeta *meta, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) { 491 LOGV("OnEmptyBufferDone buffer=%p", pBuffer); 492 493 omx_message msg; 494 msg.type = omx_message::EMPTY_BUFFER_DONE; 495 msg.node = meta; 496 msg.u.buffer_data.buffer = pBuffer; 497 498 mDispatcher->post(msg); 499 500 return OMX_ErrorNone; 501} 502 503OMX_ERRORTYPE OMX::OnFillBufferDone( 504 NodeMeta *meta, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) { 505 LOGV("OnFillBufferDone buffer=%p", pBuffer); 506 BufferMeta *buffer_meta = static_cast<BufferMeta *>(pBuffer->pAppPrivate); 507 buffer_meta->CopyFromOMX(pBuffer); 508 509 omx_message msg; 510 msg.type = omx_message::FILL_BUFFER_DONE; 511 msg.node = meta; 512 msg.u.extended_buffer_data.buffer = pBuffer; 513 msg.u.extended_buffer_data.range_offset = pBuffer->nOffset; 514 msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen; 515 msg.u.extended_buffer_data.flags = pBuffer->nFlags; 516 msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp; 517 msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate; 518 519 mDispatcher->post(msg); 520 521 return OMX_ErrorNone; 522} 523 524status_t OMX::observe_node( 525 node_id node, const sp<IOMXObserver> &observer) { 526 NodeMeta *node_meta = static_cast<NodeMeta *>(node); 527 528 node_meta->setObserver(observer); 529 530 return OK; 531} 532 533status_t OMX::fill_buffer(node_id node, buffer_id buffer) { 534 OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer; 535 header->nFilledLen = 0; 536 header->nOffset = 0; 537 header->nFlags = 0; 538 539 NodeMeta *node_meta = static_cast<NodeMeta *>(node); 540 541 OMX_ERRORTYPE err = 542 OMX_FillThisBuffer(node_meta->handle(), header); 543 544 return (err == OMX_ErrorNone) ? OK : UNKNOWN_ERROR; 545} 546 547status_t OMX::empty_buffer( 548 node_id node, 549 buffer_id buffer, 550 OMX_U32 range_offset, OMX_U32 range_length, 551 OMX_U32 flags, OMX_TICKS timestamp) { 552 OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer; 553 header->nFilledLen = range_length; 554 header->nOffset = range_offset; 555 header->nFlags = flags; 556 header->nTimeStamp = timestamp; 557 558 BufferMeta *buffer_meta = 559 static_cast<BufferMeta *>(header->pAppPrivate); 560 buffer_meta->CopyToOMX(header); 561 562 NodeMeta *node_meta = static_cast<NodeMeta *>(node); 563 564 OMX_ERRORTYPE err = 565 OMX_EmptyThisBuffer(node_meta->handle(), header); 566 567 return (err == OMX_ErrorNone) ? OK : UNKNOWN_ERROR; 568} 569 570status_t OMX::get_extension_index( 571 node_id node, 572 const char *parameter_name, 573 OMX_INDEXTYPE *index) { 574 NodeMeta *node_meta = static_cast<NodeMeta *>(node); 575 576 OMX_ERRORTYPE err = 577 OMX_GetExtensionIndex( 578 node_meta->handle(), 579 const_cast<char *>(parameter_name), index); 580 581 return err == OMX_ErrorNone ? OK : UNKNOWN_ERROR; 582} 583 584//////////////////////////////////////////////////////////////////////////////// 585 586sp<IOMXRenderer> OMX::createRenderer( 587 const sp<ISurface> &surface, 588 const char *componentName, 589 OMX_COLOR_FORMATTYPE colorFormat, 590 size_t encodedWidth, size_t encodedHeight, 591 size_t displayWidth, size_t displayHeight) { 592 VideoRenderer *impl = NULL; 593 594 static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00; 595 596 if (colorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar 597 && !strncmp(componentName, "OMX.qcom.video.decoder.", 23)) { 598 LOGW("Using QComHardwareRenderer."); 599 impl = 600 new QComHardwareRenderer( 601 surface, 602 displayWidth, displayHeight, 603 encodedWidth, encodedHeight); 604 } else if (colorFormat == OMX_COLOR_FormatCbYCrY 605 && !strcmp(componentName, "OMX.TI.Video.Decoder")) { 606 LOGW("Using TIHardwareRenderer."); 607 impl = 608 new TIHardwareRenderer( 609 surface, 610 displayWidth, displayHeight, 611 encodedWidth, encodedHeight); 612 } else { 613 LOGW("Using software renderer."); 614 impl = new SoftwareRenderer( 615 colorFormat, 616 surface, 617 displayWidth, displayHeight, 618 encodedWidth, encodedHeight); 619 } 620 621 return new OMXRenderer(impl); 622} 623 624OMXRenderer::OMXRenderer(VideoRenderer *impl) 625 : mImpl(impl) { 626} 627 628OMXRenderer::~OMXRenderer() { 629 delete mImpl; 630 mImpl = NULL; 631} 632 633void OMXRenderer::render(IOMX::buffer_id buffer) { 634 OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer; 635 636 mImpl->render( 637 header->pBuffer + header->nOffset, 638 header->nFilledLen, 639 header->pPlatformPrivate); 640} 641 642} // namespace android 643 644