dashdemux: reworked the API to retrieve fragment timestamp, fragment duration and...
authorGianluca Gennari <gennarone@gmail.com>
Wed, 24 Oct 2012 14:30:01 +0000 (16:30 +0200)
committerThiago Santos <thiago.sousa.santos@collabora.com>
Wed, 8 May 2013 21:14:25 +0000 (18:14 -0300)
This was necessary to support variable-duration Fragments.

in the new API:
- gst_mpd_client_get_current_position returns the timestamp of the NEXT fragment to download;
- gst_mpd_client_get_next_fragment_duration returns the duration of the next fragment to download;
- gst_mpd_client_get_media_presentation_duration returns the mediaPresentationDuration from the MPD file;

also there is a new internal parser function:
- gst_mpd_client_get_segment_duration extracts the constant segment duration from the MPD file
(only used when there is no SegmentTimeline syntax element in the current representation)

In gst_mpd_client_get_next_fragment, we set the timestamp/duration of the fragment just downloaded
copying the values from the corresponding GstMediaSegment.

TODO: rework SEEKING to support seeking across different Periods.

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

index 38f8d8b..f7a7e47 100644 (file)
@@ -507,6 +507,7 @@ gst_dash_demux_src_event (GstPad * pad, GstEvent * event)
       GST_MPD_CLIENT_LOCK (demux->client);
       stream = gst_mpdparser_get_active_stream_by_index (demux->client, 0);
 
