gst/base/gstbasetransform.*: Make passthrough work using the bufferpools.
authorWim Taymans <wim.taymans@gmail.com>
Fri, 15 Jul 2005 10:41:32 +0000 (10:41 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Fri, 15 Jul 2005 10:41:32 +0000 (10:41 +0000)
Original commit message from CVS:
* gst/base/gstbasetransform.c: (gst_base_transform_init),
(gst_base_transform_transform_caps), (gst_base_transform_getcaps),
(gst_base_transform_configure_caps), (gst_base_transform_setcaps),
(gst_base_transform_get_size), (gst_base_transform_buffer_alloc),
(gst_base_transform_handle_buffer), (gst_base_transform_getrange),
(gst_base_transform_chain), (gst_base_transform_change_state),
(gst_base_transform_set_passthrough),
(gst_base_transform_is_passthrough):
* gst/base/gstbasetransform.h:
Make passthrough work using the bufferpools.
Changed API a bit, subclasses have to write into a buffer
provided by the base class.
More debug info in nego functions.

* gst/elements/gstidentity.c: (gst_identity_init),
(gst_identity_transform):
Port to new base class.

ChangeLog
gst/base/gstbasetransform.c
gst/base/gstbasetransform.h
gst/elements/gstidentity.c
libs/gst/base/gstbasetransform.c
libs/gst/base/gstbasetransform.h
plugins/elements/gstidentity.c

index ac10dbe..9227c14 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,25 @@
 2005-07-15  Wim Taymans  <wim@fluendo.com>
 
+       * gst/base/gstbasetransform.c: (gst_base_transform_init),
+       (gst_base_transform_transform_caps), (gst_base_transform_getcaps),
+       (gst_base_transform_configure_caps), (gst_base_transform_setcaps),
+       (gst_base_transform_get_size), (gst_base_transform_buffer_alloc),
+       (gst_base_transform_handle_buffer), (gst_base_transform_getrange),
+       (gst_base_transform_chain), (gst_base_transform_change_state),
+       (gst_base_transform_set_passthrough),
+       (gst_base_transform_is_passthrough):
+       * gst/base/gstbasetransform.h:
+       Make passthrough work using the bufferpools.
+       Changed API a bit, subclasses have to write into a buffer
+       provided by the base class.
+       More debug info in nego functions.
+       
+       * gst/elements/gstidentity.c: (gst_identity_init),
+       (gst_identity_transform):
+       Port to new base class.
+
+2005-07-15  Wim Taymans  <wim@fluendo.com>
+
        * gst/gstmessage.c: (gst_message_new_state_changed):
        * tools/gst-launch.c: (event_loop), (main):
        Totally dump messages in -launch with the -m option.
index df64054..375e316 100644 (file)
@@ -88,6 +88,8 @@ static gboolean gst_base_transform_src_activate_pull (GstPad * pad,
     gboolean active);
 static gboolean gst_base_transform_sink_activate_push (GstPad * pad,
     gboolean active);
+static guint gst_base_transform_get_size (GstBaseTransform * trans);
+
 static GstElementStateReturn gst_base_transform_change_state (GstElement *
     element);
 
@@ -96,10 +98,10 @@ static GstFlowReturn gst_base_transform_getrange (GstPad * pad, guint64 offset,
     guint length, GstBuffer ** buffer);
 static GstFlowReturn gst_base_transform_chain (GstPad * pad,
     GstBuffer * buffer);
-static GstFlowReturn gst_base_transform_handle_buffer (GstBaseTransform * trans,
-    GstBuffer * inbuf, GstBuffer ** outbuf);
 static GstCaps *gst_base_transform_getcaps (GstPad * pad);
 static gboolean gst_base_transform_setcaps (GstPad * pad, GstCaps * caps);
+static GstFlowReturn gst_base_transform_buffer_alloc (GstPad * pad,
+    guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
 
 /* static guint gst_base_transform_signals[LAST_SIGNAL] = { 0 }; */
 
@@ -159,6 +161,8 @@ gst_base_transform_init (GstBaseTransform * trans, gpointer g_class)
       GST_DEBUG_FUNCPTR (gst_base_transform_chain));
   gst_pad_set_activatepush_function (trans->sinkpad,
       GST_DEBUG_FUNCPTR (gst_base_transform_sink_activate_push));
+  gst_pad_set_bufferalloc_function (trans->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_base_transform_buffer_alloc));
   gst_element_add_pad (GST_ELEMENT (trans), trans->sinkpad);
 
   pad_template =
@@ -174,6 +178,8 @@ gst_base_transform_init (GstBaseTransform * trans, gpointer g_class)
   gst_pad_set_activatepull_function (trans->srcpad,
       GST_DEBUG_FUNCPTR (gst_base_transform_src_activate_pull));
   gst_element_add_pad (GST_ELEMENT (trans), trans->srcpad);
+
+  trans->passthrough = FALSE;
 }
 
 static GstCaps *
@@ -187,10 +193,31 @@ gst_base_transform_transform_caps (GstBaseTransform * trans, GstPad * pad,
 
   GST_DEBUG_OBJECT (trans, "from: %" GST_PTR_FORMAT, caps);
 
-  if (klass->transform_caps)
-    ret = klass->transform_caps (trans, pad, caps);
-  else
+  /* if there is a custom transform function, use this */
+  if (klass->transform_caps) {
+    GstCaps *temp;
+    gint i;
+
+    ret = gst_caps_new_empty ();
+
+    /* we send caps with just one structure to the transform 
+     * function as this is easier for the element */
+    for (i = 0; i < gst_caps_get_size (caps); i++) {
+      GstCaps *nth;
+
+      nth = gst_caps_copy_nth (caps, i);
+      GST_DEBUG_OBJECT (trans, "  from: %" GST_PTR_FORMAT, nth);
+      temp = klass->transform_caps (trans, pad, nth);
+      gst_caps_unref (nth);
+      GST_DEBUG_OBJECT (trans, "  to  : %" GST_PTR_FORMAT, temp);
+
+      gst_caps_append (ret, temp);
+    }
+    gst_caps_do_simplify (ret);
+  } else {
+    /* else use the identity transform */
     ret = gst_caps_ref (caps);
+  }
 
   GST_DEBUG_OBJECT (trans, "to:   %" GST_PTR_FORMAT, ret);
 
@@ -210,26 +237,67 @@ gst_base_transform_getcaps (GstPad * pad)
 
   /* we can do what the peer can */
   caps = gst_pad_peer_get_caps (otherpad);
-
   if (caps) {
     GstCaps *temp;
+    const GstCaps *templ;
+
+    GST_DEBUG ("peer caps  %" GST_PTR_FORMAT, caps);
 
-    temp = gst_caps_intersect (caps, gst_pad_get_pad_template_caps (otherpad));
+    /* filtered against our padtemplate */
+    templ = gst_pad_get_pad_template_caps (otherpad);
+    GST_DEBUG ("our template  %" GST_PTR_FORMAT, templ);
+    temp = gst_caps_intersect (caps, templ);
+    GST_DEBUG ("intersected %" GST_PTR_FORMAT, temp);
     gst_caps_unref (caps);
+    /* then see what we can tranform this to */
     caps = gst_base_transform_transform_caps (trans, otherpad, temp);
+    GST_DEBUG ("transformed  %" GST_PTR_FORMAT, caps);
     gst_caps_unref (temp);
-    temp = gst_caps_intersect (caps, gst_pad_get_pad_template_caps (pad));
+    if (caps == NULL)
+      goto done;
+
+    /* and filter against the template again */
+    templ = gst_pad_get_pad_template_caps (pad);
+    GST_DEBUG ("our template  %" GST_PTR_FORMAT, templ);
+    temp = gst_caps_intersect (caps, templ);
+    GST_DEBUG ("intersected %" GST_PTR_FORMAT, temp);
     gst_caps_unref (caps);
+    /* this is what we can do */
     caps = temp;
   } else {
     /* no peer, our padtemplate is enough then */
     caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
   }
 
+done:
+  GST_DEBUG ("returning  %" GST_PTR_FORMAT, caps);
+
   return caps;
 }
 
 static gboolean
