From f0500ec8b429b2ad44ac053982022f16296f51fd Mon Sep 17 00:00:00 2001 From: George Kiagiadakis Date: Mon, 7 Aug 2017 14:25:26 +0300 Subject: [PATCH] rtmpsrc: fix flushing seek Previously this was broken, because a flushing seek causes unlock() to be called and in the implementation of unlock() we close the socket, so the seek errors out. This patch fixes it by re-connecting before the seek. Unfortunately, a seek does not work properly right after re-connecting, so a small hack is also in place: we read 1 buffer before seeking to allow librtmp to do its processing in RTMP_Read() https://bugzilla.gnome.org/show_bug.cgi?id=785941 --- ext/rtmp/gstrtmpsrc.c | 67 ++++++++++++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 20 deletions(-) diff --git a/ext/rtmp/gstrtmpsrc.c b/ext/rtmp/gstrtmpsrc.c index 14a3d27d03..12931a2a38 100644 --- a/ext/rtmp/gstrtmpsrc.c +++ b/ext/rtmp/gstrtmpsrc.c @@ -88,6 +88,7 @@ static void gst_rtmp_src_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); static void gst_rtmp_src_finalize (GObject * object); +static gboolean gst_rtmp_src_connect (GstRTMPSrc * src); static gboolean gst_rtmp_src_unlock (GstBaseSrc * src); static gboolean gst_rtmp_src_stop (GstBaseSrc * src); static gboolean gst_rtmp_src_start (GstBaseSrc * src); @@ -330,6 +331,12 @@ gst_rtmp_src_create (GstPushSrc * pushsrc, GstBuffer ** buffer) g_return_val_if_fail (src->rtmp != NULL, GST_FLOW_ERROR); + if (!RTMP_IsConnected (src->rtmp)) { + GST_DEBUG_OBJECT (src, "reconnecting"); + if (!gst_rtmp_src_connect (src)) + return GST_FLOW_ERROR; + } + size = GST_BASE_SRC_CAST (pushsrc)->blocksize; GST_DEBUG ("reading from %" G_GUINT64_FORMAT @@ -541,17 +548,24 @@ gst_rtmp_src_do_seek (GstBaseSrc * basesrc, GstSegment * segment) return FALSE; } - src->discont = TRUE; - /* Initial seek */ if (src->cur_offset == 0 && segment->start == 0) - return TRUE; + goto success; if (!src->seekable) { GST_LOG_OBJECT (src, "Not a seekable stream"); return FALSE; } + /* If we have just disconnected in unlock(), we need to re-connect + * and also let librtmp read some data before sending a seek, + * otherwise it will stall. Calling create() does both. */ + if (!RTMP_IsConnected (src->rtmp)) { + GstBuffer *buffer = NULL; + gst_rtmp_src_create (GST_PUSH_SRC (basesrc), &buffer); + gst_buffer_replace (&buffer, NULL); + } + src->last_timestamp = GST_CLOCK_TIME_NONE; if (!RTMP_SendSeek (src->rtmp, segment->start / GST_MSECOND)) { GST_ERROR_OBJECT (src, "Seeking failed"); @@ -559,12 +573,41 @@ gst_rtmp_src_do_seek (GstBaseSrc * basesrc, GstSegment * segment) return FALSE; } +success: + /* This is set here so that the call to create() above doesn't clear it */ + src->discont = TRUE; + GST_DEBUG_OBJECT (src, "Seek to %" GST_TIME_FORMAT " successfull", GST_TIME_ARGS (segment->start)); return TRUE; } +static gboolean +gst_rtmp_src_connect (GstRTMPSrc * src) +{ + RTMP_Init (src->rtmp); + src->rtmp->Link.timeout = src->timeout; + if (!RTMP_SetupURL (src->rtmp, src->uri)) { + GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), + ("Failed to setup URL '%s'", src->uri)); + return FALSE; + } + src->seekable = !(src->rtmp->Link.lFlags & RTMP_LF_LIVE); + GST_INFO_OBJECT (src, "seekable %d", src->seekable); + + /* open if required */ + if (!RTMP_IsConnected (src->rtmp)) { + if (!RTMP_Connect (src->rtmp, NULL)) { + GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), + ("Could not connect to RTMP stream \"%s\" for reading", src->uri)); + return FALSE; + } + } + + return TRUE; +} + /* open the file, do stuff necessary to go to PAUSED state */ static gboolean gst_rtmp_src_start (GstBaseSrc * basesrc) @@ -588,24 +631,8 @@ gst_rtmp_src_start (GstBaseSrc * basesrc) goto error; } - RTMP_Init (src->rtmp); - src->rtmp->Link.timeout = src->timeout; - if (!RTMP_SetupURL (src->rtmp, src->uri)) { - GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), - ("Failed to setup URL '%s'", src->uri)); + if (!gst_rtmp_src_connect (src)) goto error; - } - src->seekable = !(src->rtmp->Link.lFlags & RTMP_LF_LIVE); - GST_INFO_OBJECT (src, "seekable %d", src->seekable); - - /* open if required */ - if (!RTMP_IsConnected (src->rtmp)) { - if (!RTMP_Connect (src->rtmp, NULL)) { - GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), - ("Could not connect to RTMP stream \"%s\" for reading", src->uri)); - goto error; - } - } return TRUE;