[gst-devel] State change hangs if pipeline was changed in PAUSED

4ernov 4ernov at gmail.com
Mon Dec 6 10:03:53 CET 2010


Hello,

I've already posted a couple of questions here concerning my case with
duplicated video stream. Now it works quite right but some strange
behavior still exists.

When I change the pipeline while it's in PAUSED state and then try to
resume it (setting state PLAYING with gst_element_set_state) it never
continues to play anymore. gst_element_set_state() returns
GST_STATE_CHANGE_ASYNC and gst_element_get_state() (as in
documentation) waits for change to complete forever.

Here's a test program:

#include <glib.h>
#include <gst/gst.h>

GstElement *_pipeline, *_fakesink, *_remotesink, *_mpoint, *_queue1,
*_queue2, *_videobin, *_pipe, *gdppay;

void create_pipeline_bin()
{
	GstElement *tee, *queue1, *queue2, *valve, *xvimagesink, *audiosink;

	_pipeline      = gst_element_factory_make("playbin",  NULL);

	tee			= gst_element_factory_make("tee",  NULL);
	xvimagesink   = gst_element_factory_make("ximagesink", NULL);

	GstPad* pad;

	_videobin = gst_bin_new("videobin");
	_queue1 = queue1			= gst_element_factory_make("queue", NULL);
	_queue2 = queue2			= gst_element_factory_make("queue", NULL);
	valve                   = gst_element_factory_make("valve", NULL);

	_fakesink		= gst_element_factory_make("fakesink", NULL);
	audiosink               = gst_element_factory_make("fakesink", NULL);

	gst_object_ref(_fakesink);

	_mpoint = valve;

	gst_bin_add_many(GST_BIN(_videobin), tee, queue1, queue2, valve,
xvimagesink, _fakesink, NULL);

	gst_element_link_many(tee, queue1, xvimagesink, NULL);
	gst_element_link_many(tee, queue2, valve, _fakesink, NULL);
	pad = gst_element_get_static_pad (tee, "sink");
	gst_element_add_pad (_videobin, gst_ghost_pad_new ("sink", pad));
	gst_object_unref (GST_OBJECT (pad));

	g_object_set(G_OBJECT (_pipeline), "uri", "file:///home/alex/test.mp4", NULL);
	g_object_set(G_OBJECT (_pipeline), "video-sink", _videobin, NULL);
	g_object_set(G_OBJECT (_pipeline), "audio-sink", audiosink, NULL);

	gst_element_set_state (_pipeline, GST_STATE_PLAYING);
}

void create_remote_bin()
{
		GstElement *videomixer, *ffmpegcolorspace;
		GstPad* pad;

		videomixer		= gst_element_factory_make("videomixer",  NULL);
		ffmpegcolorspace = gst_element_factory_make("ffmpegcolorspace",  NULL);
		_pipe		= gst_element_factory_make("xvimagesink",  NULL);

		_remotesink = gst_bin_new("vmixerbin");
		gst_bin_add_many(GST_BIN(_remotesink), videomixer, ffmpegcolorspace,
_pipe, NULL);
		gst_element_link_many(videomixer, ffmpegcolorspace, _pipe, NULL);
		pad = gst_element_get_request_pad (videomixer, "sink_%d");
		gst_element_add_pad (_remotesink, gst_ghost_pad_new ("sink", pad));
		gst_object_unref (GST_OBJECT (pad));

		gst_object_ref(_remotesink);
}

void connect_remote_client()
{
	if (_remotesink && _mpoint && _videobin)
	{
                GstState state = GST_STATE(_pipeline);

		gst_element_unlink(_mpoint, _fakesink);
		gst_bin_remove(GST_BIN(_videobin), _fakesink);
		gst_element_set_state (_fakesink, GST_STATE_NULL);

		gst_bin_add(GST_BIN(_videobin), _remotesink);
		gst_element_link(_mpoint, _remotesink);

		gst_element_sync_state_with_parent(_remotesink);

		gst_element_set_state (_pipeline, state);
	}
}

void disconnect_remote_client()
{
	if (_remotesink && _mpoint && _videobin && _fakesink)
	{
                GstState state = GST_STATE(_pipeline);
		gst_element_unlink(_mpoint, _remotesink);
		gst_bin_remove(GST_BIN(_videobin), _remotesink);
		gst_element_set_state (_remotesink, GST_STATE_NULL);

		gst_bin_add(GST_BIN(_videobin), _fakesink);
		gst_element_link(_mpoint, _fakesink);

		gst_element_sync_state_with_parent(_fakesink);

		gst_element_set_state (_pipeline, state);
	}
}

void pause_pipeline()
{
	gst_element_set_state(_pipeline, GST_STATE_PAUSED);
}

void play_pipeline()
{
	gst_element_set_state(_pipeline, GST_STATE_PLAYING);
}

gboolean connect_callback(gpointer)
{
	connect_remote_client();
	return FALSE;
}

gboolean disconnect_callback(gpointer)
{
	disconnect_remote_client();
	return FALSE;
}

gboolean pause_callback(gpointer)
{
	pause_pipeline();
	return FALSE;
}

gboolean play_callback(gpointer)
{
	play_pipeline();
	return FALSE;
}

int main(int argc, char *argv[])
{
	GMainLoop* loop = g_main_loop_new (NULL, FALSE);
	gst_init(&argc, &argv);

	create_remote_bin();
	create_pipeline_bin();

	g_timeout_add(7000, connect_callback, NULL);
	g_timeout_add(16000, pause_callback, NULL);
	g_timeout_add(17000, disconnect_callback, NULL);
	g_timeout_add(18000, play_callback, NULL);

	g_main_loop_run (loop);
        return 0;
}

Second xvimagesink connects successfully in 7 secs after start. Then
in 16 sec the pipeline is set to PAUSED and in 17 sec second video
sink is disconnected. But in 18 sec pipeline doesn't want to get to
PLAYING state anymore.
No messages is posted to output after trying to set the pipeline
PLAYING state, even on DEBUG log level. One certain message is posted
before it:

GST_STATES gstelement.c:2515:gst_element_set_state_func:<playbin0>
element was busy with async state change

I should also notice that if I make pipeline changes in PLAYING state
everything work flawlessly.

Is it bug in GStreamer or should I make state change any other way?




More information about the gstreamer-devel mailing list