+gst_base_transform_configure_caps (GstBaseTransform * trans, GstCaps * in,
+    GstCaps * out)
+{
+  gboolean ret = TRUE;
+  GstBaseTransformClass *klass;
+
+  klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
+
+  /* no configure the element with the caps */
+  if (klass->set_caps) {
+    ret = klass->set_caps (trans, in, out);
+  }
+
+  /* if all goes well, get the size of the output buffer */
+  if (ret) {
+    trans->out_size = gst_base_transform_get_size (trans);
+    GST_DEBUG ("output buffer size %d", trans->out_size);
+  }
+  return ret;
+}
+
+static gboolean
 gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
 {
   GstBaseTransform *trans;
@@ -252,11 +320,9 @@ gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
   /* see how we can transform the input caps */
   othercaps = gst_base_transform_transform_caps (trans, pad, caps);
 
-  if (!othercaps || gst_caps_is_empty (othercaps)) {
-    GST_DEBUG ("transform returned useless  %" GST_PTR_FORMAT, othercaps);
-    ret = FALSE;
-    goto done;
-  }
+  /* check if transform is empty */
+  if (!othercaps || gst_caps_is_empty (othercaps))
+    goto no_transform;
 
   if (!gst_caps_is_fixed (othercaps)) {
     GstCaps *temp;
@@ -266,7 +332,7 @@ gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
     temp = gst_caps_intersect (othercaps, caps);
     GST_DEBUG ("intersect returned %" GST_PTR_FORMAT, temp);
     if (temp) {
-      if (!gst_caps_is_empty (temp)) {
+      if (!gst_caps_is_empty (temp) && otherpeer) {
         GST_DEBUG ("try passthrough with %" GST_PTR_FORMAT, caps);
         /* try passthrough. we know it's fixed, because caps is fixed */
         if (gst_pad_accept_caps (otherpeer, caps)) {
@@ -312,39 +378,99 @@ gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
     GST_DEBUG ("after fixating %" GST_PTR_FORMAT, othercaps);
   }
 
-  g_return_val_if_fail (gst_caps_is_fixed (othercaps), FALSE);
+  /* caps should be fixed now */
+  if (!gst_caps_is_fixed (othercaps))
+    goto could_not_fixate;
 
-  if (otherpeer && !gst_pad_accept_caps (otherpeer, othercaps)) {
-    GST_DEBUG ("FAILED to get peer of %" GST_PTR_FORMAT
-        " to accept %" GST_PTR_FORMAT, otherpad, othercaps);
-    ret = FALSE;
-    goto done;
-  }
+  /* and peer should accept */
+  if (otherpeer && !gst_pad_accept_caps (otherpeer, othercaps))
+    goto peer_no_accept;
 
   GST_DEBUG ("got final caps %" GST_PTR_FORMAT, othercaps);
 
   /* we know this will work, we implement the setcaps */
   gst_pad_set_caps (otherpad, othercaps);
 
-  /* success, let the element know */
-  if (klass->set_caps) {
+  trans->in_place = gst_caps_is_equal (caps, othercaps);
+  GST_DEBUG ("in_place: %d", trans->in_place);
+
+  /* see if we have to configure the element now */
+  if (!trans->delay_configure) {
     if (pad == trans->sinkpad)
-      ret = klass->set_caps (trans, caps, othercaps);
+      ret = gst_base_transform_configure_caps (trans, caps, othercaps);
     else
-      ret = klass->set_caps (trans, othercaps, caps);
+      ret = gst_base_transform_configure_caps (trans, othercaps, caps);
   }
 
 done:
-
   if (otherpeer)
     gst_object_unref (otherpeer);
-
   if (othercaps)
     gst_caps_unref (othercaps);
 
   return ret;
+
+  /* ERRORS */
+no_transform:
+  {
+    GST_DEBUG ("transform returned useless  %" GST_PTR_FORMAT, othercaps);
+    ret = FALSE;
+    goto done;
+  }
+could_not_fixate:
+  {
+    GST_DEBUG ("FAILED to fixate %" GST_PTR_FORMAT, othercaps);
+    ret = FALSE;
+    goto done;
+  }
+peer_no_accept:
+  {
+    GST_DEBUG ("FAILED to get peer of %" GST_PTR_FORMAT
+        " to accept %" GST_PTR_FORMAT, otherpad, othercaps);
+    ret = FALSE;
+    goto done;
+  }
+}
+
+static guint
+gst_base_transform_get_size (GstBaseTransform * trans)
+{
+  guint res = -1;
+  GstBaseTransformClass *bclass;
+
+  bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
+  if (bclass->get_size) {
+    res = bclass->get_size (trans);
+    GST_DEBUG ("get size function returned %d", res);
+  }
+
+  return res;
+}
+
+static GstFlowReturn
+gst_base_transform_buffer_alloc (GstPad * pad, guint64 offset, guint size,
+    GstCaps * caps, GstBuffer ** buf)
+{
+  GstBaseTransform *trans;
+  GstFlowReturn res;
+
+  trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
+
+  if (trans->in_place) {
+    /* we can only proxy the bufferpool if we do in_place transforms */
+    res = gst_pad_alloc_buffer (trans->srcpad, offset, size, caps, buf);
+  } else {
+    /* else let the default alloc function allocate a buffer */
+    *buf = NULL;
+    res = GST_FLOW_OK;
+  }
+
+  gst_object_unref (trans);
+
+  return res;
 }
 
+
 static gboolean
 gst_base_transform_event (GstPad * pad, GstEvent * event)
 {
@@ -383,6 +509,92 @@ gst_base_transform_event (GstPad * pad, GstEvent * event)
 }
 
 static GstFlowReturn
+gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
+    GstBuffer ** outbuf)
+{
+  GstBaseTransformClass *bclass;
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
+
+  if (trans->in_place) {
+    if (bclass->transform_ip) {
+      gst_buffer_ref (inbuf);
+
+      /* in place transform and subclass supports method */
+      ret = bclass->transform_ip (trans, inbuf);
+
+      *outbuf = inbuf;
+    } else {
+      /* in place transform and subclass does not support method */
+      if (bclass->transform) {
+        /* make a copy of the buffer */
+        *outbuf = inbuf;
+        inbuf = gst_buffer_copy (inbuf);
+
+        ret = bclass->transform (trans, inbuf, *outbuf);
+      } else {
+        ret = GST_FLOW_NOT_SUPPORTED;
+      }
+    }
+  } else {
+    /* figure out the output size */
+    if (trans->out_size == -1) {
+      /* ask subclass */
+      if ((trans->out_size = gst_base_transform_get_size (trans)) == -1)
+        /* else we have an error */
+        goto no_size;
+    }
+
+    /* we cannot reconfigure the element yet as we are still processing
+     * the old buffer. We will therefore delay the reconfiguration of the
+     * element until we have processed this last buffer. */
+    trans->delay_configure = TRUE;
+
+    /* no in place transform, get buffer, this might renegotiate. */
+    ret = gst_pad_alloc_buffer (trans->srcpad,
+        GST_BUFFER_OFFSET (inbuf), trans->out_size,
+        GST_PAD_CAPS (trans->srcpad), outbuf);
+
+    trans->delay_configure = FALSE;
+
+    if (ret != GST_FLOW_OK)
+      goto no_buffer;
+
+    gst_buffer_stamp (*outbuf, inbuf);
+
+    if (bclass->transform)
+      ret = bclass->transform (trans, inbuf, *outbuf);
+    else
+      ret = GST_FLOW_NOT_SUPPORTED;
+
+    if (ret)
+      ret =
+          gst_base_transform_configure_caps (trans,
+          GST_PAD_CAPS (trans->sinkpad), GST_PAD_CAPS (trans->srcpad));
+  }
+  gst_buffer_unref (inbuf);
+
+  return ret;
+
+  /* ERRORS */
+no_size:
+  {
+    gst_buffer_unref (inbuf);
+    GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
+        ("subclass did not specify output size"),
+        ("subclass did not specify output size"));
+    return GST_FLOW_ERROR;
+  }
+no_buffer:
+  {
+    gst_buffer_unref (inbuf);
+    GST_DEBUG ("could not get buffer from pool");
+    return ret;
+  }
+}
+
+static GstFlowReturn
 gst_base_transform_getrange (GstPad * pad, guint64 offset,
     guint length, GstBuffer ** buffer)
 {
@@ -390,16 +602,14 @@ gst_base_transform_getrange (GstPad * pad, guint64 offset,
   GstFlowReturn ret;
   GstBuffer *inbuf;
 
-  trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad));
-
-  GST_STREAM_LOCK (pad);
+  trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
 
   ret = gst_pad_pull_range (trans->sinkpad, offset, length, &inbuf);
   if (ret == GST_FLOW_OK) {
     ret = gst_base_transform_handle_buffer (trans, inbuf, buffer);
   }
 
-  GST_STREAM_UNLOCK (pad);
+  gst_object_unref (trans);
 
   return ret;
 }
@@ -408,33 +618,17 @@ static GstFlowReturn
 gst_base_transform_chain (GstPad * pad, GstBuffer * buffer)
 {
   GstBaseTransform *trans;
-  GstFlowReturn ret = GST_FLOW_OK;
+  GstFlowReturn ret;
   GstBuffer *outbuf;
 
-  trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad));
-
-  GST_STREAM_LOCK (pad);
+  trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
 
   ret = gst_base_transform_handle_buffer (trans, buffer, &outbuf);
   if (ret == GST_FLOW_OK) {
     ret = gst_pad_push (trans->srcpad, outbuf);
   }
 
-  GST_STREAM_UNLOCK (pad);
-
-  return ret;
-}
-
-static GstFlowReturn
-gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
-    GstBuffer ** outbuf)
-{
-  GstFlowReturn ret = GST_FLOW_OK;
-  GstBaseTransformClass *bclass;
-
-  bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
-  if (bclass->transform)
-    ret = bclass->transform (trans, inbuf, outbuf);
+  gst_object_unref (trans);
 
   return ret;
 }
