dashdemux: various fixes
authorLouis-Francis Ratté-Boulianne <louis-francis.ratte-boulianne@collabora.co.uk>
Wed, 16 Jan 2013 18:58:52 +0000 (13:58 -0500)
committerThiago Santos <thiago.sousa.santos@collabora.com>
Wed, 8 May 2013 21:14:33 +0000 (18:14 -0300)
ext/dash/gstdashdemux.c
ext/dash/gstmpdparser.c
ext/dash/gstmpdparser.h

index 68a2013..6e457ca 100644 (file)
@@ -474,6 +474,7 @@ gst_dash_demux_src_event (GstPad * pad, GstEvent * event)
   GstDashDemux *demux;
 
   demux = GST_DASH_DEMUX (gst_pad_get_element_private (pad));
+  GST_WARNING_OBJECT (demux, "Received an event");
 
   switch (event->type) {
     case GST_EVENT_SEEK:
@@ -492,6 +493,8 @@ gst_dash_demux_src_event (GstPad * pad, GstEvent * event)
       guint nb_active_stream;
       guint stream_idx;
 
+      GST_WARNING_OBJECT (demux, "Received seek event");
+
       if (gst_mpd_client_is_live (demux->client)) {
         GST_WARNING_OBJECT (demux, "Received seek event for live stream");
         return FALSE;
@@ -537,15 +540,18 @@ gst_dash_demux_src_event (GstPad * pad, GstEvent * event)
 
       stream = gst_mpdparser_get_active_stream_by_index (demux->client, 0);
       current_pos = 0;
+      current_sequence = 0;
       for (list = g_list_first (stream->segments); list;
           list = g_list_next (list)) {
         chunk = list->data;
         current_pos = chunk->start_time;
-        current_sequence = chunk->number;
+        //current_sequence = chunk->number;
+        GST_WARNING_OBJECT (demux, "%i <= %i (%i)", current_pos, target_pos, chunk->duration);
         if (current_pos <= target_pos
             && target_pos < current_pos + chunk->duration) {
           break;
         }
+        current_sequence++;
       }
       //GST_MPD_CLIENT_UNLOCK (demux->client);
 
@@ -601,6 +607,7 @@ gst_dash_demux_src_event (GstPad * pad, GstEvent * event)
 
       /* Restart the demux */
       demux->cancelled = FALSE;
+      demux->end_of_manifest = FALSE;
       gst_dash_demux_resume_download_task (demux);
       gst_dash_demux_resume_stream_task (demux);
       g_static_rec_mutex_unlock (&demux->stream_lock);
@@ -637,10 +644,10 @@ gst_dash_demux_setup_all_streams (GstDashDemux * demux)
 
   for (i = 0; i < nb_audio; i++) {
     lang = (gchar *) g_list_nth_data (listLang, i);
-    if (gst_mpdparser_get_nb_adaptationSet (demux->client) > 1)
-      if (!gst_mpd_client_setup_streaming (demux->client, GST_STREAM_AUDIO,
-              lang))
-        GST_INFO_OBJECT (demux, "No audio adaptation set found");
+    GST_INFO ("nb adaptation set: %i", gst_mpdparser_get_nb_adaptationSet (demux->client));
+    if (!gst_mpd_client_setup_streaming (demux->client, GST_STREAM_AUDIO,
+            lang))
+      GST_INFO_OBJECT (demux, "No audio adaptation set found");
 
     if (gst_mpdparser_get_nb_adaptationSet (demux->client) > nb_audio)
       if (!gst_mpd_client_setup_streaming (demux->client,
@@ -779,11 +786,13 @@ gst_dash_demux_src_query (GstPad * pad, GstQuery * query)
     }
     case GST_QUERY_SEEKING:{
       GstFormat fmt;
+      gint64 start;
+      gint64 end;
       gint64 stop = -1;
 
-      gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
-      GST_DEBUG_OBJECT (dashdemux, "Received GST_QUERY_SEEKING with format %d",
-          fmt);
+      gst_query_parse_seeking (query, &fmt, NULL, &start, &end);
+      GST_DEBUG_OBJECT (dashdemux, "Received GST_QUERY_SEEKING with format %d - %i %i",
+          fmt, start, end);
       if (fmt == GST_FORMAT_TIME) {
         GstClockTime duration;
 
@@ -876,6 +885,8 @@ switch_pads (GstDashDemux * demux, guint nb_adaptation_set)
     gst_pad_set_active (demux->srcpad[i], TRUE);
     gst_pad_set_caps (demux->srcpad[i], demux->output_caps[i]);
     gst_element_add_pad (GST_ELEMENT (demux), demux->srcpad[i]);
+    GST_INFO_OBJECT (demux, "Adding srcpad %s:%s with caps %" GST_PTR_FORMAT,
+        GST_DEBUG_PAD_NAME (demux->srcpad[i]), demux->output_caps[i]);
     i++;
   }
   /* Send 'no-more-pads' to have decodebin create the new group */
@@ -923,8 +934,7 @@ needs_pad_switch (GstDashDemux * demux, GList * fragment)
     if (G_LIKELY (demux->srcpad[i]))
       srccaps = gst_pad_get_negotiated_caps (demux->srcpad[i]);
     if (G_UNLIKELY (!srccaps
-            || (!gst_caps_is_equal_fixed (demux->output_caps[i], srccaps))
-            || demux->need_segment)) {
+            || (!gst_caps_is_equal_fixed (demux->output_caps[i], srccaps)))) {
       switch_pad = TRUE;
     }
     if (G_LIKELY (srccaps))
@@ -982,6 +992,7 @@ gst_dash_demux_stream_loop (GstDashDemux * demux)
         demux->min_buffering_time) {
       /* Warn we are below our threshold: this will eventually pause 
        * the pipeline */
+      GST_WARNING ("Below the threshold: this will eventually pause the pipeline");
       gst_element_post_message (GST_ELEMENT (demux),
           gst_message_new_buffering (GST_OBJECT (demux),
               100 * gst_dash_demux_get_buffering_ratio (demux)));
@@ -1007,10 +1018,9 @@ gst_dash_demux_stream_loop (GstDashDemux * demux)
       gst_pad_push_event (demux->srcpad[i],
           gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME,
               start, GST_CLOCK_TIME_NONE, start));
-      demux->position_shift = 0;
     }
 
-    GST_DEBUG_OBJECT (demux, "Pushing fragment #%d", fragment->index);
+    GST_DEBUG_OBJECT (demux, "Pushing fragment #%d (stream %i)", fragment->index, i);
     buffer_list = gst_fragment_get_buffer_list (fragment);
     g_object_unref (fragment);
     ret = gst_pad_push_list (demux->srcpad[i], buffer_list);
@@ -1018,6 +1028,7 @@ gst_dash_demux_stream_loop (GstDashDemux * demux)
       goto error_pushing;
   }
   demux->need_segment = FALSE;
+  demux->position_shift = 0;
   g_list_free (listfragment);
   if (GST_STATE (demux) == GST_STATE_PLAYING) {
     /* Wait for the duration of a fragment before resuming this task */
@@ -1284,6 +1295,7 @@ gst_dash_demux_download_loop (GstDashDemux * demux)
   /* Target buffering time MUST at least exceeds mimimum buffering time 
    * by the duration of a fragment, but SHOULD NOT exceed maximum
    * buffering time */
+  GST_DEBUG_OBJECT (demux, "download loop %i", demux->end_of_manifest);
   GstClockTime target_buffering_time =
       demux->min_buffering_time +
       gst_mpd_client_get_next_fragment_duration (demux->client);
@@ -1428,8 +1440,9 @@ gst_dash_demux_select_representations (GstDashDemux * demux, guint64 bitrate)
 
     /* if no representation has the required bandwidth, take the lowest one */
     if (new_index == -1)
-      new_index = 0;
+      new_index = gst_mpdparser_get_rep_idx_with_min_bandwidth (rep_list);
 
+#if 0
     if (new_index != stream->representation_idx) {
       GST_MPD_CLIENT_LOCK (demux->client);
       ret =
@@ -1444,6 +1457,7 @@ gst_dash_demux_select_representations (GstDashDemux * demux, guint64 bitrate)
             "Can not switch representation, aborting...");
       }
     }
