basetransform: refine metadata filter and transform
authorWim Taymans <wim.taymans@collabora.co.uk>
Fri, 2 Mar 2012 16:32:28 +0000 (17:32 +0100)
committerWim Taymans <wim.taymans@collabora.co.uk>
Fri, 2 Mar 2012 16:32:28 +0000 (17:32 +0100)
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
libs/gst/base/gstbasetransform.h

index 0d18549..d0d0259 100644 (file)
@@ -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, &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 */
index 9a664ad..2251d11 100644 (file)
@@ -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);