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:
Andy Wingo 2005-03-01 16:51:11 +00:00
parent c32ed239dd
commit 70d2a801d9
19 changed files with 735 additions and 344 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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},
};

View file

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

View file

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

View file

@ -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);
}

View file

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

View file

@ -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);
}

View file

@ -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, ...);

View file

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

View file

@ -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},
};

View file

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

View file

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

View file

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

View file

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

View file

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