mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-27 02:30:35 +00:00
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.
This commit is contained in:
parent
10aa48db8d
commit
d8d03b6b98
27 changed files with 1053 additions and 62 deletions
47
ChangeLog
47
ChangeLog
|
@ -1,3 +1,50 @@
|
|||
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>
|
||||
|
||||
|
|
71
gst/gstbin.c
71
gst/gstbin.c
|
@ -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
|
||||
|
|
26
gst/gstbin.h
26
gst/gstbin.h
|
@ -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));
|
||||
}
|
||||
|
|
5
tests/old/testsuite/pad/Makefile.am
Normal file
5
tests/old/testsuite/pad/Makefile.am
Normal file
|
@ -0,0 +1,5 @@
|
|||
include ../Rules
|
||||
|
||||
tests_pass = link
|
||||
tests_fail =
|
||||
tests_ignore = chainnopull getnopush
|
66
tests/old/testsuite/pad/chainnopull.c
Normal file
66
tests/old/testsuite/pad/chainnopull.c
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
71
tests/old/testsuite/pad/getnopush.c
Normal file
71
tests/old/testsuite/pad/getnopush.c
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
194
tests/old/testsuite/pad/link.c
Normal file
194
tests/old/testsuite/pad/link.c
Normal file
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
include ../Rules
|
||||
|
||||
tests_pass = thread1 thread2 thread3 thread4 thread5 threade threadf signal1 159852
|
||||
tests_pass = thread1 thread2 thread3 thread4 thread5 threade threadf signal1 159852 threadg threadi
|
||||
tests_fail = 159566 signal2 signal3
|
||||
|
||||
# threadh
|
||||
|
||||
tests_ignore = queue threadb threadc threadd staticrec threadg
|
||||
tests_ignore = queue threadb threadc threadd staticrec
|
||||
|
||||
thread1_SOURCES = thread.c
|
||||
thread1_CFLAGS = -DTESTNUM=1 $(AM_CFLAGS)
|
||||
|
|
|
@ -95,6 +95,7 @@ main (gint argc, gchar * argv[])
|
|||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
g_print ("running ...\n");
|
||||
while (gst_bin_iterate (GST_BIN (pipeline)));
|
||||
g_print ("done ...\n");
|
||||
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||
}
|
||||
if (TESTNUM == 4) {
|
||||
|
|
111
tests/old/testsuite/threads/threadi.c
Normal file
111
tests/old/testsuite/threads/threadi.c
Normal file
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Test two ways of going non-lineairly to PLAYING. Both tests have a thread
|
||||
* containing a fakesrc/sink and a containing thread.
|
||||
*
|
||||
* Test 1 tests by adding fakesrc, putting thread to PLAYING, adding
|
||||
* fakesink, syncing state and see if it iterates.
|
||||
*
|
||||
* Test2 tests by adding fakesrc/fakesink, setting fakesrc to PLAYING
|
||||
* (which should increment the container state) and then synchronizing
|
||||
* state. This reflects bug #123775.
|
||||
*/
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
static GstElement *pipeline, *fakesrc, *fakesink;
|
||||
gboolean bug = FALSE;
|
||||
|
||||
static gboolean
|
||||
cb_timeout (gpointer data)
|
||||
{
|
||||
g_assert_not_reached ();
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
cb_quit (gpointer data)
|
||||
{
|
||||
gst_main_quit ();
|
||||
|
||||
g_print ("Quit mainloop\n");
|
||||
|
||||
/* once */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
cb_eos (gpointer data)
|
||||
{
|
||||
g_print ("Received EOS\n");
|
||||
|
||||
g_idle_add ((GSourceFunc) cb_quit, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
cb_state (GstElement * element, GstElementState old_state,
|
||||
GstElementState new_state, gpointer data)
|
||||
{
|
||||
g_print ("Changed state from %d to %d\n", old_state, new_state);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
cb_play (gpointer data)
|
||||
{
|
||||
GstElementStateReturn res;
|
||||
|
||||
if (bug) {
|
||||
g_print ("Setting state\n");
|
||||
gst_element_set_state (fakesrc, GST_STATE_PLAYING);
|
||||
g_print ("Done\n");
|
||||
} else {
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
gst_bin_add (GST_BIN (pipeline), fakesink);
|
||||
}
|
||||
g_print ("Syncing state\n");
|
||||
res = gst_bin_sync_children_state (GST_BIN (data));
|
||||
g_assert (res == GST_STATE_SUCCESS);
|
||||
|
||||
g_print ("Set to playing correctly: %d\n", GST_STATE (pipeline));
|
||||
|
||||
/* once */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gint
|
||||
main (gint argc, gchar * argv[])
|
||||
{
|
||||
gint n, id;
|
||||
|
||||
gst_init (&argc, &argv);
|
||||
|
||||
for (n = 0; n < 2; n++) {
|
||||
pipeline = gst_thread_new ("p");
|
||||
g_signal_connect (pipeline, "state-change", G_CALLBACK (cb_state), NULL);
|
||||
fakesrc = gst_element_factory_make ("fakesrc", "src");
|
||||
g_object_set (G_OBJECT (fakesrc), "num-buffers", 1, NULL);
|
||||
fakesink = gst_element_factory_make ("fakesink", "sink");
|
||||
if (bug) {
|
||||
gst_bin_add_many (GST_BIN (pipeline), fakesrc, fakesink, NULL);
|
||||
} else {
|
||||
gst_bin_add (GST_BIN (pipeline), fakesrc);
|
||||
}
|
||||
gst_element_link (fakesrc, fakesink);
|
||||
g_signal_connect (pipeline, "eos", G_CALLBACK (cb_eos), NULL);
|
||||
g_idle_add ((GSourceFunc) cb_play, pipeline);
|
||||
|
||||
/* give 5 seconds */
|
||||
id = g_timeout_add (5000, (GSourceFunc) cb_timeout, NULL);
|
||||
g_print ("Enter mainloop\n");
|
||||
gst_main ();
|
||||
g_source_remove (id);
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||
gst_object_unref (GST_OBJECT (pipeline));
|
||||
|
||||
g_print ("Done with reproduce-bug-123775=%s\n", bug ? "true" : "false");
|
||||
bug = !bug;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
|
|
5
testsuite/pad/Makefile.am
Normal file
5
testsuite/pad/Makefile.am
Normal file
|
@ -0,0 +1,5 @@
|
|||
include ../Rules
|
||||
|
||||
tests_pass = link
|
||||
tests_fail =
|
||||
tests_ignore = chainnopull getnopush
|
66
testsuite/pad/chainnopull.c
Normal file
66
testsuite/pad/chainnopull.c
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
71
testsuite/pad/getnopush.c
Normal file
71
testsuite/pad/getnopush.c
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
194
testsuite/pad/link.c
Normal file
194
testsuite/pad/link.c
Normal file
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
include ../Rules
|
||||
|
||||
tests_pass = thread1 thread2 thread3 thread4 thread5 threade threadf signal1 159852
|
||||
tests_pass = thread1 thread2 thread3 thread4 thread5 threade threadf signal1 159852 threadg threadi
|
||||
tests_fail = 159566 signal2 signal3
|
||||
|
||||
# threadh
|
||||
|
||||
tests_ignore = queue threadb threadc threadd staticrec threadg
|
||||
tests_ignore = queue threadb threadc threadd staticrec
|
||||
|
||||
thread1_SOURCES = thread.c
|
||||
thread1_CFLAGS = -DTESTNUM=1 $(AM_CFLAGS)
|
||||
|
|
|
@ -95,6 +95,7 @@ main (gint argc, gchar * argv[])
|
|||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
g_print ("running ...\n");
|
||||
while (gst_bin_iterate (GST_BIN (pipeline)));
|
||||
g_print ("done ...\n");
|
||||
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||
}
|
||||
if (TESTNUM == 4) {
|
||||
|
|
111
testsuite/threads/threadi.c
Normal file
111
testsuite/threads/threadi.c
Normal file
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Test two ways of going non-lineairly to PLAYING. Both tests have a thread
|
||||
* containing a fakesrc/sink and a containing thread.
|
||||
*
|
||||
* Test 1 tests by adding fakesrc, putting thread to PLAYING, adding
|
||||
* fakesink, syncing state and see if it iterates.
|
||||
*
|
||||
* Test2 tests by adding fakesrc/fakesink, setting fakesrc to PLAYING
|
||||
* (which should increment the container state) and then synchronizing
|
||||
* state. This reflects bug #123775.
|
||||
*/
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
static GstElement *pipeline, *fakesrc, *fakesink;
|
||||
gboolean bug = FALSE;
|
||||
|
||||
static gboolean
|
||||
cb_timeout (gpointer data)
|
||||
{
|
||||
g_assert_not_reached ();
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
cb_quit (gpointer data)
|
||||
{
|
||||
gst_main_quit ();
|
||||
|
||||
g_print ("Quit mainloop\n");
|
||||
|
||||
/* once */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
cb_eos (gpointer data)
|
||||
{
|
||||
g_print ("Received EOS\n");
|
||||
|
||||
g_idle_add ((GSourceFunc) cb_quit, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
cb_state (GstElement * element, GstElementState old_state,
|
||||
GstElementState new_state, gpointer data)
|
||||
{
|
||||
g_print ("Changed state from %d to %d\n", old_state, new_state);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
cb_play (gpointer data)
|
||||
{
|
||||
GstElementStateReturn res;
|
||||
|
||||
if (bug) {
|
||||
g_print ("Setting state\n");
|
||||
gst_element_set_state (fakesrc, GST_STATE_PLAYING);
|
||||
g_print ("Done\n");
|
||||
} else {
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
gst_bin_add (GST_BIN (pipeline), fakesink);
|
||||
}
|
||||
g_print ("Syncing state\n");
|
||||
res = gst_bin_sync_children_state (GST_BIN (data));
|
||||
g_assert (res == GST_STATE_SUCCESS);
|
||||
|
||||
g_print ("Set to playing correctly: %d\n", GST_STATE (pipeline));
|
||||
|
||||
/* once */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gint
|
||||
main (gint argc, gchar * argv[])
|
||||
{
|
||||
gint n, id;
|
||||
|
||||
gst_init (&argc, &argv);
|
||||
|
||||
for (n = 0; n < 2; n++) {
|
||||
pipeline = gst_thread_new ("p");
|
||||
g_signal_connect (pipeline, "state-change", G_CALLBACK (cb_state), NULL);
|
||||
fakesrc = gst_element_factory_make ("fakesrc", "src");
|
||||
g_object_set (G_OBJECT (fakesrc), "num-buffers", 1, NULL);
|
||||
fakesink = gst_element_factory_make ("fakesink", "sink");
|
||||
if (bug) {
|
||||
gst_bin_add_many (GST_BIN (pipeline), fakesrc, fakesink, NULL);
|
||||
} else {
|
||||
gst_bin_add (GST_BIN (pipeline), fakesrc);
|
||||
}
|
||||
gst_element_link (fakesrc, fakesink);
|
||||
g_signal_connect (pipeline, "eos", G_CALLBACK (cb_eos), NULL);
|
||||
g_idle_add ((GSourceFunc) cb_play, pipeline);
|
||||
|
||||
/* give 5 seconds */
|
||||
id = g_timeout_add (5000, (GSourceFunc) cb_timeout, NULL);
|
||||
g_print ("Enter mainloop\n");
|
||||
gst_main ();
|
||||
g_source_remove (id);
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||
gst_object_unref (GST_OBJECT (pipeline));
|
||||
|
||||
g_print ("Done with reproduce-bug-123775=%s\n", bug ? "true" : "false");
|
||||
bug = !bug;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue