gst/elements/gstcapsfilter.c: Reimplement using basetransform, fixes buffer_alloc...
authorAndy Wingo <wingo@pobox.com>
Thu, 4 Aug 2005 19:40:43 +0000 (19:40 +0000)
committerAndy Wingo <wingo@pobox.com>
Thu, 4 Aug 2005 19:40:43 +0000 (19:40 +0000)
Original commit message from CVS:
2005-08-04  Andy Wingo  <wingo@pobox.com>

* gst/elements/gstcapsfilter.c: Reimplement using basetransform,
fixes buffer_alloc proxying among other things.

* gst/base/gstbasetransform.c:
* gst/base/gstbasetransform.h:
Revert patch to gstbasetransform from 7-28 removing
delay_configure.

* gst/base/gstbasetransform.h (GstBaseTransformClass.get_size):
* gst/base/gstbasetransform.c (gst_base_transform_get_size):
Semantics changed, should return not the size of the output buffer
but the byte size of a buffer with a given caps.

* gst/base/gstbasetransform.c (gst_base_transform_getcaps): Better
debug object.
(gst_base_transform_configure_caps): Don't set out_size here: (in,
out) are not the pad caps until setcaps finishes.
(gst_base_transform_buffer_alloc): Proxy the buffer_alloc for the
not-in-place case as well. Deal with changing from in-place to
not-in-place within calling pad_alloc_buffer. Still a bit
concerned about the overhead here...

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

index 5614f66..cf978be 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,32 @@
+2005-08-04  Andy Wingo  <wingo@pobox.com>
+
+       * gst/elements/gstcapsfilter.c: Reimplement using basetransform,
+       fixes buffer_alloc proxying among other things.
+
+       * gst/base/gstbasetransform.c:
+       * gst/base/gstbasetransform.h:
+       Revert patch to gstbasetransform from 7-28 removing
+       delay_configure.
+
+       * gst/base/gstbasetransform.h (GstBaseTransformClass.get_size):
+       * gst/base/gstbasetransform.c (gst_base_transform_get_size):
+       Semantics changed, should return not the size of the output buffer
+       but the byte size of a buffer with a given caps.
+
+       * gst/base/gstbasetransform.c (gst_base_transform_getcaps): Better
+       debug object.
+       (gst_base_transform_configure_caps): Don't set out_size here: (in,
+       out) are not the pad caps until setcaps finishes.
+       (gst_base_transform_buffer_alloc): Proxy the buffer_alloc for the
+       not-in-place case as well. Deal with changing from in-place to
+       not-in-place within calling pad_alloc_buffer. Still a bit
+       concerned about the overhead here...
+
+2005-08-03  Andy Wingo  <wingo@pobox.com>
+
+       * gst/base/gstbasetransform.c (gst_base_transform_setcaps): Not
+       fixating is an error.
+
 2005-08-04  Edward Hervey  <edward@fluendo.com>
 
        * gst/base/gstadapter.h: 
index 51d6ca2..d4b48f0 100644 (file)
@@ -110,7 +110,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 guint gst_base_transform_get_size (GstBaseTransform * trans,
+    GstCaps * caps);
 
 static GstElementStateReturn gst_base_transform_change_state (GstElement *
     element);
@@ -264,26 +265,26 @@ gst_base_transform_getcaps (GstPad * pad)
     GstCaps *temp;
     const GstCaps *templ;
 
-    GST_DEBUG_OBJECT (trans, "peer caps  %" GST_PTR_FORMAT, caps);
+    GST_DEBUG_OBJECT (pad, "peer caps  %" GST_PTR_FORMAT, caps);
 
     /* filtered against our padtemplate */
     templ = gst_pad_get_pad_template_caps (otherpad);
-    GST_DEBUG_OBJECT (trans, "our template  %" GST_PTR_FORMAT, templ);
+    GST_DEBUG_OBJECT (pad, "our template  %" GST_PTR_FORMAT, templ);
     temp = gst_caps_intersect (caps, templ);
