+2005-05-15 David Schleef <ds@schleef.org>
+
+ Move core plugins out of core. I don't mind fdsrc/fdsink
+ going back into the core; they were just disabled there, so
+ I moved them. Some of this stuff could (should) be deleted.
+ * gst/oldcore/Makefile.am:
+ * gst/oldcore/gstaggregator.c:
+ * gst/oldcore/gstaggregator.h:
+ * gst/oldcore/gstelements.c:
+ * gst/oldcore/gstfdsink.c:
+ * gst/oldcore/gstfdsink.h:
+ * gst/oldcore/gstfdsrc.c:
+ * gst/oldcore/gstfdsrc.h:
+ * gst/oldcore/gstmd5sink.c:
+ * gst/oldcore/gstmd5sink.h:
+ * gst/oldcore/gstmultifilesrc.c:
+ * gst/oldcore/gstmultifilesrc.h:
+ * gst/oldcore/gstpipefilter.c:
+ * gst/oldcore/gstpipefilter.h:
+ * gst/oldcore/gstshaper.c:
+ * gst/oldcore/gstshaper.h:
+ * gst/oldcore/gststatistics.c:
+ * gst/oldcore/gststatistics.h:
+
2005-05-13 Christian Schaller <uraeus@gnome.org>
* ext/Makefile.am: dist esd directory
--- /dev/null
+
+plugin_LTLIBRARIES = libgstoldcoreelements.la
+
+libgstoldcoreelements_la_SOURCES = \
+ gstelements.c \
+ gstaggregator.c \
+ gstfdsink.c \
+ gstfdsrc.c \
+ gstmd5sink.c \
+ gstmultifilesrc.c \
+ gstpipefilter.c \
+ gstshaper.c \
+ gststatistics.c
+
+
+libgstoldcoreelements_la_CFLAGS = $(GST_CFLAGS)
+libgstoldcoreelements_la_LIBADD =
+libgstoldcoreelements_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = \
+ gstaggregator.h \
+ gstfdsink.h \
+ gstfdsrc.h \
+ gstmd5sink.h \
+ gstmultifilesrc.h \
+ gstpipefilter.h \
+ gstshaper.h \
+ gststatistics.h
+
--- /dev/null
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ * 2000 Wim Taymans <wim.taymans@chello.be>
+ *
+ * gstaggregator.c: Aggregator element, N in 1 out
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "gstaggregator.h"
+
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS_ANY);
+
+GST_DEBUG_CATEGORY_STATIC (gst_aggregator_debug);
+#define GST_CAT_DEFAULT gst_aggregator_debug
+
+GstElementDetails gst_aggregator_details =
+GST_ELEMENT_DETAILS ("Aggregator pipe fitting",
+ "Generic",
+ "N-to-1 pipe fitting",
+ "Wim Taymans <wim.taymans@chello.be>");
+
+/* Aggregator signals and args */
+enum
+{
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum
+{
+ ARG_0,
+ ARG_NUM_PADS,
+ ARG_SILENT,
+ ARG_SCHED,
+ ARG_LAST_MESSAGE
+ /* FILL ME */
+};
+
+GstStaticPadTemplate aggregator_src_template =
+GST_STATIC_PAD_TEMPLATE ("sink%d",
+ GST_PAD_SINK,
+ GST_PAD_REQUEST,
+ GST_STATIC_CAPS_ANY);
+
+#define GST_TYPE_AGGREGATOR_SCHED (gst_aggregator_sched_get_type())
+static GType
+gst_aggregator_sched_get_type (void)
+{
+ static GType aggregator_sched_type = 0;
+ static GEnumValue aggregator_sched[] = {
+ {AGGREGATOR_LOOP, "1", "Loop Based"},
+ {AGGREGATOR_LOOP_SELECT, "3", "Loop Based Select"},
+ {AGGREGATOR_CHAIN, "4", "Chain Based"},
+ {0, NULL, NULL},
+ };
+
+ if (!aggregator_sched_type) {
+ aggregator_sched_type =
+ g_enum_register_static ("GstAggregatorSched", aggregator_sched);
+ }
+ return aggregator_sched_type;
+}
+
+#define AGGREGATOR_IS_LOOP_BASED(ag) ((ag)->sched != AGGREGATOR_CHAIN)
+
+static GstPad *gst_aggregator_request_new_pad (GstElement * element,
+ GstPadTemplate * temp, const gchar * unused);
+static void gst_aggregator_update_functions (GstAggregator * aggregator);
+
+static void gst_aggregator_finalize (GObject * object);
+static void gst_aggregator_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_aggregator_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static void gst_aggregator_chain (GstPad * pad, GstData * _data);
+static void gst_aggregator_loop (GstElement * element);
+
+#define _do_init(bla) \
+ GST_DEBUG_CATEGORY_INIT (gst_aggregator_debug, "aggregator", 0, "aggregator element");
+
+GST_BOILERPLATE_FULL (GstAggregator, gst_aggregator, GstElement,
+ GST_TYPE_ELEMENT, _do_init);
+
+static void
+gst_aggregator_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 (&aggregator_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&srctemplate));
+ gst_element_class_set_details (gstelement_class, &gst_aggregator_details);
+}
+
+static void
+gst_aggregator_finalize (GObject * object)
+{
+ GstAggregator *aggregator;
+
+ aggregator = GST_AGGREGATOR (object);
+
+ g_list_free (aggregator->sinkpads);
+ g_free (aggregator->last_message);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_aggregator_class_init (GstAggregatorClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+
+ gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_aggregator_set_property);
+ gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_aggregator_get_property);
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUM_PADS,
+ g_param_spec_int ("num_pads", "Num pads", "The number of source pads",
+ 0, G_MAXINT, 0, G_PARAM_READABLE));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT,
+ g_param_spec_boolean ("silent", "Silent", "Don't produce messages",
+ FALSE, G_PARAM_READWRITE));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SCHED,
+ g_param_spec_enum ("sched", "Scheduling",
+ "The type of scheduling this element should use",
+ GST_TYPE_AGGREGATOR_SCHED, AGGREGATOR_CHAIN, G_PARAM_READWRITE));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
+ g_param_spec_string ("last_message", "Last message",
+ "The current state of the element", NULL, G_PARAM_READABLE));
+
+ gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_aggregator_finalize);
+
+ gstelement_class->request_new_pad =
+ GST_DEBUG_FUNCPTR (gst_aggregator_request_new_pad);
+}
+
+static void
+gst_aggregator_init (GstAggregator * aggregator)
+{
+ aggregator->srcpad =
+ gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
+ "src");
+ gst_pad_set_getcaps_function (aggregator->srcpad, gst_pad_proxy_getcaps);
+ gst_element_add_pad (GST_ELEMENT (aggregator), aggregator->srcpad);
+
+ aggregator->numsinkpads = 0;
+ aggregator->sinkpads = NULL;
+ aggregator->silent = FALSE;
+ aggregator->sched = AGGREGATOR_LOOP;
+ aggregator->last_message = NULL;
+
+ gst_aggregator_update_functions (aggregator);
+}
+
+static GstPad *
+gst_aggregator_request_new_pad (GstElement * element, GstPadTemplate * templ,
+ const gchar * unused)
+{
+ gchar *name;
+ GstPad *sinkpad;
+ GstAggregator *aggregator;
+
+ g_return_val_if_fail (GST_IS_AGGREGATOR (element), NULL);
+
+ if (templ->direction != GST_PAD_SINK) {
+ g_warning ("gstaggregator: request new pad that is not a sink pad\n");
+ return NULL;
+ }
+
+ aggregator = GST_AGGREGATOR (element);
+
+ name = g_strdup_printf ("sink%d", aggregator->numsinkpads);
+
+ sinkpad = gst_pad_new_from_template (templ, name);
+ g_free (name);
+
+ if (!AGGREGATOR_IS_LOOP_BASED (aggregator)) {
+ gst_pad_set_chain_function (sinkpad, gst_aggregator_chain);
+ }
+ gst_pad_set_getcaps_function (sinkpad, gst_pad_proxy_getcaps);
+ gst_element_add_pad (GST_ELEMENT (aggregator), sinkpad);
+
+ aggregator->sinkpads = g_list_prepend (aggregator->sinkpads, sinkpad);
+ aggregator->numsinkpads++;
+
+ return sinkpad;
+}
+
+static void
+gst_aggregator_update_functions (GstAggregator * aggregator)
+{
+ GList *pads;
+
+ if (AGGREGATOR_IS_LOOP_BASED (aggregator)) {
+ gst_element_set_loop_function (GST_ELEMENT (aggregator),
+ GST_DEBUG_FUNCPTR (gst_aggregator_loop));
+ } else {
+ gst_element_set_loop_function (GST_ELEMENT (aggregator), NULL);
+ }
+
+ pads = aggregator->sinkpads;
+ while (pads) {
+ GstPad *pad = GST_PAD (pads->data);
+
+ if (AGGREGATOR_IS_LOOP_BASED (aggregator)) {
+ gst_pad_set_get_function (pad, NULL);
+ } else {
+ gst_element_set_loop_function (GST_ELEMENT (aggregator), NULL);
+ }
+ pads = g_list_next (pads);
+ }
+}
+
+static void
+gst_aggregator_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstAggregator *aggregator;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail (GST_IS_AGGREGATOR (object));
+
+ aggregator = GST_AGGREGATOR (object);
+
+ switch (prop_id) {
+ case ARG_SILENT:
+ aggregator->silent = g_value_get_boolean (value);
+ break;
+ case ARG_SCHED:
+ aggregator->sched = g_value_get_enum (value);
+ gst_aggregator_update_functions (aggregator);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+gst_aggregator_get_property (GObject * object, guint prop_id, GValue * value,
+ GParamSpec * pspec)
+{
+ GstAggregator *aggregator;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail (GST_IS_AGGREGATOR (object));
+
+ aggregator = GST_AGGREGATOR (object);
+
+ switch (prop_id) {
+ case ARG_NUM_PADS:
+ g_value_set_int (value, aggregator->numsinkpads);
+ break;
+ case ARG_SILENT:
+ g_value_set_boolean (value, aggregator->silent);
+ break;
+ case ARG_SCHED:
+ g_value_set_enum (value, aggregator->sched);
+ break;
+ case ARG_LAST_MESSAGE:
+ g_value_set_string (value, aggregator->last_message);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+gst_aggregator_push (GstAggregator * aggregator, GstPad * pad, GstBuffer * buf,
+ guchar * debug)
+{
+ if (!aggregator->silent) {
+ g_free (aggregator->last_message);
+
+ aggregator->last_message =
+ g_strdup_printf ("%10.10s ******* (%s:%s)a (%d bytes, %"
+ G_GUINT64_FORMAT ")", debug, GST_DEBUG_PAD_NAME (pad),
+ GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf));
+
+ g_object_notify (G_OBJECT (aggregator), "last_message");
+ }
+
+ gst_pad_push (aggregator->srcpad, GST_DATA (buf));
+}
+
+static void
+gst_aggregator_loop (GstElement * element)
+{
+ GstAggregator *aggregator;
+ GstBuffer *buf;
+ guchar *debug;
+
+ aggregator = GST_AGGREGATOR (element);
+
+ if (aggregator->sched == AGGREGATOR_LOOP) {
+ GList *pads = aggregator->sinkpads;
+
+ /* we'll loop over all pads and try to pull from all
+ * active ones */
+ while (pads) {
+ GstPad *pad = GST_PAD (pads->data);
+
+ pads = g_list_next (pads);
+
+ /* we need to check is the pad is usable. IS_USABLE will check
+ * if the pad is linked, if it is enabled (the element is
+ * playing and the app didn't gst_pad_set_enabled (pad, FALSE))
+ * and that the peer pad is also enabled.
+ */
+ if (GST_PAD_IS_USABLE (pad)) {
+ buf = GST_BUFFER (gst_pad_pull (pad));
+ debug = "loop";
+
+ /* then push it forward */
+ gst_aggregator_push (aggregator, pad, buf, debug);
+ }
+ }
+ } else {
+ if (aggregator->sched == AGGREGATOR_LOOP_SELECT) {
+ GstPad *pad;
+
+ debug = "loop_select";
+
+ buf = GST_BUFFER (gst_pad_collectv (&pad, aggregator->sinkpads));
+
+ gst_aggregator_push (aggregator, pad, buf, debug);
+ } else {
+ g_assert_not_reached ();
+ }
+ }
+}
+
+/**
+ * gst_aggregator_chain:
+ * @pad: the pad to follow
+ * @buf: the buffer to pass
+ *
+ * Chain a buffer on a pad.
+ */
+static void
+gst_aggregator_chain (GstPad * pad, GstData * _data)
+{
+ GstBuffer *buf = GST_BUFFER (_data);
+ GstAggregator *aggregator;
+
+ g_return_if_fail (pad != NULL);
+ g_return_if_fail (GST_IS_PAD (pad));
+ g_return_if_fail (buf != NULL);
+
+ aggregator = GST_AGGREGATOR (gst_pad_get_parent (pad));
+/* gst_trace_add_entry (NULL, 0, buf, "aggregator buffer");*/
+
+ gst_aggregator_push (aggregator, pad, buf, "chain");
+}
--- /dev/null
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ * 2000 Wim Taymans <wtay@chello.be>
+ *
+ * gstaggregator.h: Header for GstAggregator element
+ *
+ * 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_AGGREGATOR_H__
+#define __GST_AGGREGATOR_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+
+typedef enum {
+ AGGREGATOR_LOOP = 1,
+ AGGREGATOR_LOOP_SELECT,
+ AGGREGATOR_CHAIN
+} GstAggregatorSchedType;
+
+#define GST_TYPE_AGGREGATOR \
+ (gst_aggregator_get_type())
+#define GST_AGGREGATOR(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AGGREGATOR,GstAggregator))
+#define GST_AGGREGATOR_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AGGREGATOR,GstAggregatorClass))
+#define GST_IS_AGGREGATOR(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AGGREGATOR))
+#define GST_IS_AGGREGATOR_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AGGREGATOR))
+
+typedef struct _GstAggregator GstAggregator;
+typedef struct _GstAggregatorClass GstAggregatorClass;
+
+struct _GstAggregator {
+ GstElement element;
+
+ GstPad *srcpad;
+
+ gboolean silent;
+ GstAggregatorSchedType sched;
+
+ gint numsinkpads;
+ GList *sinkpads;
+
+ gchar *last_message;
+};
+
+struct _GstAggregatorClass {
+ GstElementClass parent_class;
+};
+
+GType gst_aggregator_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_AGGREGATOR_H__ */
--- /dev/null
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ * 2000 Wim Taymans <wtay@chello.be>
+ *
+ * gstelements.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.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gst/gst.h>
+
+#include "gstaggregator.h"
+#include "gstfdsink.h"
+#include "gstfdsrc.h"
+#include "gstmd5sink.h"
+#include "gstmultifilesrc.h"
+#include "gstpipefilter.h"
+#include "gstshaper.h"
+#include "gststatistics.h"
+
+struct _elements_entry
+{
+ gchar *name;
+ guint rank;
+ GType (*type) (void);
+};
+
+
+extern GType gst_capsfilter_get_type (void);
+extern GType gst_filesrc_get_type (void);
+extern GstElementDetails gst_filesrc_details;
+
+static struct _elements_entry _elements[] = {
+ {"aggregator", GST_RANK_NONE, gst_aggregator_get_type},
+ {"fdsink", GST_RANK_NONE, gst_fdsink_get_type},
+ {"fdsrc", GST_RANK_NONE, gst_fdsrc_get_type},
+ {"md5sink", GST_RANK_NONE, gst_md5sink_get_type},
+ {"multifilesrc", GST_RANK_NONE, gst_multifilesrc_get_type},
+ {"pipefilter", GST_RANK_NONE, gst_pipefilter_get_type},
+ {"shaper", GST_RANK_NONE, gst_shaper_get_type},
+ {"statistics", GST_RANK_NONE, gst_statistics_get_type},
+ {NULL, 0},
+};
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ struct _elements_entry *my_elements = _elements;
+
+ while ((*my_elements).name) {
+ if (!gst_element_register (plugin, (*my_elements).name, (*my_elements).rank,
+ ((*my_elements).type) ()))
+ return FALSE;
+ my_elements++;
+ }
+
+ return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "gstelements",
+ "standard GStreamer elements",
+ plugin_init, VERSION, GST_LICENSE, GST_PACKAGE, GST_ORIGIN)
--- /dev/null
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ * 2000 Wim Taymans <wtay@chello.be>
+ *
+ * gstfdsink.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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "gstfdsink.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS_ANY);
+
+GST_DEBUG_CATEGORY_STATIC (gst_fdsink_debug);
+#define GST_CAT_DEFAULT gst_fdsink_debug
+
+GstElementDetails gst_fdsink_details =
+GST_ELEMENT_DETAILS ("Filedescriptor Sink",
+ "Sink/File",
+ "Write data to a file descriptor",
+ "Erik Walthinsen <omega@cse.ogi.edu>");
+
+
+/* FdSink signals and args */
+enum
+{
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum
+{
+ ARG_0,
+ ARG_FD
+};
+
+
+#define _do_init(bla) \
+ GST_DEBUG_CATEGORY_INIT (gst_fdsink_debug, "fdsink", 0, "fdsink element");
+
+GST_BOILERPLATE_FULL (GstFdSink, gst_fdsink, GstElement, GST_TYPE_ELEMENT,
+ _do_init);
+
+static void gst_fdsink_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_fdsink_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static void gst_fdsink_chain (GstPad * pad, GstData * _data);
+
+
+static void
+gst_fdsink_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_element_class_set_details (gstelement_class, &gst_fdsink_details);
+}
+static void
+gst_fdsink_class_init (GstFdSinkClass * klass)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->set_property = gst_fdsink_set_property;
+ gobject_class->get_property = gst_fdsink_get_property;
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FD,
+ g_param_spec_int ("fd", "fd", "An open file descriptor to write to",
+ 0, G_MAXINT, 1, G_PARAM_READWRITE));
+}
+
+static void
+gst_fdsink_init (GstFdSink * fdsink)
+{
+ fdsink->sinkpad =
+ gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate),
+ "sink");
+ gst_element_add_pad (GST_ELEMENT (fdsink), fdsink->sinkpad);
+ gst_pad_set_chain_function (fdsink->sinkpad, gst_fdsink_chain);
+
+ fdsink->fd = 1;
+}
+
+static void
+gst_fdsink_chain (GstPad * pad, GstData * _data)
+{
+ GstBuffer *buf = GST_BUFFER (_data);
+ GstFdSink *fdsink;
+
+ g_return_if_fail (pad != NULL);
+ g_return_if_fail (GST_IS_PAD (pad));
+ g_return_if_fail (buf != NULL);
+
+ fdsink = GST_FDSINK (gst_pad_get_parent (pad));
+
+ g_return_if_fail (fdsink->fd >= 0);
+
+ if (GST_BUFFER_DATA (buf)) {
+ GST_DEBUG ("writing %d bytes to file descriptor %d", GST_BUFFER_SIZE (buf),
+ fdsink->fd);
+ write (fdsink->fd, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
+ }
+
+ gst_buffer_unref (buf);
+}
+
+static void
+gst_fdsink_set_property (GObject * object, guint prop_id, const GValue * value,
+ GParamSpec * pspec)
+{
+ GstFdSink *fdsink;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail (GST_IS_FDSINK (object));
+
+ fdsink = GST_FDSINK (object);
+
+ switch (prop_id) {
+ case ARG_FD:
+ fdsink->fd = g_value_get_int (value);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+gst_fdsink_get_property (GObject * object, guint prop_id, GValue * value,
+ GParamSpec * pspec)
+{
+ GstFdSink *fdsink;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail (GST_IS_FDSINK (object));
+
+ fdsink = GST_FDSINK (object);
+
+ switch (prop_id) {
+ case ARG_FD:
+ g_value_set_int (value, fdsink->fd);
+ break;
+ default:
+ break;
+ }
+}
--- /dev/null
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ * 2000 Wim Taymans <wtay@chello.be>
+ *
+ * gstfdsink.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_FDSINK_H__
+#define __GST_FDSINK_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+
+#define GST_TYPE_FDSINK \
+ (gst_fdsink_get_type())
+#define GST_FDSINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FDSINK,GstFdSink))
+#define GST_FDSINK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FDSINK,GstFdSinkClass))
+#define GST_IS_FDSINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FDSINK))
+#define GST_IS_FDSINK_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FDSINK))
+
+typedef struct _GstFdSink GstFdSink;
+typedef struct _GstFdSinkClass GstFdSinkClass;
+
+struct _GstFdSink {
+ GstElement element;
+
+ GstPad *sinkpad;
+
+ int fd;
+};
+
+struct _GstFdSinkClass {
+ GstElementClass parent_class;
+};
+
+GType gst_fdsink_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_FDSINK_H__ */
--- /dev/null
+/* GStreamer
+ * Copyright (C) 2002 Erik Walthinsen <omega@cse.ogi.edu>
+ * 2002 Wim Taymans <wim.taymans@chello.be>
+ *
+ * gstmd5sink.c: A sink computing an md5 checksum from a stream
+ *
+ * The md5 code was taken from glibc-2.2.3/crypt/md5.c and slightly
+ * modified.
+ *
+ * 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 <string.h>
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include "gstmd5sink.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_md5sink_debug);
+#define GST_CAT_DEFAULT gst_md5sink_debug
+
+GstElementDetails gst_md5sink_details = GST_ELEMENT_DETAILS ("MD5 Sink",
+ "Sink",
+ "compute MD5 for incoming data",
+ "Benjamin Otte <in7y118@public.uni-hamburg.de>");
+
+/* MD5Sink signals and args */
+enum
+{
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum
+{
+ ARG_0,
+ ARG_MD5
+ /* FILL ME */
+};
+
+GstStaticPadTemplate md5_sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS_ANY);
+
+#define _do_init(bla) \
+ GST_DEBUG_CATEGORY_INIT (gst_md5sink_debug, "md5sink", 0, "md5sink element");
+
+GST_BOILERPLATE_FULL (GstMD5Sink, gst_md5sink, GstElement, GST_TYPE_ELEMENT,
+ _do_init);
+
+/* GObject stuff */
+/*static void gst_md5sink_set_property (GObject *object, guint prop_id,
+ const GValue *value, GParamSpec *pspec);*/
+static void gst_md5sink_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static void gst_md5sink_chain (GstPad * pad, GstData * _data);
+static GstElementStateReturn gst_md5sink_change_state (GstElement * element);
+
+
+/* MD5 stuff */
+static void md5_init_ctx (GstMD5Sink * ctx);
+static gpointer md5_read_ctx (GstMD5Sink * ctx, gpointer resbuf);
+static gpointer md5_finish_ctx (GstMD5Sink * ctx, gpointer resbuf);
+static void md5_process_bytes (const void *buffer, size_t len,
+ GstMD5Sink * ctx);
+static void md5_process_block (const void *buffer, size_t len,
+ GstMD5Sink * ctx);
+
+/* This array contains the bytes used to pad the buffer to the next
+ 64-byte boundary. (RFC 1321, 3.1: Step 1) */
+static const guchar fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
+
+/* MD5 functions */
+/* Initialize structure containing state of computation.
+ (RFC 1321, 3.3: Step 3) */
+static void
+md5_init_ctx (GstMD5Sink * ctx)
+{
+ ctx->A = 0x67452301;
+ ctx->B = 0xefcdab89;
+ ctx->C = 0x98badcfe;
+ ctx->D = 0x10325476;
+
+ ctx->total[0] = ctx->total[1] = 0;
+ ctx->buflen = 0;
+}
+
+/* Process the remaining bytes in the internal buffer and the usual
+ prolog according to the standard and write the result to RESBUF.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+static gpointer
+md5_finish_ctx (GstMD5Sink * ctx, gpointer resbuf)
+{
+ /* Take yet unprocessed bytes into account. */
+ guint32 bytes = ctx->buflen;
+ size_t pad;
+
+ /* Now count remaining bytes. */
+ ctx->total[0] += bytes;
+ if (ctx->total[0] < bytes)
+ ++ctx->total[1];
+
+ pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
+ memcpy (&ctx->buffer[bytes], fillbuf, pad);
+
+ /* Put the 64-bit file length in *bits* at the end of the buffer. */
+ *(guint32 *) & ctx->buffer[bytes + pad] = GUINT32_TO_LE (ctx->total[0] << 3);
+ *(guint32 *) & ctx->buffer[bytes + pad + 4] =
+ GUINT32_TO_LE ((ctx->total[1] << 3) | (ctx->total[0] >> 29));
+
+ /* Process last bytes. */
+ md5_process_block (ctx->buffer, bytes + pad + 8, ctx);
+
+ return md5_read_ctx (ctx, resbuf);
+}
+
+/* Put result from CTX in first 16 bytes following RESBUF. The result
+ must be in little endian byte order.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+static gpointer
+md5_read_ctx (GstMD5Sink * ctx, gpointer resbuf)
+{
+ ((guint32 *) resbuf)[0] = GUINT32_TO_LE (ctx->A);
+ ((guint32 *) resbuf)[1] = GUINT32_TO_LE (ctx->B);
+ ((guint32 *) resbuf)[2] = GUINT32_TO_LE (ctx->C);
+ ((guint32 *) resbuf)[3] = GUINT32_TO_LE (ctx->D);
+
+ return resbuf;
+}
+
+static void
+md5_process_bytes (const void *buffer, size_t len, GstMD5Sink * ctx)
+{
+ /*const void aligned_buffer = buffer; */
+
+ /* When we already have some bits in our internal buffer concatenate
+ both inputs first. */
+ if (ctx->buflen != 0) {
+ size_t left_over = ctx->buflen;
+ size_t add = 128 - left_over > len ? len : 128 - left_over;
+
+ /* Only put full words in the buffer. */
+ /* Forcing alignment here appears to be only an optimization.
+ * The glibc source uses __alignof__, which seems to be a
+ * gratuitous usage of a GCC extension, when sizeof() will
+ * work fine. (And don't question the sanity of using
+ * sizeof(guint32) instead of 4. */
+ /* add -= add % __alignof__ (guint32); */
+ add -= add % sizeof (guint32);
+
+ memcpy (&ctx->buffer[left_over], buffer, add);
+ ctx->buflen += add;
+
+ if (ctx->buflen > 64) {
+ md5_process_block (ctx->buffer, ctx->buflen & ~63, ctx);
+
+ ctx->buflen &= 63;
+ /* The regions in the following copy operation cannot overlap. */
+ memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63], ctx->buflen);
+ }
+
+ buffer = (const char *) buffer + add;
+ len -= add;
+ }
+
+ /* Process available complete blocks. */
+ if (len > 64) {
+ md5_process_block (buffer, len & ~63, ctx);
+ buffer = (const char *) buffer + (len & ~63);
+ len &= 63;
+ }
+
+ /* Move remaining bytes in internal buffer. */
+ if (len > 0) {
+ size_t left_over = ctx->buflen;
+
+ memcpy (&ctx->buffer[left_over], buffer, len);
+ left_over += len;
+ if (left_over >= 64) {
+ md5_process_block (ctx->buffer, 64, ctx);
+ left_over -= 64;
+ memcpy (ctx->buffer, &ctx->buffer[64], left_over);
+ }
+ ctx->buflen = left_over;
+ }
+}
+
+
+/* These are the four functions used in the four steps of the MD5 algorithm
+ and defined in the RFC 1321. The first function is a little bit optimized
+ (as found in Colin Plumbs public domain implementation). */
+/* #define FF(b, c, d) ((b & c) | (~b & d)) */
+#define FF(b, c, d) (d ^ (b & (c ^ d)))
+#define FG(b, c, d) FF (d, b, c)
+#define FH(b, c, d) (b ^ c ^ d)
+#define FI(b, c, d) (c ^ (b | ~d))
+
+/* Process LEN bytes of BUFFER, accumulating context into CTX.
+ It is assumed that LEN % 64 == 0. */
+static void
+md5_process_block (const void *buffer, size_t len, GstMD5Sink * ctx)
+{
+ guint32 correct_words[16];
+ const guint32 *words = buffer;
+ size_t nwords = len / sizeof (guint32);
+ const guint32 *endp = words + nwords;
+ guint32 A = ctx->A;
+ guint32 B = ctx->B;
+ guint32 C = ctx->C;
+ guint32 D = ctx->D;
+
+ /* First increment the byte count. RFC 1321 specifies the possible
+ length of the file up to 2^64 bits. Here we only compute the
+ number of bytes. Do a double word increment. */
+ ctx->total[0] += len;
+ if (ctx->total[0] < len)
+ ++ctx->total[1];
+
+ /* Process all bytes in the buffer with 64 bytes in each round of
+ the loop. */
+ while (words < endp) {
+ guint32 *cwp = correct_words;
+ guint32 A_save = A;
+ guint32 B_save = B;
+ guint32 C_save = C;
+ guint32 D_save = D;
+
+ /* First round: using the given function, the context and a constant
+ the next context is computed. Because the algorithms processing
+ unit is a 32-bit word and it is determined to work on words in
+ little endian byte order we perhaps have to change the byte order
+ before the computation. To reduce the work for the next steps
+ we store the swapped words in the array CORRECT_WORDS. */
+
+#define OP(a, b, c, d, s, T) \
+ do \
+ { \
+ a += FF (b, c, d) + (*cwp++ = GUINT32_TO_LE (*words)) + T; \
+ ++words; \
+ CYCLIC (a, s); \
+ a += b; \
+ } \
+ while (0)
+
+ /* It is unfortunate that C does not provide an operator for
+ cyclic rotation. Hope the C compiler is smart enough. */
+#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
+
+ /* Before we start, one word to the strange constants.
+ They are defined in RFC 1321 as
+
+ T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
+ */
+
+ /* Round 1. */
+ OP (A, B, C, D, 7, 0xd76aa478);
+ OP (D, A, B, C, 12, 0xe8c7b756);
+ OP (C, D, A, B, 17, 0x242070db);
+ OP (B, C, D, A, 22, 0xc1bdceee);
+ OP (A, B, C, D, 7, 0xf57c0faf);
+ OP (D, A, B, C, 12, 0x4787c62a);
+ OP (C, D, A, B, 17, 0xa8304613);
+ OP (B, C, D, A, 22, 0xfd469501);
+ OP (A, B, C, D, 7, 0x698098d8);
+ OP (D, A, B, C, 12, 0x8b44f7af);
+ OP (C, D, A, B, 17, 0xffff5bb1);
+ OP (B, C, D, A, 22, 0x895cd7be);
+ OP (A, B, C, D, 7, 0x6b901122);
+ OP (D, A, B, C, 12, 0xfd987193);
+ OP (C, D, A, B, 17, 0xa679438e);
+ OP (B, C, D, A, 22, 0x49b40821);
+
+ /* For the second to fourth round we have the possibly swapped words
+ in CORRECT_WORDS. Redefine the macro to take an additional first
+ argument specifying the function to use. */
+#undef OP
+#define OP(f, a, b, c, d, k, s, T) \
+ do \
+ { \
+ a += f (b, c, d) + correct_words[k] + T; \
+ CYCLIC (a, s); \
+ a += b; \
+ } \
+ while (0)
+
+ /* Round 2. */
+ OP (FG, A, B, C, D, 1, 5, 0xf61e2562);
+ OP (FG, D, A, B, C, 6, 9, 0xc040b340);
+ OP (FG, C, D, A, B, 11, 14, 0x265e5a51);
+ OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
+ OP (FG, A, B, C, D, 5, 5, 0xd62f105d);
+ OP (FG, D, A, B, C, 10, 9, 0x02441453);
+ OP (FG, C, D, A, B, 15, 14, 0xd8a1e681);
+ OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
+ OP (FG, A, B, C, D, 9, 5, 0x21e1cde6);
+ OP (FG, D, A, B, C, 14, 9, 0xc33707d6);
+ OP (FG, C, D, A, B, 3, 14, 0xf4d50d87);
+ OP (FG, B, C, D, A, 8, 20, 0x455a14ed);
+ OP (FG, A, B, C, D, 13, 5, 0xa9e3e905);
+ OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8);
+ OP (FG, C, D, A, B, 7, 14, 0x676f02d9);
+ OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
+
+ /* Round 3. */
+ OP (FH, A, B, C, D, 5, 4, 0xfffa3942);
+ OP (FH, D, A, B, C, 8, 11, 0x8771f681);
+ OP (FH, C, D, A, B, 11, 16, 0x6d9d6122);
+ OP (FH, B, C, D, A, 14, 23, 0xfde5380c);
+ OP (FH, A, B, C, D, 1, 4, 0xa4beea44);
+ OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9);
+ OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60);
+ OP (FH, B, C, D, A, 10, 23, 0xbebfbc70);
+ OP (FH, A, B, C, D, 13, 4, 0x289b7ec6);
+ OP (FH, D, A, B, C, 0, 11, 0xeaa127fa);
+ OP (FH, C, D, A, B, 3, 16, 0xd4ef3085);
+ OP (FH, B, C, D, A, 6, 23, 0x04881d05);
+ OP (FH, A, B, C, D, 9, 4, 0xd9d4d039);
+ OP (FH, D, A, B, C, 12, 11, 0xe6db99e5);
+ OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8);
+ OP (FH, B, C, D, A, 2, 23, 0xc4ac5665);
+
+ /* Round 4. */
+ OP (FI, A, B, C, D, 0, 6, 0xf4292244);
+ OP (FI, D, A, B, C, 7, 10, 0x432aff97);
+ OP (FI, C, D, A, B, 14, 15, 0xab9423a7);
+ OP (FI, B, C, D, A, 5, 21, 0xfc93a039);
+ OP (FI, A, B, C, D, 12, 6, 0x655b59c3);
+ OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92);
+ OP (FI, C, D, A, B, 10, 15, 0xffeff47d);
+ OP (FI, B, C, D, A, 1, 21, 0x85845dd1);
+ OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f);
+ OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
+ OP (FI, C, D, A, B, 6, 15, 0xa3014314);
+ OP (FI, B, C, D, A, 13, 21, 0x4e0811a1);
+ OP (FI, A, B, C, D, 4, 6, 0xf7537e82);
+ OP (FI, D, A, B, C, 11, 10, 0xbd3af235);
+ OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
+ OP (FI, B, C, D, A, 9, 21, 0xeb86d391);
+
+ /* Add the starting values of the context. */
+ A += A_save;
+ B += B_save;
+ C += C_save;
+ D += D_save;
+ }
+
+ /* Put checksum in context given as argument. */
+ ctx->A = A;
+ ctx->B = B;
+ ctx->C = C;
+ ctx->D = D;
+}
+
+static void
+gst_md5sink_base_init (gpointer g_class)
+{
+ GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_set_details (gstelement_class, &gst_md5sink_details);
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&md5_sink_template));
+}
+
+static void
+gst_md5sink_class_init (GstMD5SinkClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+
+ gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_md5sink_get_property);
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MD5,
+ g_param_spec_string ("md5", "md5", "current value of the md5 sum",
+ "", G_PARAM_READABLE));
+
+ gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_md5sink_change_state);
+}
+
+static void
+gst_md5sink_init (GstMD5Sink * md5sink)
+{
+ GstPad *pad;
+
+ pad =
+ gst_pad_new_from_template (gst_static_pad_template_get
+ (&md5_sink_template), "sink");
+ gst_element_add_pad (GST_ELEMENT (md5sink), pad);
+ gst_pad_set_chain_function (pad, GST_DEBUG_FUNCPTR (gst_md5sink_chain));
+
+ md5_init_ctx (md5sink);
+}
+
+static GstElementStateReturn
+gst_md5sink_change_state (GstElement * element)
+{
+ GstMD5Sink *sink;
+
+ /* element check */
+ sink = GST_MD5SINK (element);
+
+ g_return_val_if_fail (GST_IS_MD5SINK (sink), GST_STATE_FAILURE);
+
+ switch (GST_STATE_TRANSITION (element)) {
+ case GST_STATE_READY_TO_PAUSED:
+ md5_init_ctx (sink);
+ g_object_notify (G_OBJECT (element), "md5");
+ break;
+ case GST_STATE_PAUSED_TO_READY:
+ md5_finish_ctx (sink, sink->md5);
+ g_object_notify (G_OBJECT (element), "md5");
+ break;
+ default:
+ break;
+ }
+
+ if ((GST_ELEMENT_CLASS (parent_class)->change_state))
+ return GST_ELEMENT_CLASS (parent_class)->change_state (element);
+
+ return GST_STATE_SUCCESS;
+}
+
+static void
+gst_md5sink_get_property (GObject * object, guint prop_id, GValue * value,
+ GParamSpec * pspec)
+{
+ GstMD5Sink *sink;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail (GST_IS_MD5SINK (object));
+
+ sink = GST_MD5SINK (object);
+
+ switch (prop_id) {
+ case ARG_MD5:
+ {
+ /* you could actually get a value for the current md5.
+ * This is currently disabled.
+ * md5_read_ctx (sink, sink->md5); */
+ /* md5 is a guchar[16] */
+ int i;
+ guchar *md5string = g_malloc0 (33);
+
+ for (i = 0; i < 16; ++i)
+ sprintf (md5string + i * 2, "%02x", sink->md5[i]);
+ g_value_set_string (value, md5string);
+ g_free (md5string);
+ }
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_md5sink_chain (GstPad * pad, GstData * _data)
+{
+ GstBuffer *buf = GST_BUFFER (_data);
+ GstMD5Sink *md5sink;
+
+ g_return_if_fail (pad != NULL);
+ g_return_if_fail (GST_IS_PAD (pad));
+ g_return_if_fail (buf != NULL);
+
+ md5sink = GST_MD5SINK (gst_pad_get_parent (pad));
+
+ if (GST_IS_BUFFER (buf)) {
+ md5_process_bytes (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf), md5sink);
+ }
+
+ gst_buffer_unref (buf);
+}
--- /dev/null
+/* GStreamer
+ * Copyright (C) 2002 Erik Walthinsen <omega@cse.ogi.edu>
+ * 2002 Wim Taymans <wtay@chello.be>
+ *
+ * gstmd5sink.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_MD5SINK_H__
+#define __GST_MD5SINK_H__
+
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+
+#define GST_TYPE_MD5SINK \
+ (gst_md5sink_get_type())
+#define GST_MD5SINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MD5SINK,GstMD5Sink))
+#define GST_MD5SINK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MD5SINK,GstMD5SinkClass))
+#define GST_IS_MD5SINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MD5SINK))
+#define GST_IS_MD5SINK_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MD5SINK))
+
+typedef struct _GstMD5Sink GstMD5Sink;
+typedef struct _GstMD5SinkClass GstMD5SinkClass;
+
+struct _GstMD5Sink {
+ GstElement element;
+
+ /* md5 information */
+ guint32 A;
+ guint32 B;
+ guint32 C;
+ guint32 D;
+
+ guint32 total[2];
+ guint32 buflen;
+ gchar buffer[128];
+
+ /* latest md5 */
+ guchar md5[16];
+
+};
+
+struct _GstMD5SinkClass {
+ GstElementClass parent_class;
+
+};
+
+GType gst_md5sink_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_MD5SINK_H__ */
--- /dev/null
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ * 2000 Wim Taymans <wtay@chello.be>
+ * 2001 Dominic Ludlam <dom@recoil.org>
+ *
+ * gstmultifilesrc.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 <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "../gst-i18n-lib.h"
+
+#include "gstmultifilesrc.h"
+
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS_ANY);
+
+GST_DEBUG_CATEGORY_STATIC (gst_multifilesrc_debug);
+#define GST_CAT_DEFAULT gst_multifilesrc_debug
+
+GstElementDetails gst_multifilesrc_details =
+GST_ELEMENT_DETAILS ("Multi File Source",
+ "Source/File",
+ "Read from multiple files in order",
+ "Dominic Ludlam <dom@openfx.org>");
+
+/* FileSrc signals and args */
+enum
+{
+ NEW_FILE,
+ LAST_SIGNAL
+};
+
+enum
+{
+ ARG_0,
+ ARG_LOCATIONS,
+ ARG_HAVENEWMEDIA
+};
+
+#define _do_init(bla) \
+ GST_DEBUG_CATEGORY_INIT (gst_multifilesrc_debug, "multifilesrc", 0, "multifilesrc element");
+
+GST_BOILERPLATE_FULL (GstMultiFileSrc, gst_multifilesrc, GstElement,
+ GST_TYPE_ELEMENT, _do_init);
+
+static void gst_multifilesrc_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_multifilesrc_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static GstData *gst_multifilesrc_get (GstPad * pad);
+
+/*static GstBuffer * gst_multifilesrc_get_region (GstPad *pad,GstRegionType type,guint64 offset,guint64 len);*/
+
+static GstElementStateReturn gst_multifilesrc_change_state (GstElement *
+ element);
+
+static gboolean gst_multifilesrc_open_file (GstMultiFileSrc * src,
+ GstPad * srcpad);
+static void gst_multifilesrc_close_file (GstMultiFileSrc * src);
+
+static guint gst_multifilesrc_signals[LAST_SIGNAL] = { 0 };
+
+static void
+gst_multifilesrc_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 (&srctemplate));
+ gst_element_class_set_details (gstelement_class, &gst_multifilesrc_details);
+}
+static void
+gst_multifilesrc_class_init (GstMultiFileSrcClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+
+ gobject_class->set_property = gst_multifilesrc_set_property;
+ gobject_class->get_property = gst_multifilesrc_get_property;
+
+ gst_multifilesrc_signals[NEW_FILE] =
+ g_signal_new ("new-file", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GstMultiFileSrcClass, new_file), NULL, NULL,
+ g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING);
+
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LOCATIONS, g_param_spec_pointer ("locations", "locations", "locations", G_PARAM_READWRITE)); /* CHECKME */
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_HAVENEWMEDIA,
+ g_param_spec_boolean ("newmedia", "newmedia",
+ "generate new media events?", FALSE, G_PARAM_READWRITE));
+
+ gstelement_class->change_state = gst_multifilesrc_change_state;
+}
+
+static void
+gst_multifilesrc_init (GstMultiFileSrc * multifilesrc)
+{
+/* GST_FLAG_SET (filesrc, GST_SRC_); */
+
+ multifilesrc->srcpad =
+ gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
+ "src");
+ gst_pad_set_get_function (multifilesrc->srcpad, gst_multifilesrc_get);
+/* gst_pad_set_getregion_function (multifilesrc->srcpad,gst_multifilesrc_get_region); */
+ gst_element_add_pad (GST_ELEMENT (multifilesrc), multifilesrc->srcpad);
+
+ multifilesrc->listptr = NULL;
+ multifilesrc->currentfilename = NULL;
+ multifilesrc->fd = 0;
+ multifilesrc->size = 0;
+ multifilesrc->map = NULL;
+ multifilesrc->new_seek = FALSE;
+ multifilesrc->have_newmedia_events = FALSE;
+}
+
+static void
+gst_multifilesrc_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstMultiFileSrc *src;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail (GST_IS_MULTIFILESRC (object));
+
+ src = GST_MULTIFILESRC (object);
+
+ switch (prop_id) {
+ case ARG_LOCATIONS:
+ /* the element must be stopped in order to do this */
+ g_return_if_fail (GST_STATE (src) < GST_STATE_PLAYING);
+
+ /* clear the filename if we get a NULL */
+ if (g_value_get_pointer (value) == NULL) {
+ gst_element_set_state (GST_ELEMENT (object), GST_STATE_NULL);
+ src->listptr = NULL;
+ /* otherwise set the new filenames */
+ } else {
+ src->listptr = g_value_get_pointer (value);
+ }
+ break;
+ case ARG_HAVENEWMEDIA:
+ src->have_newmedia_events = g_value_get_boolean (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_multifilesrc_get_property (GObject * object, guint prop_id, GValue * value,
+ GParamSpec * pspec)
+{
+ GstMultiFileSrc *src;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail (GST_IS_MULTIFILESRC (object));
+
+ src = GST_MULTIFILESRC (object);
+
+ switch (prop_id) {
+ case ARG_LOCATIONS:
+ g_value_set_pointer (value, src->listptr);
+ break;
+ case ARG_HAVENEWMEDIA:
+ g_value_set_boolean (value, src->have_newmedia_events);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+/**
+ * gst_filesrc_get:
+ * @pad: #GstPad to push a buffer from
+ *
+ * Push a new buffer from the filesrc at the current offset.
+ */
+static GstData *
+gst_multifilesrc_get (GstPad * pad)
+{
+ GstMultiFileSrc *src;
+ GstBuffer *buf;
+ GstEvent *newmedia;
+ GSList *list;
+
+
+ g_return_val_if_fail (pad != NULL, NULL);
+ src = GST_MULTIFILESRC (gst_pad_get_parent (pad));
+
+ GST_DEBUG ("curfileindex = %d newmedia flag = %s", src->curfileindex,
+ GST_FLAG_IS_SET (src, GST_MULTIFILESRC_NEWFILE) ? "true" : "false");
+
+ switch (GST_FLAG_IS_SET (src, GST_MULTIFILESRC_NEWFILE)) {
+ case FALSE:
+ if (GST_FLAG_IS_SET (src, GST_MULTIFILESRC_OPEN))
+ gst_multifilesrc_close_file (src);
+
+ if (!src->listptr) {
+ GST_DEBUG ("sending EOS event");
+ gst_element_set_eos (GST_ELEMENT (src));
+ return GST_DATA (gst_event_new (GST_EVENT_EOS));
+ }
+
+ list = src->listptr;
+ src->currentfilename = (gchar *) list->data;
+ src->listptr = src->listptr->next;
+
+ if (!gst_multifilesrc_open_file (src, pad))
+ return NULL;
+ src->curfileindex++;
+ /* emitted after the open, as the user may free the list and string from here */
+ g_signal_emit (G_OBJECT (src), gst_multifilesrc_signals[NEW_FILE], 0,
+ list);
+ if (src->have_newmedia_events) {
+ newmedia =
+ gst_event_new_discontinuous (TRUE, GST_FORMAT_TIME, (gint64) 0,
+ GST_FORMAT_UNDEFINED);
+ GST_FLAG_SET (src, GST_MULTIFILESRC_NEWFILE);
+
+ GST_DEBUG ("sending new media event");
+ return GST_DATA (newmedia);
+ }
+ default:
+ if (GST_FLAG_IS_SET (src, GST_MULTIFILESRC_NEWFILE))
+ GST_FLAG_UNSET (src, GST_MULTIFILESRC_NEWFILE);
+ /* create the buffer */
+ /* FIXME: should eventually use a bufferpool for this */
+ buf = gst_buffer_new ();
+
+ g_return_val_if_fail (buf != NULL, NULL);
+
+ /* simply set the buffer to point to the correct region of the file */
+ GST_BUFFER_DATA (buf) = src->map;
+ GST_BUFFER_SIZE (buf) = src->size;
+ GST_BUFFER_OFFSET (buf) = 0;
+ GST_BUFFER_FLAG_SET (buf, GST_BUFFER_DONTFREE);
+
+ if (src->new_seek) {
+ /* fixme, do something here */
+ src->new_seek = FALSE;
+ }
+
+ /* we're done, return the buffer */
+ GST_DEBUG ("sending buffer");
+ return GST_DATA (buf);
+ }
+
+ /* should not reach here */
+ g_assert_not_reached ();
+ return NULL;
+}
+
+/* open the file and mmap it, necessary to go to READY state */
+static gboolean
+gst_multifilesrc_open_file (GstMultiFileSrc * src, GstPad * srcpad)
+{
+ g_return_val_if_fail (!GST_FLAG_IS_SET (src, GST_MULTIFILESRC_OPEN), FALSE);
+
+ if (src->currentfilename == NULL || src->currentfilename[0] == '\0') {
+ GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,
+ (_("No file name specified for reading.")), (NULL));
+ return FALSE;
+ }
+
+ /* open the file. FIXME: do we need to use O_LARGEFILE here? */
+ src->fd = open ((const char *) src->currentfilename, O_RDONLY);
+ if (src->fd < 0) {
+ GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
+ (_("Could not open file \"%s\" for reading."), src->currentfilename),
+ GST_ERROR_SYSTEM);
+ return FALSE;
+
+ } else {
+ /* find the file length */
+ src->size = lseek (src->fd, 0, SEEK_END);
+ lseek (src->fd, 0, SEEK_SET);
+ /* map the file into memory.
+ * FIXME: don't map the whole file at once, there might
+ * be restrictions set. Get max size via getrlimit
+ * or re-try with smaller size if mmap fails with ENOMEM? */
+ src->map = mmap (NULL, src->size, PROT_READ, MAP_SHARED, src->fd, 0);
+ madvise (src->map, src->size, MADV_SEQUENTIAL);
+ /* collapse state if that failed */
+ if (src->map == NULL) {
+ close (src->fd);
+ GST_ELEMENT_ERROR (src, RESOURCE, TOO_LAZY, (NULL),
+ ("mmap call failed."));
+ return FALSE;
+ }
+ GST_FLAG_SET (src, GST_MULTIFILESRC_OPEN);
+ src->new_seek = TRUE;
+ }
+ return TRUE;
+}
+
+/* unmap and close the file */
+static void
+gst_multifilesrc_close_file (GstMultiFileSrc * src)
+{
+ g_return_if_fail (GST_FLAG_IS_SET (src, GST_MULTIFILESRC_OPEN));
+
+ /* unmap the file from memory and close the file */
+ munmap (src->map, src->size);
+ close (src->fd);
+
+ /* zero out a lot of our state */
+ src->fd = 0;
+ src->size = 0;
+ src->map = NULL;
+ src->new_seek = FALSE;
+
+ GST_FLAG_UNSET (src, GST_MULTIFILESRC_OPEN);
+}
+
+static GstElementStateReturn
+gst_multifilesrc_change_state (GstElement * element)
+{
+ g_return_val_if_fail (GST_IS_MULTIFILESRC (element), GST_STATE_FAILURE);
+
+ if (GST_STATE_PENDING (element) == GST_STATE_NULL) {
+ if (GST_FLAG_IS_SET (element, GST_MULTIFILESRC_OPEN))
+ gst_multifilesrc_close_file (GST_MULTIFILESRC (element));
+ }
+
+ if (GST_ELEMENT_CLASS (parent_class)->change_state)
+ return GST_ELEMENT_CLASS (parent_class)->change_state (element);
+
+ return GST_STATE_SUCCESS;
+}
--- /dev/null
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ * 2000 Wim Taymans <wtay@chello.be>
+ * 2001 Dominic Ludlam <dom@recoil.org>
+ *
+ * gstmultifilesrc.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_MULTIFILESRC_H__
+#define __GST_MULTIFILESRC_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+
+#define GST_TYPE_MULTIFILESRC \
+ (gst_multifilesrc_get_type())
+#define GST_MULTIFILESRC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MULTIFILESRC,GstMultiFileSrc))
+#define GST_MULTIFILESRC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MULTIFILESRC,GstMultiFileSrcClass))
+#define GST_IS_MULTIFILESRC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MULTIFILESRC))
+#define GST_IS_MULTIFILESRC_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MULTIFILESRC))
+
+typedef enum {
+ GST_MULTIFILESRC_OPEN = GST_ELEMENT_FLAG_LAST,
+ GST_MULTIFILESRC_NEWFILE = GST_ELEMENT_FLAG_LAST + 2,
+
+ GST_MULTIFILESRC_FLAG_LAST = GST_ELEMENT_FLAG_LAST + 4
+} GstMultiFileSrcFlags;
+
+typedef struct _GstMultiFileSrc GstMultiFileSrc;
+typedef struct _GstMultiFileSrcClass GstMultiFileSrcClass;
+
+struct _GstMultiFileSrc {
+ GstElement element;
+ /* pads */
+ GstPad *srcpad;
+
+ /* current file details */
+ gchar *currentfilename;
+ GSList *listptr;
+
+ /* mapping parameters */
+ gint fd;
+ gulong size; /* how long is the file? */
+ guchar *map; /* where the file is mapped to */
+
+ gint curfileindex; /* how many files have we done so far */
+
+ gboolean have_newmedia_events; /* tunable parameter to say whether new media
+ disconts should be generated */
+
+ gboolean new_seek;
+};
+
+struct _GstMultiFileSrcClass {
+ GstElementClass parent_class;
+
+ void (*new_file) (GstMultiFileSrc *multifilesrc, gchar *newfilename);
+};
+
+GType gst_multifilesrc_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_MULTIFILESRC_H__ */
--- /dev/null
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ * 2000 Wim Taymans <wtay@chello.be>
+ *
+ * gstpipefilter.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 <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "../gst-i18n-lib.h"
+#include "gstpipefilter.h"
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS_ANY);
+
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS_ANY);
+
+GST_DEBUG_CATEGORY_STATIC (gst_pipefilter_debug);
+#define GST_CAT_DEFAULT gst_pipefilter_debug
+
+GstElementDetails gst_pipefilter_details = GST_ELEMENT_DETAILS ("Pipefilter",
+ "Filter",
+ "Interoperate with an external program using stdin and stdout",
+ "Erik Walthinsen <omega@cse.ogi.edu>, "
+ "Wim Taymans <wim.taymans@chello.be>");
+
+
+/* Pipefilter signals and args */
+enum
+{
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum
+{
+ ARG_0,
+ ARG_COMMAND
+};
+
+
+#define _do_init(bla) \
+ GST_DEBUG_CATEGORY_INIT (gst_pipefilter_debug, "pipefilter", 0, "pipefilter element");
+
+GST_BOILERPLATE_FULL (GstPipefilter, gst_pipefilter, GstElement,
+ GST_TYPE_ELEMENT, _do_init);
+
+static void gst_pipefilter_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_pipefilter_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static GstData *gst_pipefilter_get (GstPad * pad);
+static void gst_pipefilter_chain (GstPad * pad, GstData * _data);
+static gboolean gst_pipefilter_handle_event (GstPad * pad, GstEvent * event);
+
+static GstElementStateReturn gst_pipefilter_change_state (GstElement * element);
+
+static void
+gst_pipefilter_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 (&srctemplate));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&sinktemplate));
+ gst_element_class_set_details (gstelement_class, &gst_pipefilter_details);
+}
+static void
+gst_pipefilter_class_init (GstPipefilterClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+
+
+ gobject_class->set_property = gst_pipefilter_set_property;
+ gobject_class->get_property = gst_pipefilter_get_property;
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_COMMAND, g_param_spec_string ("command", "command", "command", NULL, G_PARAM_READWRITE)); /* CHECKME */
+
+ gstelement_class->change_state = gst_pipefilter_change_state;
+}
+
+static void
+gst_pipefilter_init (GstPipefilter * pipefilter)
+{
+ GST_FLAG_SET (pipefilter, GST_ELEMENT_DECOUPLED);
+
+ pipefilter->sinkpad =
+ gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate),
+ "sink");
+ gst_element_add_pad (GST_ELEMENT (pipefilter), pipefilter->sinkpad);
+ gst_pad_set_chain_function (pipefilter->sinkpad, gst_pipefilter_chain);
+
+ pipefilter->srcpad =
+ gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
+ "src");
+ gst_element_add_pad (GST_ELEMENT (pipefilter), pipefilter->srcpad);
+ gst_pad_set_get_function (pipefilter->srcpad, gst_pipefilter_get);
+
+ pipefilter->command = NULL;
+ pipefilter->curoffset = 0;
+ pipefilter->bytes_per_read = 4096;
+ pipefilter->seq = 0;
+}
+
+static gboolean
+gst_pipefilter_handle_event (GstPad * pad, GstEvent * event)
+{
+ GstPipefilter *pipefilter;
+
+ pipefilter = GST_PIPEFILTER (gst_pad_get_parent (pad));
+
+ GST_DEBUG ("pipefilter: %s received event", GST_ELEMENT_NAME (pipefilter));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_EOS:
+ if (close (pipefilter->fdin[1]) < 0)
+ perror ("close");
+ if (close (pipefilter->fdout[0]) < 0)
+ perror ("close");
+ break;
+ default:
+ break;
+ }
+
+ gst_pad_event_default (pad, event);
+
+ return TRUE;
+}
+
+static GstData *
+gst_pipefilter_get (GstPad * pad)
+{
+ GstPipefilter *pipefilter;
+ GstBuffer *newbuf;
+ glong readbytes;
+
+ pipefilter = GST_PIPEFILTER (gst_pad_get_parent (pad));
+
+ /* create the buffer */
+ /* FIXME: should eventually use a bufferpool for this */
+ newbuf = gst_buffer_new ();
+ g_return_val_if_fail (newbuf, NULL);
+
+ /* allocate the space for the buffer data */
+ GST_BUFFER_DATA (newbuf) = g_malloc (pipefilter->bytes_per_read);
+ g_return_val_if_fail (GST_BUFFER_DATA (newbuf) != NULL, NULL);
+
+ /* read it in from the file */
+ GST_DEBUG ("attemting to read %ld bytes", pipefilter->bytes_per_read);
+ readbytes =
+ read (pipefilter->fdout[0], GST_BUFFER_DATA (newbuf),
+ pipefilter->bytes_per_read);
+ GST_DEBUG ("read %ld bytes", readbytes);
+ if (readbytes < 0) {
+ GST_ELEMENT_ERROR (pipefilter, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
+ return NULL;
+ }
+ /* if we didn't get as many bytes as we asked for, we're at EOF */
+ if (readbytes == 0) {
+ return GST_DATA (gst_event_new (GST_EVENT_EOS));
+
+ }
+
+ GST_BUFFER_OFFSET (newbuf) = pipefilter->curoffset;
+ GST_BUFFER_SIZE (newbuf) = readbytes;
+ pipefilter->curoffset += readbytes;
+
+ return GST_DATA (newbuf);
+}
+
+static void
+gst_pipefilter_chain (GstPad * pad, GstData * _data)
+{
+ GstBuffer *buf;
+ GstPipefilter *pipefilter;
+ glong writebytes;
+ guchar *data;
+ gulong size;
+
+ g_return_if_fail (pad != NULL);
+ g_return_if_fail (GST_IS_PAD (pad));
+
+ if (GST_IS_EVENT (_data)) {
+ gst_pipefilter_handle_event (pad, GST_EVENT (_data));
+ return;
+ }
+
+ pipefilter = GST_PIPEFILTER (gst_pad_get_parent (pad));
+
+ buf = GST_BUFFER (_data);
+ data = GST_BUFFER_DATA (buf);
+ size = GST_BUFFER_SIZE (buf);
+
+ GST_DEBUG ("attemting to write %ld bytes", size);
+ writebytes = write (pipefilter->fdin[1], data, size);
+ GST_DEBUG ("written %ld bytes", writebytes);
+ if (writebytes < 0) {
+ GST_ELEMENT_ERROR (pipefilter, RESOURCE, WRITE, (NULL), GST_ERROR_SYSTEM);
+ return;
+ }
+ gst_buffer_unref (buf);
+}
+
+static void
+gst_pipefilter_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstPipefilter *pipefilter;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail (GST_IS_PIPEFILTER (object));
+ pipefilter = GST_PIPEFILTER (object);
+
+ switch (prop_id) {
+ case ARG_COMMAND:
+ pipefilter->orig_command = g_strdup (g_value_get_string (value));
+ pipefilter->command = g_strsplit (g_value_get_string (value), " ", 0);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_pipefilter_get_property (GObject * object, guint prop_id, GValue * value,
+ GParamSpec * pspec)
+{
+ GstPipefilter *pipefilter;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail (GST_IS_PIPEFILTER (object));
+ pipefilter = GST_PIPEFILTER (object);
+
+ switch (prop_id) {
+ case ARG_COMMAND:
+ g_value_set_string (value, pipefilter->orig_command);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+/* open the file, necessary to go to RUNNING state */
+static gboolean
+gst_pipefilter_open_file (GstPipefilter * src)
+{
+ g_return_val_if_fail (!GST_FLAG_IS_SET (src, GST_PIPEFILTER_OPEN), FALSE);
+
+ pipe (src->fdin);
+ pipe (src->fdout);
+
+ if ((src->childpid = fork ()) == -1) {
+ GST_ELEMENT_ERROR (src, RESOURCE, TOO_LAZY, (NULL), GST_ERROR_SYSTEM);
+ return FALSE;
+ }
+
+ if (src->childpid == 0) {
+ close (src->fdin[1]);
+ close (src->fdout[0]);
+ /* child */
+ dup2 (src->fdin[0], STDIN_FILENO); /* set the childs input stream */
+ dup2 (src->fdout[1], STDOUT_FILENO); /* set the childs output stream */
+ execvp (src->command[0], &src->command[0]);
+ /* will only be reached if execvp has an error */
+ GST_ELEMENT_ERROR (src, RESOURCE, TOO_LAZY, (NULL), GST_ERROR_SYSTEM);
+ return FALSE;
+
+ } else {
+ close (src->fdin[0]);
+ close (src->fdout[1]);
+ }
+
+ GST_FLAG_SET (src, GST_PIPEFILTER_OPEN);
+ return TRUE;
+}
+
+/* close the file */
+static void
+gst_pipefilter_close_file (GstPipefilter * src)
+{
+ g_return_if_fail (GST_FLAG_IS_SET (src, GST_PIPEFILTER_OPEN));
+
+ /* close the file */
+ close (src->fdout[0]);
+ close (src->fdout[1]);
+ close (src->fdin[0]);
+ close (src->fdin[1]);
+
+ /* zero out a lot of our state */
+ src->curoffset = 0;
+ src->seq = 0;
+
+ GST_FLAG_UNSET (src, GST_PIPEFILTER_OPEN);
+}
+
+static GstElementStateReturn
+gst_pipefilter_change_state (GstElement * element)
+{
+ g_return_val_if_fail (GST_IS_PIPEFILTER (element), FALSE);
+
+ /* if going down into NULL state, close the file if it's open */
+ if (GST_STATE_PENDING (element) == GST_STATE_NULL) {
+ if (GST_FLAG_IS_SET (element, GST_PIPEFILTER_OPEN))
+ gst_pipefilter_close_file (GST_PIPEFILTER (element));
+ /* otherwise (READY or higher) we need to open the file */
+ } else {
+ if (!GST_FLAG_IS_SET (element, GST_PIPEFILTER_OPEN)) {
+ if (!gst_pipefilter_open_file (GST_PIPEFILTER (element)))
+ return GST_STATE_FAILURE;
+ }
+ }
+
+ if (GST_ELEMENT_CLASS (parent_class)->change_state)
+ return GST_ELEMENT_CLASS (parent_class)->change_state (element);
+ return GST_STATE_SUCCESS;
+}
--- /dev/null
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ * 2000 Wim Taymans <wtay@chello.be>
+ *
+ * gstpipefilter.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_PIPEFILTER_H__
+#define __GST_PIPEFILTER_H__
+
+#include <sys/types.h>
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+
+#define GST_TYPE_PIPEFILTER \
+ (gst_pipefilter_get_type())
+#define GST_PIPEFILTER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PIPEFILTER,GstPipefilter))
+#define GST_PIPEFILTER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PIPEFILTER,GstPipefilterClass))
+#define GST_IS_PIPEFILTER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PIPEFILTER))
+#define GST_IS_PIPEFILTER_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PIPEFILTER))
+
+typedef enum {
+ GST_PIPEFILTER_OPEN = GST_ELEMENT_FLAG_LAST,
+
+ GST_PIPEFILTER_FLAG_LAST = GST_ELEMENT_FLAG_LAST + 2
+} GstPipeFilterFlags;
+
+typedef struct _GstPipefilter GstPipefilter;
+typedef struct _GstPipefilterClass GstPipefilterClass;
+
+struct _GstPipefilter {
+ GstElement element;
+
+ GstPad *sinkpad;
+ GstPad *srcpad;
+
+ /* command */
+ gchar **command;
+ gchar *orig_command;
+ /* fd */
+ gint fdout[2];
+ gint fdin[2];
+ pid_t childpid;
+
+ gulong curoffset; /* current offset in file */
+ gulong bytes_per_read; /* bytes per read */
+
+ gulong seq; /* buffer sequence number */
+};
+
+struct _GstPipefilterClass {
+ GstElementClass parent_class;
+};
+
+GType gst_pipefilter_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_PIPEFILTER_H__ */
--- /dev/null
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ * 2000 Wim Taymans <wtay@chello.be>
+ *
+ * gstshaper.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 "gstshaper.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_shaper_debug);
+#define GST_CAT_DEFAULT gst_shaper_debug
+
+GstElementDetails gst_shaper_details = GST_ELEMENT_DETAILS ("Shaper",
+ "Generic",
+ "Synchronizes streams on different pads",
+ "Wim Taymans <wim.taymans@chello.be>");
+
+
+/* Shaper signals and args */
+enum
+{
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum
+{
+ ARG_0,
+ ARG_POLICY,
+ ARG_SILENT,
+ ARG_LAST_MESSAGE
+};
+
+typedef struct
+{
+ GstPad *sinkpad;
+ GstPad *srcpad;
+ GstBuffer *buffer;
+}
+GstShaperConnection;
+
+GstStaticPadTemplate shaper_src_template = GST_STATIC_PAD_TEMPLATE ("src%d",
+ GST_PAD_SRC,
+ GST_PAD_SOMETIMES,
+ GST_STATIC_CAPS_ANY);
+
+GstStaticPadTemplate shaper_sink_template = GST_STATIC_PAD_TEMPLATE ("sink%d",
+ GST_PAD_SINK,
+ GST_PAD_REQUEST,
+ GST_STATIC_CAPS_ANY);
+
+#define GST_TYPE_SHAPER_POLICY (gst_shaper_policy_get_type())
+static GType
+gst_shaper_policy_get_type (void)
+{
+ static GType shaper_policy_type = 0;
+ static GEnumValue shaper_policy[] = {
+ {SHAPER_POLICY_TIMESTAMPS, "1", "sync on timestamps"},
+ {SHAPER_POLICY_BUFFERSIZE, "2", "sync on buffer size"},
+ {0, NULL, NULL},
+ };
+
+ if (!shaper_policy_type) {
+ shaper_policy_type =
+ g_enum_register_static ("GstShaperPolicy", shaper_policy);
+ }
+ return shaper_policy_type;
+}
+
+#define _do_init(bla) \
+ GST_DEBUG_CATEGORY_INIT (gst_shaper_debug, "shaper", 0, "shaper element");
+
+GST_BOILERPLATE_FULL (GstShaper, gst_shaper, GstElement, GST_TYPE_ELEMENT,
+ _do_init);
+
+static void gst_shaper_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_shaper_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static GstPad *gst_shaper_request_new_pad (GstElement * element,
+ GstPadTemplate * templ, const gchar * unused);
+
+static void gst_shaper_loop (GstElement * element);
+
+
+static void
+gst_shaper_base_init (gpointer g_class)
+{
+ GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_set_details (gstelement_class, &gst_shaper_details);
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&shaper_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&shaper_sink_template));
+}
+
+static void
+gst_shaper_class_init (GstShaperClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+
+ gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_shaper_set_property);
+ gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_shaper_get_property);
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_POLICY,
+ g_param_spec_enum ("policy", "Policy", "Shaper policy",
+ GST_TYPE_SHAPER_POLICY, SHAPER_POLICY_TIMESTAMPS, G_PARAM_READWRITE));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT,
+ g_param_spec_boolean ("silent", "silent", "silent",
+ FALSE, G_PARAM_READWRITE));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
+ g_param_spec_string ("last-message", "last-message", "last-message",
+ NULL, G_PARAM_READABLE));
+
+ gstelement_class->request_new_pad =
+ GST_DEBUG_FUNCPTR (gst_shaper_request_new_pad);
+}
+
+static GstCaps *
+gst_shaper_getcaps (GstPad * pad)
+{
+ GstPad *otherpad;
+ GstShaperConnection *connection;
+
+ connection = gst_pad_get_element_private (pad);
+
+ otherpad =
+ (pad == connection->srcpad ? connection->sinkpad : connection->srcpad);
+
+ if (GST_PAD_PEER (otherpad)) {
+ return gst_pad_get_caps (GST_PAD_PEER (otherpad));
+ } else {
+ return gst_caps_new_any ();
+ }
+}
+
+static GList *
+gst_shaper_get_internal_link (GstPad * pad)
+{
+ GList *res = NULL;
+ GstShaperConnection *connection;
+ GstPad *otherpad;
+
+ connection = gst_pad_get_element_private (pad);
+
+ otherpad =
+ (pad == connection->srcpad ? connection->sinkpad : connection->srcpad);
+
+ res = g_list_prepend (res, otherpad);
+
+ return res;
+}
+
+static GstPadLinkReturn
+gst_shaper_link (GstPad * pad, const GstCaps * caps)
+{
+ GstPad *otherpad;
+ GstShaperConnection *connection;
+
+ connection = gst_pad_get_element_private (pad);
+
+ otherpad =
+ (pad == connection->srcpad ? connection->sinkpad : connection->srcpad);
+
+ return gst_pad_try_set_caps (otherpad, caps);
+}
+
+static GstShaperConnection *
+gst_shaper_create_connection (GstShaper * shaper)
+{
+ GstShaperConnection *connection;
+ gchar *padname;
+
+ shaper->nconnections++;
+
+ connection = g_new0 (GstShaperConnection, 1);
+
+ padname = g_strdup_printf ("sink%d", shaper->nconnections);
+ connection->sinkpad =
+ gst_pad_new_from_template (gst_static_pad_template_get
+ (&shaper_sink_template), padname);
+ g_free (padname);
+ gst_pad_set_getcaps_function (connection->sinkpad, gst_shaper_getcaps);
+ gst_pad_set_internal_link_function (connection->sinkpad,
+ gst_shaper_get_internal_link);
+ gst_pad_set_link_function (connection->sinkpad, gst_shaper_link);
+ gst_pad_set_element_private (connection->sinkpad, connection);
+ gst_element_add_pad (GST_ELEMENT (shaper), connection->sinkpad);
+
+ padname = g_strdup_printf ("src%d", shaper->nconnections);
+ connection->srcpad =
+ gst_pad_new_from_template (gst_static_pad_template_get
+ (&shaper_src_template), padname);
+ g_free (padname);
+ gst_pad_set_getcaps_function (connection->srcpad, gst_shaper_getcaps);
+ gst_pad_set_internal_link_function (connection->srcpad,
+ gst_shaper_get_internal_link);
+ gst_pad_set_link_function (connection->srcpad, gst_shaper_link);
+ gst_pad_set_element_private (connection->srcpad, connection);
+ gst_element_add_pad (GST_ELEMENT (shaper), connection->srcpad);
+
+ shaper->connections = g_slist_prepend (shaper->connections, connection);
+
+ return connection;
+}
+
+static GstPad *
+gst_shaper_request_new_pad (GstElement * element, GstPadTemplate * templ,
+ const gchar * unused)
+{
+ GstShaper *shaper = GST_SHAPER (element);
+ GstShaperConnection *connection;
+
+ connection = gst_shaper_create_connection (shaper);
+
+ return connection->sinkpad;
+}
+
+static void
+gst_shaper_init (GstShaper * shaper)
+{
+ gst_element_set_loop_function (GST_ELEMENT (shaper), gst_shaper_loop);
+
+ shaper->policy = SHAPER_POLICY_TIMESTAMPS;
+ shaper->connections = NULL;
+ shaper->nconnections = 0;
+ shaper->silent = FALSE;
+ shaper->last_message = NULL;
+}
+
+static void
+gst_shaper_loop (GstElement * element)
+{
+ GstShaper *shaper;
+ GSList *connections;
+ gboolean eos = TRUE;
+ GstShaperConnection *min = NULL;
+
+ shaper = GST_SHAPER (element);
+
+ /* first make sure we have a buffer on all pads */
+ connections = shaper->connections;
+ while (connections) {
+ GstShaperConnection *connection = (GstShaperConnection *) connections->data;
+
+ /* try to fill a connection without a buffer on a pad that is
+ * active */
+ if (connection->buffer == NULL && GST_PAD_IS_USABLE (connection->sinkpad)) {
+ GstBuffer *buffer;
+
+ buffer = GST_BUFFER (gst_pad_pull (connection->sinkpad));
+
+ /* events are simply pushed ASAP */
+ if (GST_IS_EVENT (buffer)) {
+ /* save event type as it will be unreffed after the next push */
+ GstEventType type = GST_EVENT_TYPE (buffer);
+
+ gst_pad_push (connection->srcpad, GST_DATA (buffer));
+
+ switch (type) {
+ /* on EOS we disable the pad so that we don't pull on
+ * it again and never get more data */
+ case GST_EVENT_EOS:
+ gst_pad_set_active (connection->sinkpad, FALSE);
+ break;
+ default:
+ break;
+ }
+ } else {
+ /* we store the buffer */
+ connection->buffer = buffer;
+ }
+ }
+ /* FIXME policy stuff goes here */
+ /* find connection with lowest timestamp */
+ if (min == NULL || (connection->buffer != NULL &&
+ (GST_BUFFER_TIMESTAMP (connection->buffer) <
+ GST_BUFFER_TIMESTAMP (min->buffer)))) {
+ min = connection;
+ }
+ connections = g_slist_next (connections);
+ }
+ /* if we have a connection with a buffer, push it */
+ if (min != NULL && min->buffer) {
+ gst_pad_push (min->srcpad, GST_DATA (min->buffer));
+ min->buffer = NULL;
+ /* since we pushed a buffer, it's not EOS */
+ eos = FALSE;
+ }
+
+ if (eos) {
+ gst_element_set_eos (element);
+ }
+}
+
+static void
+gst_shaper_set_property (GObject * object, guint prop_id, const GValue * value,
+ GParamSpec * pspec)
+{
+ GstShaper *shaper;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail (GST_IS_SHAPER (object));
+
+ shaper = GST_SHAPER (object);
+
+ switch (prop_id) {
+ case ARG_POLICY:
+ shaper->policy = g_value_get_enum (value);
+ break;
+ case ARG_SILENT:
+ shaper->silent = g_value_get_boolean (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_shaper_get_property (GObject * object, guint prop_id, GValue * value,
+ GParamSpec * pspec)
+{
+ GstShaper *shaper;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail (GST_IS_SHAPER (object));
+
+ shaper = GST_SHAPER (object);
+
+ switch (prop_id) {
+ case ARG_POLICY:
+ g_value_set_enum (value, shaper->policy);
+ break;
+ case ARG_SILENT:
+ g_value_set_boolean (value, shaper->silent);
+ break;
+ case ARG_LAST_MESSAGE:
+ g_value_set_string (value, shaper->last_message);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
--- /dev/null
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ * 2000 Wim Taymans <wtay@chello.be>
+ *
+ * gstshaper.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_SHAPER_H__
+#define __GST_SHAPER_H__
+
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+
+#define GST_TYPE_SHAPER \
+ (gst_shaper_get_type())
+#define GST_SHAPER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SHAPER,GstShaper))
+#define GST_SHAPER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SHAPER,GstShaperClass))
+#define GST_IS_SHAPER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SHAPER))
+#define GST_IS_SHAPER_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SHAPER))
+
+typedef enum {
+ SHAPER_POLICY_TIMESTAMPS = 1,
+ SHAPER_POLICY_BUFFERSIZE
+} GstShaperPolicyType;
+
+typedef struct _GstShaper GstShaper;
+typedef struct _GstShaperClass GstShaperClass;
+
+struct _GstShaper {
+ GstElement element;
+
+ GSList *connections;
+ gint nconnections;
+
+ GstShaperPolicyType policy;
+
+ gboolean silent;
+ gchar *last_message;
+};
+
+struct _GstShaperClass {
+ GstElementClass parent_class;
+};
+
+GType gst_shaper_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_SHAPER_H__ */
--- /dev/null
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ * 2000 Wim Taymans <wtay@chello.be>
+ *
+ * gststatistics.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.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "gststatistics.h"
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS_ANY);
+
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS_ANY);
+
+GST_DEBUG_CATEGORY_STATIC (gst_statistics_debug);
+#define GST_CAT_DEFAULT gst_statistics_debug
+
+GstElementDetails gst_statistics_details = GST_ELEMENT_DETAILS ("Statistics",
+ "Generic",
+ "Statistics on buffers/bytes/events",
+ "David I. Lehn <dlehn@users.sourceforge.net>");
+
+
+/* Statistics signals and args */
+enum
+{
+ SIGNAL_UPDATE,
+ LAST_SIGNAL
+};
+
+enum
+{
+ ARG_0,
+ ARG_BUFFERS,
+ ARG_BYTES,
+ ARG_EVENTS,
+ ARG_BUFFER_UPDATE_FREQ,
+ ARG_BYTES_UPDATE_FREQ,
+ ARG_EVENT_UPDATE_FREQ,
+ ARG_UPDATE_ON_EOS,
+ ARG_UPDATE,
+ ARG_SILENT
+};
+
+
+#define _do_init(bla) \
+ GST_DEBUG_CATEGORY_INIT (gst_statistics_debug, "statistics", 0, "statistics element");
+
+GST_BOILERPLATE_FULL (GstStatistics, gst_statistics, GstElement,
+ GST_TYPE_ELEMENT, _do_init);
+
+static void gst_statistics_finalize (GObject * object);
+static void gst_statistics_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_statistics_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static void gst_statistics_chain (GstPad * pad, GstData * _data);
+static void gst_statistics_reset (GstStatistics * statistics);
+static void gst_statistics_print (GstStatistics * statistics);
+
+static guint gst_statistics_signals[LAST_SIGNAL] = { 0, };
+
+static stats zero_stats = { 0, };
+
+
+static void
+gst_statistics_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 (&srctemplate));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&sinktemplate));
+ gst_element_class_set_details (gstelement_class, &gst_statistics_details);
+}
+
+static void
+gst_statistics_finalize (GObject * object)
+{
+ GstStatistics *statistics;
+
+ statistics = GST_STATISTICS (object);
+
+ if (statistics->timer)
+ g_timer_destroy (statistics->timer);
+
+ if (statistics->last_timer)
+ g_timer_destroy (statistics->last_timer);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_statistics_class_init (GstStatisticsClass * klass)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_statistics_set_property);
+ gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_statistics_get_property);
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BUFFERS,
+ g_param_spec_int64 ("buffers", "buffers", "total buffers count",
+ 0, G_MAXINT64, 0, G_PARAM_READABLE));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BYTES,
+ g_param_spec_int64 ("bytes", "bytes", "total bytes count",
+ 0, G_MAXINT64, 0, G_PARAM_READABLE));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_EVENTS,
+ g_param_spec_int64 ("events", "events", "total event count",
+ 0, G_MAXINT64, 0, G_PARAM_READABLE));
+ g_object_class_install_property (G_OBJECT_CLASS (klass),
+ ARG_BUFFER_UPDATE_FREQ, g_param_spec_int64 ("buffer_update_freq",
+ "buffer update freq", "buffer update frequency", 0, G_MAXINT64, 0,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (G_OBJECT_CLASS (klass),
+ ARG_BYTES_UPDATE_FREQ, g_param_spec_int64 ("bytes_update_freq",
+ "bytes update freq", "bytes update frequency", 0, G_MAXINT64, 0,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (G_OBJECT_CLASS (klass),
+ ARG_EVENT_UPDATE_FREQ, g_param_spec_int64 ("event_update_freq",
+ "event update freq", "event update frequency", 0, G_MAXINT64, 0,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_UPDATE_ON_EOS,
+ g_param_spec_boolean ("update_on_eos", "update on EOS",
+ "update on EOS event", TRUE, G_PARAM_READWRITE));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_UPDATE,
+ g_param_spec_boolean ("update", "update", "update", TRUE,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT,
+ g_param_spec_boolean ("silent", "silent", "silent", TRUE,
+ G_PARAM_READWRITE));
+
+ gst_statistics_signals[SIGNAL_UPDATE] =
+ g_signal_new ("update", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GstStatisticsClass, update), NULL, NULL,
+ g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+
+ gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_statistics_finalize);
+}
+
+static void
+gst_statistics_init (GstStatistics * statistics)
+{
+ statistics->sinkpad =
+ gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate),
+ "sink");
+ gst_element_add_pad (GST_ELEMENT (statistics), statistics->sinkpad);
+ gst_pad_set_chain_function (statistics->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_statistics_chain));
+
+ statistics->srcpad =
+ gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
+ "src");
+ gst_element_add_pad (GST_ELEMENT (statistics), statistics->srcpad);
+
+ statistics->timer = NULL;
+ statistics->last_timer = NULL;
+ gst_statistics_reset (statistics);
+}
+
+static void
+gst_statistics_reset (GstStatistics * statistics)
+{
+ g_return_if_fail (statistics != NULL);
+ g_return_if_fail (GST_IS_STATISTICS (statistics));
+
+ statistics->stats.buffers = 0;
+ statistics->stats.bytes = 0;
+ statistics->stats.events = 0;
+
+ statistics->last_stats.buffers = 0;
+ statistics->last_stats.bytes = 0;
+ statistics->last_stats.events = 0;
+
+ statistics->update_count.buffers = 0;
+ statistics->update_count.bytes = 0;
+ statistics->update_count.events = 0;
+
+ statistics->update_freq.buffers = 0;
+ statistics->update_freq.bytes = 0;
+ statistics->update_freq.events = 0;
+
+ statistics->update_on_eos = TRUE;
+ statistics->update = TRUE;
+ statistics->silent = FALSE;
+
+ if (!statistics->timer) {
+ statistics->timer = g_timer_new ();
+ }
+ if (!statistics->last_timer) {
+ statistics->last_timer = g_timer_new ();
+ }
+}
+
+static void
+print_stats (gboolean first, const gchar * name, const gchar * type,
+ stats * base, stats * final, double time)
+{
+ const gchar *header0 = "statistics";
+ const gchar *headerN = " ";
+ stats delta;
+
+ delta.buffers = final->buffers - base->buffers;
+ delta.bytes = final->bytes - base->bytes;
+ delta.events = final->events - base->events;
+
+ g_print ("%s: (%s) %s: s:%g buffers:%" G_GINT64_FORMAT
+ " bytes:%" G_GINT64_FORMAT
+ " events:%" G_GINT64_FORMAT "\n",
+ first ? header0 : headerN,
+ name, type, time, final->buffers, final->bytes, final->events);
+ g_print ("%s: (%s) %s: buf/s:%g B/s:%g e/s:%g B/buf:%g\n",
+ headerN,
+ name, type,
+ delta.buffers / time,
+ delta.bytes / time,
+ delta.events / time, ((double) delta.bytes / (double) delta.buffers));
+}
+
+static void
+gst_statistics_print (GstStatistics * statistics)
+{
+ const gchar *name;
+ double elapsed;
+ double last_elapsed;
+
+ g_return_if_fail (statistics != NULL);
+ g_return_if_fail (GST_IS_STATISTICS (statistics));
+
+ name = gst_object_get_name (GST_OBJECT (statistics));
+ if (!name) {
+ name = "";
+ }
+
+ elapsed = g_timer_elapsed (statistics->timer, NULL);
+ last_elapsed = g_timer_elapsed (statistics->last_timer, NULL);
+
+ print_stats (1, name, "total", &zero_stats, &statistics->stats, elapsed);
+ print_stats (0, name, "last", &statistics->last_stats, &statistics->stats,
+ last_elapsed);
+ statistics->last_stats = statistics->stats;
+ g_timer_reset (statistics->last_timer);
+}
+
+static void
+gst_statistics_chain (GstPad * pad, GstData * _data)
+{
+ GstBuffer *buf = GST_BUFFER (_data);
+ GstStatistics *statistics;
+ gboolean update = FALSE;
+
+ g_return_if_fail (pad != NULL);
+ g_return_if_fail (GST_IS_PAD (pad));
+ g_return_if_fail (buf != NULL);
+
+ statistics = GST_STATISTICS (gst_pad_get_parent (pad));
+
+ if (GST_IS_EVENT (buf)) {
+ GstEvent *event = GST_EVENT (buf);
+
+ statistics->stats.events += 1;
+ if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
+ gst_element_set_eos (GST_ELEMENT (statistics));
+ if (statistics->update_on_eos) {
+ update = TRUE;
+ }
+ }
+ if (statistics->update_freq.events) {
+ statistics->update_count.events += 1;
+ if (statistics->update_count.events == statistics->update_freq.events) {
+ statistics->update_count.events = 0;
+ update = TRUE;
+ }
+ }
+ } else {
+ statistics->stats.buffers += 1;
+ if (statistics->update_freq.buffers) {
+ statistics->update_count.buffers += 1;
+ if (statistics->update_count.buffers == statistics->update_freq.buffers) {
+ statistics->update_count.buffers = 0;
+ update = TRUE;
+ }
+ }
+
+ statistics->stats.bytes += GST_BUFFER_SIZE (buf);
+ if (statistics->update_freq.bytes) {
+ statistics->update_count.bytes += GST_BUFFER_SIZE (buf);
+ if (statistics->update_count.bytes >= statistics->update_freq.bytes) {
+ statistics->update_count.bytes = 0;
+ update = TRUE;
+ }
+ }
+ }
+
+ if (update) {
+ if (statistics->update) {
+ GST_DEBUG ("[%s]: pre update emit", GST_ELEMENT_NAME (statistics));
+ g_signal_emit (G_OBJECT (statistics),
+ gst_statistics_signals[SIGNAL_UPDATE], 0);
+ GST_DEBUG ("[%s]: post update emit", GST_ELEMENT_NAME (statistics));
+ }
+ if (!statistics->silent) {
+ gst_statistics_print (statistics);
+ }
+ }
+ gst_pad_push (statistics->srcpad, GST_DATA (buf));
+}
+
+static void
+gst_statistics_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstStatistics *statistics;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail (GST_IS_STATISTICS (object));
+
+ statistics = GST_STATISTICS (object);
+
+ switch (prop_id) {
+ case ARG_BUFFER_UPDATE_FREQ:
+ statistics->update_freq.buffers = g_value_get_int64 (value);
+ break;
+ case ARG_BYTES_UPDATE_FREQ:
+ statistics->update_freq.bytes = g_value_get_int64 (value);
+ break;
+ case ARG_EVENT_UPDATE_FREQ:
+ statistics->update_freq.events = g_value_get_int64 (value);
+ break;
+ case ARG_UPDATE_ON_EOS:
+ statistics->update_on_eos = g_value_get_boolean (value);
+ break;
+ case ARG_UPDATE:
+ statistics->update = g_value_get_boolean (value);
+ break;
+ case ARG_SILENT:
+ statistics->silent = g_value_get_boolean (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_statistics_get_property (GObject * object, guint prop_id, GValue * value,
+ GParamSpec * pspec)
+{
+ GstStatistics *statistics;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail (GST_IS_STATISTICS (object));
+
+ statistics = GST_STATISTICS (object);
+
+ switch (prop_id) {
+ case ARG_BUFFERS:
+ g_value_set_int64 (value, statistics->stats.buffers);
+ break;
+ case ARG_BYTES:
+ g_value_set_int64 (value, statistics->stats.bytes);
+ break;
+ case ARG_EVENTS:
+ g_value_set_int64 (value, statistics->stats.events);
+ break;
+ case ARG_BUFFER_UPDATE_FREQ:
+ g_value_set_int64 (value, statistics->update_freq.buffers);
+ break;
+ case ARG_BYTES_UPDATE_FREQ:
+ g_value_set_int64 (value, statistics->update_freq.bytes);
+ break;
+ case ARG_EVENT_UPDATE_FREQ:
+ g_value_set_int64 (value, statistics->update_freq.events);
+ break;
+ case ARG_UPDATE_ON_EOS:
+ g_value_set_boolean (value, statistics->update_on_eos);
+ break;
+ case ARG_UPDATE:
+ g_value_set_boolean (value, statistics->update);
+ break;
+ case ARG_SILENT:
+ g_value_set_boolean (value, statistics->silent);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
--- /dev/null
+/* GStreamer
+ * Copyright (C) 2001 David I. Lehn <dlehn@users.sourceforge.net>
+ *
+ * gststatistics.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_STATISTICS_H__
+#define __GST_STATISTICS_H__
+
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+
+#define GST_TYPE_STATISTICS \
+ (gst_statistics_get_type())
+#define GST_STATISTICS(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_STATISTICS,GstStatistics))
+#define GST_STATISTICS_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_STATISTICS,GstStatisticsClass))
+#define GST_IS_STATISTICS(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_STATISTICS))
+#define GST_IS_STATISTICS_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_STATISTICS))
+
+typedef struct _GstStatistics GstStatistics;
+typedef struct _GstStatisticsClass GstStatisticsClass;
+
+typedef struct _stats stats;
+
+struct _stats {
+ gint64 buffers;
+ gint64 bytes;
+ gint64 events;
+};
+
+struct _GstStatistics {
+ GstElement element;
+
+ GstPad *sinkpad;
+ GstPad *srcpad;
+
+ GTimer *timer;
+ GTimer *last_timer;
+
+ stats stats;
+ stats last_stats;
+ stats update_count;
+ stats update_freq;
+
+ gboolean update_on_eos;
+ gboolean update;
+ gboolean silent;
+};
+
+struct _GstStatisticsClass {
+ GstElementClass parent_class;
+
+ /* signals */
+ void (*update) (GstElement *element);
+};
+
+GType gst_statistics_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_STATISTICS_H__ */