tizen 2.3 release
[framework/multimedia/gst-plugins-ext0.10.git] / dashdemux / src / gstdashdemux.c
similarity index 55%
rename from wearable/dashdemux/src/gstdashdemux.c
rename to dashdemux/src/gstdashdemux.c
index d3460e1..ba6fe2b 100755 (executable)
@@ -167,7 +167,6 @@ enum
 {
   PROP_0,
 
-  PROP_MIN_BUFFERING_TIME,
   PROP_MAX_BUFFERING_TIME,
   PROP_BANDWIDTH_USAGE,
   PROP_MAX_BITRATE,
@@ -175,12 +174,21 @@ enum
 };
 
 /* Default values for properties */
-#define DEFAULT_MIN_BUFFERING_TIME        5     /* in seconds */
 #define DEFAULT_MAX_BUFFERING_TIME       30     /* in seconds */
 #define DEFAULT_BANDWIDTH_USAGE         0.8     /* 0 to 1     */
 #define DEFAULT_MAX_BITRATE        24000000     /* in bit/s  */
 
 #define DEFAULT_FAILED_COUNT 3
+#define DOWNLOAD_RATE_HISTORY_MAX 3
+#define DOWNLOAD_RATE_TIME_MAX 3 * GST_SECOND
+
+/* Custom internal event to signal end of period */
+#define GST_EVENT_DASH_EOP GST_EVENT_MAKE_TYPE(81, GST_EVENT_TYPE_DOWNSTREAM | GST_EVENT_TYPE_SERIALIZED)
+static GstEvent *
+gst_event_new_dash_eop (void)
+{
+  return gst_event_new_custom (GST_EVENT_DASH_EOP, NULL);
+}
 
 
 /* GObject */
@@ -202,18 +210,16 @@ static gboolean gst_dash_demux_src_query (GstPad * pad, GstQuery * query);
 static void gst_dash_demux_stream_loop (GstDashDemux * demux);
 static void gst_dash_demux_download_loop (GstDashDemux * demux);
 static void gst_dash_demux_stop (GstDashDemux * demux);
-static void gst_dash_demux_pause_stream_task (GstDashDemux * demux);
 static void gst_dash_demux_resume_stream_task (GstDashDemux * demux);
 static void gst_dash_demux_resume_download_task (GstDashDemux * demux);
 static gboolean gst_dash_demux_setup_all_streams (GstDashDemux * demux);
-static gboolean gst_dash_demux_select_representations (GstDashDemux * demux,
-    guint64 current_bitrate);
-static gboolean gst_dash_demux_get_next_fragment_set (GstDashDemux * demux);
+static gboolean gst_dash_demux_select_representations (GstDashDemux * demux);
+static GstCaps *gst_dash_demux_get_input_caps (GstDashDemux * demux, GstActiveStream * stream);
+static gboolean gst_dash_demux_get_next_fragment (GstDashDemux * demux, GstActiveStream **fragment_stream, GstClockTime *selected_ts);
 
+static void gst_dash_demux_clear_streams(GstDashDemux * demux);
 static void gst_dash_demux_reset (GstDashDemux * demux, gboolean dispose);
 static GstClockTime gst_dash_demux_get_buffering_time (GstDashDemux * demux);
-static float gst_dash_demux_get_buffering_ratio (GstDashDemux * demux);
-static GstBuffer *gst_dash_demux_merge_buffer_list (GstFragment * fragment);
 
 static void
 _do_init (GType type)
@@ -268,10 +274,12 @@ gst_dash_demux_dispose (GObject * obj)
     }
     gst_object_unref (demux->download_task);
     g_static_rec_mutex_free (&demux->download_lock);
-    g_mutex_free(demux->download_timed_lock);
     demux->download_task = NULL;
   }
 
+  g_cond_clear (&demux->download_cond);
+  g_mutex_clear (&demux->download_mutex);
+
   if (demux->downloader != NULL) {
     g_object_unref (demux->downloader);
     demux->downloader = NULL;
@@ -279,8 +287,6 @@ gst_dash_demux_dispose (GObject * obj)
 
   gst_dash_demux_reset (demux, TRUE);
 
-  g_queue_free (demux->queue);
-
   G_OBJECT_CLASS (parent_class)->dispose (obj);
 }
 
@@ -297,12 +303,6 @@ gst_dash_demux_class_init (GstDashDemuxClass * klass)
   gobject_class->get_property = gst_dash_demux_get_property;
   gobject_class->dispose = gst_dash_demux_dispose;
 
