bin, pipeline, sink: state change / async-done propagation issue with repeated rtspsrc seeks
Submitted by ste..@..il.com
Link to original bug (#760532)
Description
I'm having a issue at the moment with continuously seeks with RTSP playback. The rtsp client is connected with TCP interleave and I am seeking continuously, lets say every second or so I do a new seek. Then sometimes after seeking 3-5 times the video playback stalls for 20 seconds or so, but sometimes I can seek for 30 times before it happens.
Server:
rtsp server serving a mkv file, the pipeline looks something like:
.---------. .---------------. .------------.
| filesrc |->| matroskademux |->| rtph264pay |
'---------' '---------------' '------------'
But I have also tried adding queues in between the elements.
The video file:
resolution: 1280x720
bitrate: 4096kb
framerate: 30fps
duration: 60 min
gov length: 10
Client:
rtspsrc location=rtsp://127.0.0.1:8554/something protocols=0x4 ! queue ! rtph264depay! avdec_h264 ! autovideosink
Test:
I have tried to create a test application for this, but it seems to not always happen.
#include <gst/gst.h>
void do_seek(GstElement *pipeline, gint64 timestamp)
{
unsigned int seek_flags = GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT | GST_SEEK_FLAG_SNAP_NEAREST;
gst_element_seek_simple(pipeline, GST_FORMAT_TIME, seek_flags, timestamp);
}
int main()
{
GstElement *pipeline;
GstBus *bus;
GstMessage *msg;
gint64 position = GST_SECOND * 5;
// initialize GStreamer
gst_init(NULL, NULL);
pipeline = gst_parse_launch("rtspsrc name=rtspsrc ! queue ! rtph264depay ! fakesink", NULL);
GstElement *rtspsrc = gst_bin_get_by_name(GST_BIN(pipeline), "rtspsrc");
g_object_set(rtspsrc,
"location", "rtsp://localhost:8554/something",
"protocols", 4, // 4 = GST_RTSP_LOWER_TRANS_TCP
NULL);
g_object_unref(rtspsrc);
gst_element_set_state(pipeline, GST_STATE_PLAYING);
gst_element_get_state(pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
// Wait until error, eos or async done
bus = gst_element_get_bus(pipeline);
unsigned int bus_flags = GST_MESSAGE_ERROR | GST_MESSAGE_EOS | GST_MESSAGE_ASYNC_DONE;
msg = gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, (GstMessageType)(bus_flags));
unsigned int seek_count = 0;
while(GST_MESSAGE_TYPE(msg) != GST_MESSAGE_EOS)
{
g_print("seek (%u) again... :D\n", seek_count++);
position += GST_SECOND;
do_seek(pipeline, position);
gst_message_unref(msg);
msg = gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, (GstMessageType)(bus_flags));
}
// Free resources
gst_message_unref(msg);
gst_object_unref(bus);
gst_element_set_state(pipeline, GST_STATE_NULL);
gst_object_unref(pipeline);
g_print("done");
return 0;
}