-    GST_DEBUG_OBJECT (trans, "intersected %" GST_PTR_FORMAT, temp);
+    GST_DEBUG_OBJECT (pad, "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_OBJECT (trans, "transformed  %" GST_PTR_FORMAT, caps);
+    GST_DEBUG_OBJECT (pad, "transformed  %" GST_PTR_FORMAT, caps);
     gst_caps_unref (temp);
     if (caps == NULL)
       goto done;
 
     /* and filter against the template again */
     templ = gst_pad_get_pad_template_caps (pad);
-    GST_DEBUG_OBJECT (trans, "our template  %" GST_PTR_FORMAT, templ);
+    GST_DEBUG_OBJECT (pad, "our template  %" GST_PTR_FORMAT, templ);
     temp = gst_caps_intersect (caps, templ);
-    GST_DEBUG_OBJECT (trans, "intersected %" GST_PTR_FORMAT, temp);
+    GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
     gst_caps_unref (caps);
     /* this is what we can do */
     caps = temp;
@@ -314,11 +315,6 @@ gst_base_transform_configure_caps (GstBaseTransform * trans, GstCaps * in,
     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_OBJECT (trans, "output buffer size %d", trans->out_size);
-  }
   return ret;
 }
 
@@ -427,10 +423,12 @@ gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
   GST_DEBUG_OBJECT (trans, "in_place: %d", trans->in_place);
 
   /* see if we have to configure the element now */
-  if (pad == trans->sinkpad)
-    ret = gst_base_transform_configure_caps (trans, caps, othercaps);
-  else
-    ret = gst_base_transform_configure_caps (trans, othercaps, caps);
+  if (!trans->delay_configure) {
+    if (pad == trans->sinkpad)
+      ret = gst_base_transform_configure_caps (trans, caps, othercaps);
+    else
+      ret = gst_base_transform_configure_caps (trans, othercaps, caps);
+  }
 
 done:
   if (otherpeer)
@@ -460,7 +458,7 @@ no_transform_possible:
   }
 could_not_fixate:
   {
-    GST_DEBUG_OBJECT (trans, "FAILED to fixate %" GST_PTR_FORMAT, othercaps);
+    GST_ERROR_OBJECT (trans, "FAILED to fixate %" GST_PTR_FORMAT, othercaps);
     ret = FALSE;
     goto done;
   }
@@ -474,15 +472,15 @@ peer_no_accept:
 }
 
 static guint
