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