adaptivedemux: Allow subclasses to override how a new manifest would be downloaded
authorSebastian Dröge <sebastian@centricular.com>
Thu, 23 Apr 2015 15:22:11 +0000 (17:22 +0200)
committerSebastian Dröge <sebastian@centricular.com>
Thu, 23 Apr 2015 15:47:18 +0000 (17:47 +0200)
ext/dash/gstdashdemux.c
ext/hls/gsthlsdemux.c
ext/smoothstreaming/gstmssdemux.c
ext/smoothstreaming/gstmssmanifest.c
gst-libs/gst/adaptivedemux/gstadaptivedemux.c
gst-libs/gst/adaptivedemux/gstadaptivedemux.h

index e2d5dc7..1b18ec1 100644 (file)
@@ -214,7 +214,7 @@ static gboolean gst_dash_demux_stream_select_bitrate (GstAdaptiveDemuxStream *
 static gint64
 gst_dash_demux_get_manifest_update_interval (GstAdaptiveDemux * demux);
 static GstFlowReturn
-gst_dash_demux_update_manifest (GstAdaptiveDemux * demux, GstBuffer * buf);
+gst_dash_demux_update_manifest_data (GstAdaptiveDemux * demux, GstBuffer * buf);
 static gint64
 gst_dash_demux_stream_get_fragment_waiting_time (GstAdaptiveDemuxStream *
     stream);
@@ -354,7 +354,8 @@ gst_dash_demux_class_init (GstDashDemuxClass * klass)
   gstadaptivedemux_class->seek = gst_dash_demux_seek;
 
   gstadaptivedemux_class->process_manifest = gst_dash_demux_process_manifest;
-  gstadaptivedemux_class->update_manifest = gst_dash_demux_update_manifest;
+  gstadaptivedemux_class->update_manifest_data =
+      gst_dash_demux_update_manifest_data;
   gstadaptivedemux_class->get_manifest_update_interval =
       gst_dash_demux_get_manifest_update_interval;
 
@@ -1145,7 +1146,8 @@ gst_dash_demux_get_manifest_update_interval (GstAdaptiveDemux * demux)
 }
 
 static GstFlowReturn
-gst_dash_demux_update_manifest (GstAdaptiveDemux * demux, GstBuffer * buffer)
+gst_dash_demux_update_manifest_data (GstAdaptiveDemux * demux,
+    GstBuffer * buffer)
 {
   GstDashDemux *dashdemux = GST_DASH_DEMUX_CAST (demux);
   GstMpdClient *new_client = NULL;
index 8da415b..f9d353d 100644 (file)
@@ -100,8 +100,8 @@ static gint64 gst_hls_demux_get_manifest_update_interval (GstAdaptiveDemux *
     demux);
 static gboolean gst_hls_demux_process_manifest (GstAdaptiveDemux * demux,
     GstBuffer * buf);
-static GstFlowReturn gst_hls_demux_update_manifest (GstAdaptiveDemux * demux,
-    GstBuffer * buf);
+static GstFlowReturn gst_hls_demux_update_manifest_data (GstAdaptiveDemux *
+    demux, GstBuffer * buf);
 static gboolean gst_hls_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek);
 static gboolean
 gst_hls_demux_start_fragment (GstAdaptiveDemux * demux,
@@ -186,7 +186,8 @@ gst_hls_demux_class_init (GstHLSDemuxClass * klass)
   adaptivedemux_class->get_manifest_update_interval =
       gst_hls_demux_get_manifest_update_interval;
   adaptivedemux_class->process_manifest = gst_hls_demux_process_manifest;
-  adaptivedemux_class->update_manifest = gst_hls_demux_update_manifest;
+  adaptivedemux_class->update_manifest_data =
+      gst_hls_demux_update_manifest_data;
   adaptivedemux_class->reset = gst_hls_demux_reset;
   adaptivedemux_class->seek = gst_hls_demux_seek;
   adaptivedemux_class->stream_has_next_fragment =
@@ -400,7 +401,7 @@ gst_hls_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek)
 }
 
 static GstFlowReturn
