Commit d8d03b6b authored by Ronald S. Bultje's avatar Ronald S. Bultje

docs/pwg/advanced-types.xml: Fix description for buffer-frames=0.

Original commit message from CVS:
* docs/pwg/advanced-types.xml:
Fix description for buffer-frames=0.
* docs/gst/tmpl/gstbin.sgml:
* gst/gstbin.c: (gst_bin_child_state_change_func),
(gst_bin_change_state), (gst_bin_change_state_norecurse):
* gst/gstbin.h:
* testsuite/threads/Makefile.am:
* testsuite/threads/threadi.c: (cb_timeout), (cb_quit), (cb_eos),
(cb_state), (cb_play), (main):
Fix non-recursive state changes to *really* change the state
of the object, and not just call parent_class->state_change.
Fix a lot of lockups caused by this. Fixes #132775. Add test
for the problem. Also enable test to show #142588 (fixed).
* gst/gstthread.c: (gst_thread_change_state),
(gst_thread_child_state_change):
Don't exit the thread if we go to NULL and are inside thread
context. Instead, return control to the main thread context
and exit from there.
* gst/gstelement.c: (gst_element_disable_threadsafe_properties):
Don't unset virtual functions, since those may still be used.
That's not necessarily correct, but suffices for now.
* configure.ac:
* testsuite/Makefile.am:
* testsuite/pad/Makefile.am:
* testsuite/pad/chainnopull.c: (gst_test_sink_class_init),
(gst_test_sink_base_init), (gst_test_sink_chain),
(gst_test_sink_init), (main):
* testsuite/pad/getnopush.c: (gst_test_src_class_init),
(gst_test_src_base_init), (gst_test_src_get), (gst_test_src_init),
(main):
* testsuite/pad/link.c: (gst_test_element_class_init),
(gst_test_element_base_init), (gst_test_src_get),
(gst_test_src_loop), (gst_test_src_init), (gst_test_filter_chain),
(gst_test_filter_loop), (gst_test_filter_init),
(gst_test_sink_chain), (gst_test_sink_loop), (gst_test_sink_init),
(cb_error), (main):
Add tests to show #150546. Pass, but should fail (currently
disabled from the testsuite).
* gst/gstscheduler.c: (gst_scheduler_dispose):
Dereference child schedulers on dispose (#94464).
* testsuite/bytestream/filepadsink.c: (gst_fp_sink_init):
Fix typo.
* testsuite/threads/thread.c: (main):
Add more debug.
parent 10aa48db
2005-01-31 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
* docs/pwg/advanced-types.xml:
Fix description for buffer-frames=0.
* docs/gst/tmpl/gstbin.sgml:
* gst/gstbin.c: (gst_bin_child_state_change_func),
(gst_bin_change_state), (gst_bin_change_state_norecurse):
* gst/gstbin.h:
* testsuite/threads/Makefile.am:
* testsuite/threads/threadi.c: (cb_timeout), (cb_quit), (cb_eos),
(cb_state), (cb_play), (main):
Fix non-recursive state changes to *really* change the state
of the object, and not just call parent_class->state_change.
Fix a lot of lockups caused by this. Fixes #132775. Add test
for the problem. Also enable test to show #142588 (fixed).
* gst/gstthread.c: (gst_thread_change_state),
(gst_thread_child_state_change):
Don't exit the thread if we go to NULL and are inside thread
context. Instead, return control to the main thread context
and exit from there.
* gst/gstelement.c: (gst_element_disable_threadsafe_properties):
Don't unset virtual functions, since those may still be used.
That's not necessarily correct, but suffices for now.
* configure.ac:
* testsuite/Makefile.am:
* testsuite/pad/Makefile.am:
* testsuite/pad/chainnopull.c: (gst_test_sink_class_init),
(gst_test_sink_base_init), (gst_test_sink_chain),
(gst_test_sink_init), (main):
* testsuite/pad/getnopush.c: (gst_test_src_class_init),
(gst_test_src_base_init), (gst_test_src_get), (gst_test_src_init),
(main):
* testsuite/pad/link.c: (gst_test_element_class_init),
(gst_test_element_base_init), (gst_test_src_get),
(gst_test_src_loop), (gst_test_src_init), (gst_test_filter_chain),
(gst_test_filter_loop), (gst_test_filter_init),
(gst_test_sink_chain), (gst_test_sink_loop), (gst_test_sink_init),
(cb_error), (main):
Add tests to show #150546. Pass, but should fail (currently
disabled from the testsuite).
* gst/gstscheduler.c: (gst_scheduler_dispose):
Dereference child schedulers on dispose (#94464).
* testsuite/bytestream/filepadsink.c: (gst_fp_sink_init):
Fix typo.
* testsuite/threads/thread.c: (main):
Add more debug.
2005-01-29 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
* gst/gstpad.c: (gst_pad_push):
......
......@@ -684,6 +684,7 @@ testsuite/elements/Makefile
testsuite/ghostpads/Makefile
testsuite/indexers/Makefile
testsuite/negotiation/Makefile
testsuite/pad/Makefile
testsuite/parse/Makefile
testsuite/plugin/Makefile
testsuite/refcounting/Makefile
......
......@@ -98,6 +98,7 @@ FALSE.
@GST_BIN_SELF_SCHEDULABLE:
@GST_BIN_FLAG_PREFER_COTHREADS:
@GST_BIN_FLAG_FIXED_CLOCK:
@GST_BIN_STATE_LOCKED:
@GST_BIN_FLAG_LAST:
<!-- ##### FUNCTION gst_bin_new ##### -->
......
......@@ -334,14 +334,16 @@ plugin_init (GstPlugin *plugin)
<row>
<entry>buffer-frames</entry>
<entry>integer</entry>
<entry>greater than 0</entry>
<entry>Any</entry>
<entry>
The number of frames per buffer. The reason for this property
is that the element does not need to reuse buffers or use data
spanned over multiple buffers, so this property - when used
rightly - will decrease latency. Note that some people think that
this property is very ugly, whereas others think it is vital for
the use of &GStreamer; in professional audio applications.
the use of &GStreamer; in professional audio applications. The
special value zero is reserved and implies that size is variable
between buffers.
</entry>
</row>
......
......@@ -705,10 +705,14 @@ gst_bin_child_state_change_func (GstBin * bin, GstElementState oldstate,
bin->child_states[new_idx]++;
for (i = GST_NUM_STATES - 1; i >= 0; i--) {
if (bin->child_states[i] != 0) {
if (bin->child_states[i] != 0 || i == 0) {
gint state = (1 << i);
if (GST_STATE (bin) != state) {
/* We only change state on the parent if the state is not locked.
* State locking can occur if the bin itself set state on children,
* which should not recurse since it leads to infinite loops. */
if (GST_STATE (bin) != state &&
!GST_FLAG_IS_SET (bin, GST_BIN_STATE_LOCKED)) {
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin,
"highest child state is %s, changing bin state accordingly",
gst_element_state_get_name (state));
......@@ -832,7 +836,6 @@ gst_bin_change_state (GstElement * element)
GstBin *bin;
GstElementStateReturn ret;
GstElementState old_state, pending;
SetKidStateData data;
g_return_val_if_fail (GST_IS_BIN (element), GST_STATE_FAILURE);
......@@ -849,27 +852,43 @@ gst_bin_change_state (GstElement * element)
if (pending == GST_STATE_VOID_PENDING)
return GST_STATE_SUCCESS;
data.pending = pending;
data.result = GST_STATE_SUCCESS;
if (!gst_bin_foreach (bin, set_kid_state_func, &data)) {
GST_STATE_PENDING (element) = old_state;
return GST_STATE_FAILURE;
/* If we're changing state non-recursively (see _norecurse()),
* this flag is already set and we should not set children states. */
if (!GST_FLAG_IS_SET (bin, GST_BIN_STATE_LOCKED)) {
SetKidStateData data;
/* So now we use this flag to make sure that kids don't re-set our
* state, which would lead to infinite loops. */
GST_FLAG_SET (bin, GST_BIN_STATE_LOCKED);
data.pending = pending;
data.result = GST_STATE_SUCCESS;
if (!gst_bin_foreach (bin, set_kid_state_func, &data)) {
GST_FLAG_UNSET (bin, GST_BIN_STATE_LOCKED);
GST_STATE_PENDING (element) = old_state;
return GST_STATE_FAILURE;
}
GST_FLAG_UNSET (bin, GST_BIN_STATE_LOCKED);
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
"done changing bin's state from %s to %s, now in %s",
gst_element_state_get_name (old_state),
gst_element_state_get_name (pending),
gst_element_state_get_name (GST_STATE (element)));
/* if we're async, the kids will change state later (when the
* lock-state flag is no longer held) and all will be fine. */
if (data.result == GST_STATE_ASYNC)
return GST_STATE_ASYNC;
} else {
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
"Not recursing state change onto children");
}
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
"done changing bin's state from %s to %s, now in %s",
gst_element_state_get_name (old_state),
gst_element_state_get_name (pending),
gst_element_state_get_name (GST_STATE (element)));
if (data.result == GST_STATE_ASYNC)
ret = GST_STATE_ASYNC;
else {
/* FIXME: this should have been done by the children already, no? */
if (parent_class->change_state) {
ret = parent_class->change_state (element);
} else
ret = GST_STATE_SUCCESS;
/* FIXME: this should have been done by the children already, no? */
if (parent_class->change_state) {
ret = parent_class->change_state (element);
} else {
ret = GST_STATE_SUCCESS;
}
return ret;
}
......@@ -900,9 +919,13 @@ gst_bin_change_state_norecurse (GstBin * bin)
{
GstElementStateReturn ret;
if (parent_class->change_state) {
if (GST_ELEMENT_GET_CLASS (bin)->change_state) {
GST_CAT_LOG_OBJECT (GST_CAT_STATES, bin, "setting bin's own state");
ret = parent_class->change_state (GST_ELEMENT (bin));
/* Non-recursive state change flag */
GST_FLAG_SET (bin, GST_BIN_STATE_LOCKED);
ret = GST_ELEMENT_GET_CLASS (bin)->change_state (GST_ELEMENT (bin));
GST_FLAG_UNSET (bin, GST_BIN_STATE_LOCKED);
return ret;
} else
......
......@@ -39,20 +39,30 @@ GST_EXPORT GType _gst_bin_type;
/**
* GstBinFlags:
* @GST_BIN_FLAG_MANAGER: This bin has a scheduler and can be used as a toplevel bin.
* @GST_BIN_SELF_SCHEDULABLE: This bin iterates itself, so no calls to gst_bin_iterate() should be made.
* @GST_BIN_FLAG_PREFER_COTHREADS: This bin preferes to have its elements scheduled with cothreads
* @GST_BIN_FLAG_FIXED_CLOCK: This bin uses a fixed clock, possibly the one set with gst_bin_use_clock().
* @GST_BIN_FLAG_LAST: id of last for chaining flsg definitions
*
* Flags for a #GstBin .
* @GST_BIN_FLAG_MANAGER: this bin is a manager of child elements, i.e.
* a pipeline or thread.
* @GST_BIN_SELF_SCHEDULABLE: the bin iterates itself.
* @GST_BIN_FLAG_PREFER_COTHREADS: we prefer to have cothreads when its
* an option, over chain-based.
* @GST_BIN_FLAG_FIXED_CLOCK: bin has one clock that cannot be changed.
* @GST_BIN_STATE_LOCKED: indicator that we are in a non-recursive
* state-change on the bin, or that kids should not change parent state.
* Both are internally used to prevent infinitely recursive loops of
* state changes. Since they are mutually exclusive and serve the same
* purpose, we use the same flag for them.
* @GST_BIN_FLAG_LAST: the last enum in the series of flags in a bin,
* derived classes can use this as first value in a list of flags.
*
* GstBinFlags are a set of flags specific to bins. Most are set/used
* internally. They can be checked using the GST_FLAG_IS_SET () macro,
* and (un)set using GST_FLAG_SET () and GST_FLAG_UNSET ().
*/
typedef enum {
GST_BIN_FLAG_MANAGER = GST_ELEMENT_FLAG_LAST,
GST_BIN_SELF_SCHEDULABLE,
GST_BIN_FLAG_PREFER_COTHREADS,
GST_BIN_FLAG_FIXED_CLOCK,
/* padding */
GST_BIN_STATE_LOCKED,
GST_BIN_FLAG_LAST = GST_ELEMENT_FLAG_LAST + 5
} GstBinFlags;
......
......@@ -398,8 +398,9 @@ gst_element_disable_threadsafe_properties (GstElement * element)
g_return_if_fail (GST_IS_ELEMENT (element));
GST_FLAG_UNSET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES);
element->pre_run_func = NULL;
element->post_run_func = NULL;
//element->pre_run_func = NULL;
//element->post_run_func = NULL;
/* let's keep around that async queue */
}
......
......@@ -98,6 +98,12 @@ gst_scheduler_dispose (GObject * object)
gst_object_replace ((GstObject **) & sched->current_clock, NULL);
gst_object_replace ((GstObject **) & sched->clock, NULL);
/* kids are held reference to, so dereference here. */
while (sched->schedulers != NULL) {
gst_scheduler_remove_scheduler (sched,
GST_SCHEDULER (sched->schedulers->data));
}
G_OBJECT_CLASS (parent_class)->dispose (object);
}
......
......@@ -508,24 +508,10 @@ gst_thread_change_state (GstElement * element)
if (thread->thread_id != NULL) {
thread->thread_id = NULL;
if (is_self) {
/* or should we continue? */
GST_LOG_OBJECT (thread,
"Thread %s is destroying itself. Function call will not return!",
"Thread %s is destroying itself. Returning to mainloop ASAP!",
GST_ELEMENT_NAME (thread));
gst_scheduler_reset (GST_ELEMENT_SCHED (thread));
/* unlock and signal - we are out */
GST_DEBUG_OBJECT (thread, "signal");
g_cond_signal (thread->cond);
GST_DEBUG_OBJECT (thread, "unlock");
g_mutex_unlock (thread->lock);
GST_INFO_OBJECT (thread, "GThread %p is exiting", g_thread_self ());
g_signal_emit (G_OBJECT (thread), gst_thread_signals[SHUTDOWN], 0);
g_thread_exit (NULL);
return GST_STATE_SUCCESS;
break;
} else {
/* now wait for the thread to destroy itself */
GST_DEBUG_OBJECT (thread, "signal");
......@@ -548,6 +534,17 @@ gst_thread_change_state (GstElement * element)
} else {
ret = GST_STATE_SUCCESS;
}
g_mutex_lock (thread->lock);
if (GST_STATE (thread) == GST_STATE_PLAYING &&
GST_FLAG_IS_SET (thread, GST_THREAD_STATE_WAITING)) {
GST_FLAG_SET (thread, GST_THREAD_STATE_SPINNING);
if (!is_self) {
g_cond_signal (thread->cond);
}
}
g_mutex_unlock (thread->lock);
if (!is_self)
g_mutex_unlock (thread->iterate_lock);
......@@ -595,6 +592,13 @@ gst_thread_child_state_change (GstBin * bin, GstElementState oldstate,
if (parent_class->child_state_change)
parent_class->child_state_change (bin, oldstate, newstate, element);
/* if we're changing from playing to paused, kids will one-by-one go
* to paused while we're playing, which is bad if we execute the code
* below. We should only do that when a child explicitely changed
* state outside our own context. */
if (GST_FLAG_IS_SET (bin, GST_BIN_STATE_LOCKED))
return;
/* see if we have to wake up the thread now. */
if (is_self) {
GST_LOG_OBJECT (element, "we are in the thread context");
......
......@@ -17,7 +17,7 @@ SUBDIRS = \
bins bytestream caps cleanup clock \
$(GST_DEBUG_DIRS) \
dlopen dynparams \
elements ghostpads indexers negotiation \
elements ghostpads indexers negotiation pad \
$(GST_PARSE_DIRS) \
plugin refcounting schedulers states tags threads
......@@ -25,7 +25,7 @@ DIST_SUBDIRS = \
bins bytestream caps cleanup clock \
debug \
dlopen dynparams \
elements ghostpads indexers negotiation \
elements ghostpads indexers negotiation pad \
parse \
plugin refcounting schedulers states tags threads
......
......@@ -84,7 +84,7 @@ gst_fp_sink_init (GstFpSink * fp)
fp->sinkpad =
GST_FILE_PAD (gst_file_pad_new (gst_static_pad_template_get (&template),
"src"));
"sink"));
gst_file_pad_set_iterate_function (fp->sinkpad, do_tests);
gst_element_add_pad (GST_ELEMENT (fp), GST_PAD (fp->sinkpad));
}
......
include ../Rules
tests_pass = link
tests_fail =
tests_ignore = chainnopull getnopush
/*
* this tests that chain-based pads don't pull.
*/
#include <gst/gst.h>
typedef struct _GstTestSink
{
GstElement parent;
GstPad *sinkpad;
} GstTestSink;
typedef GstElementClass GstTestSinkClass;
static void
gst_test_sink_class_init (GstTestSinkClass * klass)
{
}
static void
gst_test_sink_base_init (gpointer klass)
{
}
static void
gst_test_sink_chain (GstPad * pad, GstData * data)
{
data = gst_pad_pull (pad);
}
static void
gst_test_sink_init (GstTestSink * sink)
{
sink->sinkpad = gst_pad_new ("sink", GST_PAD_SINK);
gst_pad_set_chain_function (sink->sinkpad, gst_test_sink_chain);
gst_element_add_pad (GST_ELEMENT (sink), sink->sinkpad);
}
GST_BOILERPLATE (GstTestSink, gst_test_sink, GstElement, GST_TYPE_ELEMENT);
int
main (int argc, char *argv[])
{
GstElement *pipeline, *fakesrc, *testsink;
gint n;
gst_init (&argc, &argv);
pipeline = gst_pipeline_new ("p");
fakesrc = gst_element_factory_make ("fakesrc", "src");
testsink = g_object_new (gst_test_sink_get_type (), NULL);
gst_object_set_name (GST_OBJECT (testsink), "sink");
gst_bin_add_many (GST_BIN (pipeline), fakesrc, testsink, NULL);
gst_element_link (fakesrc, testsink);
gst_element_set_state (pipeline, GST_STATE_PLAYING);
for (n = 0; n < 100; n++) {
if (!gst_bin_iterate (GST_BIN (pipeline)))
break;
}
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (GST_OBJECT (pipeline));
return 0;
}
/*
* this tests that get-based pads don't push.
*/
#include <gst/gst.h>
typedef struct _GstTestSrc
{
GstElement parent;
GstPad *srcpad;
} GstTestSrc;
typedef GstElementClass GstTestSrcClass;
static void
gst_test_src_class_init (GstTestSrcClass * klass)
{
}
static void
gst_test_src_base_init (gpointer klass)
{
}
static GstData *
gst_test_src_get (GstPad * pad)
{
GstEvent *event;
event = gst_event_new (GST_EVENT_INTERRUPT);
gst_event_ref (event);
gst_pad_push (pad, GST_DATA (event));
return GST_DATA (event);
}
static void
gst_test_src_init (GstTestSrc * src)
{
src->srcpad = gst_pad_new ("src", GST_PAD_SRC);
gst_pad_set_get_function (src->srcpad, gst_test_src_get);
gst_element_add_pad (GST_ELEMENT (src), src->srcpad);
}
GST_BOILERPLATE (GstTestSrc, gst_test_src, GstElement, GST_TYPE_ELEMENT);
int
main (int argc, char *argv[])
{
GstElement *pipeline, *testsrc, *fakesink;
gint n;
gst_init (&argc, &argv);
pipeline = gst_pipeline_new ("p");
testsrc = g_object_new (gst_test_src_get_type (), NULL);
gst_object_set_name (GST_OBJECT (testsrc), "src");
fakesink = gst_element_factory_make ("fakesink", "sink");
gst_bin_add_many (GST_BIN (pipeline), testsrc, fakesink, NULL);
gst_element_link (testsrc, fakesink);
gst_element_set_state (pipeline, GST_STATE_PLAYING);
for (n = 0; n < 100; n++) {
if (!gst_bin_iterate (GST_BIN (pipeline)))
break;
}
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (GST_OBJECT (pipeline));
return 0;
}
/*
* Test that:
* - get-based sources can return data, loop-based sources can push.
* - chain-based filters receive/push, loop-based filters can pull/push.
* - chain-based sinks receive, loop-based sinks pull.
*/
#include <gst/gst.h>
/*
* Scary type code.
*/
typedef struct _GstTestElement
{
GstElement parent;
GstPad *srcpad, *sinkpad;
} GstTestSrc, GstTestFilter, GstTestSink, GstTestElement;
typedef GstElementClass GstTestSrcClass, GstTestFilterClass, GstTestSinkClass,
GstTestElementClass;
#define gst_test_src_class_init gst_test_element_class_init
#define gst_test_filter_class_init gst_test_element_class_init
#define gst_test_sink_class_init gst_test_element_class_init
#define gst_test_src_base_init gst_test_element_base_init
#define gst_test_filter_base_init gst_test_element_base_init
#define gst_test_sink_base_init gst_test_element_base_init
static void
gst_test_element_class_init (GstTestElementClass * klass)
{
}
static void
gst_test_element_base_init (gpointer klass)
{
}
/*
* Actual element code.
*/
gboolean loop = FALSE;
static GstData *
gst_test_src_get (GstPad * pad)
{
return GST_DATA (gst_event_new (GST_EVENT_INTERRUPT));
}
static void
gst_test_src_loop (GstElement * element)
{
GstTestSrc *src = (GstTestElement *) element;
gst_pad_push (src->srcpad, gst_test_src_get (src->srcpad));
}
static void
gst_test_src_init (GstTestElement * src)
{
src->srcpad = gst_pad_new ("src", GST_PAD_SRC);
if (loop) {
gst_element_set_loop_function (GST_ELEMENT (src), gst_test_src_loop);
} else {
gst_pad_set_get_function (src->srcpad, gst_test_src_get);
}
gst_element_add_pad (GST_ELEMENT (src), src->srcpad);
GST_FLAG_SET (src, GST_ELEMENT_EVENT_AWARE);
}
static void
gst_test_filter_chain (GstPad * pad, GstData * data)
{
GstTestFilter *filter = (GstTestElement *) gst_pad_get_parent (pad);
gst_pad_push (filter->srcpad, data);
}
static void
gst_test_filter_loop (GstElement * element)
{
GstTestFilter *filter = (GstTestElement *) element;
gst_test_filter_chain (filter->sinkpad, gst_pad_pull (filter->sinkpad));
}
static void
gst_test_filter_init (GstTestElement * filter)
{
filter->sinkpad = gst_pad_new ("sink", GST_PAD_SINK);
if (loop) {
gst_element_set_loop_function (GST_ELEMENT (filter), gst_test_filter_loop);
} else {
gst_pad_set_chain_function (filter->sinkpad, gst_test_filter_chain);
}
gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
filter->srcpad = gst_pad_new ("src", GST_PAD_SRC);
gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
GST_FLAG_SET (filter, GST_ELEMENT_EVENT_AWARE);
}
static void
gst_test_sink_chain (GstPad * pad, GstData * data)
{
gst_data_unref (data);
}
static void
gst_test_sink_loop (GstElement * element)
{
GstTestSink *sink = (GstTestElement *) element;
gst_test_sink_chain (sink->sinkpad, gst_pad_pull (sink->sinkpad));
}
static void
gst_test_sink_init (GstTestElement * sink)
{
sink->sinkpad = gst_pad_new ("sink", GST_PAD_SINK);
if (loop) {
gst_element_set_loop_function (GST_ELEMENT (sink), gst_test_sink_loop);
} else {
gst_pad_set_chain_function (sink->sinkpad, gst_test_sink_chain);
}
gst_element_add_pad (GST_ELEMENT (sink), sink->sinkpad);
GST_FLAG_SET (sink, GST_ELEMENT_EVENT_AWARE);
}
#define parent_class src_parent_class
GST_BOILERPLATE (GstTestSrc, gst_test_src, GstElement, GST_TYPE_ELEMENT);
#undef parent_class
#define parent_class filter_parent_class
GST_BOILERPLATE (GstTestFilter, gst_test_filter, GstElement, GST_TYPE_ELEMENT);
#undef parent_class
#define parent_class sink_parent_class
GST_BOILERPLATE (GstTestSink, gst_test_sink, GstElement, GST_TYPE_ELEMENT);
#undef parent_class
/*
* Actual test.
*/
static void
cb_error (GstElement * element)
{
g_assert_not_reached ();
}
int
main (int argc, char *argv[])
{
GstElement *pipeline, *src, *filter, *sink;
gint n, r;
gboolean res;
gst_init (&argc, &argv);
for (r = 0; r < 2; r++) {
pipeline = gst_pipeline_new ("p");
g_signal_connect (pipeline, "error", G_CALLBACK (cb_error), NULL);
src = g_object_new (gst_test_src_get_type (), NULL);
gst_object_set_name (GST_OBJECT (src), "src");
filter = g_object_new (gst_test_filter_get_type (), NULL);
gst_object_set_name (GST_OBJECT (filter), "filter");
sink = g_object_new (gst_test_sink_get_type (), NULL);
gst_object_set_name (GST_OBJECT (sink), "sink");
gst_bin_add_many (GST_BIN (pipeline), src, filter, sink, NULL);
res = gst_element_link (src, filter);
g_assert (res);
res = gst_element_link (filter, sink);
g_assert (res);
gst_element_set_state (pipeline, GST_STATE_PLAYING);
for (n = 0; n < 100; n++) {
if (!gst_bin_iterate (GST_BIN (pipeline)))
g_assert_not_reached ();
}
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (GST_OBJECT (pipeline));
/* switch element types */
g_print ("Loop=%s done\n", loop ? "true" : "false");
loop = !loop;
}
return 0;
}
include ../Rules
tests_pass = thread1 thread2 thread3 thread4 thread5 threade threadf signal1 159852