diff options
Diffstat (limited to 'media/libmedia/IOMX.cpp')
-rw-r--r-- | media/libmedia/IOMX.cpp | 788 |
1 files changed, 788 insertions, 0 deletions
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp new file mode 100644 index 0000000..48e427a --- /dev/null +++ b/media/libmedia/IOMX.cpp @@ -0,0 +1,788 @@ +/* + * 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 "IOMX" +#include <utils/Log.h> + +#include <binder/IMemory.h> +#include <binder/Parcel.h> +#include <media/IOMX.h> +#include <media/stagefright/foundation/ADebug.h> + +namespace android { + +enum { + CONNECT = IBinder::FIRST_CALL_TRANSACTION, + LIVES_LOCALLY, + LIST_NODES, + ALLOCATE_NODE, + FREE_NODE, + SEND_COMMAND, + GET_PARAMETER, + SET_PARAMETER, + GET_CONFIG, + SET_CONFIG, + GET_STATE, + ENABLE_GRAPHIC_BUFFERS, + USE_BUFFER, + USE_GRAPHIC_BUFFER, + STORE_META_DATA_IN_BUFFERS, + ALLOC_BUFFER, + ALLOC_BUFFER_WITH_BACKUP, + FREE_BUFFER, + FILL_BUFFER, + EMPTY_BUFFER, + GET_EXTENSION_INDEX, + OBSERVER_ON_MSG, + GET_GRAPHIC_BUFFER_USAGE, +}; + +class BpOMX : public BpInterface<IOMX> { +public: + BpOMX(const sp<IBinder> &impl) + : BpInterface<IOMX>(impl) { + } + + virtual bool livesLocally(node_id node, pid_t pid) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + data.writeIntPtr((intptr_t)node); + data.writeInt32(pid); + remote()->transact(LIVES_LOCALLY, data, &reply); + + return reply.readInt32() != 0; + } + + virtual status_t listNodes(List<ComponentInfo> *list) { + list->clear(); + + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + remote()->transact(LIST_NODES, data, &reply); + + int32_t n = reply.readInt32(); + for (int32_t i = 0; i < n; ++i) { + list->push_back(ComponentInfo()); + ComponentInfo &info = *--list->end(); + + info.mName = reply.readString8(); + int32_t numRoles = reply.readInt32(); + for (int32_t j = 0; j < numRoles; ++j) { + info.mRoles.push_back(reply.readString8()); + } + } + + return OK; + } + + virtual status_t allocateNode( + const char *name, const sp<IOMXObserver> &observer, node_id *node) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + data.writeCString(name); + data.writeStrongBinder(observer->asBinder()); + remote()->transact(ALLOCATE_NODE, data, &reply); + + status_t err = reply.readInt32(); + if (err == OK) { + *node = (void*)reply.readIntPtr(); + } else { + *node = 0; + } + + return err; + } + + virtual status_t freeNode(node_id node) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + data.writeIntPtr((intptr_t)node); + remote()->transact(FREE_NODE, data, &reply); + + return reply.readInt32(); + } + + virtual status_t sendCommand( + node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + data.writeIntPtr((intptr_t)node); + data.writeInt32(cmd); + data.writeInt32(param); + remote()->transact(SEND_COMMAND, data, &reply); + + return reply.readInt32(); + } + + virtual status_t getParameter( + node_id node, OMX_INDEXTYPE index, + void *params, size_t size) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + data.writeIntPtr((intptr_t)node); + data.writeInt32(index); + data.writeInt32(size); + data.write(params, size); + remote()->transact(GET_PARAMETER, data, &reply); + + status_t err = reply.readInt32(); + if (err != OK) { + return err; + } + + reply.read(params, size); + + return OK; + } + + virtual status_t setParameter( + node_id node, OMX_INDEXTYPE index, + const void *params, size_t size) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + data.writeIntPtr((intptr_t)node); + data.writeInt32(index); + data.writeInt32(size); + data.write(params, size); + remote()->transact(SET_PARAMETER, data, &reply); + + return reply.readInt32(); + } + + virtual status_t getConfig( + node_id node, OMX_INDEXTYPE index, + void *params, size_t size) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + data.writeIntPtr((intptr_t)node); + data.writeInt32(index); + data.writeInt32(size); + data.write(params, size); + remote()->transact(GET_CONFIG, data, &reply); + + status_t err = reply.readInt32(); + if (err != OK) { + return err; + } + + reply.read(params, size); + + return OK; + } + + virtual status_t setConfig( + node_id node, OMX_INDEXTYPE index, + const void *params, size_t size) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + data.writeIntPtr((intptr_t)node); + data.writeInt32(index); + data.writeInt32(size); + data.write(params, size); + remote()->transact(SET_CONFIG, data, &reply); + + return reply.readInt32(); + } + + virtual status_t getState( + node_id node, OMX_STATETYPE* state) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + data.writeIntPtr((intptr_t)node); + remote()->transact(GET_STATE, data, &reply); + + *state = static_cast<OMX_STATETYPE>(reply.readInt32()); + return reply.readInt32(); + } + + virtual status_t enableGraphicBuffers( + node_id node, OMX_U32 port_index, OMX_BOOL enable) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + data.writeIntPtr((intptr_t)node); + data.writeInt32(port_index); + data.writeInt32((uint32_t)enable); + remote()->transact(ENABLE_GRAPHIC_BUFFERS, data, &reply); + + status_t err = reply.readInt32(); + return err; + } + + virtual status_t getGraphicBufferUsage( + node_id node, OMX_U32 port_index, OMX_U32* usage) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + data.writeIntPtr((intptr_t)node); + data.writeInt32(port_index); + remote()->transact(GET_GRAPHIC_BUFFER_USAGE, data, &reply); + + status_t err = reply.readInt32(); + *usage = reply.readInt32(); + return err; + } + + virtual status_t useBuffer( + node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, + buffer_id *buffer) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + data.writeIntPtr((intptr_t)node); + data.writeInt32(port_index); + data.writeStrongBinder(params->asBinder()); + remote()->transact(USE_BUFFER, data, &reply); + + status_t err = reply.readInt32(); + if (err != OK) { + *buffer = 0; + + return err; + } + + *buffer = (void*)reply.readIntPtr(); + + return err; + } + + + virtual status_t useGraphicBuffer( + node_id node, OMX_U32 port_index, + const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + data.writeIntPtr((intptr_t)node); + data.writeInt32(port_index); + data.write(*graphicBuffer); + remote()->transact(USE_GRAPHIC_BUFFER, data, &reply); + + status_t err = reply.readInt32(); + if (err != OK) { + *buffer = 0; + + return err; + } + + *buffer = (void*)reply.readIntPtr(); + + return err; + } + + virtual status_t storeMetaDataInBuffers( + node_id node, OMX_U32 port_index, OMX_BOOL enable) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + data.writeIntPtr((intptr_t)node); + data.writeInt32(port_index); + data.writeInt32((uint32_t)enable); + remote()->transact(STORE_META_DATA_IN_BUFFERS, data, &reply); + + status_t err = reply.readInt32(); + return err; + } + + virtual status_t allocateBuffer( + node_id node, OMX_U32 port_index, size_t size, + buffer_id *buffer, void **buffer_data) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + data.writeIntPtr((intptr_t)node); + data.writeInt32(port_index); + data.writeInt32(size); + remote()->transact(ALLOC_BUFFER, data, &reply); + + status_t err = reply.readInt32(); + if (err != OK) { + *buffer = 0; + + return err; + } + + *buffer = (void *)reply.readIntPtr(); + *buffer_data = (void *)reply.readIntPtr(); + + return err; + } + + virtual status_t allocateBufferWithBackup( + node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, + buffer_id *buffer) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + data.writeIntPtr((intptr_t)node); + data.writeInt32(port_index); + data.writeStrongBinder(params->asBinder()); + remote()->transact(ALLOC_BUFFER_WITH_BACKUP, data, &reply); + + status_t err = reply.readInt32(); + if (err != OK) { + *buffer = 0; + + return err; + } + + *buffer = (void*)reply.readIntPtr(); + + return err; + } + + virtual status_t freeBuffer( + node_id node, OMX_U32 port_index, buffer_id buffer) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + data.writeIntPtr((intptr_t)node); + data.writeInt32(port_index); + data.writeIntPtr((intptr_t)buffer); + remote()->transact(FREE_BUFFER, data, &reply); + + return reply.readInt32(); + } + + virtual status_t fillBuffer(node_id node, buffer_id buffer) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + data.writeIntPtr((intptr_t)node); + data.writeIntPtr((intptr_t)buffer); + remote()->transact(FILL_BUFFER, data, &reply); + + return reply.readInt32(); + } + + virtual status_t emptyBuffer( + node_id node, + buffer_id buffer, + OMX_U32 range_offset, OMX_U32 range_length, + OMX_U32 flags, OMX_TICKS timestamp) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + data.writeIntPtr((intptr_t)node); + data.writeIntPtr((intptr_t)buffer); + data.writeInt32(range_offset); + data.writeInt32(range_length); + data.writeInt32(flags); + data.writeInt64(timestamp); + remote()->transact(EMPTY_BUFFER, data, &reply); + + return reply.readInt32(); + } + + virtual status_t getExtensionIndex( + node_id node, + const char *parameter_name, + OMX_INDEXTYPE *index) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + data.writeIntPtr((intptr_t)node); + data.writeCString(parameter_name); + + remote()->transact(GET_EXTENSION_INDEX, data, &reply); + + status_t err = reply.readInt32(); + if (err == OK) { + *index = static_cast<OMX_INDEXTYPE>(reply.readInt32()); + } else { + *index = OMX_IndexComponentStartUnused; + } + + return err; + } +}; + +IMPLEMENT_META_INTERFACE(OMX, "android.hardware.IOMX"); + +//////////////////////////////////////////////////////////////////////////////// + +#define CHECK_INTERFACE(interface, data, reply) \ + do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \ + ALOGW("Call incorrectly routed to " #interface); \ + return PERMISSION_DENIED; \ + } } while (0) + +status_t BnOMX::onTransact( + uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) { + switch (code) { + case LIVES_LOCALLY: + { + CHECK_INTERFACE(IOMX, data, reply); + node_id node = (void *)data.readIntPtr(); + pid_t pid = (pid_t)data.readInt32(); + reply->writeInt32(livesLocally(node, pid)); + + return OK; + } + + case LIST_NODES: + { + CHECK_INTERFACE(IOMX, data, reply); + + List<ComponentInfo> list; + listNodes(&list); + + reply->writeInt32(list.size()); + for (List<ComponentInfo>::iterator it = list.begin(); + it != list.end(); ++it) { + ComponentInfo &cur = *it; + + reply->writeString8(cur.mName); + reply->writeInt32(cur.mRoles.size()); + for (List<String8>::iterator role_it = cur.mRoles.begin(); + role_it != cur.mRoles.end(); ++role_it) { + reply->writeString8(*role_it); + } + } + + return NO_ERROR; + } + + case ALLOCATE_NODE: + { + CHECK_INTERFACE(IOMX, data, reply); + + const char *name = data.readCString(); + + sp<IOMXObserver> observer = + interface_cast<IOMXObserver>(data.readStrongBinder()); + + node_id node; + + status_t err = allocateNode(name, observer, &node); + reply->writeInt32(err); + if (err == OK) { + reply->writeIntPtr((intptr_t)node); + } + + return NO_ERROR; + } + + case FREE_NODE: + { + CHECK_INTERFACE(IOMX, data, reply); + + node_id node = (void*)data.readIntPtr(); + + reply->writeInt32(freeNode(node)); + + return NO_ERROR; + } + + case SEND_COMMAND: + { + CHECK_INTERFACE(IOMX, data, reply); + + node_id node = (void*)data.readIntPtr(); + + OMX_COMMANDTYPE cmd = + static_cast<OMX_COMMANDTYPE>(data.readInt32()); + + OMX_S32 param = data.readInt32(); + reply->writeInt32(sendCommand(node, cmd, param)); + + return NO_ERROR; + } + + case GET_PARAMETER: + case SET_PARAMETER: + case GET_CONFIG: + case SET_CONFIG: + { + CHECK_INTERFACE(IOMX, data, reply); + + node_id node = (void*)data.readIntPtr(); + OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32()); + + size_t size = data.readInt32(); + + void *params = malloc(size); + data.read(params, size); + + status_t err; + switch (code) { + case GET_PARAMETER: + err = getParameter(node, index, params, size); + break; + case SET_PARAMETER: + err = setParameter(node, index, params, size); + break; + case GET_CONFIG: + err = getConfig(node, index, params, size); + break; + case SET_CONFIG: + err = setConfig(node, index, params, size); + break; + default: + TRESPASS(); + } + + reply->writeInt32(err); + + if ((code == GET_PARAMETER || code == GET_CONFIG) && err == OK) { + reply->write(params, size); + } + + free(params); + params = NULL; + + return NO_ERROR; + } + + case GET_STATE: + { + CHECK_INTERFACE(IOMX, data, reply); + + node_id node = (void*)data.readIntPtr(); + OMX_STATETYPE state = OMX_StateInvalid; + + status_t err = getState(node, &state); + reply->writeInt32(state); + reply->writeInt32(err); + + return NO_ERROR; + } + + case ENABLE_GRAPHIC_BUFFERS: + { + CHECK_INTERFACE(IOMX, data, reply); + + node_id node = (void*)data.readIntPtr(); + OMX_U32 port_index = data.readInt32(); + OMX_BOOL enable = (OMX_BOOL)data.readInt32(); + + status_t err = enableGraphicBuffers(node, port_index, enable); + reply->writeInt32(err); + + return NO_ERROR; + } + + case GET_GRAPHIC_BUFFER_USAGE: + { + CHECK_INTERFACE(IOMX, data, reply); + + node_id node = (void*)data.readIntPtr(); + OMX_U32 port_index = data.readInt32(); + + OMX_U32 usage = 0; + status_t err = getGraphicBufferUsage(node, port_index, &usage); + reply->writeInt32(err); + reply->writeInt32(usage); + + return NO_ERROR; + } + + case USE_BUFFER: + { + CHECK_INTERFACE(IOMX, data, reply); + + node_id node = (void*)data.readIntPtr(); + OMX_U32 port_index = data.readInt32(); + sp<IMemory> params = + interface_cast<IMemory>(data.readStrongBinder()); + + buffer_id buffer; + status_t err = useBuffer(node, port_index, params, &buffer); + reply->writeInt32(err); + + if (err == OK) { + reply->writeIntPtr((intptr_t)buffer); + } + + return NO_ERROR; + } + + case USE_GRAPHIC_BUFFER: + { + CHECK_INTERFACE(IOMX, data, reply); + + node_id node = (void*)data.readIntPtr(); + OMX_U32 port_index = data.readInt32(); + sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(); + data.read(*graphicBuffer); + + buffer_id buffer; + status_t err = useGraphicBuffer( + node, port_index, graphicBuffer, &buffer); + reply->writeInt32(err); + + if (err == OK) { + reply->writeIntPtr((intptr_t)buffer); + } + + return NO_ERROR; + } + + case STORE_META_DATA_IN_BUFFERS: + { + CHECK_INTERFACE(IOMX, data, reply); + + node_id node = (void*)data.readIntPtr(); + OMX_U32 port_index = data.readInt32(); + OMX_BOOL enable = (OMX_BOOL)data.readInt32(); + + status_t err = storeMetaDataInBuffers(node, port_index, enable); + reply->writeInt32(err); + + return NO_ERROR; + } + + case ALLOC_BUFFER: + { + CHECK_INTERFACE(IOMX, data, reply); + + node_id node = (void*)data.readIntPtr(); + OMX_U32 port_index = data.readInt32(); + size_t size = data.readInt32(); + + buffer_id buffer; + void *buffer_data; + status_t err = allocateBuffer( + node, port_index, size, &buffer, &buffer_data); + reply->writeInt32(err); + + if (err == OK) { + reply->writeIntPtr((intptr_t)buffer); + reply->writeIntPtr((intptr_t)buffer_data); + } + + return NO_ERROR; + } + + case ALLOC_BUFFER_WITH_BACKUP: + { + CHECK_INTERFACE(IOMX, data, reply); + + node_id node = (void*)data.readIntPtr(); + OMX_U32 port_index = data.readInt32(); + sp<IMemory> params = + interface_cast<IMemory>(data.readStrongBinder()); + + buffer_id buffer; + status_t err = allocateBufferWithBackup( + node, port_index, params, &buffer); + + reply->writeInt32(err); + + if (err == OK) { + reply->writeIntPtr((intptr_t)buffer); + } + + return NO_ERROR; + } + + case FREE_BUFFER: + { + CHECK_INTERFACE(IOMX, data, reply); + + node_id node = (void*)data.readIntPtr(); + OMX_U32 port_index = data.readInt32(); + buffer_id buffer = (void*)data.readIntPtr(); + reply->writeInt32(freeBuffer(node, port_index, buffer)); + + return NO_ERROR; + } + + case FILL_BUFFER: + { + CHECK_INTERFACE(IOMX, data, reply); + + node_id node = (void*)data.readIntPtr(); + buffer_id buffer = (void*)data.readIntPtr(); + reply->writeInt32(fillBuffer(node, buffer)); + + return NO_ERROR; + } + + case EMPTY_BUFFER: + { + CHECK_INTERFACE(IOMX, data, reply); + + node_id node = (void*)data.readIntPtr(); + buffer_id buffer = (void*)data.readIntPtr(); + OMX_U32 range_offset = data.readInt32(); + OMX_U32 range_length = data.readInt32(); + OMX_U32 flags = data.readInt32(); + OMX_TICKS timestamp = data.readInt64(); + + reply->writeInt32( + emptyBuffer( + node, buffer, range_offset, range_length, + flags, timestamp)); + + return NO_ERROR; + } + + case GET_EXTENSION_INDEX: + { + CHECK_INTERFACE(IOMX, data, reply); + + node_id node = (void*)data.readIntPtr(); + const char *parameter_name = data.readCString(); + + OMX_INDEXTYPE index; + status_t err = getExtensionIndex(node, parameter_name, &index); + + reply->writeInt32(err); + + if (err == OK) { + reply->writeInt32(index); + } + + return OK; + } + + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +//////////////////////////////////////////////////////////////////////////////// + +class BpOMXObserver : public BpInterface<IOMXObserver> { +public: + BpOMXObserver(const sp<IBinder> &impl) + : BpInterface<IOMXObserver>(impl) { + } + + virtual void onMessage(const omx_message &msg) { + Parcel data, reply; + data.writeInterfaceToken(IOMXObserver::getInterfaceDescriptor()); + data.write(&msg, sizeof(msg)); + + remote()->transact(OBSERVER_ON_MSG, data, &reply, IBinder::FLAG_ONEWAY); + } +}; + +IMPLEMENT_META_INTERFACE(OMXObserver, "android.hardware.IOMXObserver"); + +status_t BnOMXObserver::onTransact( + uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) { + switch (code) { + case OBSERVER_ON_MSG: + { + CHECK_INTERFACE(IOMXObserver, data, reply); + + omx_message msg; + data.read(&msg, sizeof(msg)); + + // XXX Could use readInplace maybe? + onMessage(msg); + + return NO_ERROR; + } + + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +} // namespace android |