@@ -524,6 +718,10 @@ gst_base_transform_change_state (GstElement * element)
     case GST_STATE_NULL_TO_READY:
       break;
     case GST_STATE_READY_TO_PAUSED:
+      GST_LOCK (trans);
+      trans->in_place = trans->passthrough;
+      trans->out_size = -1;
+      GST_UNLOCK (trans);
       break;
     case GST_STATE_PAUSED_TO_PLAYING:
       break;
@@ -548,3 +746,48 @@ gst_base_transform_change_state (GstElement * element)
 
   return result;
 }
+
+/**
+ * gst_base_transform_set_passthrough:
+ * @trans: the #GstBaseTransform to set
+ * @passthrough: boolean indicating passthrough mode.
+ *
+ * Set passthrough mode for this filter by default. This is mostly
+ * usefull for filters that do not care about negotiation.
+ *
+ * MT safe.
+ */
+void
+gst_base_transform_set_passthrough (GstBaseTransform * trans,
+    gboolean passthrough)
+{
+  g_return_if_fail (trans != NULL);
+
+  GST_LOCK (trans);
+  trans->passthrough = passthrough;
+  GST_UNLOCK (trans);
+}
+
+/**
+ * gst_base_transform_is_passthrough:
+ * @trans: the #GstBaseTransform to query
+ *
+ * See if @trans is configured as a passthrough transform.
+ *
+ * Returns: TRUE is the transform is configured in passthrough mode.
+ *
+ * MT safe.
+ */
+gboolean
+gst_base_transform_is_passthrough (GstBaseTransform * trans)
+{
+  gboolean result;
+
+  g_return_val_if_fail (trans != NULL, FALSE);
+
+  GST_LOCK (trans);
+  result = trans->passthrough;
+  GST_UNLOCK (trans);
+
+  return result;
+}
index e0581e6..fcd34ab 100644 (file)
@@ -49,6 +49,12 @@ struct _GstBaseTransform {
   /* source and sink pads */
   GstPad       *sinkpad;
   GstPad       *srcpad;
+
+  gboolean      passthrough;
+
+  gboolean      in_place;
+  guint                 out_size;
+  gboolean      delay_configure;
 };
 
 struct _GstBaseTransformClass {
@@ -65,6 +71,9 @@ struct _GstBaseTransformClass {
   gboolean      (*set_caps)     (GstBaseTransform *trans, GstCaps *incaps,
                                  GstCaps *outcaps);
 
+  /* get the size of the output buffer, -1 on error */
+  guint         (*get_size)     (GstBaseTransform *trans);
+
   /* start and stop processing, ideal for opening/closing the resource */
   gboolean      (*start)        (GstBaseTransform *trans);
   gboolean      (*stop)         (GstBaseTransform *trans);
@@ -73,9 +82,15 @@ struct _GstBaseTransformClass {
 
   /* transform one incoming buffer to one outgoing buffer */
   GstFlowReturn (*transform)    (GstBaseTransform *trans, GstBuffer *inbuf,
-                                 GstBuffer **outbuf);
+                                 GstBuffer *outbuf);
+
+  /* transform a buffer inplace */
+  GstFlowReturn (*transform_ip) (GstBaseTransform *trans, GstBuffer *buf);
 };
 
+void           gst_base_transform_set_passthrough (GstBaseTransform *trans, gboolean passthrough);
+gboolean       gst_base_transform_is_passthrough (GstBaseTransform *trans);
+
 GType gst_base_transform_get_type (void);
 
 G_END_DECLS
index 7c2ac82..75f7c3a 100644 (file)
@@ -98,7 +98,7 @@ static void gst_identity_get_property (GObject * object, guint prop_id,
 
 static gboolean gst_identity_event (GstBaseTransform * trans, GstEvent * event);
 static GstFlowReturn gst_identity_transform (GstBaseTransform * trans,
-    GstBuffer * inbuf, GstBuffer ** outbuf);
+    GstBuffer * inbuf, GstBuffer * outbuf);
 static gboolean gst_identity_start (GstBaseTransform * trans);
 static gboolean gst_identity_stop (GstBaseTransform * trans);
 
@@ -190,6 +190,8 @@ gst_identity_class_init (GstIdentityClass * klass)
 static void
 gst_identity_init (GstIdentity * identity)
 {
+  gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (identity), TRUE);
+
   identity->sleep_time = DEFAULT_SLEEP_TIME;
   identity->error_after = DEFAULT_ERROR_AFTER;
   identity->drop_probability = DEFAULT_DROP_PROBABILITY;
@@ -261,7 +263,7 @@ gst_identity_check_perfect (GstIdentity * identity, GstBuffer * buf)
 
 static GstFlowReturn
 gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
-    GstBuffer ** outbuf)
+    GstBuffer * outbuf)
 {
   GstFlowReturn ret = GST_FLOW_OK;
   GstIdentity *identity = GST_IDENTITY (trans);
@@ -274,7 +276,6 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
     if (identity->error_after == 0) {
       GST_ELEMENT_ERROR (identity, CORE, FAILED,
           (_("Failed after iterations as requested.")), (NULL));
-      gst_buffer_unref (inbuf);
       return GST_FLOW_ERROR;
     }
   }
@@ -294,7 +295,6 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
           GST_BUFFER_FLAGS (inbuf), inbuf);
       GST_UNLOCK (identity);
       g_object_notify (G_OBJECT (identity), "last-message");
-      gst_buffer_unref (inbuf);
       return GST_FLOW_OK;
     }
   }
@@ -319,19 +319,16 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
     g_object_notify (G_OBJECT (identity), "last-message");
   }
 
