From 7eae198be21ebd57aa99f3aa1fb4dd6f005746ab Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 2 Mar 2012 17:32:28 +0100 Subject: [PATCH] basetransform: refine metadata filter and transform Add a vmethod to filter metadata that should be passed upstream. By default, don't pass anything. Add a vmethod to transform metadata from the input buffer to the output buffer. By default, nothing is transformed or copied. --- libs/gst/base/gstbasetransform.c | 97 +++++++++++++++++++++++++++++++++++++--- libs/gst/base/gstbasetransform.h | 25 ++++++++--- 2 files changed, 112 insertions(+), 10 deletions(-) diff --git a/libs/gst/base/gstbasetransform.c b/libs/gst/base/gstbasetransform.c index 0d18549..d0d0259 100644 --- a/libs/gst/base/gstbasetransform.c +++ b/libs/gst/base/gstbasetransform.c @@ -802,22 +802,41 @@ gst_base_transform_default_decide_allocation (GstBaseTransform * trans, GstQuery * query) { guint i, n_metas; + GstBaseTransformClass *klass; + + klass = GST_BASE_TRANSFORM_GET_CLASS (trans); n_metas = gst_query_get_n_allocation_metas (query); for (i = 0; i < n_metas; i++) { GType api; + gboolean remove; api = gst_query_parse_nth_allocation_meta (query, i); - /* remove all memory dependent metadata because we are going to have to - * allocate different memory for input and output. */ + + /* by default we remove all metadata, subclasses should implement a + * filter_meta function */ if (gst_meta_api_type_has_tag (api, GST_META_TAG_MEMORY)) { - GST_LOG_OBJECT (trans, "removing memory metadata %s", g_type_name (api)); + /* remove all memory dependent metadata because we are going to have to + * allocate different memory for input and output. */ + GST_LOG_OBJECT (trans, "removing memory specific metadata %s", + g_type_name (api)); + remove = TRUE; + } else if (G_LIKELY (klass->filter_meta)) { + /* remove if the subclass said so */ + remove = !klass->filter_meta (trans, query, api); + GST_LOG_OBJECT (trans, "filter_meta for api %s returned: %s", + g_type_name (api), (remove ? "remove" : "keep")); + } else { + GST_LOG_OBJECT (trans, "removing metadata %s", g_type_name (api)); + remove = TRUE; + } + + if (remove) { gst_query_remove_nth_allocation_meta (query, i); i--; n_metas--; } } - return TRUE; } @@ -1306,7 +1325,18 @@ gst_base_transform_default_propose_allocation (GstBaseTransform * trans, GST_DEBUG_OBJECT (trans, "doing passthrough query"); ret = gst_pad_peer_query (trans->srcpad, query); } else { - ret = FALSE; + guint i, n_metas; + /* non-passthrough, copy all metadata, decide_query does not contain the + * metadata anymore that depends on the buffer memory */ + n_metas = gst_query_get_n_allocation_metas (decide_query); + for (i = 0; i < n_metas; i++) { + GType api; + + api = gst_query_parse_nth_allocation_meta (decide_query, i); + GST_DEBUG_OBJECT (trans, "proposing metadata %s", g_type_name (api)); + gst_query_add_allocation_meta (query, api); + } + ret = TRUE; } return ret; } @@ -1518,11 +1548,62 @@ unknown_size: } } +typedef struct +{ + GstBaseTransform *trans; + GstBuffer *outbuf; +} CopyMetaData; + +static gboolean +foreach_metadata (GstBuffer * inbuf, GstMeta ** meta, gpointer user_data) +{ + CopyMetaData *data = user_data; + GstBaseTransform *trans = data->trans; + GstBaseTransformClass *klass; + const GstMetaInfo *info = (*meta)->info; + GstBuffer *outbuf = data->outbuf; + gboolean do_copy; + + klass = GST_BASE_TRANSFORM_GET_CLASS (trans); + + if (GST_META_FLAG_IS_SET (*meta, GST_META_FLAG_POOLED)) { + /* never call the transform_meta with pool private metadata */ + GST_DEBUG_OBJECT (trans, "not copying pooled metadata %s", + g_type_name (info->api)); + do_copy = FALSE; + } else if (gst_meta_api_type_has_tag (info->api, GST_META_TAG_MEMORY)) { + /* never call the transform_meta with memory specific metadata */ + GST_DEBUG_OBJECT (trans, "not copying memory specific metadata %s", + g_type_name (info->api)); + do_copy = FALSE; + } else if (klass->transform_meta) { + do_copy = klass->transform_meta (trans, outbuf, *meta, inbuf); + GST_DEBUG_OBJECT (trans, "transformed metadata %s: copy: %d", + g_type_name (info->api), do_copy); + } else { + do_copy = FALSE; + GST_DEBUG_OBJECT (trans, "not copying metadata %s", + g_type_name (info->api)); + } + + /* we only copy metadata when the subclass implemented a transform_meta + * function and when it returns TRUE */ + if (do_copy) { + GstMetaTransformCopy copy_data = { FALSE, 0, -1 }; + GST_DEBUG_OBJECT (trans, "copy metadata %s", g_type_name (info->api)); + /* simply copy then */ + info->transform_func (outbuf, *meta, inbuf, + _gst_meta_transform_copy, ©_data); + } + return TRUE; +} + static gboolean default_copy_metadata (GstBaseTransform * trans, GstBuffer * inbuf, GstBuffer * outbuf) { GstBaseTransformPrivate *priv = trans->priv; + CopyMetaData data; /* now copy the metadata */ GST_DEBUG_OBJECT (trans, "copying metadata"); @@ -1540,6 +1621,12 @@ default_copy_metadata (GstBaseTransform * trans, if (!priv->gap_aware) GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_GAP); + + data.trans = trans; + data.outbuf = outbuf; + + gst_buffer_foreach_meta (inbuf, foreach_metadata, &data); + return TRUE; /* ERRORS */ diff --git a/libs/gst/base/gstbasetransform.h b/libs/gst/base/gstbasetransform.h index 9a664ad..2251d11 100644 --- a/libs/gst/base/gstbasetransform.h +++ b/libs/gst/base/gstbasetransform.h @@ -141,16 +141,22 @@ struct _GstBaseTransform { * @decide_allocation: Setup the allocation parameters for allocating output * buffers. The passed in query contains the result of the * downstream allocation query. This function is only called - * when not operating in passthrough mode. the default - * implementation will remove metadata that depends on the - * memory. + * when not operating in passthrough mode. The default + * implementation will remove all memory dependent metadata. + * If there is ia @filter_meta method implementation, it will + * be called for all metadata API in the downstream query, + * otherwise the metadata API is removed. + * @filter_meta: Return TRUE if the metadata API should be proposed in the + * upstream allocation query. The default implementation is NULL + * and will cause all metadata to be removed. * @propose_allocation: Propose buffer allocation parameters for upstream elements. * This function must be implemented if the element reads or * writes the buffer content. The query that was passed to * the decide_allocation is passed in this method (or NULL * when the element is in passthrough mode). The default * implementation will pass the query downstream when in - * passthrough mode. + * passthrough mode and will copy all the filtered metadata + * API in non-passthrough mode. * @transform_size: Optional. Given the size of a buffer in the given direction * with the given caps, calculate the size in bytes of a buffer * on the other pad with the given other caps. @@ -183,6 +189,10 @@ struct _GstBaseTransform { * Copy the metadata from the input buffer to the output buffer. * The default implementation will copy the flags, timestamps and * offsets of the buffer. + * @transform_meta: Optional. Transform the metadata on the input buffer to the + * output buffer. By default this method is NULL and no + * metadata is copied. subclasses can implement this method and + * return TRUE if the metadata is to be copied. * @before_transform: Optional. Since 0.10.22 * This method is called right before the base class will * start processing. Dynamic properties or other delayed @@ -221,6 +231,8 @@ struct _GstBaseTransformClass { /* decide allocation query for output buffers */ gboolean (*decide_allocation) (GstBaseTransform *trans, GstQuery *query); + gboolean (*filter_meta) (GstBaseTransform *trans, GstQuery *query, GType api); + /* propose allocation query parameters for input buffers */ gboolean (*propose_allocation) (GstBaseTransform *trans, GstQuery *decide_query, GstQuery *query); @@ -245,8 +257,11 @@ struct _GstBaseTransformClass { GstFlowReturn (*prepare_output_buffer) (GstBaseTransform * trans, GstBuffer *input, GstBuffer **outbuf); - gboolean (*copy_metadata) (GstBaseTransform * trans, GstBuffer *input, + /* metadata */ + gboolean (*copy_metadata) (GstBaseTransform *trans, GstBuffer *input, GstBuffer *outbuf); + gboolean (*transform_meta) (GstBaseTransform *trans, GstBuffer *outbuf, + GstMeta *meta, GstBuffer *inbuf); void (*before_transform) (GstBaseTransform *trans, GstBuffer *buffer); -- 2.7.4