-gst_base_transform_get_size (GstBaseTransform * trans)
+gst_base_transform_get_size (GstBaseTransform * trans, GstCaps * caps)
 {
   guint res = -1;
   GstBaseTransformClass *bclass;
 
   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
   if (bclass->get_size) {
-    res = bclass->get_size (trans);
-    GST_DEBUG_OBJECT (trans, "get size function returned %d", res);
+    res = bclass->get_size (trans, caps);
+    GST_DEBUG_OBJECT (trans, "get size(%p) returned %d", caps, res);
   }
 
   return res;
@@ -494,21 +492,74 @@ gst_base_transform_buffer_alloc (GstPad * pad, guint64 offset, guint size,
 {
   GstBaseTransform *trans;
   GstFlowReturn res;
+  guint got_size;
 
   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
 
+  *buf = NULL;
+
   if (trans->in_place) {
-    /* we can only proxy the bufferpool if we do in_place transforms */
+    /* request a buffer with the same caps */
     res = gst_pad_alloc_buffer (trans->srcpad, offset, size, caps, buf);
   } else {
-    /* else let the default alloc function allocate a buffer */
-    *buf = NULL;
+    /* if we are configured, request a buffer with the src caps */
+    GstCaps *srccaps = gst_pad_get_negotiated_caps (trans->srcpad);
+
+    if (!srccaps)
+      goto not_configured;
+
+    got_size = gst_base_transform_get_size (trans, srccaps);
+    if (got_size == -1) {
+      gst_caps_unref (srccaps);
+      goto unknown_size;
+    }
+
+    res = gst_pad_alloc_buffer (trans->srcpad, offset, got_size, srccaps, buf);
+    gst_caps_unref (srccaps);
+  }
+
+  if (res == GST_FLOW_OK && !trans->in_place) {
+    /* note that we might have been in place before, but calling the
+       alloc_buffer caused setcaps to switch us out of in_place -- in any case
+       the alloc_buffer served to transmit caps information but we can't use the
+       buffer. fall through and allocate a buffer corresponding to our sink
+       caps, if any */
+    GstCaps *sinkcaps = gst_pad_get_negotiated_caps (trans->sinkpad);
+
+    if (!sinkcaps)
+      goto not_configured;
+
+    got_size = gst_base_transform_get_size (trans, sinkcaps);
+    if (got_size == -1) {
+      gst_caps_unref (sinkcaps);
+      goto unknown_size;
+    }
+
+    *buf = gst_buffer_new_and_alloc (got_size);
+    gst_buffer_set_caps (*buf, sinkcaps);
+    GST_BUFFER_OFFSET (*buf) = offset;
     res = GST_FLOW_OK;
+
+    gst_caps_unref (sinkcaps);
   }
 
   gst_object_unref (trans);
-
   return res;
+
+not_configured:
+  {
+    /* let the default allocator handle it */
+    *buf = NULL;
+    gst_object_unref (trans);
+    return GST_FLOW_OK;
+  }
+unknown_size:
+  {
+    /* let the default allocator handle it */
+    *buf = NULL;
+    gst_object_unref (trans);
+    return GST_FLOW_OK;
+  }
 }
 
 
@@ -584,16 +635,25 @@ gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
     /* 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 */
+      trans->out_size = gst_base_transform_get_size (trans,
+          GST_PAD_CAPS (trans->srcpad));
+      if (trans->out_size == -1)
+        /* 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;
 
index 68673e7..fb4d07b 100644 (file)
@@ -54,6 +54,7 @@ struct _GstBaseTransform {
 
   gboolean      in_place;
   guint                 out_size;
+  gboolean      delay_configure;
 };
 
 struct _GstBaseTransformClass {
@@ -70,8 +71,8 @@ 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);
+  /* get the byte size of a given caps, -1 on error */
+  guint         (*get_size)     (GstBaseTransform *trans, GstCaps *caps);
 
   /* start and stop processing, ideal for opening/closing the resource */
   gboolean      (*start)        (GstBaseTransform *trans);
index 3ba28da..dd9e0c8 100644 (file)
  * Boston, MA 02111-1307, USA.
  */
 
-
-#include <stdlib.h>
-
 #ifdef HAVE_CONFIG_H
-#  include "config.h"
+#include "config.h"
 #endif
 
 #include "../gst-i18n-lib.h"
-#include <gst/gstmarshal.h>
 #include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+
+
+GstElementDetails gst_capsfilter_details = GST_ELEMENT_DETAILS ("CapsFilter",
+    "Generic",
+    "Pass data without modification, limiting formats",
+    "David Schleef <ds@schleef.org>");
 
 
 #define GST_TYPE_CAPSFILTER \
@@ -48,23 +51,25 @@ typedef struct _GstCapsFilterClass GstCapsFilterClass;
 
 struct _GstCapsFilter
 {
-  GstElement element;
-
-  GstPad *srcpad;
-  GstPad *sinkpad;
+  GstBaseTransform trans;
 
   GstCaps *filter_caps;
 };
 
 struct _GstCapsFilterClass
 {
-  GstElementClass element_class;
-
+  GstBaseTransformClass trans_class;
 };
 
 GType gst_capsfilter_get_type (void);
 
 
+enum
+{
+  PROP_0,
+  PROP_FILTER_CAPS
+};
+
 
 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
     GST_PAD_SINK,
@@ -76,133 +81,74 @@ static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_ALWAYS,
     GST_STATIC_CAPS_ANY);
 
+
 GST_DEBUG_CATEGORY_STATIC (gst_capsfilter_debug);
 #define GST_CAT_DEFAULT gst_capsfilter_debug
 
-GstElementDetails gst_capsfilter_details = GST_ELEMENT_DETAILS ("CapsFilter",
-    "Generic",
-    "Pass data without modification, limiting formats",
-    "David Schleef <ds@schleef.org>");
-
-enum
-{
-  PROP_0,
-  PROP_FILTER_CAPS
-};
-
-
 #define _do_init(bla) \
-    GST_DEBUG_CATEGORY_INIT (gst_capsfilter_debug, "capsfilter", 0, "capsfilter element");
+    GST_DEBUG_CATEGORY_INIT (gst_capsfilter_debug, "capsfilter", 0, \
+    "capsfilter element");
+
+GST_BOILERPLATE_FULL (GstCapsFilter, gst_capsfilter, GstBaseTransform,
+    GST_TYPE_BASE_TRANSFORM, _do_init);
 
-GST_BOILERPLATE_FULL (GstCapsFilter, gst_capsfilter, GstElement,
-    GST_TYPE_ELEMENT, _do_init);
 
-static void gst_capsfilter_finalize (GObject * object);
 static void gst_capsfilter_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec);
 static void gst_capsfilter_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * pspec);
+static void gst_capsfilter_dispose (GObject * object);
+static GstCaps *gst_capsfilter_transform_caps (GstBaseTransform * base,
+    GstPad * pad, GstCaps * caps);
+static GstFlowReturn gst_capsfilter_transform_ip (GstBaseTransform * base,
+    GstBuffer * buf);
 
