diff --git a/ChangeLog b/ChangeLog index 3a0a2aeb24..040875e64b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,43 @@ +2005-03-29 Wim Taymans + + * gst/base/Makefile.am: + * gst/base/README: + * gst/base/gstbasesink.c: (gst_basesink_get_type), + (gst_basesink_base_init), (gst_basesink_class_init), + (gst_basesink_pad_getcaps), (gst_basesink_init), + (gst_basesink_activate), (gst_basesink_change_state): + * gst/base/gstbasesink.h: + * gst/base/gstbasetransform.c: (gst_base_transform_get_type), + (gst_base_transform_base_init), (gst_base_transform_finalize), + (gst_base_transform_class_init), (gst_base_transform_init), + (gst_base_transform_proxy_getcaps), (gst_base_transform_setcaps), + (gst_base_transform_event), (gst_base_transform_getrange), + (gst_base_transform_chain), (gst_base_transform_handle_buffer), + (gst_base_transform_set_property), + (gst_base_transform_get_property), + (gst_base_transform_sink_activate), + (gst_base_transform_src_activate), + (gst_base_transform_change_state): + * gst/base/gstbasetransform.h: + * gst/elements/gstidentity.c: (gst_identity_finalize), + (gst_identity_class_init), (gst_identity_init), + (gst_identity_event), (gst_identity_check_perfect), + (gst_identity_transform), (gst_identity_set_property), + (gst_identity_get_property), (gst_identity_change_state): + * gst/elements/gstidentity.h: + * gst/gstelement.c: (gst_element_get_state_func), + (gst_element_lost_state), (gst_element_pads_activate): + * gst/gstpad.c: (gst_pad_set_active), (gst_pad_peer_set_active), + (gst_pad_check_pull_range), (gst_pad_pull_range): + * gst/gstpad.h: + Simplify pad activation. + Added function to check if pull_range can be performed. + Error out when pulling inactive or flushing pads. + Removed const from refcounted types as it does not make sense. + Simplify pad templates in basesink + Added base class for simple 1-to-1 transforms. + Make identity subclass the base transform. + 2005-03-29 Andy Wingo * docs/libs/gstreamer-libs-overrides.txt: diff --git a/gst/base/Makefile.am b/gst/base/Makefile.am index 8ba1b85d56..dda7031d9a 100644 --- a/gst/base/Makefile.am +++ b/gst/base/Makefile.am @@ -6,7 +6,8 @@ noinst_DATA = $(as_libtool_noinst_DATA_files) libgstbase_@GST_MAJORMINOR@_la_DEPENDENCIES = ../libgstreamer-@GST_MAJORMINOR@.la libgstbase_@GST_MAJORMINOR@_la_SOURCES = \ - gstbasesink.c + gstbasesink.c \ + gstbasetransform.c libgstbase_@GST_MAJORMINOR@_la_CFLAGS = $(GST_OBJ_CFLAGS) libgstbase_@GST_MAJORMINOR@_la_LIBADD = $(GST_OBJ_LIBS) @@ -16,7 +17,8 @@ libgstbase_@GST_MAJORMINOR@includedir = \ $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/base libgstbase_@GST_MAJORMINOR@include_HEADERS = \ - gstbasesink.h + gstbasesink.h \ + gstbasetransform.h install-data-local: as-libtool-install-data-local diff --git a/gst/base/README b/gst/base/README index efd6e572a9..f9c158376d 100644 --- a/gst/base/README +++ b/gst/base/README @@ -14,3 +14,14 @@ GstBaseSink FIXME: not much point making it operate in pull mode as a generic base class I guess... + +GstBaseTransform + + Base class for simple tranform filters + + - one sinkpad and one srcpad + - formats the same on sink and source pad. + - handles state changes + - does flushing + - push mode + - pull mode if transform can operate on arbitrary data diff --git a/gst/base/gstbasesink.c b/gst/base/gstbasesink.c index a476071fd3..88d7d97816 100644 --- a/gst/base/gstbasesink.c +++ b/gst/base/gstbasesink.c @@ -26,11 +26,6 @@ #include "gstbasesink.h" #include -static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS_ANY); - GST_DEBUG_CATEGORY_STATIC (gst_basesink_debug); #define GST_CAT_DEFAULT gst_basesink_debug @@ -61,11 +56,35 @@ enum PROP_PREROLL_QUEUE_LEN }; -#define _do_init(bla) \ - GST_DEBUG_CATEGORY_INIT (gst_basesink_debug, "basesink", 0, "basesink element"); +static GstElementClass *parent_class = NULL; -GST_BOILERPLATE_FULL (GstBaseSink, gst_basesink, GstElement, GST_TYPE_ELEMENT, - _do_init); +static void gst_basesink_base_init (gpointer g_class); +static void gst_basesink_class_init (GstBaseSinkClass * klass); +static void gst_basesink_init (GstBaseSink * trans, gpointer g_class); + +GType +gst_basesink_get_type (void) +{ + static GType basesink_type = 0; + + if (!basesink_type) { + static const GTypeInfo basesink_info = { + sizeof (GstBaseSinkClass), + (GBaseInitFunc) gst_basesink_base_init, + NULL, + (GClassInitFunc) gst_basesink_class_init, + NULL, + NULL, + sizeof (GstBaseSink), + 0, + (GInstanceInitFunc) gst_basesink_init, + }; + + basesink_type = g_type_register_static (GST_TYPE_ELEMENT, + "GstBaseSink", &basesink_info, G_TYPE_FLAG_ABSTRACT); + } + return basesink_type; +} static void gst_basesink_set_clock (GstElement * element, GstClock * clock); @@ -74,7 +93,6 @@ static void gst_basesink_set_property (GObject * object, guint prop_id, static void gst_basesink_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -static GstStaticPadTemplate *gst_base_sink_get_template (GstBaseSink * sink); static GstCaps *gst_base_sink_get_caps (GstBaseSink * sink); static gboolean gst_base_sink_set_caps (GstBaseSink * sink, GstCaps * caps); static GstBuffer *gst_base_sink_buffer_alloc (GstBaseSink * sink, @@ -93,32 +111,11 @@ static gboolean gst_basesink_event (GstPad * pad, GstEvent * event); static inline void gst_basesink_handle_buffer (GstBaseSink * basesink, GstBuffer * buf); -static GstStaticPadTemplate * -gst_basesink_get_template (GstBaseSink * bsink) -{ - GstStaticPadTemplate *template = NULL; - GstBaseSinkClass *bclass; - - bclass = GST_BASESINK_GET_CLASS (bsink); - - if (bclass->get_template) - template = bclass->get_template (bsink); - - if (template == NULL) { - template = &sinktemplate; - } - return template; -} - static void gst_basesink_base_init (gpointer g_class) { - //GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); - - /* - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&sinktemplate)); - */ + GST_DEBUG_CATEGORY_INIT (gst_basesink_debug, "basesink", 0, + "basesink element"); } static void @@ -130,6 +127,8 @@ gst_basesink_class_init (GstBaseSinkClass * klass) gobject_class = (GObjectClass *) klass; gstelement_class = (GstElementClass *) klass; + parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_basesink_set_property); gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_basesink_get_property); @@ -153,7 +152,6 @@ gst_basesink_class_init (GstBaseSinkClass * klass) klass->get_caps = GST_DEBUG_FUNCPTR (gst_base_sink_get_caps); klass->set_caps = GST_DEBUG_FUNCPTR (gst_base_sink_set_caps); - klass->get_template = GST_DEBUG_FUNCPTR (gst_base_sink_get_template); klass->buffer_alloc = GST_DEBUG_FUNCPTR (gst_base_sink_buffer_alloc); klass->get_times = GST_DEBUG_FUNCPTR (gst_basesink_get_times); } @@ -171,13 +169,15 @@ gst_basesink_pad_getcaps (GstPad * pad) caps = bclass->get_caps (bsink); if (caps == NULL) { - GstStaticPadTemplate *stemplate; - GstPadTemplate *template; + GstPadTemplate *pad_template; - stemplate = gst_basesink_get_template (bsink); - template = gst_static_pad_template_get (stemplate); - caps = gst_caps_copy (gst_pad_template_get_caps (template)); + pad_template = + gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "sink"); + if (pad_template != NULL) { + caps = gst_caps_ref (gst_pad_template_get_caps (pad_template)); + } } + return caps; } @@ -213,15 +213,16 @@ gst_basesink_pad_buffer_alloc (GstPad * pad, guint64 offset, guint size, } static void -gst_basesink_init (GstBaseSink * basesink) +gst_basesink_init (GstBaseSink * basesink, gpointer g_class) { - GstStaticPadTemplate *template; + GstPadTemplate *pad_template; - template = gst_basesink_get_template (basesink); + pad_template = + gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "sink"); + g_return_if_fail (pad_template != NULL); + + basesink->sinkpad = gst_pad_new_from_template (pad_template, "sink"); - basesink->sinkpad = - gst_pad_new_from_template (gst_static_pad_template_get (template), - "sink"); gst_pad_set_getcaps_function (basesink->sinkpad, GST_DEBUG_FUNCPTR (gst_basesink_pad_getcaps)); gst_pad_set_setcaps_function (basesink->sinkpad, @@ -328,12 +329,6 @@ gst_basesink_get_property (GObject * object, guint prop_id, GValue * value, GST_UNLOCK (sink); } -static GstStaticPadTemplate * -gst_base_sink_get_template (GstBaseSink * sink) -{ - return &sinktemplate; -} - static GstCaps * gst_base_sink_get_caps (GstBaseSink * sink) { @@ -735,6 +730,7 @@ gst_basesink_activate (GstPad * pad, GstActivateMode mode) case GST_ACTIVATE_PULL: /* if we have a scheduler we can start the task */ g_return_val_if_fail (basesink->has_loop, FALSE); + gst_pad_peer_set_active (pad, mode); if (GST_ELEMENT_SCHEDULER (basesink)) { GST_STREAM_LOCK (pad); GST_RPAD_TASK (pad) = @@ -791,7 +787,7 @@ gst_basesink_change_state (GstElement * element) break; case GST_STATE_READY_TO_PAUSED: /* need to complete preroll before this state change completes, there - * is no data flow in READY so we cqn safely assume we need to preroll. */ + * is no data flow in READY so we can safely assume we need to preroll. */ basesink->offset = 0; GST_PREROLL_LOCK (basesink->sinkpad); basesink->preroll_queue = g_queue_new (); diff --git a/gst/base/gstbasesink.h b/gst/base/gstbasesink.h index 3c64f78ed3..b3eafade44 100644 --- a/gst/base/gstbasesink.h +++ b/gst/base/gstbasesink.h @@ -66,8 +66,6 @@ struct _GstBaseSink { struct _GstBaseSinkClass { GstElementClass parent_class; - GstStaticPadTemplate* (*get_template) (GstBaseSink *sink); - GstCaps* (*get_caps) (GstBaseSink *sink); gboolean (*set_caps) (GstBaseSink *sink, GstCaps *caps); diff --git a/gst/base/gstbasetransform.c b/gst/base/gstbasetransform.c new file mode 100644 index 0000000000..c6032d6964 --- /dev/null +++ b/gst/base/gstbasetransform.c @@ -0,0 +1,404 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * 2005 Wim Taymans + * + * gstbasetransform.c: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#include + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "../gst-i18n-lib.h" +#include "gstbasetransform.h" +#include + +GST_DEBUG_CATEGORY_STATIC (gst_base_transform_debug); +#define GST_CAT_DEFAULT gst_base_transform_debug + +/* BaseTransform signals and args */ +enum +{ + SIGNAL_HANDOFF, + /* FILL ME */ + LAST_SIGNAL +}; + +enum +{ + PROP_0, +}; + +static GstElementClass *parent_class = NULL; + +static void gst_base_transform_base_init (gpointer g_class); +static void gst_base_transform_class_init (GstBaseTransformClass * klass); +static void gst_base_transform_init (GstBaseTransform * trans, + gpointer g_class); + +GType +gst_base_transform_get_type (void) +{ + static GType base_transform_type = 0; + + if (!base_transform_type) { + static const GTypeInfo base_transform_info = { + sizeof (GstBaseTransformClass), + (GBaseInitFunc) gst_base_transform_base_init, + NULL, + (GClassInitFunc) gst_base_transform_class_init, + NULL, + NULL, + sizeof (GstBaseTransform), + 0, + (GInstanceInitFunc) gst_base_transform_init, + }; + + base_transform_type = g_type_register_static (GST_TYPE_ELEMENT, + "GstBaseTransform", &base_transform_info, G_TYPE_FLAG_ABSTRACT); + } + return base_transform_type; +} + +static void gst_base_transform_finalize (GObject * object); +static void gst_base_transform_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_base_transform_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static gboolean gst_base_transform_src_activate (GstPad * pad, + GstActivateMode mode); +static gboolean gst_base_transform_sink_activate (GstPad * pad, + GstActivateMode mode); +static GstElementStateReturn gst_base_transform_change_state (GstElement * + element); + +static gboolean gst_base_transform_event (GstPad * pad, GstEvent * event); +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_proxy_getcaps (GstPad * pad); +static gboolean gst_base_transform_setcaps (GstPad * pad, GstCaps * caps); + +/* static guint gst_base_transform_signals[LAST_SIGNAL] = { 0 }; */ + +static void +gst_base_transform_base_init (gpointer g_class) +{ + GST_DEBUG_CATEGORY_INIT (gst_base_transform_debug, "basetransform", 0, + "basetransform element"); +} + +static void +gst_base_transform_finalize (GObject * object) +{ + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_base_transform_class_init (GstBaseTransformClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = G_OBJECT_CLASS (klass); + gstelement_class = GST_ELEMENT_CLASS (klass); + + parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + + gobject_class->set_property = + GST_DEBUG_FUNCPTR (gst_base_transform_set_property); + gobject_class->get_property = + GST_DEBUG_FUNCPTR (gst_base_transform_get_property); + + gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_base_transform_finalize); + + gstelement_class->change_state = + GST_DEBUG_FUNCPTR (gst_base_transform_change_state); +} + +static void +gst_base_transform_init (GstBaseTransform * trans, gpointer g_class) +{ + GstPadTemplate *pad_template; + + GST_DEBUG ("gst_base_transform_init"); + + pad_template = + gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "sink"); + g_return_if_fail (pad_template != NULL); + trans->sinkpad = gst_pad_new_from_template (pad_template, "sink"); + gst_pad_set_getcaps_function (trans->sinkpad, + GST_DEBUG_FUNCPTR (gst_base_transform_proxy_getcaps)); + gst_pad_set_setcaps_function (trans->sinkpad, + GST_DEBUG_FUNCPTR (gst_base_transform_setcaps)); + gst_pad_set_event_function (trans->sinkpad, + GST_DEBUG_FUNCPTR (gst_base_transform_event)); + gst_pad_set_chain_function (trans->sinkpad, + GST_DEBUG_FUNCPTR (gst_base_transform_chain)); + gst_pad_set_activate_function (trans->sinkpad, + GST_DEBUG_FUNCPTR (gst_base_transform_sink_activate)); + gst_element_add_pad (GST_ELEMENT (trans), trans->sinkpad); + + pad_template = + gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src"); + g_return_if_fail (pad_template != NULL); + trans->srcpad = gst_pad_new_from_template (pad_template, "src"); + gst_pad_set_getcaps_function (trans->srcpad, + GST_DEBUG_FUNCPTR (gst_base_transform_proxy_getcaps)); + gst_pad_set_getrange_function (trans->srcpad, + GST_DEBUG_FUNCPTR (gst_base_transform_getrange)); + gst_pad_set_activate_function (trans->srcpad, + GST_DEBUG_FUNCPTR (gst_base_transform_src_activate)); + gst_element_add_pad (GST_ELEMENT (trans), trans->srcpad); +} + +static GstCaps * +gst_base_transform_proxy_getcaps (GstPad * pad) +{ + GstPad *otherpad; + GstBaseTransform *trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad)); + + otherpad = pad == trans->srcpad ? trans->sinkpad : trans->srcpad; + + return gst_pad_peer_get_caps (otherpad); +} + +static gboolean +gst_base_transform_setcaps (GstPad * pad, GstCaps * caps) +{ + GstBaseTransform *trans; + GstBaseTransformClass *bclass; + gboolean result = TRUE; + + trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad)); + bclass = GST_BASE_TRANSFORM_GET_CLASS (trans); + + if (bclass->set_caps) + result = bclass->set_caps (trans, caps); + + return result; +} + +static gboolean +gst_base_transform_event (GstPad * pad, GstEvent * event) +{ + GstBaseTransform *trans; + GstBaseTransformClass *bclass; + gboolean ret = FALSE; + + trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad)); + bclass = GST_BASE_TRANSFORM_GET_CLASS (trans); + + if (bclass->event) + bclass->event (trans, event); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_FLUSH: + if (GST_EVENT_FLUSH_DONE (event)) { + } + GST_STREAM_LOCK (pad); + break; + case GST_EVENT_EOS: + GST_STREAM_LOCK (pad); + break; + default: + break; + } + ret = gst_pad_event_default (pad, event); + GST_STREAM_UNLOCK (pad); + + return ret; +} + +static GstFlowReturn +gst_base_transform_getrange (GstPad * pad, guint64 offset, + guint length, GstBuffer ** buffer) +{ + GstBaseTransform *trans; + GstFlowReturn ret; + GstBuffer *inbuf; + + trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad)); + + GST_STREAM_LOCK (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); + + return ret; +} + +static GstFlowReturn +gst_base_transform_chain (GstPad * pad, GstBuffer * buffer) +{ + GstBaseTransform *trans; + GstFlowReturn ret = GST_FLOW_OK; + GstBuffer *outbuf; + + trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad)); + + GST_STREAM_LOCK (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_buffer_unref (inbuf); + + return ret; +} + +static void +gst_base_transform_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstBaseTransform *trans; + + trans = GST_BASE_TRANSFORM (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_base_transform_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstBaseTransform *trans; + + trans = GST_BASE_TRANSFORM (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static gboolean +gst_base_transform_sink_activate (GstPad * pad, GstActivateMode mode) +{ + gboolean result = FALSE; + GstBaseTransform *trans; + + trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad)); + + switch (mode) { + case GST_ACTIVATE_PUSH: + result = TRUE; + break; + case GST_ACTIVATE_PULL: + result = TRUE; + break; + case GST_ACTIVATE_NONE: + result = TRUE; + break; + } + return result; +} + +static gboolean +gst_base_transform_src_activate (GstPad * pad, GstActivateMode mode) +{ + gboolean result = FALSE; + GstBaseTransform *trans; + + trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad)); + + switch (mode) { + case GST_ACTIVATE_PUSH: + result = TRUE; + break; + case GST_ACTIVATE_PULL: + result = gst_pad_set_active (trans->sinkpad, mode); + result = gst_pad_peer_set_active (trans->sinkpad, mode); + break; + case GST_ACTIVATE_NONE: + result = TRUE; + break; + } + return result; +} + +static GstElementStateReturn +gst_base_transform_change_state (GstElement * element) +{ + GstBaseTransform *trans; + GstElementState transition; + GstElementStateReturn result; + + trans = GST_BASE_TRANSFORM (element); + transition = GST_STATE_TRANSITION (element); + + switch (transition) { + case GST_STATE_NULL_TO_READY: + break; + case GST_STATE_READY_TO_PAUSED: + break; + case GST_STATE_PAUSED_TO_PLAYING: + break; + default: + break; + } + + result = GST_ELEMENT_CLASS (parent_class)->change_state (element); + + switch (transition) { + case GST_STATE_PLAYING_TO_PAUSED: + break; + case GST_STATE_PAUSED_TO_READY: + break; + case GST_STATE_READY_TO_NULL: + break; + default: + break; + } + + return result; +} diff --git a/gst/base/gstbasetransform.h b/gst/base/gstbasetransform.h new file mode 100644 index 0000000000..788fe5350a --- /dev/null +++ b/gst/base/gstbasetransform.h @@ -0,0 +1,67 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2005 Wim Taymans + * + * gstbasetransform.h: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifndef __GST_BASE_TRANSFORM_H__ +#define __GST_BASE_TRANSFORM_H__ + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_BASE_TRANSFORM (gst_base_transform_get_type()) +#define GST_BASE_TRANSFORM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_BASE_TRANSFORM,GstBaseTransform)) +#define GST_BASE_TRANSFORM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_BASE_TRANSFORM,GstBaseTransformClass)) +#define GST_BASE_TRANSFORM_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_BASE_TRANSFORM,GstBaseTransformClass)) +#define GST_IS_BASE_TRANSFORM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_BASE_TRANSFORM)) +#define GST_IS_BASE_TRANSFORM_CLASS(obj)(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_BASE_TRANSFORM)) + +/* the names of the templates for the sink and source pads */ +#define GST_BASE_TRANSFORM_SINK_NAME "sink" +#define GST_BASE_TRANSFORM_SRC_NAME "src" + +typedef struct _GstBaseTransform GstBaseTransform; +typedef struct _GstBaseTransformClass GstBaseTransformClass; + +struct _GstBaseTransform { + GstElement element; + + /* source and sink pads */ + GstPad *sinkpad; + GstPad *srcpad; +}; + +struct _GstBaseTransformClass { + GstElementClass parent_class; + + gboolean (*set_caps) (GstBaseTransform *trans, GstCaps *caps); + + gboolean (*event) (GstBaseTransform *trans, GstEvent *event); + GstFlowReturn (*transform) (GstBaseTransform *trans, GstBuffer *inbuf, GstBuffer **outbuf); +}; + +GType gst_base_transform_get_type(void); + +G_END_DECLS + +#endif /* __GST_BASE_TRANSFORM_H__ */ diff --git a/gst/elements/gstidentity.c b/gst/elements/gstidentity.c index 0b8a6d2f7e..76a61f7e12 100644 --- a/gst/elements/gstidentity.c +++ b/gst/elements/gstidentity.c @@ -59,7 +59,6 @@ enum LAST_SIGNAL }; -#define DEFAULT_LOOP_BASED FALSE #define DEFAULT_SLEEP_TIME 0 #define DEFAULT_DUPLICATE 1 #define DEFAULT_ERROR_AFTER -1 @@ -73,11 +72,6 @@ enum enum { PROP_0, - PROP_HAS_GETRANGE, - PROP_HAS_CHAIN, - PROP_HAS_SINK_LOOP, - PROP_HAS_SRC_LOOP, - PROP_LOOP_BASED, PROP_SLEEP_TIME, PROP_DUPLICATE, PROP_ERROR_AFTER, @@ -91,14 +85,11 @@ enum }; -typedef GstFlowReturn (*IdentityPushFunc) (GstIdentity *, GstBuffer *); - - #define _do_init(bla) \ GST_DEBUG_CATEGORY_INIT (gst_identity_debug, "identity", 0, "identity element"); -GST_BOILERPLATE_FULL (GstIdentity, gst_identity, GstElement, GST_TYPE_ELEMENT, - _do_init); +GST_BOILERPLATE_FULL (GstIdentity, gst_identity, GstBaseTransform, + GST_TYPE_BASE_TRANSFORM, _do_init); static void gst_identity_finalize (GObject * object); static void gst_identity_set_property (GObject * object, guint prop_id, @@ -107,17 +98,9 @@ static void gst_identity_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); static GstElementStateReturn gst_identity_change_state (GstElement * element); -static gboolean gst_identity_event (GstPad * pad, GstEvent * event); -static GstFlowReturn gst_identity_getrange (GstPad * pad, guint64 offset, - guint length, GstBuffer ** buffer); -static GstFlowReturn gst_identity_chain (GstPad * pad, GstBuffer * buffer); -static void gst_identity_src_loop (GstPad * pad); -static void gst_identity_sink_loop (GstPad * pad); -static GstFlowReturn gst_identity_handle_buffer (GstIdentity * identity, - GstBuffer * buf); -static void gst_identity_set_clock (GstElement * element, GstClock * clock); -static GstCaps *gst_identity_proxy_getcaps (GstPad * pad); - +static gboolean gst_identity_event (GstBaseTransform * trans, GstEvent * event); +static GstFlowReturn gst_identity_transform (GstBaseTransform * trans, + GstBuffer * inbuf, GstBuffer ** outbuf); static guint gst_identity_signals[LAST_SIGNAL] = { 0 }; @@ -140,9 +123,6 @@ gst_identity_finalize (GObject * object) identity = GST_IDENTITY (object); - g_mutex_free (identity->pen_lock); - g_cond_free (identity->pen_cond); - g_free (identity->last_message); G_OBJECT_CLASS (parent_class)->finalize (object); @@ -153,29 +133,15 @@ gst_identity_class_init (GstIdentityClass * klass) { GObjectClass *gobject_class; GstElementClass *gstelement_class; + GstBaseTransformClass *gstbasetrans_class; gobject_class = G_OBJECT_CLASS (klass); gstelement_class = GST_ELEMENT_CLASS (klass); + gstbasetrans_class = GST_BASE_TRANSFORM_CLASS (klass); gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_identity_set_property); gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_identity_get_property); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_GETRANGE, - g_param_spec_boolean ("has-getrange", "Has getrange", - "If the src pad will implement a getrange function", - TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_CHAIN, - g_param_spec_boolean ("has-chain", "Has chain", - "If the sink pad will implement a chain function", - TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_SRC_LOOP, - g_param_spec_boolean ("has-src-loop", "Has src loop", - "If the src pad will implement a loop function", - FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_SINK_LOOP, - g_param_spec_boolean ("has-sink-loop", "Has sink loop", - "If the sink pad will implement a loop function", - FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SLEEP_TIME, g_param_spec_uint ("sleep-time", "Sleep time", "Microseconds to sleep between processing", 0, G_MAXUINT, @@ -220,33 +186,16 @@ gst_identity_class_init (GstIdentityClass * klass) gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_identity_finalize); - gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_identity_set_clock); gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_identity_change_state); + gstbasetrans_class->event = GST_DEBUG_FUNCPTR (gst_identity_event); + gstbasetrans_class->transform = GST_DEBUG_FUNCPTR (gst_identity_transform); } static void gst_identity_init (GstIdentity * identity) { - identity->sinkpad = - gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate), - "sink"); - gst_element_add_pad (GST_ELEMENT (identity), identity->sinkpad); - gst_pad_set_getcaps_function (identity->sinkpad, - GST_DEBUG_FUNCPTR (gst_identity_proxy_getcaps)); - gst_pad_set_event_function (identity->sinkpad, - GST_DEBUG_FUNCPTR (gst_identity_event)); - - identity->srcpad = - gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate), - "src"); - gst_pad_set_getcaps_function (identity->srcpad, - GST_DEBUG_FUNCPTR (gst_identity_proxy_getcaps)); - gst_pad_set_getrange_function (identity->srcpad, - GST_DEBUG_FUNCPTR (gst_identity_getrange)); - gst_element_add_pad (GST_ELEMENT (identity), identity->srcpad); - identity->sleep_time = DEFAULT_SLEEP_TIME; identity->duplicate = DEFAULT_DUPLICATE; identity->error_after = DEFAULT_ERROR_AFTER; @@ -257,279 +206,78 @@ gst_identity_init (GstIdentity * identity) identity->check_perfect = DEFAULT_CHECK_PERFECT; identity->dump = DEFAULT_DUMP; identity->last_message = NULL; - identity->srccaps = NULL; - - identity->pen_data = NULL; - identity->pen_lock = g_mutex_new (); - identity->pen_cond = g_cond_new (); - identity->pen_flushing = FALSE; -} - -static void -gst_identity_set_clock (GstElement * element, GstClock * clock) -{ - GstIdentity *identity = GST_IDENTITY (element); - - gst_object_replace ((GstObject **) & identity->clock, (GstObject *) clock); -} - -static GstCaps * -gst_identity_proxy_getcaps (GstPad * pad) -{ - GstPad *otherpad; - GstIdentity *identity = GST_IDENTITY (GST_OBJECT_PARENT (pad)); - - otherpad = pad == identity->srcpad ? identity->sinkpad : identity->srcpad; - - return gst_pad_peer_get_caps (otherpad); } static gboolean -identity_queue_push (GstIdentity * identity, GstData * data) -{ - gboolean ret; - - g_mutex_lock (identity->pen_lock); - while (identity->pen_data && !identity->pen_flushing) - g_cond_wait (identity->pen_cond, identity->pen_lock); - if (identity->pen_flushing) { - gst_data_unref (identity->pen_data); - identity->pen_data = NULL; - gst_data_unref (data); - ret = FALSE; - } else { - identity->pen_data = data; - ret = TRUE; - } - g_cond_signal (identity->pen_cond); - g_mutex_unlock (identity->pen_lock); - - return ret; -} - -static GstData * -identity_queue_pop (GstIdentity * identity) -{ - GstData *ret; - - g_mutex_lock (identity->pen_lock); - while (!(ret = identity->pen_data) && !identity->pen_flushing) - g_cond_wait (identity->pen_cond, identity->pen_lock); - g_cond_signal (identity->pen_cond); - g_mutex_unlock (identity->pen_lock); - - return ret; -} - -static void -identity_queue_flush (GstIdentity * identity) -{ - g_mutex_lock (identity->pen_lock); - identity->pen_flushing = TRUE; - g_cond_signal (identity->pen_cond); - g_mutex_unlock (identity->pen_lock); -} - -static gboolean -gst_identity_event (GstPad * pad, GstEvent * event) +gst_identity_event (GstBaseTransform * trans, GstEvent * event) { GstIdentity *identity; - gboolean ret; - identity = GST_IDENTITY (GST_PAD_PARENT (pad)); - - GST_STREAM_LOCK (pad); + identity = GST_IDENTITY (trans); if (!identity->silent) { g_free (identity->last_message); identity->last_message = g_strdup_printf ("chain ******* (%s:%s)E (type: %d) %p", - GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE (event), event); + GST_DEBUG_PAD_NAME (trans->sinkpad), GST_EVENT_TYPE (event), event); g_object_notify (G_OBJECT (identity), "last_message"); } - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_FLUSH: - /* forward event */ - gst_pad_event_default (pad, event); - if (GST_EVENT_FLUSH_DONE (event)) { - if (identity->sink_mode == GST_ACTIVATE_PULL) { - /* already have the sink stream lock */ - gst_task_start (GST_RPAD_TASK (identity->sinkpad)); - } - if (identity->src_mode == GST_ACTIVATE_PUSH) { - GST_STREAM_LOCK (identity->srcpad); - gst_task_start (GST_RPAD_TASK (identity->srcpad)); - GST_STREAM_UNLOCK (identity->srcpad); - } - } else { - /* unblock both functions */ - identity_queue_flush (identity); - - } - ret = TRUE; - goto done; - case GST_EVENT_EOS: - if (identity->sink_mode == GST_ACTIVATE_PULL) { - /* already have the sink stream lock */ - gst_task_pause (GST_RPAD_TASK (identity->sinkpad)); - } - break; - default: - break; - } - - if (identity->decoupled) { - ret = identity_queue_push (identity, (GstData *) event); - } else { - ret = gst_pad_push_event (identity->srcpad, event); - } - -done: - GST_STREAM_UNLOCK (pad); - return ret; -} - -static GstFlowReturn -gst_identity_getrange (GstPad * pad, guint64 offset, - guint length, GstBuffer ** buffer) -{ - GstIdentity *identity; - GstFlowReturn ret; - - identity = GST_IDENTITY (GST_PAD_PARENT (pad)); - - GST_STREAM_LOCK (pad); - - ret = gst_pad_pull_range (identity->sinkpad, offset, length, buffer); - - GST_STREAM_UNLOCK (pad); - - return ret; -} - -static GstFlowReturn -gst_identity_chain (GstPad * pad, GstBuffer * buffer) -{ - GstIdentity *identity; - GstFlowReturn ret = GST_FLOW_OK; - - identity = GST_IDENTITY (GST_PAD_PARENT (pad)); - - GST_STREAM_LOCK (pad); - - ret = gst_identity_handle_buffer (identity, buffer); - - GST_STREAM_UNLOCK (pad); - - return ret; -} - -#define DEFAULT_PULL_SIZE 1024 - -static void -gst_identity_sink_loop (GstPad * pad) -{ - GstIdentity *identity; - GstBuffer *buffer; - GstFlowReturn ret; - - identity = GST_IDENTITY (GST_PAD_PARENT (pad)); - - GST_STREAM_LOCK (pad); - - ret = gst_pad_pull_range (pad, identity->offset, DEFAULT_PULL_SIZE, &buffer); - if (ret != GST_FLOW_OK) - goto sink_loop_pause; - - ret = gst_identity_handle_buffer (identity, buffer); - if (ret != GST_FLOW_OK) - goto sink_loop_pause; - - GST_STREAM_UNLOCK (pad); - return; - -sink_loop_pause: - gst_task_pause (GST_RPAD_TASK (identity->sinkpad)); - GST_STREAM_UNLOCK (pad); - return; + return TRUE; } static void -gst_identity_src_loop (GstPad * pad) +gst_identity_check_perfect (GstIdentity * identity, GstBuffer * buf) { - GstIdentity *identity; - GstData *data; - GstFlowReturn ret; + GstClockTime timestamp; - identity = GST_IDENTITY (GST_PAD_PARENT (pad)); - - GST_STREAM_LOCK (pad); - - data = identity_queue_pop (identity); - if (!data) /* we're getting flushed */ - goto src_loop_pause; - - if (GST_IS_EVENT (data)) { - if (GST_EVENT_TYPE (data) == GST_EVENT_EOS) - gst_task_pause (GST_RPAD_TASK (identity->srcpad)); - gst_pad_push_event (identity->srcpad, GST_EVENT (data)); - } else { - ret = gst_pad_push (identity->srcpad, (GstBuffer *) data); - if (ret != GST_FLOW_OK) - goto src_loop_pause; - } - - GST_STREAM_UNLOCK (pad); - return; - -src_loop_pause: - gst_task_pause (GST_RPAD_TASK (identity->srcpad)); - GST_STREAM_UNLOCK (pad); - return; -} - -static GstFlowReturn -gst_identity_handle_buffer (GstIdentity * identity, GstBuffer * buf) -{ - GstFlowReturn ret = GST_FLOW_OK; - guint i; + timestamp = GST_BUFFER_TIMESTAMP (buf); /* see if we need to do perfect stream checking */ /* invalid timestamp drops us out of check. FIXME: maybe warn ? */ - if (identity->check_perfect && - GST_BUFFER_TIMESTAMP (buf) != GST_CLOCK_TIME_NONE) { + if (timestamp != GST_CLOCK_TIME_NONE) { /* check if we had a previous buffer to compare to */ if (identity->prev_timestamp != GST_CLOCK_TIME_NONE) { - if (identity->prev_timestamp + identity->prev_duration != - GST_BUFFER_TIMESTAMP (buf)) { + guint64 offset; + + if (identity->prev_timestamp + identity->prev_duration != timestamp) { GST_WARNING_OBJECT (identity, "Buffer not time-contiguous with previous one: " "prev ts %" GST_TIME_FORMAT ", prev dur %" GST_TIME_FORMAT ", new ts %" GST_TIME_FORMAT, GST_TIME_ARGS (identity->prev_timestamp), - GST_TIME_ARGS (identity->prev_duration), - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); + GST_TIME_ARGS (identity->prev_duration), GST_TIME_ARGS (timestamp)); } - if (identity->prev_offset_end != GST_BUFFER_OFFSET (buf)) { + + offset = GST_BUFFER_OFFSET (buf); + if (identity->prev_offset_end != offset) { GST_WARNING_OBJECT (identity, "Buffer not data-contiguous with previous one: " "prev offset_end %" G_GINT64_FORMAT ", new offset %" - G_GINT64_FORMAT, identity->prev_offset_end, - GST_BUFFER_OFFSET (buf)); + G_GINT64_FORMAT, identity->prev_offset_end, offset); } } /* update prev values */ - identity->prev_timestamp = GST_BUFFER_TIMESTAMP (buf); + identity->prev_timestamp = timestamp; identity->prev_duration = GST_BUFFER_DURATION (buf); identity->prev_offset_end = GST_BUFFER_OFFSET_END (buf); } +} + +static GstFlowReturn +gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf, + GstBuffer ** outbuf) +{ + GstFlowReturn ret = GST_FLOW_OK; + GstIdentity *identity = GST_IDENTITY (trans); + guint i; + + if (identity->check_perfect) + gst_identity_check_perfect (identity, inbuf); if (identity->error_after >= 0) { identity->error_after--; if (identity->error_after == 0) { - gst_buffer_unref (buf); GST_ELEMENT_ERROR (identity, CORE, FAILED, (_("Failed after iterations as requested.")), (NULL)); return GST_FLOW_ERROR; @@ -543,18 +291,18 @@ gst_identity_handle_buffer (GstIdentity * identity, GstBuffer * buf) g_strdup_printf ("dropping ******* (%s:%s)i (%d bytes, timestamp: %" GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %" G_GINT64_FORMAT ", offset_end: % " G_GINT64_FORMAT ", flags: %d) %p", - GST_DEBUG_PAD_NAME (identity->sinkpad), GST_BUFFER_SIZE (buf), - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), - GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf), - GST_BUFFER_OFFSET_END (buf), GST_BUFFER_FLAGS (buf), buf); + GST_DEBUG_PAD_NAME (trans->sinkpad), GST_BUFFER_SIZE (inbuf), + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)), + GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf)), + GST_BUFFER_OFFSET (inbuf), GST_BUFFER_OFFSET_END (inbuf), + GST_BUFFER_FLAGS (inbuf), inbuf); g_object_notify (G_OBJECT (identity), "last-message"); - gst_buffer_unref (buf); return GST_FLOW_OK; } } if (identity->dump) { - gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); + gst_util_dump_mem (GST_BUFFER_DATA (inbuf), GST_BUFFER_SIZE (inbuf)); } for (i = identity->duplicate; i; i--) { @@ -566,76 +314,48 @@ gst_identity_handle_buffer (GstIdentity * identity, GstBuffer * buf) g_strdup_printf ("chain ******* (%s:%s)i (%d bytes, timestamp: %" GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %" G_GINT64_FORMAT ", offset_end: % " G_GINT64_FORMAT ", flags: %d) %p", - GST_DEBUG_PAD_NAME (identity->sinkpad), GST_BUFFER_SIZE (buf), - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), - GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf), - GST_BUFFER_OFFSET_END (buf), GST_BUFFER_FLAGS (buf), buf); + GST_DEBUG_PAD_NAME (trans->sinkpad), GST_BUFFER_SIZE (inbuf), + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)), + GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf)), + GST_BUFFER_OFFSET (inbuf), GST_BUFFER_OFFSET_END (inbuf), + GST_BUFFER_FLAGS (inbuf), inbuf); g_object_notify (G_OBJECT (identity), "last-message"); } - time = GST_BUFFER_TIMESTAMP (buf); + time = GST_BUFFER_TIMESTAMP (inbuf); if (identity->datarate > 0) { time = identity->offset * GST_SECOND / identity->datarate; - GST_BUFFER_TIMESTAMP (buf) = time; - GST_BUFFER_DURATION (buf) = - GST_BUFFER_SIZE (buf) * GST_SECOND / identity->datarate; + GST_BUFFER_TIMESTAMP (inbuf) = time; + GST_BUFFER_DURATION (inbuf) = + GST_BUFFER_SIZE (inbuf) * GST_SECOND / identity->datarate; } g_signal_emit (G_OBJECT (identity), gst_identity_signals[SIGNAL_HANDOFF], 0, - buf); + inbuf); if (i > 1) - gst_buffer_ref (buf); + gst_buffer_ref (inbuf); if (identity->sync) { - if (identity->clock) { + if (GST_ELEMENT (identity)->clock) { /* gst_element_wait (GST_ELEMENT (identity), time); */ } } - identity->offset += GST_BUFFER_SIZE (buf); - if (identity->decoupled) { - if (!identity_queue_push (identity, (GstData *) buf)) - return GST_FLOW_UNEXPECTED; - } else { - ret = gst_pad_push (identity->srcpad, buf); - if (ret != GST_FLOW_OK) - return ret; - } + identity->offset += GST_BUFFER_SIZE (inbuf); if (identity->sleep_time) g_usleep (identity->sleep_time); + + gst_buffer_ref (inbuf); + *outbuf = inbuf; } return ret; } -static void -gst_identity_set_dataflow_funcs (GstIdentity * identity) -{ - if (identity->has_getrange) - gst_pad_set_getrange_function (identity->srcpad, gst_identity_getrange); - else - gst_pad_set_getrange_function (identity->srcpad, NULL); - - if (identity->has_chain) - gst_pad_set_chain_function (identity->sinkpad, gst_identity_chain); - else - gst_pad_set_chain_function (identity->sinkpad, NULL); - - if (identity->has_src_loop) - gst_pad_set_loop_function (identity->srcpad, gst_identity_src_loop); - else - gst_pad_set_loop_function (identity->srcpad, NULL); - - if (identity->has_sink_loop) - gst_pad_set_loop_function (identity->sinkpad, gst_identity_sink_loop); - else - gst_pad_set_loop_function (identity->sinkpad, NULL); -} - static void gst_identity_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) @@ -645,22 +365,6 @@ gst_identity_set_property (GObject * object, guint prop_id, identity = GST_IDENTITY (object); switch (prop_id) { - case PROP_HAS_GETRANGE: - identity->has_getrange = g_value_get_boolean (value); - gst_identity_set_dataflow_funcs (identity); - break; - case PROP_HAS_CHAIN: - identity->has_chain = g_value_get_boolean (value); - gst_identity_set_dataflow_funcs (identity); - break; - case PROP_HAS_SRC_LOOP: - identity->has_src_loop = g_value_get_boolean (value); - gst_identity_set_dataflow_funcs (identity); - break; - case PROP_HAS_SINK_LOOP: - identity->has_sink_loop = g_value_get_boolean (value); - gst_identity_set_dataflow_funcs (identity); - break; case PROP_SLEEP_TIME: identity->sleep_time = g_value_get_uint (value); break; @@ -703,18 +407,6 @@ gst_identity_get_property (GObject * object, guint prop_id, GValue * value, identity = GST_IDENTITY (object); switch (prop_id) { - case PROP_HAS_GETRANGE: - g_value_set_boolean (value, identity->has_getrange); - break; - case PROP_HAS_CHAIN: - g_value_set_boolean (value, identity->has_chain); - break; - case PROP_HAS_SRC_LOOP: - g_value_set_boolean (value, identity->has_src_loop); - break; - case PROP_HAS_SINK_LOOP: - g_value_set_boolean (value, identity->has_sink_loop); - break; case PROP_SLEEP_TIME: g_value_set_uint (value, identity->sleep_time); break; @@ -755,12 +447,15 @@ static GstElementStateReturn gst_identity_change_state (GstElement * element) { GstIdentity *identity; + GstElementState transition; + GstElementStateReturn result; g_return_val_if_fail (GST_IS_IDENTITY (element), GST_STATE_FAILURE); identity = GST_IDENTITY (element); + transition = GST_STATE_TRANSITION (element); - switch (GST_STATE_TRANSITION (element)) { + switch (transition) { case GST_STATE_NULL_TO_READY: break; case GST_STATE_READY_TO_PAUSED: @@ -770,6 +465,14 @@ gst_identity_change_state (GstElement * element) identity->prev_offset_end = -1; break; case GST_STATE_PAUSED_TO_PLAYING: + break; + default: + break; + } + + result = GST_ELEMENT_CLASS (parent_class)->change_state (element); + + switch (transition) { case GST_STATE_PLAYING_TO_PAUSED: break; case GST_STATE_PAUSED_TO_READY: @@ -782,8 +485,5 @@ gst_identity_change_state (GstElement * element) break; } - if (GST_ELEMENT_CLASS (parent_class)->change_state) - return GST_ELEMENT_CLASS (parent_class)->change_state (element); - - return GST_STATE_SUCCESS; + return result; } diff --git a/gst/elements/gstidentity.h b/gst/elements/gstidentity.h index e187f2e2c2..4a51a070b4 100644 --- a/gst/elements/gstidentity.h +++ b/gst/elements/gstidentity.h @@ -26,6 +26,7 @@ #include +#include G_BEGIN_DECLS @@ -45,24 +46,8 @@ typedef struct _GstIdentity GstIdentity; typedef struct _GstIdentityClass GstIdentityClass; struct _GstIdentity { - GstElement element; + GstBaseTransform element; - GstPad *sinkpad; - GstPad *srcpad; - - GstData *pen_data; - GMutex *pen_lock; - GCond *pen_cond; - gboolean pen_flushing; - - gboolean has_chain; - gboolean has_getrange; - gboolean has_src_loop; - gboolean has_sink_loop; - GstActivateMode sink_mode; - GstActivateMode src_mode; - gboolean decoupled; - guint duplicate; gint error_after; gfloat drop_probability; @@ -75,15 +60,12 @@ struct _GstIdentity { GstClockTime prev_timestamp; GstClockTime prev_duration; guint64 prev_offset_end; - GstClock *clock; gchar *last_message; - GstCaps *srccaps; - - guint64 offset; + guint64 offset; }; struct _GstIdentityClass { - GstElementClass parent_class; + GstBaseTransformClass parent_class; /* signals */ void (*handoff) (GstElement *element, GstBuffer *buf); diff --git a/gst/gstelement.c b/gst/gstelement.c index 6eaecf1e22..287e7a534e 100644 --- a/gst/gstelement.c +++ b/gst/gstelement.c @@ -1983,7 +1983,7 @@ restart: if (GST_IS_REAL_PAD (pad)) { GstRealPad *peer; gboolean pad_loop, pad_get; - gboolean delay = FALSE; + gboolean done = FALSE; /* see if the pad has a loop function and grab * the peer */ @@ -2003,38 +2003,24 @@ restart: /* see if the peer has a loop function */ peer_loop = GST_RPAD_LOOPFUNC (peer) != NULL; - /* sinkpads with a loop function are delayed since they - * need the srcpad to be active first */ - if (GST_PAD_IS_SINK (pad) && pad_loop && peer_get) { + /* If the pad is a sink with loop and the peer has a get function, + * we can activate the sinkpad */ + if ((GST_PAD_IS_SINK (pad) && pad_loop && peer_get) || + (GST_PAD_IS_SRC (pad) && peer_loop && pad_get)) { GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, - "delaying pad %s", GST_OBJECT_NAME (pad)); - delay = TRUE; - } else if (GST_PAD_IS_SRC (pad) && peer_loop && pad_get) { - /* If the pad is a source and the peer has a loop function, - * we can activate the srcpad and then the loopbased sinkpad */ - GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, - "%sactivating pad %s", (active ? "" : "(de)"), + "%sactivating pad %s pull mode", (active ? "" : "(de)"), GST_OBJECT_NAME (pad)); result &= gst_pad_set_active (pad, (active ? GST_ACTIVATE_PULL : GST_ACTIVATE_NONE)); - - GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, - "%sactivating delayed pad %s", (active ? "" : "(de)"), - GST_OBJECT_NAME (peer)); - result &= gst_pad_set_active (GST_PAD (peer), - (active ? GST_ACTIVATE_PULL : GST_ACTIVATE_NONE)); - - /* set flag here since we don't want the code below to activate - * the pad again */ - delay = TRUE; + done = TRUE; } gst_object_unref (GST_OBJECT (peer)); } - /* all other conditions are just push based pads */ - if (!delay) { + if (!done) { + /* all other conditions are just push based pads */ GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, - "%sactivating pad %s", (active ? "" : "(de)"), + "%sactivating pad %s push mode", (active ? "" : "(de)"), GST_OBJECT_NAME (pad)); result &= gst_pad_set_active (pad, diff --git a/gst/gstpad.c b/gst/gstpad.c index 72ffefaaf5..35fe793843 100644 --- a/gst/gstpad.c +++ b/gst/gstpad.c @@ -437,9 +437,15 @@ lost_ghostpad: /** * gst_pad_set_active: * @pad: the #GstPad to activate or deactivate. - * @active: TRUE to activate the pad. + * @mode: the mode of the pad. * - * Activates or deactivates the given pad. + * Activates or deactivates the given pad in the given mode. + * + * For a source pad: PULL mode will call the getrange function, + * PUSH mode will require the element to call _push() on the pad. + * + * For a sink pad: PULL mode will require the element to call + * the _pull_range() function, PUSH mode will call the chain function. * * Returns: TRUE if the operation was successfull. * @@ -457,13 +463,12 @@ gst_pad_set_active (GstPad * pad, GstActivateMode mode) GST_PAD_REALIZE_AND_LOCK (pad, realpad, lost_ghostpad); - active = (mode != GST_ACTIVATE_NONE); - + active = GST_PAD_MODE_ACTIVATE (mode); old = GST_PAD_IS_ACTIVE (realpad); /* if nothing changed, we can just exit */ if (G_UNLIKELY (old == active)) - goto exit; + goto was_ok; /* make sure data is disallowed when going inactive */ if (!active) { @@ -475,14 +480,16 @@ gst_pad_set_active (GstPad * pad, GstActivateMode mode) } if (active) { - if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC) { + if (GST_RPAD_DIRECTION (realpad) == GST_PAD_SRC) { if (mode == GST_ACTIVATE_PULL) { if (!realpad->getrangefunc) goto wrong_mode; } else { - /* we can push if driven by a chain or loop on the sink pad */ + /* we can push if driven by a chain or loop on the sink pad. + * peer pad is assumed to be active now. */ } - } else { /* sink pads */ + } else { + /* sink pads */ if (mode == GST_ACTIVATE_PULL) { /* the src can drive us with getrange */ } else { @@ -509,18 +516,23 @@ gst_pad_set_active (GstPad * pad, GstActivateMode mode) goto activate_error; } - /* when going to active alow data passing now */ + /* when going to active allow data passing now */ if (active) { - GST_CAT_DEBUG (GST_CAT_PADS, "activating pad %s:%s", - GST_DEBUG_PAD_NAME (realpad)); + GST_CAT_DEBUG (GST_CAT_PADS, "activating pad %s:%s in mode %d", + GST_DEBUG_PAD_NAME (realpad), mode); GST_FLAG_SET (realpad, GST_PAD_ACTIVE); } - -exit: GST_UNLOCK (realpad); return TRUE; +was_ok: + { + GST_CAT_DEBUG (GST_CAT_PADS, + "pad %s:%s was active", GST_DEBUG_PAD_NAME (realpad)); + GST_UNLOCK (realpad); + return TRUE; + } /* errors */ lost_ghostpad: { @@ -544,6 +556,42 @@ activate_error: } } +/** + * gst_pad_peer_set_active: + * @pad: the #GstPad to activate or deactivate the peer of. + * @mode: the mode of the pad. + * + * Activates or deactivates the given peer of a pad. Elements + * that will perform a _pull_range() on their sinkpads need + * to call this function when the sinkpad is activated or when + * an internally linked source pad is activated in pull mode. + * + * Returns: TRUE if the operation was successfull. + * + * MT safe. + */ +gboolean +gst_pad_peer_set_active (GstPad * pad, GstActivateMode mode) +{ + GstPad *peer; + gboolean result = FALSE; + + peer = gst_pad_get_peer (pad); + if (!peer) + goto no_peer; + + result = gst_pad_set_active (peer, mode); + gst_object_unref (GST_OBJECT_CAST (peer)); + + return result; + + /* errors */ +no_peer: + { + return FALSE; + } +} + /** * gst_pad_is_active: * @pad: the #GstPad to query @@ -2909,6 +2957,74 @@ no_function: } } + +/** + * gst_pad_check_pull_range: + * @pad: a sink #GstRealPad. + * + * Checks if a #gst_pad_pull_range() can be performed on the peer + * source pad. This function is used by plugins that want to check + * if they can use random access on the peer source pad. + * + * The peer sourcepad can implement a custom #GstPadCheckGetRangeFunction + * if it needs to perform some logic to determine if pull_range is + * possible. + * + * Returns: a gboolean with the result. + * + * MT safe. + */ +gboolean +gst_pad_check_pull_range (GstPad * pad) +{ + GstRealPad *peer; + gboolean ret; + GstPadCheckGetRangeFunction checkgetrangefunc; + + g_return_val_if_fail (GST_IS_REAL_PAD (pad), GST_FLOW_ERROR); + g_return_val_if_fail (GST_RPAD_DIRECTION (pad) == GST_PAD_SINK, + GST_FLOW_ERROR); + + GST_LOCK (pad); + + if (G_UNLIKELY ((peer = GST_RPAD_PEER (pad)) == NULL)) + goto not_connected; + + gst_object_ref (GST_OBJECT_CAST (peer)); + GST_UNLOCK (pad); + + /* see note in above function */ + if (G_UNLIKELY ((checkgetrangefunc = peer->checkgetrangefunc) == NULL)) + goto no_function; + + GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, + "calling checkgetrangefunc %s of peer pad %s:%s", + GST_DEBUG_FUNCPTR_NAME (checkgetrangefunc), GST_DEBUG_PAD_NAME (peer)); + + ret = checkgetrangefunc (GST_PAD_CAST (peer)); + + gst_object_unref (GST_OBJECT_CAST (peer)); + + return ret; + + /* ERROR recovery here */ +not_connected: + { + GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, + "checkinh pull range, but it was not linked"); + GST_UNLOCK (pad); + return FALSE; + } +no_function: + { + GST_ELEMENT_ERROR (GST_PAD_PARENT (pad), CORE, PAD, (NULL), + ("pad %s:%s checked pull_range but the peer pad %s:%s has no checkgetrangefunction", + GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (peer))); + gst_object_unref (GST_OBJECT (peer)); + return FALSE; + } +} + /** * gst_pad_pull_range: * @pad: a sink #GstPad. @@ -2943,6 +3059,12 @@ gst_pad_pull_range (GstPad * pad, guint64 offset, guint size, if (G_UNLIKELY ((peer = GST_RPAD_PEER (pad)) == NULL)) goto not_connected; + if (G_UNLIKELY (!GST_RPAD_IS_ACTIVE (peer))) + goto not_active; + + if (G_UNLIKELY (GST_RPAD_IS_FLUSHING (peer))) + goto flushing; + gst_object_ref (GST_OBJECT_CAST (peer)); GST_UNLOCK (pad); @@ -2951,8 +3073,10 @@ gst_pad_pull_range (GstPad * pad, guint64 offset, guint size, goto no_function; GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, - "calling getrangefunc %s of peer pad %s:%s", - GST_DEBUG_FUNCPTR_NAME (getrangefunc), GST_DEBUG_PAD_NAME (peer)); + "calling getrangefunc %s of peer pad %s:%s, offset %" + G_GUINT64_FORMAT ", size %u", + GST_DEBUG_FUNCPTR_NAME (getrangefunc), GST_DEBUG_PAD_NAME (peer), + offset, size); ret = getrangefunc (GST_PAD_CAST (peer), offset, size, buffer); @@ -2968,6 +3092,20 @@ not_connected: GST_UNLOCK (pad); return GST_FLOW_NOT_CONNECTED; } +not_active: + { + GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, + "pulling range, but it was inactive"); + GST_UNLOCK (pad); + return GST_FLOW_WRONG_STATE; + } +flushing: + { + GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, + "pulling range, but pad was flushing"); + GST_UNLOCK (pad); + return GST_FLOW_UNEXPECTED; + } no_function: { GST_ELEMENT_ERROR (GST_PAD_PARENT (pad), CORE, PAD, (NULL), @@ -3163,9 +3301,9 @@ gst_pad_template_new (const gchar * name_template, * Gets the capabilities of the pad template. * * Returns: the #GstCaps of the pad template. If you need to keep a reference to - * the caps, make a copy (see gst_caps_copy ()). + * the caps, take a ref (see gst_caps_ref ()). */ -const GstCaps * +GstCaps * gst_pad_template_get_caps (GstPadTemplate * templ) { g_return_val_if_fail (GST_IS_PAD_TEMPLATE (templ), NULL); @@ -3354,6 +3492,8 @@ gst_ghost_pad_new (const gchar * name, GstPad * pad) * The caller must free this list after use. * * Returns: a newly allocated #GList of pads. + * + * Not MT safe. */ GList * gst_pad_get_internal_links_default (GstPad * pad) @@ -3394,6 +3534,8 @@ gst_pad_get_internal_links_default (GstPad * pad) * The caller must free this list after use. * * Returns: a newly allocated #GList of pads. + * + * Not MT safe. */ GList * gst_pad_get_internal_links (GstPad * pad) diff --git a/gst/gstpad.h b/gst/gstpad.h index fc28d5d786..7cfd561d3c 100644 --- a/gst/gstpad.h +++ b/gst/gstpad.h @@ -96,8 +96,8 @@ typedef enum { GST_PAD_LINK_OK = 0, /* link ok */ } GstPadLinkReturn; -#define GST_PAD_LINK_FAILED(ret) (ret < GST_PAD_LINK_OK) -#define GST_PAD_LINK_SUCCESSFUL(ret) (ret >= GST_PAD_LINK_OK) +#define GST_PAD_LINK_FAILED(ret) ((ret) < GST_PAD_LINK_OK) +#define GST_PAD_LINK_SUCCESSFUL(ret) ((ret) >= GST_PAD_LINK_OK) typedef enum { GST_FLOW_OK = 0, /* data passing was ok */ @@ -116,6 +116,8 @@ typedef enum { GST_ACTIVATE_PULL, } GstActivateMode; +#define GST_PAD_MODE_ACTIVATE(mode) ((mode) != GST_ACTIVATE_NONE) + /* convenience functions */ #ifdef G_HAVE_ISO_VARARGS #define GST_PAD_QUERY_TYPE_FUNCTION(functionname, ...) GST_QUERY_TYPE_FUNCTION (GstPad *, functionname, __VA_ARGS__); @@ -136,6 +138,7 @@ typedef void (*GstPadLoopFunction) (GstPad *pad); typedef GstFlowReturn (*GstPadChainFunction) (GstPad *pad, GstBuffer *buffer); typedef GstFlowReturn (*GstPadGetRangeFunction) (GstPad *pad, guint64 offset, guint length, GstBuffer **buffer); +typedef gboolean (*GstPadCheckGetRangeFunction) (GstPad *pad); typedef gboolean (*GstPadEventFunction) (GstPad *pad, GstEvent *event); /* convert/query/format functions */ @@ -237,6 +240,7 @@ struct _GstRealPad { /* data transport functions */ GstPadLoopFunction loopfunc; GstPadChainFunction chainfunc; + GstPadCheckGetRangeFunction checkgetrangefunc; GstPadGetRangeFunction getrangefunc; GstPadEventFunction eventfunc; @@ -301,6 +305,7 @@ struct _GstGhostPadClass { #define GST_RPAD_ACTIVATEFUNC(pad) (GST_REAL_PAD_CAST(pad)->activatefunc) #define GST_RPAD_LOOPFUNC(pad) (GST_REAL_PAD_CAST(pad)->loopfunc) #define GST_RPAD_CHAINFUNC(pad) (GST_REAL_PAD_CAST(pad)->chainfunc) +#define GST_RPAD_CHECKGETRANGEFUNC(pad) (GST_REAL_PAD_CAST(pad)->checkgetrangefunc) #define GST_RPAD_GETRANGEFUNC(pad) (GST_REAL_PAD_CAST(pad)->getrangefunc) #define GST_RPAD_EVENTFUNC(pad) (GST_REAL_PAD_CAST(pad)->eventfunc) #define GST_RPAD_CONVERTFUNC(pad) (GST_REAL_PAD_CAST(pad)->convertfunc) @@ -458,6 +463,7 @@ GstElement* gst_pad_get_real_parent (GstPad *pad); GstPadDirection gst_pad_get_direction (GstPad *pad); gboolean gst_pad_set_active (GstPad *pad, GstActivateMode mode); +gboolean gst_pad_peer_set_active (GstPad *pad, GstActivateMode mode); gboolean gst_pad_is_active (GstPad *pad); gboolean gst_pad_set_blocked (GstPad *pad, gboolean blocked); gboolean gst_pad_set_blocked_async (GstPad *pad, gboolean blocked, @@ -524,6 +530,7 @@ GstCaps * gst_pad_get_filter_caps (GstPad * pad); /* data passing functions */ GstFlowReturn gst_pad_push (GstPad *pad, GstBuffer *buffer); +gboolean gst_pad_check_pull_range (GstPad *pad); GstFlowReturn gst_pad_pull_range (GstPad *pad, guint64 offset, guint size, GstBuffer **buffer); gboolean gst_pad_push_event (GstPad *pad, GstEvent *event); @@ -593,7 +600,7 @@ GstPadTemplate* gst_pad_template_new (const gchar *name_template, GstCaps *caps); GstPadTemplate * gst_static_pad_template_get (GstStaticPadTemplate *pad_template); -const GstCaps* gst_pad_template_get_caps (GstPadTemplate *templ); +GstCaps* gst_pad_template_get_caps (GstPadTemplate *templ); #ifndef GST_DISABLE_LOADSAVE xmlNodePtr gst_ghost_pad_save_thyself (GstPad *pad, diff --git a/libs/gst/base/Makefile.am b/libs/gst/base/Makefile.am index 8ba1b85d56..dda7031d9a 100644 --- a/libs/gst/base/Makefile.am +++ b/libs/gst/base/Makefile.am @@ -6,7 +6,8 @@ noinst_DATA = $(as_libtool_noinst_DATA_files) libgstbase_@GST_MAJORMINOR@_la_DEPENDENCIES = ../libgstreamer-@GST_MAJORMINOR@.la libgstbase_@GST_MAJORMINOR@_la_SOURCES = \ - gstbasesink.c + gstbasesink.c \ + gstbasetransform.c libgstbase_@GST_MAJORMINOR@_la_CFLAGS = $(GST_OBJ_CFLAGS) libgstbase_@GST_MAJORMINOR@_la_LIBADD = $(GST_OBJ_LIBS) @@ -16,7 +17,8 @@ libgstbase_@GST_MAJORMINOR@includedir = \ $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/base libgstbase_@GST_MAJORMINOR@include_HEADERS = \ - gstbasesink.h + gstbasesink.h \ + gstbasetransform.h install-data-local: as-libtool-install-data-local diff --git a/libs/gst/base/README b/libs/gst/base/README index efd6e572a9..f9c158376d 100644 --- a/libs/gst/base/README +++ b/libs/gst/base/README @@ -14,3 +14,14 @@ GstBaseSink FIXME: not much point making it operate in pull mode as a generic base class I guess... + +GstBaseTransform + + Base class for simple tranform filters + + - one sinkpad and one srcpad + - formats the same on sink and source pad. + - handles state changes + - does flushing + - push mode + - pull mode if transform can operate on arbitrary data diff --git a/libs/gst/base/gstbasesink.c b/libs/gst/base/gstbasesink.c index a476071fd3..88d7d97816 100644 --- a/libs/gst/base/gstbasesink.c +++ b/libs/gst/base/gstbasesink.c @@ -26,11 +26,6 @@ #include "gstbasesink.h" #include -static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS_ANY); - GST_DEBUG_CATEGORY_STATIC (gst_basesink_debug); #define GST_CAT_DEFAULT gst_basesink_debug @@ -61,11 +56,35 @@ enum PROP_PREROLL_QUEUE_LEN }; -#define _do_init(bla) \ - GST_DEBUG_CATEGORY_INIT (gst_basesink_debug, "basesink", 0, "basesink element"); +static GstElementClass *parent_class = NULL; -GST_BOILERPLATE_FULL (GstBaseSink, gst_basesink, GstElement, GST_TYPE_ELEMENT, - _do_init); +static void gst_basesink_base_init (gpointer g_class); +static void gst_basesink_class_init (GstBaseSinkClass * klass); +static void gst_basesink_init (GstBaseSink * trans, gpointer g_class); + +GType +gst_basesink_get_type (void) +{ + static GType basesink_type = 0; + + if (!basesink_type) { + static const GTypeInfo basesink_info = { + sizeof (GstBaseSinkClass), + (GBaseInitFunc) gst_basesink_base_init, + NULL, + (GClassInitFunc) gst_basesink_class_init, + NULL, + NULL, + sizeof (GstBaseSink), + 0, + (GInstanceInitFunc) gst_basesink_init, + }; + + basesink_type = g_type_register_static (GST_TYPE_ELEMENT, + "GstBaseSink", &basesink_info, G_TYPE_FLAG_ABSTRACT); + } + return basesink_type; +} static void gst_basesink_set_clock (GstElement * element, GstClock * clock); @@ -74,7 +93,6 @@ static void gst_basesink_set_property (GObject * object, guint prop_id, static void gst_basesink_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -static GstStaticPadTemplate *gst_base_sink_get_template (GstBaseSink * sink); static GstCaps *gst_base_sink_get_caps (GstBaseSink * sink); static gboolean gst_base_sink_set_caps (GstBaseSink * sink, GstCaps * caps); static GstBuffer *gst_base_sink_buffer_alloc (GstBaseSink * sink, @@ -93,32 +111,11 @@ static gboolean gst_basesink_event (GstPad * pad, GstEvent * event); static inline void gst_basesink_handle_buffer (GstBaseSink * basesink, GstBuffer * buf); -static GstStaticPadTemplate * -gst_basesink_get_template (GstBaseSink * bsink) -{ - GstStaticPadTemplate *template = NULL; - GstBaseSinkClass *bclass; - - bclass = GST_BASESINK_GET_CLASS (bsink); - - if (bclass->get_template) - template = bclass->get_template (bsink); - - if (template == NULL) { - template = &sinktemplate; - } - return template; -} - static void gst_basesink_base_init (gpointer g_class) { - //GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); - - /* - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&sinktemplate)); - */ + GST_DEBUG_CATEGORY_INIT (gst_basesink_debug, "basesink", 0, + "basesink element"); } static void @@ -130,6 +127,8 @@ gst_basesink_class_init (GstBaseSinkClass * klass) gobject_class = (GObjectClass *) klass; gstelement_class = (GstElementClass *) klass; + parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_basesink_set_property); gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_basesink_get_property); @@ -153,7 +152,6 @@ gst_basesink_class_init (GstBaseSinkClass * klass) klass->get_caps = GST_DEBUG_FUNCPTR (gst_base_sink_get_caps); klass->set_caps = GST_DEBUG_FUNCPTR (gst_base_sink_set_caps); - klass->get_template = GST_DEBUG_FUNCPTR (gst_base_sink_get_template); klass->buffer_alloc = GST_DEBUG_FUNCPTR (gst_base_sink_buffer_alloc); klass->get_times = GST_DEBUG_FUNCPTR (gst_basesink_get_times); } @@ -171,13 +169,15 @@ gst_basesink_pad_getcaps (GstPad * pad) caps = bclass->get_caps (bsink); if (caps == NULL) { - GstStaticPadTemplate *stemplate; - GstPadTemplate *template; + GstPadTemplate *pad_template; - stemplate = gst_basesink_get_template (bsink); - template = gst_static_pad_template_get (stemplate); - caps = gst_caps_copy (gst_pad_template_get_caps (template)); + pad_template = + gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "sink"); + if (pad_template != NULL) { + caps = gst_caps_ref (gst_pad_template_get_caps (pad_template)); + } } + return caps; } @@ -213,15 +213,16 @@ gst_basesink_pad_buffer_alloc (GstPad * pad, guint64 offset, guint size, } static void -gst_basesink_init (GstBaseSink * basesink) +gst_basesink_init (GstBaseSink * basesink, gpointer g_class) { - GstStaticPadTemplate *template; + GstPadTemplate *pad_template; - template = gst_basesink_get_template (basesink); + pad_template = + gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "sink"); + g_return_if_fail (pad_template != NULL); + + basesink->sinkpad = gst_pad_new_from_template (pad_template, "sink"); - basesink->sinkpad = - gst_pad_new_from_template (gst_static_pad_template_get (template), - "sink"); gst_pad_set_getcaps_function (basesink->sinkpad, GST_DEBUG_FUNCPTR (gst_basesink_pad_getcaps)); gst_pad_set_setcaps_function (basesink->sinkpad, @@ -328,12 +329,6 @@ gst_basesink_get_property (GObject * object, guint prop_id, GValue * value, GST_UNLOCK (sink); } -static GstStaticPadTemplate * -gst_base_sink_get_template (GstBaseSink * sink) -{ - return &sinktemplate; -} - static GstCaps * gst_base_sink_get_caps (GstBaseSink * sink) { @@ -735,6 +730,7 @@ gst_basesink_activate (GstPad * pad, GstActivateMode mode) case GST_ACTIVATE_PULL: /* if we have a scheduler we can start the task */ g_return_val_if_fail (basesink->has_loop, FALSE); + gst_pad_peer_set_active (pad, mode); if (GST_ELEMENT_SCHEDULER (basesink)) { GST_STREAM_LOCK (pad); GST_RPAD_TASK (pad) = @@ -791,7 +787,7 @@ gst_basesink_change_state (GstElement * element) break; case GST_STATE_READY_TO_PAUSED: /* need to complete preroll before this state change completes, there - * is no data flow in READY so we cqn safely assume we need to preroll. */ + * is no data flow in READY so we can safely assume we need to preroll. */ basesink->offset = 0; GST_PREROLL_LOCK (basesink->sinkpad); basesink->preroll_queue = g_queue_new (); diff --git a/libs/gst/base/gstbasesink.h b/libs/gst/base/gstbasesink.h index 3c64f78ed3..b3eafade44 100644 --- a/libs/gst/base/gstbasesink.h +++ b/libs/gst/base/gstbasesink.h @@ -66,8 +66,6 @@ struct _GstBaseSink { struct _GstBaseSinkClass { GstElementClass parent_class; - GstStaticPadTemplate* (*get_template) (GstBaseSink *sink); - GstCaps* (*get_caps) (GstBaseSink *sink); gboolean (*set_caps) (GstBaseSink *sink, GstCaps *caps); diff --git a/libs/gst/base/gstbasetransform.c b/libs/gst/base/gstbasetransform.c new file mode 100644 index 0000000000..c6032d6964 --- /dev/null +++ b/libs/gst/base/gstbasetransform.c @@ -0,0 +1,404 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * 2005 Wim Taymans + * + * gstbasetransform.c: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#include + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "../gst-i18n-lib.h" +#include "gstbasetransform.h" +#include + +GST_DEBUG_CATEGORY_STATIC (gst_base_transform_debug); +#define GST_CAT_DEFAULT gst_base_transform_debug + +/* BaseTransform signals and args */ +enum +{ + SIGNAL_HANDOFF, + /* FILL ME */ + LAST_SIGNAL +}; + +enum +{ + PROP_0, +}; + +static GstElementClass *parent_class = NULL; + +static void gst_base_transform_base_init (gpointer g_class); +static void gst_base_transform_class_init (GstBaseTransformClass * klass); +static void gst_base_transform_init (GstBaseTransform * trans, + gpointer g_class); + +GType +gst_base_transform_get_type (void) +{ + static GType base_transform_type = 0; + + if (!base_transform_type) { + static const GTypeInfo base_transform_info = { + sizeof (GstBaseTransformClass), + (GBaseInitFunc) gst_base_transform_base_init, + NULL, + (GClassInitFunc) gst_base_transform_class_init, + NULL, + NULL, + sizeof (GstBaseTransform), + 0, + (GInstanceInitFunc) gst_base_transform_init, + }; + + base_transform_type = g_type_register_static (GST_TYPE_ELEMENT, + "GstBaseTransform", &base_transform_info, G_TYPE_FLAG_ABSTRACT); + } + return base_transform_type; +} + +static void gst_base_transform_finalize (GObject * object); +static void gst_base_transform_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_base_transform_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static gboolean gst_base_transform_src_activate (GstPad * pad, + GstActivateMode mode); +static gboolean gst_base_transform_sink_activate (GstPad * pad, + GstActivateMode mode); +static GstElementStateReturn gst_base_transform_change_state (GstElement * + element); + +static gboolean gst_base_transform_event (GstPad * pad, GstEvent * event); +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_proxy_getcaps (GstPad * pad); +static gboolean gst_base_transform_setcaps (GstPad * pad, GstCaps * caps); + +/* static guint gst_base_transform_signals[LAST_SIGNAL] = { 0 }; */ + +static void +gst_base_transform_base_init (gpointer g_class) +{ + GST_DEBUG_CATEGORY_INIT (gst_base_transform_debug, "basetransform", 0, + "basetransform element"); +} + +static void +gst_base_transform_finalize (GObject * object) +{ + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_base_transform_class_init (GstBaseTransformClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = G_OBJECT_CLASS (klass); + gstelement_class = GST_ELEMENT_CLASS (klass); + + parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + + gobject_class->set_property = + GST_DEBUG_FUNCPTR (gst_base_transform_set_property); + gobject_class->get_property = + GST_DEBUG_FUNCPTR (gst_base_transform_get_property); + + gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_base_transform_finalize); + + gstelement_class->change_state = + GST_DEBUG_FUNCPTR (gst_base_transform_change_state); +} + +static void +gst_base_transform_init (GstBaseTransform * trans, gpointer g_class) +{ + GstPadTemplate *pad_template; + + GST_DEBUG ("gst_base_transform_init"); + + pad_template = + gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "sink"); + g_return_if_fail (pad_template != NULL); + trans->sinkpad = gst_pad_new_from_template (pad_template, "sink"); + gst_pad_set_getcaps_function (trans->sinkpad, + GST_DEBUG_FUNCPTR (gst_base_transform_proxy_getcaps)); + gst_pad_set_setcaps_function (trans->sinkpad, + GST_DEBUG_FUNCPTR (gst_base_transform_setcaps)); + gst_pad_set_event_function (trans->sinkpad, + GST_DEBUG_FUNCPTR (gst_base_transform_event)); + gst_pad_set_chain_function (trans->sinkpad, + GST_DEBUG_FUNCPTR (gst_base_transform_chain)); + gst_pad_set_activate_function (trans->sinkpad, + GST_DEBUG_FUNCPTR (gst_base_transform_sink_activate)); + gst_element_add_pad (GST_ELEMENT (trans), trans->sinkpad); + + pad_template = + gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src"); + g_return_if_fail (pad_template != NULL); + trans->srcpad = gst_pad_new_from_template (pad_template, "src"); + gst_pad_set_getcaps_function (trans->srcpad, + GST_DEBUG_FUNCPTR (gst_base_transform_proxy_getcaps)); + gst_pad_set_getrange_function (trans->srcpad, + GST_DEBUG_FUNCPTR (gst_base_transform_getrange)); + gst_pad_set_activate_function (trans->srcpad, + GST_DEBUG_FUNCPTR (gst_base_transform_src_activate)); + gst_element_add_pad (GST_ELEMENT (trans), trans->srcpad); +} + +static GstCaps * +gst_base_transform_proxy_getcaps (GstPad * pad) +{ + GstPad *otherpad; + GstBaseTransform *trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad)); + + otherpad = pad == trans->srcpad ? trans->sinkpad : trans->srcpad; + + return gst_pad_peer_get_caps (otherpad); +} + +static gboolean +gst_base_transform_setcaps (GstPad * pad, GstCaps * caps) +{ + GstBaseTransform *trans; + GstBaseTransformClass *bclass; + gboolean result = TRUE; + + trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad)); + bclass = GST_BASE_TRANSFORM_GET_CLASS (trans); + + if (bclass->set_caps) + result = bclass->set_caps (trans, caps); + + return result; +} + +static gboolean +gst_base_transform_event (GstPad * pad, GstEvent * event) +{ + GstBaseTransform *trans; + GstBaseTransformClass *bclass; + gboolean ret = FALSE; + + trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad)); + bclass = GST_BASE_TRANSFORM_GET_CLASS (trans); + + if (bclass->event) + bclass->event (trans, event); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_FLUSH: + if (GST_EVENT_FLUSH_DONE (event)) { + } + GST_STREAM_LOCK (pad); + break; + case GST_EVENT_EOS: + GST_STREAM_LOCK (pad); + break; + default: + break; + } + ret = gst_pad_event_default (pad, event); + GST_STREAM_UNLOCK (pad); + + return ret; +} + +static GstFlowReturn +gst_base_transform_getrange (GstPad * pad, guint64 offset, + guint length, GstBuffer ** buffer) +{ + GstBaseTransform *trans; + GstFlowReturn ret; + GstBuffer *inbuf; + + trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad)); + + GST_STREAM_LOCK (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); + + return ret; +} + +static GstFlowReturn +gst_base_transform_chain (GstPad * pad, GstBuffer * buffer) +{ + GstBaseTransform *trans; + GstFlowReturn ret = GST_FLOW_OK; + GstBuffer *outbuf; + + trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad)); + + GST_STREAM_LOCK (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_buffer_unref (inbuf); + + return ret; +} + +static void +gst_base_transform_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstBaseTransform *trans; + + trans = GST_BASE_TRANSFORM (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_base_transform_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstBaseTransform *trans; + + trans = GST_BASE_TRANSFORM (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static gboolean +gst_base_transform_sink_activate (GstPad * pad, GstActivateMode mode) +{ + gboolean result = FALSE; + GstBaseTransform *trans; + + trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad)); + + switch (mode) { + case GST_ACTIVATE_PUSH: + result = TRUE; + break; + case GST_ACTIVATE_PULL: + result = TRUE; + break; + case GST_ACTIVATE_NONE: + result = TRUE; + break; + } + return result; +} + +static gboolean +gst_base_transform_src_activate (GstPad * pad, GstActivateMode mode) +{ + gboolean result = FALSE; + GstBaseTransform *trans; + + trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad)); + + switch (mode) { + case GST_ACTIVATE_PUSH: + result = TRUE; + break; + case GST_ACTIVATE_PULL: + result = gst_pad_set_active (trans->sinkpad, mode); + result = gst_pad_peer_set_active (trans->sinkpad, mode); + break; + case GST_ACTIVATE_NONE: + result = TRUE; + break; + } + return result; +} + +static GstElementStateReturn +gst_base_transform_change_state (GstElement * element) +{ + GstBaseTransform *trans; + GstElementState transition; + GstElementStateReturn result; + + trans = GST_BASE_TRANSFORM (element); + transition = GST_STATE_TRANSITION (element); + + switch (transition) { + case GST_STATE_NULL_TO_READY: + break; + case GST_STATE_READY_TO_PAUSED: + break; + case GST_STATE_PAUSED_TO_PLAYING: + break; + default: + break; + } + + result = GST_ELEMENT_CLASS (parent_class)->change_state (element); + + switch (transition) { + case GST_STATE_PLAYING_TO_PAUSED: + break; + case GST_STATE_PAUSED_TO_READY: + break; + case GST_STATE_READY_TO_NULL: + break; + default: + break; + } + + return result; +} diff --git a/libs/gst/base/gstbasetransform.h b/libs/gst/base/gstbasetransform.h new file mode 100644 index 0000000000..788fe5350a --- /dev/null +++ b/libs/gst/base/gstbasetransform.h @@ -0,0 +1,67 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2005 Wim Taymans + * + * gstbasetransform.h: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifndef __GST_BASE_TRANSFORM_H__ +#define __GST_BASE_TRANSFORM_H__ + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_BASE_TRANSFORM (gst_base_transform_get_type()) +#define GST_BASE_TRANSFORM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_BASE_TRANSFORM,GstBaseTransform)) +#define GST_BASE_TRANSFORM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_BASE_TRANSFORM,GstBaseTransformClass)) +#define GST_BASE_TRANSFORM_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_BASE_TRANSFORM,GstBaseTransformClass)) +#define GST_IS_BASE_TRANSFORM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_BASE_TRANSFORM)) +#define GST_IS_BASE_TRANSFORM_CLASS(obj)(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_BASE_TRANSFORM)) + +/* the names of the templates for the sink and source pads */ +#define GST_BASE_TRANSFORM_SINK_NAME "sink" +#define GST_BASE_TRANSFORM_SRC_NAME "src" + +typedef struct _GstBaseTransform GstBaseTransform; +typedef struct _GstBaseTransformClass GstBaseTransformClass; + +struct _GstBaseTransform { + GstElement element; + + /* source and sink pads */ + GstPad *sinkpad; + GstPad *srcpad; +}; + +struct _GstBaseTransformClass { + GstElementClass parent_class; + + gboolean (*set_caps) (GstBaseTransform *trans, GstCaps *caps); + + gboolean (*event) (GstBaseTransform *trans, GstEvent *event); + GstFlowReturn (*transform) (GstBaseTransform *trans, GstBuffer *inbuf, GstBuffer **outbuf); +}; + +GType gst_base_transform_get_type(void); + +G_END_DECLS + +#endif /* __GST_BASE_TRANSFORM_H__ */ diff --git a/plugins/elements/gstidentity.c b/plugins/elements/gstidentity.c index 0b8a6d2f7e..76a61f7e12 100644 --- a/plugins/elements/gstidentity.c +++ b/plugins/elements/gstidentity.c @@ -59,7 +59,6 @@ enum LAST_SIGNAL }; -#define DEFAULT_LOOP_BASED FALSE #define DEFAULT_SLEEP_TIME 0 #define DEFAULT_DUPLICATE 1 #define DEFAULT_ERROR_AFTER -1 @@ -73,11 +72,6 @@ enum enum { PROP_0, - PROP_HAS_GETRANGE, - PROP_HAS_CHAIN, - PROP_HAS_SINK_LOOP, - PROP_HAS_SRC_LOOP, - PROP_LOOP_BASED, PROP_SLEEP_TIME, PROP_DUPLICATE, PROP_ERROR_AFTER, @@ -91,14 +85,11 @@ enum }; -typedef GstFlowReturn (*IdentityPushFunc) (GstIdentity *, GstBuffer *); - - #define _do_init(bla) \ GST_DEBUG_CATEGORY_INIT (gst_identity_debug, "identity", 0, "identity element"); -GST_BOILERPLATE_FULL (GstIdentity, gst_identity, GstElement, GST_TYPE_ELEMENT, - _do_init); +GST_BOILERPLATE_FULL (GstIdentity, gst_identity, GstBaseTransform, + GST_TYPE_BASE_TRANSFORM, _do_init); static void gst_identity_finalize (GObject * object); static void gst_identity_set_property (GObject * object, guint prop_id, @@ -107,17 +98,9 @@ static void gst_identity_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); static GstElementStateReturn gst_identity_change_state (GstElement * element); -static gboolean gst_identity_event (GstPad * pad, GstEvent * event); -static GstFlowReturn gst_identity_getrange (GstPad * pad, guint64 offset, - guint length, GstBuffer ** buffer); -static GstFlowReturn gst_identity_chain (GstPad * pad, GstBuffer * buffer); -static void gst_identity_src_loop (GstPad * pad); -static void gst_identity_sink_loop (GstPad * pad); -static GstFlowReturn gst_identity_handle_buffer (GstIdentity * identity, - GstBuffer * buf); -static void gst_identity_set_clock (GstElement * element, GstClock * clock); -static GstCaps *gst_identity_proxy_getcaps (GstPad * pad); - +static gboolean gst_identity_event (GstBaseTransform * trans, GstEvent * event); +static GstFlowReturn gst_identity_transform (GstBaseTransform * trans, + GstBuffer * inbuf, GstBuffer ** outbuf); static guint gst_identity_signals[LAST_SIGNAL] = { 0 }; @@ -140,9 +123,6 @@ gst_identity_finalize (GObject * object) identity = GST_IDENTITY (object); - g_mutex_free (identity->pen_lock); - g_cond_free (identity->pen_cond); - g_free (identity->last_message); G_OBJECT_CLASS (parent_class)->finalize (object); @@ -153,29 +133,15 @@ gst_identity_class_init (GstIdentityClass * klass) { GObjectClass *gobject_class; GstElementClass *gstelement_class; + GstBaseTransformClass *gstbasetrans_class; gobject_class = G_OBJECT_CLASS (klass); gstelement_class = GST_ELEMENT_CLASS (klass); + gstbasetrans_class = GST_BASE_TRANSFORM_CLASS (klass); gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_identity_set_property); gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_identity_get_property); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_GETRANGE, - g_param_spec_boolean ("has-getrange", "Has getrange", - "If the src pad will implement a getrange function", - TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_CHAIN, - g_param_spec_boolean ("has-chain", "Has chain", - "If the sink pad will implement a chain function", - TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_SRC_LOOP, - g_param_spec_boolean ("has-src-loop", "Has src loop", - "If the src pad will implement a loop function", - FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_SINK_LOOP, - g_param_spec_boolean ("has-sink-loop", "Has sink loop", - "If the sink pad will implement a loop function", - FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SLEEP_TIME, g_param_spec_uint ("sleep-time", "Sleep time", "Microseconds to sleep between processing", 0, G_MAXUINT, @@ -220,33 +186,16 @@ gst_identity_class_init (GstIdentityClass * klass) gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_identity_finalize); - gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_identity_set_clock); gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_identity_change_state); + gstbasetrans_class->event = GST_DEBUG_FUNCPTR (gst_identity_event); + gstbasetrans_class->transform = GST_DEBUG_FUNCPTR (gst_identity_transform); } static void gst_identity_init (GstIdentity * identity) { - identity->sinkpad = - gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate), - "sink"); - gst_element_add_pad (GST_ELEMENT (identity), identity->sinkpad); - gst_pad_set_getcaps_function (identity->sinkpad, - GST_DEBUG_FUNCPTR (gst_identity_proxy_getcaps)); - gst_pad_set_event_function (identity->sinkpad, - GST_DEBUG_FUNCPTR (gst_identity_event)); - - identity->srcpad = - gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate), - "src"); - gst_pad_set_getcaps_function (identity->srcpad, - GST_DEBUG_FUNCPTR (gst_identity_proxy_getcaps)); - gst_pad_set_getrange_function (identity->srcpad, - GST_DEBUG_FUNCPTR (gst_identity_getrange)); - gst_element_add_pad (GST_ELEMENT (identity), identity->srcpad); - identity->sleep_time = DEFAULT_SLEEP_TIME; identity->duplicate = DEFAULT_DUPLICATE; identity->error_after = DEFAULT_ERROR_AFTER; @@ -257,279 +206,78 @@ gst_identity_init (GstIdentity * identity) identity->check_perfect = DEFAULT_CHECK_PERFECT; identity->dump = DEFAULT_DUMP; identity->last_message = NULL; - identity->srccaps = NULL; - - identity->pen_data = NULL; - identity->pen_lock = g_mutex_new (); - identity->pen_cond = g_cond_new (); - identity->pen_flushing = FALSE; -} - -static void -gst_identity_set_clock (GstElement * element, GstClock * clock) -{ - GstIdentity *identity = GST_IDENTITY (element); - - gst_object_replace ((GstObject **) & identity->clock, (GstObject *) clock); -} - -static GstCaps * -gst_identity_proxy_getcaps (GstPad * pad) -{ - GstPad *otherpad; - GstIdentity *identity = GST_IDENTITY (GST_OBJECT_PARENT (pad)); - - otherpad = pad == identity->srcpad ? identity->sinkpad : identity->srcpad; - - return gst_pad_peer_get_caps (otherpad); } static gboolean -identity_queue_push (GstIdentity * identity, GstData * data) -{ - gboolean ret; - - g_mutex_lock (identity->pen_lock); - while (identity->pen_data && !identity->pen_flushing) - g_cond_wait (identity->pen_cond, identity->pen_lock); - if (identity->pen_flushing) { - gst_data_unref (identity->pen_data); - identity->pen_data = NULL; - gst_data_unref (data); - ret = FALSE; - } else { - identity->pen_data = data; - ret = TRUE; - } - g_cond_signal (identity->pen_cond); - g_mutex_unlock (identity->pen_lock); - - return ret; -} - -static GstData * -identity_queue_pop (GstIdentity * identity) -{ - GstData *ret; - - g_mutex_lock (identity->pen_lock); - while (!(ret = identity->pen_data) && !identity->pen_flushing) - g_cond_wait (identity->pen_cond, identity->pen_lock); - g_cond_signal (identity->pen_cond); - g_mutex_unlock (identity->pen_lock); - - return ret; -} - -static void -identity_queue_flush (GstIdentity * identity) -{ - g_mutex_lock (identity->pen_lock); - identity->pen_flushing = TRUE; - g_cond_signal (identity->pen_cond); - g_mutex_unlock (identity->pen_lock); -} - -static gboolean -gst_identity_event (GstPad * pad, GstEvent * event) +gst_identity_event (GstBaseTransform * trans, GstEvent * event) { GstIdentity *identity; - gboolean ret; - identity = GST_IDENTITY (GST_PAD_PARENT (pad)); - - GST_STREAM_LOCK (pad); + identity = GST_IDENTITY (trans); if (!identity->silent) { g_free (identity->last_message); identity->last_message = g_strdup_printf ("chain ******* (%s:%s)E (type: %d) %p", - GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE (event), event); + GST_DEBUG_PAD_NAME (trans->sinkpad), GST_EVENT_TYPE (event), event); g_object_notify (G_OBJECT (identity), "last_message"); } - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_FLUSH: - /* forward event */ - gst_pad_event_default (pad, event); - if (GST_EVENT_FLUSH_DONE (event)) { - if (identity->sink_mode == GST_ACTIVATE_PULL) { - /* already have the sink stream lock */ - gst_task_start (GST_RPAD_TASK (identity->sinkpad)); - } - if (identity->src_mode == GST_ACTIVATE_PUSH) { - GST_STREAM_LOCK (identity->srcpad); - gst_task_start (GST_RPAD_TASK (identity->srcpad)); - GST_STREAM_UNLOCK (identity->srcpad); - } - } else { - /* unblock both functions */ - identity_queue_flush (identity); - - } - ret = TRUE; - goto done; - case GST_EVENT_EOS: - if (identity->sink_mode == GST_ACTIVATE_PULL) { - /* already have the sink stream lock */ - gst_task_pause (GST_RPAD_TASK (identity->sinkpad)); - } - break; - default: - break; - } - - if (identity->decoupled) { - ret = identity_queue_push (identity, (GstData *) event); - } else { - ret = gst_pad_push_event (identity->srcpad, event); - } - -done: - GST_STREAM_UNLOCK (pad); - return ret; -} - -static GstFlowReturn -gst_identity_getrange (GstPad * pad, guint64 offset, - guint length, GstBuffer ** buffer) -{ - GstIdentity *identity; - GstFlowReturn ret; - - identity = GST_IDENTITY (GST_PAD_PARENT (pad)); - - GST_STREAM_LOCK (pad); - - ret = gst_pad_pull_range (identity->sinkpad, offset, length, buffer); - - GST_STREAM_UNLOCK (pad); - - return ret; -} - -static GstFlowReturn -gst_identity_chain (GstPad * pad, GstBuffer * buffer) -{ - GstIdentity *identity; - GstFlowReturn ret = GST_FLOW_OK; - - identity = GST_IDENTITY (GST_PAD_PARENT (pad)); - - GST_STREAM_LOCK (pad); - - ret = gst_identity_handle_buffer (identity, buffer); - - GST_STREAM_UNLOCK (pad); - - return ret; -} - -#define DEFAULT_PULL_SIZE 1024 - -static void -gst_identity_sink_loop (GstPad * pad) -{ - GstIdentity *identity; - GstBuffer *buffer; - GstFlowReturn ret; - - identity = GST_IDENTITY (GST_PAD_PARENT (pad)); - - GST_STREAM_LOCK (pad); - - ret = gst_pad_pull_range (pad, identity->offset, DEFAULT_PULL_SIZE, &buffer); - if (ret != GST_FLOW_OK) - goto sink_loop_pause; - - ret = gst_identity_handle_buffer (identity, buffer); - if (ret != GST_FLOW_OK) - goto sink_loop_pause; - - GST_STREAM_UNLOCK (pad); - return; - -sink_loop_pause: - gst_task_pause (GST_RPAD_TASK (identity->sinkpad)); - GST_STREAM_UNLOCK (pad); - return; + return TRUE; } static void -gst_identity_src_loop (GstPad * pad) +gst_identity_check_perfect (GstIdentity * identity, GstBuffer * buf) { - GstIdentity *identity; - GstData *data; - GstFlowReturn ret; + GstClockTime timestamp; - identity = GST_IDENTITY (GST_PAD_PARENT (pad)); - - GST_STREAM_LOCK (pad); - - data = identity_queue_pop (identity); - if (!data) /* we're getting flushed */ - goto src_loop_pause; - - if (GST_IS_EVENT (data)) { - if (GST_EVENT_TYPE (data) == GST_EVENT_EOS) - gst_task_pause (GST_RPAD_TASK (identity->srcpad)); - gst_pad_push_event (identity->srcpad, GST_EVENT (data)); - } else { - ret = gst_pad_push (identity->srcpad, (GstBuffer *) data); - if (ret != GST_FLOW_OK) - goto src_loop_pause; - } - - GST_STREAM_UNLOCK (pad); - return; - -src_loop_pause: - gst_task_pause (GST_RPAD_TASK (identity->srcpad)); - GST_STREAM_UNLOCK (pad); - return; -} - -static GstFlowReturn -gst_identity_handle_buffer (GstIdentity * identity, GstBuffer * buf) -{ - GstFlowReturn ret = GST_FLOW_OK; - guint i; + timestamp = GST_BUFFER_TIMESTAMP (buf); /* see if we need to do perfect stream checking */ /* invalid timestamp drops us out of check. FIXME: maybe warn ? */ - if (identity->check_perfect && - GST_BUFFER_TIMESTAMP (buf) != GST_CLOCK_TIME_NONE) { + if (timestamp != GST_CLOCK_TIME_NONE) { /* check if we had a previous buffer to compare to */ if (identity->prev_timestamp != GST_CLOCK_TIME_NONE) { - if (identity->prev_timestamp + identity->prev_duration != - GST_BUFFER_TIMESTAMP (buf)) { + guint64 offset; + + if (identity->prev_timestamp + identity->prev_duration != timestamp) { GST_WARNING_OBJECT (identity, "Buffer not time-contiguous with previous one: " "prev ts %" GST_TIME_FORMAT ", prev dur %" GST_TIME_FORMAT ", new ts %" GST_TIME_FORMAT, GST_TIME_ARGS (identity->prev_timestamp), - GST_TIME_ARGS (identity->prev_duration), - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); + GST_TIME_ARGS (identity->prev_duration), GST_TIME_ARGS (timestamp)); } - if (identity->prev_offset_end != GST_BUFFER_OFFSET (buf)) { + + offset = GST_BUFFER_OFFSET (buf); + if (identity->prev_offset_end != offset) { GST_WARNING_OBJECT (identity, "Buffer not data-contiguous with previous one: " "prev offset_end %" G_GINT64_FORMAT ", new offset %" - G_GINT64_FORMAT, identity->prev_offset_end, - GST_BUFFER_OFFSET (buf)); + G_GINT64_FORMAT, identity->prev_offset_end, offset); } } /* update prev values */ - identity->prev_timestamp = GST_BUFFER_TIMESTAMP (buf); + identity->prev_timestamp = timestamp; identity->prev_duration = GST_BUFFER_DURATION (buf); identity->prev_offset_end = GST_BUFFER_OFFSET_END (buf); } +} + +static GstFlowReturn +gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf, + GstBuffer ** outbuf) +{ + GstFlowReturn ret = GST_FLOW_OK; + GstIdentity *identity = GST_IDENTITY (trans); + guint i; + + if (identity->check_perfect) + gst_identity_check_perfect (identity, inbuf); if (identity->error_after >= 0) { identity->error_after--; if (identity->error_after == 0) { - gst_buffer_unref (buf); GST_ELEMENT_ERROR (identity, CORE, FAILED, (_("Failed after iterations as requested.")), (NULL)); return GST_FLOW_ERROR; @@ -543,18 +291,18 @@ gst_identity_handle_buffer (GstIdentity * identity, GstBuffer * buf) g_strdup_printf ("dropping ******* (%s:%s)i (%d bytes, timestamp: %" GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %" G_GINT64_FORMAT ", offset_end: % " G_GINT64_FORMAT ", flags: %d) %p", - GST_DEBUG_PAD_NAME (identity->sinkpad), GST_BUFFER_SIZE (buf), - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), - GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf), - GST_BUFFER_OFFSET_END (buf), GST_BUFFER_FLAGS (buf), buf); + GST_DEBUG_PAD_NAME (trans->sinkpad), GST_BUFFER_SIZE (inbuf), + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)), + GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf)), + GST_BUFFER_OFFSET (inbuf), GST_BUFFER_OFFSET_END (inbuf), + GST_BUFFER_FLAGS (inbuf), inbuf); g_object_notify (G_OBJECT (identity), "last-message"); - gst_buffer_unref (buf); return GST_FLOW_OK; } } if (identity->dump) { - gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); + gst_util_dump_mem (GST_BUFFER_DATA (inbuf), GST_BUFFER_SIZE (inbuf)); } for (i = identity->duplicate; i; i--) { @@ -566,76 +314,48 @@ gst_identity_handle_buffer (GstIdentity * identity, GstBuffer * buf) g_strdup_printf ("chain ******* (%s:%s)i (%d bytes, timestamp: %" GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %" G_GINT64_FORMAT ", offset_end: % " G_GINT64_FORMAT ", flags: %d) %p", - GST_DEBUG_PAD_NAME (identity->sinkpad), GST_BUFFER_SIZE (buf), - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), - GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf), - GST_BUFFER_OFFSET_END (buf), GST_BUFFER_FLAGS (buf), buf); + GST_DEBUG_PAD_NAME (trans->sinkpad), GST_BUFFER_SIZE (inbuf), + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)), + GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf)), + GST_BUFFER_OFFSET (inbuf), GST_BUFFER_OFFSET_END (inbuf), + GST_BUFFER_FLAGS (inbuf), inbuf); g_object_notify (G_OBJECT (identity), "last-message"); } - time = GST_BUFFER_TIMESTAMP (buf); + time = GST_BUFFER_TIMESTAMP (inbuf); if (identity->datarate > 0) { time = identity->offset * GST_SECOND / identity->datarate; - GST_BUFFER_TIMESTAMP (buf) = time; - GST_BUFFER_DURATION (buf) = - GST_BUFFER_SIZE (buf) * GST_SECOND / identity->datarate; + GST_BUFFER_TIMESTAMP (inbuf) = time; + GST_BUFFER_DURATION (inbuf) = + GST_BUFFER_SIZE (inbuf) * GST_SECOND / identity->datarate; } g_signal_emit (G_OBJECT (identity), gst_identity_signals[SIGNAL_HANDOFF], 0, - buf); + inbuf); if (i > 1) - gst_buffer_ref (buf); + gst_buffer_ref (inbuf); if (identity->sync) { - if (identity->clock) { + if (GST_ELEMENT (identity)->clock) { /* gst_element_wait (GST_ELEMENT (identity), time); */ } } - identity->offset += GST_BUFFER_SIZE (buf); - if (identity->decoupled) { - if (!identity_queue_push (identity, (GstData *) buf)) - return GST_FLOW_UNEXPECTED; - } else { - ret = gst_pad_push (identity->srcpad, buf); - if (ret != GST_FLOW_OK) - return ret; - } + identity->offset += GST_BUFFER_SIZE (inbuf); if (identity->sleep_time) g_usleep (identity->sleep_time); + + gst_buffer_ref (inbuf); + *outbuf = inbuf; } return ret; } -static void -gst_identity_set_dataflow_funcs (GstIdentity * identity) -{ - if (identity->has_getrange) - gst_pad_set_getrange_function (identity->srcpad, gst_identity_getrange); - else - gst_pad_set_getrange_function (identity->srcpad, NULL); - - if (identity->has_chain) - gst_pad_set_chain_function (identity->sinkpad, gst_identity_chain); - else - gst_pad_set_chain_function (identity->sinkpad, NULL); - - if (identity->has_src_loop) - gst_pad_set_loop_function (identity->srcpad, gst_identity_src_loop); - else - gst_pad_set_loop_function (identity->srcpad, NULL); - - if (identity->has_sink_loop) - gst_pad_set_loop_function (identity->sinkpad, gst_identity_sink_loop); - else - gst_pad_set_loop_function (identity->sinkpad, NULL); -} - static void gst_identity_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) @@ -645,22 +365,6 @@ gst_identity_set_property (GObject * object, guint prop_id, identity = GST_IDENTITY (object); switch (prop_id) { - case PROP_HAS_GETRANGE: - identity->has_getrange = g_value_get_boolean (value); - gst_identity_set_dataflow_funcs (identity); - break; - case PROP_HAS_CHAIN: - identity->has_chain = g_value_get_boolean (value); - gst_identity_set_dataflow_funcs (identity); - break; - case PROP_HAS_SRC_LOOP: - identity->has_src_loop = g_value_get_boolean (value); - gst_identity_set_dataflow_funcs (identity); - break; - case PROP_HAS_SINK_LOOP: - identity->has_sink_loop = g_value_get_boolean (value); - gst_identity_set_dataflow_funcs (identity); - break; case PROP_SLEEP_TIME: identity->sleep_time = g_value_get_uint (value); break; @@ -703,18 +407,6 @@ gst_identity_get_property (GObject * object, guint prop_id, GValue * value, identity = GST_IDENTITY (object); switch (prop_id) { - case PROP_HAS_GETRANGE: - g_value_set_boolean (value, identity->has_getrange); - break; - case PROP_HAS_CHAIN: - g_value_set_boolean (value, identity->has_chain); - break; - case PROP_HAS_SRC_LOOP: - g_value_set_boolean (value, identity->has_src_loop); - break; - case PROP_HAS_SINK_LOOP: - g_value_set_boolean (value, identity->has_sink_loop); - break; case PROP_SLEEP_TIME: g_value_set_uint (value, identity->sleep_time); break; @@ -755,12 +447,15 @@ static GstElementStateReturn gst_identity_change_state (GstElement * element) { GstIdentity *identity; + GstElementState transition; + GstElementStateReturn result; g_return_val_if_fail (GST_IS_IDENTITY (element), GST_STATE_FAILURE); identity = GST_IDENTITY (element); + transition = GST_STATE_TRANSITION (element); - switch (GST_STATE_TRANSITION (element)) { + switch (transition) { case GST_STATE_NULL_TO_READY: break; case GST_STATE_READY_TO_PAUSED: @@ -770,6 +465,14 @@ gst_identity_change_state (GstElement * element) identity->prev_offset_end = -1; break; case GST_STATE_PAUSED_TO_PLAYING: + break; + default: + break; + } + + result = GST_ELEMENT_CLASS (parent_class)->change_state (element); + + switch (transition) { case GST_STATE_PLAYING_TO_PAUSED: break; case GST_STATE_PAUSED_TO_READY: @@ -782,8 +485,5 @@ gst_identity_change_state (GstElement * element) break; } - if (GST_ELEMENT_CLASS (parent_class)->change_state) - return GST_ELEMENT_CLASS (parent_class)->change_state (element); - - return GST_STATE_SUCCESS; + return result; } diff --git a/plugins/elements/gstidentity.h b/plugins/elements/gstidentity.h index e187f2e2c2..4a51a070b4 100644 --- a/plugins/elements/gstidentity.h +++ b/plugins/elements/gstidentity.h @@ -26,6 +26,7 @@ #include +#include G_BEGIN_DECLS @@ -45,24 +46,8 @@ typedef struct _GstIdentity GstIdentity; typedef struct _GstIdentityClass GstIdentityClass; struct _GstIdentity { - GstElement element; + GstBaseTransform element; - GstPad *sinkpad; - GstPad *srcpad; - - GstData *pen_data; - GMutex *pen_lock; - GCond *pen_cond; - gboolean pen_flushing; - - gboolean has_chain; - gboolean has_getrange; - gboolean has_src_loop; - gboolean has_sink_loop; - GstActivateMode sink_mode; - GstActivateMode src_mode; - gboolean decoupled; - guint duplicate; gint error_after; gfloat drop_probability; @@ -75,15 +60,12 @@ struct _GstIdentity { GstClockTime prev_timestamp; GstClockTime prev_duration; guint64 prev_offset_end; - GstClock *clock; gchar *last_message; - GstCaps *srccaps; - - guint64 offset; + guint64 offset; }; struct _GstIdentityClass { - GstElementClass parent_class; + GstBaseTransformClass parent_class; /* signals */ void (*handoff) (GstElement *element, GstBuffer *buf);