+      /* FIXME: support seeking across periods */
       current_pos = 0;
       target_pos = (GstClockTime) start;
       for (walk = stream->segments; walk; walk = walk->next) {
@@ -551,6 +552,7 @@ gst_dash_demux_src_event (GstPad * pad, GstEvent * event)
 
       GST_MPD_CLIENT_LOCK (demux->client);
       GST_DEBUG_OBJECT (demux, "Seeking to sequence %d", current_sequence);
+      /* FIXME: support seeking across periods */
       stream_idx = 0;
       /* Update the current sequence on all streams */
       while (stream_idx < nb_active_stream) {
@@ -562,7 +564,7 @@ gst_dash_demux_src_event (GstPad * pad, GstEvent * event)
         stream_idx++;
       }
       /* Calculate offset in the next fragment */
-      gst_mpd_client_get_current_position (demux->client, &demux->position);
+      demux->position = gst_mpd_client_get_current_position (demux->client);
       demux->position_shift = start - demux->position;
       demux->need_segment = TRUE;
       GST_MPD_CLIENT_UNLOCK (demux->client);
@@ -685,7 +687,7 @@ gst_dash_demux_sink_event (GstPad * pad, GstEvent * event)
         return FALSE;
       /* Send duration message */
       if (!gst_mpd_client_is_live (demux->client)) {
-        GstClockTime duration = gst_mpd_client_get_duration (demux->client);
+        GstClockTime duration = gst_mpd_client_get_media_presentation_duration (demux->client);
 
         if (duration != GST_CLOCK_TIME_NONE) {
           GST_DEBUG_OBJECT (demux, "Sending duration message : %" GST_TIME_FORMAT,
@@ -731,7 +733,7 @@ gst_dash_demux_src_query (GstPad * pad, GstQuery * query)
 
       gst_query_parse_duration (query, &fmt, NULL);
       if (fmt == GST_FORMAT_TIME) {
-        duration = gst_mpd_client_get_duration (dashdemux->client);
+        duration = gst_mpd_client_get_media_presentation_duration (dashdemux->client);
         if (GST_CLOCK_TIME_IS_VALID (duration) && duration > 0) {
           gst_query_set_duration (query, GST_FORMAT_TIME, duration);
           ret = TRUE;
@@ -752,7 +754,7 @@ gst_dash_demux_src_query (GstPad * pad, GstQuery * query)
       if (fmt == GST_FORMAT_TIME) {
         GstClockTime duration;
 
-        duration = gst_mpd_client_get_duration (dashdemux->client);
+        duration = gst_mpd_client_get_media_presentation_duration (dashdemux->client);
         if (GST_CLOCK_TIME_IS_VALID (duration) && duration > 0)
           stop = duration;
 
@@ -1151,7 +1153,7 @@ gst_dash_demux_download_loop (GstDashDemux * demux)
    * buffering time */
   GstClockTime target_buffering_time =
       demux->min_buffering_time +
-      gst_mpd_client_get_target_duration (demux->client);
+      gst_mpd_client_get_next_fragment_duration (demux->client);
   if (demux->max_buffering_time > target_buffering_time)
     target_buffering_time = demux->max_buffering_time;
   if (!demux->end_of_manifest
index 75b02c5..e60800b 100644 (file)
@@ -83,6 +83,7 @@ static gchar *gst_mpdparser_get_initializationURL (GstURLType *InitializationURL
 static gchar *gst_mpdparser_build_URL_from_template (const gchar *url_template, const gchar *id, guint number, guint bandwidth, guint time);
 static gboolean gst_mpd_client_add_media_segment (GstActiveStream *stream, GstSegmentURLNode *url_node, guint number, guint start, GstClockTime start_time, GstClockTime duration);
 static const gchar *gst_mpdparser_mimetype_to_caps (const gchar * mimeType);
+static GstClockTime gst_mpd_client_get_segment_duration (GstMpdClient * client);
 
 /* Adaptation Set */
 static GstAdaptationSetNode *gst_mpdparser_get_first_adapt_set_with_mimeType (GList *AdaptationSets, const gchar *mimeType);
@@ -2331,6 +2332,40 @@ gst_mpdparser_parse_baseURL (GstMpdClient * client)
   return ret;
 }
 
+static GstClockTime
+gst_mpd_client_get_segment_duration (GstMpdClient * client)
+{
+  GstActiveStream *stream;
+  GstStreamPeriod *stream_period;
+  GstMultSegmentBaseType *base = NULL;
+  GstClockTime duration;
+  guint timescale;
+
+  stream = gst_mpdparser_get_active_stream_by_index (client, client->stream_idx);
+  g_return_val_if_fail (stream != NULL, GST_CLOCK_TIME_NONE);
+  stream_period = gst_mpdparser_get_stream_period (client);
+  g_return_val_if_fail (stream_period != NULL, GST_CLOCK_TIME_NONE);
+
+  if (stream->cur_segment_list) {
+    base = stream->cur_segment_list->MultSegBaseType;
+  } else if (stream->cur_seg_template) {
+    base = stream->cur_seg_template->MultSegBaseType;
+  }
+
+  if (base == NULL || base->SegBaseType == NULL) {
+    /* this may happen when we have a single segment */
+    duration = stream_period->duration;
+  } else {
+    duration = base->duration * GST_SECOND;
+    timescale = base->SegBaseType->timescale;
+
+    if (timescale > 1)
+      duration /= timescale;
+  }
+
+  return duration;
+}
+
 /*****************************/
 /******* API functions *******/
 /*****************************/
@@ -2504,7 +2539,10 @@ gst_mpd_client_setup_representation (GstMpdClient * client, GstActiveStream *str
   g_return_val_if_fail (stream_period->period != NULL, FALSE);
 
   PeriodStart = stream_period->start;
-  PeriodEnd = stream_period->start + stream_period->duration;
+  if (GST_CLOCK_TIME_IS_VALID (stream_period->duration))
+    PeriodEnd = stream_period->start + stream_period->duration;
+  else
+    PeriodEnd = GST_CLOCK_TIME_NONE;
 
   GST_LOG ("Building segment list for Period from %" GST_TIME_FORMAT " to %"
       GST_TIME_FORMAT, GST_TIME_ARGS (PeriodStart), GST_TIME_ARGS (PeriodEnd));
@@ -2573,7 +2611,9 @@ gst_mpd_client_setup_representation (GstMpdClient * client, GstActiveStream *str
           }
         }
       } else {
-        duration = gst_mpd_client_get_target_duration (client);
+        duration = gst_mpd_client_get_segment_duration (client);
+        if (!GST_CLOCK_TIME_IS_VALID (duration))
+          return FALSE;
 
         while (SegmentURL) {
           if (!gst_mpd_client_add_media_segment (stream, SegmentURL->data, i, 0, start_time, duration)) {
@@ -2638,7 +2678,9 @@ gst_mpd_client_setup_representation (GstMpdClient * client, GstActiveStream *str
           }
         }
       } else {
-        duration = gst_mpd_client_get_target_duration (client);
+        duration = gst_mpd_client_get_segment_duration (client);
+        if (!GST_CLOCK_TIME_IS_VALID (duration) || !GST_CLOCK_TIME_IS_VALID (PeriodEnd))
+          return FALSE;
 
         while (PeriodStart + start_time < PeriodEnd) {
           if (!gst_mpd_client_add_media_segment (stream, NULL, i, 0, start_time, duration)) {
@@ -2653,7 +2695,7 @@ gst_mpd_client_setup_representation (GstMpdClient * client, GstActiveStream *str
 
   /* check duration of last segment */
   last_media_segment = g_list_last (stream->segments)->data;
-  if (last_media_segment) {
+  if (last_media_segment && GST_CLOCK_TIME_IS_VALID (PeriodEnd)) {
     if (last_media_segment->start_time + last_media_segment->duration > PeriodEnd) {
       last_media_segment->duration = PeriodEnd - last_media_segment->start_time;
       GST_LOG ("Fixed duration of last segment: %" GST_TIME_FORMAT, GST_TIME_ARGS (last_media_segment->duration));
@@ -2908,12 +2950,9 @@ gst_mpd_client_get_next_fragment (GstMpdClient * client,
         stream->cur_representation->id, currentChunk->number, stream->cur_representation->bandwidth, currentChunk->start);
   }
 
-  gst_mpd_client_get_current_position (client, timestamp);
-  *duration = gst_mpd_client_get_target_duration (client);
-  //*timestamp = currentChunk->start_time;
-  //*duration = currentChunk->duration;
+  *timestamp = currentChunk->start_time;
+  *duration = currentChunk->duration;
   *discontinuity = stream->segment_idx != currentChunk->number;
-  stream->segment_idx += 1;
   if (mediaURL == NULL) {
     /* single segment with URL encoded in the baseURL syntax element */
     *uri = g_strdup (gst_mpdparser_get_baseURL (client));
@@ -2923,6 +2962,7 @@ gst_mpd_client_get_next_fragment (GstMpdClient * client,
   } else {
     *uri = mediaURL;
   }
+  stream->segment_idx += 1;
   GST_MPD_CLIENT_UNLOCK (client);
 
   GST_DEBUG ("Loading chunk with URL %s", *uri);
@@ -2965,24 +3005,37 @@ gst_mpd_client_get_next_header (GstMpdClient * client, const gchar **uri, guint
   return *uri == NULL ? FALSE : TRUE;
 }
 
-void
-gst_mpd_client_get_current_position (GstMpdClient * client,
-    GstClockTime * timestamp)
+GstClockTime
+gst_mpd_client_get_current_position (GstMpdClient * client)
 {
   GstActiveStream *stream;
-  GstClockTime duration;
+  GstMediaSegment *media_segment;
 
-  *timestamp = GST_CLOCK_TIME_NONE;
+  stream = g_list_nth_data (client->active_streams, client->stream_idx);
+  g_return_val_if_fail (stream != NULL, GST_CLOCK_TIME_NONE);
+
+  media_segment = g_list_nth_data (stream->segments, stream->segment_idx);
+  g_return_val_if_fail (media_segment != NULL, GST_CLOCK_TIME_NONE);
+
+  return media_segment->start_time;
+}
+
+GstClockTime
+gst_mpd_client_get_next_fragment_duration (GstMpdClient * client)
+{
+  GstActiveStream *stream;
+  GstMediaSegment *media_segment;
 
   stream = g_list_nth_data (client->active_streams, client->stream_idx);
-  g_return_if_fail (stream != NULL);
+  g_return_val_if_fail (stream != NULL, 0);
+
+  media_segment = g_list_nth_data (stream->segments, stream->segment_idx);
 
-  duration = gst_mpd_client_get_target_duration (client);
-  *timestamp = duration == GST_CLOCK_TIME_NONE ? GST_CLOCK_TIME_NONE : stream->segment_idx * duration;
+  return media_segment == NULL ? 0 : media_segment->duration;
 }
 
 GstClockTime
-gst_mpd_client_get_duration (GstMpdClient * client)
+gst_mpd_client_get_media_presentation_duration (GstMpdClient * client)
 {
   GstClockTime duration;
 
@@ -3000,41 +3053,6 @@ gst_mpd_client_get_duration (GstMpdClient * client)
   return duration;
 }
 
-GstClockTime
-gst_mpd_client_get_target_duration (GstMpdClient * client)
-{
-  GstActiveStream *stream;
-  GstStreamPeriod *stream_period;
-  GstMultSegmentBaseType *base = NULL;
-  GstClockTime duration;
-  guint timescale;
-
-  stream = gst_mpdparser_get_active_stream_by_index (client, client->stream_idx);
-  g_return_val_if_fail (stream != NULL, GST_CLOCK_TIME_NONE);
-  stream_period = gst_mpdparser_get_stream_period (client);
-  g_return_val_if_fail (stream_period != NULL, GST_CLOCK_TIME_NONE);
-
-  if (stream->cur_segment_list) {
-    base = stream->cur_segment_list->MultSegBaseType;
-  } else if (stream->cur_seg_template) {
-    base = stream->cur_seg_template->MultSegBaseType;
-  }
-
-  if (base == NULL || base->SegBaseType == NULL) {
-    /* this may happen when we have a single segment */
-    /* TODO: support SegmentTimeline */
-    duration = stream_period->duration;
-  } else {
-    duration = base->duration * GST_SECOND;
-    timescale = base->SegBaseType->timescale;
-
-    if (timescale > 1)
-      duration /= timescale;
-  }
-
-  return duration;
-}
-
 gboolean
 gst_mpd_client_get_next_period (GstMpdClient *client)
 {
index b061f5d..8254c87 100644 (file)
@@ -467,9 +467,9 @@ gboolean gst_mpd_parse (GstMpdClient *client, const gchar *data, gint size);
 gboolean gst_mpd_client_setup_media_presentation (GstMpdClient *client);
 gboolean gst_mpd_client_setup_streaming (GstMpdClient *client, GstStreamMimeType mimeType, gchar* lang);
 gboolean gst_mpd_client_setup_representation (GstMpdClient *client, GstActiveStream *stream, GstRepresentationNode *representation);
-void gst_mpd_client_get_current_position (GstMpdClient *client, GstClockTime * timestamp);
-GstClockTime gst_mpd_client_get_duration (GstMpdClient *client);
-GstClockTime gst_mpd_client_get_target_duration (GstMpdClient *client);
+GstClockTime gst_mpd_client_get_current_position (GstMpdClient *client);
+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_next_fragment (GstMpdClient *client, guint indexStream, gboolean *discontinuity, gchar **uri, GstClockTime *duration, GstClockTime *timestamp);
 gboolean gst_mpd_client_get_next_header (GstMpdClient *client, const gchar **uri, guint stream_idx);
 gboolean gst_mpd_client_is_live (GstMpdClient * client);