-gst_hls_demux_update_manifest (GstAdaptiveDemux * demux, GstBuffer * buf)
+gst_hls_demux_update_manifest_data (GstAdaptiveDemux * demux, GstBuffer * buf)
 {
   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
   if (!gst_hls_demux_update_playlist (hlsdemux, TRUE, NULL))
index 90cfac1..8f10d7d 100644 (file)
@@ -135,7 +135,8 @@ static gboolean gst_mss_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek);
 static gint64
 gst_mss_demux_get_manifest_update_interval (GstAdaptiveDemux * demux);
 static GstFlowReturn
-gst_mss_demux_update_manifest (GstAdaptiveDemux * demux, GstBuffer * buffer);
+gst_mss_demux_update_manifest_data (GstAdaptiveDemux * demux,
+    GstBuffer * buffer);
 
 static void
 gst_mss_demux_class_init (GstMssDemuxClass * klass)
@@ -188,7 +189,8 @@ gst_mss_demux_class_init (GstMssDemuxClass * klass)
       gst_mss_demux_stream_select_bitrate;
   gstadaptivedemux_class->stream_update_fragment_info =
       gst_mss_demux_stream_update_fragment_info;
-  gstadaptivedemux_class->update_manifest = gst_mss_demux_update_manifest;
+  gstadaptivedemux_class->update_manifest_data =
+      gst_mss_demux_update_manifest_data;
 
   GST_DEBUG_CATEGORY_INIT (mssdemux_debug, "mssdemux", 0, "mssdemux plugin");
 }
@@ -546,7 +548,8 @@ gst_mss_demux_get_manifest_update_interval (GstAdaptiveDemux * demux)
 }
 
 static GstFlowReturn
