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:
This commit is contained in:
David Schleef 2005-05-15 23:06:37 +00:00
parent 3ad1774754
commit 924a50450f
17 changed files with 3223 additions and 0 deletions

View file

@ -1,3 +1,27 @@
2005-05-15 David Schleef <ds@schleef.org>
Move core plugins out of core. I don't mind fdsrc/fdsink
going back into the core; they were just disabled there, so
I moved them. Some of this stuff could (should) be deleted.
* gst/oldcore/Makefile.am:
* gst/oldcore/gstaggregator.c:
* gst/oldcore/gstaggregator.h:
* gst/oldcore/gstelements.c:
* gst/oldcore/gstfdsink.c:
* gst/oldcore/gstfdsink.h:
* gst/oldcore/gstfdsrc.c:
* gst/oldcore/gstfdsrc.h:
* gst/oldcore/gstmd5sink.c:
* gst/oldcore/gstmd5sink.h:
* gst/oldcore/gstmultifilesrc.c:
* gst/oldcore/gstmultifilesrc.h:
* gst/oldcore/gstpipefilter.c:
* gst/oldcore/gstpipefilter.h:
* gst/oldcore/gstshaper.c:
* gst/oldcore/gstshaper.h:
* gst/oldcore/gststatistics.c:
* gst/oldcore/gststatistics.h:
2005-05-13 Christian Schaller <uraeus@gnome.org> 2005-05-13 Christian Schaller <uraeus@gnome.org>
* ext/Makefile.am: dist esd directory * ext/Makefile.am: dist esd directory

29
gst/oldcore/Makefile.am Normal file
View file

@ -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

379
gst/oldcore/gstaggregator.c Normal file
View file

@ -0,0 +1,379 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wim.taymans@chello.be>
*
* gstaggregator.c: Aggregator element, N in 1 out
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "gstaggregator.h"
static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
GST_DEBUG_CATEGORY_STATIC (gst_aggregator_debug);
#define GST_CAT_DEFAULT gst_aggregator_debug
GstElementDetails gst_aggregator_details =
GST_ELEMENT_DETAILS ("Aggregator pipe fitting",
"Generic",
"N-to-1 pipe fitting",
"Wim Taymans <wim.taymans@chello.be>");
/* Aggregator signals and args */
enum
{
/* FILL ME */
LAST_SIGNAL
};
enum
{
ARG_0,
ARG_NUM_PADS,
ARG_SILENT,
ARG_SCHED,
ARG_LAST_MESSAGE
/* FILL ME */
};
GstStaticPadTemplate aggregator_src_template =
GST_STATIC_PAD_TEMPLATE ("sink%d",
GST_PAD_SINK,
GST_PAD_REQUEST,
GST_STATIC_CAPS_ANY);
#define GST_TYPE_AGGREGATOR_SCHED (gst_aggregator_sched_get_type())
static GType
gst_aggregator_sched_get_type (void)
{
static GType aggregator_sched_type = 0;
static GEnumValue aggregator_sched[] = {
{AGGREGATOR_LOOP, "1", "Loop Based"},
{AGGREGATOR_LOOP_SELECT, "3", "Loop Based Select"},
{AGGREGATOR_CHAIN, "4", "Chain Based"},
{0, NULL, NULL},
};
if (!aggregator_sched_type) {
aggregator_sched_type =
g_enum_register_static ("GstAggregatorSched", aggregator_sched);
}
return aggregator_sched_type;
}
#define AGGREGATOR_IS_LOOP_BASED(ag) ((ag)->sched != AGGREGATOR_CHAIN)
static GstPad *gst_aggregator_request_new_pad (GstElement * element,
GstPadTemplate * temp, const gchar * unused);
static void gst_aggregator_update_functions (GstAggregator * aggregator);
static void gst_aggregator_finalize (GObject * object);
static void gst_aggregator_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_aggregator_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_aggregator_chain (GstPad * pad, GstData * _data);
static void gst_aggregator_loop (GstElement * element);
#define _do_init(bla) \
GST_DEBUG_CATEGORY_INIT (gst_aggregator_debug, "aggregator", 0, "aggregator element");
GST_BOILERPLATE_FULL (GstAggregator, gst_aggregator, GstElement,
GST_TYPE_ELEMENT, _do_init);
static void
gst_aggregator_base_init (gpointer g_class)
{
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&aggregator_src_template));
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&srctemplate));
gst_element_class_set_details (gstelement_class, &gst_aggregator_details);
}
static void
gst_aggregator_finalize (GObject * object)
{
GstAggregator *aggregator;
aggregator = GST_AGGREGATOR (object);
g_list_free (aggregator->sinkpads);
g_free (aggregator->last_message);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gst_aggregator_class_init (GstAggregatorClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_aggregator_set_property);
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_aggregator_get_property);
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUM_PADS,
g_param_spec_int ("num_pads", "Num pads", "The number of source pads",
0, G_MAXINT, 0, G_PARAM_READABLE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT,
g_param_spec_boolean ("silent", "Silent", "Don't produce messages",
FALSE, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SCHED,
g_param_spec_enum ("sched", "Scheduling",
"The type of scheduling this element should use",
GST_TYPE_AGGREGATOR_SCHED, AGGREGATOR_CHAIN, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
g_param_spec_string ("last_message", "Last message",
"The current state of the element", NULL, G_PARAM_READABLE));
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_aggregator_finalize);
gstelement_class->request_new_pad =
GST_DEBUG_FUNCPTR (gst_aggregator_request_new_pad);
}
static void
gst_aggregator_init (GstAggregator * aggregator)
{
aggregator->srcpad =
gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
"src");
gst_pad_set_getcaps_function (aggregator->srcpad, gst_pad_proxy_getcaps);
gst_element_add_pad (GST_ELEMENT (aggregator), aggregator->srcpad);
aggregator->numsinkpads = 0;
aggregator->sinkpads = NULL;
aggregator->silent = FALSE;
aggregator->sched = AGGREGATOR_LOOP;
aggregator->last_message = NULL;
gst_aggregator_update_functions (aggregator);
}
static GstPad *
gst_aggregator_request_new_pad (GstElement * element, GstPadTemplate * templ,
const gchar * unused)
{
gchar *name;
GstPad *sinkpad;
GstAggregator *aggregator;
g_return_val_if_fail (GST_IS_AGGREGATOR (element), NULL);
if (templ->direction != GST_PAD_SINK) {
g_warning ("gstaggregator: request new pad that is not a sink pad\n");
return NULL;
}
aggregator = GST_AGGREGATOR (element);
name = g_strdup_printf ("sink%d", aggregator->numsinkpads);
sinkpad = gst_pad_new_from_template (templ, name);
g_free (name);
if (!AGGREGATOR_IS_LOOP_BASED (aggregator)) {
gst_pad_set_chain_function (sinkpad, gst_aggregator_chain);
}
gst_pad_set_getcaps_function (sinkpad, gst_pad_proxy_getcaps);
gst_element_add_pad (GST_ELEMENT (aggregator), sinkpad);
aggregator->sinkpads = g_list_prepend (aggregator->sinkpads, sinkpad);
aggregator->numsinkpads++;
return sinkpad;
}
static void
gst_aggregator_update_functions (GstAggregator * aggregator)
{
GList *pads;
if (AGGREGATOR_IS_LOOP_BASED (aggregator)) {
gst_element_set_loop_function (GST_ELEMENT (aggregator),
GST_DEBUG_FUNCPTR (gst_aggregator_loop));
} else {
gst_element_set_loop_function (GST_ELEMENT (aggregator), NULL);
}
pads = aggregator->sinkpads;
while (pads) {
GstPad *pad = GST_PAD (pads->data);
if (AGGREGATOR_IS_LOOP_BASED (aggregator)) {
gst_pad_set_get_function (pad, NULL);
} else {
gst_element_set_loop_function (GST_ELEMENT (aggregator), NULL);
}
pads = g_list_next (pads);
}
}
static void
gst_aggregator_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstAggregator *aggregator;
/* it's not null if we got it, but it might not be ours */
g_return_if_fail (GST_IS_AGGREGATOR (object));
aggregator = GST_AGGREGATOR (object);
switch (prop_id) {
case ARG_SILENT:
aggregator->silent = g_value_get_boolean (value);
break;
case ARG_SCHED:
aggregator->sched = g_value_get_enum (value);
gst_aggregator_update_functions (aggregator);
break;
default:
break;
}
}
static void
gst_aggregator_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
GstAggregator *aggregator;
/* it's not null if we got it, but it might not be ours */
g_return_if_fail (GST_IS_AGGREGATOR (object));
aggregator = GST_AGGREGATOR (object);
switch (prop_id) {
case ARG_NUM_PADS:
g_value_set_int (value, aggregator->numsinkpads);
break;
case ARG_SILENT:
g_value_set_boolean (value, aggregator->silent);
break;
case ARG_SCHED:
g_value_set_enum (value, aggregator->sched);
break;
case ARG_LAST_MESSAGE:
g_value_set_string (value, aggregator->last_message);
break;
default:
break;
}
}
static void
gst_aggregator_push (GstAggregator * aggregator, GstPad * pad, GstBuffer * buf,
guchar * debug)
{
if (!aggregator->silent) {
g_free (aggregator->last_message);
aggregator->last_message =
g_strdup_printf ("%10.10s ******* (%s:%s)a (%d bytes, %"
G_GUINT64_FORMAT ")", debug, GST_DEBUG_PAD_NAME (pad),
GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf));
g_object_notify (G_OBJECT (aggregator), "last_message");
}
gst_pad_push (aggregator->srcpad, GST_DATA (buf));
}
static void
gst_aggregator_loop (GstElement * element)
{
GstAggregator *aggregator;
GstBuffer *buf;
guchar *debug;
aggregator = GST_AGGREGATOR (element);
if (aggregator->sched == AGGREGATOR_LOOP) {
GList *pads = aggregator->sinkpads;
/* we'll loop over all pads and try to pull from all
* active ones */
while (pads) {
GstPad *pad = GST_PAD (pads->data);
pads = g_list_next (pads);
/* we need to check is the pad is usable. IS_USABLE will check
* if the pad is linked, if it is enabled (the element is
* playing and the app didn't gst_pad_set_enabled (pad, FALSE))
* and that the peer pad is also enabled.
*/
if (GST_PAD_IS_USABLE (pad)) {
buf = GST_BUFFER (gst_pad_pull (pad));
debug = "loop";
/* then push it forward */
gst_aggregator_push (aggregator, pad, buf, debug);
}
}
} else {
if (aggregator->sched == AGGREGATOR_LOOP_SELECT) {
GstPad *pad;
debug = "loop_select";
buf = GST_BUFFER (gst_pad_collectv (&pad, aggregator->sinkpads));
gst_aggregator_push (aggregator, pad, buf, debug);
} else {
g_assert_not_reached ();
}
}
}
/**
* gst_aggregator_chain:
* @pad: the pad to follow
* @buf: the buffer to pass
*
* Chain a buffer on a pad.
*/
static void
gst_aggregator_chain (GstPad * pad, GstData * _data)
{
GstBuffer *buf = GST_BUFFER (_data);
GstAggregator *aggregator;
g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_PAD (pad));
g_return_if_fail (buf != NULL);
aggregator = GST_AGGREGATOR (gst_pad_get_parent (pad));
/* gst_trace_add_entry (NULL, 0, buf, "aggregator buffer");*/
gst_aggregator_push (aggregator, pad, buf, "chain");
}

