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