+2005-03-29 Wim Taymans <wim@fluendo.com>
+
+ * 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 <wingo@pobox.com>
* docs/libs/gstreamer-libs-overrides.txt:
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)
$(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
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
#include "gstbasesink.h"
#include <gst/gstmarshal.h>
-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
PROP_PREROLL_QUEUE_LEN
};
-#define _do_init(bla) \
- GST_DEBUG_CATEGORY_INIT (gst_basesink_debug, "basesink", 0, "basesink element");
+static GstElementClass *parent_class = NULL;
+
+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,
+ };
-GST_BOILERPLATE_FULL (GstBaseSink, gst_basesink, GstElement, GST_TYPE_ELEMENT,
- _do_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);
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,
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
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);
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);
}
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;
}
}
static void
-gst_basesink_init (GstBaseSink * basesink)
+gst_basesink_init (GstBaseSink * basesink, gpointer g_class)
{
- GstStaticPadTemplate *template;
+ GstPadTemplate *pad_template;
+
+ pad_template =
+ gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "sink");
+ g_return_if_fail (pad_template != NULL);
- template = gst_basesink_get_template (basesink);
+ 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,
GST_UNLOCK (sink);
}
-static GstStaticPadTemplate *
-gst_base_sink_get_template (GstBaseSink * sink)
-{
- return &sinktemplate;
-}
-
static GstCaps *
gst_base_sink_get_caps (GstBaseSink * sink)
{
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) =
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 ();
struct _GstBaseSinkClass {
GstElementClass parent_class;
- GstStaticPadTemplate* (*get_template) (GstBaseSink *sink);
-
GstCaps* (*get_caps) (GstBaseSink *sink);
gboolean (*set_caps) (GstBaseSink *sink, GstCaps *caps);
--- /dev/null
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ * 2000 Wim Taymans <wtay@chello.be>
+ * 2005 Wim Taymans <wim@fluendo.com>
+ *
+ * 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 <stdlib.h>
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "../gst-i18n-lib.h"
+#include "gstbasetransform.h"
+#include <gst/gstmarshal.h>
+
+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;
+}
--- /dev/null
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ * 2005 Wim Taymans <wim@fluendo.com>
+ *
+ * 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 <gst/gst.h>
+
+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__ */
LAST_SIGNAL
};
-#define DEFAULT_LOOP_BASED FALSE
#define DEFAULT_SLEEP_TIME 0
#define DEFAULT_DUPLICATE 1
#define DEFAULT_ERROR_AFTER -1
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,
};
-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,
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 };
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);
{
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,
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;
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;
+ return TRUE;
}
-#define DEFAULT_PULL_SIZE 1024
-
static void
-gst_identity_sink_loop (GstPad * pad)
+gst_identity_check_perfect (GstIdentity * identity, GstBuffer * buf)
{
- 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;
-}
+ GstClockTime timestamp;
-static void
-gst_identity_src_loop (GstPad * pad)
-{
- GstIdentity *identity;
- GstData *data;
- GstFlowReturn ret;
-
- 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;
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--) {
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)
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;
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;
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:
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:
break;
}
- if (GST_ELEMENT_CLASS (parent_class)->change_state)
- return GST_ELEMENT_CLASS (parent_class)->change_state (element);
-
- return GST_STATE_SUCCESS;
+ return result;
}
#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
G_BEGIN_DECLS
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;
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);
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 */
/* 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,
/**
* 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.
*
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) {
}
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 {
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:
{
}
}
+/**
+ * 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
}
}
+
+/**
+ * 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.
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);
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);
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),
* 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);
* 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)
* 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)
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 */
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__);
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 */
/* data transport functions */
GstPadLoopFunction loopfunc;
GstPadChainFunction chainfunc;
+ GstPadCheckGetRangeFunction checkgetrangefunc;
GstPadGetRangeFunction getrangefunc;
GstPadEventFunction eventfunc;
#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)
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,
/* 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);
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,
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)
$(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
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
#include "gstbasesink.h"
#include <gst/gstmarshal.h>
-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
PROP_PREROLL_QUEUE_LEN
};
-#define _do_init(bla) \
- GST_DEBUG_CATEGORY_INIT (gst_basesink_debug, "basesink", 0, "basesink element");
+static GstElementClass *parent_class = NULL;
+
+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,
+ };
-GST_BOILERPLATE_FULL (GstBaseSink, gst_basesink, GstElement, GST_TYPE_ELEMENT,
- _do_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);
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,
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
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);
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);
}
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;
}
}
static void
-gst_basesink_init (GstBaseSink * basesink)
+gst_basesink_init (GstBaseSink * basesink, gpointer g_class)
{
- GstStaticPadTemplate *template;
+ GstPadTemplate *pad_template;
+
+ pad_template =
+ gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "sink");
+ g_return_if_fail (pad_template != NULL);
- template = gst_basesink_get_template (basesink);
+ 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,
GST_UNLOCK (sink);
}
-static GstStaticPadTemplate *
-gst_base_sink_get_template (GstBaseSink * sink)
-{
- return &sinktemplate;
-}
-
static GstCaps *
gst_base_sink_get_caps (GstBaseSink * sink)
{
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) =
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 ();
struct _GstBaseSinkClass {
GstElementClass parent_class;
- GstStaticPadTemplate* (*get_template) (GstBaseSink *sink);
-
GstCaps* (*get_caps) (GstBaseSink *sink);
gboolean (*set_caps) (GstBaseSink *sink, GstCaps *caps);
--- /dev/null
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ * 2000 Wim Taymans <wtay@chello.be>
+ * 2005 Wim Taymans <wim@fluendo.com>
+ *
+ * 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 <stdlib.h>
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "../gst-i18n-lib.h"
+#include "gstbasetransform.h"
+#include <gst/gstmarshal.h>
+
+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;
+}
--- /dev/null
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ * 2005 Wim Taymans <wim@fluendo.com>
+ *
+ * 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 <gst/gst.h>
+
+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__ */
LAST_SIGNAL
};
-#define DEFAULT_LOOP_BASED FALSE
#define DEFAULT_SLEEP_TIME 0
#define DEFAULT_DUPLICATE 1
#define DEFAULT_ERROR_AFTER -1
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,
};
-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,
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 };
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);
{
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,
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;
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;
+ return TRUE;
}
-#define DEFAULT_PULL_SIZE 1024
-
static void
-gst_identity_sink_loop (GstPad * pad)
+gst_identity_check_perfect (GstIdentity * identity, GstBuffer * buf)
{
- 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;
-}
+ GstClockTime timestamp;
-static void
-gst_identity_src_loop (GstPad * pad)
-{
- GstIdentity *identity;
- GstData *data;
- GstFlowReturn ret;
-
- 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;
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--) {
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)
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;
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;
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:
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:
break;
}
- if (GST_ELEMENT_CLASS (parent_class)->change_state)
- return GST_ELEMENT_CLASS (parent_class)->change_state (element);
-
- return GST_STATE_SUCCESS;
+ return result;
}
#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
G_BEGIN_DECLS
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;
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);