View file

@ -0,0 +1,74 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
*
* gstaggregator.h: Header for GstAggregator element
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_AGGREGATOR_H__
#define __GST_AGGREGATOR_H__
#include <gst/gst.h>
G_BEGIN_DECLS
typedef enum {
AGGREGATOR_LOOP = 1,
AGGREGATOR_LOOP_SELECT,
AGGREGATOR_CHAIN
} GstAggregatorSchedType;
#define GST_TYPE_AGGREGATOR \
(gst_aggregator_get_type())
#define GST_AGGREGATOR(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AGGREGATOR,GstAggregator))
#define GST_AGGREGATOR_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AGGREGATOR,GstAggregatorClass))
#define GST_IS_AGGREGATOR(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AGGREGATOR))
#define GST_IS_AGGREGATOR_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AGGREGATOR))
typedef struct _GstAggregator GstAggregator;
typedef struct _GstAggregatorClass GstAggregatorClass;
struct _GstAggregator {
GstElement element;
GstPad *srcpad;
gboolean silent;
GstAggregatorSchedType sched;
gint numsinkpads;
GList *sinkpads;
gchar *last_message;
};
struct _GstAggregatorClass {
GstElementClass parent_class;
};
GType gst_aggregator_get_type (void);
G_END_DECLS
#endif /* __GST_AGGREGATOR_H__ */

82
gst/oldcore/gstelements.c Normal file
View file

@ -0,0 +1,82 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
*
* gstelements.c:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <gst/gst.h>
#include "gstaggregator.h"
#include "gstfdsink.h"
#include "gstfdsrc.h"
#include "gstmd5sink.h"
#include "gstmultifilesrc.h"
#include "gstpipefilter.h"
#include "gstshaper.h"
#include "gststatistics.h"
struct _elements_entry
{
gchar *name;
guint rank;
GType (*type) (void);
};
extern GType gst_capsfilter_get_type (void);
extern GType gst_filesrc_get_type (void);
extern GstElementDetails gst_filesrc_details;
static struct _elements_entry _elements[] = {
{"aggregator", GST_RANK_NONE, gst_aggregator_get_type},
{"fdsink", GST_RANK_NONE, gst_fdsink_get_type},
{"fdsrc", GST_RANK_NONE, gst_fdsrc_get_type},
{"md5sink", GST_RANK_NONE, gst_md5sink_get_type},
{"multifilesrc", GST_RANK_NONE, gst_multifilesrc_get_type},
{"pipefilter", GST_RANK_NONE, gst_pipefilter_get_type},
{"shaper", GST_RANK_NONE, gst_shaper_get_type},
{"statistics", GST_RANK_NONE, gst_statistics_get_type},
{NULL, 0},
};
static gboolean
plugin_init (GstPlugin * plugin)
{
struct _elements_entry *my_elements = _elements;
while ((*my_elements).name) {
if (!gst_element_register (plugin, (*my_elements).name, (*my_elements).rank,
((*my_elements).type) ()))
return FALSE;
my_elements++;
}
return TRUE;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"gstelements",
"standard GStreamer elements",
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE, GST_ORIGIN)

172
gst/oldcore/gstfdsink.c Normal file
View file

@ -0,0 +1,172 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
*
* gstfdsink.c:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "gstfdsink.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
GST_DEBUG_CATEGORY_STATIC (gst_fdsink_debug);
#define GST_CAT_DEFAULT gst_fdsink_debug
GstElementDetails gst_fdsink_details =
GST_ELEMENT_DETAILS ("Filedescriptor Sink",
"Sink/File",
"Write data to a file descriptor",
"Erik Walthinsen <omega@cse.ogi.edu>");
/* FdSink signals and args */
enum
{
/* FILL ME */
LAST_SIGNAL
};
enum
{
ARG_0,
ARG_FD
};
#define _do_init(bla) \
GST_DEBUG_CATEGORY_INIT (gst_fdsink_debug, "fdsink", 0, "fdsink element");
GST_BOILERPLATE_FULL (GstFdSink, gst_fdsink, GstElement, GST_TYPE_ELEMENT,
_do_init);
static void gst_fdsink_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_fdsink_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_fdsink_chain (GstPad * pad, GstData * _data);
static void
gst_fdsink_base_init (gpointer g_class)
{
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&sinktemplate));
gst_element_class_set_details (gstelement_class, &gst_fdsink_details);
}
static void
gst_fdsink_class_init (GstFdSinkClass * klass)
{
GObjectClass *gobject_class;
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->set_property = gst_fdsink_set_property;
gobject_class->get_property = gst_fdsink_get_property;
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FD,
g_param_spec_int ("fd", "fd", "An open file descriptor to write to",
0, G_MAXINT, 1, G_PARAM_READWRITE));
}
static void
gst_fdsink_init (GstFdSink * fdsink)
{
fdsink->sinkpad =
gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate),
"sink");
gst_element_add_pad (GST_ELEMENT (fdsink), fdsink->sinkpad);
gst_pad_set_chain_function (fdsink->sinkpad, gst_fdsink_chain);
fdsink->fd = 1;
}
static void
gst_fdsink_chain (GstPad * pad, GstData * _data)
{
GstBuffer *buf = GST_BUFFER (_data);
GstFdSink *fdsink;
g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_PAD (pad));
g_return_if_fail (buf != NULL);
fdsink = GST_FDSINK (gst_pad_get_parent (pad));
g_return_if_fail (fdsink->fd >= 0);
if (GST_BUFFER_DATA (buf)) {
GST_DEBUG ("writing %d bytes to file descriptor %d", GST_BUFFER_SIZE (buf),
fdsink->fd);
write (fdsink->fd, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
}
gst_buffer_unref (buf);
}
static void
gst_fdsink_set_property (GObject * object, guint prop_id, const GValue * value,
GParamSpec * pspec)
{
GstFdSink *fdsink;
/* it's not null if we got it, but it might not be ours */
g_return_if_fail (GST_IS_FDSINK (object));
fdsink = GST_FDSINK (object);
switch (prop_id) {
case ARG_FD:
fdsink->fd = g_value_get_int (value);
break;
default:
break;
}
}
static void
gst_fdsink_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
GstFdSink *fdsink;
/* it's not null if we got it, but it might not be ours */
g_return_if_fail (GST_IS_FDSINK (object));
fdsink = GST_FDSINK (object);
switch (prop_id) {
case ARG_FD:
g_value_set_int (value, fdsink->fd);
break;
default:
break;
}
}

62
gst/oldcore/gstfdsink.h Normal file
View file

@ -0,0 +1,62 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
*
* gstfdsink.h:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_FDSINK_H__
#define __GST_FDSINK_H__
#include <gst/gst.h>
G_BEGIN_DECLS
#define GST_TYPE_FDSINK \
(gst_fdsink_get_type())
#define GST_FDSINK(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FDSINK,GstFdSink))
#define GST_FDSINK_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FDSINK,GstFdSinkClass))
#define GST_IS_FDSINK(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FDSINK))
#define GST_IS_FDSINK_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FDSINK))
typedef struct _GstFdSink GstFdSink;
typedef struct _GstFdSinkClass GstFdSinkClass;
struct _GstFdSink {
GstElement element;
GstPad *sinkpad;
int fd;
};
struct _GstFdSinkClass {
GstElementClass parent_class;
};
GType gst_fdsink_get_type(void);
G_END_DECLS
#endif /* __GST_FDSINK_H__ */

497
gst/oldcore/gstmd5sink.c Normal file
View file

