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