raspberrypi-userland/0002-Revert-Revert-mmal-Support-64-bit-clients.patch
2021-09-03 19:36:39 +08:00

1018 lines
45 KiB
Diff

From 30475fef6590cf05f3f84122238fc2cc9bb1d676 Mon Sep 17 00:00:00 2001
From: yafen <yafen@iscas.ac.cn>
Date: Wed, 11 Aug 2021 04:58:40 +0800
Subject: [PATCH 2/2] Revert "Revert "mmal: Support 64 bit clients""
This reverts commit e31da99739927e87707b2e1bc978e75653706b9c.
---
interface/mmal/vc/mmal_vc_api.c | 72 ++++--
interface/mmal/vc/mmal_vc_client.c | 310 ++++++++++++++++++++----
interface/mmal/vc/mmal_vc_client_priv.h | 6 +
interface/mmal/vc/mmal_vc_msgs.h | 147 ++++++++++-
4 files changed, 461 insertions(+), 74 deletions(-)
diff --git a/interface/mmal/vc/mmal_vc_api.c b/interface/mmal/vc/mmal_vc_api.c
index a20cc28..f35e445 100644
--- a/interface/mmal/vc/mmal_vc_api.c
+++ b/interface/mmal/vc/mmal_vc_api.c
@@ -85,8 +85,10 @@ typedef struct MMAL_COMPONENT_MODULE_T
MMAL_BOOL_T event_ctx_initialised;
MMAL_VC_CLIENT_BUFFER_CONTEXT_T event_ctx; /**< Used as the ctx for event buffers */
+ uint32_t event_ctx_handle; /**< Used as the ctx for event buffers */
} MMAL_COMPONENT_MODULE_T;
+
/*****************************************************************************
* Local function prototypes
*****************************************************************************/
@@ -148,7 +150,8 @@ static MMAL_STATUS_T mmal_vc_port_requirements_set(MMAL_PORT_T *port)
msg.component_handle = module->component_handle;
msg.action = MMAL_WORKER_PORT_ACTION_SET_REQUIREMENTS;
msg.port_handle = module->port_handle;
- msg.param.enable.port = *port;
+ msg.param.enable.port.buffer_num = port->buffer_num;
+ msg.param.enable.port.buffer_size = port->buffer_size;
status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, sizeof(msg),
MMAL_WORKER_PORT_ACTION, &reply, &replylen, MMAL_FALSE);
@@ -224,7 +227,7 @@ static MMAL_STATUS_T mmal_vc_port_enable(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb
for (i = 0; i < pool->headers_num; i++)
{
drv = mmal_buffer_header_driver_data(pool->header[i]);
- drv->client_context = &port->component->priv->module->event_ctx;
+ drv->client_context = port->component->priv->module->event_ctx_handle;
drv->magic = MMAL_MAGIC;
}
@@ -255,7 +258,8 @@ static MMAL_STATUS_T mmal_vc_port_enable(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb
msg.component_handle = module->component_handle;
msg.action = MMAL_WORKER_PORT_ACTION_ENABLE;
msg.port_handle = module->port_handle;
- msg.param.enable.port = *port;
+ msg.param.enable.port.buffer_num = port->buffer_num;
+ msg.param.enable.port.buffer_size = port->buffer_size;
status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, sizeof(msg),
MMAL_WORKER_PORT_ACTION, &reply, &replylen, MMAL_FALSE);
@@ -368,7 +372,7 @@ static MMAL_STATUS_T mmal_vc_port_flush_sync(MMAL_PORT_T *port)
client_context.magic = MMAL_MAGIC;
client_context.port = port;
- msg->drvbuf.client_context = &client_context;
+ msg->drvbuf.client_context = mmal_vc_allocate_client_context(&client_context);
msg->drvbuf.component_handle = module->component_handle;
msg->drvbuf.port_handle = module->port_handle;
msg->drvbuf.magic = MMAL_MAGIC;
@@ -384,6 +388,7 @@ static MMAL_STATUS_T mmal_vc_port_flush_sync(MMAL_PORT_T *port)
if (status != MMAL_SUCCESS)
LOG_ERROR("failed to disable port - reason %d", status);
+ mmal_vc_release_client_context(&client_context);
return status;
}
@@ -502,7 +507,7 @@ static void mmal_vc_do_callback(MMAL_COMPONENT_T *component)
/* Events generated by this component are handled differently */
if (mmal_buffer_header_driver_data(buffer)->client_context ==
- &component->priv->module->event_ctx)
+ component->priv->module->event_ctx_handle)
{
mmal_port_event_send(port, buffer);
return;
@@ -528,14 +533,16 @@ static void mmal_vc_port_send_callback(mmal_worker_buffer_from_host *msg)
{
MMAL_BUFFER_HEADER_T *buffer;
MMAL_PORT_T *port;
- MMAL_VC_CLIENT_BUFFER_CONTEXT_T *client_context = msg->drvbuf.client_context;
+ MMAL_VC_CLIENT_BUFFER_CONTEXT_T *client_context = mmal_vc_lookup_client_context(msg->drvbuf.client_context);
vcos_assert(client_context);
vcos_assert(client_context->magic == MMAL_MAGIC);
buffer = client_context->buffer;
port = client_context->port;
- vcos_blockpool_free(msg->drvbuf.client_context);
+
+ vcos_blockpool_free(client_context);
+ mmal_vc_release_client_context(client_context);
vcos_assert(port->priv->module->magic == MMAL_MAGIC);
mmal_vc_msg_to_buffer_header(buffer, msg);
@@ -614,7 +621,7 @@ static MMAL_STATUS_T mmal_vc_port_send(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *
client_context->callback_event = NULL;
client_context->port = port;
- msg->drvbuf.client_context = client_context;
+ msg->drvbuf.client_context = mmal_vc_allocate_client_context(client_context);
msg->drvbuf.component_handle = module->component_handle;
msg->drvbuf.port_handle = module->port_handle;
msg->drvbuf.magic = MMAL_MAGIC;
@@ -641,12 +648,14 @@ static MMAL_STATUS_T mmal_vc_port_send(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *
if (!VCOS_BLOCKPOOL_IS_VALID_HANDLE_FORMAT(msg->drvbuf.component_handle, 256))
{
LOG_ERROR("bad component handle 0x%x", msg->drvbuf.component_handle);
+ mmal_vc_release_client_context(client_context);
return MMAL_EINVAL;
}
if (msg->drvbuf.port_handle > 255)
{
LOG_ERROR("bad port handle 0x%x", msg->drvbuf.port_handle);
+ mmal_vc_release_client_context(client_context);
return MMAL_EINVAL;
}
@@ -693,7 +702,8 @@ static MMAL_STATUS_T mmal_vc_port_send(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *
if (status != MMAL_SUCCESS)
{
LOG_INFO("failed %d", status);
- vcos_blockpool_free(msg->drvbuf.client_context);
+ vcos_blockpool_free(client_context);
+ mmal_vc_release_client_context(client_context);
buffer->data = mmal_vc_shm_lock(buffer->data, port->priv->module->zero_copy_workaround);
}
@@ -795,6 +805,7 @@ static MMAL_STATUS_T mmal_vc_component_destroy(MMAL_COMPONENT_T *component)
mmal_ports_free(component->clock, component->clock_num);
mmal_queue_destroy(component->priv->module->callback_queue);
+ mmal_vc_release_client_context(&component->priv->module->event_ctx);
vcos_free(component->priv->module);
component->priv->module = NULL;
@@ -802,6 +813,7 @@ static MMAL_STATUS_T mmal_vc_component_destroy(MMAL_COMPONENT_T *component)
fail:
// no longer require videocore
mmal_vc_release();
+ mmal_vc_release_client_component(component);
mmal_vc_shm_exit();
mmal_vc_deinit();
return status;
@@ -928,6 +940,17 @@ MMAL_STATUS_T mmal_vc_get_core_stats(MMAL_CORE_STATISTICS_T *stats,
return status;
}
+static void mmal_vc_copy_es_format_to_vc(MMAL_ES_FORMAT_T *src, MMAL_VC_ES_FORMAT_T *dest)
+{
+ // IPC MMAL_VC_ES_FORMAT_T is not necessarily the same as MMAL_ES_FORMAT_T,
+ // so copy fields individually.
+ dest->type = src->type;
+ dest->encoding = src->encoding;
+ dest->encoding_variant = src->encoding_variant;
+ dest->bitrate = src->bitrate;
+ dest->flags = src->flags;
+ dest->extradata_size = src->extradata_size;
+}
/** Get port context data. */
static MMAL_STATUS_T mmal_vc_port_info_get(MMAL_PORT_T *port)
@@ -969,9 +992,9 @@ static MMAL_STATUS_T mmal_vc_port_info_get(MMAL_PORT_T *port)
port->buffer_alignment_min = reply.port.buffer_alignment_min;
port->is_enabled = reply.port.is_enabled;
port->capabilities = reply.port.capabilities;
- reply.format.extradata = port->format->extradata;
- reply.format.es = port->format->es;
- *port->format = reply.format;
+
+ mmal_vc_copy_es_format_from_vc(&reply.format, port->format);
+
*port->format->es = reply.es;
if(port->format->extradata_size)
{
@@ -1001,15 +1024,22 @@ static MMAL_STATUS_T mmal_vc_port_info_set(MMAL_PORT_T *port)
msg.component_handle = module->component_handle;
msg.port_type = port->type;
msg.index = port->index;
- msg.port = *port;
- msg.format = *port->format;
+
+ //Only copy the values that are used into the MMAL_PORT_T of the IPC.
+ msg.port.buffer_num = port->buffer_num;
+ msg.port.buffer_size = port->buffer_size;
+ msg.port.is_enabled = port->is_enabled;
+
+ mmal_vc_copy_es_format_to_vc(port->format, &msg.format);
+
msg.es = *port->format->es;
+
if(msg.format.extradata_size > MMAL_FORMAT_EXTRADATA_MAX_SIZE)
{
vcos_assert(0);
msg.format.extradata_size = MMAL_FORMAT_EXTRADATA_MAX_SIZE;
}
- memcpy(msg.extradata, msg.format.extradata, msg.format.extradata_size);
+ memcpy(msg.extradata, port->format->extradata, msg.format.extradata_size);
LOG_TRACE("set port info (%i:%i)", port->type, port->index);
@@ -1037,9 +1067,9 @@ static MMAL_STATUS_T mmal_vc_port_info_set(MMAL_PORT_T *port)
port->buffer_alignment_min = reply.port.buffer_alignment_min;
port->is_enabled = reply.port.is_enabled;
port->capabilities = reply.port.capabilities;
- reply.format.extradata = port->format->extradata;
- reply.format.es = port->format->es;
- *port->format = reply.format;
+
+ mmal_vc_copy_es_format_from_vc(&reply.format, port->format);
+
*port->format->es = reply.es;
if(port->format->extradata_size)
{
@@ -1328,7 +1358,6 @@ static MMAL_STATUS_T mmal_vc_component_create(const char *name, MMAL_COMPONENT_T
return MMAL_EINVAL;
}
- msg.client_component = component;
/* coverity[secure_coding] Length tested above */
strcpy(msg.name, basename);
#ifdef __linux__
@@ -1351,6 +1380,8 @@ static MMAL_STATUS_T mmal_vc_component_create(const char *name, MMAL_COMPONENT_T
return status;
}
+ msg.client_component = mmal_vc_allocate_client_component(component);
+
// claim VC for entire duration of component.
status = mmal_vc_use();
@@ -1371,6 +1402,7 @@ static MMAL_STATUS_T mmal_vc_component_create(const char *name, MMAL_COMPONENT_T
LOG_ERROR("failed to create component '%s' (%i:%s)", name, status,
mmal_status_to_string(status));
mmal_vc_release();
+ mmal_vc_release_client_component(component);
mmal_vc_shm_exit();
mmal_vc_deinit();
return status;
@@ -1391,6 +1423,7 @@ static MMAL_STATUS_T mmal_vc_component_create(const char *name, MMAL_COMPONENT_T
MMAL_WORKER_COMPONENT_DESTROY, &reply, &replylen, MMAL_FALSE);
vcos_assert(destroy_status == MMAL_SUCCESS);
mmal_vc_release();
+ mmal_vc_release_client_component(component);
mmal_vc_shm_exit();
mmal_vc_deinit();
return status;
@@ -1496,6 +1529,7 @@ static MMAL_STATUS_T mmal_vc_component_create(const char *name, MMAL_COMPONENT_T
module->event_ctx_initialised = MMAL_FALSE;
module->event_ctx.magic = MMAL_MAGIC;
module->event_ctx.callback_event = mmal_vc_port_send_event_callback;
+ module->event_ctx_handle = mmal_vc_allocate_client_context(&module->event_ctx);
/* populate component structure */
component->priv->pf_enable = mmal_vc_component_enable;
diff --git a/interface/mmal/vc/mmal_vc_client.c b/interface/mmal/vc/mmal_vc_client.c
index 4935a27..f3241d2 100644
--- a/interface/mmal/vc/mmal_vc_client.c
+++ b/interface/mmal/vc/mmal_vc_client.c
@@ -53,6 +53,7 @@ static VCOS_LOG_CAT_T mmal_ipc_log_category;
*/
typedef struct MMAL_WAITER_T
{
+ int index;
VCOS_SEMAPHORE_T sem;
unsigned inuse;
void *dest; /**< Where to write reply */
@@ -82,6 +83,151 @@ struct MMAL_CLIENT_T
MMAL_BOOL_T inited;
};
+/*****************************************************************************
+ * Lookup table functions for client_component handles.
+ * Required as the IPC is strictly 32bit, therefore 64bit userland can not
+ * pass in the required pointers.
+ *****************************************************************************/
+#define MAX_COMPONENT_HANDLES 128
+
+typedef struct
+{
+ unsigned int inuse:1;
+ unsigned int index:31;
+ MMAL_COMPONENT_T *component;
+} MMAL_CLIENT_COMPONENT_T;
+
+typedef struct
+{
+ MMAL_CLIENT_COMPONENT_T components[MAX_COMPONENT_HANDLES];
+ VCOS_MUTEX_T lock;
+} MMAL_CLIENT_COMPONENT_POOL_T;
+
+static MMAL_CLIENT_COMPONENT_POOL_T client_component_pool;
+
+uint32_t mmal_vc_allocate_client_component(MMAL_COMPONENT_T *component)
+{
+ int i;
+
+ vcos_mutex_lock(&client_component_pool.lock);
+ for (i=0; i<MAX_COMPONENT_HANDLES; i++)
+ {
+ if (client_component_pool.components[i].inuse == 0)
+ break;
+ }
+
+ if (vcos_verify(i != MAX_COMPONENT_HANDLES))
+ {
+ client_component_pool.components[i].index = i;
+ client_component_pool.components[i].component = component;
+ client_component_pool.components[i].inuse = 1;
+ }
+ vcos_mutex_unlock(&client_component_pool.lock);
+
+ return i;
+}
+
+static MMAL_COMPONENT_T *lookup_client_component(int index)
+{
+ if (vcos_verify(index < MAX_COMPONENT_HANDLES))
+ {
+ vcos_assert(client_component_pool.components[index].inuse);
+ return client_component_pool.components[index].component;
+ }
+
+ return NULL;
+}
+
+void mmal_vc_release_client_component(MMAL_COMPONENT_T *component)
+{
+ int i;
+
+ vcos_mutex_lock(&client_component_pool.lock);
+ for (i=0; i<MAX_COMPONENT_HANDLES; i++)
+ {
+ if (client_component_pool.components[i].component == component)
+ {
+ client_component_pool.components[i].component = NULL;
+ client_component_pool.components[i].inuse = 0;
+ }
+ }
+ vcos_mutex_unlock(&client_component_pool.lock);
+}
+
+#define MAX_CLIENT_CONTEXTS 512
+
+typedef struct
+{
+ unsigned int inuse:1;
+ unsigned int index:31;
+ MMAL_VC_CLIENT_BUFFER_CONTEXT_T *ctx;
+} MMAL_CLIENT_CONTEXT_T;
+
+typedef struct
+{
+ MMAL_CLIENT_CONTEXT_T contexts[MAX_CLIENT_CONTEXTS];
+ VCOS_MUTEX_T lock;
+} MMAL_CLIENT_CONTEXT_POOL_T;
+
+static MMAL_CLIENT_CONTEXT_POOL_T client_context_pool;
+#define CLIENT_CONTEXT_MAGIC 0xFEDC0000
+#define CLIENT_CONTEXT_MAGIC_MASK(a) (a & 0xFFFF)
+#define CLIENT_CONTEXT_MAGIC_CHECK(a) (a & 0xFFFF0000)
+
+uint32_t mmal_vc_allocate_client_context(MMAL_VC_CLIENT_BUFFER_CONTEXT_T *context)
+{
+ int i;
+
+ vcos_mutex_lock(&client_context_pool.lock);
+ for (i=0; i<MAX_CLIENT_CONTEXTS; i++)
+ {
+ if (client_context_pool.contexts[i].inuse == 0)
+ break;
+ }
+
+ if (vcos_verify(i != MAX_CLIENT_CONTEXTS))
+ {
+ client_context_pool.contexts[i].index = i;
+ client_context_pool.contexts[i].ctx = context;
+ client_context_pool.contexts[i].inuse = 1;
+ }
+ vcos_mutex_unlock(&client_context_pool.lock);
+
+ return i | CLIENT_CONTEXT_MAGIC;
+}
+
+MMAL_VC_CLIENT_BUFFER_CONTEXT_T *mmal_vc_lookup_client_context(int index)
+{
+ if (vcos_verify((CLIENT_CONTEXT_MAGIC_CHECK(index) == CLIENT_CONTEXT_MAGIC) &&
+ (CLIENT_CONTEXT_MAGIC_MASK(index) < MAX_CLIENT_CONTEXTS)))
+ {
+ vcos_assert(client_context_pool.contexts[CLIENT_CONTEXT_MAGIC_MASK(index)].inuse);
+ return client_context_pool.contexts[CLIENT_CONTEXT_MAGIC_MASK(index)].ctx;
+ }
+
+ return NULL;
+}
+
+void mmal_vc_release_client_context(MMAL_VC_CLIENT_BUFFER_CONTEXT_T *context)
+{
+ int i;
+
+ vcos_mutex_lock(&client_context_pool.lock);
+ for (i=0; i<MAX_CLIENT_CONTEXTS; i++)
+ {
+ if (client_context_pool.contexts[i].ctx == context)
+ {
+ client_context_pool.contexts[i].ctx = NULL;
+ client_context_pool.contexts[i].inuse = 0;
+ break;
+ }
+ }
+ if (i >= MAX_CLIENT_CONTEXTS)
+ LOG_ERROR("Failed to release context %p - not found", context);
+
+ vcos_mutex_unlock(&client_context_pool.lock);
+}
+
/* One client per process/VC connection. Multiple threads may
* be using a single client.
*/
@@ -90,6 +236,8 @@ static MMAL_CLIENT_T client;
static void init_once(void)
{
vcos_mutex_create(&client.lock, VCOS_FUNCTION);
+ vcos_mutex_create(&client_component_pool.lock, VCOS_FUNCTION);
+ vcos_mutex_create(&client_context_pool.lock, VCOS_FUNCTION);
}
/** Create a pool of wait-structures.
@@ -107,6 +255,7 @@ static MMAL_STATUS_T create_waitpool(MMAL_WAITPOOL_T *waitpool)
for (i=0; i<MAX_WAITERS; i++)
{
waitpool->waiters[i].inuse = 0;
+ waitpool->waiters[i].index = i;
status = vcos_semaphore_create(&waitpool->waiters[i].sem,
"mmal waiter", 0);
if (status != VCOS_SUCCESS)
@@ -161,6 +310,19 @@ static MMAL_WAITER_T *get_waiter(MMAL_CLIENT_T *client)
return waiter;
}
+/** Look up a waiter reference based on the static client
+ */
+static MMAL_WAITER_T *lookup_waiter(uint32_t index)
+{
+ //NB this uses the static client variable, whilst most others use the client
+ //variable passed in. I don't believe there is a way to have multiple clients
+ //in one process, so this should be safe.
+ if (vcos_verify(index < MAX_WAITERS))
+ return &client.waitpool.waiters[index];
+
+ return NULL;
+}
+
/** Return a waiter to the pool.
*/
static void release_waiter(MMAL_CLIENT_T *client, MMAL_WAITER_T *waiter)
@@ -198,13 +360,15 @@ static void mmal_vc_handle_event_msg(VCHIQ_HEADER_T *vchiq_header,
void *context)
{
mmal_worker_event_to_host *msg = (mmal_worker_event_to_host *)vchiq_header->data;
- MMAL_COMPONENT_T *component = msg->client_component;
+ MMAL_COMPONENT_T *component = lookup_client_component(msg->client_component);
+ MMAL_VC_CLIENT_BUFFER_CONTEXT_T *client_context;
MMAL_BUFFER_HEADER_T *buffer;
MMAL_STATUS_T status;
MMAL_PORT_T *port;
- LOG_DEBUG("event to host, cmd 0x%08x len %d to component %p port (%d,%d)",
- msg->cmd, msg->length, msg->client_component, msg->port_type, msg->port_num);
+ LOG_DEBUG("event to host, cmd 0x%08x len %d to component %u/%p port (%d,%d)",
+ msg->cmd, msg->length, msg->client_component, component, msg->port_type,
+ msg->port_num);
(void)context;
port = mmal_vc_port_by_number(component, msg->port_type, msg->port_num);
@@ -229,11 +393,12 @@ static void mmal_vc_handle_event_msg(VCHIQ_HEADER_T *vchiq_header,
}
buffer->length = msg->length;
+ client_context = mmal_vc_lookup_client_context(mmal_buffer_header_driver_data(buffer)->client_context);
/* Sanity check that the event buffers have the proper vc client context */
if (!vcos_verify(mmal_buffer_header_driver_data(buffer)->magic == MMAL_MAGIC &&
- mmal_buffer_header_driver_data(buffer)->client_context &&
- mmal_buffer_header_driver_data(buffer)->client_context->magic == MMAL_MAGIC &&
- mmal_buffer_header_driver_data(buffer)->client_context->callback_event))
+ client_context &&
+ client_context->magic == MMAL_MAGIC &&
+ client_context->callback_event))
{
LOG_ERROR("event buffers not configured properly by component");
goto error;
@@ -258,9 +423,53 @@ static void mmal_vc_handle_event_msg(VCHIQ_HEADER_T *vchiq_header,
else
{
if (msg->length)
- memcpy(buffer->data, msg->data, msg->length);
+ {
+ if (buffer->cmd == MMAL_EVENT_FORMAT_CHANGED && buffer->length >= msg->length)
+ {
+ //64bit userspace.
+ //No need to fix the pointers in the msg as mmal_event_format_changed_get
+ //will do that for us, but the start positions of each section does need
+ //to be adjusted.
+ mmal_worker_event_format_changed *fmt_changed_vc =
+ (mmal_worker_event_format_changed*)msg->data;
+ MMAL_EVENT_FORMAT_CHANGED_T *fmt_changed_host =
+ (MMAL_EVENT_FORMAT_CHANGED_T*)buffer->data;
+ MMAL_ES_FORMAT_T *fmt_host;
+ MMAL_VC_ES_FORMAT_T *fmt_vc;
+ MMAL_ES_SPECIFIC_FORMAT_T *es_host, *es_vc;
+ const uint32_t size_host = sizeof(MMAL_EVENT_FORMAT_CHANGED_T) +
+ sizeof(MMAL_ES_FORMAT_T) +
+ sizeof(MMAL_ES_SPECIFIC_FORMAT_T);
+ const uint32_t size_vc = sizeof(mmal_worker_event_format_changed) +
+ sizeof(MMAL_VC_ES_FORMAT_T) +
+ sizeof(MMAL_ES_SPECIFIC_FORMAT_T);
+
+ //Copy the base event (ignore the format pointer from the end)
+ memcpy(fmt_changed_host, fmt_changed_vc, sizeof(mmal_worker_event_format_changed));
+ fmt_changed_host->format = NULL;
+
+ //Copy the es format
+ fmt_vc = (MMAL_VC_ES_FORMAT_T *)&fmt_changed_vc[1];
+ fmt_host = (MMAL_ES_FORMAT_T *)&fmt_changed_host[1];
+ mmal_vc_copy_es_format_from_vc(fmt_vc, fmt_host);
+
+ //Copy the ES_SPECIFIC_FORMAT_T (structures are identical)
+ es_host = (MMAL_ES_SPECIFIC_FORMAT_T *)&fmt_host[1];
+ es_vc = (MMAL_ES_SPECIFIC_FORMAT_T *)&fmt_vc[1];
+ memcpy(es_host, es_vc, sizeof(MMAL_ES_SPECIFIC_FORMAT_T));
+
+ //Copy the extradata (if present)
+ fmt_host->extradata_size = msg->length - size_vc;
+ memcpy((uint8_t *)&es_host[1], (uint8_t*)&es_vc[1], fmt_host->extradata_size);
+ buffer->length = size_host + fmt_host->extradata_size;
+ }
+ else
+ {
+ memcpy(buffer->data, msg->data, msg->length);
+ }
+ }
- mmal_buffer_header_driver_data(buffer)->client_context->callback_event(port, buffer);
+ client_context->callback_event(port, buffer);
LOG_DEBUG("done callback back to client");
vchiq_release_message(service, vchiq_header);
}
@@ -324,29 +533,36 @@ static VCHIQ_STATUS_T mmal_vc_vchiq_callback(VCHIQ_REASON_T reason,
if (msg->msgid == MMAL_WORKER_BUFFER_TO_HOST)
{
+ MMAL_VC_CLIENT_BUFFER_CONTEXT_T *client_context;
LOG_TRACE("buffer to host");
mmal_worker_buffer_from_host *msg = (mmal_worker_buffer_from_host *)vchiq_header->data;
- LOG_TRACE("len %d context %p", msg->buffer_header.length, msg->drvbuf.client_context);
- vcos_assert(msg->drvbuf.client_context);
- vcos_assert(msg->drvbuf.client_context->magic == MMAL_MAGIC);
+
+ client_context = mmal_vc_lookup_client_context(msg->drvbuf.client_context);
+ LOG_TRACE("len %d context %p", msg->buffer_header.length, client_context);
+ vcos_assert(client_context);
+ vcos_assert(client_context->magic == MMAL_MAGIC);
/* If the buffer is referencing another, need to replicate it here
* in order to use the reference buffer's payload and ensure the
* reference is not released prematurely */
if (msg->has_reference)
- mmal_buffer_header_replicate(msg->drvbuf.client_context->buffer,
- msg->drvbuf_ref.client_context->buffer);
+ {
+ MMAL_VC_CLIENT_BUFFER_CONTEXT_T *ref_context =
+ mmal_vc_lookup_client_context(msg->drvbuf_ref.client_context);
+ vcos_assert(ref_context);
+ mmal_buffer_header_replicate(client_context->buffer, ref_context->buffer);
+ }
/* Sanity check the size of the transfer so we don't overrun our buffer */
if (!vcos_verify(msg->buffer_header.offset + msg->buffer_header.length <=
- msg->drvbuf.client_context->buffer->alloc_size))
+ client_context->buffer->alloc_size))
{
LOG_TRACE("buffer too small (%i, %i)",
msg->buffer_header.offset + msg->buffer_header.length,
- msg->drvbuf.client_context->buffer->alloc_size);
+ client_context->buffer->alloc_size);
msg->buffer_header.length = 0;
msg->buffer_header.flags |= MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED;
- msg->drvbuf.client_context->callback(msg);
+ client_context->callback(msg);
vchiq_release_message(service, vchiq_header);
break;
}
@@ -357,7 +573,7 @@ static VCHIQ_STATUS_T mmal_vc_vchiq_callback(VCHIQ_REASON_T reason,
{
/* a buffer full of data for us to process */
VCHIQ_STATUS_T vst = VCHIQ_SUCCESS;
- LOG_TRACE("queue bulk rx: %p, %d", msg->drvbuf.client_context->buffer->data +
+ LOG_TRACE("queue bulk rx: %p, %d", client_context->buffer->data +
msg->buffer_header.offset, msg->buffer_header.length);
int len = msg->buffer_header.length;
len = (len+3) & (~3);
@@ -370,7 +586,7 @@ static VCHIQ_STATUS_T mmal_vc_vchiq_callback(VCHIQ_REASON_T reason,
{
/* buffer transferred using vchiq bulk xfer */
vst = vchiq_queue_bulk_receive(service,
- msg->drvbuf.client_context->buffer->data + msg->buffer_header.offset,
+ client_context->buffer->data + msg->buffer_header.offset,
len, vchiq_header);
if (vst != VCHIQ_SUCCESS)
@@ -378,20 +594,20 @@ static VCHIQ_STATUS_T mmal_vc_vchiq_callback(VCHIQ_REASON_T reason,
LOG_TRACE("queue bulk rx len %d failed to start", msg->buffer_header.length);
msg->buffer_header.length = 0;
msg->buffer_header.flags |= MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED;
- msg->drvbuf.client_context->callback(msg);
+ client_context->callback(msg);
vchiq_release_message(service, vchiq_header);
}
}
else if (msg->payload_in_message <= MMAL_VC_SHORT_DATA)
{
/* we have already received the buffer data in the message! */
- MMAL_BUFFER_HEADER_T *dst = msg->drvbuf.client_context->buffer;
+ MMAL_BUFFER_HEADER_T *dst = client_context->buffer;
LOG_TRACE("short data: dst = %p, dst->data = %p, len %d short len %d", dst, dst? dst->data : 0, msg->buffer_header.length, msg->payload_in_message);
memcpy(dst->data, msg->short_data, msg->payload_in_message);
dst->offset = 0;
dst->length = msg->payload_in_message;
vchiq_release_message(service, vchiq_header);
- msg->drvbuf.client_context->callback(msg);
+ client_context->callback(msg);
}
else
{
@@ -409,9 +625,9 @@ static VCHIQ_STATUS_T mmal_vc_vchiq_callback(VCHIQ_REASON_T reason,
* be picked up in the callback to complete the sequence.
*/
LOG_TRACE("doing cb (%p) context %p",
- msg->drvbuf.client_context, msg->drvbuf.client_context ?
- msg->drvbuf.client_context->callback : 0);
- msg->drvbuf.client_context->callback(msg);
+ client_context, client_context ?
+ client_context->callback : 0);
+ client_context->callback(msg);
LOG_TRACE("done callback back to client");
vchiq_release_message(service, vchiq_header);
}
@@ -422,7 +638,7 @@ static VCHIQ_STATUS_T mmal_vc_vchiq_callback(VCHIQ_REASON_T reason,
}
else
{
- MMAL_WAITER_T *waiter = msg->u.waiter;
+ MMAL_WAITER_T *waiter = lookup_waiter(msg->u.waiter);
LOG_TRACE("waking up waiter at %p", waiter);
vcos_assert(waiter->inuse);
int len = vcos_min(waiter->destlen, vchiq_header->size);
@@ -443,7 +659,7 @@ static VCHIQ_STATUS_T mmal_vc_vchiq_callback(VCHIQ_REASON_T reason,
#ifdef VCOS_LOGGING_ENABLED
mmal_worker_buffer_from_host *msg = (mmal_worker_buffer_from_host *)context;
#endif
- LOG_TRACE("bulk tx done: %p, %d", msg->buffer_header.data, msg->buffer_header.length);
+ LOG_TRACE("bulk tx done: %08x, %d", msg->buffer_header.data, msg->buffer_header.length);
}
break;
case VCHIQ_BULK_RECEIVE_DONE:
@@ -453,18 +669,21 @@ static VCHIQ_STATUS_T mmal_vc_vchiq_callback(VCHIQ_REASON_T reason,
if (msg_hdr->msgid == MMAL_WORKER_BUFFER_TO_HOST)
{
mmal_worker_buffer_from_host *msg = (mmal_worker_buffer_from_host *)msg_hdr;
- vcos_assert(msg->drvbuf.client_context->magic == MMAL_MAGIC);
- msg->drvbuf.client_context->callback(msg);
- LOG_TRACE("bulk rx done: %p, %d", msg->buffer_header.data, msg->buffer_header.length);
+ MMAL_VC_CLIENT_BUFFER_CONTEXT_T *client_context = mmal_vc_lookup_client_context(msg->drvbuf.client_context);
+ vcos_assert(client_context && client_context->magic == MMAL_MAGIC);
+ client_context->callback(msg);
+ LOG_TRACE("bulk rx done: %08x, %d", msg->buffer_header.data, msg->buffer_header.length);
}
else
{
mmal_worker_event_to_host *msg = (mmal_worker_event_to_host *)msg_hdr;
- MMAL_PORT_T *port = mmal_vc_port_by_number(msg->client_component, msg->port_type, msg->port_num);
+ MMAL_COMPONENT_T *component = lookup_client_component(msg->client_component);
+ MMAL_VC_CLIENT_BUFFER_CONTEXT_T *client_context =
+ mmal_vc_lookup_client_context(mmal_buffer_header_driver_data(msg->delayed_buffer)->client_context);
+ MMAL_PORT_T *port = mmal_vc_port_by_number(component, msg->port_type, msg->port_num);
- vcos_assert(port);
- mmal_buffer_header_driver_data(msg->delayed_buffer)->
- client_context->callback_event(port, msg->delayed_buffer);
+ vcos_assert(client_context && port);
+ client_context->callback_event(port, msg->delayed_buffer);
LOG_DEBUG("event bulk rx done, length %d", msg->length);
}
vchiq_release_message(service, header);
@@ -477,21 +696,25 @@ static VCHIQ_STATUS_T mmal_vc_vchiq_callback(VCHIQ_REASON_T reason,
if (msg_hdr->msgid == MMAL_WORKER_BUFFER_TO_HOST)
{
mmal_worker_buffer_from_host *msg = (mmal_worker_buffer_from_host *)msg_hdr;
- LOG_TRACE("bulk rx aborted: %p, %d", msg->buffer_header.data, msg->buffer_header.length);
- vcos_assert(msg->drvbuf.client_context->magic == MMAL_MAGIC);
+ MMAL_VC_CLIENT_BUFFER_CONTEXT_T *client_context = mmal_vc_lookup_client_context(msg->drvbuf.client_context);
+ LOG_TRACE("bulk rx aborted: %08x, %d", msg->buffer_header.data, msg->buffer_header.length);
+ vcos_assert(client_context && client_context->magic == MMAL_MAGIC);
msg->buffer_header.flags |= MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED;
- msg->drvbuf.client_context->callback(msg);
+ client_context->callback(msg);
}
else
{
mmal_worker_event_to_host *msg = (mmal_worker_event_to_host *)msg_hdr;
- MMAL_PORT_T *port = mmal_vc_port_by_number(msg->client_component, msg->port_type, msg->port_num);
+ MMAL_COMPONENT_T *component = lookup_client_component(msg->client_component);
+ MMAL_VC_CLIENT_BUFFER_CONTEXT_T *client_context =
+ mmal_vc_lookup_client_context(mmal_buffer_header_driver_data(msg->delayed_buffer)->client_context);
+ MMAL_PORT_T *port = mmal_vc_port_by_number(component, msg->port_type, msg->port_num);
vcos_assert(port);
LOG_DEBUG("event bulk rx aborted");
msg->delayed_buffer->flags |= MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED;
- mmal_buffer_header_driver_data(msg->delayed_buffer)->
- client_context->callback_event(port, msg->delayed_buffer);
+
+ client_context->callback_event(port, msg->delayed_buffer);
}
vchiq_release_message(service, header);
}
@@ -499,9 +722,12 @@ static VCHIQ_STATUS_T mmal_vc_vchiq_callback(VCHIQ_REASON_T reason,
case VCHIQ_BULK_TRANSMIT_ABORTED:
{
mmal_worker_buffer_from_host *msg = (mmal_worker_buffer_from_host *)context;
- LOG_INFO("bulk tx aborted: %p, %d", msg->buffer_header.data, msg->buffer_header.length);
- vcos_assert(msg->drvbuf.client_context->magic == MMAL_MAGIC);
+ MMAL_VC_CLIENT_BUFFER_CONTEXT_T *client_context =
+ mmal_vc_lookup_client_context(msg->drvbuf.client_context);
+ LOG_INFO("bulk tx aborted: %08x, %d", msg->buffer_header.data, msg->buffer_header.length);
+ vcos_assert(client_context->magic == MMAL_MAGIC);
/* Nothing to do as the VC side will release the buffer and notify us of the error */
+ client_context = NULL; // Avoid warnings in release builds
}
break;
default:
@@ -548,7 +774,7 @@ MMAL_STATUS_T mmal_vc_sendwait_message(struct MMAL_CLIENT_T *client,
waiter = get_waiter(client);
msg_header->msgid = msgid;
- msg_header->u.waiter = waiter;
+ msg_header->u.waiter = waiter->index;
msg_header->magic = MMAL_MAGIC;
waiter->dest = dest;
diff --git a/interface/mmal/vc/mmal_vc_client_priv.h b/interface/mmal/vc/mmal_vc_client_priv.h
index 0fc3aaa..0b8f570 100644
--- a/interface/mmal/vc/mmal_vc_client_priv.h
+++ b/interface/mmal/vc/mmal_vc_client_priv.h
@@ -76,5 +76,11 @@ MMAL_STATUS_T mmal_vc_send_message(MMAL_CLIENT_T *client,
uint8_t *data, size_t data_size,
uint32_t msgid);
+uint32_t mmal_vc_allocate_client_component(MMAL_COMPONENT_T *component);
+void mmal_vc_release_client_component(MMAL_COMPONENT_T *component);
+
+uint32_t mmal_vc_allocate_client_context(MMAL_VC_CLIENT_BUFFER_CONTEXT_T *context);
+MMAL_VC_CLIENT_BUFFER_CONTEXT_T *mmal_vc_lookup_client_context(int index);
+void mmal_vc_release_client_context(MMAL_VC_CLIENT_BUFFER_CONTEXT_T *context);
#endif
diff --git a/interface/mmal/vc/mmal_vc_msgs.h b/interface/mmal/vc/mmal_vc_msgs.h
index 343922b..7e1a3e2 100644
--- a/interface/mmal/vc/mmal_vc_msgs.h
+++ b/interface/mmal/vc/mmal_vc_msgs.h
@@ -112,10 +112,10 @@ typedef struct
{
uint32_t magic;
uint32_t msgid;
- struct MMAL_CONTROL_SERVICE_T *control_service; /** Handle to the control service */
+ uint32_t control_service; /** Handle to the control service (unused) */
union {
- struct MMAL_WAITER_T *waiter; /** User-land wait structure, passed back */
+ uint32_t waiter; /** User-land wait structure, passed back */
} u;
MMAL_STATUS_T status; /** Result code, passed back */
@@ -152,7 +152,7 @@ typedef struct
typedef struct
{
mmal_worker_msg_header header;
- void *client_component; /** Client component */
+ uint32_t client_component; /** Client component */
char name[128];
uint32_t pid; /**< For debug */
} mmal_worker_component_create;
@@ -206,6 +206,71 @@ typedef struct
} mmal_worker_port_info_get;
vcos_static_assert(sizeof(mmal_worker_port_info_get) <= MMAL_WORKER_MAX_MSG_LEN);
+typedef struct
+{
+ MMAL_ES_TYPE_T type; /**< Type of the elementary stream */
+
+ MMAL_FOURCC_T encoding; /**< FourCC specifying the encoding of the elementary stream.
+ * See the \ref MmalEncodings "pre-defined encodings" for some
+ * examples.
+ */
+ MMAL_FOURCC_T encoding_variant;/**< FourCC specifying the specific encoding variant of
+ * the elementary stream. See the \ref MmalEncodingVariants
+ * "pre-defined encoding variants" for some examples.
+ */
+
+ uint32_t es; /**< Type specific information for the elementary stream */
+
+ uint32_t bitrate; /**< Bitrate in bits per second */
+ uint32_t flags; /**< Flags describing properties of the elementary stream.
+ * See \ref elementarystreamflags "Elementary stream flags".
+ */
+
+ uint32_t extradata_size; /**< Size of the codec specific data */
+ uint32_t extradata; /**< Codec specific data */
+
+} MMAL_VC_ES_FORMAT_T;
+
+typedef struct
+{
+ uint32_t priv; /**< Private member used by the framework */
+ uint32_t name; /**< Port name. Used for debugging purposes (Read Only) */
+
+ MMAL_PORT_TYPE_T type; /**< Type of the port (Read Only) */
+ uint16_t index; /**< Index of the port in its type list (Read Only) */
+ uint16_t index_all; /**< Index of the port in the list of all ports (Read Only) */
+
+ uint32_t is_enabled; /**< Indicates whether the port is enabled or not (Read Only) */
+ uint32_t format; /**< Format of the elementary stream */
+
+ uint32_t buffer_num_min; /**< Minimum number of buffers the port requires (Read Only).
+ This is set by the component. */
+ uint32_t buffer_size_min; /**< Minimum size of buffers the port requires (Read Only).
+ This is set by the component. */
+ uint32_t buffer_alignment_min; /**< Minimum alignment requirement for the buffers (Read Only).
+ A value of zero means no special alignment requirements.
+ This is set by the component. */
+ uint32_t buffer_num_recommended; /**< Number of buffers the port recommends for optimal performance (Read Only).
+ A value of zero means no special recommendation.
+ This is set by the component. */
+ uint32_t buffer_size_recommended; /**< Size of buffers the port recommends for optimal performance (Read Only).
+ A value of zero means no special recommendation.
+ This is set by the component. */
+ uint32_t buffer_num; /**< Actual number of buffers the port will use.
+ This is set by the client. */
+ uint32_t buffer_size; /**< Actual maximum size of the buffers that will be sent
+ to the port. This is set by the client. */
+
+ uint32_t component; /**< Component this port belongs to (Read Only) */
+ uint32_t userdata; /**< Field reserved for use by the client */
+
+ uint32_t capabilities; /**< Flags describing the capabilities of a port (Read Only).
+ * Bitwise combination of \ref portcapabilities "Port capabilities"
+ * values.
+ */
+
+} MMAL_VC_PORT_T;
+
/** Component port info. Used to set port info.
*/
typedef struct
@@ -214,8 +279,8 @@ typedef struct
uint32_t component_handle; /**< Which component */
MMAL_PORT_TYPE_T port_type; /**< Type of port */
uint32_t index; /**< Which port of given type to get */
- MMAL_PORT_T port;
- MMAL_ES_FORMAT_T format;
+ MMAL_VC_PORT_T port;
+ MMAL_VC_ES_FORMAT_T format;
MMAL_ES_SPECIFIC_FORMAT_T es;
uint8_t extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE];
} mmal_worker_port_info_set;
@@ -231,8 +296,8 @@ typedef struct
uint32_t index; /**< Which port of given type to get */
int32_t found; /**< Did we find anything? */
uint32_t port_handle; /**< Handle to use for this port */
- MMAL_PORT_T port;
- MMAL_ES_FORMAT_T format;
+ MMAL_VC_PORT_T port;
+ MMAL_VC_ES_FORMAT_T format;
MMAL_ES_SPECIFIC_FORMAT_T es;
uint8_t extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE];
} mmal_worker_port_info;
@@ -285,7 +350,7 @@ typedef struct
/** Action parameter */
union {
struct {
- MMAL_PORT_T port;
+ MMAL_VC_PORT_T port;
} enable;
struct {
uint32_t component_handle;
@@ -357,9 +422,41 @@ struct MMAL_DRIVER_BUFFER_T
uint32_t port_handle; /**< Index into array of ports for this component */
/** Client side uses this to get back to its context structure. */
- struct MMAL_VC_CLIENT_BUFFER_CONTEXT_T *client_context;
+ uint32_t client_context;
};
+typedef struct MMAL_VC_BUFFER_HEADER_T
+{
+ uint32_t next; /**< Used to link several buffer headers together */
+
+ uint32_t priv; /**< Data private to the framework */
+
+ uint32_t cmd; /**< Defines what the buffer header contains. This is a FourCC
+ with 0 as a special value meaning stream data */
+
+ uint32_t data; /**< Pointer to the start of the payload buffer (should not be
+ changed by component) */
+ uint32_t alloc_size; /**< Allocated size in bytes of payload buffer */
+ uint32_t length; /**< Number of bytes currently used in the payload buffer (starting
+ from offset) */
+ uint32_t offset; /**< Offset in bytes to the start of valid data in the payload buffer */
+
+ uint32_t flags; /**< Flags describing properties of a buffer header (see
+ \ref bufferheaderflags "Buffer header flags") */
+
+ int64_t pts; /**< Presentation timestamp in microseconds. \ref MMAL_TIME_UNKNOWN
+ is used when the pts is unknown. */
+ int64_t dts; /**< Decode timestamp in microseconds (dts = pts, except in the case
+ of video streams with B frames). \ref MMAL_TIME_UNKNOWN
+ is used when the dts is unknown. */
+
+ /** Type specific data that's associated with a payload buffer */
+ uint32_t type;
+
+ uint32_t user_data; /**< Field reserved for use by the client */
+
+} MMAL_VC_BUFFER_HEADER_T;
+
/** Receive a buffer from the host.
*
* @sa mmal_port_send_buffer()
@@ -382,7 +479,7 @@ typedef struct mmal_worker_buffer_from_host
struct MMAL_DRIVER_BUFFER_T drvbuf_ref;
/** the buffer header itself */
- MMAL_BUFFER_HEADER_T buffer_header;
+ MMAL_VC_BUFFER_HEADER_T buffer_header;
MMAL_BUFFER_HEADER_TYPE_SPECIFIC_T buffer_header_type_specific;
MMAL_BOOL_T is_zero_copy;
@@ -411,17 +508,29 @@ typedef struct mmal_worker_event_to_host
{
mmal_worker_msg_header header;
- struct MMAL_COMPONENT_T *client_component;
+ uint32_t client_component;
uint32_t port_type;
uint32_t port_num;
uint32_t cmd;
uint32_t length;
uint8_t data[MMAL_WORKER_EVENT_SPACE];
- MMAL_BUFFER_HEADER_T *delayed_buffer; /* Only used to remember buffer for bulk rx */
+ MMAL_BUFFER_HEADER_T *delayed_buffer; /* Only used to remember buffer for bulk rx */ // FIXME
} mmal_worker_event_to_host;
vcos_static_assert(sizeof(mmal_worker_event_to_host) <= MMAL_WORKER_MAX_MSG_LEN);
+typedef struct mmal_worker_event_format_changed
+{
+ uint32_t buffer_size_min; /**< Minimum size of buffers the port requires */
+ uint32_t buffer_num_min; /**< Minimum number of buffers the port requires */
+ uint32_t buffer_size_recommended; /**< Size of buffers the port recommends for optimal performance.
+ A value of zero means no special recommendation. */
+ uint32_t buffer_num_recommended; /**< Number of buffers the port recommends for optimal
+ performance. A value of zero means no special recommendation. */
+
+ uint32_t format; /**< New elementary stream format */
+} mmal_worker_event_format_changed;
+
typedef struct
{
mmal_worker_msg_header header;
@@ -515,7 +624,7 @@ static inline void mmal_vc_buffer_header_to_msg(mmal_worker_buffer_from_host *ms
msg->buffer_header.pts = header->pts;
msg->buffer_header.dts = header->dts;
msg->buffer_header.alloc_size = header->alloc_size;
- msg->buffer_header.data = header->data;
+ msg->buffer_header.data = (uintptr_t)header->data;
msg->buffer_header_type_specific = *header->type;
}
@@ -531,5 +640,17 @@ static inline void mmal_vc_msg_to_buffer_header(MMAL_BUFFER_HEADER_T *header,
*header->type = msg->buffer_header_type_specific;
}
+static inline void mmal_vc_copy_es_format_from_vc(MMAL_VC_ES_FORMAT_T *src, MMAL_ES_FORMAT_T *dest)
+{
+ // IPC MMAL_VC_ES_FORMAT_T is not necessarily the same as MMAL_ES_FORMAT_T,
+ // so copy fields individually.
+ dest->type = src->type;
+ dest->encoding = src->encoding;
+ dest->encoding_variant = src->encoding_variant;
+ dest->bitrate = src->bitrate;
+ dest->flags = src->flags;
+ dest->extradata_size = src->extradata_size;
+}
+
#endif
--
2.27.0