mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-29 05:01:23 +00:00
remove elements that shouldn't be in core
Original commit message from CVS: * gst/elements/Makefile.am: * gst/elements/gstaggregator.c: * gst/elements/gstaggregator.h: * gst/elements/gstelements.c: * gst/elements/gstmd5sink.c: * gst/elements/gstmd5sink.h: * gst/elements/gstmultifilesrc.c: * gst/elements/gstmultifilesrc.h: * gst/elements/gstpipefilter.c: * gst/elements/gstpipefilter.h: * gst/elements/gstshaper.c: * gst/elements/gstshaper.h: * gst/elements/gststatistics.c: * gst/elements/gststatistics.h: * po/POTFILES.in: remove elements that shouldn't be in core
This commit is contained in:
parent
663710d482
commit
abec51e3da
30 changed files with 19 additions and 5795 deletions
19
ChangeLog
19
ChangeLog
|
@ -1,3 +1,22 @@
|
||||||
|
2005-05-16 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
||||||
|
|
||||||
|
* gst/elements/Makefile.am:
|
||||||
|
* gst/elements/gstaggregator.c:
|
||||||
|
* gst/elements/gstaggregator.h:
|
||||||
|
* gst/elements/gstelements.c:
|
||||||
|
* gst/elements/gstmd5sink.c:
|
||||||
|
* gst/elements/gstmd5sink.h:
|
||||||
|
* gst/elements/gstmultifilesrc.c:
|
||||||
|
* gst/elements/gstmultifilesrc.h:
|
||||||
|
* gst/elements/gstpipefilter.c:
|
||||||
|
* gst/elements/gstpipefilter.h:
|
||||||
|
* gst/elements/gstshaper.c:
|
||||||
|
* gst/elements/gstshaper.h:
|
||||||
|
* gst/elements/gststatistics.c:
|
||||||
|
* gst/elements/gststatistics.h:
|
||||||
|
* po/POTFILES.in:
|
||||||
|
remove elements that shouldn't be in core
|
||||||
|
|
||||||
2005-05-16 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
2005-05-16 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
||||||
|
|
||||||
* gst/autoplug/.cvsignore
|
* gst/autoplug/.cvsignore
|
||||||
|
|
|
@ -10,21 +10,8 @@ AS_LIBTOOL_LIB = libgstelements
|
||||||
EXTRA_DIST = $(as_libtool_EXTRA_DIST)
|
EXTRA_DIST = $(as_libtool_EXTRA_DIST)
|
||||||
noinst_DATA = $(as_libtool_noinst_DATA_files)
|
noinst_DATA = $(as_libtool_noinst_DATA_files)
|
||||||
|
|
||||||
# FIXME:
|
|
||||||
# Disable multifilesrc on Windows, cause it uses mmap excessively
|
|
||||||
# and I don't feel like fixing it yet. See also the disablement
|
|
||||||
# in gstelements.c.
|
|
||||||
if AS_LIBTOOL_WIN32
|
|
||||||
multifilesrc =
|
|
||||||
pipefilter =
|
|
||||||
else
|
|
||||||
multifilesrc = gstmultifilesrc.c
|
|
||||||
pipefilter = gstpipefilter.c
|
|
||||||
endif
|
|
||||||
|
|
||||||
libgstelements_la_DEPENDENCIES = ../libgstreamer-@GST_MAJORMINOR@.la
|
libgstelements_la_DEPENDENCIES = ../libgstreamer-@GST_MAJORMINOR@.la
|
||||||
libgstelements_la_SOURCES = \
|
libgstelements_la_SOURCES = \
|
||||||
gstaggregator.c \
|
|
||||||
gstbufferstore.c \
|
gstbufferstore.c \
|
||||||
gstelements.c \
|
gstelements.c \
|
||||||
gstfakesink.c \
|
gstfakesink.c \
|
||||||
|
@ -34,11 +21,6 @@ libgstelements_la_SOURCES = \
|
||||||
gstfdsink.c \
|
gstfdsink.c \
|
||||||
gstfdsrc.c \
|
gstfdsrc.c \
|
||||||
gstidentity.c \
|
gstidentity.c \
|
||||||
gstmd5sink.c \
|
|
||||||
$(multifilesrc) \
|
|
||||||
$(pipefilter) \
|
|
||||||
gstshaper.c \
|
|
||||||
gststatistics.c \
|
|
||||||
gsttee.c \
|
gsttee.c \
|
||||||
gsttypefindelement.c
|
gsttypefindelement.c
|
||||||
|
|
||||||
|
@ -47,7 +29,6 @@ libgstelements_la_LIBADD = $(GST_OBJ_LIBS)
|
||||||
libgstelements_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(as_libtool_LDFLAGS)
|
libgstelements_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(as_libtool_LDFLAGS)
|
||||||
|
|
||||||
noinst_HEADERS = \
|
noinst_HEADERS = \
|
||||||
gstaggregator.h \
|
|
||||||
gstbufferstore.h \
|
gstbufferstore.h \
|
||||||
gstfakesink.h \
|
gstfakesink.h \
|
||||||
gstfakesrc.h \
|
gstfakesrc.h \
|
||||||
|
@ -56,11 +37,6 @@ noinst_HEADERS = \
|
||||||
gstfilesink.h \
|
gstfilesink.h \
|
||||||
gstfilesrc.h \
|
gstfilesrc.h \
|
||||||
gstidentity.h \
|
gstidentity.h \
|
||||||
gstmd5sink.h \
|
|
||||||
gstmultifilesrc.h \
|
|
||||||
gstpipefilter.h \
|
|
||||||
gstshaper.h \
|
|
||||||
gststatistics.h \
|
|
||||||
gsttee.h \
|
gsttee.h \
|
||||||
gsttypefindelement.h
|
gsttypefindelement.h
|
||||||
|
|
||||||
|
|
|
@ -1,378 +0,0 @@
|
||||||
/* 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;
|
|
||||||
|
|
||||||
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);
|
|
||||||
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_aggregator_set_property);
|
|
||||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_aggregator_get_property);
|
|
||||||
|
|
||||||
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 = (guchar *) "loop";
|
|
||||||
|
|
||||||
/* then push it forward */
|
|
||||||
gst_aggregator_push (aggregator, pad, buf, debug);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (aggregator->sched == AGGREGATOR_LOOP_SELECT) {
|
|
||||||
GstPad *pad;
|
|
||||||
|
|
||||||
debug = (guchar *) "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, (guchar *) "chain");
|
|
||||||
}
|
|
|
@ -1,74 +0,0 @@
|
||||||
/* 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__ */
|
|
|
@ -27,7 +27,6 @@
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
|
||||||
#include "gstaggregator.h"
|
|
||||||
#include "gstfakesink.h"
|
#include "gstfakesink.h"
|
||||||
#include "gstfakesrc.h"
|
#include "gstfakesrc.h"
|
||||||
#include "gstfdsink.h"
|
#include "gstfdsink.h"
|
||||||
|
@ -35,11 +34,6 @@
|
||||||
#include "gstfilesink.h"
|
#include "gstfilesink.h"
|
||||||
#include "gstfilesrc.h"
|
#include "gstfilesrc.h"
|
||||||
#include "gstidentity.h"
|
#include "gstidentity.h"
|
||||||
#include "gstmd5sink.h"
|
|
||||||
#include "gstmultifilesrc.h"
|
|
||||||
#include "gstpipefilter.h"
|
|
||||||
#include "gstshaper.h"
|
|
||||||
#include "gststatistics.h"
|
|
||||||
#include "gsttee.h"
|
#include "gsttee.h"
|
||||||
#include "gsttypefindelement.h"
|
#include "gsttypefindelement.h"
|
||||||
|
|
||||||
|
@ -55,7 +49,6 @@ extern GType gst_filesrc_get_type (void);
|
||||||
extern GstElementDetails gst_filesrc_details;
|
extern GstElementDetails gst_filesrc_details;
|
||||||
|
|
||||||
static struct _elements_entry _elements[] = {
|
static struct _elements_entry _elements[] = {
|
||||||
{"aggregator", GST_RANK_NONE, gst_aggregator_get_type},
|
|
||||||
{"fakesrc", GST_RANK_NONE, gst_fakesrc_get_type},
|
{"fakesrc", GST_RANK_NONE, gst_fakesrc_get_type},
|
||||||
{"fakesink", GST_RANK_NONE, gst_fakesink_get_type},
|
{"fakesink", GST_RANK_NONE, gst_fakesink_get_type},
|
||||||
{"fdsink", GST_RANK_NONE, gst_fdsink_get_type},
|
{"fdsink", GST_RANK_NONE, gst_fdsink_get_type},
|
||||||
|
@ -63,13 +56,6 @@ static struct _elements_entry _elements[] = {
|
||||||
{"filesrc", GST_RANK_PRIMARY, gst_filesrc_get_type},
|
{"filesrc", GST_RANK_PRIMARY, gst_filesrc_get_type},
|
||||||
{"filesink", GST_RANK_NONE, gst_filesink_get_type},
|
{"filesink", GST_RANK_NONE, gst_filesink_get_type},
|
||||||
{"identity", GST_RANK_NONE, gst_identity_get_type},
|
{"identity", GST_RANK_NONE, gst_identity_get_type},
|
||||||
{"md5sink", GST_RANK_NONE, gst_md5sink_get_type},
|
|
||||||
#ifndef HAVE_WIN32
|
|
||||||
{"multifilesrc", GST_RANK_NONE, gst_multifilesrc_get_type},
|
|
||||||
{"pipefilter", GST_RANK_NONE, gst_pipefilter_get_type},
|
|
||||||
#endif
|
|
||||||
{"shaper", GST_RANK_NONE, gst_shaper_get_type},
|
|
||||||
{"statistics", GST_RANK_NONE, gst_statistics_get_type},
|
|
||||||
{"tee", GST_RANK_NONE, gst_tee_get_type},
|
{"tee", GST_RANK_NONE, gst_tee_get_type},
|
||||||
{"typefind", GST_RANK_NONE, gst_type_find_element_get_type},
|
{"typefind", GST_RANK_NONE, gst_type_find_element_get_type},
|
||||||
{NULL, 0},
|
{NULL, 0},
|
||||||
|
|
|
@ -1,498 +0,0 @@
|
||||||
/* 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;
|
|
||||||
gchar *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);
|
|
||||||
}
|
|
|
@ -1,74 +0,0 @@
|
||||||
/* 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__ */
|
|
|
@ -1,366 +0,0 @@
|
||||||
/* 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;
|
|
||||||
|
|
||||||
|
|
||||||
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));
|
|
||||||
|
|
||||||
|
|
||||||
gobject_class->set_property = gst_multifilesrc_set_property;
|
|
||||||
gobject_class->get_property = gst_multifilesrc_get_property;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
|
@ -1,85 +0,0 @@
|
||||||
/* 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__ */
|
|
|
@ -1,356 +0,0 @@
|
||||||
/* 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;
|
|
||||||
}
|
|
|
@ -1,81 +0,0 @@
|
||||||
/* 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__ */
|
|
|
@ -1,374 +0,0 @@
|
||||||
/* 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;
|
|
||||||
|
|
||||||
|
|
||||||
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));
|
|
||||||
|
|
||||||
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_shaper_set_property);
|
|
||||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_shaper_get_property);
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,72 +0,0 @@
|
||||||
/* 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__ */
|
|
|
@ -1,416 +0,0 @@
|
||||||
/* 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);
|
|
||||||
|
|
||||||
|
|
||||||
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);
|
|
||||||
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_statistics_set_property);
|
|
||||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_statistics_get_property);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,84 +0,0 @@
|
||||||
/* 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__ */
|
|
|
@ -10,21 +10,8 @@ AS_LIBTOOL_LIB = libgstelements
|
||||||
EXTRA_DIST = $(as_libtool_EXTRA_DIST)
|
EXTRA_DIST = $(as_libtool_EXTRA_DIST)
|
||||||
noinst_DATA = $(as_libtool_noinst_DATA_files)
|
noinst_DATA = $(as_libtool_noinst_DATA_files)
|
||||||
|
|
||||||
# FIXME:
|
|
||||||
# Disable multifilesrc on Windows, cause it uses mmap excessively
|
|
||||||
# and I don't feel like fixing it yet. See also the disablement
|
|
||||||
# in gstelements.c.
|
|
||||||
if AS_LIBTOOL_WIN32
|
|
||||||
multifilesrc =
|
|
||||||
pipefilter =
|
|
||||||
else
|
|
||||||
multifilesrc = gstmultifilesrc.c
|
|
||||||
pipefilter = gstpipefilter.c
|
|
||||||
endif
|
|
||||||
|
|
||||||
libgstelements_la_DEPENDENCIES = ../libgstreamer-@GST_MAJORMINOR@.la
|
libgstelements_la_DEPENDENCIES = ../libgstreamer-@GST_MAJORMINOR@.la
|
||||||
libgstelements_la_SOURCES = \
|
libgstelements_la_SOURCES = \
|
||||||
gstaggregator.c \
|
|
||||||
gstbufferstore.c \
|
gstbufferstore.c \
|
||||||
gstelements.c \
|
gstelements.c \
|
||||||
gstfakesink.c \
|
gstfakesink.c \
|
||||||
|
@ -34,11 +21,6 @@ libgstelements_la_SOURCES = \
|
||||||
gstfdsink.c \
|
gstfdsink.c \
|
||||||
gstfdsrc.c \
|
gstfdsrc.c \
|
||||||
gstidentity.c \
|
gstidentity.c \
|
||||||
gstmd5sink.c \
|
|
||||||
$(multifilesrc) \
|
|
||||||
$(pipefilter) \
|
|
||||||
gstshaper.c \
|
|
||||||
gststatistics.c \
|
|
||||||
gsttee.c \
|
gsttee.c \
|
||||||
gsttypefindelement.c
|
gsttypefindelement.c
|
||||||
|
|
||||||
|
@ -47,7 +29,6 @@ libgstelements_la_LIBADD = $(GST_OBJ_LIBS)
|
||||||
libgstelements_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(as_libtool_LDFLAGS)
|
libgstelements_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(as_libtool_LDFLAGS)
|
||||||
|
|
||||||
noinst_HEADERS = \
|
noinst_HEADERS = \
|
||||||
gstaggregator.h \
|
|
||||||
gstbufferstore.h \
|
gstbufferstore.h \
|
||||||
gstfakesink.h \
|
gstfakesink.h \
|
||||||
gstfakesrc.h \
|
gstfakesrc.h \
|
||||||
|
@ -56,11 +37,6 @@ noinst_HEADERS = \
|
||||||
gstfilesink.h \
|
gstfilesink.h \
|
||||||
gstfilesrc.h \
|
gstfilesrc.h \
|
||||||
gstidentity.h \
|
gstidentity.h \
|
||||||
gstmd5sink.h \
|
|
||||||
gstmultifilesrc.h \
|
|
||||||
gstpipefilter.h \
|
|
||||||
gstshaper.h \
|
|
||||||
gststatistics.h \
|
|
||||||
gsttee.h \
|
gsttee.h \
|
||||||
gsttypefindelement.h
|
gsttypefindelement.h
|
||||||
|
|
||||||
|
|
|
@ -1,378 +0,0 @@
|
||||||
/* 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;
|
|
||||||
|
|
||||||
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);
|
|
||||||
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_aggregator_set_property);
|
|
||||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_aggregator_get_property);
|
|
||||||
|
|
||||||
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 = (guchar *) "loop";
|
|
||||||
|
|
||||||
/* then push it forward */
|
|
||||||
gst_aggregator_push (aggregator, pad, buf, debug);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (aggregator->sched == AGGREGATOR_LOOP_SELECT) {
|
|
||||||
GstPad *pad;
|
|
||||||
|
|
||||||
debug = (guchar *) "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, (guchar *) "chain");
|
|
||||||
}
|
|
|
@ -1,74 +0,0 @@
|
||||||
/* 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__ */
|
|
|
@ -27,7 +27,6 @@
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
|
||||||
#include "gstaggregator.h"
|
|
||||||
#include "gstfakesink.h"
|
#include "gstfakesink.h"
|
||||||
#include "gstfakesrc.h"
|
#include "gstfakesrc.h"
|
||||||
#include "gstfdsink.h"
|
#include "gstfdsink.h"
|
||||||
|
@ -35,11 +34,6 @@
|
||||||
#include "gstfilesink.h"
|
#include "gstfilesink.h"
|
||||||
#include "gstfilesrc.h"
|
#include "gstfilesrc.h"
|
||||||
#include "gstidentity.h"
|
#include "gstidentity.h"
|
||||||
#include "gstmd5sink.h"
|
|
||||||
#include "gstmultifilesrc.h"
|
|
||||||
#include "gstpipefilter.h"
|
|
||||||
#include "gstshaper.h"
|
|
||||||
#include "gststatistics.h"
|
|
||||||
#include "gsttee.h"
|
#include "gsttee.h"
|
||||||
#include "gsttypefindelement.h"
|
#include "gsttypefindelement.h"
|
||||||
|
|
||||||
|
@ -55,7 +49,6 @@ extern GType gst_filesrc_get_type (void);
|
||||||
extern GstElementDetails gst_filesrc_details;
|
extern GstElementDetails gst_filesrc_details;
|
||||||
|
|
||||||
static struct _elements_entry _elements[] = {
|
static struct _elements_entry _elements[] = {
|
||||||
{"aggregator", GST_RANK_NONE, gst_aggregator_get_type},
|
|
||||||
{"fakesrc", GST_RANK_NONE, gst_fakesrc_get_type},
|
{"fakesrc", GST_RANK_NONE, gst_fakesrc_get_type},
|
||||||
{"fakesink", GST_RANK_NONE, gst_fakesink_get_type},
|
{"fakesink", GST_RANK_NONE, gst_fakesink_get_type},
|
||||||
{"fdsink", GST_RANK_NONE, gst_fdsink_get_type},
|
{"fdsink", GST_RANK_NONE, gst_fdsink_get_type},
|
||||||
|
@ -63,13 +56,6 @@ static struct _elements_entry _elements[] = {
|
||||||
{"filesrc", GST_RANK_PRIMARY, gst_filesrc_get_type},
|
{"filesrc", GST_RANK_PRIMARY, gst_filesrc_get_type},
|
||||||
{"filesink", GST_RANK_NONE, gst_filesink_get_type},
|
{"filesink", GST_RANK_NONE, gst_filesink_get_type},
|
||||||
{"identity", GST_RANK_NONE, gst_identity_get_type},
|
{"identity", GST_RANK_NONE, gst_identity_get_type},
|
||||||
{"md5sink", GST_RANK_NONE, gst_md5sink_get_type},
|
|
||||||
#ifndef HAVE_WIN32
|
|
||||||
{"multifilesrc", GST_RANK_NONE, gst_multifilesrc_get_type},
|
|
||||||
{"pipefilter", GST_RANK_NONE, gst_pipefilter_get_type},
|
|
||||||
#endif
|
|
||||||
{"shaper", GST_RANK_NONE, gst_shaper_get_type},
|
|
||||||
{"statistics", GST_RANK_NONE, gst_statistics_get_type},
|
|
||||||
{"tee", GST_RANK_NONE, gst_tee_get_type},
|
{"tee", GST_RANK_NONE, gst_tee_get_type},
|
||||||
{"typefind", GST_RANK_NONE, gst_type_find_element_get_type},
|
{"typefind", GST_RANK_NONE, gst_type_find_element_get_type},
|
||||||
{NULL, 0},
|
{NULL, 0},
|
||||||
|
|
|
@ -1,498 +0,0 @@
|
||||||
/* 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;
|
|
||||||
gchar *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);
|
|
||||||
}
|
|
|
@ -1,74 +0,0 @@
|
||||||
/* 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__ */
|
|
|
@ -1,366 +0,0 @@
|
||||||
/* 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;
|
|
||||||
|
|
||||||
|
|
||||||
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));
|
|
||||||
|
|
||||||
|
|
||||||
gobject_class->set_property = gst_multifilesrc_set_property;
|
|
||||||
gobject_class->get_property = gst_multifilesrc_get_property;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
|
@ -1,85 +0,0 @@
|
||||||
/* 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__ */
|
|
|
@ -1,356 +0,0 @@
|
||||||
/* 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;
|
|
||||||
}
|
|
|
@ -1,81 +0,0 @@
|
||||||
/* 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__ */
|
|
|
@ -1,374 +0,0 @@
|
||||||
/* 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;
|
|
||||||
|
|
||||||
|
|
||||||
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));
|
|
||||||
|
|
||||||
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_shaper_set_property);
|
|
||||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_shaper_get_property);
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,72 +0,0 @@
|
||||||
/* 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__ */
|
|
|
@ -1,416 +0,0 @@
|
||||||
/* 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);
|
|
||||||
|
|
||||||
|
|
||||||
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);
|
|
||||||
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_statistics_set_property);
|
|
||||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_statistics_get_property);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,84 +0,0 @@
|
||||||
/* 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__ */
|
|
|
@ -4,13 +4,10 @@ gst/gst.c
|
||||||
gst/gstelement.c
|
gst/gstelement.c
|
||||||
gst/gsterror.c
|
gst/gsterror.c
|
||||||
gst/gsttag.c
|
gst/gsttag.c
|
||||||
gst/autoplug/gstspider.c
|
|
||||||
gst/elements/gstfakesink.c
|
gst/elements/gstfakesink.c
|
||||||
gst/elements/gstfilesink.c
|
gst/elements/gstfilesink.c
|
||||||
gst/elements/gstfilesrc.c
|
gst/elements/gstfilesrc.c
|
||||||
gst/elements/gstidentity.c
|
gst/elements/gstidentity.c
|
||||||
gst/elements/gstmultifilesrc.c
|
|
||||||
gst/elements/gstpipefilter.c
|
|
||||||
gst/elements/gsttypefindelement.c
|
gst/elements/gsttypefindelement.c
|
||||||
gst/parse/grammar.y
|
gst/parse/grammar.y
|
||||||
tools/gst-inspect.c
|
tools/gst-inspect.c
|
||||||
|
|
Loading…
Reference in a new issue