dashdemux: each fragment can have its own index
authorThiago Santos <thiago.sousa.santos@collabora.com>
Mon, 1 Jul 2013 20:50:37 +0000 (17:50 -0300)
committerThiago Santos <thiago.sousa.santos@collabora.com>
Mon, 1 Jul 2013 21:52:08 +0000 (18:52 -0300)
Return index URI/range to dashdemux from the mpdparser to be able
to download and deliver them downstream for playback.

ext/dash/gstdashdemux.c
ext/dash/gstmpdparser.c
ext/dash/gstmpdparser.h

index a56896e..0efd04a 100644 (file)
@@ -1854,10 +1854,6 @@ gst_dash_demux_get_next_fragment (GstDashDemux * demux)
   GstActiveStream *active_stream;
   GstFragment *download;
   GstBuffer *header_buffer;
-  gchar *next_fragment_uri;
-  GstClockTime duration;
-  GstClockTime timestamp;
-  gboolean discont;
   GTimeVal now;
   GTimeVal start;
   GstClockTime diff;
@@ -1916,33 +1912,35 @@ gst_dash_demux_get_next_fragment (GstDashDemux * demux)
   if (selected_stream) {
     guint stream_idx = selected_stream->index;
     GstBuffer *buffer;
-    gint64 range_start, range_end;
+    GstMediaFragmentInfo fragment;
 
     if (gst_mpd_client_get_next_fragment (demux->client,
-            stream_idx, &discont, &next_fragment_uri, &range_start, &range_end,
-            &duration, &timestamp)) {
+            stream_idx, &fragment)) {
 
       g_get_current_time (&start);
       GST_INFO_OBJECT (demux, "Next fragment for stream #%i", stream_idx);
       GST_INFO_OBJECT (demux,
           "Fetching next fragment %s ts:%" GST_TIME_FORMAT " dur:%"
           GST_TIME_FORMAT " Range:%" G_GINT64_FORMAT "-%" G_GINT64_FORMAT,
-          next_fragment_uri, GST_TIME_ARGS (timestamp),
-          GST_TIME_ARGS (duration), range_start, range_end);
+          fragment.uri, GST_TIME_ARGS (fragment.timestamp),
+          GST_TIME_ARGS (fragment.duration),
+          fragment.range_start, fragment.range_end);
 
       /* got a fragment to fetch, no end of period */
       end_of_period = FALSE;
 
       download = gst_uri_downloader_fetch_uri_with_range (demux->downloader,
-          next_fragment_uri, range_start, range_end);
-      g_free (next_fragment_uri);
+          fragment.uri, fragment.range_start, fragment.range_end);
 
-      if (download == NULL)
+      if (download == NULL) {
+        gst_media_fragment_info_clear (&fragment);
         return FALSE;
+      }
 
       active_stream =
           gst_mpdparser_get_active_stream_by_index (demux->client, stream_idx);
       if (active_stream == NULL) {
+        gst_media_fragment_info_clear (&fragment);
         g_object_unref (download);
         return FALSE;
       }
@@ -1950,6 +1948,30 @@ gst_dash_demux_get_next_fragment (GstDashDemux * demux)
       buffer = gst_fragment_get_buffer (download);
       g_object_unref (download);
 