@ -0,0 +1,497 @@
/* GStreamer
* Copyright (C) 2002 Erik Walthinsen <omega@cse.ogi.edu>
* 2002 Wim Taymans <wim.taymans@chello.be>
*
* gstmd5sink.c: A sink computing an md5 checksum from a stream
*
* The md5 code was taken from glibc-2.2.3/crypt/md5.c and slightly
* modified.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <string.h>
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <gst/gst.h>
#include "gstmd5sink.h"
GST_DEBUG_CATEGORY_STATIC (gst_md5sink_debug);
#define GST_CAT_DEFAULT gst_md5sink_debug
GstElementDetails gst_md5sink_details = GST_ELEMENT_DETAILS ("MD5 Sink",
"Sink",
"compute MD5 for incoming data",
"Benjamin Otte <in7y118@public.uni-hamburg.de>");
/* MD5Sink signals and args */
enum
{
/* FILL ME */
LAST_SIGNAL
};
enum
{
ARG_0,
ARG_MD5
/* FILL ME */
};
GstStaticPadTemplate md5_sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
#define _do_init(bla) \
GST_DEBUG_CATEGORY_INIT (gst_md5sink_debug, "md5sink", 0, "md5sink element");
GST_BOILERPLATE_FULL (GstMD5Sink, gst_md5sink, GstElement, GST_TYPE_ELEMENT,
_do_init);
/* GObject stuff */
/*static void gst_md5sink_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec);*/
static void gst_md5sink_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_md5sink_chain (GstPad * pad, GstData * _data);
static GstElementStateReturn gst_md5sink_change_state (GstElement * element);
/* MD5 stuff */
static void md5_init_ctx (GstMD5Sink * ctx);
static gpointer md5_read_ctx (GstMD5Sink * ctx, gpointer resbuf);
static gpointer md5_finish_ctx (GstMD5Sink * ctx, gpointer resbuf);
static void md5_process_bytes (const void *buffer, size_t len,
GstMD5Sink * ctx);
static void md5_process_block (const void *buffer, size_t len,
GstMD5Sink * ctx);
/* This array contains the bytes used to pad the buffer to the next
64-byte boundary. (RFC 1321, 3.1: Step 1) */
static const guchar fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
/* MD5 functions */
/* Initialize structure containing state of computation.
(RFC 1321, 3.3: Step 3) */
static void
md5_init_ctx (GstMD5Sink * ctx)
{
ctx->A = 0x67452301;
ctx->B = 0xefcdab89;
ctx->C = 0x98badcfe;
ctx->D = 0x10325476;
ctx->total[0] = ctx->total[1] = 0;
ctx->buflen = 0;
}
/* Process the remaining bytes in the internal buffer and the usual
prolog according to the standard and write the result to RESBUF.
IMPORTANT: On some systems it is required that RESBUF is correctly
aligned for a 32 bits value. */
static gpointer
md5_finish_ctx (GstMD5Sink * ctx, gpointer resbuf)
{
/* Take yet unprocessed bytes into account. */
guint32 bytes = ctx->buflen;
size_t pad;
/* Now count remaining bytes. */
ctx->total[0] += bytes;
if (ctx->total[0] < bytes)
++ctx->total[1];
pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
memcpy (&ctx->buffer[bytes], fillbuf, pad);
/* Put the 64-bit file length in *bits* at the end of the buffer. */
*(guint32 *) & ctx->buffer[bytes + pad] = GUINT32_TO_LE (ctx->total[0] << 3);
*(guint32 *) & ctx->buffer[bytes + pad + 4] =
GUINT32_TO_LE ((ctx->total[1] << 3) | (ctx->total[0] >> 29));
/* Process last bytes. */
md5_process_block (ctx->buffer, bytes + pad + 8, ctx);
return md5_read_ctx (ctx, resbuf);
}
/* Put result from CTX in first 16 bytes following RESBUF. The result
must be in little endian byte order.
IMPORTANT: On some systems it is required that RESBUF is correctly
aligned for a 32 bits value. */
static gpointer
md5_read_ctx (GstMD5Sink * ctx, gpointer resbuf)
{
((guint32 *) resbuf)[0] = GUINT32_TO_LE (ctx->A);
((guint32 *) resbuf)[1] = GUINT32_TO_LE (ctx->B);
((guint32 *) resbuf)[2] = GUINT32_TO_LE (ctx->C);
((guint32 *) resbuf)[3] = GUINT32_TO_LE (ctx->D);
return resbuf;
}
static void
md5_process_bytes (const void *buffer, size_t len, GstMD5Sink * ctx)
{
/*const void aligned_buffer = buffer; */
/* When we already have some bits in our internal buffer concatenate
both inputs first. */
if (ctx->buflen != 0) {
size_t left_over = ctx->buflen;
size_t add = 128 - left_over > len ? len : 128 - left_over;
/* Only put full words in the buffer. */
/* Forcing alignment here appears to be only an optimization.
* The glibc source uses __alignof__, which seems to be a
* gratuitous usage of a GCC extension, when sizeof() will
* work fine. (And don't question the sanity of using
* sizeof(guint32) instead of 4. */
/* add -= add % __alignof__ (guint32); */
add -= add % sizeof (guint32);
memcpy (&ctx->buffer[left_over], buffer, add);
ctx->buflen += add;
if (ctx->buflen > 64) {
md5_process_block (ctx->buffer, ctx->buflen & ~63, ctx);
ctx->buflen &= 63;
/* The regions in the following copy operation cannot overlap. */
memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63], ctx->buflen);
}
buffer = (const char *) buffer + add;
len -= add;
}
/* Process available complete blocks. */
if (len > 64) {
md5_process_block (buffer, len & ~63, ctx);
buffer = (const char *) buffer + (len & ~63);
len &= 63;
}
/* Move remaining bytes in internal buffer. */
if (len > 0) {
size_t left_over = ctx->buflen;
memcpy (&ctx->buffer[left_over], buffer, len);
left_over += len;
if (left_over >= 64) {
md5_process_block (ctx->buffer, 64, ctx);
left_over -= 64;
memcpy (ctx->buffer, &ctx->buffer[64], left_over);
}
ctx->buflen = left_over;
}
}
/* These are the four functions used in the four steps of the MD5 algorithm
and defined in the RFC 1321. The first function is a little bit optimized
(as found in Colin Plumbs public domain implementation). */
/* #define FF(b, c, d) ((b & c) | (~b & d)) */
#define FF(b, c, d) (d ^ (b & (c ^ d)))
#define FG(b, c, d) FF (d, b, c)
#define FH(b, c, d) (b ^ c ^ d)
#define FI(b, c, d) (c ^ (b | ~d))
/* Process LEN bytes of BUFFER, accumulating context into CTX.
It is assumed that LEN % 64 == 0. */
static void
md5_process_block (const void *buffer, size_t len, GstMD5Sink * ctx)
{
guint32 correct_words[16];
const guint32 *words = buffer;
size_t nwords = len / sizeof (guint32);
const guint32 *endp = words + nwords;
guint32 A = ctx->A;
guint32 B = ctx->B;
guint32 C = ctx->C;
guint32 D = ctx->D;
/* First increment the byte count. RFC 1321 specifies the possible
length of the file up to 2^64 bits. Here we only compute the
number of bytes. Do a double word increment. */
ctx->total[0] += len;
if (ctx->total[0] < len)
++ctx->total[1];
/* Process all bytes in the buffer with 64 bytes in each round of
the loop. */
while (words < endp) {
guint32 *cwp = correct_words;
guint32 A_save = A;
guint32 B_save = B;
guint32 C_save = C;
guint32 D_save = D;
/* First round: using the given function, the context and a constant
the next context is computed. Because the algorithms processing
unit is a 32-bit word and it is determined to work on words in
little endian byte order we perhaps have to change the byte order
before the computation. To reduce the work for the next steps
we store the swapped words in the array CORRECT_WORDS. */
#define OP(a, b, c, d, s, T) \
do \
{ \
a += FF (b, c, d) + (*cwp++ = GUINT32_TO_LE (*words)) + T; \
++words; \
CYCLIC (a, s); \
a += b; \
} \
while (0)
/* It is unfortunate that C does not provide an operator for
cyclic rotation. Hope the C compiler is smart enough. */
#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
/* Before we start, one word to the strange constants.
They are defined in RFC 1321 as
T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
*/
/* Round 1. */
OP (A, B, C, D, 7, 0xd76aa478);
OP (D, A, B, C, 12, 0xe8c7b756);
OP (C, D, A, B, 17, 0x242070db);
OP (B, C, D, A, 22, 0xc1bdceee);
OP (A, B, C, D, 7, 0xf57c0faf);
OP (D, A, B, C, 12, 0x4787c62a);
OP (C, D, A, B, 17, 0xa8304613);
OP (B, C, D, A, 22, 0xfd469501);
OP (A, B, C, D, 7, 0x698098d8);
OP (D, A, B, C, 12, 0x8b44f7af);
OP (C, D, A, B, 17, 0xffff5bb1);
OP (B, C, D, A, 22, 0x895cd7be);
OP (A, B, C, D, 7, 0x6b901122);
OP (D, A, B, C, 12, 0xfd987193);
OP (C, D, A, B, 17, 0xa679438e);
OP (B, C, D, A, 22, 0x49b40821);
/* For the second to fourth round we have the possibly swapped words
in CORRECT_WORDS. Redefine the macro to take an additional first
argument specifying the function to use. */
#undef OP
#define OP(f, a, b, c, d, k, s, T) \
do \
{ \
a += f (b, c, d) + correct_words[k] + T; \
CYCLIC (a, s); \
a += b; \
} \
while (0)
/* Round 2. */
OP (FG, A, B, C, D, 1, 5, 0xf61e2562);
OP (FG, D, A, B, C, 6, 9, 0xc040b340);
OP (FG, C, D, A, B, 11, 14, 0x265e5a51);
OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
OP (FG, A, B, C, D, 5, 5, 0xd62f105d);
OP (FG, D, A, B, C, 10, 9, 0x02441453);
OP (FG, C, D, A, B, 15, 14, 0xd8a1e681);
OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
OP (FG, A, B, C, D, 9, 5, 0x21e1cde6);
OP (FG, D, A, B, C, 14, 9, 0xc33707d6);
OP (FG, C, D, A, B, 3, 14, 0xf4d50d87);
OP (FG, B, C, D, A, 8, 20, 0x455a14ed);
OP (FG, A, B, C, D, 13, 5, 0xa9e3e905);
OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8);
OP (FG, C, D, A, B, 7, 14, 0x676f02d9);
OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
/* Round 3. */
OP (FH, A, B, C, D, 5, 4, 0xfffa3942);
OP (FH, D, A, B, C, 8, 11, 0x8771f681);
OP (FH, C, D, A, B, 11, 16, 0x6d9d6122);
OP (FH, B, C, D, A, 14, 23, 0xfde5380c);
OP (FH, A, B, C, D, 1, 4, 0xa4beea44);
OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9);
OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60);
OP (FH, B, C, D, A, 10, 23, 0xbebfbc70);
OP (FH, A, B, C, D, 13, 4, 0x289b7ec6);
OP (FH, D, A, B, C, 0, 11, 0xeaa127fa);
OP (FH, C, D, A, B, 3, 16, 0xd4ef3085);
OP (FH, B, C, D, A, 6, 23, 0x04881d05);
OP (FH, A, B, C, D, 9, 4, 0xd9d4d039);
OP (FH, D, A, B, C, 12, 11, 0xe6db99e5);
OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8);
OP (FH, B, C, D, A, 2, 23, 0xc4ac5665);
/* Round 4. */
OP (FI, A, B, C, D, 0, 6, 0xf4292244);
OP (FI, D, A, B, C, 7, 10, 0x432aff97);
OP (FI, C, D, A, B, 14, 15, 0xab9423a7);
OP (FI, B, C, D, A, 5, 21, 0xfc93a039);
OP (FI, A, B, C, D, 12, 6, 0x655b59c3);
OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92);
OP (FI, C, D, A, B, 10, 15, 0xffeff47d);
OP (FI, B, C, D, A, 1, 21, 0x85845dd1);
OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f);
OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
OP (FI, C, D, A, B, 6, 15, 0xa3014314);
OP (FI, B, C, D, A, 13, 21, 0x4e0811a1);
OP (FI, A, B, C, D, 4, 6, 0xf7537e82);
OP (FI, D, A, B, C, 11, 10, 0xbd3af235);
OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
OP (FI, B, C, D, A, 9, 21, 0xeb86d391);
/* Add the starting values of the context. */
A += A_save;
B += B_save;
C += C_save;
D += D_save;
}
/* Put checksum in context given as argument. */
ctx->A = A;
ctx->B = B;
ctx->C = C;
ctx->D = D;
}
static void
gst_md5sink_base_init (gpointer g_class)
{
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_set_details (gstelement_class, &gst_md5sink_details);
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&md5_sink_template));
}
static void
gst_md5sink_class_init (GstMD5SinkClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_md5sink_get_property);
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MD5,
g_param_spec_string ("md5", "md5", "current value of the md5 sum",
"", G_PARAM_READABLE));
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_md5sink_change_state);
}
static void
gst_md5sink_init (GstMD5Sink * md5sink)
{
GstPad *pad;
pad =
gst_pad_new_from_template (gst_static_pad_template_get
(&md5_sink_template), "sink");
gst_element_add_pad (GST_ELEMENT (md5sink), pad);
gst_pad_set_chain_function (pad, GST_DEBUG_FUNCPTR (gst_md5sink_chain));
md5_init_ctx (md5sink);
}
static GstElementStateReturn
gst_md5sink_change_state (GstElement * element)
{
GstMD5Sink *sink;
/* element check */
sink = GST_MD5SINK (element);
g_return_val_if_fail (GST_IS_MD5SINK (sink), GST_STATE_FAILURE);
switch (GST_STATE_TRANSITION (element)) {
case GST_STATE_READY_TO_PAUSED:
md5_init_ctx (sink);
g_object_notify (G_OBJECT (element), "md5");
break;
case GST_STATE_PAUSED_TO_READY:
md5_finish_ctx (sink, sink->md5);
g_object_notify (G_OBJECT (element), "md5");
break;
default:
break;
}
if ((GST_ELEMENT_CLASS (parent_class)->change_state))
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
return GST_STATE_SUCCESS;
}
static void
gst_md5sink_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
GstMD5Sink *sink;
/* it's not null if we got it, but it might not be ours */
g_return_if_fail (GST_IS_MD5SINK (object));
sink = GST_MD5SINK (object);
switch (prop_id) {
case ARG_MD5:
{
/* you could actually get a value for the current md5.
* This is currently disabled.
* md5_read_ctx (sink, sink->md5); */
/* md5 is a guchar[16] */
int i;
guchar *md5string = g_malloc0 (33);
for (i = 0; i < 16; ++i)
sprintf (md5string + i * 2, "%02x", sink->md5[i]);
g_value_set_string (value, md5string);
g_free (md5string);
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_md5sink_chain (GstPad * pad, GstData * _data)
{
GstBuffer *buf = GST_BUFFER (_data);
GstMD5Sink *md5sink;
g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_PAD (pad));
g_return_if_fail (buf != NULL);
md5sink = GST_MD5SINK (gst_pad_get_parent (pad));
if (GST_IS_BUFFER (buf)) {
md5_process_bytes (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf), md5sink);
}
gst_buffer_unref (buf);
}