-  *outbuf = gst_buffer_make_writable (inbuf);
-  /* inbuf is no longer usable */
-
   if (identity->datarate > 0) {
     GstClockTime time = identity->offset * GST_SECOND / identity->datarate;
 
-    GST_BUFFER_TIMESTAMP (*outbuf) = time;
-    GST_BUFFER_DURATION (*outbuf) =
-        GST_BUFFER_SIZE (*outbuf) * GST_SECOND / identity->datarate;
+    GST_BUFFER_TIMESTAMP (outbuf) = time;
+    GST_BUFFER_DURATION (outbuf) =
+        GST_BUFFER_SIZE (outbuf) * GST_SECOND / identity->datarate;
   }
 
   g_signal_emit (G_OBJECT (identity), gst_identity_signals[SIGNAL_HANDOFF], 0,
-      *outbuf);
+      outbuf);
 
   if (identity->sync) {
     GstClock *clock;
@@ -344,7 +341,7 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
       /* FIXME: actually unlock this somewhere if the state changes */
       GST_LOCK (identity);
       identity->clock_id = gst_clock_new_single_shot_id (clock,
-          GST_BUFFER_TIMESTAMP (*outbuf) + GST_ELEMENT (identity)->base_time);
+          GST_BUFFER_TIMESTAMP (outbuf) + GST_ELEMENT (identity)->base_time);
       GST_UNLOCK (identity);
       cret = gst_clock_id_wait (identity->clock_id, NULL);
       GST_LOCK (identity);
@@ -358,7 +355,7 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
     }
   }
 
-  identity->offset += GST_BUFFER_SIZE (*outbuf);
+  identity->offset += GST_BUFFER_SIZE (outbuf);
 
   if (identity->sleep_time && ret == GST_FLOW_OK)
     g_usleep (identity->sleep_time);
index df64054..375e316 100644 (file)
@@ -88,6 +88,8 @@ static gboolean gst_base_transform_src_activate_pull (GstPad * pad,
     gboolean active);
 static gboolean gst_base_transform_sink_activate_push (GstPad * pad,
     gboolean active);
+static guint gst_base_transform_get_size (GstBaseTransform * trans);
+
 static GstElementStateReturn gst_base_transform_change_state (GstElement *
     element);
 
@@ -96,10 +98,10 @@ static GstFlowReturn gst_base_transform_getrange (GstPad * pad, guint64 offset,
     guint length, GstBuffer ** buffer);
 static GstFlowReturn gst_base_transform_chain (GstPad * pad,
     GstBuffer * buffer);
-static GstFlowReturn gst_base_transform_handle_buffer (GstBaseTransform * trans,
-    GstBuffer * inbuf, GstBuffer ** outbuf);
 static GstCaps *gst_base_transform_getcaps (GstPad * pad);
 static gboolean gst_base_transform_setcaps (GstPad * pad, GstCaps * caps);
+static GstFlowReturn gst_base_transform_buffer_alloc (GstPad * pad,
+    guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
 
 /* static guint gst_base_transform_signals[LAST_SIGNAL] = { 0 }; */
 
@@ -159,6 +161,8 @@ gst_base_transform_init (GstBaseTransform * trans, gpointer g_class)
       GST_DEBUG_FUNCPTR (gst_base_transform_chain));
   gst_pad_set_activatepush_function (trans->sinkpad,
       GST_DEBUG_FUNCPTR (gst_base_transform_sink_activate_push));
+  gst_pad_set_bufferalloc_function (trans->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_base_transform_buffer_alloc));
   gst_element_add_pad (GST_ELEMENT (trans), trans->sinkpad);
 
   pad_template =
@@ -174,6 +178,8 @@ gst_base_transform_init (GstBaseTransform * trans, gpointer g_class)
   gst_pad_set_activatepull_function (trans->srcpad,
       GST_DEBUG_FUNCPTR (gst_base_transform_src_activate_pull));
   gst_element_add_pad (GST_ELEMENT (trans), trans->srcpad);
+
+  trans->passthrough = FALSE;
 }
 
 static GstCaps *
@@ -187,10 +193,31 @@ gst_base_transform_transform_caps (GstBaseTransform * trans, GstPad * pad,
 
   GST_DEBUG_OBJECT (trans, "from: %" GST_PTR_FORMAT, caps);
 
-  if (klass->transform_caps)
-    ret = klass->transform_caps (trans, pad, caps);
-  else
+  /* if there is a custom transform function, use this */
+  if (klass->transform_caps) {
+    GstCaps *temp;
+    gint i;
+
+    ret = gst_caps_new_empty ();
+
+    /* we send caps with just one structure to the transform 
+     * function as this is easier for the element */
+    for (i = 0; i < gst_caps_get_size (caps); i++) {
+      GstCaps *nth;
+
+      nth = gst_caps_copy_nth (caps, i);
+      GST_DEBUG_OBJECT (trans, "  from: %" GST_PTR_FORMAT, nth);
+      temp = klass->transform_caps (trans, pad, nth);
+      gst_caps_unref (nth);
+      GST_DEBUG_OBJECT (trans, "  to  : %" GST_PTR_FORMAT, temp);
+
+      gst_caps_append (ret, temp);
+    }
+    gst_caps_do_simplify (ret);
+  } else {
+    /* else use the identity transform */
     ret = gst_caps_ref (caps);
+  }
 
   GST_DEBUG_OBJECT (trans, "to:   %" GST_PTR_FORMAT, ret);
 
@@ -210,26 +237,67 @@ gst_base_transform_getcaps (GstPad * pad)
 
   /* we can do what the peer can */
   caps = gst_pad_peer_get_caps (otherpad);
-
   if (caps) {
     GstCaps *temp;
+    const GstCaps *templ;
+
+    GST_DEBUG ("peer caps  %" GST_PTR_FORMAT, caps);
 
-    temp = gst_caps_intersect (caps, gst_pad_get_pad_template_caps (otherpad));
+    /* filtered against our padtemplate */
+    templ = gst_pad_get_pad_template_caps (otherpad);
+    GST_DEBUG ("our template  %" GST_PTR_FORMAT, templ);
+    temp = gst_caps_intersect (caps, templ);
+    GST_DEBUG ("intersected %" GST_PTR_FORMAT, temp);
     gst_caps_unref (caps);
+    /* then see what we can tranform this to */
     caps = gst_base_transform_transform_caps (trans, otherpad, temp);
+    GST_DEBUG ("transformed  %" GST_PTR_FORMAT, caps);
     gst_caps_unref (temp);
-    temp = gst_caps_intersect (caps, gst_pad_get_pad_template_caps (pad));
+    if (caps == NULL)
+      goto done;
+
+    /* and filter against the template again */
+    templ = gst_pad_get_pad_template_caps (pad);
+    GST_DEBUG ("our template  %" GST_PTR_FORMAT, templ);
+    temp = gst_caps_intersect (caps, templ);
+    GST_DEBUG ("intersected %" GST_PTR_FORMAT, temp);
     gst_caps_unref (caps);
+    /* this is what we can do */
     caps = temp;
   } else {
     /* no peer, our padtemplate is enough then */
     caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
   }
 
+done:
+  GST_DEBUG ("returning  %" GST_PTR_FORMAT, caps);
+
   return caps;
 }
 
 static gboolean