+#endif
     i++;
   }
   return ret;
@@ -1462,7 +1476,7 @@ gst_dash_demux_get_next_header (GstDashDemux * demux, guint stream_idx)
 
   if (strncmp (initializationURL, "http://", 7) != 0) {
     next_header_uri =
-        g_strconcat (gst_mpdparser_get_baseURL (demux->client),
+        g_strconcat (gst_mpdparser_get_baseURL (demux->client, stream_idx),
         initializationURL, NULL);
   } else {
     next_header_uri = g_strdup (initializationURL);
@@ -1673,6 +1687,7 @@ gst_dash_demux_get_next_fragment_set (GstDashDemux * demux)
       return FALSE;
     }
 
+    GST_INFO_OBJECT (demux, "Next fragment for stream #%i", stream_idx);
     GST_INFO_OBJECT (demux, "Fetching next fragment %s", next_fragment_uri);
 
     download = gst_uri_downloader_fetch_uri (demux->downloader,
index 4cd76b1..291ff5a 100644 (file)
@@ -108,10 +108,11 @@ static void gst_mpdparser_parse_root_node (GstMPDNode ** pointer,
 static gint convert_to_millisecs (gint decimals, gint pos);
 static int strncmp_ext (const char *s1, const char *s2);
 static GstStreamPeriod *gst_mpdparser_get_stream_period (GstMpdClient * client);
-static gchar *gst_mpdparser_parse_baseURL (GstMpdClient * client);
+static gchar *gst_mpdparser_parse_baseURL (GstMpdClient * client,
+    GstActiveStream *stream);
 static gchar *gst_mpdparser_get_segmentURL_for_range (gchar * url,
     GstRange * range);
-static gchar *gst_mpdparser_get_mediaURL (GstMpdClient * client,
+static gchar *gst_mpdparser_get_mediaURL (GstActiveStream * stream,
     GstSegmentURLNode * segmentURL);
 static gchar *gst_mpdparser_get_initializationURL (GstURLType *
     InitializationURL);
@@ -1463,6 +1464,8 @@ gst_mpdparser_parse_period_node (GList ** list, xmlNode * a_node)
   }
   *list = g_list_append (*list, new_period);
 
+  new_period->start = GST_CLOCK_TIME_NONE;
+
   GST_LOG ("attributes of Period node:");
   new_period->id = gst_mpdparser_get_xml_prop_string (a_node, "id");
   new_period->start = gst_mpdparser_get_xml_prop_duration (a_node, "start");
@@ -1681,6 +1684,7 @@ gst_mpdparser_get_first_adapt_set_with_mimeType (GList * AdaptationSets,
       if (!this_mimeType && adapt_set->RepresentationBase) {
         this_mimeType = adapt_set->RepresentationBase->mimeType;
       }
+      GST_DEBUG("Looking for mime type %s -> %s", mimeType, this_mimeType);
       if (strncmp_ext (this_mimeType, mimeType) == 0)
         return adapt_set;
     }
@@ -1703,6 +1707,8 @@ gst_mpdparser_get_adapt_set_with_mimeType_and_idx (GList * AdaptationSets,
   if (AdaptationSets == NULL)
     return NULL;
 
+  // FIXME Use ContentComponent to determine if this adaptation set contains
+  // the content type we're looking for.
   for (list = g_list_first (AdaptationSets); list; list = g_list_next (list)) {
     adapt_set = (GstAdaptationSetNode *) list->data;
     if (adapt_set) {
@@ -1712,9 +1718,9 @@ gst_mpdparser_get_adapt_set_with_mimeType_and_idx (GList * AdaptationSets,
           gst_mpdparser_get_lowest_representation (adapt_set->Representations);
       if (rep->RepresentationBase)
         this_mimeType = rep->RepresentationBase->mimeType;
-      if (!this_mimeType && adapt_set->RepresentationBase) {
+      if (!this_mimeType && adapt_set->RepresentationBase)
         this_mimeType = adapt_set->RepresentationBase->mimeType;
-      }
+      GST_DEBUG("Looking for mime type %s -> %i: %s", mimeType, i, this_mimeType);
       if (strncmp_ext (this_mimeType, mimeType) == 0) {
         if (idx < 0 || i <= idx)
           selected = adapt_set;
@@ -1744,11 +1750,16 @@ gst_mpdparser_get_first_adapt_set_with_mimeType_and_lang (GList *
       gchar *this_mimeType = NULL;
       rep =
           gst_mpdparser_get_lowest_representation (adapt_set->Representations);
+      if (rep && rep->BaseURLs) {
+        GstBaseURL *url = rep->BaseURLs->data;
+        GST_DEBUG("%s", url->baseURL);
+      }
       if (rep->RepresentationBase)
         this_mimeType = rep->RepresentationBase->mimeType;
       if (!this_mimeType && adapt_set->RepresentationBase) {
         this_mimeType = adapt_set->RepresentationBase->mimeType;
       }
+      GST_DEBUG("Looking for mime type %s -> %s", mimeType, this_mimeType);
       if (strncmp_ext (this_mimeType, mimeType) == 0
           && strncmp_ext (this_lang, lang) == 0)
         return adapt_set;
@@ -1762,13 +1773,20 @@ static GstRepresentationNode *
 gst_mpdparser_get_lowest_representation (GList * Representations)
 {
   GList *list = NULL;
+  GstRepresentationNode *rep = NULL;
+  GstRepresentationNode *lowest = NULL;
 
   if (Representations == NULL)
     return NULL;
 
-  list = g_list_first (Representations);
+  for (list = g_list_first (Representations); list; list = g_list_next (list)) {
+    rep = (GstRepresentationNode *) list->data;
+    if (rep && (!lowest || rep->bandwidth < lowest->bandwidth)) {
+      lowest = rep;
+    }
+  }
 
-  return list ? (GstRepresentationNode *) list->data : NULL;
+  return lowest;
 }
 
 #if 0
@@ -1852,11 +1870,35 @@ gst_mpdparser_get_segment_base (GstPeriodNode * Period,
 }
 
 gint
+gst_mpdparser_get_rep_idx_with_min_bandwidth (GList * Representations)
+{
+  GList *list = NULL, *lowest;
+  GstRepresentationNode *rep = NULL;
+  gint lowest_bandwidth = -1;
+
+  if (Representations == NULL)
+    return NULL;
+
+  for (list = g_list_first (Representations); list; list = g_list_next (list)) {
+    rep = (GstRepresentationNode *) list->data;
+    if (rep && (!lowest || rep->bandwidth < lowest_bandwidth)) {
+      lowest = list;
+      lowest_bandwidth = rep->bandwidth;
+    }
+  }
+
+  return lowest ? g_list_position (Representations, lowest) : -1;
+}
+
+gint
 gst_mpdparser_get_rep_idx_with_max_bandwidth (GList * Representations,
     gint max_bandwidth)
 {
   GList *list = NULL, *best = NULL;
   GstRepresentationNode *representation;
+  gint best_bandwidth = 0;
+
+  GST_DEBUG ("max_bandwidth = %i", max_bandwidth);
 
   if (Representations == NULL)
     return -1;
@@ -1866,8 +1908,10 @@ gst_mpdparser_get_rep_idx_with_max_bandwidth (GList * Representations,
 
   for (list = g_list_first (Representations); list; list = g_list_next (list)) {
     representation = (GstRepresentationNode *) list->data;
-    if (representation && representation->bandwidth <= max_bandwidth) {
+    if (representation && representation->bandwidth <= max_bandwidth &&
+        representation->bandwidth > best_bandwidth) {
       best = list;
+      best_bandwidth = representation->bandwidth;
     }
   }
 
@@ -2280,17 +2324,15 @@ gst_mpdparser_get_segmentURL_for_range (gchar * url, GstRange * range)
 }
 
 static gchar *
-gst_mpdparser_get_mediaURL (GstMpdClient * client,
+gst_mpdparser_get_mediaURL (GstActiveStream *stream,
     GstSegmentURLNode * segmentURL)
 {
   const gchar *url_prefix;
 
-  g_return_val_if_fail (client != NULL, NULL);
+  g_return_val_if_fail (stream != NULL, NULL);
   g_return_val_if_fail (segmentURL != NULL, NULL);
 
-  url_prefix =
-      segmentURL->media ? segmentURL->
-      media : gst_mpdparser_get_baseURL (client);
+  url_prefix = segmentURL->media ? segmentURL->media : stream->baseURL;
   g_return_val_if_fail (url_prefix != NULL, NULL);
 
   return gst_mpdparser_get_segmentURL_for_range (segmentURL->media,
@@ -2381,9 +2423,9 @@ gst_mpdparser_get_stream_period (GstMpdClient * client)
 
 /* select a stream and extract the baseURL (if present) */
 static gchar *
-gst_mpdparser_parse_baseURL (GstMpdClient * client)
+gst_mpdparser_parse_baseURL (GstMpdClient * client, GstActiveStream *stream)
 {
-  GstActiveStream *stream;
+  //GstActiveStream *stream;
   GstStreamPeriod *stream_period;
   GstBaseURL *baseURL;
   GList *list;
@@ -2391,8 +2433,9 @@ gst_mpdparser_parse_baseURL (GstMpdClient * client)
   static gchar empty[] = "";
   gchar *ret = NULL;
 
-  stream =
-      gst_mpdparser_get_active_stream_by_index (client, client->stream_idx);
+  //stream =
+  //    gst_mpdparser_get_active_stream_by_index (client, client->stream_idx);
+
   g_return_val_if_fail (stream != NULL, empty);
   stream_period = gst_mpdparser_get_stream_period (client);
   g_return_val_if_fail (stream_period != NULL, empty);
@@ -2417,6 +2460,9 @@ gst_mpdparser_parse_baseURL (GstMpdClient * client)
     }
     baseURL_array[1] = baseURL->baseURL;
   }
+  GST_DEBUG("Current adaptation set id %i (%s)", stream->cur_adapt_set->id,
+      stream->cur_adapt_set->contentType);
+
   if ((list = stream->cur_adapt_set->BaseURLs) != NULL) {
     baseURL = g_list_nth_data (list, stream->baseURL_idx);
     if (!baseURL) {
@@ -2424,6 +2470,7 @@ gst_mpdparser_parse_baseURL (GstMpdClient * client)
     }
     baseURL_array[2] = baseURL->baseURL;
   }
+
   if ((list = stream->cur_representation->BaseURLs) != NULL) {
     baseURL = g_list_nth_data (list, stream->baseURL_idx);
     if (!baseURL) {
@@ -2588,13 +2635,13 @@ gst_mpd_parse (GstMpdClient * client, const gchar * data, gint size)
 }
 
 const gchar *
-gst_mpdparser_get_baseURL (GstMpdClient * client)
+gst_mpdparser_get_baseURL (GstMpdClient * client, guint indexStream)
 {
   GstActiveStream *stream;
 
   g_return_val_if_fail (client != NULL, NULL);
   g_return_val_if_fail (client->active_streams != NULL, NULL);
-  stream = g_list_nth_data (client->active_streams, client->stream_idx);
+  stream = g_list_nth_data (client->active_streams, indexStream);
   g_return_val_if_fail (stream != NULL, NULL);
 
   return stream->baseURL;
@@ -2822,10 +2869,11 @@ gst_mpd_client_setup_representation (GstMpdClient * client,
       } else {
         duration = gst_mpd_client_get_segment_duration (client);
         if (!GST_CLOCK_TIME_IS_VALID (duration)
-            || !GST_CLOCK_TIME_IS_VALID (PeriodEnd))
+            || !GST_CLOCK_TIME_IS_VALID (PeriodEnd)
+            || duration <= 0)
           return FALSE;
 
-        while (PeriodStart + start_time < PeriodEnd) {
+        while (start_time < PeriodEnd) {
           if (!gst_mpd_client_add_media_segment (stream, NULL, i, 0, start_time,
                   duration)) {
             return FALSE;
@@ -2850,7 +2898,7 @@ gst_mpd_client_setup_representation (GstMpdClient * client,
   }
 
   g_free (stream->baseURL);
-  stream->baseURL = gst_mpdparser_parse_baseURL (client);
+  stream->baseURL = gst_mpdparser_parse_baseURL (client, stream);
 
   return TRUE;
 }
@@ -2966,6 +3014,9 @@ gst_mpd_client_setup_streaming (GstMpdClient * client,
   GstRepresentationNode *representation;
   GList *rep_list = NULL;
 
+  GstRepresentationNode *rep;
+  GstBaseURL *url;
+
   stream_period = gst_mpdparser_get_stream_period (client);
   if (stream_period == NULL || stream_period->period == NULL) {
     GST_DEBUG ("No more Period nodes in the MPD file, terminating...");
@@ -3043,6 +3094,8 @@ gst_mpd_client_setup_streaming (GstMpdClient * client,
   stream->mimeType = mimeType;
   stream->cur_adapt_set = adapt_set;
 
+  GST_DEBUG("0. Current stream %p", stream);
+
   /* retrive representation list */
   if (stream->cur_adapt_set != NULL)
     rep_list = stream->cur_adapt_set->Representations;
@@ -3106,23 +3159,25 @@ gst_mpd_client_get_next_fragment (GstMpdClient * client,
     return FALSE;
   }
 
+  GST_DEBUG("currentChunk->SegmentURL = %s", currentChunk->SegmentURL);
   if (currentChunk->SegmentURL != NULL) {
-    mediaURL = gst_mpdparser_get_mediaURL (client, currentChunk->SegmentURL);
+    mediaURL = gst_mpdparser_get_mediaURL (stream, currentChunk->SegmentURL);
   } 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);
   }
+  GST_DEBUG("mediaURL = %s", mediaURL);
 
   *timestamp = currentChunk->start_time;
   *duration = currentChunk->duration;
   *discontinuity = segment_idx != currentChunk->number;
   if (mediaURL == NULL) {
     /* single segment with URL encoded in the baseURL syntax element */
-    *uri = g_strdup (gst_mpdparser_get_baseURL (client));
+    *uri = g_strdup (stream->baseURL);
   } else if (strncmp (mediaURL, "http://", 7) != 0) {
-    *uri = g_strconcat (gst_mpdparser_get_baseURL (client), mediaURL, NULL);
+    *uri = g_strconcat (stream->baseURL, mediaURL, NULL);
     g_free (mediaURL);
   } else {
     *uri = mediaURL;
@@ -3199,6 +3254,7 @@ gst_mpd_client_get_next_fragment_duration (GstMpdClient * client)
   GstActiveStream *stream;
   GstMediaSegment *media_segment;
 
+  GST_WARNING ("Stream index: %i", client->stream_idx);
   stream = g_list_nth_data (client->active_streams, client->stream_idx);
   g_return_val_if_fail (stream != NULL, 0);
 
index a084543..6663804 100644 (file)
@@ -480,9 +480,10 @@ guint gst_mpd_client_get_period_index (GstMpdClient *client);
 
 /* Representation selection */
 gint gst_mpdparser_get_rep_idx_with_max_bandwidth (GList *Representations, gint max_bandwidth);
+gint gst_mpdparser_get_rep_idx_with_min_bandwidth (GList * Representations);
 
 /* URL management */
-const gchar *gst_mpdparser_get_baseURL (GstMpdClient *client);
+const gchar *gst_mpdparser_get_baseURL (GstMpdClient *client, guint indexStream);
 GstMediaSegment *gst_mpdparser_get_chunk_by_index (GstMpdClient *client, guint indexStream, guint indexChunk);
 
 /* Active stream */