diff options
Diffstat (limited to 'media/libstagefright/omx/OMX.cpp')
-rw-r--r-- | media/libstagefright/omx/OMX.cpp | 621 |
1 files changed, 621 insertions, 0 deletions
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp new file mode 100644 index 0000000..c18f5ce --- /dev/null +++ b/media/libstagefright/omx/OMX.cpp @@ -0,0 +1,621 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "OMX" +#include <utils/Log.h> + +#include <sys/socket.h> + +#undef NDEBUG +#include <assert.h> + +#include "OMX.h" +#include "pv_omxcore.h" + +#include <binder/IMemory.h> + +#include <OMX_Component.h> + +namespace android { + +class NodeMeta { +public: + NodeMeta(OMX *owner) + : mOwner(owner), + mHandle(NULL) { + } + + OMX *owner() const { + return mOwner; + } + + void setHandle(OMX_HANDLETYPE handle) { + assert(mHandle == NULL); + mHandle = handle; + } + + OMX_HANDLETYPE handle() const { + return mHandle; + } + + void setObserver(const sp<IOMXObserver> &observer) { + mObserver = observer; + } + + sp<IOMXObserver> observer() { + return mObserver; + } + +private: + OMX *mOwner; + OMX_HANDLETYPE mHandle; + sp<IOMXObserver> mObserver; + + NodeMeta(const NodeMeta &); + NodeMeta &operator=(const NodeMeta &); +}; + +class BufferMeta { +public: + BufferMeta(OMX *owner, const sp<IMemory> &mem, bool is_backup = false) + : mOwner(owner), + mMem(mem), + mIsBackup(is_backup) { + } + + BufferMeta(OMX *owner, size_t size) + : mOwner(owner), + mSize(size), + mIsBackup(false) { + } + + void CopyFromOMX(const OMX_BUFFERHEADERTYPE *header) { + if (!mIsBackup) { + return; + } + + memcpy((OMX_U8 *)mMem->pointer() + header->nOffset, + header->pBuffer + header->nOffset, + header->nFilledLen); + } + + void CopyToOMX(const OMX_BUFFERHEADERTYPE *header) { + if (!mIsBackup) { + return; + } + + memcpy(header->pBuffer + header->nOffset, + (const OMX_U8 *)mMem->pointer() + header->nOffset, + header->nFilledLen); + } + +private: + OMX *mOwner; + sp<IMemory> mMem; + size_t mSize; + bool mIsBackup; + + BufferMeta(const BufferMeta &); + BufferMeta &operator=(const BufferMeta &); +}; + +// static +OMX_CALLBACKTYPE OMX::kCallbacks = { + &OnEvent, &OnEmptyBufferDone, &OnFillBufferDone +}; + +// static +OMX_ERRORTYPE OMX::OnEvent( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, + OMX_IN OMX_U32 nData2, + OMX_IN OMX_PTR pEventData) { + NodeMeta *meta = static_cast<NodeMeta *>(pAppData); + return meta->owner()->OnEvent(meta, eEvent, nData1, nData2, pEventData); +} + +// static +OMX_ERRORTYPE OMX::OnEmptyBufferDone( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) { + NodeMeta *meta = static_cast<NodeMeta *>(pAppData); + return meta->owner()->OnEmptyBufferDone(meta, pBuffer); +} + +// static +OMX_ERRORTYPE OMX::OnFillBufferDone( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) { + NodeMeta *meta = static_cast<NodeMeta *>(pAppData); + return meta->owner()->OnFillBufferDone(meta, pBuffer); +} + +OMX::OMX() +#if IOMX_USES_SOCKETS + : mSock(-1) +#endif +{ +} + +OMX::~OMX() { +#if IOMX_USES_SOCKETS + assert(mSock < 0); +#endif +} + +#if IOMX_USES_SOCKETS +status_t OMX::connect(int *sd) { + Mutex::Autolock autoLock(mLock); + + if (mSock >= 0) { + return UNKNOWN_ERROR; + } + + int sockets[2]; + if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sockets) < 0) { + return UNKNOWN_ERROR; + } + + mSock = sockets[0]; + *sd = sockets[1]; + + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + int err = pthread_create(&mThread, &attr, ThreadWrapper, this); + assert(err == 0); + + pthread_attr_destroy(&attr); + + return OK; +} + +// static +void *OMX::ThreadWrapper(void *me) { + ((OMX *)me)->threadEntry(); + + return NULL; +} + +void OMX::threadEntry() { + bool done = false; + while (!done) { + omx_message msg; + ssize_t n = recv(mSock, &msg, sizeof(msg), 0); + + if (n <= 0) { + break; + } + + Mutex::Autolock autoLock(mLock); + + switch (msg.type) { + case omx_message::FILL_BUFFER: + { + OMX_BUFFERHEADERTYPE *header = + static_cast<OMX_BUFFERHEADERTYPE *>( + msg.u.buffer_data.buffer); + + header->nFilledLen = 0; + header->nOffset = 0; + header->nFlags = 0; + + NodeMeta *node_meta = static_cast<NodeMeta *>( + msg.u.buffer_data.node); + + LOGV("FillThisBuffer buffer=%p", header); + + OMX_ERRORTYPE err = + OMX_FillThisBuffer(node_meta->handle(), header); + assert(err == OMX_ErrorNone); + break; + } + + case omx_message::EMPTY_BUFFER: + { + OMX_BUFFERHEADERTYPE *header = + static_cast<OMX_BUFFERHEADERTYPE *>( + msg.u.extended_buffer_data.buffer); + + header->nFilledLen = msg.u.extended_buffer_data.range_length; + header->nOffset = msg.u.extended_buffer_data.range_offset; + header->nFlags = msg.u.extended_buffer_data.flags; + header->nTimeStamp = msg.u.extended_buffer_data.timestamp; + + BufferMeta *buffer_meta = + static_cast<BufferMeta *>(header->pAppPrivate); + buffer_meta->CopyToOMX(header); + + NodeMeta *node_meta = static_cast<NodeMeta *>( + msg.u.extended_buffer_data.node); + + LOGV("EmptyThisBuffer buffer=%p", header); + + OMX_ERRORTYPE err = + OMX_EmptyThisBuffer(node_meta->handle(), header); + assert(err == OMX_ErrorNone); + break; + } + + case omx_message::SEND_COMMAND: + { + NodeMeta *node_meta = static_cast<NodeMeta *>( + msg.u.send_command_data.node); + + OMX_ERRORTYPE err = + OMX_SendCommand( + node_meta->handle(), msg.u.send_command_data.cmd, + msg.u.send_command_data.param, NULL); + assert(err == OMX_ErrorNone); + break; + } + + case omx_message::DISCONNECT: + { + omx_message msg; + msg.type = omx_message::DISCONNECTED; + ssize_t n = send(mSock, &msg, sizeof(msg), 0); + assert(n > 0 && static_cast<size_t>(n) == sizeof(msg)); + done = true; + break; + } + + default: + LOGE("received unknown omx_message type %d", msg.type); + break; + } + } + + Mutex::Autolock autoLock(mLock); + close(mSock); + mSock = -1; +} +#endif + +status_t OMX::list_nodes(List<String8> *list) { + OMX_MasterInit(); // XXX Put this somewhere else. + + list->clear(); + + OMX_U32 index = 0; + char componentName[256]; + while (OMX_MasterComponentNameEnum(componentName, sizeof(componentName), index) + == OMX_ErrorNone) { + list->push_back(String8(componentName)); + + ++index; + } + + return OK; +} + +status_t OMX::allocate_node(const char *name, node_id *node) { + Mutex::Autolock autoLock(mLock); + + *node = 0; + + OMX_MasterInit(); // XXX Put this somewhere else. + + NodeMeta *meta = new NodeMeta(this); + + OMX_HANDLETYPE handle; + OMX_ERRORTYPE err = OMX_MasterGetHandle( + &handle, const_cast<char *>(name), meta, &kCallbacks); + + if (err != OMX_ErrorNone) { + LOGE("FAILED to allocate omx component '%s'", name); + + delete meta; + meta = NULL; + + return UNKNOWN_ERROR; + } + + meta->setHandle(handle); + + *node = meta; + + return OK; +} + +status_t OMX::free_node(node_id node) { + Mutex::Autolock autoLock(mLock); + + NodeMeta *meta = static_cast<NodeMeta *>(node); + + OMX_ERRORTYPE err = OMX_MasterFreeHandle(meta->handle()); + + delete meta; + meta = NULL; + + return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK; +} + +status_t OMX::send_command( + node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) { + Mutex::Autolock autoLock(mLock); + +#if IOMX_USES_SOCKETS + if (mSock < 0) { + return UNKNOWN_ERROR; + } +#endif + + NodeMeta *meta = static_cast<NodeMeta *>(node); + OMX_ERRORTYPE err = OMX_SendCommand(meta->handle(), cmd, param, NULL); + + return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK; +} + +status_t OMX::get_parameter( + node_id node, OMX_INDEXTYPE index, + void *params, size_t size) { + Mutex::Autolock autoLock(mLock); + + NodeMeta *meta = static_cast<NodeMeta *>(node); + OMX_ERRORTYPE err = OMX_GetParameter(meta->handle(), index, params); + + return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK; +} + +status_t OMX::set_parameter( + node_id node, OMX_INDEXTYPE index, + const void *params, size_t size) { + Mutex::Autolock autoLock(mLock); + + NodeMeta *meta = static_cast<NodeMeta *>(node); + OMX_ERRORTYPE err = + OMX_SetParameter(meta->handle(), index, const_cast<void *>(params)); + + return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK; +} + +status_t OMX::use_buffer( + node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, + buffer_id *buffer) { + Mutex::Autolock autoLock(mLock); + + BufferMeta *buffer_meta = new BufferMeta(this, params); + + OMX_BUFFERHEADERTYPE *header; + + NodeMeta *node_meta = static_cast<NodeMeta *>(node); + OMX_ERRORTYPE err = + OMX_UseBuffer(node_meta->handle(), &header, port_index, buffer_meta, + params->size(), static_cast<OMX_U8 *>(params->pointer())); + + if (err != OMX_ErrorNone) { + LOGE("OMX_UseBuffer failed with error %d (0x%08x)", err, err); + + delete buffer_meta; + buffer_meta = NULL; + + *buffer = 0; + return UNKNOWN_ERROR; + } + + *buffer = header; + + return OK; +} + +status_t OMX::allocate_buffer( + node_id node, OMX_U32 port_index, size_t size, + buffer_id *buffer) { + Mutex::Autolock autoLock(mLock); + + BufferMeta *buffer_meta = new BufferMeta(this, size); + + OMX_BUFFERHEADERTYPE *header; + + NodeMeta *node_meta = static_cast<NodeMeta *>(node); + OMX_ERRORTYPE err = + OMX_AllocateBuffer(node_meta->handle(), &header, port_index, + buffer_meta, size); + + if (err != OMX_ErrorNone) { + delete buffer_meta; + buffer_meta = NULL; + + *buffer = 0; + return UNKNOWN_ERROR; + } + + *buffer = header; + + return OK; +} + +status_t OMX::allocate_buffer_with_backup( + node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, + buffer_id *buffer) { + Mutex::Autolock autoLock(mLock); + + BufferMeta *buffer_meta = new BufferMeta(this, params, true); + + OMX_BUFFERHEADERTYPE *header; + + NodeMeta *node_meta = static_cast<NodeMeta *>(node); + OMX_ERRORTYPE err = + OMX_AllocateBuffer( + node_meta->handle(), &header, port_index, buffer_meta, + params->size()); + + if (err != OMX_ErrorNone) { + delete buffer_meta; + buffer_meta = NULL; + + *buffer = 0; + return UNKNOWN_ERROR; + } + + *buffer = header; + + return OK; +} + +status_t OMX::free_buffer(node_id node, OMX_U32 port_index, buffer_id buffer) { + OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer; + BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate); + + NodeMeta *node_meta = static_cast<NodeMeta *>(node); + OMX_ERRORTYPE err = + OMX_FreeBuffer(node_meta->handle(), port_index, header); + + delete buffer_meta; + buffer_meta = NULL; + + return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK; +} + +OMX_ERRORTYPE OMX::OnEvent( + NodeMeta *meta, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, + OMX_IN OMX_U32 nData2, + OMX_IN OMX_PTR pEventData) { + LOGV("OnEvent(%d, %ld, %ld)", eEvent, nData1, nData2); + + omx_message msg; + msg.type = omx_message::EVENT; + msg.u.event_data.node = meta; + msg.u.event_data.event = eEvent; + msg.u.event_data.data1 = nData1; + msg.u.event_data.data2 = nData2; + +#if !IOMX_USES_SOCKETS + sp<IOMXObserver> observer = meta->observer(); + if (observer.get() != NULL) { + observer->on_message(msg); + } +#else + assert(mSock >= 0); + + ssize_t n = send(mSock, &msg, sizeof(msg), 0); + assert(n > 0 && static_cast<size_t>(n) == sizeof(msg)); +#endif + + return OMX_ErrorNone; +} + +OMX_ERRORTYPE OMX::OnEmptyBufferDone( + NodeMeta *meta, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) { + LOGV("OnEmptyBufferDone buffer=%p", pBuffer); + + omx_message msg; + msg.type = omx_message::EMPTY_BUFFER_DONE; + msg.u.buffer_data.node = meta; + msg.u.buffer_data.buffer = pBuffer; + +#if !IOMX_USES_SOCKETS + sp<IOMXObserver> observer = meta->observer(); + if (observer.get() != NULL) { + observer->on_message(msg); + } +#else + assert(mSock >= 0); + ssize_t n = send(mSock, &msg, sizeof(msg), 0); + assert(n > 0 && static_cast<size_t>(n) == sizeof(msg)); +#endif + + return OMX_ErrorNone; +} + +OMX_ERRORTYPE OMX::OnFillBufferDone( + NodeMeta *meta, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) { + LOGV("OnFillBufferDone buffer=%p", pBuffer); + BufferMeta *buffer_meta = static_cast<BufferMeta *>(pBuffer->pAppPrivate); + buffer_meta->CopyFromOMX(pBuffer); + + omx_message msg; + msg.type = omx_message::FILL_BUFFER_DONE; + msg.u.extended_buffer_data.node = meta; + msg.u.extended_buffer_data.buffer = pBuffer; + msg.u.extended_buffer_data.range_offset = pBuffer->nOffset; + msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen; + msg.u.extended_buffer_data.flags = pBuffer->nFlags; + msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp; + msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate; + +#if !IOMX_USES_SOCKETS + sp<IOMXObserver> observer = meta->observer(); + if (observer.get() != NULL) { + observer->on_message(msg); + } +#else + assert(mSock >= 0); + + ssize_t n = send(mSock, &msg, sizeof(msg), 0); + assert(n > 0 && static_cast<size_t>(n) == sizeof(msg)); +#endif + + return OMX_ErrorNone; +} + +#if !IOMX_USES_SOCKETS +status_t OMX::observe_node( + node_id node, const sp<IOMXObserver> &observer) { + NodeMeta *node_meta = static_cast<NodeMeta *>(node); + + node_meta->setObserver(observer); + + return OK; +} + +void OMX::fill_buffer(node_id node, buffer_id buffer) { + OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer; + header->nFilledLen = 0; + header->nOffset = 0; + header->nFlags = 0; + + NodeMeta *node_meta = static_cast<NodeMeta *>(node); + + OMX_ERRORTYPE err = + OMX_FillThisBuffer(node_meta->handle(), header); + assert(err == OMX_ErrorNone); +} + +void OMX::empty_buffer( + node_id node, + buffer_id buffer, + OMX_U32 range_offset, OMX_U32 range_length, + OMX_U32 flags, OMX_TICKS timestamp) { + OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer; + header->nFilledLen = range_length; + header->nOffset = range_offset; + header->nFlags = flags; + header->nTimeStamp = timestamp; + + BufferMeta *buffer_meta = + static_cast<BufferMeta *>(header->pAppPrivate); + buffer_meta->CopyToOMX(header); + + NodeMeta *node_meta = static_cast<NodeMeta *>(node); + + OMX_ERRORTYPE err = + OMX_EmptyThisBuffer(node_meta->handle(), header); + assert(err == OMX_ErrorNone); +} +#endif + +} // namespace android + |