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

