From: Andy Wingo Date: Thu, 4 Aug 2005 19:40:43 +0000 (+0000) Subject: gst/elements/gstcapsfilter.c: Reimplement using basetransform, fixes buffer_alloc... X-Git-Tag: RELEASE-0_9_2~163 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e20ed97cb2d772212934d880cfb3be3c548180ca;p=platform%2Fupstream%2Fgstreamer.git gst/elements/gstcapsfilter.c: Reimplement using basetransform, fixes buffer_alloc proxying among other things. Original commit message from CVS: 2005-08-04 Andy Wingo * 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... --- diff --git a/ChangeLog b/ChangeLog index 5614f66..cf978be 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,32 @@ +2005-08-04 Andy Wingo + + * 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 + + * gst/base/gstbasetransform.c (gst_base_transform_setcaps): Not + fixating is an error. + 2005-08-04 Edward Hervey * gst/base/gstadapter.h: diff --git a/gst/base/gstbasetransform.c b/gst/base/gstbasetransform.c index 51d6ca2..d4b48f0 100644 --- a/gst/base/gstbasetransform.c +++ b/gst/base/gstbasetransform.c @@ -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; diff --git a/gst/base/gstbasetransform.h b/gst/base/gstbasetransform.h index 68673e7..fb4d07b 100644 --- a/gst/base/gstbasetransform.h +++ b/gst/base/gstbasetransform.h @@ -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); diff --git a/gst/elements/gstcapsfilter.c b/gst/elements/gstcapsfilter.c index 3ba28da..dd9e0c8 100644 --- a/gst/elements/gstcapsfilter.c +++ b/gst/elements/gstcapsfilter.c @@ -20,16 +20,19 @@ * Boston, MA 02111-1307, USA. */ - -#include - #ifdef HAVE_CONFIG_H -# include "config.h" +#include "config.h" #endif #include "../gst-i18n-lib.h" -#include #include +#include + + +GstElementDetails gst_capsfilter_details = GST_ELEMENT_DETAILS ("CapsFilter", + "Generic", + "Pass data without modification, limiting formats", + "David Schleef "); #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 "); - -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; +} diff --git a/libs/gst/base/gstbasetransform.c b/libs/gst/base/gstbasetransform.c index 51d6ca2..d4b48f0 100644 --- a/libs/gst/base/gstbasetransform.c +++ b/libs/gst/base/gstbasetransform.c @@ -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; diff --git a/libs/gst/base/gstbasetransform.h b/libs/gst/base/gstbasetransform.h index 68673e7..fb4d07b 100644 --- a/libs/gst/base/gstbasetransform.h +++ b/libs/gst/base/gstbasetransform.h @@ -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); diff --git a/plugins/elements/gstcapsfilter.c b/plugins/elements/gstcapsfilter.c index 3ba28da..dd9e0c8 100644 --- a/plugins/elements/gstcapsfilter.c +++ b/plugins/elements/gstcapsfilter.c @@ -20,16 +20,19 @@ * Boston, MA 02111-1307, USA. */ - -#include - #ifdef HAVE_CONFIG_H -# include "config.h" +#include "config.h" #endif #include "../gst-i18n-lib.h" -#include #include +#include + + +GstElementDetails gst_capsfilter_details = GST_ELEMENT_DETAILS ("CapsFilter", + "Generic", + "Pass data without modification, limiting formats", + "David Schleef "); #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 "); - -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; +}