+gst_base_transform_configure_caps (GstBaseTransform * trans, GstCaps * in,
+    GstCaps * out)
+{
+  gboolean ret = TRUE;
+  GstBaseTransformClass *klass;
+
+  klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
+
+  /* no configure the element with the caps */
+  if (klass->set_caps) {
+    ret = klass->set_caps (trans, in, out);
+  }
+
+  /* if all goes well, get the size of the output buffer */
+  if (ret) {
+    trans->out_size = gst_base_transform_get_size (trans);
+    GST_DEBUG ("output buffer size %d", trans->out_size);
+  }
+  return ret;
+}
+
+static gboolean
 gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
 {
   GstBaseTransform *trans;
@@ -252,11 +320,9 @@ gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
   /* see how we can transform the input caps */
   othercaps = gst_base_transform_transform_caps (trans, pad, caps);
 
-  if (!othercaps || gst_caps_is_empty (othercaps)) {
-    GST_DEBUG ("transform returned useless  %" GST_PTR_FORMAT, othercaps);
-    ret = FALSE;
-    goto done;
-  }
+  /* check if transform is empty */
+  if (!othercaps || gst_caps_is_empty (othercaps))
+    goto no_transform;
 
   if (!gst_caps_is_fixed (othercaps)) {
     GstCaps *temp;
@@ -266,7 +332,7 @@ gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
     temp = gst_caps_intersect (othercaps, caps);
     GST_DEBUG ("intersect returned %" GST_PTR_FORMAT, temp);
     if (temp) {
-      if (!gst_caps_is_empty (temp)) {
+      if (!gst_caps_is_empty (temp) && otherpeer) {
         GST_DEBUG ("try passthrough with %" GST_PTR_FORMAT, caps);
         /* try passthrough. we know it's fixed, because caps is fixed */
         if (gst_pad_accept_caps (otherpeer, caps)) {
@@ -312,39 +378,99 @@ gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
     GST_DEBUG ("after fixating %" GST_PTR_FORMAT, othercaps);
   }
 
-  g_return_val_if_fail (gst_caps_is_fixed (othercaps), FALSE);
+  /* caps should be fixed now */
+  if (!gst_caps_is_fixed (othercaps))
+    goto could_not_fixate;
 
-  if (otherpeer && !gst_pad_accept_caps (otherpeer, othercaps)) {
-    GST_DEBUG ("FAILED to get peer of %" GST_PTR_FORMAT
-        " to accept %" GST_PTR_FORMAT, otherpad, othercaps);
-    ret = FALSE;
-    goto done;
-  }
+  /* and peer should accept */
+  if (otherpeer && !gst_pad_accept_caps (otherpeer, othercaps))
+    goto peer_no_accept;
 
   GST_DEBUG ("got final caps %" GST_PTR_FORMAT, othercaps);
 
   /* we know this will work, we implement the setcaps */
   gst_pad_set_caps (otherpad, othercaps);
 
-  /* success, let the element know */
-  if (klass->set_caps) {
+  trans->in_place = gst_caps_is_equal (caps, othercaps);
+  GST_DEBUG ("in_place: %d", trans->in_place);
+
+  /* see if we have to configure the element now */
+  if (!trans->delay_configure) {
     if (pad == trans->sinkpad)
-      ret = klass->set_caps (trans, caps, othercaps);
+      ret = gst_base_transform_configure_caps (trans, caps, othercaps);
     else
-      ret = klass->set_caps (trans, othercaps, caps);
+      ret = gst_base_transform_configure_caps (trans, othercaps, caps);
   }
 
 done:
-
   if (otherpeer)
     gst_object_unref (otherpeer);
-
   if (othercaps)
     gst_caps_unref (othercaps);
 
   return ret;
+
+  /* ERRORS */
+no_transform:
+  {
+    GST_DEBUG ("transform returned useless  %" GST_PTR_FORMAT, othercaps);
+    ret = FALSE;
+    goto done;
+  }
+could_not_fixate:
+  {
+    GST_DEBUG ("FAILED to fixate %" GST_PTR_FORMAT, othercaps);
+    ret = FALSE;
+    goto done;
+  }
+peer_no_accept:
+  {
+    GST_DEBUG ("FAILED to get peer of %" GST_PTR_FORMAT
+        " to accept %" GST_PTR_FORMAT, otherpad, othercaps);
+    ret = FALSE;
+    goto done;
+  }
+}
+
+static guint
+gst_base_transform_get_size (GstBaseTransform * trans)
+{
+  guint res = -1;
+  GstBaseTransformClass *bclass;
+
+  bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
+  if (bclass->get_size) {
+    res = bclass->get_size (trans);
+    GST_DEBUG ("get size function returned %d", res);
+  }
+
+  return res;
+}
+
+static GstFlowReturn
+gst_base_transform_buffer_alloc (GstPad * pad, guint64 offset, guint size,
+    GstCaps * caps, GstBuffer ** buf)
+{
+  GstBaseTransform *trans;
+  GstFlowReturn res;
+
+  trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
+
+  if (trans->in_place) {
+    /* we can only proxy the bufferpool if we do in_place transforms */
+    res = gst_pad_alloc_buffer (trans->srcpad, offset, size, caps, buf);
+  } else {
+    /* else let the default alloc function allocate a buffer */
+    *buf = NULL;
+    res = GST_FLOW_OK;
+  }
+
+  gst_object_unref (trans);
+
+  return res;
 }
 
+
 static gboolean
 gst_base_transform_event (GstPad * pad, GstEvent * event)
 {
@@ -383,6 +509,92 @@ gst_base_transform_event (GstPad * pad, GstEvent * event)
 }
 
 static GstFlowReturn
+gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
+    GstBuffer ** outbuf)
+{
+  GstBaseTransformClass *bclass;
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
+
+  if (trans->in_place) {
+    if (bclass->transform_ip) {
+      gst_buffer_ref (inbuf);
+
+      /* in place transform and subclass supports method */
+      ret = bclass->transform_ip (trans, inbuf);
+
+      *outbuf = inbuf;
+    } else {
+      /* in place transform and subclass does not support method */
+      if (bclass->transform) {
+        /* make a copy of the buffer */
+        *outbuf = inbuf;
+        inbuf = gst_buffer_copy (inbuf);
+
+        ret = bclass->transform (trans, inbuf, *outbuf);
+      } else {
+        ret = GST_FLOW_NOT_SUPPORTED;
+      }
+    }
+  } else {
+    /* figure out the output size */
+    if (trans->out_size == -1) {
+      /* ask subclass */
+      if ((trans->out_size = gst_base_transform_get_size (trans)) == -1)
+        /* else we have an error */
+        goto no_size;
+    }
+
+    /* we cannot reconfigure the element yet as we are still processing
+     * the old buffer. We will therefore delay the reconfiguration of the
+     * element until we have processed this last buffer. */
+    trans->delay_configure = TRUE;
+
+    /* no in place transform, get buffer, this might renegotiate. */
+    ret = gst_pad_alloc_buffer (trans->srcpad,
+        GST_BUFFER_OFFSET (inbuf), trans->out_size,
+        GST_PAD_CAPS (trans->srcpad), outbuf);
+
+    trans->delay_configure = FALSE;
+
+    if (ret != GST_FLOW_OK)
+      goto no_buffer;
+
+    gst_buffer_stamp (*outbuf, inbuf);
+
+    if (bclass->transform)
+      ret = bclass->transform (trans, inbuf, *outbuf);
+    else
+      ret = GST_FLOW_NOT_SUPPORTED;
+
+    if (ret)
+      ret =
+          gst_base_transform_configure_caps (trans,
+          GST_PAD_CAPS (trans->sinkpad), GST_PAD_CAPS (trans->srcpad));
+  }
+  gst_buffer_unref (inbuf);
+
+  return ret;
+
+  /* ERRORS */
+no_size:
+  {
+    gst_buffer_unref (inbuf);
+    GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
+        ("subclass did not specify output size"),
+        ("subclass did not specify output size"));
+    return GST_FLOW_ERROR;
+  }
+no_buffer:
+  {
+    gst_buffer_unref (inbuf);
+    GST_DEBUG ("could not get buffer from pool");
+    return ret;
+  }
+}
+
+static GstFlowReturn
 gst_base_transform_getrange (GstPad * pad, guint64 offset,
     guint length, GstBuffer ** buffer)
 {
@@ -390,16 +602,14 @@ gst_base_transform_getrange (GstPad * pad, guint64 offset,
   GstFlowReturn ret;
   GstBuffer *inbuf;
 
-  trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad));
-
-  GST_STREAM_LOCK (pad);
+  trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
 
   ret = gst_pad_pull_range (trans->sinkpad, offset, length, &inbuf);
   if (ret == GST_FLOW_OK) {
     ret = gst_base_transform_handle_buffer (trans, inbuf, buffer);
   }
 
-  GST_STREAM_UNLOCK (pad);
+  gst_object_unref (trans);
 
   return ret;
 }
@@ -408,33 +618,17 @@ static GstFlowReturn
 gst_base_transform_chain (GstPad * pad, GstBuffer * buffer)
 {
   GstBaseTransform *trans;
-  GstFlowReturn ret = GST_FLOW_OK;
+  GstFlowReturn ret;
   GstBuffer *outbuf;
 
-  trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad));
-
-  GST_STREAM_LOCK (pad);
+  trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
 
   ret = gst_base_transform_handle_buffer (trans, buffer, &outbuf);
   if (ret == GST_FLOW_OK) {
     ret = gst_pad_push (trans->srcpad, outbuf);
   }
 
-  GST_STREAM_UNLOCK (pad);
-
-  return ret;
-}
-
-static GstFlowReturn
-gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
-    GstBuffer ** outbuf)
-{
-  GstFlowReturn ret = GST_FLOW_OK;
-  GstBaseTransformClass *bclass;
-
-  bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
-  if (bclass->transform)
-    ret = bclass->transform (trans, inbuf, outbuf);
+  gst_object_unref (trans);
 
   return ret;
 }