-static GstCaps *gst_capsfilter_getcaps (GstPad * pad);
-static GstFlowReturn gst_capsfilter_chain (GstPad * pad, GstBuffer * buf);
 
 static void
 gst_capsfilter_base_init (gpointer g_class)
 {
-  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
+  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
 
-  gst_element_class_add_pad_template (gstelement_class,
+  gst_element_class_add_pad_template (element_class,
       gst_static_pad_template_get (&srctemplate));
-  gst_element_class_add_pad_template (gstelement_class,
+  gst_element_class_add_pad_template (element_class,
       gst_static_pad_template_get (&sinktemplate));
-  gst_element_class_set_details (gstelement_class, &gst_capsfilter_details);
-}
-
-static void
-gst_capsfilter_finalize (GObject * object)
-{
-  GstCapsFilter *capsfilter;
-
-  capsfilter = GST_CAPSFILTER (object);
-
-  gst_caps_unref (capsfilter->filter_caps);
-
-  G_OBJECT_CLASS (parent_class)->finalize (object);
+  gst_element_class_set_details (element_class, &gst_capsfilter_details);
 }
 
 static void
 gst_capsfilter_class_init (GstCapsFilterClass * klass)
 {
   GObjectClass *gobject_class;
-  GstElementClass *gstelement_class;
+  GstBaseTransformClass *trans_class;
 
-  gobject_class = G_OBJECT_CLASS (klass);
-  gstelement_class = GST_ELEMENT_CLASS (klass);
-
-  gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_capsfilter_set_property);
-  gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_capsfilter_get_property);
-  gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_capsfilter_finalize);
+  gobject_class = (GObjectClass *) klass;
+  gobject_class->set_property = gst_capsfilter_set_property;
+  gobject_class->get_property = gst_capsfilter_get_property;
+  gobject_class->dispose = gst_capsfilter_dispose;
 
   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_FILTER_CAPS,
       g_param_spec_boxed ("filter_caps", _("Filter caps"),
           _("Restrict the possible allowed formats"),
           GST_TYPE_CAPS, G_PARAM_READWRITE));
-}
 
-static void
-gst_capsfilter_init (GstCapsFilter * capsfilter)
-{
-  gst_element_create_all_pads (GST_ELEMENT (capsfilter));
-
-  capsfilter->srcpad = gst_element_get_pad (GST_ELEMENT (capsfilter), "src");
-  capsfilter->sinkpad = gst_element_get_pad (GST_ELEMENT (capsfilter), "sink");
-
-  gst_pad_set_getcaps_function (capsfilter->srcpad, gst_capsfilter_getcaps);
-
-  gst_pad_set_getcaps_function (capsfilter->sinkpad, gst_capsfilter_getcaps);
-  gst_pad_set_chain_function (capsfilter->sinkpad, gst_capsfilter_chain);
-
-  capsfilter->filter_caps = gst_caps_new_any ();
+  trans_class = (GstBaseTransformClass *) klass;
+  trans_class->transform_caps = gst_capsfilter_transform_caps;
+  trans_class->transform_ip = gst_capsfilter_transform_ip;
 }
 
