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