-gst_mss_demux_update_manifest (GstAdaptiveDemux * demux, GstBuffer * buffer)
+gst_mss_demux_update_manifest_data (GstAdaptiveDemux * demux,
+    GstBuffer * buffer)
 {
   GstMssDemux *mssdemux = GST_MSS_DEMUX_CAST (demux);
 
index 7254e4d..e92e3da 100644 (file)
@@ -724,7 +724,8 @@ _gst_mss_stream_audio_caps_from_qualitylevel_xml (GstMssStreamQuality * q)
     gst_structure_set (structure, "rate", G_TYPE_INT, rate, NULL);
 
   if (q->bitrate)
-    gst_structure_set (structure, "bitrate", G_TYPE_INT, (int) q->bitrate, NULL);
+    gst_structure_set (structure, "bitrate", G_TYPE_INT, (int) q->bitrate,
+        NULL);
 
   if (codec_data)
     gst_structure_set (structure, "codec_data", GST_TYPE_BUFFER, codec_data,
index 4b356f8..033a434 100644 (file)
@@ -106,7 +106,7 @@ enum GstAdaptiveDemuxFlowReturn
 struct _GstAdaptiveDemuxPrivate
 {
   GstAdapter *input_adapter;
-  GstBuffer *manifest_buffer;
+  gboolean have_manifest;
 
   GstUriDownloader *downloader;
 
@@ -167,6 +167,8 @@ gst_adaptive_demux_stream_get_fragment_waiting_time (GstAdaptiveDemux * demux,
     GstAdaptiveDemuxStream * stream);
 static GstFlowReturn gst_adaptive_demux_update_manifest (GstAdaptiveDemux *
     demux);
+static GstFlowReturn
+gst_adaptive_demux_update_manifest_default (GstAdaptiveDemux * demux);
 static gboolean gst_adaptive_demux_has_next_period (GstAdaptiveDemux * demux);
 static void gst_adaptive_demux_advance_period (GstAdaptiveDemux * demux);
 
@@ -314,6 +316,7 @@ gst_adaptive_demux_class_init (GstAdaptiveDemuxClass * klass)
 
   klass->data_received = gst_adaptive_demux_stream_data_received_default;
   klass->finish_fragment = gst_adaptive_demux_stream_finish_fragment_default;
+  klass->update_manifest = gst_adaptive_demux_update_manifest_default;
 }
 
 static void
@@ -419,6 +422,7 @@ gst_adaptive_demux_sink_event (GstPad * pad, GstObject * parent,
       gboolean query_res;
       gboolean ret = TRUE;
       gsize available;
+      GstBuffer *manifest_buffer;
 
       demux_class = GST_ADAPTIVE_DEMUX_GET_CLASS (demux);
       available = gst_adapter_available (demux->priv->input_adapter);
@@ -460,16 +464,19 @@ gst_adaptive_demux_sink_event (GstPad * pad, GstObject * parent,
       gst_query_unref (query);
 
       /* Let the subclass parse the manifest */
-      demux->priv->manifest_buffer =
+      manifest_buffer =
           gst_adapter_take_buffer (demux->priv->input_adapter, available);
-      if (!demux_class->process_manifest (demux, demux->priv->manifest_buffer)) {
+      if (!demux_class->process_manifest (demux, manifest_buffer)) {
         /* In most cases, this will happen if we set a wrong url in the
          * source element and we have received the 404 HTML response instead of
          * the manifest */
         GST_ELEMENT_ERROR (demux, STREAM, DECODE, ("Invalid manifest."),
             (NULL));
         ret = FALSE;
+      } else {
+        demux->priv->have_manifest = TRUE;
       }
+      gst_buffer_unref (manifest_buffer);
 
       gst_element_post_message (GST_ELEMENT_CAST (demux),
           gst_message_new_element (GST_OBJECT_CAST (demux),
@@ -578,10 +585,7 @@ gst_adaptive_demux_reset (GstAdaptiveDemux * demux)
   demux->manifest_base_uri = NULL;
 
   gst_adapter_clear (demux->priv->input_adapter);
-  if (demux->priv->manifest_buffer) {
-    gst_buffer_unref (demux->priv->manifest_buffer);
-    demux->priv->manifest_buffer = NULL;
-  }
+  demux->priv->have_manifest = FALSE;
 
   gst_segment_init (&demux->segment, GST_FORMAT_TIME);
 
@@ -1101,7 +1105,7 @@ gst_adaptive_demux_src_query (GstPad * pad, GstObject * parent,
 
       GST_MANIFEST_LOCK (demux);
       gst_query_parse_duration (query, &fmt, NULL);
-      if (fmt == GST_FORMAT_TIME && demux->priv->manifest_buffer != NULL) {
+      if (fmt == GST_FORMAT_TIME && demux->priv->have_manifest) {
         duration = demux_class->get_duration (demux);
 
         if (GST_CLOCK_TIME_IS_VALID (duration) && duration > 0) {
@@ -1118,7 +1122,7 @@ gst_adaptive_demux_src_query (GstPad * pad, GstObject * parent,
       gboolean live = FALSE;
 
       GST_MANIFEST_LOCK (demux);
-      live = demux->priv->manifest_buffer && gst_adaptive_demux_is_live (demux);
+      live = demux->priv->have_manifest && gst_adaptive_demux_is_live (demux);
       GST_MANIFEST_UNLOCK (demux);
 
       gst_query_set_latency (query, live, 0, -1);
@@ -1131,7 +1135,7 @@ gst_adaptive_demux_src_query (GstPad * pad, GstObject * parent,
       gint64 start = 0;
 
       GST_MANIFEST_LOCK (demux);
-      if (demux->priv->manifest_buffer == NULL) {
+      if (demux->priv->have_manifest) {
         GST_MANIFEST_UNLOCK (demux);
         return FALSE;           /* can't answer without manifest */
       }
@@ -2470,7 +2474,7 @@ gst_adaptive_demux_stream_get_fragment_waiting_time (GstAdaptiveDemux *
 }
 
 static GstFlowReturn
-gst_adaptive_demux_update_manifest (GstAdaptiveDemux * demux)
+gst_adaptive_demux_update_manifest_default (GstAdaptiveDemux * demux)
 {
   GstAdaptiveDemuxClass *klass = GST_ADAPTIVE_DEMUX_GET_CLASS (demux);
   GstFragment *download;
@@ -2493,33 +2497,42 @@ gst_adaptive_demux_update_manifest (GstAdaptiveDemux * demux)
 
     buffer = gst_fragment_get_buffer (download);
     g_object_unref (download);
-    ret = klass->update_manifest (demux, buffer);
-    if (ret == GST_FLOW_OK) {
-      GstClockTime duration;
-      gst_buffer_unref (demux->priv->manifest_buffer);
-      demux->priv->manifest_buffer = buffer;
+    ret = klass->update_manifest_data (demux, buffer);
+    gst_buffer_unref (buffer);
+    GST_MANIFEST_UNLOCK (demux);
+    /* FIXME: Should the manifest uri vars be reverted to original
+     * values if updating fails? */
+  } else {
+    ret = GST_FLOW_NOT_LINKED;
+  }
 
-      /* Send an updated duration message */
-      duration = klass->get_duration (demux);
+  return ret;
+}
 
-      GST_MANIFEST_UNLOCK (demux);
-      if (duration != GST_CLOCK_TIME_NONE) {
-        GST_DEBUG_OBJECT (demux,
-            "Sending duration message : %" GST_TIME_FORMAT,
-            GST_TIME_ARGS (duration));
-        gst_element_post_message (GST_ELEMENT (demux),
-            gst_message_new_duration_changed (GST_OBJECT (demux)));
-      } else {
-        GST_DEBUG_OBJECT (demux,
-            "Duration unknown, can not send the duration message");
-      }
+static GstFlowReturn
+gst_adaptive_demux_update_manifest (GstAdaptiveDemux * demux)
+{
+  GstAdaptiveDemuxClass *klass = GST_ADAPTIVE_DEMUX_GET_CLASS (demux);
+  GstFlowReturn ret;
+
+  ret = klass->update_manifest (demux);
+
+  if (ret == GST_FLOW_OK) {
+    GstClockTime duration;
+    GST_MANIFEST_LOCK (demux);
+    /* Send an updated duration message */
+    duration = klass->get_duration (demux);
+    GST_MANIFEST_UNLOCK (demux);
+    if (duration != GST_CLOCK_TIME_NONE) {
+      GST_DEBUG_OBJECT (demux,
+          "Sending duration message : %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (duration));
+      gst_element_post_message (GST_ELEMENT (demux),
+          gst_message_new_duration_changed (GST_OBJECT (demux)));
     } else {
-      GST_MANIFEST_UNLOCK (demux);
-      gst_buffer_unref (buffer);
-      /* Should the manifest uri vars be reverted to original values? */
+      GST_DEBUG_OBJECT (demux,
+          "Duration unknown, can not send the duration message");
     }
-  } else {
-    ret = GST_FLOW_NOT_LINKED;
   }
 
   return ret;
index ca47418..9303a84 100644 (file)
@@ -237,9 +237,23 @@ struct _GstAdaptiveDemuxClass
    * Returns: the update interval in microseconds
    */
   gint64        (*get_manifest_update_interval) (GstAdaptiveDemux * demux);
+
   /**
    * update_manifest:
    * @demux: #GstAdaptiveDemux
+   *
+   * During live streaming, this will be called for the subclass to update its
+   * manifest with the new version. By default it fetches the manifest URI
+   * and passes it to GstAdaptiveDemux::update_manifest_data().
+   *
+   * Returns: #GST_FLOW_OK is all succeeded, #GST_FLOW_EOS if the stream ended
+   *          or #GST_FLOW_ERROR if an error happened
+   */
+  GstFlowReturn (*update_manifest) (GstAdaptiveDemux * demux);
+
+  /**
+   * update_manifest_data:
+   * @demux: #GstAdaptiveDemux
    * @buf: Downloaded manifest data
    *
    * During live streaming, this will be called for the subclass to update its
@@ -248,7 +262,7 @@ struct _GstAdaptiveDemuxClass
    * Returns: #GST_FLOW_OK is all succeeded, #GST_FLOW_EOS if the stream ended
    *          or #GST_FLOW_ERROR if an error happened
    */
-  GstFlowReturn (*update_manifest) (GstAdaptiveDemux * demux, GstBuffer * buf);
+  GstFlowReturn (*update_manifest_data) (GstAdaptiveDemux * demux, GstBuffer * buf);
 
   gboolean      (*is_live)          (GstAdaptiveDemux * demux);
   GstClockTime  (*get_duration)     (GstAdaptiveDemux * demux);