-  g_object_class_install_property (gobject_class, PROP_MIN_BUFFERING_TIME,
-      g_param_spec_uint ("min-buffering-time", "Minimum buffering time",
-          "Minimum number of seconds of buffer accumulated before playback",
-          1, G_MAXUINT, DEFAULT_MIN_BUFFERING_TIME,
-          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
   g_object_class_install_property (gobject_class, PROP_MAX_BUFFERING_TIME,
       g_param_spec_uint ("max-buffering-time", "Maximum buffering time",
           "Maximum number of seconds of buffer accumulated during playback",
@@ -326,6 +326,48 @@ gst_dash_demux_class_init (GstDashDemuxClass * klass)
       GST_DEBUG_FUNCPTR (gst_dash_demux_change_state);
 }
 
+static gboolean
+_check_queue_full (GstDataQueue * q, guint visible, guint bytes, guint64 time,
+    GstDashDemux *demux)
+{
+  return time > demux->max_buffering_time;
+}
+
+static void
+_data_queue_item_destroy (GstDataQueueItem * item)
+{
+  gst_mini_object_unref (item->object);
+  g_free (item);
+}
+
+static void
+gst_dash_demux_stream_push_event (GstDashDemuxStream * stream,
+                                  GstEvent *event)
+{
+  GstDataQueueItem *item = g_new0 (GstDataQueueItem, 1);
+
+  item->object = GST_MINI_OBJECT_CAST (event);
+  item->destroy = (GDestroyNotify) _data_queue_item_destroy;
+
+  gst_data_queue_push (stream->queue, item);
+}
+
+static void
+gst_dash_demux_stream_push_data (GstDashDemuxStream * stream,
+    GstBuffer * buffer)
+{
+  GstDataQueueItem *item = g_new0 (GstDataQueueItem, 1);
+
+  item->object = GST_MINI_OBJECT_CAST (buffer);
+  item->duration = GST_BUFFER_DURATION (buffer);
+  item->visible = TRUE;
+  item->size = GST_BUFFER_SIZE (buffer);
+
+  item->destroy = (GDestroyNotify) _data_queue_item_destroy;
+
+  gst_data_queue_push (stream->queue, item);
+}
+
 static void
 gst_dash_demux_init (GstDashDemux * demux, GstDashDemuxClass * klass)
 {
@@ -341,18 +383,20 @@ gst_dash_demux_init (GstDashDemux * demux, GstDashDemuxClass * klass)
   demux->downloader = gst_uri_downloader_new ();
 
   /* Properties */
-  demux->min_buffering_time = DEFAULT_MIN_BUFFERING_TIME * GST_SECOND;
   demux->max_buffering_time = DEFAULT_MAX_BUFFERING_TIME * GST_SECOND;
   demux->bandwidth_usage = DEFAULT_BANDWIDTH_USAGE;
   demux->max_bitrate = DEFAULT_MAX_BITRATE;
 
-  demux->queue = g_queue_new ();
+  demux->max_video_width = 0;
+  demux->max_video_height = 0;
+
   /* Updates task */
   g_static_rec_mutex_init (&demux->download_lock);
   demux->download_task =
       gst_task_create ((GstTaskFunction) gst_dash_demux_download_loop, demux);
   gst_task_set_lock (demux->download_task, &demux->download_lock);
-  demux->download_timed_lock = g_mutex_new ();
+  g_cond_init (&demux->download_cond);
+  g_mutex_init (&demux->download_mutex);
 
   /* Streaming task */
   g_static_rec_mutex_init (&demux->stream_lock);
@@ -369,9 +413,6 @@ gst_dash_demux_set_property (GObject * object, guint prop_id,
   GstDashDemux *demux = GST_DASH_DEMUX (object);
 
   switch (prop_id) {
-    case PROP_MIN_BUFFERING_TIME:
-      demux->min_buffering_time = g_value_get_uint (value) * GST_SECOND;
-      break;
     case PROP_MAX_BUFFERING_TIME:
       demux->max_buffering_time = g_value_get_uint (value) * GST_SECOND;
       break;
@@ -394,13 +435,8 @@ gst_dash_demux_get_property (GObject * object, guint prop_id, GValue * value,
   GstDashDemux *demux = GST_DASH_DEMUX (object);
 
   switch (prop_id) {
-    case PROP_MIN_BUFFERING_TIME:
-      g_value_set_uint (value, demux->min_buffering_time);
-      demux->min_buffering_time *= GST_SECOND;
-      break;
     case PROP_MAX_BUFFERING_TIME:
-      g_value_set_uint (value, demux->max_buffering_time);
-      demux->max_buffering_time *= GST_SECOND;
+      g_value_set_uint (value, demux->max_buffering_time / GST_SECOND);
       break;
     case PROP_BANDWIDTH_USAGE:
       g_value_set_float (value, demux->bandwidth_usage);
@@ -420,18 +456,14 @@ gst_dash_demux_change_state (GstElement * element, GstStateChange transition)
   GstStateChangeReturn ret;
   GstDashDemux *demux = GST_DASH_DEMUX (element);
 
+  GST_DEBUG_OBJECT (demux, "changing state %s - %s",
+      gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
+      gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
+
   switch (transition) {
     case GST_STATE_CHANGE_READY_TO_PAUSED:
       gst_dash_demux_reset (demux, FALSE);
       break;
-    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
-      /* Start the streaming loop in paused only if we already received
-         the manifest. It might have been stopped if we were in PAUSED
-         state and we filled our queue with enough cached fragments
-       */
-      if (demux->client->mpd_node != NULL)
-        gst_dash_demux_resume_stream_task (demux);
-      break;
     default:
       break;
   }
@@ -439,9 +471,6 @@ gst_dash_demux_change_state (GstElement * element, GstStateChange transition)
   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
 
   switch (transition) {
-    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
-      gst_dash_demux_pause_stream_task (demux);
-      break;
     case GST_STATE_CHANGE_PAUSED_TO_READY:
       demux->cancelled = TRUE;
       gst_dash_demux_stop (demux);
@@ -455,19 +484,16 @@ gst_dash_demux_change_state (GstElement * element, GstStateChange transition)
 }
 
 void
-gst_dash_demux_clear_queue (GstDashDemux * demux)
+gst_dash_demux_flush_stream_queues (GstDashDemux * demux)
 {
-  while (!g_queue_is_empty (demux->queue)) {
-    GList *listfragment = g_queue_pop_head (demux->queue);
-    guint j = 0;
-    while (j < g_list_length (listfragment)) {
-      GstFragment *fragment = g_list_nth_data (listfragment, j);
-      g_object_unref (fragment);
-      j++;
-    }
-    g_list_free (listfragment);
+  GSList *it;
+  GstDashDemuxStream *stream;
+  for(it = demux->streams; it; it=it->next)
+  {
+    stream = it->data;
+    gst_data_queue_set_flushing(stream->queue, TRUE);
+    gst_data_queue_flush(stream->queue);
   }
-  g_queue_clear (demux->queue);
 }
 
 static gboolean
@@ -486,13 +512,15 @@ gst_dash_demux_src_event (GstPad * pad, GstEvent * event)
       GstSeekType start_type, stop_type;
       gint64 start, stop;
       GList *list;
-      GstClockTime current_pos, target_pos;
-      guint current_sequence, current_period;
+      GstClockTime current_pos = GST_CLOCK_TIME_NONE;
+      GstClockTime target_pos;
+      guint current_period;
       GstActiveStream *stream;
-      GstMediaSegment *chunk;
-      GstStreamPeriod *period;
+      GstStreamPeriod *period = NULL;
       guint nb_active_stream;
-      guint stream_idx;
+      guint stream_idx = 0;
+      guint *seek_idx = NULL;   /*Seek positions on each stream*/
+      gboolean end_of_mpd = FALSE;
 
       if (gst_mpd_client_is_live (demux->client)) {
         GST_WARNING_OBJECT (demux, "Received seek event for live stream");
@@ -525,6 +553,11 @@ gst_dash_demux_src_event (GstPad * pad, GstEvent * event)
           break;
         }
       }
+      if(target_pos == current_pos + period->duration) {
+        /*Seeking to the end of MPD*/
+        end_of_mpd = TRUE;
+        goto seeking;
+      }
       if (list == NULL) {
         GST_WARNING_OBJECT (demux, "Could not find seeked Period");
         return FALSE;
@@ -537,25 +570,31 @@ gst_dash_demux_src_event (GstPad * pad, GstEvent * event)
           return FALSE;
       }
 
-      stream = gst_mpdparser_get_active_stream_by_index (demux->client, 0);
-      current_pos = 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;
-        if (current_pos <= target_pos
-            && target_pos < current_pos + chunk->duration) {
-          break;
-        }
+      /*select the requested segments for all streams*/
+      nb_active_stream = gst_mpdparser_get_nb_active_stream (demux->client);
+      seek_idx = g_malloc0(sizeof(gint)*nb_active_stream);
+      gint video_idx = gst_mpd_client_get_video_active_stream_id(demux->client);
+      if(video_idx >= 0) {
+        /*Seeking on video stream firstly.*/
+        GstClockTime segment_start;
+        segment_start = gst_mpd_client_stream_find_segment(demux->client, video_idx,
+                                                         target_pos, &seek_idx[video_idx]);
+        if(!GST_CLOCK_TIME_IS_VALID(segment_start))
+          goto no_segment;
+        target_pos = segment_start;
       }
-      //GST_MPD_CLIENT_UNLOCK (demux->client);
-
-      if (list == NULL) {
-        GST_WARNING_OBJECT (demux, "Could not find seeked fragment");
-        return FALSE;
+      /*Seeking on non video streams*/
+      for (stream_idx = 0; stream_idx < nb_active_stream; stream_idx++) {
+        if (video_idx != stream_idx) {
+          GstClockTime stream_start = gst_mpd_client_stream_find_segment(demux->client,
+                                          stream_idx, target_pos, &seek_idx[stream_idx]);
+          if(!GST_CLOCK_TIME_IS_VALID (stream_start)) {
+            goto no_segment;
+          }
+        }
       }
 
+seeking:
       /* We can actually perform the seek */
       nb_active_stream = gst_mpdparser_get_nb_active_stream (demux->client);
 
@@ -563,7 +602,9 @@ gst_dash_demux_src_event (GstPad * pad, GstEvent * event)
         GST_DEBUG_OBJECT (demux, "sending flush start");
         stream_idx = 0;
         while (stream_idx < nb_active_stream) {
-          gst_pad_push_event (demux->srcpad[stream_idx],
+          GstDashDemuxStream *dash_stream = g_slist_nth_data (demux->streams, stream_idx);
+         dash_stream->need_header = TRUE;
+          gst_pad_push_event (dash_stream->srcpad,
               gst_event_new_flush_start ());
           stream_idx++;
         }
@@ -572,32 +613,48 @@ gst_dash_demux_src_event (GstPad * pad, GstEvent * event)
       /* Stop the demux */
       demux->cancelled = TRUE;
       gst_dash_demux_stop (demux);
+      GST_DEBUG_OBJECT (demux, "joining tasks");
+      gst_task_join (demux->stream_task);
+      gst_task_join (demux->download_task);
+      GST_DEBUG_OBJECT (demux, "tasks was joined");
 
       /* Wait for streaming to finish */
       g_static_rec_mutex_lock (&demux->stream_lock);
 
-      /* Clear the buffering queue */
-      /* FIXME: allow seeking in the buffering queue */
-      gst_dash_demux_clear_queue (demux);
-
       //GST_MPD_CLIENT_LOCK (demux->client);
-      GST_DEBUG_OBJECT (demux, "Seeking to sequence %d", current_sequence);
-      /* Update the current sequence on all streams */
-      gst_mpd_client_set_segment_index_for_all_streams (demux->client,
-          current_sequence);
-      /* Calculate offset in the next fragment */
-      demux->position = gst_mpd_client_get_current_position (demux->client);
-      demux->position_shift = start - demux->position;
-      demux->need_segment = TRUE;
+      demux->end_of_period = end_of_mpd;
       //GST_MPD_CLIENT_UNLOCK (demux->client);
 
+
+      for (stream_idx = 0; stream_idx < nb_active_stream; stream_idx++) {
+        GstDashDemuxStream *dash_stream = g_slist_nth_data (demux->streams, stream_idx);
+        GstCaps *caps = gst_pad_get_negotiated_caps (dash_stream->srcpad);
+        if(caps) {
+          gst_caps_replace (&dash_stream->input_caps, NULL);
+          gst_caps_unref (caps);
+        }
+        if(!end_of_mpd) {
+          GST_DEBUG_OBJECT (demux, "Seeking to sequence %d on stream %d", seek_idx[stream_idx], stream_idx);
+          stream = gst_mpdparser_get_active_stream_by_index (demux->client, stream_idx);
+          gst_mpd_client_set_segment_index(stream, seek_idx[stream_idx]);
+        }
+        gst_data_queue_set_flushing(dash_stream->queue, FALSE);
+        dash_stream->start_time = target_pos;
+        dash_stream->download_end_of_period = end_of_mpd;
+        dash_stream->stream_end_of_period = end_of_mpd;
+        dash_stream->stream_eos = end_of_mpd;
+        dash_stream->need_segment = TRUE;
+      }
+      if(!end_of_mpd)
+        g_free(seek_idx);
+
       if (flags & GST_SEEK_FLAG_FLUSH) {
         GST_DEBUG_OBJECT (demux, "Sending flush stop on all pad");
-        stream_idx = 0;
-        while (stream_idx < nb_active_stream) {
-          gst_pad_push_event (demux->srcpad[stream_idx],
+
+        for (stream_idx = 0; stream_idx < nb_active_stream; stream_idx++) {
+          GstDashDemuxStream *dash_stream = g_slist_nth_data (demux->streams, stream_idx);
+          gst_pad_push_event (dash_stream->srcpad,
               gst_event_new_flush_stop ());
-          stream_idx++;
         }
       }
 
@@ -608,6 +665,12 @@ gst_dash_demux_src_event (GstPad * pad, GstEvent * event)
       g_static_rec_mutex_unlock (&demux->stream_lock);
 
       return TRUE;
+no_segment:
+      {
+        GST_WARNING_OBJECT (demux, "Could not find seeked fragment on stream %d", stream_idx);
+        g_free(seek_idx);
+        return FALSE;
+      }
     }
     default:
       break;
@@ -617,21 +680,25 @@ gst_dash_demux_src_event (GstPad * pad, GstEvent * event)
 }
 
 static gboolean
-gst_dash_demux_setup_all_streams (GstDashDemux * demux)
+gst_dash_demux_setup_mpdparser_streams (GstDashDemux * demux, GstMpdClient *client)
 {
   GList *listLang = NULL;
   guint i, nb_audio;
   gchar *lang;
 
-  GST_MPD_CLIENT_LOCK (demux->client);
+  GST_MPD_CLIENT_LOCK (client);
   /* clean old active stream list, if any */
-  gst_active_streams_free (demux->client);
+  gst_active_streams_free (client);
 
-  if (!gst_mpd_client_setup_streaming (demux->client, GST_STREAM_VIDEO, ""))
+  if (!gst_mpd_client_setup_streaming (client, GST_STREAM_VIDEO, "")) {
     GST_INFO_OBJECT (demux, "No video adaptation set found");
+  } else {
+    gst_mpd_client_get_max_video_dimensions(client, &demux->max_video_width,
+                                            &demux->max_video_height);
+  }
 
   nb_audio =
-      gst_mpdparser_get_list_and_nb_of_audio_language (demux->client,
+      gst_mpdparser_get_list_and_nb_of_audio_language (client,
       &listLang);
   if (nb_audio == 0)
     nb_audio = 1;
@@ -639,17 +706,61 @@ 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,
+    if (gst_mpdparser_get_nb_adaptationSet (client) > 1)
+      if (!gst_mpd_client_setup_streaming (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,
+    if (gst_mpdparser_get_nb_adaptationSet (client) > nb_audio)
+      if (!gst_mpd_client_setup_streaming (client,
               GST_STREAM_APPLICATION, lang))
         GST_INFO_OBJECT (demux, "No application adaptation set found");
   }
-  GST_MPD_CLIENT_UNLOCK (demux->client);
+  GST_MPD_CLIENT_UNLOCK (client);
+  return TRUE;
+}
+
+static gboolean
+gst_dash_demux_setup_all_streams (GstDashDemux * demux)
+{
+  guint i;
+  if( !gst_dash_demux_setup_mpdparser_streams(demux, demux->client))
+    return FALSE;
+
+  GST_DEBUG_OBJECT (demux, "Creating dashdemux streams");
+  gst_dash_demux_clear_streams(demux);
+  for ( i =0; i < gst_mpdparser_get_nb_active_stream (demux->client); i++) {
+    GstDashDemuxStream *dash_stream;
+    GstCaps *caps;
+    GstActiveStream *active_stream;
+    dash_stream = g_new0(GstDashDemuxStream, 1);
+    demux->streams = g_slist_append(demux->streams, dash_stream);
+    dash_stream->idx = i;
+    dash_stream->queue = gst_data_queue_new ((GstDataQueueCheckFullFunction) _check_queue_full, demux);
+    dash_stream->need_header = TRUE;
+    dash_stream->need_segment = TRUE;
+    dash_stream->start_time = GST_CLOCK_TIME_NONE;
+    gst_download_rate_init (&dash_stream->dnl_rate);
+    gst_download_rate_set_max_length (&dash_stream->dnl_rate,
+                                     DOWNLOAD_RATE_HISTORY_MAX);
+    gst_download_rate_set_aver_period (&dash_stream->dnl_rate,
+                                      DOWNLOAD_RATE_TIME_MAX);
+    /*Create stream pad*/
+    active_stream = gst_mpdparser_get_active_stream_by_index(demux->client, i);
+    caps = gst_dash_demux_get_input_caps(demux, active_stream);
+    dash_stream->srcpad = gst_pad_new_from_static_template (&srctemplate, NULL);
+    gst_pad_set_event_function (dash_stream->srcpad,
+        GST_DEBUG_FUNCPTR (gst_dash_demux_src_event));
+    gst_pad_set_query_function (dash_stream->srcpad,
+        GST_DEBUG_FUNCPTR (gst_dash_demux_src_query));
+    gst_pad_set_element_private (dash_stream->srcpad, demux);
+    gst_pad_set_active (dash_stream->srcpad, TRUE);
+    gst_pad_set_caps (dash_stream->srcpad, caps);
+    gst_caps_unref(caps);
+    gst_element_add_pad (GST_ELEMENT (demux), gst_object_ref (dash_stream->srcpad));
+  }
+  /* Send 'no-more-pads' to have decodebin create the new group */
+  gst_element_no_more_pads (GST_ELEMENT (demux));
 
   return TRUE;
 }
@@ -699,6 +810,7 @@ gst_dash_demux_sink_event (GstPad * pad, GstEvent * event)
             (NULL));
         return FALSE;
       }
+
       gst_buffer_unref (demux->manifest);
       demux->manifest = NULL;
 
@@ -840,188 +952,20 @@ static void
 gst_dash_demux_stop (GstDashDemux * demux)
 {
   gst_uri_downloader_cancel (demux->downloader);
+  gst_dash_demux_flush_stream_queues (demux);
 
   if (GST_TASK_STATE (demux->download_task) != GST_TASK_STOPPED) {
     GST_TASK_SIGNAL (demux->download_task);
     gst_task_stop (demux->download_task);
+    g_mutex_lock (&demux->download_mutex);
+    g_cond_signal (&demux->download_cond);
+    g_mutex_unlock (&demux->download_mutex);
   }
   if (GST_TASK_STATE (demux->stream_task) != GST_TASK_STOPPED) {
     GST_TASK_SIGNAL (demux->stream_task);
     gst_task_stop (demux->stream_task);
   }
 }
-#ifdef DASHDEMUX_MODIFICATION
-static void
-_update_caps(GstDashDemux * demux, guint nb_adaptation_set)
-{
-  guint i = 0;
-  GstCaps *caps;
-
-  /* Create and activate new pads */
-  i = 0;
-  while (i < nb_adaptation_set) {
-    caps = gst_pad_get_caps(demux->srcpad[i]);
-    if(caps){
-      caps = gst_caps_make_writable(caps);
-      gst_caps_replace(&caps,demux->output_caps[i]);
-    }
-    else{
-      caps = demux->output_caps[i];
-    }
-    gst_pad_use_fixed_caps (demux->srcpad[i]);
-    gst_pad_set_caps (demux->srcpad[i], caps);
-    gst_caps_unref(caps);
-    i++;
-  }
-}
-
-static void
-_add_pads(GstDashDemux * demux, guint nb_adaptation_set)
-{
-  guint i = 0;
-
-  /* Create and activate new pads */
-  i = 0;
-  while (i < nb_adaptation_set) {
-    demux->srcpad[i] = gst_pad_new_from_static_template (&srctemplate, NULL);
-    gst_pad_set_event_function (demux->srcpad[i],
-        GST_DEBUG_FUNCPTR (gst_dash_demux_src_event));
-    gst_pad_set_query_function (demux->srcpad[i],
-        GST_DEBUG_FUNCPTR (gst_dash_demux_src_query));
-    gst_pad_set_element_private (demux->srcpad[i], demux);
-    gst_pad_set_active (demux->srcpad[i], TRUE);
-    gst_pad_set_caps (demux->srcpad[i], demux->output_caps[i]);
-    gst_caps_unref(demux->output_caps[i]);
-    gst_element_add_pad (GST_ELEMENT (demux), demux->srcpad[i]);
-    i++;
-  }
-  /* Send 'no-more-pads' to have decodebin create the new group */
-  gst_element_no_more_pads (GST_ELEMENT (demux));
-}
-
-static gboolean
-_needs_caps_update (GstDashDemux * demux, GList * fragment)
-{
-
-  gboolean update_caps = FALSE;
-  guint i = 0;
-  while (i < g_list_length (fragment)) {
-    GstFragment *newFragment = g_list_nth_data (fragment, i);
-    if (newFragment == NULL) {
-      continue;
-    }
-    GstCaps *srccaps = NULL;
-    demux->output_caps[i] = gst_fragment_get_caps (newFragment);
-    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)) {
-      update_caps = TRUE;
-    }
-    if (G_LIKELY (srccaps))
-      gst_caps_unref (srccaps);
-    i++;
-  }
-  return update_caps;
-}
-
-#else
-/* switch_pads:
- *
- * Called when switching from one set of representations to another, but
- * only if one of the new representations requires different downstream
- * elements (see the next function).
- *
- * This function first creates the new pads, then sends a no-more-pads
- * event (that will tell decodebin to create a new group), then sends
- * EOS on the old pads to trigger the group switch.
- *
- */
-static void
-switch_pads (GstDashDemux * demux, guint nb_adaptation_set)
-{
-  GstPad *oldpad[MAX_LANGUAGES];
-  guint i = 0;
-  /* Remember old pads */
-  while (i < nb_adaptation_set) {
-    oldpad[i] = demux->srcpad[i];
-    if (oldpad[i]) {
-      GST_DEBUG_OBJECT (demux,
-          "Switching pads (oldpad:%p)" GST_PTR_FORMAT, oldpad[i]);
-    }
-    i++;
-  }
-  /* Create and activate new pads */
-  i = 0;
-  while (i < nb_adaptation_set) {
-    demux->srcpad[i] = gst_pad_new_from_static_template (&srctemplate, NULL);
-    gst_pad_set_event_function (demux->srcpad[i],
-        GST_DEBUG_FUNCPTR (gst_dash_demux_src_event));
-    gst_pad_set_query_function (demux->srcpad[i],
-        GST_DEBUG_FUNCPTR (gst_dash_demux_src_query));
-    gst_pad_set_element_private (demux->srcpad[i], demux);
-    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]);
-    i++;
-  }
-  /* Send 'no-more-pads' to have decodebin create the new group */
-  gst_element_no_more_pads (GST_ELEMENT (demux));
-  /* Push out EOS on all old pads to switch to the new group */
-  i = 0;
-  while (i < nb_adaptation_set) {
-    if (oldpad[i]) {
-      gst_pad_push_event (oldpad[i], gst_event_new_eos ());
-      gst_pad_set_active (oldpad[i], FALSE);
-      gst_element_remove_pad (GST_ELEMENT (demux), oldpad[i]);
-    }
-    i++;
-  }
-}
-
-/* needs_pad_switch:
- *
- * Figure out if the newly selected representations require a new set
- * of demuxers and decoders or if we can carry on with the existing ones.
- *
- * Basically, we look at the list of fragments we need to push downstream,
- * and compare their caps with those of the corresponding src pads.
- *
- * As soon as one fragment requires a new set of caps, we need to switch
- * all decoding pads to recreate a whole decoding group as we cannot
- * move pads between groups (FIXME: or can we ?).
- *
- * FIXME: redundant with need_add_header
- *
- */
-static gboolean
-needs_pad_switch (GstDashDemux * demux, GList * fragment)
-{
-
-  gboolean switch_pad = FALSE;
-  guint i = 0;
-  while (i < g_list_length (fragment)) {
-    GstFragment *newFragment = g_list_nth_data (fragment, i);
-    if (newFragment == NULL) {
-      continue;
-    }
-    GstCaps *srccaps = NULL;
-    demux->output_caps[i] = gst_fragment_get_caps (newFragment);
-    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)) {
-      switch_pad = TRUE;
-    }
-    if (G_LIKELY (srccaps))
-      gst_caps_unref (srccaps);
-    i++;
-  }
-  return switch_pad;
-}
-#endif
 
 /* gst_dash_demux_stream_loop:
  *
@@ -1046,100 +990,115 @@ needs_pad_switch (GstDashDemux * demux, GList * fragment)
 static void
 gst_dash_demux_stream_loop (GstDashDemux * demux)
 {
-  GList *listfragment;
   GstFlowReturn ret;
-  GstBufferList *buffer_list;
-  guint nb_adaptation_set = 0;
-  GstActiveStream *stream;
-
-  /* Wait until the next scheduled push downstream */
-  if (g_cond_timed_wait (GST_TASK_GET_COND (demux->stream_task),
-          demux->stream_timed_lock, &demux->next_push)) {
-    goto quit;
-  }
+  GstActiveStream *active_stream;
+  GstDashDemuxStream *selected_stream = NULL;
+  GstClockTime min_ts = GST_CLOCK_TIME_NONE;
+  guint i = 0;
+  gboolean eos = TRUE;
+  gboolean eop = TRUE;
 
-  if (g_queue_is_empty (demux->queue)) {
-    if (demux->end_of_manifest)
-      goto end_of_manifest;
+  for (i = 0; i < g_slist_length (demux->streams); i++) {
+    GstDashDemuxStream *dash_stream = g_slist_nth_data (demux->streams, i);
+    GstBuffer *buffer;
+    GstDataQueueItem *item;
 
-    return;
-  }
+    if (dash_stream->stream_eos) {
+      GST_DEBUG_OBJECT (demux, "Stream %d is eos, skipping", dash_stream->idx);
+      continue;
+    }
 
-  if (GST_STATE (demux) == GST_STATE_PLAYING) {
-    if (!demux->end_of_manifest
-        && gst_dash_demux_get_buffering_time (demux) <
-        demux->min_buffering_time) {
-      /* Warn we are below our 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)));
+    if (dash_stream->stream_end_of_period) {
+      GST_DEBUG_OBJECT (demux, "Stream %d is eop, skipping", dash_stream->idx);
+      eos = FALSE;
+      continue;
     }
-  }
-  listfragment = g_queue_pop_head (demux->queue);
-  nb_adaptation_set = g_list_length (listfragment);
-#ifdef DASHDEMUX_MODIFICATION
-  /* Figure out if we need to create pads or update caps */
-  gboolean caps_changed = _needs_caps_update (demux, listfragment);
-  if (caps_changed) {
-    if(demux->srcpad[0] == NULL)
-    {
-      _add_pads(demux,nb_adaptation_set);
-      demux->need_segment = TRUE;
-    }else{
-      _update_caps(demux,nb_adaptation_set);
+    eos = FALSE;
+    eop = FALSE;
+
+    if (!gst_data_queue_peek (dash_stream->queue, &item))
+      goto flushing;
+
+    if(GST_IS_BUFFER(item->object)) {
+      buffer = GST_BUFFER(item->object);
+      if(GST_BUFFER_TIMESTAMP(buffer) < min_ts ||
+         !GST_CLOCK_TIME_IS_VALID(min_ts)) {
+        min_ts = GST_BUFFER_TIMESTAMP(buffer);
+        selected_stream = dash_stream;
+      } else if (!GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (item->object))) {
+        selected_stream = dash_stream;
+        break;
+      }
+    } else {
+      selected_stream = dash_stream;
+      break;
     }
   }
-#else
-  /* Figure out if we need to create/switch pads */
-  gboolean switch_pad = needs_pad_switch (demux, listfragment);
-  if (switch_pad) {
-    switch_pads (demux, nb_adaptation_set);
-    demux->need_segment = TRUE;
-  }
-#endif
-  guint i = 0;
-  for (i = 0; i < nb_adaptation_set; i++) {
-    GstFragment *fragment = g_list_nth_data (listfragment, i);
-    stream = gst_mpdparser_get_active_stream_by_index (demux->client, i);
-    if (demux->need_segment) {
-      GstClockTime start = fragment->start_time + demux->position_shift;
-      /* And send a newsegment */
-      GST_DEBUG_OBJECT (demux, "Sending new-segment. segment start:%"
-          GST_TIME_FORMAT, GST_TIME_ARGS (start));
-      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);
-    buffer_list = gst_fragment_get_buffer_list (fragment);
-    g_object_unref (fragment);
-    ret = gst_pad_push_list (demux->srcpad[i], buffer_list);
-    if ((ret != GST_FLOW_OK) && (stream->mimeType == GST_STREAM_VIDEO))
-      goto error_pushing;
-  }
-  demux->need_segment = FALSE;
-  g_list_free (listfragment);
-  GST_STATE_LOCK(demux);
-  if (GST_STATE (demux) == GST_STATE_PLAYING) {
-    /* Wait for the duration of a fragment before resuming this task */
-    g_get_current_time (&demux->next_push);
-    g_time_val_add (&demux->next_push,
-        gst_mpd_client_get_next_fragment_duration (demux->client)
-        / GST_SECOND * G_USEC_PER_SEC);
-    GST_DEBUG_OBJECT (demux, "Next push scheduled at %s",
-        g_time_val_to_iso8601 (&demux->next_push));
+  if(selected_stream) {
+    GstBuffer *buffer;
+    GstDataQueueItem *item;
+
+    if (!gst_data_queue_pop (selected_stream->queue, &item))
+      goto end;
+    if ( GST_IS_BUFFER (item->object)) {
+      buffer = GST_BUFFER(item->object);
+      active_stream = gst_mpdparser_get_active_stream_by_index (demux->client, selected_stream->idx);
+
+      if (selected_stream->need_segment) {
+        if(!GST_CLOCK_TIME_IS_VALID (selected_stream->start_time)) {
+          if(GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))){
+            selected_stream->start_time = GST_BUFFER_TIMESTAMP (buffer);
+          } else {
+            selected_stream->start_time = 0;
+          }
+        }
+        /* And send a newsegment */
+        GST_DEBUG_OBJECT (demux, "Sending new-segment stream #%d. segment start:%"
+            GST_TIME_FORMAT, selected_stream->idx, GST_TIME_ARGS (selected_stream->start_time));
+        gst_pad_push_event (selected_stream->srcpad,
+            gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME,
+                selected_stream->start_time, GST_CLOCK_TIME_NONE, selected_stream->start_time));
+        selected_stream->need_segment = FALSE;
+      }
+
+      GST_DEBUG_OBJECT (demux, "Pushing fragment #%llu (stream %d) ts=%"GST_TIME_FORMAT, GST_BUFFER_OFFSET (buffer),
+                        selected_stream->idx, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
+      ret = gst_pad_push (selected_stream->srcpad, gst_buffer_ref(buffer) );
+      item->destroy (item);
+      if ((ret != GST_FLOW_OK) && (active_stream->mimeType == GST_STREAM_VIDEO))
+        goto error_pushing;
+    } else {
+      GstEvent *event = GST_EVENT (item->object);
+      if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
+        selected_stream->stream_eos = TRUE;
+        selected_stream->stream_end_of_period = TRUE;
+      } else if (GST_EVENT_TYPE (event) == GST_EVENT_DASH_EOP) {
+        selected_stream->stream_end_of_period = TRUE;
+      }
+
+      if (GST_EVENT_TYPE (item->object) != GST_EVENT_DASH_EOP) {
+        gst_pad_push_event (selected_stream->srcpad,
+            gst_event_ref (GST_EVENT_CAST (item->object)));
+      }
+
+      item->destroy (item);
+    }
   } else {
-    /* The pipeline is now set up, wait until playback begins */
-    GST_INFO_OBJECT (demux, "Pausing streaming task");
-    gst_task_pause (demux->stream_task);
+    if (eos) {
+      goto end_of_manifest;
+    } else if (eop) {
+      /*TODO Switch to next period*/
+    }
   }
-  GST_STATE_UNLOCK(demux);
 
-quit:
+end:
+  return;
+
+flushing:
   {
+    GST_INFO_OBJECT (demux, "Queue is flushing. Stopped streaming task");
+    gst_task_stop (demux->stream_task);
     return;
   }
 
@@ -1148,7 +1107,8 @@ end_of_manifest:
     GST_INFO_OBJECT (demux, "Reached end of manifest, sending EOS");
     guint i = 0;
     for (i = 0; i < gst_mpdparser_get_nb_active_stream (demux->client); i++) {
-      gst_pad_push_event (demux->srcpad[i], gst_event_new_eos ());
+      GstDashDemuxStream *dash_stream = g_slist_nth_data (demux->streams, i);
+      gst_pad_push_event (dash_stream->srcpad, gst_event_new_eos ());
     }
     GST_INFO_OBJECT (demux, "Stopped streaming task");
     gst_task_stop (demux->stream_task);
@@ -1167,18 +1127,37 @@ error_pushing:
 }
 
 static void
+gst_dash_demux_clear_streams(GstDashDemux * demux) {
+  guint i = 0;
+  gst_dash_demux_flush_stream_queues (demux);
+  for (i = 0; i < g_slist_length(demux->streams); i++) {
+    GstDashDemuxStream *dash_stream = g_slist_nth_data (demux->streams, i);
+    gst_download_rate_deinit (&dash_stream->dnl_rate);
+    if (dash_stream->input_caps) {
+      gst_caps_unref (dash_stream->input_caps);
+      dash_stream->input_caps = NULL;
+    }
+    if (dash_stream->srcpad) {
+      gst_object_unref (dash_stream->srcpad);
+      dash_stream->srcpad = NULL;
+    }
+    /*TODO consider unref stream->output_caps*/
+    g_object_unref (dash_stream->queue);
+  }
+  if(demux->streams) {
+    g_slist_free(demux->streams);
+    demux->streams = NULL;
+  }
+}
+
+static void
 gst_dash_demux_reset (GstDashDemux * demux, gboolean dispose)
 {
+  gint stream_idx;
   demux->end_of_period = FALSE;
-  demux->end_of_manifest = FALSE;
   demux->cancelled = FALSE;
 
-  guint i = 0;
-  for (i = 0; i < MAX_LANGUAGES; i++)
-    if (demux->input_caps[i]) {
-      gst_caps_unref (demux->input_caps[i]);
-      demux->input_caps[i] = NULL;
-    }
+  gst_dash_demux_clear_streams(demux);
 
   if (demux->manifest) {
     gst_buffer_unref (demux->manifest);
@@ -1192,74 +1171,218 @@ gst_dash_demux_reset (GstDashDemux * demux, gboolean dispose)
     demux->client = gst_mpd_client_new ();
   }
 
-  gst_dash_demux_clear_queue (demux);
-
   demux->last_manifest_update = GST_CLOCK_TIME_NONE;
-  demux->position = 0;
-  demux->position_shift = 0;
-  demux->need_segment = TRUE;
+  for (stream_idx = 0; stream_idx < g_slist_length (demux->streams); stream_idx++) {
+    GstDashDemuxStream *dash_stream = g_slist_nth_data (demux->streams, stream_idx);
+    dash_stream->need_segment = TRUE;
+  }
 }
 
 static GstClockTime
 gst_dash_demux_get_buffering_time (GstDashDemux * demux)
 {
   GstClockTime buffer_time = 0;
-  GList *listfragment;
-  GstFragment *first_fragment, *last_fragment;
+  GSList *it;
+  GstDashDemuxStream *stream;
+  GstDataQueueSize queue_size;
 
-  if (g_queue_is_empty (demux->queue))
-    return 0;
+  for(it=demux->streams; it; it=it->next) {
+    stream = it->data;
+    gst_data_queue_get_level(stream->queue, &queue_size);
 
-  /* get first fragment */
-  listfragment = g_queue_peek_head (demux->queue);
-  first_fragment = listfragment->data;
-  /* get last fragment */
-  listfragment = g_queue_peek_tail (demux->queue);
-  last_fragment = listfragment->data;
-
-  if (first_fragment && last_fragment) {
-    buffer_time = last_fragment->stop_time - first_fragment->start_time;
+    if (queue_size.time > 0) {
+      buffer_time = queue_size.time;
+      break;
+    }
   }
 
   return buffer_time;
 }
 
-static float
-gst_dash_demux_get_buffering_ratio (GstDashDemux * demux)
+static gboolean
+gst_dash_demux_update_manifest(GstDashDemux *demux) {
+  GstFragment *download;
+  GstBuffer *buffer;
+  GstClockTime duration, now = gst_util_get_timestamp();
+  gint64 update_period = demux->client->mpd_node->minimumUpdatePeriod;
+
+  if (update_period == -1) {
+    GST_DEBUG_OBJECT (demux, "minimumUpdatePeriod unspecified, will not update MPD");
+    return TRUE;
+  }
+
+  /* init reference time for manifest file updates */
+  if (!GST_CLOCK_TIME_IS_VALID (demux->last_manifest_update))
+    demux->last_manifest_update = now;
+
+  /* update the manifest file */
+  if (now >= demux->last_manifest_update + update_period * GST_MSECOND) {
+    GST_DEBUG_OBJECT (demux, "Updating manifest file from URL %s",
+        demux->client->mpd_uri);
+    download =
+        gst_uri_downloader_fetch_uri (demux->downloader,
+        demux->client->mpd_uri);
+    if (download == NULL) {
+      GST_WARNING_OBJECT (demux,
+          "Failed to update the manifest file from URL %s",
+          demux->client->mpd_uri);
+    } else {
+      GstMpdClient *new_client = NULL;
+      guint period_idx;
+      const gchar *period_id;
+      GSList *iter;
+
+      buffer = gst_fragment_get_buffer(download);
+      g_object_unref (download);
+      /* parse the manifest file */
+      if (buffer == NULL) {
+        GST_WARNING_OBJECT (demux, "Error validating the manifest.");
+        return TRUE;
+      }
+
+      new_client = gst_mpd_client_new ();
+      new_client->mpd_uri = g_strdup (demux->client->mpd_uri);
+      if (!gst_mpd_parse (new_client,
+              (gchar *) GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (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_WARNING_OBJECT (demux, "Error parsing the manifest.");
+        gst_buffer_unref (buffer);
+        return TRUE;
+      }
+
+      gst_buffer_unref (buffer);
+      GST_DEBUG_OBJECT (demux, "Updating manifest");
+
+      period_id = gst_mpd_client_get_period_id (demux->client);
+      period_idx = gst_mpd_client_get_period_index (demux->client);
+
+      /* setup video, audio and subtitle streams, starting from current Period */
+      if (!gst_mpd_client_setup_media_presentation (new_client)) {
+        /* TODO */
+      }
+
+      if (period_idx) {
+        /*If more than one period exists.*/
+        if (!gst_mpd_client_set_period_id (new_client, period_id)) {
+          GST_DEBUG_OBJECT (demux,
+              "Error setting up the updated manifest file");
+          return FALSE;
+        }
+      } else {
+        if (!gst_mpd_client_set_period_index (new_client, period_idx)) {
+          GST_DEBUG_OBJECT (demux,
+              "Error setting up the updated manifest file");
+          return FALSE;
+        }
+      }
+
+      if (!gst_dash_demux_setup_mpdparser_streams (demux, new_client)) {
+            GST_ERROR_OBJECT (demux, "Failed to setup streams on manifest "
+                "update");
+            return FALSE;
+      }
+
+      /* update the streams to play from the next segment */
+      for (iter = demux->streams; iter; iter = g_slist_next (iter)) {
+        GstDashDemuxStream *demux_stream = iter->data;
+        GstActiveStream *new_stream;
+        GstClockTime ts;
+
+        new_stream = gst_mpdparser_get_active_stream_by_index (new_client,
+            demux_stream->idx);
+
+        if (!new_stream) {
+          GST_DEBUG_OBJECT (demux,
+              "Stream of index %d is missing from manifest update",
+              demux_stream->idx);
+          return FALSE;
+        }
+
+        if (gst_mpd_client_get_next_fragment_timestamp (demux->client,
+                demux_stream->idx, &ts)) {
+          gst_mpd_client_stream_seek (new_client, demux_stream->idx, ts);
+
+        } else
+            if (gst_mpd_client_get_last_fragment_timestamp (demux->client,
+                demux_stream->idx, &ts)) {
+          /* try to set to the old timestamp + 1 */
+          gst_mpd_client_stream_seek (new_client, demux_stream->idx, ts+1);
+        }
+      }
+
+      /*Remember download failed count*/
+      new_client->download_failed_count = demux->client->download_failed_count;
+
+      gst_mpd_client_free (demux->client);
+      demux->client = new_client;
+
+      /* Send an updated duration message */
+      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,
+            GST_TIME_ARGS (duration));
+        gst_element_post_message (GST_ELEMENT (demux),
+            gst_message_new_duration(GST_OBJECT (demux), GST_FORMAT_TIME, duration));
+      } else {
+        GST_DEBUG_OBJECT (demux,
+            "mediaPresentationDuration unknown, can not send the duration message");
+      }
+      demux->last_manifest_update = gst_util_get_timestamp ();
+      GST_DEBUG_OBJECT (demux, "Manifest file successfully updated");
+    }
+  }
+  return TRUE;
+}
+
+static void
+gst_dash_demux_download_wait (GstDashDemux * demux, GstClockTime time_diff)
 {
-  float buffering_time = gst_dash_demux_get_buffering_time (demux);
-  if (buffering_time >= demux->min_buffering_time) {
-    return 1.0;
-  } else
-    return buffering_time / demux->min_buffering_time;
+  gint64 end_time = g_get_monotonic_time () + time_diff / GST_USECOND;
+
+  GST_DEBUG_OBJECT (demux, "Download waiting for %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (time_diff));
+  g_cond_wait_until (&demux->download_cond, &demux->download_mutex, end_time);
+  GST_DEBUG_OBJECT (demux, "Download finished waiting");
 }
 
-static GstBuffer *
-gst_dash_demux_merge_buffer_list (GstFragment * fragment)
+static void
+gst_dash_demux_check_live(GstDashDemux* demux, GstActiveStream *fragment_stream,
+     GstClockTime fragment_ts)
 {
-  GstBufferList *list;
-  GstBufferListIterator *it;
-  GstBuffer *buffer, *ret = NULL;
-  GstAdapter *adapter;
-  gsize size;
-
-  adapter = gst_adapter_new ();
-  list = gst_fragment_get_buffer_list (fragment);
-  it = gst_buffer_list_iterate (list);
-  while (gst_buffer_list_iterator_next_group (it)) {
-    while ((buffer = gst_buffer_list_iterator_next (it)) != NULL) {
-      gst_adapter_push (adapter, gst_buffer_ref (buffer));
-    }
+  gint64 time_diff;
+  gint pos;
+
+  pos =
+      gst_mpd_client_check_time_position (demux->client, fragment_stream,
+      fragment_ts, &time_diff);
+  GST_DEBUG_OBJECT (demux,
+      "Checked position for fragment ts %" GST_TIME_FORMAT
+      ", res: %d, diff: %" G_GINT64_FORMAT, GST_TIME_ARGS (fragment_ts),
+      pos, time_diff);
+
+  time_diff *= GST_USECOND;
+  if (pos < 0) {
+    /* we're behind, try moving to the 'present' */
+    GDateTime *now = g_date_time_new_now_utc ();
+
+    GST_DEBUG_OBJECT (demux,
+        "Falling behind live stream, moving forward");
+      gst_mpd_client_seek_to_time(demux->client, now);
+    g_date_time_unref (now);
+
+  } else if (pos > 0) {
+    /* we're ahead, wait a little */
+
+    GST_DEBUG_OBJECT (demux, "Waiting for next segment to be created");
+    gst_dash_demux_download_wait (demux, time_diff);
+  } else {
+    demux->client->download_failed_count++;
   }
-  gst_buffer_list_iterator_free (it);
-  gst_buffer_list_unref (list);
-  size = gst_adapter_available (adapter);
-  if (size > 0)
-    ret = gst_adapter_take_buffer (adapter, size);
-  GST_DEBUG ("Extracted a buffer of size %d from the fragment", size);
-  g_object_unref (adapter);
-
-  return ret;
 }
 
 /* gst_dash_demux_download_loop:
@@ -1293,157 +1416,57 @@ gst_dash_demux_merge_buffer_list (GstFragment * fragment)
 void
 gst_dash_demux_download_loop (GstDashDemux * demux)
 {
-  GstClock *clock = gst_element_get_clock (GST_ELEMENT (demux));
-  gint64 update_period = demux->client->mpd_node->minimumUpdatePeriod;
-
-  /* Wait until the next scheduled download */
-  if (g_cond_timed_wait (GST_TASK_GET_COND (demux->download_task),
-          demux->download_timed_lock, &demux->next_download)) {
-    goto quit;
+  GstActiveStream *fragment_stream = NULL;
+  GstClockTime fragment_ts;
+  if ( gst_mpd_client_is_live (demux->client) && demux->client->mpd_uri != NULL ) {
+    if (!gst_dash_demux_update_manifest(demux))
+      goto end_of_manifest;
   }
 
-  if (clock && gst_mpd_client_is_live (demux->client)
-      && demux->client->mpd_uri != NULL && update_period != -1) {
-    GstFragment *download;
-    GstBuffer *buffer;
-    GstClockTime duration, now = gst_clock_get_time (clock);
-
-    /* init reference time for manifest file updates */
-    if (!GST_CLOCK_TIME_IS_VALID (demux->last_manifest_update))
-      demux->last_manifest_update = now;
-
-    /* update the manifest file */
-    if (now >= demux->last_manifest_update + update_period * GST_MSECOND) {
-      GST_DEBUG_OBJECT (demux, "Updating manifest file from URL %s",
-          demux->client->mpd_uri);
-      download =
-          gst_uri_downloader_fetch_uri (demux->downloader,
-          demux->client->mpd_uri);
-      if (download == NULL) {
-        GST_WARNING_OBJECT (demux,
-            "Failed to update the manifest file from URL %s",
-            demux->client->mpd_uri);
+  /* try to switch to another set of representations if needed */
+  gst_dash_demux_select_representations (demux);
+
+  /* fetch the next fragment */
+  while (!gst_dash_demux_get_next_fragment (demux, &fragment_stream, &fragment_ts)) {
+    if (demux->end_of_period) {
+      GST_INFO_OBJECT (demux, "Reached the end of the Period");
+      /* setup video, audio and subtitle streams, starting from the next Period */
+      if (!gst_mpd_client_set_period_index (demux->client,
+              gst_mpd_client_get_period_index (demux->client) + 1)
+          || !gst_dash_demux_setup_all_streams (demux)) {
+        GST_INFO_OBJECT (demux, "Reached the end of the manifest file");
+        gst_task_start (demux->stream_task);
+        goto end_of_manifest;
+      }
+      /* start playing from the first segment of the new period */
+      gst_mpd_client_set_segment_index_for_all_streams (demux->client, 0);
+      demux->end_of_period = FALSE;
+    } else if (!demux->cancelled) {
+      gst_uri_downloader_reset (demux->downloader);
+      if(gst_mpd_client_is_live (demux->client)) {
+        gst_dash_demux_check_live (demux, fragment_stream, fragment_ts);
       } else {
-        buffer = gst_dash_demux_merge_buffer_list (download);
-        g_object_unref (download);
-        /* parse the manifest file */
-        if (buffer == NULL) {
-          GST_WARNING_OBJECT (demux, "Error validating the manifest.");
-        } else if (!gst_mpd_parse (demux->client,
-                (gchar *) GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (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_WARNING_OBJECT (demux, "Error parsing the manifest.");
-          gst_buffer_unref (buffer);
-        } else {
-          GstActiveStream *stream;
-          guint segment_index;
-
-          gst_buffer_unref (buffer);
-          stream = gst_mpdparser_get_active_stream_by_index (demux->client, 0);
-          segment_index = gst_mpd_client_get_segment_index (stream);
-          /* setup video, audio and subtitle streams, starting from first Period */
-          if (!gst_mpd_client_setup_media_presentation (demux->client) ||
-              !gst_mpd_client_set_period_index (demux->client,
-                  gst_mpd_client_get_period_index (demux->client))
-              || !gst_dash_demux_setup_all_streams (demux)) {
-            GST_DEBUG_OBJECT (demux,
-                "Error setting up the updated manifest file");
-            goto end_of_manifest;
-          }
-          /* continue playing from the the next segment */
-          /* FIXME: support multiple streams with different segment duration */
-          gst_mpd_client_set_segment_index_for_all_streams (demux->client,
-              segment_index);
-
-          /* Send an updated duration message */
-          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,
-                GST_TIME_ARGS (duration));
-            gst_element_post_message (GST_ELEMENT (demux),
-                gst_message_new_duration (GST_OBJECT (demux), GST_FORMAT_TIME,
-                    duration));
-          } else {
-            GST_DEBUG_OBJECT (demux,
-                "mediaPresentationDuration unknown, can not send the duration message");
-          }
-          demux->last_manifest_update += update_period * GST_MSECOND;
-          GST_DEBUG_OBJECT (demux, "Manifest file successfully updated");
-        }
+        demux->client->download_failed_count++;
       }
-    }
-  }
-
-
-  /* Target buffering time MUST at least exceeds mimimum buffering time
-   * by the duration of a fragment, but SHOULD NOT exceed maximum
-   * buffering time */
-  GstClockTime target_buffering_time =
-      demux->min_buffering_time +
-      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
-      && gst_dash_demux_get_buffering_time (demux) < target_buffering_time) {
-    if (GST_STATE (demux) != GST_STATE_PLAYING) {
-      /* Signal our buffering status (this will eventually restart the
-       * pipeline when we have reached 100 %) */
-      gst_element_post_message (GST_ELEMENT (demux),
-          gst_message_new_buffering (GST_OBJECT (demux),
-              100 * gst_dash_demux_get_buffering_ratio (demux)));
-    }
 
-    /* try to switch to another set of representations if needed */
-    gst_dash_demux_select_representations (demux,
-        demux->bandwidth_usage * demux->dnl_rate *
-        gst_dash_demux_get_buffering_ratio (demux));
-
-    /* fetch the next fragment */
-    while (!gst_dash_demux_get_next_fragment_set (demux)) {
-      if (demux->end_of_period) {
-        GST_INFO_OBJECT (demux, "Reached the end of the Period");
-        /* setup video, audio and subtitle streams, starting from the next Period */
-        if (!gst_mpd_client_set_period_index (demux->client,
-                gst_mpd_client_get_period_index (demux->client) + 1)
-            || !gst_dash_demux_setup_all_streams (demux)) {
-          GST_INFO_OBJECT (demux, "Reached the end of the manifest file");
-          demux->end_of_manifest = TRUE;
-          if (GST_STATE (demux) != GST_STATE_PLAYING) {
-            /* Restart the pipeline regardless of the current buffering level */
-            gst_element_post_message (GST_ELEMENT (demux),
-                gst_message_new_buffering (GST_OBJECT (demux), 100));
-          }
-          gst_task_start (demux->stream_task);
-          goto end_of_manifest;
-        }
-        /* start playing from the first segment of the new period */
-        gst_mpd_client_set_segment_index_for_all_streams (demux->client, 0);
-        demux->end_of_period = FALSE;
-      } else if (!demux->cancelled) {
-        demux->client->update_failed_count++;
-        if (demux->client->update_failed_count < DEFAULT_FAILED_COUNT) {
-          GST_WARNING_OBJECT (demux, "Could not fetch the next fragment");
-          goto quit;
-        } else {
-          goto error_downloading;
-        }
-      } else {
+      if (demux->client->download_failed_count < DEFAULT_FAILED_COUNT) {
+        GST_WARNING_OBJECT (demux, "Could not fetch the next fragment");
         goto quit;
+      } else if (gst_mpd_client_set_next_baseURL_for_stream (demux->client)) {
+       GST_INFO_OBJECT (demux, "Current baseURL is %s. Trying to select another",
+                        gst_mpdparser_get_baseURL (demux->client));
+       demux->client->download_failed_count = 0;
+      } else {
+        goto error_downloading;
       }
+    } else {
+      goto quit;
     }
-    GST_INFO_OBJECT (demux, "Internal buffering : %" PRIu64 " s",
-        gst_dash_demux_get_buffering_time (demux) / GST_SECOND);
-    demux->client->update_failed_count = 0;
-  } else {
-    /* schedule the next download in 100 ms */
-    g_get_current_time (&demux->next_download);
-    g_time_val_add (&demux->next_download, 100000);
   }
+  GST_INFO_OBJECT (demux, "Internal buffering : %" PRIu64 " s",
+      gst_dash_demux_get_buffering_time (demux) / GST_SECOND);
+  demux->client->download_failed_count = 0;
+
 
 quit:
   {
@@ -1467,25 +1490,15 @@ error_downloading:
 }
 
 static void
-gst_dash_demux_pause_stream_task (GstDashDemux * demux)
-{
-  /* Send a signal to the stream task so that it pauses itself */
-  GST_TASK_SIGNAL (demux->stream_task);
-  /* Pause it explicitly (if it was not in the COND) */
-  gst_task_pause (demux->stream_task);
-}
-
-static void
 gst_dash_demux_resume_stream_task (GstDashDemux * demux)
 {
-  g_get_current_time (&demux->next_push);
   gst_task_start (demux->stream_task);
 }
 
 static void
 gst_dash_demux_resume_download_task (GstDashDemux * demux)
 {
-  g_get_current_time (&demux->next_download);
+  gst_uri_downloader_reset(demux->downloader);
   gst_task_start (demux->download_task);
 }
 
@@ -1502,25 +1515,36 @@ gst_dash_demux_resume_download_task (GstDashDemux * demux)
  * Returns TRUE if a new set of representations has been selected
  */
 static gboolean
-gst_dash_demux_select_representations (GstDashDemux * demux, guint64 bitrate)
+gst_dash_demux_select_representations (GstDashDemux * demux)
 {
-  GstActiveStream *stream = NULL;
+  GstDashDemuxStream *stream = NULL;
+  GstActiveStream *active_stream = NULL;
   GList *rep_list = NULL;
+  GSList *iter;
   gint new_index;
   gboolean ret = FALSE;
 
-  guint i = 0;
-  while (i < gst_mpdparser_get_nb_active_stream (demux->client)) {
-    stream = gst_mpdparser_get_active_stream_by_index (demux->client, i);
-    if (!stream)
+  GST_MPD_CLIENT_LOCK (demux->client);
+  for (iter = demux->streams; iter; iter = g_slist_next (iter)) {
+    guint64 bitrate;
+
+    stream = iter->data;
+    active_stream =
+      gst_mpdparser_get_active_stream_by_index (demux->client, stream->idx);
+    if (!active_stream)
       return FALSE;
 
     /* retrieve representation list */
-    if (stream->cur_adapt_set)
-      rep_list = stream->cur_adapt_set->Representations;
+    if (active_stream->cur_adapt_set)
+      rep_list = active_stream->cur_adapt_set->Representations;
     if (!rep_list)
       return FALSE;
 
+    bitrate = gst_download_rate_get_current_rate (&stream->dnl_rate) *
+      demux->bandwidth_usage;
+
+    GST_DEBUG_OBJECT (demux, "Trying to change bitrate to %" G_GUINT64_FORMAT, bitrate);
+
     /* get representation index with current max_bandwidth */
     new_index =
         gst_mpdparser_get_rep_idx_with_max_bandwidth (rep_list, bitrate);
@@ -1529,22 +1553,23 @@ gst_dash_demux_select_representations (GstDashDemux * demux, guint64 bitrate)
     if (new_index == -1)
       new_index = 0;
 
-    if (new_index != stream->representation_idx) {
-      GST_MPD_CLIENT_LOCK (demux->client);
-      ret =
-          gst_mpd_client_setup_representation (demux->client, stream,
-          g_list_nth_data (rep_list, new_index));
-      GST_MPD_CLIENT_UNLOCK (demux->client);
-      if (ret) {
+    if (new_index != active_stream->representation_idx) {
+      GstRepresentationNode *rep = g_list_nth_data (rep_list, new_index);
+      GST_INFO_OBJECT (demux, "Changing representation idx: %d %d %u",
+                      stream->idx, new_index, rep->bandwidth);
+      if (gst_mpd_client_setup_representation (demux->client, active_stream,
+                                              rep)) {
+       ret = TRUE;
+       stream->need_header = TRUE;
         GST_INFO_OBJECT (demux, "Switching bitrate to %d",
-            stream->cur_representation->bandwidth);
+            active_stream->cur_representation->bandwidth);
       } else {
         GST_WARNING_OBJECT (demux,
             "Can not switch representation, aborting...");
       }
     }
-    i++;
   }
+  GST_MPD_CLIENT_UNLOCK (demux->client);
   return ret;
 }
 
@@ -1571,64 +1596,28 @@ gst_dash_demux_get_next_header (GstDashDemux * demux, guint stream_idx)
 
   fragment = gst_uri_downloader_fetch_uri (demux->downloader, next_header_uri);
   g_free (next_header_uri);
+  g_free (initializationURL);
 
   return fragment;
 }
 
-static GstBufferListItem
-gst_dash_demux_add_buffer_cb (GstBuffer ** buffer,
-    guint group, guint idx, gpointer user_data)
-{
-  GstFragment *frag = GST_FRAGMENT (user_data);
-  /* This buffer still belongs to the original fragment */
-  /* so we need to increase refcount */
-  gst_fragment_add_buffer (frag, gst_buffer_ref (*buffer));
-  return GST_BUFFER_LIST_CONTINUE;
-}
-
-/* Since we cannot add headers after the chunk has been downloaded, we have to recreate a new fragment */
-static GstFragment *
-gst_dash_demux_prepend_header (GstDashDemux * demux,
-    GstFragment * frag, GstFragment * header)
-{
-  GstFragment *res = gst_fragment_new ();
-  res->name = g_strdup (frag->name);
-  res->download_start_time = frag->download_start_time;
-  res->download_stop_time = frag->download_stop_time;
-  res->start_time = frag->start_time;
-  res->stop_time = frag->stop_time;
-  res->index = frag->index;
-  res->discontinuous = frag->discontinuous;
-
-  GstBufferList *list;
-  list = gst_fragment_get_buffer_list (header);
-  gst_buffer_list_foreach (list, gst_dash_demux_add_buffer_cb, res);
-  gst_buffer_list_unref (list);
-  list = gst_fragment_get_buffer_list (frag);
-  gst_buffer_list_foreach (list, gst_dash_demux_add_buffer_cb, res);
-  gst_buffer_list_unref (list);
-
-  res->completed = TRUE;
-
-  return res;
-}
-
 static GstCaps *
 gst_dash_demux_get_video_input_caps (GstDashDemux * demux,
     GstActiveStream * stream)
 {
-  guint width = 0, height = 0;
+  guint width = 0, height = 0, bandwidth = 0;
   const gchar *mimeType = NULL;
   GstCaps *caps = NULL;
 
   if (stream == NULL)
     return NULL;
 #ifdef DASHDEMUX_MODIFICATION
-  /* caps need to inlcude resolution  */
+  /* caps need to inlcude resolution and bandwidth */
     width = gst_mpd_client_get_video_stream_width (stream);
     height = gst_mpd_client_get_video_stream_height (stream);
+    bandwidth = gst_mpd_client_get_video_stream_bandwidth (stream);
 #else
-  /* if bitstreamSwitching is true we dont need to swich pads on resolution change */  
+  /* if bitstreamSwitching is true we dont need to swich pads on resolution change */
   if (!gst_mpd_client_get_bitstream_switching_flag (stream)) {
     width = gst_mpd_client_get_video_stream_width (stream);
     height = gst_mpd_client_get_video_stream_height (stream);
@@ -1644,6 +1633,12 @@ gst_dash_demux_get_video_input_caps (GstDashDemux * demux,
         G_TYPE_INT, height, NULL);
   }
 
+  if (bandwidth > 0)
+    gst_caps_set_simple (caps, "bandwidth", G_TYPE_INT, bandwidth, NULL);
+
+  gst_caps_set_simple (caps, "max-width", G_TYPE_INT, demux->max_video_width, "max-height",
+      G_TYPE_INT, demux->max_video_height, NULL);
+
 /*  add ContentProtection to caps  */
   if ( stream->cur_adapt_set->RepresentationBase->ContentProtection != NULL){
     GList *list;
@@ -1728,41 +1723,23 @@ gst_dash_demux_get_application_input_caps (GstDashDemux * demux,
 static GstCaps *
 gst_dash_demux_get_input_caps (GstDashDemux * demux, GstActiveStream * stream)
 {
+  GstCaps *caps;
   switch (stream->mimeType) {
     case GST_STREAM_VIDEO:
-      return gst_dash_demux_get_video_input_caps (demux, stream);
+      caps = gst_dash_demux_get_video_input_caps (demux, stream);
+      break;
     case GST_STREAM_AUDIO:
-      return gst_dash_demux_get_audio_input_caps (demux, stream);
+      caps = gst_dash_demux_get_audio_input_caps (demux, stream);
+      break;
     case GST_STREAM_APPLICATION:
-      return gst_dash_demux_get_application_input_caps (demux, stream);
+      caps = gst_dash_demux_get_application_input_caps (demux, stream);
+      break;
     default:
       return GST_CAPS_NONE;
   }
-}
-
-static gboolean
-need_add_header (GstDashDemux * demux)
-{
-  GstActiveStream *stream;
-  GstCaps *caps;
-  guint stream_idx = 0;
-  gboolean switch_caps = FALSE;
-  while (stream_idx < gst_mpdparser_get_nb_active_stream (demux->client)) {
-    stream =
-        gst_mpdparser_get_active_stream_by_index (demux->client, stream_idx);
-    if (stream == NULL)
-      return FALSE;
-    caps = gst_dash_demux_get_input_caps (demux, stream);
-    if (!demux->input_caps[stream_idx]
-        || !gst_caps_is_equal (caps, demux->input_caps[stream_idx])) {
-      switch_caps = TRUE;
-      gst_caps_unref (caps);
-      break;
-    }
-    gst_caps_unref (caps);
-    stream_idx++;
-  }
-  return switch_caps;
+  /*Need to signal downstream elements about dash*/
+  gst_caps_set_simple(caps, "variant", G_TYPE_STRING, "dash-fragmented", NULL);
+  return caps;
 }
 
 /* gst_dash_demux_get_next_fragment_set:
@@ -1775,90 +1752,151 @@ need_add_header (GstDashDemux * demux)
  *
  */
 static gboolean
-gst_dash_demux_get_next_fragment_set (GstDashDemux * demux)
+gst_dash_demux_get_next_fragment (GstDashDemux * demux,GstActiveStream **fragment_stream,
+     GstClockTime *selected_ts)
 {
   GstActiveStream *stream;
+  GstDashDemuxStream *dash_stream;
+  GstDashDemuxStream *selected_stream = NULL;
   GstFragment *download, *header;
-  GList *fragment_set;
   gchar *next_fragment_uri;
   GstClockTime duration;
   GstClockTime timestamp;
+  GstClockTime min_timestamp = GST_CLOCK_TIME_NONE;
   gboolean discont;
   GTimeVal now;
   GTimeVal start;
   GstClockTime diff;
   guint64 size_buffer = 0;
+  GstBuffer *buffer;
+  guint stream_idx;
+  gboolean end_of_period = TRUE;
 
-  g_get_current_time (&start);
-  /* Figure out if we will need to switch pads, thus requiring a new
-   * header to initialize the new decoding chain
-   * FIXME: redundant with needs_pad_switch */
-  gboolean need_header = need_add_header (demux);
-  guint stream_idx = 0;
-  fragment_set = NULL;
-  /* Get the fragment corresponding to each stream index */
-  while (stream_idx < gst_mpdparser_get_nb_active_stream (demux->client)) {
-    if (!gst_mpd_client_get_next_fragment (demux->client,
-            stream_idx, &discont, &next_fragment_uri, &duration, &timestamp)) {
-      GST_INFO_OBJECT (demux, "This Period doesn't contain more fragments");
-      demux->end_of_period = TRUE;
-      return FALSE;
+  /*Select stream with smallest progress*/
+  for (stream_idx = 0; stream_idx < g_slist_length (demux->streams); stream_idx++) {
+    dash_stream = g_slist_nth_data (demux->streams, stream_idx);
+
+    if (dash_stream->download_end_of_period)
+      continue;
+
+    if (gst_mpd_client_get_next_fragment_timestamp (demux->client, stream_idx, &timestamp)) {
+      if( timestamp < min_timestamp || !GST_CLOCK_TIME_IS_VALID(min_timestamp) ) {
+        selected_stream = dash_stream;
+        min_timestamp = timestamp;
+      }
+    } else {
+      GstEvent *event = NULL;
+
+      GST_INFO_OBJECT (demux,
+          "This Period doesn't contain more fragments for stream %u",
+          dash_stream->idx);
+
+      /* check if this is live and we should wait for more data */
+      if (gst_mpd_client_is_live (demux->client)
+          && demux->client->mpd_node->minimumUpdatePeriod != -1) {
+        end_of_period = FALSE;
+        continue;
+      }
+
+      if (gst_mpd_client_has_next_period (demux->client)) {
+        event = gst_event_new_dash_eop ();
+      } else {
+        GST_DEBUG_OBJECT (demux,
+            "No more fragments or periods for this stream, setting EOS");
+        event = gst_event_new_eos ();
+      }
+      dash_stream->download_end_of_period = TRUE;
+      gst_dash_demux_stream_push_event (dash_stream, event);
     }
+  }
+
+  if (selected_ts)
+    *selected_ts = min_timestamp;
+  if (fragment_stream && selected_stream)
+    *fragment_stream = gst_mpdparser_get_active_stream_by_index (demux->client, selected_stream->idx);
+   /* Fetch next fragment from selected stream */
+  if(selected_stream) {
 
-    GST_INFO_OBJECT (demux, "Fetching next fragment %s", next_fragment_uri);
+    if (!gst_mpd_client_get_next_fragment (demux->client,
+            selected_stream->idx, &discont, &next_fragment_uri, &duration, &timestamp)) {
+      GST_WARNING_OBJECT (demux, "Failed to download fragment for stream %d", selected_stream->idx);
+    } else {
 
-    download = gst_uri_downloader_fetch_uri (demux->downloader,
-        next_fragment_uri);
-    g_free (next_fragment_uri);
+      g_get_current_time (&start);
+      GST_INFO_OBJECT (demux, "Fetching next fragment stream=%d ts=%"GST_TIME_FORMAT" url=%s",
+                       selected_stream->idx, GST_TIME_ARGS(timestamp), next_fragment_uri);
 
-    if (download == NULL)
-      return FALSE;
+      stream = gst_mpdparser_get_active_stream_by_index (demux->client, selected_stream->idx);
 
-    download->start_time = timestamp;
-    download->stop_time = timestamp + duration;
+      end_of_period = FALSE;
 
-    stream =
-        gst_mpdparser_get_active_stream_by_index (demux->client, stream_idx);
-    if (stream == NULL)
-      return FALSE;
+      download = gst_uri_downloader_fetch_uri (demux->downloader,
+          next_fragment_uri);
+      g_free (next_fragment_uri);
+
+      if (stream == NULL)
+        return FALSE;
+
+      if (download == NULL) {
+        guint segment_idx = gst_mpd_client_get_segment_index ( stream );
+        if(segment_idx > 0) {
+          /*Move to previous segment if download failed*/
+          gst_mpd_client_set_segment_index (stream, segment_idx - 1);
+        }
+        return FALSE;
+      }
+
+      download->start_time = timestamp;
+      download->stop_time = timestamp + duration;
 
-    download->index = gst_mpd_client_get_segment_index (stream) - 1;
+      download->index = gst_mpd_client_get_segment_index (stream) - 1;
 
-    GstCaps *caps = gst_dash_demux_get_input_caps (demux, stream);
+      GstCaps *caps = gst_dash_demux_get_input_caps (demux, stream);
+      buffer = gst_fragment_get_buffer (download);
+      g_return_val_if_fail (buffer != NULL, FALSE);
 
-    if (need_header) {
-      /* Store the new input caps for that stream */
-      gst_caps_replace (&demux->input_caps[stream_idx], caps);
-      GST_INFO_OBJECT (demux, "Input source caps: %" GST_PTR_FORMAT,
-          demux->input_caps[stream_idx]);
-      /* We need to fetch a new header */
-      if ((header = gst_dash_demux_get_next_header (demux, stream_idx)) == NULL) {
-        GST_INFO_OBJECT (demux, "Unable to fetch header");
+      if (selected_stream->need_header) {
+        /* Store the new input caps for that stream */
+        gst_caps_replace (&dash_stream->input_caps, caps);
+        GST_INFO_OBJECT (demux, "Input source caps: %" GST_PTR_FORMAT,
+            dash_stream->input_caps);
+
+        /* We need to fetch a new header */
+        if ((header = gst_dash_demux_get_next_header (demux, selected_stream->idx)) == NULL) {
+          GST_INFO_OBJECT (demux, "Unable to fetch header");
+        } else {
+          /* Replace fragment buffer with a new one including the header */
+          GstBuffer *header_buffer = gst_fragment_get_buffer(header);
+          buffer = gst_buffer_join(header_buffer, buffer);
+          g_object_unref (header);
+         selected_stream->need_header = FALSE;
+        }
       } else {
-        /* Replace fragment with a new one including the header */
-        GstFragment *new_fragment =
-            gst_dash_demux_prepend_header (demux, download, header);
-        g_object_unref (header);
-        g_object_unref (download);
-        download = new_fragment;
+        gst_caps_unref (caps);
       }
-    } else
-      gst_caps_unref (caps);
 
-    gst_fragment_set_caps (download, demux->input_caps[stream_idx]);
-    fragment_set = g_list_append (fragment_set, download);
-    size_buffer += gst_fragment_get_buffer_size (download);
-    stream_idx++;
+      g_get_current_time (&now);
+      g_object_unref (download);
+
+      gst_buffer_set_caps(buffer, dash_stream->input_caps);
+      GST_BUFFER_TIMESTAMP(buffer) = timestamp;
+      GST_BUFFER_DURATION(buffer) = duration;
+      GST_BUFFER_OFFSET(buffer) = gst_mpd_client_get_segment_index (stream) - 1;
+      size_buffer = GST_BUFFER_SIZE (buffer);
+      /* Push fragment into the queue */
+      gst_dash_demux_stream_push_data (selected_stream, buffer);
+      diff = (GST_TIMEVAL_TO_TIME (now) - GST_TIMEVAL_TO_TIME (start));
+      gst_download_rate_add_rate (&selected_stream->dnl_rate, size_buffer, diff, duration);
+      GST_DEBUG_OBJECT (demux,
+                        "Stream: %d Download rate = %" G_GUINT64_FORMAT " Kbits/s (%" G_GUINT64_FORMAT
+                        " Ko in %.2f s)\n", selected_stream->idx,
+                        gst_download_rate_get_current_rate (&selected_stream->dnl_rate) / 1000,
+                        size_buffer / 1024,
+                        ((double) diff / GST_SECOND));
+    }
   }
-  /* Push fragment set into the queue */
-  g_queue_push_tail (demux->queue, fragment_set);
-  /* Wake the download task up */
-  GST_TASK_SIGNAL (demux->download_task);
-  g_get_current_time (&now);
-  diff = (GST_TIMEVAL_TO_TIME (now) - GST_TIMEVAL_TO_TIME (start));
-  demux->dnl_rate = (size_buffer * 8) / ((double) diff / GST_SECOND);
-  GST_INFO_OBJECT (demux,
-      "Download rate = %" PRIu64 " Kbits/s (%" PRIu64 " Ko in %.2f s)",
-      demux->dnl_rate / 1000, size_buffer / 1024, ((double) diff / GST_SECOND));
-  return TRUE;
+
+  demux->end_of_period = end_of_period;
+
+  return !end_of_period;
 }