hlsdemux: Always use the redirect target to resolve relative URIs
authorSebastian Dröge <sebastian@centricular.com>
Wed, 28 May 2014 08:19:40 +0000 (10:19 +0200)
committerSebastian Dröge <sebastian@centricular.com>
Wed, 28 May 2014 08:19:40 +0000 (10:19 +0200)
But redownload the playlists from the original URI if it's not
a permanent redirect.

ext/hls/gsthlsdemux.c
ext/hls/m3u8.c
ext/hls/m3u8.h

index 3e21f5932b92f3179aaea6069d281bb9a2d1f067..2b8880bd8f7841f33e73c9dcac90ee01381ecd5b 100644 (file)
@@ -105,7 +105,7 @@ static gboolean gst_hls_demux_update_playlist (GstHLSDemux * demux,
     gboolean update, GError ** err);
 static void gst_hls_demux_reset (GstHLSDemux * demux, gboolean dispose);
 static gboolean gst_hls_demux_set_location (GstHLSDemux * demux,
-    const gchar * uri);
+    const gchar * uri, const gchar * base_uri);
 static gchar *gst_hls_src_buf_to_utf8_playlist (GstBuffer * buf);
 
 static gboolean gst_hls_demux_change_playlist (GstHLSDemux * demux,
@@ -572,7 +572,6 @@ gst_hls_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
   GstHLSDemux *demux;
   GstQuery *query;
   gboolean ret;
-  gchar *uri;
 
   demux = GST_HLS_DEMUX (parent);
 
@@ -592,18 +591,19 @@ gst_hls_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
       ret = gst_pad_peer_query (demux->sinkpad, query);
       if (ret) {
         gboolean permanent;
+        gchar *uri, *redirect_uri;
 
-        gst_query_parse_uri_redirection (query, &uri);
+        gst_query_parse_uri (query, &uri);
+        gst_query_parse_uri_redirection (query, &redirect_uri);
         gst_query_parse_uri_redirection_permanent (query, &permanent);
 
-        /* Only use the redirect target for permanent redirects */
-        if (!permanent || uri == NULL) {
-          g_free (uri);
-          gst_query_parse_uri (query, &uri);
+        if (permanent) {
+          gst_hls_demux_set_location (demux, redirect_uri, redirect_uri);
+        } else {
+          gst_hls_demux_set_location (demux, uri, redirect_uri);
         }
-
-        gst_hls_demux_set_location (demux, uri);
         g_free (uri);
+        g_free (redirect_uri);
       }
       gst_query_unref (query);
 
@@ -1291,7 +1291,7 @@ gst_hls_demux_reset (GstHLSDemux * demux, gboolean dispose)
   }
 
   if (!dispose) {
-    demux->client = gst_m3u8_client_new ("");
+    demux->client = gst_m3u8_client_new ("", NULL);
   }
 
   gst_segment_init (&demux->segment, GST_FORMAT_TIME);
@@ -1324,12 +1324,14 @@ gst_hls_demux_reset (GstHLSDemux * demux, gboolean dispose)
 }
 
 static gboolean
-gst_hls_demux_set_location (GstHLSDemux * demux, const gchar * uri)
+gst_hls_demux_set_location (GstHLSDemux * demux, const gchar * uri,
+    const gchar * base_uri)
 {
   if (demux->client)
     gst_m3u8_client_free (demux->client);
-  demux->client = gst_m3u8_client_new (uri);
-  GST_INFO_OBJECT (demux, "Changed location: %s", uri);
+  demux->client = gst_m3u8_client_new (uri, base_uri);
+  GST_INFO_OBJECT (demux, "Changed location: %s (base uri: %s)", uri,
+      GST_STR_NULL (base_uri));
   return TRUE;
 }
 
