From 924a50450fb0354821f4e8fedad5290e623362b2 Mon Sep 17 00:00:00 2001 From: David Schleef Date: Sun, 15 May 2005 23:06:37 +0000 Subject: Move core plugins out of core. I don't mind fdsrc/fdsink going back into the core; they were just disabled there, so Original commit message from CVS: 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: --- gst/oldcore/Makefile.am | 29 +++ gst/oldcore/gstaggregator.c | 379 ++++++++++++++++++++++++++++++++ gst/oldcore/gstaggregator.h | 74 +++++++ gst/oldcore/gstelements.c | 82 +++++++ gst/oldcore/gstfdsink.c | 172 +++++++++++++++ gst/oldcore/gstfdsink.h | 62 ++++++ gst/oldcore/gstmd5sink.c | 497 ++++++++++++++++++++++++++++++++++++++++++ gst/oldcore/gstmd5sink.h | 74 +++++++ gst/oldcore/gstmultifilesrc.c | 363 ++++++++++++++++++++++++++++++ gst/oldcore/gstmultifilesrc.h | 85 ++++++++ gst/oldcore/gstpipefilter.c | 356 ++++++++++++++++++++++++++++++ gst/oldcore/gstpipefilter.h | 81 +++++++ gst/oldcore/gstshaper.c | 373 +++++++++++++++++++++++++++++++ gst/oldcore/gstshaper.h | 72 ++++++ gst/oldcore/gststatistics.c | 416 +++++++++++++++++++++++++++++++++++ gst/oldcore/gststatistics.h | 84 +++++++ 16 files changed, 3199 insertions(+) create mode 100644 gst/oldcore/Makefile.am create mode 100644 gst/oldcore/gstaggregator.c create mode 100644 gst/oldcore/gstaggregator.h create mode 100644 gst/oldcore/gstelements.c create mode 100644 gst/oldcore/gstfdsink.c create mode 100644 gst/oldcore/gstfdsink.h create mode 100644 gst/oldcore/gstmd5sink.c create mode 100644 gst/oldcore/gstmd5sink.h create mode 100644 gst/oldcore/gstmultifilesrc.c create mode 100644 gst/oldcore/gstmultifilesrc.h create mode 100644 gst/oldcore/gstpipefilter.c create mode 100644 gst/oldcore/gstpipefilter.h create mode 100644 gst/oldcore/gstshaper.c create mode 100644 gst/oldcore/gstshaper.h create mode 100644 gst/oldcore/gststatistics.c create mode 100644 gst/oldcore/gststatistics.h (limited to 'gst/oldcore') diff --git a/gst/oldcore/Makefile.am b/gst/oldcore/Makefile.am new file mode 100644 index 00000000..c871c87b --- /dev/null +++ b/gst/oldcore/Makefile.am @@ -0,0 +1,29 @@ + +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 + diff --git a/gst/oldcore/gstaggregator.c b/gst/oldcore/gstaggregator.c new file mode 100644 index 00000000..ddd806cf --- /dev/null +++ b/gst/oldcore/gstaggregator.c @@ -0,0 +1,379 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * 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 "); + +/* 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"); +} diff --git a/gst/oldcore/gstaggregator.h b/gst/oldcore/gstaggregator.h new file mode 100644 index 00000000..24af881d --- /dev/null +++ b/gst/oldcore/gstaggregator.h @@ -0,0 +1,74 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * 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 + +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__ */ diff --git a/gst/oldcore/gstelements.c b/gst/oldcore/gstelements.c new file mode 100644 index 00000000..7c7d5a82 --- /dev/null +++ b/gst/oldcore/gstelements.c @@ -0,0 +1,82 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * 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 + +#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) diff --git a/gst/oldcore/gstfdsink.c b/gst/oldcore/gstfdsink.c new file mode 100644 index 00000000..1fca02c3 --- /dev/null +++ b/gst/oldcore/gstfdsink.c @@ -0,0 +1,172 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * 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 +#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 "); + + +/* 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; + } +} diff --git a/gst/oldcore/gstfdsink.h b/gst/oldcore/gstfdsink.h new file mode 100644 index 00000000..838705a7 --- /dev/null +++ b/gst/oldcore/gstfdsink.h @@ -0,0 +1,62 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * 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 + +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__ */ diff --git a/gst/oldcore/gstmd5sink.c b/gst/oldcore/gstmd5sink.c new file mode 100644 index 00000000..4ebbb4c4 --- /dev/null +++ b/gst/oldcore/gstmd5sink.c @@ -0,0 +1,497 @@ +/* GStreamer + * Copyright (C) 2002 Erik Walthinsen + * 2002 Wim Taymans + * + * 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 + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#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 "); + +/* 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); +} diff --git a/gst/oldcore/gstmd5sink.h b/gst/oldcore/gstmd5sink.h new file mode 100644 index 00000000..d2b8109a --- /dev/null +++ b/gst/oldcore/gstmd5sink.h @@ -0,0 +1,74 @@ +/* GStreamer + * Copyright (C) 2002 Erik Walthinsen + * 2002 Wim Taymans + * + * 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 + +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__ */ diff --git a/gst/oldcore/gstmultifilesrc.c b/gst/oldcore/gstmultifilesrc.c new file mode 100644 index 00000000..ea951736 --- /dev/null +++ b/gst/oldcore/gstmultifilesrc.c @@ -0,0 +1,363 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * 2001 Dominic Ludlam + * + * 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 +#include +#include +#include +#include +#include +#include + +#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 "); + +/* 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; +} diff --git a/gst/oldcore/gstmultifilesrc.h b/gst/oldcore/gstmultifilesrc.h new file mode 100644 index 00000000..077d69ec --- /dev/null +++ b/gst/oldcore/gstmultifilesrc.h @@ -0,0 +1,85 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * 2001 Dominic Ludlam + * + * 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 + +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__ */ diff --git a/gst/oldcore/gstpipefilter.c b/gst/oldcore/gstpipefilter.c new file mode 100644 index 00000000..f8021240 --- /dev/null +++ b/gst/oldcore/gstpipefilter.c @@ -0,0 +1,356 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * 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 +#include +#include +#include +#include +#include +#include + +#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 , " + "Wim Taymans "); + + +/* 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; +} diff --git a/gst/oldcore/gstpipefilter.h b/gst/oldcore/gstpipefilter.h new file mode 100644 index 00000000..08c3a471 --- /dev/null +++ b/gst/oldcore/gstpipefilter.h @@ -0,0 +1,81 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * 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 +#include + +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__ */ diff --git a/gst/oldcore/gstshaper.c b/gst/oldcore/gstshaper.c new file mode 100644 index 00000000..c14ab36a --- /dev/null +++ b/gst/oldcore/gstshaper.c @@ -0,0 +1,373 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * 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 + +#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 "); + + +/* 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; + } +} diff --git a/gst/oldcore/gstshaper.h b/gst/oldcore/gstshaper.h new file mode 100644 index 00000000..1fe84e51 --- /dev/null +++ b/gst/oldcore/gstshaper.h @@ -0,0 +1,72 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * 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 + +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__ */ diff --git a/gst/oldcore/gststatistics.c b/gst/oldcore/gststatistics.c new file mode 100644 index 00000000..ef6cca3b --- /dev/null +++ b/gst/oldcore/gststatistics.c @@ -0,0 +1,416 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * 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 "); + + +/* 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; + } +} diff --git a/gst/oldcore/gststatistics.h b/gst/oldcore/gststatistics.h new file mode 100644 index 00000000..4c1ab57a --- /dev/null +++ b/gst/oldcore/gststatistics.h @@ -0,0 +1,84 @@ +/* GStreamer + * Copyright (C) 2001 David I. Lehn + * + * 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 + +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__ */ -- cgit