74
gst/oldcore/gstmd5sink.h Normal file
View file

@ -0,0 +1,74 @@
/* GStreamer
* Copyright (C) 2002 Erik Walthinsen <omega@cse.ogi.edu>
* 2002 Wim Taymans <wtay@chello.be>
*
* gstmd5sink.h:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_MD5SINK_H__
#define __GST_MD5SINK_H__
#include <gst/gst.h>
G_BEGIN_DECLS
#define GST_TYPE_MD5SINK \
(gst_md5sink_get_type())
#define GST_MD5SINK(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MD5SINK,GstMD5Sink))
#define GST_MD5SINK_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MD5SINK,GstMD5SinkClass))
#define GST_IS_MD5SINK(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MD5SINK))
#define GST_IS_MD5SINK_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MD5SINK))
typedef struct _GstMD5Sink GstMD5Sink;
typedef struct _GstMD5SinkClass GstMD5SinkClass;
struct _GstMD5Sink {
GstElement element;
/* md5 information */
guint32 A;
guint32 B;
guint32 C;
guint32 D;
guint32 total[2];
guint32 buflen;
gchar buffer[128];
/* latest md5 */
guchar md5[16];
};
struct _GstMD5SinkClass {
GstElementClass parent_class;
};
GType gst_md5sink_get_type (void);
G_END_DECLS
#endif /* __GST_MD5SINK_H__ */

View file

