hlssink: implement a chain_list to request key unit for segments
authorThiago Santos <thiagoss@osg.samsung.com>
Sat, 28 Mar 2015 14:40:14 +0000 (11:40 -0300)
committerThiago Santos <thiagoss@osg.samsung.com>
Mon, 30 Mar 2015 15:31:08 +0000 (12:31 -0300)
upstream might send buffer lists instead of buffers and hlssink's
probe won't get called and a new segment won't be created when needed.

This patch fixes it by adding a chain_list function to the sink pad
that will just pass through the whole bufferlist if no segment needs
to be requested at the moment or convert the list into buffers to
check the proper timestamp to request the next key-unit that will
start the segment.

https://bugzilla.gnome.org/show_bug.cgi?id=746906

ext/hls/gsthlssink.c

index ea337eaa6efaf6b1129076f74f4b8666a3b60469..445caf50a8a74510ba2aa9a3d05a608f3df4d50b 100644 (file)
@@ -85,6 +85,8 @@ static void gst_hls_sink_reset (GstHlsSink * sink);
 static GstStateChangeReturn
 gst_hls_sink_change_state (GstElement * element, GstStateChange trans);
 static gboolean schedule_next_key_unit (GstHlsSink * sink);
+static GstFlowReturn gst_hls_sink_chain_list (GstPad * pad, GstObject * parent,
+    GstBufferList * list);
 
 static void
 gst_hls_sink_dispose (GObject * object)
@@ -180,6 +182,7 @@ gst_hls_sink_init (GstHlsSink * sink)
       gst_hls_sink_ghost_event_probe, sink, NULL);
   gst_pad_add_probe (sink->ghostpad, GST_PAD_PROBE_TYPE_BUFFER,
       gst_hls_sink_ghost_buffer_probe, sink, NULL);
+  gst_pad_set_chain_list_function (sink->ghostpad, gst_hls_sink_chain_list);
 
   sink->location = g_strdup (DEFAULT_LOCATION);
   sink->playlist_location = g_strdup (DEFAULT_PLAYLIST_LOCATION);
@@ -499,6 +502,19 @@ out:
   return res;
 }
 
+static void
+gst_hls_sink_check_schedule_next_key_unit (GstHlsSink * sink, GstBuffer * buf)
+{
+  GstClockTime timestamp;
+
+  timestamp = GST_BUFFER_TIMESTAMP (buf);
+  if (!GST_CLOCK_TIME_IS_VALID (timestamp))
+    return;
+
+  sink->last_running_time = gst_segment_to_running_time (&sink->segment,
+      GST_FORMAT_TIME, timestamp);
+  schedule_next_key_unit (sink);
+}
 
 static GstPadProbeReturn
 gst_hls_sink_ghost_buffer_probe (GstPad * pad, GstPadProbeInfo * info,
@@ -506,19 +522,45 @@ gst_hls_sink_ghost_buffer_probe (GstPad * pad, GstPadProbeInfo * info,
 {
   GstHlsSink *sink = GST_HLS_SINK_CAST (data);
   GstBuffer *buffer = gst_pad_probe_info_get_buffer (info);
-  GstClockTime timestamp;
 
-  timestamp = GST_BUFFER_TIMESTAMP (buffer);
-  if (sink->target_duration == 0 || !GST_CLOCK_TIME_IS_VALID (timestamp)
-      || sink->waiting_fku)
+  if (sink->target_duration == 0 || sink->waiting_fku)
     return GST_PAD_PROBE_OK;
 
-  sink->last_running_time = gst_segment_to_running_time (&sink->segment,
-      GST_FORMAT_TIME, timestamp);
-  schedule_next_key_unit (sink);
+  gst_hls_sink_check_schedule_next_key_unit (sink, buffer);
   return GST_PAD_PROBE_OK;
 }
 
+static GstFlowReturn
+gst_hls_sink_chain_list (GstPad * pad, GstObject * parent, GstBufferList * list)
+{
+  guint i, len;
+  GstBuffer *buffer;
+  GstFlowReturn ret;
+  GstHlsSink *sink = GST_HLS_SINK_CAST (parent);
+
+  if (sink->target_duration == 0 || sink->waiting_fku)
+    return gst_proxy_pad_chain_list_default (pad, parent, list);
+
+  GST_DEBUG_OBJECT (pad, "chaining each group in list as a merged buffer");
+
+  len = gst_buffer_list_length (list);
+
+  ret = GST_FLOW_OK;
+  for (i = 0; i < len; i++) {
+    buffer = gst_buffer_list_get (list, i);
+
+    if (!sink->waiting_fku)
+      gst_hls_sink_check_schedule_next_key_unit (sink, buffer);
+
+    ret = gst_pad_chain (pad, gst_buffer_ref (buffer));
+    if (ret != GST_FLOW_OK)
+      break;
+  }
+  gst_buffer_list_unref (list);
+
+  return ret;
+}
+
 gboolean
 gst_hls_sink_plugin_init (GstPlugin * plugin)
 {