diff options
Diffstat (limited to 'media/libmedia/IOMX.cpp')
-rw-r--r-- | media/libmedia/IOMX.cpp | 561 |
1 files changed, 561 insertions, 0 deletions
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp new file mode 100644 index 0000000..f2a657a --- /dev/null +++ b/media/libmedia/IOMX.cpp @@ -0,0 +1,561 @@ +//#define LOG_NDEBUG 0 +#define LOG_TAG "IOMX" +#include <utils/Log.h> + +#include <binder/IMemory.h> +#include <binder/Parcel.h> +#include <media/IOMX.h> + +namespace android { + +enum { + CONNECT = IBinder::FIRST_CALL_TRANSACTION, + LIST_NODES, + ALLOCATE_NODE, + FREE_NODE, + SEND_COMMAND, + GET_PARAMETER, + SET_PARAMETER, + USE_BUFFER, + ALLOC_BUFFER, + ALLOC_BUFFER_WITH_BACKUP, + FREE_BUFFER, + OBSERVE_NODE, + FILL_BUFFER, + EMPTY_BUFFER, + OBSERVER_ON_MSG, +}; + +static void *readVoidStar(const Parcel *parcel) { + // FIX if sizeof(void *) != sizeof(int32) + return (void *)parcel->readInt32(); +} + +static void writeVoidStar(void *x, Parcel *parcel) { + // FIX if sizeof(void *) != sizeof(int32) + parcel->writeInt32((int32_t)x); +} + +class BpOMX : public BpInterface<IOMX> { +public: + BpOMX(const sp<IBinder> &impl) + : BpInterface<IOMX>(impl) { + } + +#if IOMX_USES_SOCKETS + virtual status_t connect(int *sd) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + remote()->transact(CONNECT, data, &reply); + + status_t err = reply.readInt32(); + if (err == OK) { + *sd = dup(reply.readFileDescriptor()); + } else { + *sd = -1; + } + + return reply.readInt32(); + } +#endif + + virtual status_t list_nodes(List<String8> *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) { + String8 s = reply.readString8(); + + list->push_back(s); + } + + return OK; + } + + virtual status_t allocate_node(const char *name, node_id *node) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + data.writeCString(name); + remote()->transact(ALLOCATE_NODE, data, &reply); + + status_t err = reply.readInt32(); + if (err == OK) { + *node = readVoidStar(&reply); + } else { + *node = 0; + } + + return err; + } + + virtual status_t free_node(node_id node) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + writeVoidStar(node, &data); + remote()->transact(FREE_NODE, data, &reply); + + return reply.readInt32(); + } + + virtual status_t send_command( + node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + writeVoidStar(node, &data); + data.writeInt32(cmd); + data.writeInt32(param); + remote()->transact(SEND_COMMAND, data, &reply); + + return reply.readInt32(); + } + + virtual status_t get_parameter( + node_id node, OMX_INDEXTYPE index, + void *params, size_t size) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + writeVoidStar(node, &data); + 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 set_parameter( + node_id node, OMX_INDEXTYPE index, + const void *params, size_t size) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + writeVoidStar(node, &data); + data.writeInt32(index); + data.writeInt32(size); + data.write(params, size); + remote()->transact(SET_PARAMETER, data, &reply); + + return reply.readInt32(); + } + + virtual status_t use_buffer( + node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, + buffer_id *buffer) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + writeVoidStar(node, &data); + 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 = readVoidStar(&reply); + + return err; + } + + virtual status_t allocate_buffer( + node_id node, OMX_U32 port_index, size_t size, + buffer_id *buffer) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + writeVoidStar(node, &data); + 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 = readVoidStar(&reply); + + return err; + } + + virtual status_t allocate_buffer_with_backup( + node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, + buffer_id *buffer) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + writeVoidStar(node, &data); + 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 = readVoidStar(&reply); + + return err; + } + + virtual status_t free_buffer( + node_id node, OMX_U32 port_index, buffer_id buffer) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + writeVoidStar(node, &data); + data.writeInt32(port_index); + writeVoidStar(buffer, &data); + remote()->transact(FREE_BUFFER, data, &reply); + + return reply.readInt32(); + } + +#if !IOMX_USES_SOCKETS + virtual status_t observe_node( + node_id node, const sp<IOMXObserver> &observer) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + writeVoidStar(node, &data); + data.writeStrongBinder(observer->asBinder()); + remote()->transact(OBSERVE_NODE, data, &reply); + + return reply.readInt32(); + } + + virtual void fill_buffer(node_id node, buffer_id buffer) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + writeVoidStar(node, &data); + writeVoidStar(buffer, &data); + remote()->transact(FILL_BUFFER, data, &reply, IBinder::FLAG_ONEWAY); + } + + virtual void empty_buffer( + 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()); + writeVoidStar(node, &data); + writeVoidStar(buffer, &data); + data.writeInt32(range_offset); + data.writeInt32(range_length); + data.writeInt32(flags); + data.writeInt64(timestamp); + remote()->transact(EMPTY_BUFFER, data, &reply, IBinder::FLAG_ONEWAY); + } +#endif +}; + +IMPLEMENT_META_INTERFACE(OMX, "android.hardware.IOMX"); + +//////////////////////////////////////////////////////////////////////////////// + +#define CHECK_INTERFACE(interface, data, reply) \ + do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \ + LOGW("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) { +#if IOMX_USES_SOCKETS + case CONNECT: + { + CHECK_INTERFACE(IOMX, data, reply); + + int s; + status_t err = connect(&s); + + reply->writeInt32(err); + if (err == OK) { + assert(s >= 0); + reply->writeDupFileDescriptor(s); + close(s); + s = -1; + } else { + assert(s == -1); + } + + return NO_ERROR; + } +#endif + + case LIST_NODES: + { + CHECK_INTERFACE(IOMX, data, reply); + + List<String8> list; + list_nodes(&list); + + reply->writeInt32(list.size()); + for (List<String8>::iterator it = list.begin(); + it != list.end(); ++it) { + reply->writeString8(*it); + } + + return NO_ERROR; + } + + case ALLOCATE_NODE: + { + CHECK_INTERFACE(IOMX, data, reply); + + node_id node; + status_t err = allocate_node(data.readCString(), &node); + reply->writeInt32(err); + if (err == OK) { + writeVoidStar(node, reply); + } + + return NO_ERROR; + } + + case FREE_NODE: + { + CHECK_INTERFACE(IOMX, data, reply); + + node_id node = readVoidStar(&data); + + reply->writeInt32(free_node(node)); + + return NO_ERROR; + } + + case SEND_COMMAND: + { + CHECK_INTERFACE(IOMX, data, reply); + + node_id node = readVoidStar(&data); + + OMX_COMMANDTYPE cmd = + static_cast<OMX_COMMANDTYPE>(data.readInt32()); + + OMX_S32 param = data.readInt32(); + reply->writeInt32(send_command(node, cmd, param)); + + return NO_ERROR; + } + + case GET_PARAMETER: + { + CHECK_INTERFACE(IOMX, data, reply); + + node_id node = readVoidStar(&data); + OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32()); + + size_t size = data.readInt32(); + + // XXX I am not happy with this but Parcel::readInplace didn't work. + void *params = malloc(size); + data.read(params, size); + + status_t err = get_parameter(node, index, params, size); + + reply->writeInt32(err); + + if (err == OK) { + reply->write(params, size); + } + + free(params); + params = NULL; + + return NO_ERROR; + } + + case SET_PARAMETER: + { + CHECK_INTERFACE(IOMX, data, reply); + + node_id node = readVoidStar(&data); + OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32()); + + size_t size = data.readInt32(); + void *params = const_cast<void *>(data.readInplace(size)); + + reply->writeInt32(set_parameter(node, index, params, size)); + + return NO_ERROR; + } + + case USE_BUFFER: + { + CHECK_INTERFACE(IOMX, data, reply); + + node_id node = readVoidStar(&data); + OMX_U32 port_index = data.readInt32(); + sp<IMemory> params = + interface_cast<IMemory>(data.readStrongBinder()); + + buffer_id buffer; + status_t err = use_buffer(node, port_index, params, &buffer); + reply->writeInt32(err); + + if (err == OK) { + writeVoidStar(buffer, reply); + } + + return NO_ERROR; + } + + case ALLOC_BUFFER: + { + CHECK_INTERFACE(IOMX, data, reply); + + node_id node = readVoidStar(&data); + OMX_U32 port_index = data.readInt32(); + size_t size = data.readInt32(); + + buffer_id buffer; + status_t err = allocate_buffer(node, port_index, size, &buffer); + reply->writeInt32(err); + + if (err == OK) { + writeVoidStar(buffer, reply); + } + + return NO_ERROR; + } + + case ALLOC_BUFFER_WITH_BACKUP: + { + CHECK_INTERFACE(IOMX, data, reply); + + node_id node = readVoidStar(&data); + OMX_U32 port_index = data.readInt32(); + sp<IMemory> params = + interface_cast<IMemory>(data.readStrongBinder()); + + buffer_id buffer; + status_t err = allocate_buffer_with_backup( + node, port_index, params, &buffer); + + reply->writeInt32(err); + + if (err == OK) { + writeVoidStar(buffer, reply); + } + + return NO_ERROR; + } + + case FREE_BUFFER: + { + CHECK_INTERFACE(IOMX, data, reply); + + node_id node = readVoidStar(&data); + OMX_U32 port_index = data.readInt32(); + buffer_id buffer = readVoidStar(&data); + reply->writeInt32(free_buffer(node, port_index, buffer)); + + return NO_ERROR; + } + +#if !IOMX_USES_SOCKETS + case OBSERVE_NODE: + { + CHECK_INTERFACE(IOMX, data, reply); + + node_id node = readVoidStar(&data); + sp<IOMXObserver> observer = + interface_cast<IOMXObserver>(data.readStrongBinder()); + reply->writeInt32(observe_node(node, observer)); + + return NO_ERROR; + } + + case FILL_BUFFER: + { + CHECK_INTERFACE(IOMX, data, reply); + + node_id node = readVoidStar(&data); + buffer_id buffer = readVoidStar(&data); + fill_buffer(node, buffer); + + return NO_ERROR; + } + + case EMPTY_BUFFER: + { + CHECK_INTERFACE(IOMX, data, reply); + + node_id node = readVoidStar(&data); + buffer_id buffer = readVoidStar(&data); + OMX_U32 range_offset = data.readInt32(); + OMX_U32 range_length = data.readInt32(); + OMX_U32 flags = data.readInt32(); + OMX_TICKS timestamp = data.readInt64(); + + empty_buffer( + node, buffer, range_offset, range_length, + flags, timestamp); + + return NO_ERROR; + } +#endif + + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +//////////////////////////////////////////////////////////////////////////////// + +class BpOMXObserver : public BpInterface<IOMXObserver> { +public: + BpOMXObserver(const sp<IBinder> &impl) + : BpInterface<IOMXObserver>(impl) { + } + + virtual void on_message(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? + on_message(msg); + + return NO_ERROR; + } + + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +} // namespace android |