@ -0,0 +1,363 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
* 2001 Dominic Ludlam <dom@recoil.org>
*
* gstmultifilesrc.c:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <errno.h>
#include <string.h>
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "../gst-i18n-lib.h"
#include "gstmultifilesrc.h"
static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
GST_DEBUG_CATEGORY_STATIC (gst_multifilesrc_debug);
#define GST_CAT_DEFAULT gst_multifilesrc_debug
GstElementDetails gst_multifilesrc_details =
GST_ELEMENT_DETAILS ("Multi File Source",
"Source/File",
"Read from multiple files in order",
"Dominic Ludlam <dom@openfx.org>");
/* FileSrc signals and args */
enum
{
NEW_FILE,
LAST_SIGNAL
};
enum
{
ARG_0,
ARG_LOCATIONS,
ARG_HAVENEWMEDIA
};
#define _do_init(bla) \
GST_DEBUG_CATEGORY_INIT (gst_multifilesrc_debug, "multifilesrc", 0, "multifilesrc element");
GST_BOILERPLATE_FULL (GstMultiFileSrc, gst_multifilesrc, GstElement,
GST_TYPE_ELEMENT, _do_init);
static void gst_multifilesrc_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_multifilesrc_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static GstData *gst_multifilesrc_get (GstPad * pad);
/*static GstBuffer * gst_multifilesrc_get_region (GstPad *pad,GstRegionType type,guint64 offset,guint64 len);*/
static GstElementStateReturn gst_multifilesrc_change_state (GstElement *
element);
static gboolean gst_multifilesrc_open_file (GstMultiFileSrc * src,
GstPad * srcpad);
static void gst_multifilesrc_close_file (GstMultiFileSrc * src);
static guint gst_multifilesrc_signals[LAST_SIGNAL] = { 0 };
static void
gst_multifilesrc_base_init (gpointer g_class)
{
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&srctemplate));
gst_element_class_set_details (gstelement_class, &gst_multifilesrc_details);
}
static void
gst_multifilesrc_class_init (GstMultiFileSrcClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
gobject_class->set_property = gst_multifilesrc_set_property;
gobject_class->get_property = gst_multifilesrc_get_property;
gst_multifilesrc_signals[NEW_FILE] =
g_signal_new ("new-file", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstMultiFileSrcClass, new_file), NULL, NULL,
g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING);
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LOCATIONS, g_param_spec_pointer ("locations", "locations", "locations", G_PARAM_READWRITE)); /* CHECKME */
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_HAVENEWMEDIA,
g_param_spec_boolean ("newmedia", "newmedia",
"generate new media events?", FALSE, G_PARAM_READWRITE));
gstelement_class->change_state = gst_multifilesrc_change_state;
}
static void
gst_multifilesrc_init (GstMultiFileSrc * multifilesrc)
{
/* GST_FLAG_SET (filesrc, GST_SRC_); */
multifilesrc->srcpad =
gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
"src");
gst_pad_set_get_function (multifilesrc->srcpad, gst_multifilesrc_get);
/* gst_pad_set_getregion_function (multifilesrc->srcpad,gst_multifilesrc_get_region); */
gst_element_add_pad (GST_ELEMENT (multifilesrc), multifilesrc->srcpad);
multifilesrc->listptr = NULL;
multifilesrc->currentfilename = NULL;
multifilesrc->fd = 0;
multifilesrc->size = 0;
multifilesrc->map = NULL;
multifilesrc->new_seek = FALSE;
multifilesrc->have_newmedia_events = FALSE;
}
static void
gst_multifilesrc_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstMultiFileSrc *src;
/* it's not null if we got it, but it might not be ours */
g_return_if_fail (GST_IS_MULTIFILESRC (object));
src = GST_MULTIFILESRC (object);
switch (prop_id) {
case ARG_LOCATIONS:
/* the element must be stopped in order to do this */
g_return_if_fail (GST_STATE (src) < GST_STATE_PLAYING);
/* clear the filename if we get a NULL */
if (g_value_get_pointer (value) == NULL) {
gst_element_set_state (GST_ELEMENT (object), GST_STATE_NULL);
src->listptr = NULL;
/* otherwise set the new filenames */
} else {
src->listptr = g_value_get_pointer (value);
}
break;
case ARG_HAVENEWMEDIA:
src->have_newmedia_events = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_multifilesrc_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
GstMultiFileSrc *src;
/* it's not null if we got it, but it might not be ours */
g_return_if_fail (GST_IS_MULTIFILESRC (object));
src = GST_MULTIFILESRC (object);
switch (prop_id) {
case ARG_LOCATIONS:
g_value_set_pointer (value, src->listptr);
break;
case ARG_HAVENEWMEDIA:
g_value_set_boolean (value, src->have_newmedia_events);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/**
* gst_filesrc_get:
* @pad: #GstPad to push a buffer from
*
* Push a new buffer from the filesrc at the current offset.
*/
static GstData *
gst_multifilesrc_get (GstPad * pad)
{
GstMultiFileSrc *src;
GstBuffer *buf;
GstEvent *newmedia;
GSList *list;
g_return_val_if_fail (pad != NULL, NULL);
src = GST_MULTIFILESRC (gst_pad_get_parent (pad));
GST_DEBUG ("curfileindex = %d newmedia flag = %s", src->curfileindex,
GST_FLAG_IS_SET (src, GST_MULTIFILESRC_NEWFILE) ? "true" : "false");
switch (GST_FLAG_IS_SET (src, GST_MULTIFILESRC_NEWFILE)) {
case FALSE:
if (GST_FLAG_IS_SET (src, GST_MULTIFILESRC_OPEN))
gst_multifilesrc_close_file (src);
if (!src->listptr) {
GST_DEBUG ("sending EOS event");
gst_element_set_eos (GST_ELEMENT (src));
return GST_DATA (gst_event_new (GST_EVENT_EOS));
}
list = src->listptr;
src->currentfilename = (gchar *) list->data;
src->listptr = src->listptr->next;
if (!gst_multifilesrc_open_file (src, pad))
return NULL;
src->curfileindex++;
/* emitted after the open, as the user may free the list and string from here */
g_signal_emit (G_OBJECT (src), gst_multifilesrc_signals[NEW_FILE], 0,
list);
if (src->have_newmedia_events) {
newmedia =
gst_event_new_discontinuous (TRUE, GST_FORMAT_TIME, (gint64) 0,
GST_FORMAT_UNDEFINED);
GST_FLAG_SET (src, GST_MULTIFILESRC_NEWFILE);
GST_DEBUG ("sending new media event");
return GST_DATA (newmedia);
}
default:
if (GST_FLAG_IS_SET (src, GST_MULTIFILESRC_NEWFILE))
GST_FLAG_UNSET (src, GST_MULTIFILESRC_NEWFILE);
/* create the buffer */
/* FIXME: should eventually use a bufferpool for this */
buf = gst_buffer_new ();
g_return_val_if_fail (buf != NULL, NULL);
/* simply set the buffer to point to the correct region of the file */
GST_BUFFER_DATA (buf) = src->map;
GST_BUFFER_SIZE (buf) = src->size;
GST_BUFFER_OFFSET (buf) = 0;
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_DONTFREE);
if (src->new_seek) {
/* fixme, do something here */
src->new_seek = FALSE;
}
/* we're done, return the buffer */
GST_DEBUG ("sending buffer");
return GST_DATA (buf);
}
/* should not reach here */
g_assert_not_reached ();
return NULL;
}
/* open the file and mmap it, necessary to go to READY state */
static gboolean
gst_multifilesrc_open_file (GstMultiFileSrc * src, GstPad * srcpad)
{
g_return_val_if_fail (!GST_FLAG_IS_SET (src, GST_MULTIFILESRC_OPEN), FALSE);
if (src->currentfilename == NULL || src->currentfilename[0] == '\0') {
GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,
(_("No file name specified for reading.")), (NULL));
return FALSE;
}
/* open the file. FIXME: do we need to use O_LARGEFILE here? */
src->fd = open ((const char *) src->currentfilename, O_RDONLY);
if (src->fd < 0) {
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
(_("Could not open file \"%s\" for reading."), src->currentfilename),
GST_ERROR_SYSTEM);
return FALSE;
} else {
/* find the file length */
src->size = lseek (src->fd, 0, SEEK_END);
lseek (src->fd, 0, SEEK_SET);
/* map the file into memory.
* FIXME: don't map the whole file at once, there might
* be restrictions set. Get max size via getrlimit
* or re-try with smaller size if mmap fails with ENOMEM? */
src->map = mmap (NULL, src->size, PROT_READ, MAP_SHARED, src->fd, 0);
madvise (src->map, src->size, MADV_SEQUENTIAL);
/* collapse state if that failed */
if (src->map == NULL) {
close (src->fd);
GST_ELEMENT_ERROR (src, RESOURCE, TOO_LAZY, (NULL),
("mmap call failed."));
return FALSE;
}
GST_FLAG_SET (src, GST_MULTIFILESRC_OPEN);
src->new_seek = TRUE;
}
return TRUE;
}
/* unmap and close the file */
static void
gst_multifilesrc_close_file (GstMultiFileSrc * src)
{
g_return_if_fail (GST_FLAG_IS_SET (src, GST_MULTIFILESRC_OPEN));
/* unmap the file from memory and close the file */
munmap (src->map, src->size);
close (src->fd);
/* zero out a lot of our state */
src->fd = 0;
src->size = 0;
src->map = NULL;
src->new_seek = FALSE;
GST_FLAG_UNSET (src, GST_MULTIFILESRC_OPEN);
}
static GstElementStateReturn
gst_multifilesrc_change_state (GstElement * element)
{
g_return_val_if_fail (GST_IS_MULTIFILESRC (element), GST_STATE_FAILURE);
if (GST_STATE_PENDING (element) == GST_STATE_NULL) {
if (GST_FLAG_IS_SET (element, GST_MULTIFILESRC_OPEN))
gst_multifilesrc_close_file (GST_MULTIFILESRC (element));
}
if (GST_ELEMENT_CLASS (parent_class)->change_state)
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
return GST_STATE_SUCCESS;
}

View file

@ -0,0 +1,85 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
* 2001 Dominic Ludlam <dom@recoil.org>
*
* gstmultifilesrc.h:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_MULTIFILESRC_H__
#define __GST_MULTIFILESRC_H__
#include <gst/gst.h>
G_BEGIN_DECLS
#define GST_TYPE_MULTIFILESRC \
(gst_multifilesrc_get_type())
#define GST_MULTIFILESRC(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MULTIFILESRC,GstMultiFileSrc))
#define GST_MULTIFILESRC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MULTIFILESRC,GstMultiFileSrcClass))
#define GST_IS_MULTIFILESRC(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MULTIFILESRC))
#define GST_IS_MULTIFILESRC_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MULTIFILESRC))
typedef enum {
GST_MULTIFILESRC_OPEN = GST_ELEMENT_FLAG_LAST,
GST_MULTIFILESRC_NEWFILE = GST_ELEMENT_FLAG_LAST + 2,
GST_MULTIFILESRC_FLAG_LAST = GST_ELEMENT_FLAG_LAST + 4
} GstMultiFileSrcFlags;
typedef struct _GstMultiFileSrc GstMultiFileSrc;
typedef struct _GstMultiFileSrcClass GstMultiFileSrcClass;
struct _GstMultiFileSrc {
GstElement element;
/* pads */
GstPad *srcpad;
/* current file details */
gchar *currentfilename;
GSList *listptr;
/* mapping parameters */
gint fd;
gulong size; /* how long is the file? */
guchar *map; /* where the file is mapped to */
gint curfileindex; /* how many files have we done so far */
gboolean have_newmedia_events; /* tunable parameter to say whether new media
disconts should be generated */
gboolean new_seek;
};
struct _GstMultiFileSrcClass {
GstElementClass parent_class;
void (*new_file) (GstMultiFileSrc *multifilesrc, gchar *newfilename);
};
GType gst_multifilesrc_get_type(void);
G_END_DECLS
#endif /* __GST_MULTIFILESRC_H__ */

356
gst/oldcore/gstpipefilter.c Normal file
View file