@@ -524,6 +718,10 @@ gst_base_transform_change_state (GstElement * element)
     case GST_STATE_NULL_TO_READY:
       break;
     case GST_STATE_READY_TO_PAUSED:
+      GST_LOCK (trans);
+      trans->in_place = trans->passthrough;
+      trans->out_size = -1;
+      GST_UNLOCK (trans);
       break;
     case GST_STATE_PAUSED_TO_PLAYING:
       break;
@@ -548,3 +746,48 @@ gst_base_transform_change_state (GstElement * element)
 
   return result;
 }
+
+/**
+ * gst_base_transform_set_passthrough:
+ * @trans: the #GstBaseTransform to set
+ * @passthrough: boolean indicating passthrough mode.
+ *
+ * Set passthrough mode for this filter by default. This is mostly
+ * usefull for filters that do not care about negotiation.
+ *
+ * MT safe.
+ */
+void
+gst_base_transform_set_passthrough (GstBaseTransform * trans,
+    gboolean passthrough)
+{
+  g_return_if_fail (trans != NULL);
+
+  GST_LOCK (trans);
+  trans->passthrough = passthrough;
+  GST_UNLOCK (trans);
+}
+
+/**
+ * gst_base_transform_is_passthrough:
+ * @trans: the #GstBaseTransform to query
+ *
+ * See if @trans is configured as a passthrough transform.
+ *
+ * Returns: TRUE is the transform is configured in passthrough mode.
+ *
+ * MT safe.
+ */
+gboolean
+gst_base_transform_is_passthrough (GstBaseTransform * trans)
+{
+  gboolean result;
+
+  g_return_val_if_fail (trans != NULL, FALSE);
+
+  GST_LOCK (trans);
+  result = trans->passthrough;
+  GST_UNLOCK (trans);
+
+  return result;
+}
index e0581e6..fcd34ab 100644 (file)
@@ -49,6 +49,12 @@ struct _GstBaseTransform {
   /* source and sink pads */
   GstPad       *sinkpad;
   GstPad       *srcpad;
+
+  gboolean      passthrough;
+
+  gboolean      in_place;
+  guint                 out_size;
+  gboolean      delay_configure;
 };
 
 struct _GstBaseTransformClass {
@@ -65,6 +71,9 @@ struct _GstBaseTransformClass {
   gboolean      (*set_caps)     (GstBaseTransform *trans, GstCaps *incaps,
                                  GstCaps *outcaps);
 
+  /* get the size of the output buffer, -1 on error */
+  guint         (*get_size)     (GstBaseTransform *trans);
+
   /* start and stop processing, ideal for opening/closing the resource */
   gboolean      (*start)        (GstBaseTransform *trans);
   gboolean      (*stop)         (GstBaseTransform *trans);
@@ -73,9 +82,15 @@ struct _GstBaseTransformClass {
 
   /* transform one incoming buffer to one outgoing buffer */
   GstFlowReturn (*transform)    (GstBaseTransform *trans, GstBuffer *inbuf,
-                                 GstBuffer **outbuf);
+                                 GstBuffer *outbuf);
+
+  /* transform a buffer inplace */
+  GstFlowReturn (*transform_ip) (GstBaseTransform *trans, GstBuffer *buf);
 };
 
+void           gst_base_transform_set_passthrough (GstBaseTransform *trans, gboolean passthrough);
+gboolean       gst_base_transform_is_passthrough (GstBaseTransform *trans);
+
 GType gst_base_transform_get_type (void);
 
 G_END_DECLS
index 7c2ac82..75f7c3a 100644 (file)
@@ -98,7 +98,7 @@ static void gst_identity_get_property (GObject * object, guint prop_id,
 
 static gboolean gst_identity_event (GstBaseTransform * trans, GstEvent * event);
 static GstFlowReturn gst_identity_transform (GstBaseTransform * trans,
-    GstBuffer * inbuf, GstBuffer ** outbuf);
+    GstBuffer * inbuf, GstBuffer * outbuf);
 static gboolean gst_identity_start (GstBaseTransform * trans);
 static gboolean gst_identity_stop (GstBaseTransform * trans);
 
@@ -190,6 +190,8 @@ gst_identity_class_init (GstIdentityClass * klass)
 static void
 gst_identity_init (GstIdentity * identity)
 {
+  gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (identity), TRUE);
+
   identity->sleep_time = DEFAULT_SLEEP_TIME;
   identity->error_after = DEFAULT_ERROR_AFTER;
   identity->drop_probability = DEFAULT_DROP_PROBABILITY;
@@ -261,7 +263,7 @@ gst_identity_check_perfect (GstIdentity * identity, GstBuffer * buf)
 
 static GstFlowReturn
 gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
-    GstBuffer ** outbuf)
+    GstBuffer * outbuf)
 {
   GstFlowReturn ret = GST_FLOW_OK;
   GstIdentity *identity = GST_IDENTITY (trans);
@@ -274,7 +276,6 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
     if (identity->error_after == 0) {
       GST_ELEMENT_ERROR (identity, CORE, FAILED,
           (_("Failed after iterations as requested.")), (NULL));
-      gst_buffer_unref (inbuf);
       return GST_FLOW_ERROR;
     }
   }
