mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-05-04 23:44:48 +00:00
tests/complexity.c: Adjust to lack of gst_bin_iterate, boolean link return values.
Original commit message from CVS: 2005-03-01 Andy Wingo <wingo@pobox.com> * tests/complexity.c: Adjust to lack of gst_bin_iterate, boolean link return values. * gst/elements/gsttee.c, gst/elements/gsttee.h: I am the master of do-nothing plugins! Fear the dev-zero! * gst/elements/gstelements.c * gst/elements/Makefile.am: Add tee back to gstelements. * gst/gstutils.h * gst/gstutils.c (gst_pad_proxy_getcaps, gst_pad_proxy_setcaps): Resurrect from the dead. Use gst_iterator_fold to be threadsafe. * gst/gstiterator.h (GstIteratorFoldFunction): Return a bool. * gst/gstiterator.c (gst_iterator_fold): Only continue folding as long as the fold function returns TRUE. Add a bunch o docs. (gst_iterator_foreach): Add docs about when the iterator will be freed. (gst_iterator_find_custom): Make more efficient because of the bool-return-value thing. * check/gst/gstiterator.c (add_fold_func): Adapt to new fold-funcs-returning-bool policy. * gst/gstutils.h: * gst/gstutils.c (gst_element_link, gst_element_link_many) (gst_element_link_filtered, gst_element_link_pads) (gst_element_link_pads_filtered): It seems Wim changed the return type to booleans internally. Assume he knows what he's doing and change the prototypes as well.
This commit is contained in:
parent
c32ed239dd
commit
70d2a801d9
19 changed files with 735 additions and 344 deletions
72
ChangeLog
72
ChangeLog
|
@ -1,3 +1,75 @@
|
|||
2005-03-01 Andy Wingo <wingo@pobox.com>
|
||||
|
||||
* tests/complexity.c: Adjust to lack of gst_bin_iterate, boolean
|
||||
link return values.
|
||||
|
||||
* gst/elements/gsttee.c, gst/elements/gsttee.h: I am the master of
|
||||
do-nothing plugins! Fear the dev-zero!
|
||||
|
||||
* gst/elements/gstelements.c
|
||||
* gst/elements/Makefile.am: Add tee back to gstelements.
|
||||
|
||||
* gst/gstutils.h
|
||||
* gst/gstutils.c (gst_pad_proxy_getcaps, gst_pad_proxy_setcaps):
|
||||
Resurrect from the dead. Use gst_iterator_fold to be threadsafe.
|
||||
|
||||
* gst/gstiterator.h (GstIteratorFoldFunction): Return a bool.
|
||||
|
||||
* gst/gstiterator.c (gst_iterator_fold): Only continue folding as
|
||||
long as the fold function returns TRUE. Add a bunch o docs.
|
||||
(gst_iterator_foreach): Add docs about when the iterator will be
|
||||
freed.
|
||||
(gst_iterator_find_custom): Make more efficient because of the
|
||||
bool-return-value thing.
|
||||
|
||||
* check/gst/gstiterator.c (add_fold_func): Adapt to new
|
||||
fold-funcs-returning-bool policy.
|
||||
|
||||
* gst/gstutils.h:
|
||||
* gst/gstutils.c (gst_element_link, gst_element_link_many)
|
||||
(gst_element_link_filtered, gst_element_link_pads)
|
||||
(gst_element_link_pads_filtered): It seems Wim changed the return
|
||||
type to booleans internally. Assume he knows what he's doing and
|
||||
change the prototypes as well.
|
||||
|
||||
* tests/Makefile.am, tests/complexity.c:
|
||||
* tests/complexity.gnuplot, tests/bench-complexity.scm: Merge in
|
||||
complexity tests from HEAD.
|
||||
|
||||
* gst/gstpipeline.c: Fix element details.
|
||||
(gst_pipeline_set_property, gst_pipeline_get_property): Lock
|
||||
around the whole get/set properties.
|
||||
|
||||
* gst/gstpad.c (gst_real_pad_set_property): Add a FIXME, the
|
||||
::active property doesn't make sense any more.
|
||||
(gst_pad_set_active): Check to see if the pad has the right
|
||||
functions to be activated in this mode.
|
||||
(gst_pad_event_default): Handle EOS specially, pausing the task on
|
||||
the pad if necessary.
|
||||
|
||||
* gst/gstbin.c: Adapt callers of gst_iterator_foreach and
|
||||
gst_iterator_filter to new argument order.
|
||||
|
||||
* gst/gstiterator.c (gst_iterator_find_custom)
|
||||
(gst_iterator_foreach): Implement on top of gst_iterator_fold
|
||||
instead of using the filter_next internals. A bit cleaner this
|
||||
way.
|
||||
|
||||
* gst/gstiterator.h:
|
||||
(gst_iterator_filter, gst_iterator_find_custom): Switch the
|
||||
argument order so user_data is last.
|
||||
(gst_iterator_foreach): Return the GstIteratorResult so the caller
|
||||
knows if all elements were called, or if an error or resync
|
||||
happened.
|
||||
(gst_iterator_fold): New procedure.
|
||||
|
||||
* check/Makefile.am (TESTS):
|
||||
* check/gst/gstiterator.c: New test suite for GstIterator. Checks
|
||||
that iterating through a list hits all members in order, that
|
||||
resync works correctly, and that fold works.
|
||||
|
||||
* gst/base/gstbasesink.c (gst_basesink_event): Fix Waymans bug.
|
||||
|
||||
2005-02-24 Wim Taymans <wim@fluendo.com>
|
||||
|
||||
* gst/base/README:
|
||||
|
|
|
@ -115,10 +115,11 @@ START_TEST (test_resync)
|
|||
|
||||
gst_iterator_free (iter);
|
||||
}
|
||||
END_TEST static void
|
||||
END_TEST static gboolean
|
||||
add_fold_func (gpointer item, GValue * ret, gpointer user_data)
|
||||
{
|
||||
g_value_set_int (ret, g_value_get_int (ret) + GPOINTER_TO_INT (item));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
START_TEST (test_fold)
|
||||
|
|
|
@ -394,39 +394,6 @@ Sets the parent of an element.
|
|||
@clock:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gst_element_clock_wait ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
@element:
|
||||
@id:
|
||||
@jitter:
|
||||
@Returns:
|
||||
<!-- # Unused Parameters # -->
|
||||
@clock:
|
||||
@time:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gst_element_get_time ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
@element:
|
||||
@Returns:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gst_element_wait ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
@element:
|
||||
@timestamp:
|
||||
@Returns:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gst_element_is_indexable ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -29,8 +29,19 @@ the pipeline, use gst_object_unref() to free its resources.
|
|||
@fixed_clock:
|
||||
@stream_time:
|
||||
@delay:
|
||||
@play_timeout:
|
||||
@eosed:
|
||||
|
||||
<!-- ##### ARG GstPipeline:delay ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
<!-- ##### ARG GstPipeline:play-timeout ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
<!-- ##### FUNCTION gst_pipeline_new ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -29,19 +29,19 @@ libgstelements_la_SOURCES = \
|
|||
gstfilesrc.c \
|
||||
gstidentity.c \
|
||||
gstelements.c \
|
||||
#gstaggregator.c \
|
||||
gstbufferstore.c \
|
||||
gstfakesink.c \
|
||||
gstfilesink.c \
|
||||
gstfdsink.c \
|
||||
gstfdsrc.c \
|
||||
gstmd5sink.c \
|
||||
$(multifilesrc) \
|
||||
$(pipefilter) \
|
||||
gstshaper.c \
|
||||
gststatistics.c \
|
||||
gsttee.c \
|
||||
gsttypefindelement.c
|
||||
gsttee.c
|
||||
|
||||
# gstaggregator.c \
|
||||
# gstbufferstore.c \
|
||||
# gstfilesink.c \
|
||||
# gstfdsink.c \
|
||||
# gstfdsrc.c \
|
||||
# gstmd5sink.c \
|
||||
# $(multifilesrc) \
|
||||
# $(pipefilter) \
|
||||
# gstshaper.c \
|
||||
# gststatistics.c \
|
||||
# gsttypefindelement.c
|
||||
|
||||
libgstelements_la_CFLAGS = $(GST_OBJ_CFLAGS)
|
||||
libgstelements_la_LIBADD = $(GST_OBJ_LIBS)
|
||||
|
|
|
@ -70,7 +70,7 @@ static struct _elements_entry _elements[] = {
|
|||
#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},
|
||||
// {NULL, 0},
|
||||
};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wim.taymans@chello.be>
|
||||
* 2000,2001,2002,2003,2004,2005 Wim Taymans <wim@fluendo.com>
|
||||
*
|
||||
*
|
||||
* gsttee.c: Tee element, one in N out
|
||||
*
|
||||
|
@ -40,21 +41,16 @@ GstElementDetails gst_tee_details = GST_ELEMENT_DETAILS ("Tee pipe fitting",
|
|||
"Generic",
|
||||
"1-to-N pipe fitting",
|
||||
"Erik Walthinsen <omega@cse.ogi.edu>, "
|
||||
"Wim Taymans <wim.taymans@chello.be>");
|
||||
|
||||
/* Tee signals and args */
|
||||
enum
|
||||
{
|
||||
/* FILL ME */
|
||||
LAST_SIGNAL
|
||||
};
|
||||
"Wim \"Tim\" Taymans <wim@fluendo.com>");
|
||||
|
||||
enum
|
||||
{
|
||||
ARG_0,
|
||||
ARG_SILENT,
|
||||
ARG_NUM_PADS,
|
||||
ARG_LAST_MESSAGE
|
||||
PROP_0,
|
||||
PROP_NUM_SRC_PADS,
|
||||
PROP_HAS_SINK_LOOP,
|
||||
PROP_HAS_CHAIN,
|
||||
PROP_SILENT,
|
||||
PROP_LAST_MESSAGE
|
||||
/* FILL ME */
|
||||
};
|
||||
|
||||
|
@ -77,7 +73,9 @@ static void gst_tee_set_property (GObject * object, guint prop_id,
|
|||
static void gst_tee_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
|
||||
static void gst_tee_chain (GstPad * pad, GstData * _data);
|
||||
static GstFlowReturn gst_tee_chain (GstPad * pad, GstBuffer * buffer);
|
||||
static void gst_tee_loop (GstPad * pad);
|
||||
static gboolean gst_tee_sink_activate (GstPad * pad, GstActivateMode mode);
|
||||
|
||||
|
||||
static void
|
||||
|
@ -113,22 +111,26 @@ gst_tee_class_init (GstTeeClass * klass)
|
|||
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", "num_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", "silent",
|
||||
TRUE, G_PARAM_CONSTRUCT | 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->finalize = GST_DEBUG_FUNCPTR (gst_tee_finalize);
|
||||
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_tee_set_property);
|
||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_tee_get_property);
|
||||
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NUM_SRC_PADS,
|
||||
g_param_spec_int ("num-src-pads", "num-src-pads", "num-src-pads",
|
||||
0, G_MAXINT, 0, G_PARAM_READABLE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_SINK_LOOP,
|
||||
g_param_spec_boolean ("has-sink-loop", "has-sink-loop", "has-sink-loop",
|
||||
FALSE, G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_CHAIN,
|
||||
g_param_spec_boolean ("has-chain", "has-chain", "has-chain",
|
||||
TRUE, G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SILENT,
|
||||
g_param_spec_boolean ("silent", "silent", "silent",
|
||||
TRUE, G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LAST_MESSAGE,
|
||||
g_param_spec_string ("last_message", "last_message", "last_message",
|
||||
NULL, G_PARAM_READABLE));
|
||||
|
||||
gstelement_class->request_new_pad =
|
||||
GST_DEBUG_FUNCPTR (gst_tee_request_new_pad);
|
||||
}
|
||||
|
@ -140,25 +142,30 @@ gst_tee_init (GstTee * tee)
|
|||
gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate),
|
||||
"sink");
|
||||
gst_element_add_pad (GST_ELEMENT (tee), tee->sinkpad);
|
||||
gst_pad_set_chain_function (tee->sinkpad, GST_DEBUG_FUNCPTR (gst_tee_chain));
|
||||
gst_pad_set_link_function (tee->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_pad_proxy_pad_link));
|
||||
gst_pad_set_setcaps_function (tee->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_pad_proxy_setcaps));
|
||||
gst_pad_set_getcaps_function (tee->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
|
||||
|
||||
tee->last_message = NULL;
|
||||
}
|
||||
|
||||
/* helper compare function */
|
||||
gint
|
||||
name_pad_compare (gconstpointer a, gconstpointer b)
|
||||
static void
|
||||
gst_tee_update_pad_functions (GstTee * tee)
|
||||
{
|
||||
GstPad *pad = (GstPad *) a;
|
||||
gchar *name = (gchar *) b;
|
||||
gst_pad_set_activate_function (tee->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_tee_sink_activate));
|
||||
|
||||
g_assert (GST_IS_PAD (pad));
|
||||
if (tee->has_chain)
|
||||
gst_pad_set_chain_function (tee->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_tee_chain));
|
||||
else
|
||||
gst_pad_set_chain_function (tee->sinkpad, NULL);
|
||||
|
||||
return strcmp (name, gst_pad_get_name (pad)); /* returns 0 if match */
|
||||
if (tee->has_sink_loop)
|
||||
gst_pad_set_loop_function (tee->sinkpad, GST_DEBUG_FUNCPTR (gst_tee_loop));
|
||||
else
|
||||
gst_pad_set_loop_function (tee->sinkpad, NULL);
|
||||
}
|
||||
|
||||
static GstPad *
|
||||
|
@ -168,50 +175,21 @@ gst_tee_request_new_pad (GstElement * element, GstPadTemplate * templ,
|
|||
gchar *name;
|
||||
GstPad *srcpad;
|
||||
GstTee *tee;
|
||||
gint i = 0;
|
||||
const GList *pads;
|
||||
|
||||
g_return_val_if_fail (GST_IS_TEE (element), NULL);
|
||||
|
||||
if (templ->direction != GST_PAD_SRC) {
|
||||
g_warning ("gsttee: request new pad that is not a SRC pad\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tee = GST_TEE (element);
|
||||
|
||||
/* try names in order and find one that's not in use atm */
|
||||
pads = gst_element_get_pad_list (element);
|
||||
|
||||
name = NULL;
|
||||
while (!name) {
|
||||
name = g_strdup_printf ("src%d", i);
|
||||
if (g_list_find_custom ((GList *) pads, (gconstpointer) name,
|
||||
name_pad_compare) != NULL) {
|
||||
/* this name is taken, use the next one */
|
||||
++i;
|
||||
g_free (name);
|
||||
name = NULL;
|
||||
}
|
||||
}
|
||||
if (!tee->silent) {
|
||||
g_free (tee->last_message);
|
||||
tee->last_message = g_strdup_printf ("new pad %s", name);
|
||||
g_object_notify (G_OBJECT (tee), "last_message");
|
||||
}
|
||||
GST_LOCK (tee);
|
||||
name = g_strdup_printf ("src%d", tee->pad_counter++);
|
||||
GST_UNLOCK (tee);
|
||||
|
||||
srcpad = gst_pad_new_from_template (templ, name);
|
||||
g_free (name);
|
||||
gst_pad_set_link_function (srcpad,
|
||||
GST_DEBUG_FUNCPTR (gst_pad_proxy_pad_link));
|
||||
|
||||
gst_pad_set_setcaps_function (srcpad,
|
||||
GST_DEBUG_FUNCPTR (gst_pad_proxy_setcaps));
|
||||
gst_pad_set_getcaps_function (srcpad,
|
||||
GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
|
||||
gst_element_add_pad (GST_ELEMENT (tee), srcpad);
|
||||
GST_PAD_ELEMENT_PRIVATE (srcpad) = NULL;
|
||||
|
||||
if (GST_PAD_CAPS (tee->sinkpad)) {
|
||||
gst_pad_try_set_caps (srcpad, GST_PAD_CAPS (tee->sinkpad));
|
||||
}
|
||||
|
||||
return srcpad;
|
||||
}
|
||||
|
@ -220,95 +198,202 @@ static void
|
|||
gst_tee_set_property (GObject * object, guint prop_id, const GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
GstTee *tee;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail (GST_IS_TEE (object));
|
||||
|
||||
tee = GST_TEE (object);
|
||||
GstTee *tee = GST_TEE (object);
|
||||
|
||||
GST_LOCK (tee);
|
||||
switch (prop_id) {
|
||||
case ARG_SILENT:
|
||||
case PROP_HAS_SINK_LOOP:
|
||||
tee->has_sink_loop = g_value_get_boolean (value);
|
||||
gst_tee_update_pad_functions (tee);
|
||||
break;
|
||||
case PROP_HAS_CHAIN:
|
||||
tee->has_chain = g_value_get_boolean (value);
|
||||
gst_tee_update_pad_functions (tee);
|
||||
break;
|
||||
case PROP_SILENT:
|
||||
tee->silent = g_value_get_boolean (value);
|
||||
g_object_notify (G_OBJECT (tee), "silent");
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
GST_UNLOCK (tee);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_tee_get_property (GObject * object, guint prop_id, GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
GstTee *tee;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail (GST_IS_TEE (object));
|
||||
|
||||
tee = GST_TEE (object);
|
||||
GstTee *tee = GST_TEE (object);
|
||||
|
||||
GST_LOCK (tee);
|
||||
switch (prop_id) {
|
||||
case ARG_NUM_PADS:
|
||||
case PROP_NUM_SRC_PADS:
|
||||
g_value_set_int (value, GST_ELEMENT (tee)->numsrcpads);
|
||||
break;
|
||||
case ARG_SILENT:
|
||||
case PROP_HAS_SINK_LOOP:
|
||||
g_value_set_boolean (value, tee->has_sink_loop);
|
||||
break;
|
||||
case PROP_HAS_CHAIN:
|
||||
g_value_set_boolean (value, tee->has_chain);
|
||||
break;
|
||||
case PROP_SILENT:
|
||||
g_value_set_boolean (value, tee->silent);
|
||||
break;
|
||||
case ARG_LAST_MESSAGE:
|
||||
case PROP_LAST_MESSAGE:
|
||||
g_value_set_string (value, tee->last_message);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
GST_UNLOCK (tee);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_tee_chain:
|
||||
* @pad: the pad to follow
|
||||
* @buf: the buffer to pass
|
||||
*
|
||||
* Chain a buffer on a pad.
|
||||
*/
|
||||
static void
|
||||
gst_tee_chain (GstPad * pad, GstData * _data)
|
||||
typedef struct
|
||||
{
|
||||
GstBuffer *buf = GST_BUFFER (_data);
|
||||
GstTee *tee;
|
||||
const GList *pads;
|
||||
GstBuffer *buffer;
|
||||
} PushData;
|
||||
|
||||
g_return_if_fail (pad != NULL);
|
||||
g_return_if_fail (GST_IS_PAD (pad));
|
||||
g_return_if_fail (buf != NULL);
|
||||
static gboolean
|
||||
gst_tee_do_push (GstPad * pad, GValue * ret, PushData * data)
|
||||
{
|
||||
GstFlowReturn res;
|
||||
|
||||
if (GST_PAD_DIRECTION (pad) != GST_PAD_SRC || !GST_PAD_IS_USABLE (pad))
|
||||
return TRUE;
|
||||
|
||||
if (G_UNLIKELY (!data->tee->silent)) {
|
||||
GstTee *tee = data->tee;
|
||||
GstBuffer *buf = data->buffer;
|
||||
|
||||
g_free (tee->last_message);
|
||||
tee->last_message =
|
||||
g_strdup_printf ("chain ******* (%s:%s)t (%d bytes, %"
|
||||
G_GUINT64_FORMAT ") %p", GST_DEBUG_PAD_NAME (pad),
|
||||
GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf), buf);
|
||||
g_object_notify (G_OBJECT (tee), "last_message");
|
||||
}
|
||||
|
||||
res = gst_pad_push (pad, gst_buffer_ref (data->buffer));
|
||||
g_value_set_enum (ret, res);
|
||||
return (res == GST_FLOW_OK);
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_tee_handle_buffer (GstTee * tee, GstBuffer * buffer)
|
||||
{
|
||||
GstIterator *iter;
|
||||
PushData data;
|
||||
GValue ret = { 0, };
|
||||
GstIteratorResult res;
|
||||
|
||||
tee->offset += GST_BUFFER_SIZE (buffer);
|
||||
|
||||
g_value_init (&ret, GST_TYPE_FLOW_RETURN);
|
||||
iter = gst_element_iterate_pads (GST_ELEMENT (tee));
|
||||
data.tee = tee;
|
||||
data.buffer = buffer;
|
||||
|
||||
res = gst_iterator_fold (iter, (GstIteratorFoldFunction) gst_tee_do_push,
|
||||
&ret, &data);
|
||||
if (res != GST_ITERATOR_DONE)
|
||||
gst_iterator_free (iter);
|
||||
gst_buffer_unref (buffer);
|
||||
|
||||
/* no need to unset gvalue */
|
||||
return g_value_get_enum (&ret);
|
||||
}
|
||||
|
||||
#define WITH_STREAM_LOCK(pad, expr) G_STMT_START {\
|
||||
GST_STREAM_LOCK (pad); \
|
||||
expr; \
|
||||
GST_STREAM_UNLOCK (pad); \
|
||||
}G_STMT_END
|
||||
|
||||
static GstFlowReturn
|
||||
gst_tee_chain (GstPad * pad, GstBuffer * buffer)
|
||||
{
|
||||
GstFlowReturn res;
|
||||
GstTee *tee;
|
||||
|
||||
tee = GST_TEE (gst_pad_get_parent (pad));
|
||||
|
||||
gst_buffer_ref_by_count (buf, GST_ELEMENT (tee)->numsrcpads - 1);
|
||||
WITH_STREAM_LOCK (pad, res = gst_tee_handle_buffer (tee, buffer));
|
||||
|
||||
pads = gst_element_get_pad_list (GST_ELEMENT (tee));
|
||||
|
||||
while (pads) {
|
||||
GstPad *outpad = GST_PAD (pads->data);
|
||||
|
||||
pads = g_list_next (pads);
|
||||
|
||||
if (GST_PAD_DIRECTION (outpad) != GST_PAD_SRC)
|
||||
continue;
|
||||
|
||||
if (!tee->silent) {
|
||||
g_free (tee->last_message);
|
||||
tee->last_message =
|
||||
g_strdup_printf ("chain ******* (%s:%s)t (%d bytes, %"
|
||||
G_GUINT64_FORMAT ") %p", GST_DEBUG_PAD_NAME (outpad),
|
||||
GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf), buf);
|
||||
g_object_notify (G_OBJECT (tee), "last_message");
|
||||
}
|
||||
|
||||
if (GST_PAD_IS_USABLE (outpad))
|
||||
gst_pad_push (outpad, GST_DATA (buf));
|
||||
else
|
||||
gst_buffer_unref (buf);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
#define DEFAULT_SIZE 1024
|
||||
|
||||
static void
|
||||
gst_tee_loop (GstPad * pad)
|
||||
{
|
||||
GstBuffer *buffer;
|
||||
GstFlowReturn res;
|
||||
GstTee *tee;
|
||||
|
||||
GST_STREAM_LOCK (pad);
|
||||
|
||||
tee = GST_TEE (gst_pad_get_parent (pad));
|
||||
|
||||
res = gst_pad_pull_range (pad, tee->offset, DEFAULT_SIZE, &buffer);
|
||||
if (res != GST_FLOW_OK)
|
||||
goto pause_task;
|
||||
|
||||
res = gst_tee_handle_buffer (tee, buffer);
|
||||
if (res != GST_FLOW_OK)
|
||||
goto pause_task;
|
||||
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
return;
|
||||
|
||||
pause_task:
|
||||
gst_pad_pause_task (pad);
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
return;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_tee_sink_activate (GstPad * pad, GstActivateMode mode)
|
||||
{
|
||||
gboolean result = FALSE;
|
||||
GstTee *tee;
|
||||
|
||||
tee = GST_TEE (GST_OBJECT_PARENT (pad));
|
||||
|
||||
switch (mode) {
|
||||
case GST_ACTIVATE_PUSH:
|
||||
g_return_val_if_fail (tee->has_chain, FALSE);
|
||||
result = TRUE;
|
||||
break;
|
||||
case GST_ACTIVATE_PULL:
|
||||
g_return_val_if_fail (tee->has_sink_loop, FALSE);
|
||||
if (GST_ELEMENT_SCHEDULER (tee)) {
|
||||
GST_STREAM_LOCK (pad);
|
||||
GST_RPAD_TASK (pad) =
|
||||
gst_scheduler_create_task (GST_ELEMENT_SCHEDULER (tee),
|
||||
(GstTaskFunction) gst_tee_loop, pad);
|
||||
|
||||
gst_pad_start_task (pad);
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
result = TRUE;
|
||||
}
|
||||
break;
|
||||
case GST_ACTIVATE_NONE:
|
||||
GST_STREAM_LOCK (pad);
|
||||
if (GST_RPAD_TASK (pad)) {
|
||||
gst_pad_stop_task (pad);
|
||||
gst_object_unref (GST_OBJECT (GST_RPAD_TASK (pad)));
|
||||
GST_RPAD_TASK (pad) = NULL;
|
||||
}
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
|
||||
result = TRUE;
|
||||
break;
|
||||
}
|
||||
tee->sink_mode = mode;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -49,6 +49,12 @@ struct _GstTee {
|
|||
GstPad *sinkpad;
|
||||
|
||||
gboolean silent;
|
||||
gboolean has_chain;
|
||||
gboolean has_sink_loop;
|
||||
gint pad_counter;
|
||||
guint64 offset;
|
||||
GstActivateMode sink_mode;
|
||||
|
||||
gchar *last_message;
|
||||
};
|
||||
|
||||
|
|
|
@ -416,8 +416,15 @@ gst_iterator_filter (GstIterator * it, GCompareFunc func, gpointer user_data)
|
|||
* This procedure can be used (and is used internally) to implement the foreach
|
||||
* and find_custom operations.
|
||||
*
|
||||
* Returns: the result of the last call to gst_iterator_next(). This function
|
||||
* stops on a resync.
|
||||
* The fold will proceed as long as @func returns TRUE. When the iterator has no
|
||||
* more arguments, GST_ITERATOR_DONE will be returned. If @func returns FALSE,
|
||||
* the fold will stop, and GST_ITERATOR_OK will be returned. Errors or resyncs
|
||||
* will cause fold to return GST_ITERATOR_ERROR or GST_ITERATOR_RESYNC as
|
||||
* appropriate.
|
||||
*
|
||||
* The iterator will only be freed if fold returns GST_ITERATOR_DONE.
|
||||
*
|
||||
* Returns: A #GstIteratorResult, as described above.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
|
@ -432,9 +439,11 @@ gst_iterator_fold (GstIterator * iter, GstIteratorFoldFunction func,
|
|||
result = gst_iterator_next (iter, &item);
|
||||
switch (result) {
|
||||
case GST_ITERATOR_OK:
|
||||
func (item, ret, user_data);
|
||||
/* fixme: is there a way to ref/unref items? */
|
||||
break;
|
||||
if (!func (item, ret, user_data))
|
||||
goto fold_interrupted;
|
||||
else
|
||||
break;
|
||||
case GST_ITERATOR_RESYNC:
|
||||
case GST_ITERATOR_ERROR:
|
||||
goto fold_interrupted;
|
||||
|
@ -457,10 +466,11 @@ typedef struct
|
|||
gpointer user_data;
|
||||
} ForeachFoldData;
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
foreach_fold_func (gpointer item, GValue * unused, ForeachFoldData * data)
|
||||
{
|
||||
data->func (item, data->user_data);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -472,8 +482,8 @@ foreach_fold_func (gpointer item, GValue * unused, ForeachFoldData * data)
|
|||
* Iterate over all element of @it and call the given function for
|
||||
* each element.
|
||||
*
|
||||
* Returns: the result of the last call to gst_iterator_next(). This function
|
||||
* stops on a resync.
|
||||
* Returns: the result call to gst_iterator_fold(). If the result is not
|
||||
* GST_ITERATOR_DONE, the iterator is not freed.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
|
@ -495,12 +505,15 @@ typedef struct
|
|||
gpointer user_data;
|
||||
} FindCustomFoldData;
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
find_custom_fold_func (gpointer item, GValue * ret, FindCustomFoldData * data)
|
||||
{
|
||||
if (!g_value_get_pointer (ret))
|
||||
if (data->func (item, data->user_data))
|
||||
g_value_set_pointer (ret, item);
|
||||
if (data->func (item, data->user_data)) {
|
||||
g_value_set_pointer (ret, item);
|
||||
return FALSE;
|
||||
} else {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -512,6 +525,9 @@ find_custom_fold_func (gpointer item, GValue * ret, FindCustomFoldData * data)
|
|||
* Find the first element in @it that matches the compare function.
|
||||
* The compare function should return 0 when the element is found.
|
||||
*
|
||||
* Will free the iterator when finished, regardless of whether an item is found
|
||||
* or not.
|
||||
*
|
||||
* Returns: The element in the iterator that matches the compare
|
||||
* function or NULL when no element matched.
|
||||
*
|
||||
|
@ -522,15 +538,20 @@ gst_iterator_find_custom (GstIterator * iter, GCompareFunc func,
|
|||
gpointer user_data)
|
||||
{
|
||||
GValue ret = { 0, };
|
||||
GstIteratorResult res;
|
||||
FindCustomFoldData data;
|
||||
|
||||
g_value_init (&ret, G_TYPE_POINTER);
|
||||
data.func = func;
|
||||
data.user_data = user_data;
|
||||
|
||||
gst_iterator_fold (iter, (GstIteratorFoldFunction) find_custom_fold_func,
|
||||
res =
|
||||
gst_iterator_fold (iter, (GstIteratorFoldFunction) find_custom_fold_func,
|
||||
&ret, &data);
|
||||
|
||||
if (res != GST_ITERATOR_DONE)
|
||||
gst_iterator_free (iter);
|
||||
|
||||
/* no need to unset, it's just a pointer */
|
||||
return g_value_get_pointer (&ret);
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ typedef GstIteratorItem (*GstIteratorItemFunction) (GstIterator *it, gpointer
|
|||
typedef void (*GstIteratorResyncFunction) (GstIterator *it);
|
||||
typedef void (*GstIteratorFreeFunction) (GstIterator *it);
|
||||
|
||||
typedef void (*GstIteratorFoldFunction) (gpointer item, GValue *ret, gpointer user_data);
|
||||
typedef gboolean (*GstIteratorFoldFunction) (gpointer item, GValue *ret, gpointer user_data);
|
||||
|
||||
#define GST_ITERATOR(it) ((GstIterator*)(it))
|
||||
#define GST_ITERATOR_LOCK(it) (GST_ITERATOR(it)->lock)
|
||||
|
|
142
gst/gstutils.c
142
gst/gstutils.c
|
@ -796,7 +796,7 @@ gst_element_state_get_name (GstElementState state)
|
|||
*
|
||||
* Returns: TRUE if the pads could be linked, FALSE otherwise.
|
||||
*/
|
||||
GstPadLinkReturn
|
||||
gboolean
|
||||
gst_element_link_pads_filtered (GstElement * src, const gchar * srcpadname,
|
||||
GstElement * dest, const gchar * destpadname, const GstCaps * filtercaps)
|
||||
{
|
||||
|
@ -1040,7 +1040,7 @@ gst_element_link_pads_filtered (GstElement * src, const gchar * srcpadname,
|
|||
*
|
||||
* Returns: TRUE if the elements could be linked, FALSE otherwise.
|
||||
*/
|
||||
GstPadLinkReturn
|
||||
gboolean
|
||||
gst_element_link_filtered (GstElement * src, GstElement * dest,
|
||||
const GstCaps * filtercaps)
|
||||
{
|
||||
|
@ -1057,7 +1057,7 @@ gst_element_link_filtered (GstElement * src, GstElement * dest,
|
|||
*
|
||||
* Returns: TRUE on success, FALSE otherwise.
|
||||
*/
|
||||
GstPadLinkReturn
|
||||
gboolean
|
||||
gst_element_link_many (GstElement * element_1, GstElement * element_2, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
@ -1090,7 +1090,7 @@ gst_element_link_many (GstElement * element_1, GstElement * element_2, ...)
|
|||
*
|
||||
* Returns: TRUE if the elements could be linked, FALSE otherwise.
|
||||
*/
|
||||
GstPadLinkReturn
|
||||
gboolean
|
||||
gst_element_link (GstElement * src, GstElement * dest)
|
||||
{
|
||||
return gst_element_link_pads_filtered (src, NULL, dest, NULL, NULL);
|
||||
|
@ -1110,7 +1110,7 @@ gst_element_link (GstElement * src, GstElement * dest)
|
|||
*
|
||||
* Returns: TRUE if the pads could be linked, FALSE otherwise.
|
||||
*/
|
||||
GstPadLinkReturn
|
||||
gboolean
|
||||
gst_element_link_pads (GstElement * src, const gchar * srcpadname,
|
||||
GstElement * dest, const gchar * destpadname)
|
||||
{
|
||||
|
@ -1646,3 +1646,135 @@ gst_buffer_stamp (GstBuffer * dest, const GstBuffer * src)
|
|||
GST_BUFFER_OFFSET (dest) = GST_BUFFER_OFFSET (src);
|
||||
GST_BUFFER_OFFSET_END (dest) = GST_BUFFER_OFFSET_END (src);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
intersect_caps_func (GstPad * pad, GValue * ret, GstPad * orig)
|
||||
{
|
||||
if (pad != orig) {
|
||||
GstCaps *peercaps, *existing;
|
||||
|
||||
existing = g_value_get_pointer (ret);
|
||||
peercaps = gst_pad_peer_get_caps (pad);
|
||||
g_value_set_pointer (ret, gst_caps_intersect (existing, peercaps));
|
||||
gst_caps_unref (existing);
|
||||
gst_caps_unref (peercaps);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_pad_proxy_getcaps:
|
||||
* @pad: a #GstPad to proxy.
|
||||
*
|
||||
* Calls gst_pad_get_allowed_caps() for every other pad belonging to the
|
||||
* same element as @pad, and returns the intersection of the results.
|
||||
*
|
||||
* This function is useful as a default getcaps function for an element
|
||||
* that can handle any stream format, but requires all its pads to have
|
||||
* the same caps. Two such elements are tee and aggregator.
|
||||
*
|
||||
* Returns: the intersection of the other pads' allowed caps.
|
||||
*/
|
||||
GstCaps *
|
||||
gst_pad_proxy_getcaps (GstPad * pad)
|
||||
{
|
||||
GstElement *element;
|
||||
GstCaps *caps, *intersected;
|
||||
GstIterator *iter;
|
||||
GstIteratorResult res;
|
||||
GValue ret = { 0, };
|
||||
|
||||
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
|
||||
|
||||
GST_DEBUG ("proxying getcaps for %s:%s", GST_DEBUG_PAD_NAME (pad));
|
||||
|
||||
element = gst_pad_get_parent (pad);
|
||||
|
||||
iter = gst_element_iterate_pads (element);
|
||||
|
||||
g_value_init (&ret, G_TYPE_POINTER);
|
||||
g_value_set_pointer (&ret, gst_caps_new_any ());
|
||||
|
||||
res = gst_iterator_fold (iter, (GstIteratorFoldFunction) intersect_caps_func,
|
||||
&ret, pad);
|
||||
if (res != GST_ITERATOR_DONE) {
|
||||
g_warning ("Pad list changed during capsnego for element %s",
|
||||
GST_ELEMENT_NAME (element));
|
||||
gst_iterator_free (iter);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
caps = g_value_get_pointer (&ret);
|
||||
g_value_unset (&ret);
|
||||
|
||||
intersected = gst_caps_intersect (caps, gst_pad_get_pad_template_caps (pad));
|
||||
gst_caps_unref (caps);
|
||||
|
||||
return intersected;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GstPad *orig;
|
||||
GstCaps *caps;
|
||||
} LinkData;
|
||||
|
||||
static gboolean
|
||||
link_fold_func (GstPad * pad, GValue * ret, LinkData * data)
|
||||
{
|
||||
gboolean success = TRUE;
|
||||
|
||||
if (pad != data->orig) {
|
||||
success = gst_pad_set_caps (pad, data->caps);
|
||||
g_value_set_boolean (ret, success);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_pad_proxy_setcaps
|
||||
* @pad: a #GstPad to proxy from
|
||||
* @caps: the #GstCaps to link with
|
||||
*
|
||||
* Calls gst_pad_set_caps() for every other pad belonging to the
|
||||
* same element as @pad. If gst_pad_set_caps() fails on any pad,
|
||||
* the proxy setcaps fails. May be used only during negotiation.
|
||||
*
|
||||
* Returns: TRUE if sucessful
|
||||
*/
|
||||
gboolean
|
||||
gst_pad_proxy_setcaps (GstPad * pad, GstCaps * caps)
|
||||
{
|
||||
GstElement *element;
|
||||
GstIterator *iter;
|
||||
GstIteratorResult res;
|
||||
GValue ret = { 0, };
|
||||
LinkData data;
|
||||
|
||||
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
|
||||
g_return_val_if_fail (caps != NULL, FALSE);
|
||||
|
||||
GST_DEBUG ("proxying pad link for %s:%s", GST_DEBUG_PAD_NAME (pad));
|
||||
|
||||
element = gst_pad_get_parent (pad);
|
||||
|
||||
iter = gst_element_iterate_pads (element);
|
||||
|
||||
g_value_init (&ret, G_TYPE_BOOLEAN);
|
||||
g_value_set_boolean (&ret, TRUE);
|
||||
data.orig = pad;
|
||||
data.caps = caps;
|
||||
|
||||
res = gst_iterator_fold (iter, (GstIteratorFoldFunction) link_fold_func,
|
||||
&ret, &data);
|
||||
if (res != GST_ITERATOR_DONE) {
|
||||
g_warning ("Pad list changed during proxy_pad_link for element %s",
|
||||
GST_ELEMENT_NAME (element));
|
||||
gst_iterator_free (iter);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* ok not to unset the gvalue */
|
||||
return g_value_get_boolean (&ret);
|
||||
}
|
||||
|
|
|
@ -240,18 +240,18 @@ GstPadTemplate* gst_element_get_compatible_pad_template (GstElement *ele
|
|||
|
||||
G_CONST_RETURN gchar* gst_element_state_get_name (GstElementState state);
|
||||
|
||||
GstPadLinkReturn gst_element_link (GstElement *src, GstElement *dest);
|
||||
GstPadLinkReturn gst_element_link_many (GstElement *element_1,
|
||||
gboolean gst_element_link (GstElement *src, GstElement *dest);
|
||||
gboolean gst_element_link_many (GstElement *element_1,
|
||||
GstElement *element_2, ...);
|
||||
GstPadLinkReturn gst_element_link_filtered (GstElement *src, GstElement *dest,
|
||||
gboolean gst_element_link_filtered (GstElement *src, GstElement *dest,
|
||||
const GstCaps *filtercaps);
|
||||
void gst_element_unlink (GstElement *src, GstElement *dest);
|
||||
void gst_element_unlink_many (GstElement *element_1,
|
||||
GstElement *element_2, ...);
|
||||
|
||||
GstPadLinkReturn gst_element_link_pads (GstElement *src, const gchar *srcpadname,
|
||||
gboolean gst_element_link_pads (GstElement *src, const gchar *srcpadname,
|
||||
GstElement *dest, const gchar *destpadname);
|
||||
GstPadLinkReturn gst_element_link_pads_filtered (GstElement *src, const gchar *srcpadname,
|
||||
gboolean gst_element_link_pads_filtered (GstElement *src, const gchar *srcpadname,
|
||||
GstElement *dest, const gchar *destpadname,
|
||||
const GstCaps *filtercaps);
|
||||
void gst_element_unlink_pads (GstElement *src, const gchar *srcpadname,
|
||||
|
@ -267,6 +267,8 @@ gboolean gst_pad_can_link_filtered (GstPad *srcpad, GstPad
|
|||
|
||||
void gst_pad_use_fixed_caps (GstPad *pad);
|
||||
GstCaps* gst_pad_get_fixed_caps_func (GstPad *pad);
|
||||
GstCaps* gst_pad_proxy_getcaps (GstPad * pad);
|
||||
gboolean gst_pad_proxy_setcaps (GstPad * pad, GstCaps * caps);
|
||||
|
||||
/* bin functions */
|
||||
void gst_bin_add_many (GstBin *bin, GstElement *element_1, ...);
|
||||
|
|
|
@ -29,19 +29,19 @@ libgstelements_la_SOURCES = \
|
|||
gstfilesrc.c \
|
||||
gstidentity.c \
|
||||
gstelements.c \
|
||||
#gstaggregator.c \
|
||||
gstbufferstore.c \
|
||||
gstfakesink.c \
|
||||
gstfilesink.c \
|
||||
gstfdsink.c \
|
||||
gstfdsrc.c \
|
||||
gstmd5sink.c \
|
||||
$(multifilesrc) \
|
||||
$(pipefilter) \
|
||||
gstshaper.c \
|
||||
gststatistics.c \
|
||||
gsttee.c \
|
||||
gsttypefindelement.c
|
||||
gsttee.c
|
||||
|
||||
# gstaggregator.c \
|
||||
# gstbufferstore.c \
|
||||
# gstfilesink.c \
|
||||
# gstfdsink.c \
|
||||
# gstfdsrc.c \
|
||||
# gstmd5sink.c \
|
||||
# $(multifilesrc) \
|
||||
# $(pipefilter) \
|
||||
# gstshaper.c \
|
||||
# gststatistics.c \
|
||||
# gsttypefindelement.c
|
||||
|
||||
libgstelements_la_CFLAGS = $(GST_OBJ_CFLAGS)
|
||||
libgstelements_la_LIBADD = $(GST_OBJ_LIBS)
|
||||
|
|
|
@ -70,7 +70,7 @@ static struct _elements_entry _elements[] = {
|
|||
#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},
|
||||
// {NULL, 0},
|
||||
};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wim.taymans@chello.be>
|
||||
* 2000,2001,2002,2003,2004,2005 Wim Taymans <wim@fluendo.com>
|
||||
*
|
||||
*
|
||||
* gsttee.c: Tee element, one in N out
|
||||
*
|
||||
|
@ -40,21 +41,16 @@ GstElementDetails gst_tee_details = GST_ELEMENT_DETAILS ("Tee pipe fitting",
|
|||
"Generic",
|
||||
"1-to-N pipe fitting",
|
||||
"Erik Walthinsen <omega@cse.ogi.edu>, "
|
||||
"Wim Taymans <wim.taymans@chello.be>");
|
||||
|
||||
/* Tee signals and args */
|
||||
enum
|
||||
{
|
||||
/* FILL ME */
|
||||
LAST_SIGNAL
|
||||
};
|
||||
"Wim \"Tim\" Taymans <wim@fluendo.com>");
|
||||
|
||||
enum
|
||||
{
|
||||
ARG_0,
|
||||
ARG_SILENT,
|
||||
ARG_NUM_PADS,
|
||||
ARG_LAST_MESSAGE
|
||||
PROP_0,
|
||||
PROP_NUM_SRC_PADS,
|
||||
PROP_HAS_SINK_LOOP,
|
||||
PROP_HAS_CHAIN,
|
||||
PROP_SILENT,
|
||||
PROP_LAST_MESSAGE
|
||||
/* FILL ME */
|
||||
};
|
||||
|
||||
|
@ -77,7 +73,9 @@ static void gst_tee_set_property (GObject * object, guint prop_id,
|
|||
static void gst_tee_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
|
||||
static void gst_tee_chain (GstPad * pad, GstData * _data);
|
||||
static GstFlowReturn gst_tee_chain (GstPad * pad, GstBuffer * buffer);
|
||||
static void gst_tee_loop (GstPad * pad);
|
||||
static gboolean gst_tee_sink_activate (GstPad * pad, GstActivateMode mode);
|
||||
|
||||
|
||||
static void
|
||||
|
@ -113,22 +111,26 @@ gst_tee_class_init (GstTeeClass * klass)
|
|||
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", "num_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", "silent",
|
||||
TRUE, G_PARAM_CONSTRUCT | 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->finalize = GST_DEBUG_FUNCPTR (gst_tee_finalize);
|
||||
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_tee_set_property);
|
||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_tee_get_property);
|
||||
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NUM_SRC_PADS,
|
||||
g_param_spec_int ("num-src-pads", "num-src-pads", "num-src-pads",
|
||||
0, G_MAXINT, 0, G_PARAM_READABLE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_SINK_LOOP,
|
||||
g_param_spec_boolean ("has-sink-loop", "has-sink-loop", "has-sink-loop",
|
||||
FALSE, G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_CHAIN,
|
||||
g_param_spec_boolean ("has-chain", "has-chain", "has-chain",
|
||||
TRUE, G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SILENT,
|
||||
g_param_spec_boolean ("silent", "silent", "silent",
|
||||
TRUE, G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LAST_MESSAGE,
|
||||
g_param_spec_string ("last_message", "last_message", "last_message",
|
||||
NULL, G_PARAM_READABLE));
|
||||
|
||||
gstelement_class->request_new_pad =
|
||||
GST_DEBUG_FUNCPTR (gst_tee_request_new_pad);
|
||||
}
|
||||
|
@ -140,25 +142,30 @@ gst_tee_init (GstTee * tee)
|
|||
gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate),
|
||||
"sink");
|
||||
gst_element_add_pad (GST_ELEMENT (tee), tee->sinkpad);
|
||||
gst_pad_set_chain_function (tee->sinkpad, GST_DEBUG_FUNCPTR (gst_tee_chain));
|
||||
gst_pad_set_link_function (tee->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_pad_proxy_pad_link));
|
||||
gst_pad_set_setcaps_function (tee->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_pad_proxy_setcaps));
|
||||
gst_pad_set_getcaps_function (tee->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
|
||||
|
||||
tee->last_message = NULL;
|
||||
}
|
||||
|
||||
/* helper compare function */
|
||||
gint
|
||||
name_pad_compare (gconstpointer a, gconstpointer b)
|
||||
static void
|
||||
gst_tee_update_pad_functions (GstTee * tee)
|
||||
{
|
||||
GstPad *pad = (GstPad *) a;
|
||||
gchar *name = (gchar *) b;
|
||||
gst_pad_set_activate_function (tee->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_tee_sink_activate));
|
||||
|
||||
g_assert (GST_IS_PAD (pad));
|
||||
if (tee->has_chain)
|
||||
gst_pad_set_chain_function (tee->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_tee_chain));
|
||||
else
|
||||
gst_pad_set_chain_function (tee->sinkpad, NULL);
|
||||
|
||||
return strcmp (name, gst_pad_get_name (pad)); /* returns 0 if match */
|
||||
if (tee->has_sink_loop)
|
||||
gst_pad_set_loop_function (tee->sinkpad, GST_DEBUG_FUNCPTR (gst_tee_loop));
|
||||
else
|
||||
gst_pad_set_loop_function (tee->sinkpad, NULL);
|
||||
}
|
||||
|
||||
static GstPad *
|
||||
|
@ -168,50 +175,21 @@ gst_tee_request_new_pad (GstElement * element, GstPadTemplate * templ,
|
|||
gchar *name;
|
||||
GstPad *srcpad;
|
||||
GstTee *tee;
|
||||
gint i = 0;
|
||||
const GList *pads;
|
||||
|
||||
g_return_val_if_fail (GST_IS_TEE (element), NULL);
|
||||
|
||||
if (templ->direction != GST_PAD_SRC) {
|
||||
g_warning ("gsttee: request new pad that is not a SRC pad\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tee = GST_TEE (element);
|
||||
|
||||
/* try names in order and find one that's not in use atm */
|
||||
pads = gst_element_get_pad_list (element);
|
||||
|
||||
name = NULL;
|
||||
while (!name) {
|
||||
name = g_strdup_printf ("src%d", i);
|
||||
if (g_list_find_custom ((GList *) pads, (gconstpointer) name,
|
||||
name_pad_compare) != NULL) {
|
||||
/* this name is taken, use the next one */
|
||||
++i;
|
||||
g_free (name);
|
||||
name = NULL;
|
||||
}
|
||||
}
|
||||
if (!tee->silent) {
|
||||
g_free (tee->last_message);
|
||||
tee->last_message = g_strdup_printf ("new pad %s", name);
|
||||
g_object_notify (G_OBJECT (tee), "last_message");
|
||||
}
|
||||
GST_LOCK (tee);
|
||||
name = g_strdup_printf ("src%d", tee->pad_counter++);
|
||||
GST_UNLOCK (tee);
|
||||
|
||||
srcpad = gst_pad_new_from_template (templ, name);
|
||||
g_free (name);
|
||||
gst_pad_set_link_function (srcpad,
|
||||
GST_DEBUG_FUNCPTR (gst_pad_proxy_pad_link));
|
||||
|
||||
gst_pad_set_setcaps_function (srcpad,
|
||||
GST_DEBUG_FUNCPTR (gst_pad_proxy_setcaps));
|
||||
gst_pad_set_getcaps_function (srcpad,
|
||||
GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
|
||||
gst_element_add_pad (GST_ELEMENT (tee), srcpad);
|
||||
GST_PAD_ELEMENT_PRIVATE (srcpad) = NULL;
|
||||
|
||||
if (GST_PAD_CAPS (tee->sinkpad)) {
|
||||
gst_pad_try_set_caps (srcpad, GST_PAD_CAPS (tee->sinkpad));
|
||||
}
|
||||
|
||||
return srcpad;
|
||||
}
|
||||
|
@ -220,95 +198,202 @@ static void
|
|||
gst_tee_set_property (GObject * object, guint prop_id, const GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
GstTee *tee;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail (GST_IS_TEE (object));
|
||||
|
||||
tee = GST_TEE (object);
|
||||
GstTee *tee = GST_TEE (object);
|
||||
|
||||
GST_LOCK (tee);
|
||||
switch (prop_id) {
|
||||
case ARG_SILENT:
|
||||
case PROP_HAS_SINK_LOOP:
|
||||
tee->has_sink_loop = g_value_get_boolean (value);
|
||||
gst_tee_update_pad_functions (tee);
|
||||
break;
|
||||
case PROP_HAS_CHAIN:
|
||||
tee->has_chain = g_value_get_boolean (value);
|
||||
gst_tee_update_pad_functions (tee);
|
||||
break;
|
||||
case PROP_SILENT:
|
||||
tee->silent = g_value_get_boolean (value);
|
||||
g_object_notify (G_OBJECT (tee), "silent");
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
GST_UNLOCK (tee);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_tee_get_property (GObject * object, guint prop_id, GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
GstTee *tee;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail (GST_IS_TEE (object));
|
||||
|
||||
tee = GST_TEE (object);
|
||||
GstTee *tee = GST_TEE (object);
|
||||
|
||||
GST_LOCK (tee);
|
||||
switch (prop_id) {
|
||||
case ARG_NUM_PADS:
|
||||
case PROP_NUM_SRC_PADS:
|
||||
g_value_set_int (value, GST_ELEMENT (tee)->numsrcpads);
|
||||
break;
|
||||
case ARG_SILENT:
|
||||
case PROP_HAS_SINK_LOOP:
|
||||
g_value_set_boolean (value, tee->has_sink_loop);
|
||||
break;
|
||||
case PROP_HAS_CHAIN:
|
||||
g_value_set_boolean (value, tee->has_chain);
|
||||
break;
|
||||
case PROP_SILENT:
|
||||
g_value_set_boolean (value, tee->silent);
|
||||
break;
|
||||
case ARG_LAST_MESSAGE:
|
||||
case PROP_LAST_MESSAGE:
|
||||
g_value_set_string (value, tee->last_message);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
GST_UNLOCK (tee);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_tee_chain:
|
||||
* @pad: the pad to follow
|
||||
* @buf: the buffer to pass
|
||||
*
|
||||
* Chain a buffer on a pad.
|
||||
*/
|
||||
static void
|
||||
gst_tee_chain (GstPad * pad, GstData * _data)
|
||||
typedef struct
|
||||
{
|
||||
GstBuffer *buf = GST_BUFFER (_data);
|
||||
GstTee *tee;
|
||||
const GList *pads;
|
||||
GstBuffer *buffer;
|
||||
} PushData;
|
||||
|
||||
g_return_if_fail (pad != NULL);
|
||||
g_return_if_fail (GST_IS_PAD (pad));
|
||||
g_return_if_fail (buf != NULL);
|
||||
static gboolean
|
||||
gst_tee_do_push (GstPad * pad, GValue * ret, PushData * data)
|
||||
{
|
||||
GstFlowReturn res;
|
||||
|
||||
if (GST_PAD_DIRECTION (pad) != GST_PAD_SRC || !GST_PAD_IS_USABLE (pad))
|
||||
return TRUE;
|
||||
|
||||
if (G_UNLIKELY (!data->tee->silent)) {
|
||||
GstTee *tee = data->tee;
|
||||
GstBuffer *buf = data->buffer;
|
||||
|
||||
g_free (tee->last_message);
|
||||
tee->last_message =
|
||||
g_strdup_printf ("chain ******* (%s:%s)t (%d bytes, %"
|
||||
G_GUINT64_FORMAT ") %p", GST_DEBUG_PAD_NAME (pad),
|
||||
GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf), buf);
|
||||
g_object_notify (G_OBJECT (tee), "last_message");
|
||||
}
|
||||
|
||||
res = gst_pad_push (pad, gst_buffer_ref (data->buffer));
|
||||
g_value_set_enum (ret, res);
|
||||
return (res == GST_FLOW_OK);
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_tee_handle_buffer (GstTee * tee, GstBuffer * buffer)
|
||||
{
|
||||
GstIterator *iter;
|
||||
PushData data;
|
||||
GValue ret = { 0, };
|
||||
GstIteratorResult res;
|
||||
|
||||
tee->offset += GST_BUFFER_SIZE (buffer);
|
||||
|
||||
g_value_init (&ret, GST_TYPE_FLOW_RETURN);
|
||||
iter = gst_element_iterate_pads (GST_ELEMENT (tee));
|
||||
data.tee = tee;
|
||||
data.buffer = buffer;
|
||||
|
||||
res = gst_iterator_fold (iter, (GstIteratorFoldFunction) gst_tee_do_push,
|
||||
&ret, &data);
|
||||
if (res != GST_ITERATOR_DONE)
|
||||
gst_iterator_free (iter);
|
||||
gst_buffer_unref (buffer);
|
||||
|
||||
/* no need to unset gvalue */
|
||||
return g_value_get_enum (&ret);
|
||||
}
|
||||
|
||||
#define WITH_STREAM_LOCK(pad, expr) G_STMT_START {\
|
||||
GST_STREAM_LOCK (pad); \
|
||||
expr; \
|
||||
GST_STREAM_UNLOCK (pad); \
|
||||
}G_STMT_END
|
||||
|
||||
static GstFlowReturn
|
||||
gst_tee_chain (GstPad * pad, GstBuffer * buffer)
|
||||
{
|
||||
GstFlowReturn res;
|
||||
GstTee *tee;
|
||||
|
||||
tee = GST_TEE (gst_pad_get_parent (pad));
|
||||
|
||||
gst_buffer_ref_by_count (buf, GST_ELEMENT (tee)->numsrcpads - 1);
|
||||
WITH_STREAM_LOCK (pad, res = gst_tee_handle_buffer (tee, buffer));
|
||||
|
||||
pads = gst_element_get_pad_list (GST_ELEMENT (tee));
|
||||
|
||||
while (pads) {
|
||||
GstPad *outpad = GST_PAD (pads->data);
|
||||
|
||||
pads = g_list_next (pads);
|
||||
|
||||
if (GST_PAD_DIRECTION (outpad) != GST_PAD_SRC)
|
||||
continue;
|
||||
|
||||
if (!tee->silent) {
|
||||
g_free (tee->last_message);
|
||||
tee->last_message =
|
||||
g_strdup_printf ("chain ******* (%s:%s)t (%d bytes, %"
|
||||
G_GUINT64_FORMAT ") %p", GST_DEBUG_PAD_NAME (outpad),
|
||||
GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf), buf);
|
||||
g_object_notify (G_OBJECT (tee), "last_message");
|
||||
}
|
||||
|
||||
if (GST_PAD_IS_USABLE (outpad))
|
||||
gst_pad_push (outpad, GST_DATA (buf));
|
||||
else
|
||||
gst_buffer_unref (buf);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
#define DEFAULT_SIZE 1024
|
||||
|
||||
static void
|
||||
gst_tee_loop (GstPad * pad)
|
||||
{
|
||||
GstBuffer *buffer;
|
||||
GstFlowReturn res;
|
||||
GstTee *tee;
|
||||
|
||||
GST_STREAM_LOCK (pad);
|
||||
|
||||
tee = GST_TEE (gst_pad_get_parent (pad));
|
||||
|
||||
res = gst_pad_pull_range (pad, tee->offset, DEFAULT_SIZE, &buffer);
|
||||
if (res != GST_FLOW_OK)
|
||||
goto pause_task;
|
||||
|
||||
res = gst_tee_handle_buffer (tee, buffer);
|
||||
if (res != GST_FLOW_OK)
|
||||
goto pause_task;
|
||||
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
return;
|
||||
|
||||
pause_task:
|
||||
gst_pad_pause_task (pad);
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
return;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_tee_sink_activate (GstPad * pad, GstActivateMode mode)
|
||||
{
|
||||
gboolean result = FALSE;
|
||||
GstTee *tee;
|
||||
|
||||
tee = GST_TEE (GST_OBJECT_PARENT (pad));
|
||||
|
||||
switch (mode) {
|
||||
case GST_ACTIVATE_PUSH:
|
||||
g_return_val_if_fail (tee->has_chain, FALSE);
|
||||
result = TRUE;
|
||||
break;
|
||||
case GST_ACTIVATE_PULL:
|
||||
g_return_val_if_fail (tee->has_sink_loop, FALSE);
|
||||
if (GST_ELEMENT_SCHEDULER (tee)) {
|
||||
GST_STREAM_LOCK (pad);
|
||||
GST_RPAD_TASK (pad) =
|
||||
gst_scheduler_create_task (GST_ELEMENT_SCHEDULER (tee),
|
||||
(GstTaskFunction) gst_tee_loop, pad);
|
||||
|
||||
gst_pad_start_task (pad);
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
result = TRUE;
|
||||
}
|
||||
break;
|
||||
case GST_ACTIVATE_NONE:
|
||||
GST_STREAM_LOCK (pad);
|
||||
if (GST_RPAD_TASK (pad)) {
|
||||
gst_pad_stop_task (pad);
|
||||
gst_object_unref (GST_OBJECT (GST_RPAD_TASK (pad)));
|
||||
GST_RPAD_TASK (pad) = NULL;
|
||||
}
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
|
||||
result = TRUE;
|
||||
break;
|
||||
}
|
||||
tee->sink_mode = mode;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -49,6 +49,12 @@ struct _GstTee {
|
|||
GstPad *sinkpad;
|
||||
|
||||
gboolean silent;
|
||||
gboolean has_chain;
|
||||
gboolean has_sink_loop;
|
||||
gint pad_counter;
|
||||
guint64 offset;
|
||||
GstActivateMode sink_mode;
|
||||
|
||||
gchar *last_message;
|
||||
};
|
||||
|
||||
|
|
|
@ -95,7 +95,7 @@ main (gint argc, gchar * argv[])
|
|||
new_src_list = g_slist_prepend (new_src_list, e);
|
||||
|
||||
gst_bin_add (GST_BIN (pipeline), e);
|
||||
if (gst_element_link (src, e) != GST_PAD_LINK_OK)
|
||||
if (!gst_element_link (src, e))
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
|
@ -114,7 +114,8 @@ main (gint argc, gchar * argv[])
|
|||
GST_TIME_ARGS (end - start));
|
||||
|
||||
start = gst_get_current_time ();
|
||||
while (gst_bin_iterate (GST_BIN (pipeline)));
|
||||
gst_bus_poll (gst_element_get_bus (pipeline),
|
||||
GST_MESSAGE_EOS | GST_MESSAGE_ERROR, -1);
|
||||
end = gst_get_current_time ();
|
||||
g_print ("%" GST_TIME_FORMAT " - putting %u buffers through\n",
|
||||
GST_TIME_ARGS (end - start), BUFFER_COUNT);
|
||||
|
|
|
@ -115,10 +115,11 @@ START_TEST (test_resync)
|
|||
|
||||
gst_iterator_free (iter);
|
||||
}
|
||||
END_TEST static void
|
||||
END_TEST static gboolean
|
||||
add_fold_func (gpointer item, GValue * ret, gpointer user_data)
|
||||
{
|
||||
g_value_set_int (ret, g_value_get_int (ret) + GPOINTER_TO_INT (item));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
START_TEST (test_fold)
|
||||
|
|
|
@ -95,7 +95,7 @@ main (gint argc, gchar * argv[])
|
|||
new_src_list = g_slist_prepend (new_src_list, e);
|
||||
|
||||
gst_bin_add (GST_BIN (pipeline), e);
|
||||
if (gst_element_link (src, e) != GST_PAD_LINK_OK)
|
||||
if (!gst_element_link (src, e))
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
|
@ -114,7 +114,8 @@ main (gint argc, gchar * argv[])
|
|||
GST_TIME_ARGS (end - start));
|
||||
|
||||
start = gst_get_current_time ();
|
||||
while (gst_bin_iterate (GST_BIN (pipeline)));
|
||||
gst_bus_poll (gst_element_get_bus (pipeline),
|
||||
GST_MESSAGE_EOS | GST_MESSAGE_ERROR, -1);
|
||||
end = gst_get_current_time ();
|
||||
g_print ("%" GST_TIME_FORMAT " - putting %u buffers through\n",
|
||||
GST_TIME_ARGS (end - start), BUFFER_COUNT);
|
||||
|
|
Loading…
Reference in a new issue