-static GstCaps *
-gst_capsfilter_getcaps (GstPad * pad)
-{
-  GstPad *otherpad;
-  GstCapsFilter *capsfilter = GST_CAPSFILTER (GST_OBJECT_PARENT (pad));
-  GstCaps *caps;
-  GstCaps *icaps;
-
-  otherpad = (pad == capsfilter->srcpad) ? capsfilter->sinkpad :
-      capsfilter->srcpad;
-
-  caps = gst_pad_peer_get_caps (otherpad);
-  if (caps == NULL)
-    caps = gst_caps_new_any ();
-
-  icaps = gst_caps_intersect (caps, capsfilter->filter_caps);
-  gst_caps_unref (caps);
-
-  return icaps;
-}
-
-static GstFlowReturn
-gst_capsfilter_chain (GstPad * pad, GstBuffer * buf)
+static void
+gst_capsfilter_init (GstCapsFilter * filter)
 {
-  GstCapsFilter *capsfilter = GST_CAPSFILTER (GST_PAD_PARENT (pad));
-
-  gst_pad_push (capsfilter->srcpad, buf);
-
-  return GST_FLOW_OK;
+  gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (filter), TRUE);
+  filter->filter_caps = gst_caps_new_any ();
 }
 
 static void
 gst_capsfilter_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec)
 {
-  GstCapsFilter *capsfilter;
-
-  capsfilter = GST_CAPSFILTER (object);
+  GstCapsFilter *capsfilter = GST_CAPSFILTER (object);
 
   switch (prop_id) {
     case PROP_FILTER_CAPS:{
@@ -230,9 +176,7 @@ static void
 gst_capsfilter_get_property (GObject * object, guint prop_id, GValue * value,
     GParamSpec * pspec)
 {
-  GstCapsFilter *capsfilter;
-
-  capsfilter = GST_CAPSFILTER (object);
+  GstCapsFilter *capsfilter = GST_CAPSFILTER (object);
 
   switch (prop_id) {
     case PROP_FILTER_CAPS:
@@ -243,3 +187,31 @@ gst_capsfilter_get_property (GObject * object, guint prop_id, GValue * value,
       break;
   }
 }
+
+static void
+gst_capsfilter_dispose (GObject * object)
+{
+  GstCapsFilter *filter = GST_CAPSFILTER (object);
+
+  gst_caps_replace (&filter->filter_caps, NULL);
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static GstCaps *
+gst_capsfilter_transform_caps (GstBaseTransform * base, GstPad * pad,
+    GstCaps * caps)
+{
+  GstCapsFilter *capsfilter = GST_CAPSFILTER (base);
+  GstCaps *ret;
+
+  ret = gst_caps_intersect (caps, capsfilter->filter_caps);
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_capsfilter_transform_ip (GstBaseTransform * base, GstBuffer * buf)
+{
+  return GST_FLOW_OK;
+}
index 51d6ca2..d4b48f0 100644 (file)
@@ -110,7 +110,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 guint gst_base_transform_get_size (GstBaseTransform * trans,
+    GstCaps * caps);
 
 static GstElementStateReturn gst_base_transform_change_state (GstElement *
     element);
@@ -264,26 +265,26 @@ gst_base_transform_getcaps (GstPad * pad)
     GstCaps *temp;
     const GstCaps *templ;
 
-    GST_DEBUG_OBJECT (trans, "peer caps  %" GST_PTR_FORMAT, caps);
+    GST_DEBUG_OBJECT (pad, "peer caps  %" GST_PTR_FORMAT, caps);
 
     /* filtered against our padtemplate */
     templ = gst_pad_get_pad_template_caps (otherpad);
-    GST_DEBUG_OBJECT (trans, "our template  %" GST_PTR_FORMAT, templ);
+    GST_DEBUG_OBJECT (pad, "our template  %" GST_PTR_FORMAT, templ);
     temp = gst_caps_intersect (caps, templ);
-    GST_DEBUG_OBJECT (trans, "intersected %" GST_PTR_FORMAT, temp);
+    GST_DEBUG_OBJECT (pad, "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_OBJECT (trans, "transformed  %" GST_PTR_FORMAT, caps);
+    GST_DEBUG_OBJECT (pad, "transformed  %" GST_PTR_FORMAT, caps);
     gst_caps_unref (temp);
     if (caps == NULL)
       goto done;
 
     /* and filter against the template again */
     templ = gst_pad_get_pad_template_caps (pad);
-    GST_DEBUG_OBJECT (trans, "our template  %" GST_PTR_FORMAT, templ);
+    GST_DEBUG_OBJECT (pad, "our template  %" GST_PTR_FORMAT, templ);
     temp = gst_caps_intersect (caps, templ);
-    GST_DEBUG_OBJECT (trans, "intersected %" GST_PTR_FORMAT, temp);
+    GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
     gst_caps_unref (caps);
     /* this is what we can do */
     caps = temp;
@@ -314,11 +315,6 @@ gst_base_transform_configure_caps (GstBaseTransform * trans, GstCaps * in,
     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_OBJECT (trans, "output buffer size %d", trans->out_size);
-  }
   return ret;
 }
 
@@ -427,10 +423,12 @@ gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
   GST_DEBUG_OBJECT (trans, "in_place: %d", trans->in_place);
 
   /* see if we have to configure the element now */
-  if (pad == trans->sinkpad)
-    ret = gst_base_transform_configure_caps (trans, caps, othercaps);
-  else
-    ret = gst_base_transform_configure_caps (trans, othercaps, caps);
+  if (!trans->delay_configure) {
+    if (pad == trans->sinkpad)
+      ret = gst_base_transform_configure_caps (trans, caps, othercaps);
+    else
+      ret = gst_base_transform_configure_caps (trans, othercaps, caps);
+  }
 
 done:
   if (otherpeer)
@@ -460,7 +458,7 @@ no_transform_possible:
   }
 could_not_fixate:
   {
-    GST_DEBUG_OBJECT (trans, "FAILED to fixate %" GST_PTR_FORMAT, othercaps);
+    GST_ERROR_OBJECT (trans, "FAILED to fixate %" GST_PTR_FORMAT, othercaps);
     ret = FALSE;
     goto done;
   }
@@ -474,15 +472,15 @@ peer_no_accept:
 }
 
 static guint
-gst_base_transform_get_size (GstBaseTransform * trans)
+gst_base_transform_get_size (GstBaseTransform * trans, GstCaps * caps)
 {
   guint res = -1;
   GstBaseTransformClass *bclass;
 
   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
   if (bclass->get_size) {
-    res = bclass->get_size (trans);
-    GST_DEBUG_OBJECT (trans, "get size function returned %d", res);
+    res = bclass->get_size (trans, caps);
+    GST_DEBUG_OBJECT (trans, "get size(%p) returned %d", caps, res);
   }
 
   return res;
@@ -494,21 +492,74 @@ gst_base_transform_buffer_alloc (GstPad * pad, guint64 offset, guint size,
 {
   GstBaseTransform *trans;
   GstFlowReturn res;
+  guint got_size;
 
   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
 
+  *buf = NULL;
+
   if (trans->in_place) {
-    /* we can only proxy the bufferpool if we do in_place transforms */
+    /* request a buffer with the same caps */
     res = gst_pad_alloc_buffer (trans->srcpad, offset, size, caps, buf);
   } else {
-    /* else let the default alloc function allocate a buffer */
-    *buf = NULL;
+    /* if we are configured, request a buffer with the src caps */
+    GstCaps *srccaps = gst_pad_get_negotiated_caps (trans->srcpad);
+
+    if (!srccaps)
+      goto not_configured;
+
+    got_size = gst_base_transform_get_size (trans, srccaps);
+    if (got_size == -1) {
+      gst_caps_unref (srccaps);
+      goto unknown_size;
+    }
+
+    res = gst_pad_alloc_buffer (trans->srcpad, offset, got_size, srccaps, buf);
+    gst_caps_unref (srccaps);
+  }
+
+  if (res == GST_FLOW_OK && !trans->in_place) {
+    /* note that we might have been in place before, but calling the
+       alloc_buffer caused setcaps to switch us out of in_place -- in any case
+       the alloc_buffer served to transmit caps information but we can't use the
+       buffer. fall through and allocate a buffer corresponding to our sink
+       caps, if any */
+    GstCaps *sinkcaps = gst_pad_get_negotiated_caps (trans->sinkpad);
+
+    if (!sinkcaps)
+      goto not_configured;
+
+    got_size = gst_base_transform_get_size (trans, sinkcaps);
+    if (got_size == -1) {
+      gst_caps_unref (sinkcaps);
+      goto unknown_size;
+    }
+
+    *buf = gst_buffer_new_and_alloc (got_size);
+    gst_buffer_set_caps (*buf, sinkcaps);
+    GST_BUFFER_OFFSET (*buf) = offset;
     res = GST_FLOW_OK;
+
+    gst_caps_unref (sinkcaps);
   }
 
   gst_object_unref (trans);
-
   return res;
+
+not_configured:
+  {
+    /* let the default allocator handle it */
+    *buf = NULL;
+    gst_object_unref (trans);
+    return GST_FLOW_OK;
+  }
+unknown_size:
+  {
+    /* let the default allocator handle it */
+    *buf = NULL;
+    gst_object_unref (trans);
+    return GST_FLOW_OK;
+  }
 }
 
 
@@ -584,16 +635,25 @@ gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
     /* 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 */
+      trans->out_size = gst_base_transform_get_size (trans,
+          GST_PAD_CAPS (trans->srcpad));
+      if (trans->out_size == -1)
+        /* 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;
 
index 68673e7..fb4d07b 100644 (file)
@@ -54,6 +54,7 @@ struct _GstBaseTransform {
 
   gboolean      in_place;
   guint                 out_size;
+  gboolean      delay_configure;
 };
 
 struct _GstBaseTransformClass {
@@ -70,8 +71,8 @@ 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);
+  /* get the byte size of a given caps, -1 on error */
+  guint         (*get_size)     (GstBaseTransform *trans, GstCaps *caps);
 
   /* start and stop processing, ideal for opening/closing the resource */
   gboolean      (*start)        (GstBaseTransform *trans);
index 3ba28da..dd9e0c8 100644 (file)
  * Boston, MA 02111-1307, USA.
  */
 
-
-#include <stdlib.h>
-
 #ifdef HAVE_CONFIG_H
-#  include "config.h"
+#include "config.h"
 #endif
 
 #include "../gst-i18n-lib.h"
-#include <gst/gstmarshal.h>
 #include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+
+
+GstElementDetails gst_capsfilter_details = GST_ELEMENT_DETAILS ("CapsFilter",
+    "Generic",
+    "Pass data without modification, limiting formats",
+    "David Schleef <ds@schleef.org>");
 
 
 #define GST_TYPE_CAPSFILTER \
@@ -48,23 +51,25 @@ typedef struct _GstCapsFilterClass GstCapsFilterClass;
 
 struct _GstCapsFilter
 {
-  GstElement element;
-
-  GstPad *srcpad;
-  GstPad *sinkpad;
+  GstBaseTransform trans;
 
   GstCaps *filter_caps;
 };
 
 struct _GstCapsFilterClass
 {
-  GstElementClass element_class;
-
+  GstBaseTransformClass trans_class;
 };
 
 GType gst_capsfilter_get_type (void);
 
 
+enum
+{
+  PROP_0,
+  PROP_FILTER_CAPS
+};
+
 
 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
     GST_PAD_SINK,
@@ -76,133 +81,74 @@ static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_ALWAYS,
     GST_STATIC_CAPS_ANY);
 
+
 GST_DEBUG_CATEGORY_STATIC (gst_capsfilter_debug);
 #define GST_CAT_DEFAULT gst_capsfilter_debug
 
-GstElementDetails gst_capsfilter_details = GST_ELEMENT_DETAILS ("CapsFilter",
-    "Generic",
-    "Pass data without modification, limiting formats",
-    "David Schleef <ds@schleef.org>");
-
-enum
-{
-  PROP_0,
-  PROP_FILTER_CAPS
-};
-
-
 #define _do_init(bla) \
-    GST_DEBUG_CATEGORY_INIT (gst_capsfilter_debug, "capsfilter", 0, "capsfilter element");
+    GST_DEBUG_CATEGORY_INIT (gst_capsfilter_debug, "capsfilter", 0, \
+    "capsfilter element");
+
+GST_BOILERPLATE_FULL (GstCapsFilter, gst_capsfilter, GstBaseTransform,
+    GST_TYPE_BASE_TRANSFORM, _do_init);
 
-GST_BOILERPLATE_FULL (GstCapsFilter, gst_capsfilter, GstElement,
-    GST_TYPE_ELEMENT, _do_init);
 
-static void gst_capsfilter_finalize (GObject * object);
 static void gst_capsfilter_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec);
 static void gst_capsfilter_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * pspec);
+static void gst_capsfilter_dispose (GObject * object);
+static GstCaps *gst_capsfilter_transform_caps (GstBaseTransform * base,
+    GstPad * pad, GstCaps * caps);
+static GstFlowReturn gst_capsfilter_transform_ip (GstBaseTransform * base,
+    GstBuffer * buf);
 
-static GstCaps *gst_capsfilter_getcaps (GstPad * pad);
-static GstFlowReturn gst_capsfilter_chain (GstPad * pad, GstBuffer * buf);
 
 static void
 gst_capsfilter_base_init (gpointer g_class)
 {
-  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
+  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
 
-  gst_element_class_add_pad_template (gstelement_class,
+  gst_element_class_add_pad_template (element_class,
       gst_static_pad_template_get (&srctemplate));
-  gst_element_class_add_pad_template (gstelement_class,
+  gst_element_class_add_pad_template (element_class,
       gst_static_pad_template_get (&sinktemplate));
-  gst_element_class_set_details (gstelement_class, &gst_capsfilter_details);
-}
-
-static void
-gst_capsfilter_finalize (GObject * object)
-{
-  GstCapsFilter *capsfilter;
-
-  capsfilter = GST_CAPSFILTER (object);
-
-  gst_caps_unref (capsfilter->filter_caps);
-
-  G_OBJECT_CLASS (parent_class)->finalize (object);
+  gst_element_class_set_details (element_class, &gst_capsfilter_details);
 }
 
 static void
 gst_capsfilter_class_init (GstCapsFilterClass * klass)
 {
   GObjectClass *gobject_class;
-  GstElementClass *gstelement_class;
+  GstBaseTransformClass *trans_class;
 
-  gobject_class = G_OBJECT_CLASS (klass);
-  gstelement_class = GST_ELEMENT_CLASS (klass);
-
-  gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_capsfilter_set_property);
-  gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_capsfilter_get_property);
-  gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_capsfilter_finalize);
+  gobject_class = (GObjectClass *) klass;
+  gobject_class->set_property = gst_capsfilter_set_property;
+  gobject_class->get_property = gst_capsfilter_get_property;
+  gobject_class->dispose = gst_capsfilter_dispose;
 
   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_FILTER_CAPS,
       g_param_spec_boxed ("filter_caps", _("Filter caps"),
           _("Restrict the possible allowed formats"),
           GST_TYPE_CAPS, G_PARAM_READWRITE));
-}
 
-static void
-gst_capsfilter_init (GstCapsFilter * capsfilter)
-{
-  gst_element_create_all_pads (GST_ELEMENT (capsfilter));
-
-  capsfilter->srcpad = gst_element_get_pad (GST_ELEMENT (capsfilter), "src");
-  capsfilter->sinkpad = gst_element_get_pad (GST_ELEMENT (capsfilter), "sink");
-
-  gst_pad_set_getcaps_function (capsfilter->srcpad, gst_capsfilter_getcaps);
-
-  gst_pad_set_getcaps_function (capsfilter->sinkpad, gst_capsfilter_getcaps);
-  gst_pad_set_chain_function (capsfilter->sinkpad, gst_capsfilter_chain);
-
-  capsfilter->filter_caps = gst_caps_new_any ();
+  trans_class = (GstBaseTransformClass *) klass;
+  trans_class->transform_caps = gst_capsfilter_transform_caps;
+  trans_class->transform_ip = gst_capsfilter_transform_ip;
 }
 
-static GstCaps *
-gst_capsfilter_getcaps (GstPad * pad)
-{
-  GstPad *otherpad;
-  GstCapsFilter *capsfilter = GST_CAPSFILTER (GST_OBJECT_PARENT (pad));
-  GstCaps *caps;
-  GstCaps *icaps;
-
-  otherpad = (pad == capsfilter->srcpad) ? capsfilter->sinkpad :
-      capsfilter->srcpad;
-
-  caps = gst_pad_peer_get_caps (otherpad);
-  if (caps == NULL)
-    caps = gst_caps_new_any ();
-
-  icaps = gst_caps_intersect (caps, capsfilter->filter_caps);
-  gst_caps_unref (caps);
-
-  return icaps;
-}
-
-static GstFlowReturn
-gst_capsfilter_chain (GstPad * pad, GstBuffer * buf)
+static void
+gst_capsfilter_init (GstCapsFilter * filter)
 {
-  GstCapsFilter *capsfilter = GST_CAPSFILTER (GST_PAD_PARENT (pad));
-
-  gst_pad_push (capsfilter->srcpad, buf);
-
-  return GST_FLOW_OK;
+  gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (filter), TRUE);
+  filter->filter_caps = gst_caps_new_any ();
 }
 
 static void
 gst_capsfilter_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec)
 {
-  GstCapsFilter *capsfilter;
-
-  capsfilter = GST_CAPSFILTER (object);
+  GstCapsFilter *capsfilter = GST_CAPSFILTER (object);
 
   switch (prop_id) {
     case PROP_FILTER_CAPS:{
@@ -230,9 +176,7 @@ static void
 gst_capsfilter_get_property (GObject * object, guint prop_id, GValue * value,
     GParamSpec * pspec)
 {
-  GstCapsFilter *capsfilter;
-
-  capsfilter = GST_CAPSFILTER (object);
+  GstCapsFilter *capsfilter = GST_CAPSFILTER (object);
 
   switch (prop_id) {
     case PROP_FILTER_CAPS:
@@ -243,3 +187,31 @@ gst_capsfilter_get_property (GObject * object, guint prop_id, GValue * value,
       break;
   }
 }
+
+static void
+gst_capsfilter_dispose (GObject * object)
+{
+  GstCapsFilter *filter = GST_CAPSFILTER (object);
+
+  gst_caps_replace (&filter->filter_caps, NULL);
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static GstCaps *
+gst_capsfilter_transform_caps (GstBaseTransform * base, GstPad * pad,
+    GstCaps * caps)
+{
+  GstCapsFilter *capsfilter = GST_CAPSFILTER (base);
+  GstCaps *ret;
+
+  ret = gst_caps_intersect (caps, capsfilter->filter_caps);
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_capsfilter_transform_ip (GstBaseTransform * base, GstBuffer * buf)
+{
+  return GST_FLOW_OK;
+}