[Solved] gst_element_set_state deadlocks of element before input-selector
This post was updated on .
I'm trying to create a dynamic pipeline which allows multiple connections to
rtsp sources, toggle between them using input-selector and send the data
(after decoded) to an appsink.
When launching the pipeline everything works fine.
The issues occur when I kill one of the RTSP servers.
I try to recover from this, so I remove the rtspsrc from the pipeline and
try to add it again.
Before I remove it, I try to change the state of that rtspsrc element to
GST_STATE_NULL. But as I do that, this function call deadlocks.
Btw, this only occurs if the RTSP server I kill is not the active one in the
I tried adding a queue after every rtspsrc and it indeed helped. So instead
of it deadlocks every time, it only deadlocks every like 10th time. After I
added the queue, the element which causes the deadlock is the queue, not the
If I try to add some sleep time before setting the state to NULL then it will always deadlock once again. So it's some sort of a race condition.
I'm sharing parts of my code which are relevant:
Bus callback which detects the rtsp errors.
After it removes is I wait 1 second before trying to re-establish connection
with it again.
I think the reason it deadlocks, is because it is waiting for the element to
flush all the data downstream before changing states, but the input-selector
doesn't take data from that element. This is why this only occurs when the
active pad is not part of the rtspsrc that died.
How can I flush the buffer of the queue / rtspsrc before changing the state?
To flush the queue, you can do something like the following:
- Get the queue sink and src pads
- Add a probe to the src pad with a new callback to delete EOS signals
- Send an EOS to the sink pad
- In the callback function, wait for the EOS to arrive, then delete it. The
queue should be flushed.
- Set the queue to NULL and do whatever.
If you have to flush the rtspsrc, you'll have to send the EOS to that
instead of the queue sink pad (I've never done this, though, so can't speak
static GstPadProbeReturn delete_eos_cb(GstPad* pad, GstPadProbeInfo* info,
GstEvent* pad_event = gst_pad_probe_get_event(info);
if (pad_event->type == GST_EVENT_EOS)
// EOS went through the element
// Do something with rtspsrc and queue
return GST_PAD_PROBE_DROP; // Delete the EOS to prevent flushing the
return GST_PAD_PROBE_OK; // Otherwise, pass the event onwards
On a side note, I recently had a problem where I was trying to set an
element to NULL before removing it from a pipeline, but this was in
deadlock. To solve this, instead of altering the pipeline in the bus message
handler, I scheduled a function to run a bit later using something similar
to your QTimer::singleShot. Just FYI.
I ended up throwing the queue away. Didn't really need it.
I flushed the buffer using:
Then I could change the state without a problem.
Then I had a different issue where my new rtspsrc didn't send any data to the input-selector.
I figured out that I needed to send a flush_stop event so that the input-selector pad can receive new data to its sink pad.
I really hope this will help anyone in the future. I googled this forever and couldn't find an answer.
I think that the reason that it deadlocked is because data was still present in the element when I tried to change it to NULL. And since this element is not active in the input-selector, it will remain there. So flushing is a must.