@@ -1489,7 +1491,6 @@ gst_hls_demux_update_playlist (GstHLSDemux * demux, gboolean update,
   GstBuffer *buf;
   gchar *playlist;
   gboolean updated = FALSE;
-
   const gchar *uri = gst_m3u8_client_get_current_uri (demux->client);
 
   download =
@@ -1499,6 +1500,19 @@ gst_hls_demux_update_playlist (GstHLSDemux * demux, gboolean update,
   if (download == NULL)
     return FALSE;
 
+  /* Set the base URI of the playlist to the redirect target if any */
+  GST_M3U8_CLIENT_LOCK (demux->client);
+  g_free (demux->client->current->uri);
+  g_free (demux->client->current->base_uri);
+  if (download->redirect_permanent) {
+    demux->client->current->uri = g_strdup (download->redirect_uri);
+    demux->client->current->base_uri = NULL;
+  } else {
+    demux->client->current->uri = g_strdup (download->uri);
+    demux->client->current->base_uri = g_strdup (download->redirect_uri);
+  }
+  GST_M3U8_CLIENT_UNLOCK (demux->client);
+
   buf = gst_fragment_get_buffer (download);
   playlist = gst_hls_src_buf_to_utf8_playlist (buf);
   g_object_unref (download);
index d129723e7a0838f0f63d4729534d44796e7207da..618d52d1b0975624a5219fbdba2a92fc56c215ed 100644 (file)
@@ -50,13 +50,15 @@ gst_m3u8_new (void)
 }
 
 static void
-gst_m3u8_set_uri (GstM3U8 * self, gchar * uri)
+gst_m3u8_set_uri (GstM3U8 * self, gchar * uri, gchar * base_uri)
 {
   g_return_if_fail (self != NULL);
 
-  if (self->uri)
-    g_free (self->uri);
+  g_free (self->uri);
   self->uri = uri;
+
+  g_free (self->base_uri);
+  self->base_uri = base_uri;
 }
 
 static void
@@ -65,6 +67,7 @@ gst_m3u8_free (GstM3U8 * self)
   g_return_if_fail (self != NULL);
 
   g_free (self->uri);
+  g_free (self->base_uri);
   g_free (self->codecs);
   g_free (self->key);
 
@@ -322,7 +325,7 @@ gst_m3u8_update (GstM3U8 * self, gchar * data, gboolean * updated)
         goto next_line;
       }
 
-      data = uri_join (self->uri, data);
+      data = uri_join (self->base_uri ? self->base_uri : self->uri, data);
       if (data == NULL)
         goto next_line;
 
@@ -333,7 +336,7 @@ gst_m3u8_update (GstM3U8 * self, gchar * data, gboolean * updated)
           gst_m3u8_free (list);
           g_free (data);
         } else {
-          gst_m3u8_set_uri (list, data);
+          gst_m3u8_set_uri (list, data, NULL);
           self->lists = g_list_append (self->lists, list);
         }
         list = NULL;
@@ -427,12 +430,12 @@ gst_m3u8_update (GstM3U8 * self, gchar * data, gboolean * updated)
           if (uri[0] == '"')
             uri += 1;
 
-          uri = uri_join (self->uri, uri);
+          uri = uri_join (self->base_uri ? self->base_uri : self->uri, uri);
           g_free (urip);
 
           if (uri == NULL)
             continue;
-          gst_m3u8_set_uri (new_list, uri);
+          gst_m3u8_set_uri (new_list, uri, NULL);
         }
       }
 
@@ -484,7 +487,8 @@ gst_m3u8_update (GstM3U8 * self, gchar * data, gboolean * updated)
           if (key[0] == '"')
             key += 1;
 
-          self->key = uri_join (self->uri, key);
+          self->key =
+              uri_join (self->base_uri ? self->base_uri : self->uri, key);
           g_free (keyp);
         } else if (g_str_equal (a, "IV")) {
           gchar *ivp = v;
@@ -591,7 +595,7 @@ gst_m3u8_update (GstM3U8 * self, gchar * data, gboolean * updated)
 }
 
 GstM3U8Client *
-gst_m3u8_client_new (const gchar * uri)
+gst_m3u8_client_new (const gchar * uri, const gchar * base_uri)
 {
   GstM3U8Client *client;
 
@@ -604,7 +608,7 @@ gst_m3u8_client_new (const gchar * uri)
   client->sequence_position = 0;
   client->update_failed_count = 0;
   g_mutex_init (&client->lock);
-  gst_m3u8_set_uri (client->main, g_strdup (uri));
+  gst_m3u8_set_uri (client->main, g_strdup (uri), g_strdup (base_uri));
 
   return client;
 }
index 096287a6044b3f4df8e82a274bff1779efcd724f..d49287a0628213eec083ca890f77279c3e47632d 100644 (file)
@@ -37,7 +37,9 @@ typedef struct _GstM3U8Client GstM3U8Client;
 
 struct _GstM3U8
 {
-  gchar *uri;
+  gchar *uri;                   /* actually downloaded URI */
+  gchar *base_uri;              /* URI to use as base for resolving relative URIs.
+                                 * This will be different to uri in case of redirects */
 
   gboolean endlist;             /* if ENDLIST has been reached */
   gint version;                 /* last EXT-X-VERSION */
@@ -85,7 +87,7 @@ struct _GstM3U8Client
 };
 
 
-GstM3U8Client *gst_m3u8_client_new (const gchar * uri);
+GstM3U8Client *gst_m3u8_client_new (const gchar * uri, const gchar * base_uri);
 void gst_m3u8_client_free (GstM3U8Client * client);
 gboolean gst_m3u8_client_update (GstM3U8Client * client, gchar * data);
 void gst_m3u8_client_set_current (GstM3U8Client * client, GstM3U8 * m3u8);