rtmpsrc: fix flushing seek
authorGeorge Kiagiadakis <george.kiagiadakis@collabora.com>
Mon, 7 Aug 2017 11:25:26 +0000 (14:25 +0300)
committerGeorge Kiagiadakis <george.kiagiadakis@collabora.com>
Tue, 8 Aug 2017 13:00:44 +0000 (16:00 +0300)
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

index 14a3d27..12931a2 100644 (file)
@@ -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;