@ -0,0 +1,356 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
*
* gstpipefilter.c:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "../gst-i18n-lib.h"
#include "gstpipefilter.h"
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
GST_DEBUG_CATEGORY_STATIC (gst_pipefilter_debug);
#define GST_CAT_DEFAULT gst_pipefilter_debug
GstElementDetails gst_pipefilter_details = GST_ELEMENT_DETAILS ("Pipefilter",
"Filter",
"Interoperate with an external program using stdin and stdout",
"Erik Walthinsen <omega@cse.ogi.edu>, "
"Wim Taymans <wim.taymans@chello.be>");
/* Pipefilter signals and args */
enum
{
/* FILL ME */
LAST_SIGNAL
};
enum
{
ARG_0,
ARG_COMMAND
};
#define _do_init(bla) \
GST_DEBUG_CATEGORY_INIT (gst_pipefilter_debug, "pipefilter", 0, "pipefilter element");
GST_BOILERPLATE_FULL (GstPipefilter, gst_pipefilter, GstElement,
GST_TYPE_ELEMENT, _do_init);
static void gst_pipefilter_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_pipefilter_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static GstData *gst_pipefilter_get (GstPad * pad);
static void gst_pipefilter_chain (GstPad * pad, GstData * _data);
static gboolean gst_pipefilter_handle_event (GstPad * pad, GstEvent * event);
static GstElementStateReturn gst_pipefilter_change_state (GstElement * element);
static void
gst_pipefilter_base_init (gpointer g_class)
{
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&srctemplate));
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&sinktemplate));
gst_element_class_set_details (gstelement_class, &gst_pipefilter_details);
}
static void
gst_pipefilter_class_init (GstPipefilterClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
gobject_class->set_property = gst_pipefilter_set_property;
gobject_class->get_property = gst_pipefilter_get_property;
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_COMMAND, g_param_spec_string ("command", "command", "command", NULL, G_PARAM_READWRITE)); /* CHECKME */
gstelement_class->change_state = gst_pipefilter_change_state;
}
static void
gst_pipefilter_init (GstPipefilter * pipefilter)
{
GST_FLAG_SET (pipefilter, GST_ELEMENT_DECOUPLED);
pipefilter->sinkpad =
gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate),
"sink");
gst_element_add_pad (GST_ELEMENT (pipefilter), pipefilter->sinkpad);
gst_pad_set_chain_function (pipefilter->sinkpad, gst_pipefilter_chain);
pipefilter->srcpad =
gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
"src");
gst_element_add_pad (GST_ELEMENT (pipefilter), pipefilter->srcpad);
gst_pad_set_get_function (pipefilter->srcpad, gst_pipefilter_get);
pipefilter->command = NULL;
pipefilter->curoffset = 0;
pipefilter->bytes_per_read = 4096;
pipefilter->seq = 0;
}
static gboolean
gst_pipefilter_handle_event (GstPad * pad, GstEvent * event)
{
GstPipefilter *pipefilter;
pipefilter = GST_PIPEFILTER (gst_pad_get_parent (pad));
GST_DEBUG ("pipefilter: %s received event", GST_ELEMENT_NAME (pipefilter));
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_EOS:
if (close (pipefilter->fdin[1]) < 0)
perror ("close");
if (close (pipefilter->fdout[0]) < 0)
perror ("close");
break;
default:
break;
}
gst_pad_event_default (pad, event);
return TRUE;
}
static GstData *
gst_pipefilter_get (GstPad * pad)
{
GstPipefilter *pipefilter;
GstBuffer *newbuf;
glong readbytes;
pipefilter = GST_PIPEFILTER (gst_pad_get_parent (pad));
/* create the buffer */
/* FIXME: should eventually use a bufferpool for this */
newbuf = gst_buffer_new ();
g_return_val_if_fail (newbuf, NULL);
/* allocate the space for the buffer data */
GST_BUFFER_DATA (newbuf) = g_malloc (pipefilter->bytes_per_read);
g_return_val_if_fail (GST_BUFFER_DATA (newbuf) != NULL, NULL);
/* read it in from the file */
GST_DEBUG ("attemting to read %ld bytes", pipefilter->bytes_per_read);
readbytes =
read (pipefilter->fdout[0], GST_BUFFER_DATA (newbuf),
pipefilter->bytes_per_read);
GST_DEBUG ("read %ld bytes", readbytes);
if (readbytes < 0) {
GST_ELEMENT_ERROR (pipefilter, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
return NULL;
}
/* if we didn't get as many bytes as we asked for, we're at EOF */
if (readbytes == 0) {
return GST_DATA (gst_event_new (GST_EVENT_EOS));
}
GST_BUFFER_OFFSET (newbuf) = pipefilter->curoffset;
GST_BUFFER_SIZE (newbuf) = readbytes;
pipefilter->curoffset += readbytes;
return GST_DATA (newbuf);
}
static void
gst_pipefilter_chain (GstPad * pad, GstData * _data)
{
GstBuffer *buf;
GstPipefilter *pipefilter;
glong writebytes;
guchar *data;
gulong size;
g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_PAD (pad));
if (GST_IS_EVENT (_data)) {
gst_pipefilter_handle_event (pad, GST_EVENT (_data));
return;
}
pipefilter = GST_PIPEFILTER (gst_pad_get_parent (pad));
buf = GST_BUFFER (_data);
data = GST_BUFFER_DATA (buf);
size = GST_BUFFER_SIZE (buf);
GST_DEBUG ("attemting to write %ld bytes", size);
writebytes = write (pipefilter->fdin[1], data, size);
GST_DEBUG ("written %ld bytes", writebytes);
if (writebytes < 0) {
GST_ELEMENT_ERROR (pipefilter, RESOURCE, WRITE, (NULL), GST_ERROR_SYSTEM);
return;
}
gst_buffer_unref (buf);
}
static void
gst_pipefilter_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstPipefilter *pipefilter;
/* it's not null if we got it, but it might not be ours */
g_return_if_fail (GST_IS_PIPEFILTER (object));
pipefilter = GST_PIPEFILTER (object);
switch (prop_id) {
case ARG_COMMAND:
pipefilter->orig_command = g_strdup (g_value_get_string (value));
pipefilter->command = g_strsplit (g_value_get_string (value), " ", 0);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_pipefilter_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
GstPipefilter *pipefilter;
/* it's not null if we got it, but it might not be ours */
g_return_if_fail (GST_IS_PIPEFILTER (object));
pipefilter = GST_PIPEFILTER (object);
switch (prop_id) {
case ARG_COMMAND:
g_value_set_string (value, pipefilter->orig_command);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/* open the file, necessary to go to RUNNING state */
static gboolean
gst_pipefilter_open_file (GstPipefilter * src)
{
g_return_val_if_fail (!GST_FLAG_IS_SET (src, GST_PIPEFILTER_OPEN), FALSE);
pipe (src->fdin);
pipe (src->fdout);
if ((src->childpid = fork ()) == -1) {
GST_ELEMENT_ERROR (src, RESOURCE, TOO_LAZY, (NULL), GST_ERROR_SYSTEM);
return FALSE;
}
if (src->childpid == 0) {
close (src->fdin[1]);
close (src->fdout[0]);
/* child */
dup2 (src->fdin[0], STDIN_FILENO); /* set the childs input stream */
dup2 (src->fdout[1], STDOUT_FILENO); /* set the childs output stream */
execvp (src->command[0], &src->command[0]);
/* will only be reached if execvp has an error */
GST_ELEMENT_ERROR (src, RESOURCE, TOO_LAZY, (NULL), GST_ERROR_SYSTEM);
return FALSE;
} else {
close (src->fdin[0]);
close (src->fdout[1]);
}
GST_FLAG_SET (src, GST_PIPEFILTER_OPEN);
return TRUE;
}
/* close the file */
static void
gst_pipefilter_close_file (GstPipefilter * src)
{
g_return_if_fail (GST_FLAG_IS_SET (src, GST_PIPEFILTER_OPEN));
/* close the file */
close (src->fdout[0]);
close (src->fdout[1]);
close (src->fdin[0]);
close (src->fdin[1]);
/* zero out a lot of our state */
src->curoffset = 0;
src->seq = 0;
GST_FLAG_UNSET (src, GST_PIPEFILTER_OPEN);
}
static GstElementStateReturn
gst_pipefilter_change_state (GstElement * element)
{
g_return_val_if_fail (GST_IS_PIPEFILTER (element), FALSE);
/* if going down into NULL state, close the file if it's open */
if (GST_STATE_PENDING (element) == GST_STATE_NULL) {
if (GST_FLAG_IS_SET (element, GST_PIPEFILTER_OPEN))
gst_pipefilter_close_file (GST_PIPEFILTER (element));
/* otherwise (READY or higher) we need to open the file */
} else {
if (!GST_FLAG_IS_SET (element, GST_PIPEFILTER_OPEN)) {
if (!gst_pipefilter_open_file (GST_PIPEFILTER (element)))
return GST_STATE_FAILURE;
}
}
if (GST_ELEMENT_CLASS (parent_class)->change_state)
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
return GST_STATE_SUCCESS;
}

View file

@ -0,0 +1,81 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
*
* gstpipefilter.h:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_PIPEFILTER_H__
#define __GST_PIPEFILTER_H__
#include <sys/types.h>
#include <gst/gst.h>
G_BEGIN_DECLS
#define GST_TYPE_PIPEFILTER \
(gst_pipefilter_get_type())
#define GST_PIPEFILTER(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PIPEFILTER,GstPipefilter))
#define GST_PIPEFILTER_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PIPEFILTER,GstPipefilterClass))
#define GST_IS_PIPEFILTER(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PIPEFILTER))
#define GST_IS_PIPEFILTER_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PIPEFILTER))
typedef enum {
GST_PIPEFILTER_OPEN = GST_ELEMENT_FLAG_LAST,
GST_PIPEFILTER_FLAG_LAST = GST_ELEMENT_FLAG_LAST + 2
} GstPipeFilterFlags;
typedef struct _GstPipefilter GstPipefilter;
typedef struct _GstPipefilterClass GstPipefilterClass;
struct _GstPipefilter {
GstElement element;
GstPad *sinkpad;
GstPad *srcpad;
/* command */
gchar **command;
gchar *orig_command;
/* fd */
gint fdout[2];
gint fdin[2];
pid_t childpid;
gulong curoffset; /* current offset in file */
gulong bytes_per_read; /* bytes per read */
gulong seq; /* buffer sequence number */
};
struct _GstPipefilterClass {
GstElementClass parent_class;
};
GType gst_pipefilter_get_type(void);
G_END_DECLS
#endif /* __GST_PIPEFILTER_H__ */

373
gst/oldcore/gstshaper.c Normal file
View file

@ -0,0 +1,373 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
*
* gstshaper.c:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "gstshaper.h"
GST_DEBUG_CATEGORY_STATIC (gst_shaper_debug);
#define GST_CAT_DEFAULT gst_shaper_debug
GstElementDetails gst_shaper_details = GST_ELEMENT_DETAILS ("Shaper",
"Generic",
"Synchronizes streams on different pads",
"Wim Taymans <wim.taymans@chello.be>");
/* Shaper signals and args */
enum
{
/* FILL ME */
LAST_SIGNAL
};
enum
{
ARG_0,
ARG_POLICY,
ARG_SILENT,
ARG_LAST_MESSAGE
};
typedef struct
{
GstPad *sinkpad;
GstPad *srcpad;
GstBuffer *buffer;
}
GstShaperConnection;
GstStaticPadTemplate shaper_src_template = GST_STATIC_PAD_TEMPLATE ("src%d",
GST_PAD_SRC,
GST_PAD_SOMETIMES,
GST_STATIC_CAPS_ANY);
GstStaticPadTemplate shaper_sink_template = GST_STATIC_PAD_TEMPLATE ("sink%d",
GST_PAD_SINK,
GST_PAD_REQUEST,
GST_STATIC_CAPS_ANY);
#define GST_TYPE_SHAPER_POLICY (gst_shaper_policy_get_type())
static GType
gst_shaper_policy_get_type (void)
{
static GType shaper_policy_type = 0;
static GEnumValue shaper_policy[] = {
{SHAPER_POLICY_TIMESTAMPS, "1", "sync on timestamps"},
{SHAPER_POLICY_BUFFERSIZE, "2", "sync on buffer size"},
{0, NULL, NULL},
};
if (!shaper_policy_type) {
shaper_policy_type =
g_enum_register_static ("GstShaperPolicy", shaper_policy);
}
return shaper_policy_type;
}
#define _do_init(bla) \
GST_DEBUG_CATEGORY_INIT (gst_shaper_debug, "shaper", 0, "shaper element");
GST_BOILERPLATE_FULL (GstShaper, gst_shaper, GstElement, GST_TYPE_ELEMENT,
_do_init);
static void gst_shaper_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_shaper_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static GstPad *gst_shaper_request_new_pad (GstElement * element,
GstPadTemplate * templ, const gchar * unused);
static void gst_shaper_loop (GstElement * element);
static void
gst_shaper_base_init (gpointer g_class)
{
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_set_details (gstelement_class, &gst_shaper_details);
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&shaper_src_template));
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&shaper_sink_template));
}
static void
gst_shaper_class_init (GstShaperClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_shaper_set_property);
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_shaper_get_property);
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_POLICY,
g_param_spec_enum ("policy", "Policy", "Shaper policy",
GST_TYPE_SHAPER_POLICY, SHAPER_POLICY_TIMESTAMPS, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT,
g_param_spec_boolean ("silent", "silent", "silent",
FALSE, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
g_param_spec_string ("last-message", "last-message", "last-message",
NULL, G_PARAM_READABLE));
gstelement_class->request_new_pad =
GST_DEBUG_FUNCPTR (gst_shaper_request_new_pad);
}
static GstCaps *
gst_shaper_getcaps (GstPad * pad)
{
GstPad *otherpad;
GstShaperConnection *connection;
connection = gst_pad_get_element_private (pad);
otherpad =
(pad == connection->srcpad ? connection->sinkpad : connection->srcpad);
if (GST_PAD_PEER (otherpad)) {
return gst_pad_get_caps (GST_PAD_PEER (otherpad));
} else {
return gst_caps_new_any ();
}
}
static GList *
gst_shaper_get_internal_link (GstPad * pad)
{
GList *res = NULL;
GstShaperConnection *connection;
GstPad *otherpad;
connection = gst_pad_get_element_private (pad);
otherpad =
(pad == connection->srcpad ? connection->sinkpad : connection->srcpad);
res = g_list_prepend (res, otherpad);
return res;
}
static GstPadLinkReturn
gst_shaper_link (GstPad * pad, const GstCaps * caps)
{
GstPad *otherpad;
GstShaperConnection *connection;
connection = gst_pad_get_element_private (pad);
otherpad =
(pad == connection->srcpad ? connection->sinkpad : connection->srcpad);
return gst_pad_try_set_caps (otherpad, caps);
}
static GstShaperConnection *
gst_shaper_create_connection (GstShaper * shaper)
{
GstShaperConnection *connection;
gchar *padname;
shaper->nconnections++;
connection = g_new0 (GstShaperConnection, 1);
padname = g_strdup_printf ("sink%d", shaper->nconnections);
connection->sinkpad =
gst_pad_new_from_template (gst_static_pad_template_get
(&shaper_sink_template), padname);
g_free (padname);
gst_pad_set_getcaps_function (connection->sinkpad, gst_shaper_getcaps);
gst_pad_set_internal_link_function (connection->sinkpad,
gst_shaper_get_internal_link);
gst_pad_set_link_function (connection->sinkpad, gst_shaper_link);
gst_pad_set_element_private (connection->sinkpad, connection);
gst_element_add_pad (GST_ELEMENT (shaper), connection->sinkpad);
padname = g_strdup_printf ("src%d", shaper->nconnections);
connection->srcpad =
gst_pad_new_from_template (gst_static_pad_template_get
(&shaper_src_template), padname);
g_free (padname);
gst_pad_set_getcaps_function (connection->srcpad, gst_shaper_getcaps);
gst_pad_set_internal_link_function (connection->srcpad,
gst_shaper_get_internal_link);
gst_pad_set_link_function (connection->srcpad, gst_shaper_link);
gst_pad_set_element_private (connection->srcpad, connection);
gst_element_add_pad (GST_ELEMENT (shaper), connection->srcpad);
shaper->connections = g_slist_prepend (shaper->connections, connection);
return connection;
}
static GstPad *
gst_shaper_request_new_pad (GstElement * element, GstPadTemplate * templ,
const gchar * unused)
{
GstShaper *shaper = GST_SHAPER (element);
GstShaperConnection *connection;
connection = gst_shaper_create_connection (shaper);
return connection->sinkpad;
}
static void
gst_shaper_init (GstShaper * shaper)
{
gst_element_set_loop_function (GST_ELEMENT (shaper), gst_shaper_loop);
shaper->policy = SHAPER_POLICY_TIMESTAMPS;
shaper->connections = NULL;
shaper->nconnections = 0;
shaper->silent = FALSE;
shaper->last_message = NULL;
}
static void
gst_shaper_loop (GstElement * element)
{
GstShaper *shaper;
GSList *connections;
gboolean eos = TRUE;
GstShaperConnection *min = NULL;
shaper = GST_SHAPER (element);
/* first make sure we have a buffer on all pads */
connections = shaper->connections;
while (connections) {
GstShaperConnection *connection = (GstShaperConnection *) connections->data;
/* try to fill a connection without a buffer on a pad that is
* active */
if (connection->buffer == NULL && GST_PAD_IS_USABLE (connection->sinkpad)) {
GstBuffer *buffer;
buffer = GST_BUFFER (gst_pad_pull (connection->sinkpad));
/* events are simply pushed ASAP */
if (GST_IS_EVENT (buffer)) {
/* save event type as it will be unreffed after the next push */
GstEventType type = GST_EVENT_TYPE (buffer);
gst_pad_push (connection->srcpad, GST_DATA (buffer));
switch (type) {
/* on EOS we disable the pad so that we don't pull on
* it again and never get more data */
case GST_EVENT_EOS:
gst_pad_set_active (connection->sinkpad, FALSE);
break;
default:
break;
}
} else {
/* we store the buffer */
connection->buffer = buffer;
}
}
/* FIXME policy stuff goes here */
/* find connection with lowest timestamp */
if (min == NULL || (connection->buffer != NULL &&
(GST_BUFFER_TIMESTAMP (connection->buffer) <
GST_BUFFER_TIMESTAMP (min->buffer)))) {
min = connection;
}
connections = g_slist_next (connections);
}
/* if we have a connection with a buffer, push it */
if (min != NULL && min->buffer) {
gst_pad_push (min->srcpad, GST_DATA (min->buffer));
min->buffer = NULL;
/* since we pushed a buffer, it's not EOS */
eos = FALSE;
}
if (eos) {
gst_element_set_eos (element);
}
}
static void
gst_shaper_set_property (GObject * object, guint prop_id, const GValue * value,
GParamSpec * pspec)
{
GstShaper *shaper;
/* it's not null if we got it, but it might not be ours */
g_return_if_fail (GST_IS_SHAPER (object));
shaper = GST_SHAPER (object);
switch (prop_id) {
case ARG_POLICY:
shaper->policy = g_value_get_enum (value);
break;
case ARG_SILENT:
shaper->silent = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_shaper_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
GstShaper *shaper;
/* it's not null if we got it, but it might not be ours */
g_return_if_fail (GST_IS_SHAPER (object));
shaper = GST_SHAPER (object);
switch (prop_id) {
case ARG_POLICY:
g_value_set_enum (value, shaper->policy);
break;
case ARG_SILENT:
g_value_set_boolean (value, shaper->silent);
break;
case ARG_LAST_MESSAGE:
g_value_set_string (value, shaper->last_message);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}

72
gst/oldcore/gstshaper.h Normal file
View file

@ -0,0 +1,72 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
*
* gstshaper.h:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_SHAPER_H__
#define __GST_SHAPER_H__
#include <gst/gst.h>
G_BEGIN_DECLS
#define GST_TYPE_SHAPER \
(gst_shaper_get_type())
#define GST_SHAPER(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SHAPER,GstShaper))
#define GST_SHAPER_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SHAPER,GstShaperClass))
#define GST_IS_SHAPER(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SHAPER))
#define GST_IS_SHAPER_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SHAPER))
typedef enum {
SHAPER_POLICY_TIMESTAMPS = 1,
SHAPER_POLICY_BUFFERSIZE
} GstShaperPolicyType;
typedef struct _GstShaper GstShaper;
typedef struct _GstShaperClass GstShaperClass;
struct _GstShaper {
GstElement element;
GSList *connections;
gint nconnections;
GstShaperPolicyType policy;
gboolean silent;
gchar *last_message;
};
struct _GstShaperClass {
GstElementClass parent_class;
};
GType gst_shaper_get_type (void);
G_END_DECLS
#endif /* __GST_SHAPER_H__ */

416
gst/oldcore/gststatistics.c Normal file
View file

@ -0,0 +1,416 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
*
* gststatistics.c:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "gststatistics.h"
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
GST_DEBUG_CATEGORY_STATIC (gst_statistics_debug);
#define GST_CAT_DEFAULT gst_statistics_debug
GstElementDetails gst_statistics_details = GST_ELEMENT_DETAILS ("Statistics",
"Generic",
"Statistics on buffers/bytes/events",
"David I. Lehn <dlehn@users.sourceforge.net>");
/* Statistics signals and args */
enum
{
SIGNAL_UPDATE,
LAST_SIGNAL
};
enum
{
ARG_0,
ARG_BUFFERS,
ARG_BYTES,
ARG_EVENTS,
ARG_BUFFER_UPDATE_FREQ,
ARG_BYTES_UPDATE_FREQ,
ARG_EVENT_UPDATE_FREQ,
ARG_UPDATE_ON_EOS,
ARG_UPDATE,
ARG_SILENT
};
#define _do_init(bla) \
GST_DEBUG_CATEGORY_INIT (gst_statistics_debug, "statistics", 0, "statistics element");
GST_BOILERPLATE_FULL (GstStatistics, gst_statistics, GstElement,
GST_TYPE_ELEMENT, _do_init);
static void gst_statistics_finalize (GObject * object);
static void gst_statistics_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_statistics_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_statistics_chain (GstPad * pad, GstData * _data);
static void gst_statistics_reset (GstStatistics * statistics);
static void gst_statistics_print (GstStatistics * statistics);
static guint gst_statistics_signals[LAST_SIGNAL] = { 0, };
static stats zero_stats = { 0, };
static void
gst_statistics_base_init (gpointer g_class)
{
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&srctemplate));
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&sinktemplate));
gst_element_class_set_details (gstelement_class, &gst_statistics_details);
}
static void
gst_statistics_finalize (GObject * object)
{
GstStatistics *statistics;
statistics = GST_STATISTICS (object);
if (statistics->timer)
g_timer_destroy (statistics->timer);
if (statistics->last_timer)
g_timer_destroy (statistics->last_timer);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gst_statistics_class_init (GstStatisticsClass * klass)
{
GObjectClass *gobject_class;
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_statistics_set_property);
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_statistics_get_property);
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BUFFERS,
g_param_spec_int64 ("buffers", "buffers", "total buffers count",
0, G_MAXINT64, 0, G_PARAM_READABLE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BYTES,
g_param_spec_int64 ("bytes", "bytes", "total bytes count",
0, G_MAXINT64, 0, G_PARAM_READABLE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_EVENTS,
g_param_spec_int64 ("events", "events", "total event count",
0, G_MAXINT64, 0, G_PARAM_READABLE));
g_object_class_install_property (G_OBJECT_CLASS (klass),
ARG_BUFFER_UPDATE_FREQ, g_param_spec_int64 ("buffer_update_freq",
"buffer update freq", "buffer update frequency", 0, G_MAXINT64, 0,
G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass),
ARG_BYTES_UPDATE_FREQ, g_param_spec_int64 ("bytes_update_freq",
"bytes update freq", "bytes update frequency", 0, G_MAXINT64, 0,
G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass),
ARG_EVENT_UPDATE_FREQ, g_param_spec_int64 ("event_update_freq",
"event update freq", "event update frequency", 0, G_MAXINT64, 0,
G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_UPDATE_ON_EOS,
g_param_spec_boolean ("update_on_eos", "update on EOS",
"update on EOS event", TRUE, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_UPDATE,
g_param_spec_boolean ("update", "update", "update", TRUE,
G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT,
g_param_spec_boolean ("silent", "silent", "silent", TRUE,
G_PARAM_READWRITE));
gst_statistics_signals[SIGNAL_UPDATE] =
g_signal_new ("update", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstStatisticsClass, update), NULL, NULL,
g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_statistics_finalize);
}
static void
gst_statistics_init (GstStatistics * statistics)
{
statistics->sinkpad =
gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate),
"sink");
gst_element_add_pad (GST_ELEMENT (statistics), statistics->sinkpad);
gst_pad_set_chain_function (statistics->sinkpad,
GST_DEBUG_FUNCPTR (gst_statistics_chain));
statistics->srcpad =
gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
"src");
gst_element_add_pad (GST_ELEMENT (statistics), statistics->srcpad);
statistics->timer = NULL;
statistics->last_timer = NULL;
gst_statistics_reset (statistics);
}
static void
gst_statistics_reset (GstStatistics * statistics)
{
g_return_if_fail (statistics != NULL);
g_return_if_fail (GST_IS_STATISTICS (statistics));
statistics->stats.buffers = 0;
statistics->stats.bytes = 0;
statistics->stats.events = 0;
statistics->last_stats.buffers = 0;
statistics->last_stats.bytes = 0;
statistics->last_stats.events = 0;
statistics->update_count.buffers = 0;
statistics->update_count.bytes = 0;
statistics->update_count.events = 0;
statistics->update_freq.buffers = 0;
statistics->update_freq.bytes = 0;
statistics->update_freq.events = 0;
statistics->update_on_eos = TRUE;
statistics->update = TRUE;
statistics->silent = FALSE;
if (!statistics->timer) {
statistics->timer = g_timer_new ();
}
if (!statistics->last_timer) {
statistics->last_timer = g_timer_new ();
}
}
static void
print_stats (gboolean first, const gchar * name, const gchar * type,
stats * base, stats * final, double time)
{
const gchar *header0 = "statistics";
const gchar *headerN = " ";
stats delta;
delta.buffers = final->buffers - base->buffers;
delta.bytes = final->bytes - base->bytes;
delta.events = final->events - base->events;
g_print ("%s: (%s) %s: s:%g buffers:%" G_GINT64_FORMAT
" bytes:%" G_GINT64_FORMAT
" events:%" G_GINT64_FORMAT "\n",
first ? header0 : headerN,
name, type, time, final->buffers, final->bytes, final->events);
g_print ("%s: (%s) %s: buf/s:%g B/s:%g e/s:%g B/buf:%g\n",
headerN,
name, type,
delta.buffers / time,
delta.bytes / time,
delta.events / time, ((double) delta.bytes / (double) delta.buffers));
}
static void
gst_statistics_print (GstStatistics * statistics)
{
const gchar *name;
double elapsed;
double last_elapsed;
g_return_if_fail (statistics != NULL);
g_return_if_fail (GST_IS_STATISTICS (statistics));
name = gst_object_get_name (GST_OBJECT (statistics));
if (!name) {
name = "";
}
elapsed = g_timer_elapsed (statistics->timer, NULL);
last_elapsed = g_timer_elapsed (statistics->last_timer, NULL);
print_stats (1, name, "total", &zero_stats, &statistics->stats, elapsed);
print_stats (0, name, "last", &statistics->last_stats, &statistics->stats,
last_elapsed);
statistics->last_stats = statistics->stats;
g_timer_reset (statistics->last_timer);
}
static void
gst_statistics_chain (GstPad * pad, GstData * _data)
{
GstBuffer *buf = GST_BUFFER (_data);
GstStatistics *statistics;
gboolean update = FALSE;
g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_PAD (pad));
g_return_if_fail (buf != NULL);
statistics = GST_STATISTICS (gst_pad_get_parent (pad));
if (GST_IS_EVENT (buf)) {
GstEvent *event = GST_EVENT (buf);
statistics->stats.events += 1;
if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
gst_element_set_eos (GST_ELEMENT (statistics));
if (statistics->update_on_eos) {
update = TRUE;
}
}
if (statistics->update_freq.events) {
statistics->update_count.events += 1;
if (statistics->update_count.events == statistics->update_freq.events) {
statistics->update_count.events = 0;
update = TRUE;
}
}
} else {
statistics->stats.buffers += 1;
if (statistics->update_freq.buffers) {
statistics->update_count.buffers += 1;
if (statistics->update_count.buffers == statistics->update_freq.buffers) {
statistics->update_count.buffers = 0;
update = TRUE;
}
}
statistics->stats.bytes += GST_BUFFER_SIZE (buf);
if (statistics->update_freq.bytes) {
statistics->update_count.bytes += GST_BUFFER_SIZE (buf);
if (statistics->update_count.bytes >= statistics->update_freq.bytes) {
statistics->update_count.bytes = 0;
update = TRUE;
}
}
}
if (update) {
if (statistics->update) {
GST_DEBUG ("[%s]: pre update emit", GST_ELEMENT_NAME (statistics));
g_signal_emit (G_OBJECT (statistics),
gst_statistics_signals[SIGNAL_UPDATE], 0);
GST_DEBUG ("[%s]: post update emit", GST_ELEMENT_NAME (statistics));
}
if (!statistics->silent) {
gst_statistics_print (statistics);
}
}
gst_pad_push (statistics->srcpad, GST_DATA (buf));
}
static void
gst_statistics_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstStatistics *statistics;
/* it's not null if we got it, but it might not be ours */
g_return_if_fail (GST_IS_STATISTICS (object));
statistics = GST_STATISTICS (object);
switch (prop_id) {
case ARG_BUFFER_UPDATE_FREQ:
statistics->update_freq.buffers = g_value_get_int64 (value);
break;
case ARG_BYTES_UPDATE_FREQ:
statistics->update_freq.bytes = g_value_get_int64 (value);
break;
case ARG_EVENT_UPDATE_FREQ:
statistics->update_freq.events = g_value_get_int64 (value);
break;
case ARG_UPDATE_ON_EOS:
statistics->update_on_eos = g_value_get_boolean (value);
break;
case ARG_UPDATE:
statistics->update = g_value_get_boolean (value);
break;
case ARG_SILENT:
statistics->silent = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_statistics_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
GstStatistics *statistics;
/* it's not null if we got it, but it might not be ours */
g_return_if_fail (GST_IS_STATISTICS (object));
statistics = GST_STATISTICS (object);
switch (prop_id) {
case ARG_BUFFERS:
g_value_set_int64 (value, statistics->stats.buffers);
break;
case ARG_BYTES:
g_value_set_int64 (value, statistics->stats.bytes);
break;
case ARG_EVENTS:
g_value_set_int64 (value, statistics->stats.events);
break;
case ARG_BUFFER_UPDATE_FREQ:
g_value_set_int64 (value, statistics->update_freq.buffers);
break;
case ARG_BYTES_UPDATE_FREQ:
g_value_set_int64 (value, statistics->update_freq.bytes);
break;
case ARG_EVENT_UPDATE_FREQ:
g_value_set_int64 (value, statistics->update_freq.events);
break;
case ARG_UPDATE_ON_EOS:
g_value_set_boolean (value, statistics->update_on_eos);
break;
case ARG_UPDATE:
g_value_set_boolean (value, statistics->update);
break;
case ARG_SILENT:
g_value_set_boolean (value, statistics->silent);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}

View file

@ -0,0 +1,84 @@
/* GStreamer
* Copyright (C) 2001 David I. Lehn <dlehn@users.sourceforge.net>
*
* gststatistics.h:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_STATISTICS_H__
#define __GST_STATISTICS_H__
#include <gst/gst.h>
G_BEGIN_DECLS
#define GST_TYPE_STATISTICS \
(gst_statistics_get_type())
#define GST_STATISTICS(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_STATISTICS,GstStatistics))
#define GST_STATISTICS_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_STATISTICS,GstStatisticsClass))
#define GST_IS_STATISTICS(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_STATISTICS))
#define GST_IS_STATISTICS_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_STATISTICS))
typedef struct _GstStatistics GstStatistics;
typedef struct _GstStatisticsClass GstStatisticsClass;
typedef struct _stats stats;
struct _stats {
gint64 buffers;
gint64 bytes;
gint64 events;
};
struct _GstStatistics {
GstElement element;
GstPad *sinkpad;
GstPad *srcpad;
GTimer *timer;
GTimer *last_timer;
stats stats;
stats last_stats;
stats update_count;
stats update_freq;
gboolean update_on_eos;
gboolean update;
gboolean silent;
};
struct _GstStatisticsClass {
GstElementClass parent_class;
/* signals */
void (*update) (GstElement *element);
};
GType gst_statistics_get_type(void);
G_END_DECLS
#endif /* __GST_STATISTICS_H__ */