+      /* it is possible to have an index per fragment, so check and download */
+      if (fragment.index_uri || fragment.index_range_start
+          || fragment.index_range_end != -1) {
+        const gchar *uri = fragment.index_uri;
+        GstBuffer *index_buffer;
+
+        if (!uri)               /* fallback to default media uri */
+          uri = fragment.uri;
+
+        GST_DEBUG_OBJECT (demux,
+            "Fragment index download: %s %" G_GINT64_FORMAT "-%"
+            G_GINT64_FORMAT, uri, fragment.index_range_start,
+            fragment.index_range_end);
+        download =
+            gst_uri_downloader_fetch_uri_with_range (demux->downloader, uri,
+            fragment.index_range_start, fragment.index_range_end);
+        if (download) {
+          index_buffer = gst_fragment_get_buffer (download);
+          if (index_buffer)
+            buffer = gst_buffer_append (index_buffer, buffer);
+          g_object_unref (download);
+        }
+      }
+
       if (selected_stream->need_header) {
         /* We need to fetch a new header */
         if ((header_buffer =
@@ -1964,11 +1986,13 @@ gst_dash_demux_get_next_fragment (GstDashDemux * demux)
 
       buffer = gst_buffer_make_writable (buffer);
 
-      GST_BUFFER_TIMESTAMP (buffer) = timestamp;
-      GST_BUFFER_DURATION (buffer) = duration;
+      GST_BUFFER_TIMESTAMP (buffer) = fragment.timestamp;
+      GST_BUFFER_DURATION (buffer) = fragment.duration;
       GST_BUFFER_OFFSET (buffer) =
           gst_mpd_client_get_segment_index (active_stream) - 1;
 
+      gst_media_fragment_info_clear (&fragment);
+
       gst_dash_demux_stream_push_data (selected_stream, buffer);
       selected_stream->has_data_queued = TRUE;
       size_buffer += gst_buffer_get_size (buffer);
index 92eaa11..05fed03 100644 (file)
@@ -3281,13 +3281,12 @@ gst_mpd_client_get_next_fragment_timestamp (GstMpdClient * client,
 
 gboolean
 gst_mpd_client_get_next_fragment (GstMpdClient * client,
-    guint indexStream, gboolean * discontinuity, gchar ** uri,
-    gint64 * range_start, gint64 * range_end,
-    GstClockTime * duration, GstClockTime * timestamp)
+    guint indexStream, GstMediaFragmentInfo * fragment)
 {
   GstActiveStream *stream = NULL;
   GstMediaSegment *currentChunk;
   gchar *mediaURL = NULL;
+  gchar *indexURL = NULL;
   guint segment_idx;
 
   /* select stream */
@@ -3296,7 +3295,6 @@ gst_mpd_client_get_next_fragment (GstMpdClient * client,
   stream = g_list_nth_data (client->active_streams, indexStream);
   g_return_val_if_fail (stream != NULL, FALSE);
   g_return_val_if_fail (stream->cur_representation != NULL, FALSE);
-  g_return_val_if_fail (discontinuity != NULL, FALSE);
 
   GST_MPD_CLIENT_LOCK (client);
   segment_idx = gst_mpd_client_get_segment_index (stream);
@@ -3311,38 +3309,83 @@ gst_mpd_client_get_next_fragment (GstMpdClient * client,
 
   GST_DEBUG ("currentChunk->SegmentURL = %p", currentChunk->SegmentURL);
   if (currentChunk->SegmentURL != NULL) {
-    mediaURL = g_strdup (gst_mpdparser_get_mediaURL (stream, currentChunk->SegmentURL));
+    mediaURL =
+        g_strdup (gst_mpdparser_get_mediaURL (stream,
+            currentChunk->SegmentURL));
+    indexURL = currentChunk->SegmentURL->index;
   } else if (stream->cur_seg_template != NULL) {
     mediaURL =
         gst_mpdparser_build_URL_from_template (stream->cur_seg_template->media,
         stream->cur_representation->id, currentChunk->number,
         stream->cur_representation->bandwidth, currentChunk->start);
+    if (stream->cur_seg_template->index) {
+      indexURL =
+          gst_mpdparser_build_URL_from_template (stream->cur_seg_template->
+          index, stream->cur_representation->id, currentChunk->number,
+          stream->cur_representation->bandwidth, currentChunk->start);
+    }
   }
   GST_DEBUG ("mediaURL = %s", mediaURL);
-
-  *timestamp = currentChunk->start_time;
-  *duration = currentChunk->duration;
-  *discontinuity = segment_idx != currentChunk->number;
-  *range_start = 0;
-  *range_end = -1;
-  if (currentChunk->SegmentURL && currentChunk->SegmentURL->mediaRange) {
-    *range_start = currentChunk->SegmentURL->mediaRange->first_byte_pos;
-    *range_end = currentChunk->SegmentURL->mediaRange->last_byte_pos;
+  GST_DEBUG ("indexURL = %s", indexURL);
+
+  fragment->timestamp = currentChunk->start_time;
+  fragment->duration = currentChunk->duration;
+  fragment->discontinuity = segment_idx != currentChunk->number;
+  fragment->range_start = 0;
+  fragment->range_end = -1;
+  fragment->index_uri = NULL;
+  fragment->index_range_start = 0;
+  fragment->index_range_end = -1;
+  if (currentChunk->SegmentURL) {
+    if (currentChunk->SegmentURL->mediaRange) {
+      fragment->range_start =
+          currentChunk->SegmentURL->mediaRange->first_byte_pos;
+      fragment->range_end = currentChunk->SegmentURL->mediaRange->last_byte_pos;
+    }
+    if (currentChunk->SegmentURL->indexRange) {
+      fragment->index_range_start =
+          currentChunk->SegmentURL->indexRange->first_byte_pos;
+      fragment->index_range_end =
+          currentChunk->SegmentURL->indexRange->last_byte_pos;
+    }
   }
 
   if (mediaURL == NULL) {
     /* single segment with URL encoded in the baseURL syntax element */
-    *uri = g_strdup (stream->baseURL);
+    fragment->uri = g_strdup (stream->baseURL);
   } else if (strncmp (mediaURL, "http://", 7) != 0) {
-    *uri = g_strconcat (stream->baseURL, mediaURL, stream->queryURL, NULL);
+    fragment->uri =
+        g_strconcat (stream->baseURL, mediaURL, stream->queryURL, NULL);
   } else {
-    *uri = g_strconcat (mediaURL, stream->queryURL, NULL);
+    fragment->uri = g_strconcat (mediaURL, stream->queryURL, NULL);
   }
   g_free (mediaURL);
+
+  if (indexURL != NULL) {
+    if (strncmp (indexURL, "http://", 7) != 0) {
+      fragment->index_uri =
+          g_strconcat (stream->baseURL, indexURL, stream->queryURL, NULL);
+    } else {
+      fragment->index_uri = g_strconcat (indexURL, stream->queryURL, NULL);
+    }
+    g_free (indexURL);
+  } else if (fragment->index_range_start || fragment->index_range_end != -1) {
+    /* index has no specific URL but has a range, we should only use this if
+     * the media also has a range, otherwise we are serving some data twice
+     * (in the media fragment and again in the index) */
+    if (!(fragment->range_start || fragment->range_end != -1)) {
+      GST_WARNING ("Ignoring index ranges because there isn't a media range "
+          "and URIs would be the same");
+      /* removing index information */
+      fragment->index_range_start = 0;
+      fragment->index_range_end = -1;
+    }
+  }
+
   gst_mpd_client_set_segment_index (stream, segment_idx + 1);
   GST_MPD_CLIENT_UNLOCK (client);
 
-  GST_DEBUG ("Loading chunk with URL %s", *uri);
+  GST_DEBUG ("Loading chunk with URL %s", fragment->uri);
 
   return TRUE;
 }
@@ -3369,8 +3412,8 @@ gst_mpd_client_get_next_header (GstMpdClient * client, gchar ** uri,
   *uri = NULL;
   if (stream->cur_segment_base && stream->cur_segment_base->Initialization) {
     *uri =
-        g_strdup (gst_mpdparser_get_initializationURL (stream, stream->cur_segment_base->
-        Initialization));
+        g_strdup (gst_mpdparser_get_initializationURL (stream,
+            stream->cur_segment_base->Initialization));
     if (stream->cur_segment_base->Initialization->range) {
       *range_start =
           stream->cur_segment_base->Initialization->range->first_byte_pos;
@@ -3419,12 +3462,10 @@ gst_mpd_client_get_next_header_index (GstMpdClient * client, gchar ** uri,
   *uri = NULL;
   if (stream->cur_segment_base && stream->cur_segment_base->indexRange) {
     *uri =
-        g_strdup (gst_mpdparser_get_initializationURL (stream, stream->cur_segment_base->
-        Initialization));
-    *range_start =
-        stream->cur_segment_base->indexRange->first_byte_pos;
-    *range_end =
-        stream->cur_segment_base->indexRange->last_byte_pos;
+        g_strdup (gst_mpdparser_get_initializationURL (stream,
+            stream->cur_segment_base->Initialization));
+    *range_start = stream->cur_segment_base->indexRange->first_byte_pos;
+    *range_end = stream->cur_segment_base->indexRange->last_byte_pos;
   } else if (stream->cur_seg_template) {
     const gchar *initialization = NULL;
     if (stream->cur_seg_template->index) {
@@ -3812,3 +3853,10 @@ gst_mpdparser_get_list_and_nb_of_audio_language (GstMpdClient * client,
 
   return nb_adapatation_set;
 }
+
+void
+gst_media_fragment_info_clear (GstMediaFragmentInfo * fragment)
+{
+  g_free (fragment->uri);
+  g_free (fragment->index_uri);
+}
index f7582f9..64a434e 100644 (file)
@@ -34,6 +34,7 @@ G_BEGIN_DECLS
 typedef struct _GstMpdClient              GstMpdClient;
 typedef struct _GstActiveStream           GstActiveStream;
 typedef struct _GstStreamPeriod           GstStreamPeriod;
+typedef struct _GstMediaFragmentInfo      GstMediaFragmentInfo;
 typedef struct _GstMediaSegment           GstMediaSegment;
 typedef struct _GstMPDNode                GstMPDNode;
 typedef struct _GstPeriodNode             GstPeriodNode;
@@ -417,6 +418,21 @@ struct _GstMediaSegment
   GstClockTime duration;                      /* segment duration */
 };
 
+struct _GstMediaFragmentInfo
+{
+  gchar *uri;
+  gint64 range_start;
+  gint64 range_end;
+
+  gchar *index_uri;
+  gint64 index_range_start;
+  gint64 index_range_end;
+
+  gboolean discontinuity;
+  GstClockTime timestamp;
+  GstClockTime duration;
+};
+
 /**
  * GstActiveStream:
  *
@@ -460,6 +476,7 @@ struct _GstMpdClient
 GstMpdClient *gst_mpd_client_new (void);
 void gst_active_streams_free (GstMpdClient * client);
 void gst_mpd_client_free (GstMpdClient * client);
+void gst_media_fragment_info_clear (GstMediaFragmentInfo * fragment);
 
 /* MPD file parsing */
 gboolean gst_mpd_parse (GstMpdClient *client, const gchar *data, gint size);
@@ -473,7 +490,7 @@ GstClockTime gst_mpd_client_get_next_fragment_duration (GstMpdClient * client);
 GstClockTime gst_mpd_client_get_media_presentation_duration (GstMpdClient *client);
 gboolean gst_mpd_client_get_last_fragment_timestamp (GstMpdClient * client, guint stream_idx, GstClockTime * ts);
 gboolean gst_mpd_client_get_next_fragment_timestamp (GstMpdClient * client, guint stream_idx, GstClockTime * ts);
-gboolean gst_mpd_client_get_next_fragment (GstMpdClient *client, guint indexStream, gboolean *discontinuity, gchar **uri, gint64 * range_start, gint64 * range_end, GstClockTime *duration, GstClockTime *timestamp);
+gboolean gst_mpd_client_get_next_fragment (GstMpdClient *client, guint indexStream, GstMediaFragmentInfo * fragment);
 gboolean gst_mpd_client_get_next_header (GstMpdClient *client, gchar **uri, guint stream_idx, gint64 * range_start, gint64 * range_end);
 gboolean gst_mpd_client_get_next_header_index (GstMpdClient *client, gchar **uri, guint stream_idx, gint64 * range_start, gint64 * range_end);
 gboolean gst_mpd_client_is_live (GstMpdClient * client);