@@ -294,7 +295,6 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
           GST_BUFFER_FLAGS (inbuf), inbuf);
       GST_UNLOCK (identity);
       g_object_notify (G_OBJECT (identity), "last-message");
-      gst_buffer_unref (inbuf);
       return GST_FLOW_OK;
     }
   }
@@ -319,19 +319,16 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
     g_object_notify (G_OBJECT (identity), "last-message");
   }
 
-  *outbuf = gst_buffer_make_writable (inbuf);
-  /* inbuf is no longer usable */
-
   if (identity->datarate > 0) {
     GstClockTime time = identity->offset * GST_SECOND / identity->datarate;
 
-    GST_BUFFER_TIMESTAMP (*outbuf) = time;
-    GST_BUFFER_DURATION (*outbuf) =
-        GST_BUFFER_SIZE (*outbuf) * GST_SECOND / identity->datarate;
+    GST_BUFFER_TIMESTAMP (outbuf) = time;
+    GST_BUFFER_DURATION (outbuf) =
+        GST_BUFFER_SIZE (outbuf) * GST_SECOND / identity->datarate;
   }
 
   g_signal_emit (G_OBJECT (identity), gst_identity_signals[SIGNAL_HANDOFF], 0,
-      *outbuf);
+      outbuf);
 
   if (identity->sync) {
     GstClock *clock;
@@ -344,7 +341,7 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
       /* FIXME: actually unlock this somewhere if the state changes */
       GST_LOCK (identity);
       identity->clock_id = gst_clock_new_single_shot_id (clock,
-          GST_BUFFER_TIMESTAMP (*outbuf) + GST_ELEMENT (identity)->base_time);
+          GST_BUFFER_TIMESTAMP (outbuf) + GST_ELEMENT (identity)->base_time);
       GST_UNLOCK (identity);
       cret = gst_clock_id_wait (identity->clock_id, NULL);
       GST_LOCK (identity);
@@ -358,7 +355,7 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
     }
   }
 
-  identity->offset += GST_BUFFER_SIZE (*outbuf);
+  identity->offset += GST_BUFFER_SIZE (outbuf);
 
   if (identity->sleep_time && ret == GST_FLOW_OK)
     g_usleep (identity->sleep_time);