tizen 2.3 release
[framework/multimedia/gst-plugins-ext0.10.git] / dashdemux / src / gstmpdparser.c
similarity index 87%
rename from wearable/dashdemux/src/gstmpdparser.c
rename to dashdemux/src/gstmpdparser.c
index 474a9ac..1d835be 100755 (executable)
@@ -110,7 +110,7 @@ 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_get_segmentURL_for_range (gchar * url,
+static gchar *gst_mpdparser_get_segmentURL_for_range (const gchar *url,
     GstRange * range);
 static gchar *gst_mpdparser_get_mediaURL (GstMpdClient * client,
     GstSegmentURLNode * segmentURL);
@@ -122,9 +122,7 @@ 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);
-static void gst_mpd_client_set_segment_index (GstActiveStream * stream,
-    guint segment_idx);
+static GstClockTime gst_mpd_client_get_segment_duration (GstMpdClient * client, GstActiveStream * stream);
 
 /* Adaptation Set */
 static GstAdaptationSetNode
@@ -145,7 +143,7 @@ static GstRepresentationNode *gst_mpdparser_get_highest_representation (GList *
     Representations);
 static GstRepresentationNode
     *gst_mpdparser_get_representation_with_max_bandwidth (GList *
-    Representations, gint max_bandwidth);
+    Representations, guint64 max_bandwidth);
 #endif
 static GstSegmentBaseType *gst_mpdparser_get_segment_base (GstPeriodNode *
     Period, GstAdaptationSetNode * AdaptationSet,
@@ -903,7 +901,6 @@ gst_mpdparser_parse_baseURL_node (GList ** list, xmlNode * a_node)
 
   GST_LOG ("content of BaseURL node:");
   new_base_url->baseURL = gst_mpdparser_get_xml_node_content (a_node);
-
   GST_LOG ("attributes of BaseURL node:");
   new_base_url->serviceLocation =
       gst_mpdparser_get_xml_prop_string (a_node, "serviceLocation");
@@ -1233,6 +1230,8 @@ gst_mpdparser_parse_representation_base_type (GstRepresentationBaseType **
       gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "width", 0);
   representation_base->height =
       gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "height", 0);
+  representation_base->bandwidth = 
+      gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "bandwidth", 0);
   representation_base->sar = gst_mpdparser_get_xml_prop_ratio (a_node, "sar");
   representation_base->frameRate =
       gst_mpdparser_get_xml_prop_framerate (a_node, "frameRate");
@@ -1865,10 +1864,13 @@ gst_mpdparser_get_segment_base (GstPeriodNode * Period,
 
 gint
 gst_mpdparser_get_rep_idx_with_max_bandwidth (GList * Representations,
-    gint max_bandwidth)
+    guint64 max_bandwidth)
 {
   GList *list = NULL, *best = NULL;
   GstRepresentationNode *representation;
+  guint64 best_bandwidth = 0;
+
+  GST_DEBUG ("max bandwidth %" G_GUINT64_FORMAT, max_bandwidth);
 
   if (Representations == NULL)
     return -1;
@@ -1877,9 +1879,11 @@ gst_mpdparser_get_rep_idx_with_max_bandwidth (GList * Representations,
     return 0;
 
   for (list = g_list_first (Representations); list; list = g_list_next (list)) {
-    representation = (GstRepresentationNode *) list->data;
-    if (representation && representation->bandwidth <= max_bandwidth) {
+    representation = (GstRepresentationNode *) list->data; 
+    if (representation && representation->bandwidth <= max_bandwidth &&
+       representation->bandwidth > best_bandwidth) {
       best = list;
+      best_bandwidth = representation->bandwidth;
     }
   }
 
@@ -2267,13 +2271,14 @@ gst_mpdparser_free_active_stream (GstActiveStream * active_stream)
   if (active_stream) {
     g_list_foreach (active_stream->segments,
         (GFunc) gst_mpdparser_free_media_segment, NULL);
-    g_list_free (active_stream->segments);
+    if (active_stream->segments)
+      g_list_free (active_stream->segments);
     g_slice_free (GstActiveStream, active_stream);
   }
 }
 
 static gchar *
-gst_mpdparser_get_segmentURL_for_range (gchar * url, GstRange * range)
+gst_mpdparser_get_segmentURL_for_range (const gchar * url, GstRange * range)
 {
   gchar *segmentURL;
 
@@ -2416,28 +2421,28 @@ gst_mpdparser_parse_baseURL (GstMpdClient * client)
 
   /* FIXME: this simple implementation is not fully compliant with RFC 3986 */
   if ((list = client->mpd_node->BaseURLs) != NULL) {
-    baseURL = g_list_nth_data (list, stream->baseURL_idx);
+    baseURL = g_list_nth_data (list, stream->mpd_baseURL_idx);
     if (!baseURL) {
       baseURL = list->data;
     }
     baseURL_array[0] = baseURL->baseURL;
   }
   if ((list = stream_period->period->BaseURLs) != NULL) {
-    baseURL = g_list_nth_data (list, stream->baseURL_idx);
+    baseURL = g_list_nth_data (list, stream->period_baseURL_idx);
     if (!baseURL) {
       baseURL = list->data;
     }
     baseURL_array[1] = baseURL->baseURL;
   }
   if ((list = stream->cur_adapt_set->BaseURLs) != NULL) {
-    baseURL = g_list_nth_data (list, stream->baseURL_idx);
+    baseURL = g_list_nth_data (list, stream->adaptset_baseURL_idx);
     if (!baseURL) {
       baseURL = list->data;
     }
     baseURL_array[2] = baseURL->baseURL;
   }
   if ((list = stream->cur_representation->BaseURLs) != NULL) {
-    baseURL = g_list_nth_data (list, stream->baseURL_idx);
+    baseURL = g_list_nth_data (list, stream->repr_baseURL_idx);
     if (!baseURL) {
       baseURL = list->data;
     }
@@ -2459,22 +2464,17 @@ gst_mpdparser_parse_baseURL (GstMpdClient * client)
     }
   }
 
-  GST_DEBUG ("selected baseURL with index %d: %s", stream->baseURL_idx, ret);
-
   return ret;
 }
 
 static GstClockTime
-gst_mpd_client_get_segment_duration (GstMpdClient * client)
+gst_mpd_client_get_segment_duration (GstMpdClient * client, GstActiveStream *stream)
 {
-  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);
@@ -2511,6 +2511,8 @@ gst_mpd_client_new ()
   client = g_new0 (GstMpdClient, 1);
   client->lock = g_mutex_new ();
 
+  client->download_failed_count = 0;
+
   return client;
 }
 
@@ -2586,8 +2588,6 @@ gst_mpd_parse (GstMpdClient * client, const gchar * data, gint size)
       }
       /* free the document */
       xmlFreeDoc (doc);
-      /* cleanup function for the XML library */
-      xmlCleanupParser ();
       /* dump XML library memory for debugging */
       xmlMemoryDump ();
     }
@@ -2612,19 +2612,50 @@ gst_mpdparser_get_baseURL (GstMpdClient * client)
   return stream->baseURL;
 }
 
-GstMediaSegment *
+gboolean
 gst_mpdparser_get_chunk_by_index (GstMpdClient * client, guint indexStream,
-    guint indexChunk)
+    guint indexChunk, GstMediaSegment *segment)
 {
   GstActiveStream *stream;
 
   /* select stream */
-  g_return_val_if_fail (client != NULL, NULL);
-  g_return_val_if_fail (client->active_streams != NULL, NULL);
+  g_return_val_if_fail (client != NULL, FALSE);
+  g_return_val_if_fail (segment != NULL, FALSE);
+  g_return_val_if_fail (client->active_streams != NULL, FALSE);
   stream = g_list_nth_data (client->active_streams, indexStream);
-  g_return_val_if_fail (stream != NULL, NULL);
+  g_return_val_if_fail (stream != NULL, FALSE);
+
+  if(stream->segments) {
+    GstMediaSegment *list_segment;
+    if ( indexChunk >= g_list_length (stream->segments))
+      return FALSE;
+    list_segment = g_list_nth_data (stream->segments, indexChunk);
+    memcpy (segment, list_segment, sizeof (GstMediaSegment));
+  } else {
+    GstClockTime duration;
+    GstStreamPeriod *stream_period;
+    GstClockTime start_time;
+    stream_period = gst_mpdparser_get_stream_period (client);
+    g_return_val_if_fail (stream->cur_seg_template->MultSegBaseType->SegmentTimeline == NULL, FALSE);
+    g_return_val_if_fail (stream_period != NULL, FALSE);
+    g_return_val_if_fail (stream_period->period != NULL, FALSE);
+
+    duration = gst_mpd_client_get_segment_duration (client, stream);
+    if (!GST_CLOCK_TIME_IS_VALID (duration))
+      return FALSE;
+
+    start_time = duration * indexChunk;
+    if (GST_CLOCK_TIME_IS_VALID (stream_period->start) && GST_CLOCK_TIME_IS_VALID (stream_period->duration)
+      && start_time >= stream_period->start + stream_period->duration)
+      return FALSE;
 
-  return (GstMediaSegment *) g_list_nth_data (stream->segments, indexChunk);
+    segment->number = indexChunk + stream->cur_seg_template->MultSegBaseType->startNumber;
+    segment->start_time = start_time;
+    segment->duration = duration;
+    segment->SegmentURL = NULL;
+  }
+
+  return TRUE;
 }
 
 static gboolean
@@ -2760,7 +2791,7 @@ gst_mpd_client_setup_representation (GstMpdClient * client,
           }
         }
       } else {
-        duration = gst_mpd_client_get_segment_duration (client);
+        duration =gst_mpd_client_get_segment_duration (client, stream);
         if (!GST_CLOCK_TIME_IS_VALID (duration))
           return FALSE;
 
@@ -2832,19 +2863,7 @@ 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))
-          return FALSE;
-
-        while (PeriodStart + start_time < PeriodEnd) {
-          if (!gst_mpd_client_add_media_segment (stream, NULL, i, 0, start_time,
-                  duration)) {
-            return FALSE;
-          }
-          i++;
-          start_time += duration;
-        }
+         /*The segment is created on demand with the template, no need to build a list */
       }
     }
   }
@@ -2908,6 +2927,8 @@ gst_mpd_client_setup_media_presentation (GstMpdClient * client)
     } else if (idx == 0 && client->mpd_node->type == GST_MPD_FILE_TYPE_STATIC) {
       /* first period of a static MPD file, start time is 0 */
       start = 0;
+    } else if (gst_mpd_client_is_live (client)) {
+      /*it should be a live stream, let this pass.*/
     } else {
       /* this is an 'Early Available Period' */
       goto early;
@@ -2928,6 +2949,8 @@ gst_mpd_client_setup_media_presentation (GstMpdClient * client)
       /* last Period of the Media Presentation */
       duration =
           client->mpd_node->mediaPresentationDuration * GST_MSECOND - start;
+    } else if (gst_mpd_client_is_live (client)) {
+      /*it should be a live stream, let this pass.*/
     } else {
       /* Invalid MPD file! */
       goto syntax_error;
@@ -3054,14 +3077,17 @@ gst_mpd_client_setup_streaming (GstMpdClient * client,
   }
   client->active_streams = g_list_append (client->active_streams, stream);
 
-  stream->baseURL_idx = 0;
+  stream->mpd_baseURL_idx = 0;
+  stream->period_baseURL_idx = 0;
+  stream->adaptset_baseURL_idx = 0;
+  stream->repr_baseURL_idx = 0;
+
   stream->mimeType = mimeType;
   stream->cur_adapt_set = adapt_set;
 
   /* retrive representation list */
   if (stream->cur_adapt_set != NULL)
     rep_list = stream->cur_adapt_set->Representations;
-
 #if 0
   /* fast start */
   representation =
@@ -3093,12 +3119,69 @@ gst_mpd_client_setup_streaming (GstMpdClient * client,
 }
 
 gboolean
+gst_mpd_client_get_next_fragment_timestamp (GstMpdClient * client,
+    guint stream_idx, GstClockTime * ts)
+{
+  GstActiveStream *stream;
+  gint segment_idx;
+  GstMediaSegment currentChunk;
+
+  GST_DEBUG ("Stream index: %i", stream_idx);
+  stream = g_list_nth_data (client->active_streams, stream_idx);
+  g_return_val_if_fail (stream != NULL, 0);
+
+  GST_MPD_CLIENT_LOCK (client);
+  segment_idx = gst_mpd_client_get_segment_index (stream);
+  GST_DEBUG ("Looking for fragment sequence chunk %d", segment_idx);
+
+
+  if (!gst_mpdparser_get_chunk_by_index (client, stream_idx, segment_idx, &currentChunk)) {
+    GST_MPD_CLIENT_UNLOCK (client);
+    return FALSE;
+  }
+
+  *ts = currentChunk.start_time;
+  GST_MPD_CLIENT_UNLOCK (client);
+
+  return TRUE;
+}
+
+gboolean
+gst_mpd_client_get_last_fragment_timestamp (GstMpdClient * client,
+    guint stream_idx, GstClockTime * ts)
+{
+  GstActiveStream *stream;
+  gint segment_idx = 0;
+  GstMediaSegment currentChunk;
+
+  GST_DEBUG ("Stream index: %i", stream_idx);
+  stream = g_list_nth_data (client->active_streams, stream_idx);
+  g_return_val_if_fail (stream != NULL, 0);
+
+  GST_MPD_CLIENT_LOCK (client);
+  if (stream->segments)
+    segment_idx = g_list_length (stream->segments) - 1;
+  GST_DEBUG ("Looking for fragment sequence chunk %d", segment_idx);
+
+  if (!gst_mpdparser_get_chunk_by_index (client, stream_idx, segment_idx,
+          &currentChunk)) {
+    GST_MPD_CLIENT_UNLOCK (client);
+    return FALSE;
+  }
+
+  *ts = currentChunk.start_time;
+  GST_MPD_CLIENT_UNLOCK (client);
+
+  return TRUE;
+}
+
+gboolean
 gst_mpd_client_get_next_fragment (GstMpdClient * client,
     guint indexStream, gboolean * discontinuity, gchar ** uri,
     GstClockTime * duration, GstClockTime * timestamp)
 {
   GstActiveStream *stream = NULL;
-  GstMediaSegment *currentChunk;
+  GstMediaSegment currentChunk;
   gchar *mediaURL = NULL;
   guint segment_idx;
 
@@ -3114,25 +3197,23 @@ gst_mpd_client_get_next_fragment (GstMpdClient * client,
   segment_idx = gst_mpd_client_get_segment_index (stream);
   GST_DEBUG ("Looking for fragment sequence chunk %d", segment_idx);
 
-  currentChunk =
-      gst_mpdparser_get_chunk_by_index (client, indexStream, segment_idx);
-  if (currentChunk == NULL) {
+  if (!gst_mpdparser_get_chunk_by_index (client, indexStream, segment_idx, &currentChunk)) {
     GST_MPD_CLIENT_UNLOCK (client);
     return FALSE;
   }
 
-  if (currentChunk->SegmentURL != NULL) {
-    mediaURL = gst_mpdparser_get_mediaURL (client, currentChunk->SegmentURL);
+  if (currentChunk.SegmentURL != NULL) {
+    mediaURL = gst_mpdparser_get_mediaURL (client, 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);
+        stream->cur_representation->id, currentChunk.number,
+        stream->cur_representation->bandwidth, currentChunk.start);
   }
 
-  *timestamp = currentChunk->start_time;
-  *duration = currentChunk->duration;
-  *discontinuity = segment_idx != currentChunk->number;
+  *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));
@@ -3196,21 +3277,25 @@ gst_mpd_client_get_next_header (GstMpdClient * client, const gchar ** uri,
   return *uri == NULL ? FALSE : TRUE;
 }
 
-GstClockTime
-gst_mpd_client_get_current_position (GstMpdClient * client)
+gboolean
+gst_mpd_client_get_stream_current_position (GstMpdClient * client, guint stream_idx, GstClockTime *ts)
 {
   GstActiveStream *stream;
-  GstMediaSegment *media_segment;
-
-  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,
-      gst_mpd_client_get_segment_index (stream));
-  g_return_val_if_fail (media_segment != NULL, GST_CLOCK_TIME_NONE);
+  GstMediaSegment media_segment;
+  stream = gst_mpdparser_get_active_stream_by_index( client, stream_idx);
+  g_return_val_if_fail (stream != NULL, FALSE);
+  if(!gst_mpdparser_get_chunk_by_index(client, stream_idx,
+               gst_mpd_client_get_segment_index (stream), &media_segment))
+  {
+   return FALSE;
+  }
 
-  return media_segment->start_time;
+  if (GST_CLOCK_TIME_IS_VALID (media_segment.start_time)) {
+  *ts = media_segment.start_time;
+   return TRUE;
+  } else {
+   return FALSE;
+  }
 }
 
 GstClockTime
@@ -3218,15 +3303,26 @@ gst_mpd_client_get_next_fragment_duration (GstMpdClient * client)
 {
   GstActiveStream *stream;
   GstMediaSegment *media_segment;
+  gint seg_idx;
 
   stream = g_list_nth_data (client->active_streams, client->stream_idx);
   g_return_val_if_fail (stream != NULL, 0);
+  seg_idx = gst_mpd_client_get_segment_index (stream);
 
-  media_segment =
-      g_list_nth_data (stream->segments,
-      gst_mpd_client_get_segment_index (stream));
+  if(stream->segments) {
+    media_segment =
+        g_list_nth_data (stream->segments, seg_idx);
+    return media_segment == NULL ? 0 : media_segment->duration;
+  } else {
+    GstClockTime duration =
+        gst_mpd_client_get_segment_duration (client, stream);
+    g_return_val_if_fail (stream->cur_seg_template->MultSegBaseType->
+        SegmentTimeline == NULL, 0);
 
-  return media_segment == NULL ? 0 : media_segment->duration;
+    if (GST_CLOCK_TIME_IS_VALID (duration))
+      return duration;
+    return 0;
+  }
 }
 
 GstClockTime
@@ -3281,6 +3377,66 @@ gst_mpd_client_get_period_index (GstMpdClient * client)
   return period_idx;
 }
 
+gboolean
+gst_mpd_client_set_period_id (GstMpdClient * client, const gchar * period_id)
+{
+  GstStreamPeriod *next_stream_period;
+  gboolean ret = FALSE;
+  GList *iter;
+  gint index = 0;
+
+  g_return_val_if_fail (client != NULL, FALSE);
+  g_return_val_if_fail (client->periods != NULL, FALSE);
+  g_return_val_if_fail (period_id != NULL, FALSE);
+
+  GST_MPD_CLIENT_LOCK (client);
+  for (iter = client->periods; iter; iter = g_list_next (iter)) {
+    next_stream_period = iter->data;
+
+    if (next_stream_period->period->id
+        && strcmp (next_stream_period->period->id, period_id) == 0) {
+      client->period_idx = index;
+      ret = TRUE;
+      break;
+    }
+    index++;
+  }
+  GST_MPD_CLIENT_UNLOCK (client);
+
+  return ret;
+}
+
+const gchar *
+gst_mpd_client_get_period_id (GstMpdClient * client)
+{
+  GstStreamPeriod *period;
+  gchar *period_id = NULL;
+
+  g_return_val_if_fail (client != NULL, 0);
+  GST_MPD_CLIENT_LOCK (client);
+  period = g_list_nth_data (client->periods, client->period_idx);
+  if (period && period->period)
+    period_id = period->period->id;
+  GST_MPD_CLIENT_UNLOCK (client);
+
+  return period_id;
+}
+
+gboolean
+gst_mpd_client_has_next_period (GstMpdClient * client)
+{
+  GList *next_stream_period;
+  g_return_val_if_fail (client != NULL, FALSE);
+  g_return_val_if_fail (client->periods != NULL, FALSE);
+
+  GST_MPD_CLIENT_LOCK (client);
+  next_stream_period =
+      g_list_nth_data (client->periods, client->period_idx + 1);
+  GST_MPD_CLIENT_UNLOCK (client);
+
+  return next_stream_period != NULL;
+}
+
 void
 gst_mpd_client_set_segment_index_for_all_streams (GstMpdClient * client,
     guint segment_idx)
@@ -3300,7 +3456,51 @@ gst_mpd_client_set_segment_index_for_all_streams (GstMpdClient * client,
   }
 }
 
-static void
+gboolean
+gst_mpd_client_set_next_baseURL_for_stream (GstMpdClient * client)
+{
+  GstActiveStream *stream;
+  GstStreamPeriod *stream_period;
+  GList *list;
+
+  g_return_val_if_fail (client != NULL, FALSE);
+  g_return_val_if_fail (client->active_streams != NULL, FALSE);
+
+  stream = g_list_nth_data (client->active_streams,
+                           client->stream_idx);
+  g_return_val_if_fail (stream != NULL, FALSE);
+  stream_period = gst_mpdparser_get_stream_period (client);
+  g_return_val_if_fail (stream_period != NULL, FALSE);
+
+  if ((list = stream->cur_representation->BaseURLs) != NULL &&
+      stream->repr_baseURL_idx < g_list_length (list) - 1) {
+    stream->repr_baseURL_idx++;
+  } else if ((list = stream->cur_adapt_set->BaseURLs) != NULL &&
+            stream->adaptset_baseURL_idx < g_list_length (list) - 1) {
+    stream->adaptset_baseURL_idx++;
+    stream->repr_baseURL_idx = 0;
+  } else if ((list = stream_period->period->BaseURLs) != NULL &&
+            stream->period_baseURL_idx < g_list_length (list) - 1) {
+    stream->period_baseURL_idx++;
+    stream->adaptset_baseURL_idx = 0;
+    stream->repr_baseURL_idx = 0;
+  } else if ((list = client->mpd_node->BaseURLs) != NULL &&
+            stream->mpd_baseURL_idx < g_list_length (list) - 1) {
+      stream->mpd_baseURL_idx++;
+      stream->period_baseURL_idx = 0;
+      stream->adaptset_baseURL_idx = 0;
+      stream->repr_baseURL_idx = 0;
+  } else {
+    GST_WARNING ("Unable to change URI: No alternative baseURL available");
+    return FALSE;
+  }
+
+  stream->baseURL = gst_mpdparser_parse_baseURL (client);
+
+  return TRUE;
+}
+
+void
 gst_mpd_client_set_segment_index (GstActiveStream * stream, guint segment_idx)
 {
   g_return_if_fail (stream != NULL);
@@ -3355,6 +3555,169 @@ gst_mpdparser_get_active_stream_by_index (GstMpdClient * client,
   return g_list_nth_data (client->active_streams, stream_idx);
 }
 
+gint
+gst_mpd_client_get_video_active_stream_id(GstMpdClient *client) {
+  guint idx;
+  g_return_val_if_fail (client != NULL, -1);
+  g_return_val_if_fail (client->active_streams != NULL, -1);
+  for (idx = 0; idx < gst_mpdparser_get_nb_active_stream(client); idx++) {
+   GstActiveStream *stream = gst_mpdparser_get_active_stream_by_index(client, idx);
+   if( strncmp_ext (gst_mpd_client_get_stream_mimeType (stream), "video") == 0 )
+     return idx;
+  }
+  return -1;
+}
+
+gboolean
+gst_mpd_client_stream_seek (GstMpdClient * client, gint stream_idx, GstClockTime ts)
+{
+  guint segment_idx = 0;
+  GstActiveStream *stream;
+  GST_MPD_CLIENT_LOCK (client);
+  GST_DEBUG ("mpd client seeking to %"GST_TIME_FORMAT" on stream %d", GST_TIME_ARGS(ts), stream_idx);
+  stream = gst_mpdparser_get_active_stream_by_index (client, stream_idx);
+  g_return_val_if_fail (stream != NULL, FALSE);
+
+  if ( GST_CLOCK_TIME_IS_VALID (gst_mpd_client_stream_find_segment (client,
+          stream_idx, ts, &segment_idx))) {
+    gst_mpd_client_set_segment_index(stream, segment_idx);
+  }
+  GST_MPD_CLIENT_UNLOCK (client);
+  return TRUE;
+}
+
+static GDateTime *
+_gst_date_time_to_g_date_time (GstDateTime * datetime)
+{
+  g_return_val_if_fail (datetime != NULL, NULL);
+  return g_date_time_new_utc ( gst_date_time_get_year (datetime), gst_date_time_get_month(datetime),
+         gst_date_time_get_day(datetime), gst_date_time_get_hour(datetime),
+         gst_date_time_get_minute(datetime),gst_date_time_get_second(datetime));
+}
+
+gboolean
+gst_mpd_client_seek_to_time (GstMpdClient * client, GDateTime * time)
+{
+  GDateTime *start =
+      _gst_date_time_to_g_date_time (client->mpd_node->availabilityStartTime);
+  GTimeSpan ts_microseconds;
+  GstClockTime ts;
+  gboolean ret = TRUE;
+  gint i;
+
+  g_return_val_if_fail (gst_mpd_client_is_live (client), 0);
+
+  ts_microseconds = g_date_time_difference (time, start);
+  g_date_time_unref (start);
+
+  ts = ts_microseconds * GST_USECOND;
+  for (i=0; i < g_list_length (client->active_streams); i++) {
+    ret = ret & gst_mpd_client_stream_seek (client, i, ts);
+  }
+  return ret;
+}
+
+gint
+gst_mpd_client_check_time_position (GstMpdClient * client,
+    GstActiveStream * stream, GstClockTime ts, gint64 * diff)
+{
+  GDateTime *now = g_date_time_new_now_utc ();
+  GDateTime *start =
+      _gst_date_time_to_g_date_time (client->mpd_node->availabilityStartTime);
+  GTimeSpan stream_now;
+  GTimeSpan ts_microseconds;
+  GstClockTime duration;
+
+  g_return_val_if_fail (gst_mpd_client_is_live (client), 0);
+
+  duration = gst_mpd_client_get_segment_duration (client, stream);
+  stream_now = g_date_time_difference (now, start);
+  g_date_time_unref (now);
+  g_date_time_unref (start);
+
+  /* sum duration to check if the segment is fully ready */
+  ts_microseconds = (ts + duration) / GST_USECOND;
+
+  /*
+   * This functions checks if a given ts is in the 'available range' of
+   * a DASH presentation. This only makes sense for live streams, which
+   * are continuously adding new segments and removing old ones.
+   *
+   * Note: Both the client and the server should use UTC as a time reference.
+   *
+   * @ts is the time since the beginning of the stream and we need to find out
+   * if it is currently available. The server should be hosting segments
+   *
+   * * ---------------- ... --- * ----------- * ---- ...
+   * |
+   * | past(unavailable) |      | available   | future(unavailable yet)
+   * |
+   * * ---------------- ... --- * ----------- * ---- ...
+   * |                          |             |
+   * availabilitStartTime       |             UTC now
+   *                            UTC now - timeShiftBufferDepth
+   *
+   * This function should return 0 if @ts is in the 'available' area, 1 for
+   * 'future' and '-1' for past and the corresponding distance to the
+   * 'available' area is set to @diff
+   *
+   * TODO untested with live presentations with multiple periods as no
+   * examples for it could be found/generated
+   */
+
+  if (ts_microseconds > stream_now) {
+    *diff = ts_microseconds - stream_now;
+    return 1;
+  }
+  if (GST_CLOCK_TIME_IS_VALID (client->mpd_node->timeShiftBufferDepth)
+      && ts_microseconds <
+      stream_now - client->mpd_node->timeShiftBufferDepth * GST_USECOND) {
+    *diff = ts_microseconds - stream_now;
+    return -1;
+  }
+
+  *diff = 0;
+  return 0;
+}
+
+/*Finds the segment with appropriate time*/
+GstClockTime
+gst_mpd_client_stream_find_segment(GstMpdClient *client, guint stream_idx,
+                                   GstClockTime seek_pos, guint *seg_num)
+{
+  guint cur_segment_idx=0;
+  GstMediaSegment *chunk;
+  GList *list = NULL;
+  GstClockTime current_pos = 0;
+  GstActiveStream *stream = gst_mpdparser_get_active_stream_by_index (client, stream_idx);
+  g_return_val_if_fail (stream != NULL, GST_CLOCK_TIME_NONE);
+  if(stream->segments != NULL) {
+    for (list = g_list_first (stream->segments); list;
+        list = g_list_next (list)) {
+      chunk = list->data;
+      current_pos = chunk->start_time;
+      if (current_pos <= seek_pos
+          && seek_pos < current_pos + chunk->duration) {
+        break;
+      }
+      cur_segment_idx++;
+    }
+    if(list != NULL) {
+      *seg_num = cur_segment_idx;
+      return current_pos;
+    } else {
+      return GST_CLOCK_TIME_NONE;
+    }
+  } else {
+    GstClockTime duration;
+    duration = gst_mpd_client_get_segment_duration (client, stream);
+    if( !GST_CLOCK_TIME_IS_VALID (duration) )
+      return FALSE;
+    *seg_num = seek_pos / duration;
+    return *seg_num * duration;
+  }
+}
+
 static const gchar *
 gst_mpdparser_mimetype_to_caps (const gchar * mimeType)
 {
@@ -3396,6 +3759,52 @@ gst_mpd_client_get_bitstream_switching_flag (GstActiveStream * stream)
   return stream->cur_adapt_set->bitstreamSwitching;
 }
 
+gboolean
+gst_mpd_client_get_max_video_dimensions (GstMpdClient *client, gint *max_width, gint *max_height)
+{
+  GList *period_it, *repr_it;
+  GstStreamPeriod *period;
+  GstAdaptationSetNode *adaptset;
+  GstRepresentationNode *repr;
+
+  g_return_val_if_fail (client != NULL, FALSE);
+  g_return_val_if_fail (max_height != NULL, FALSE);
+  g_return_val_if_fail (max_width != NULL, FALSE);
+
+  *max_width = 0;
+  *max_height = 0;
+
+  period_it = client->periods;
+  while(period_it) {
+    period = period_it->data;
+    adaptset = gst_mpdparser_get_adapt_set_with_mimeType_and_idx (
+          period->period->AdaptationSets, "video", 0);
+    if(adaptset == NULL)
+      continue;
+    repr_it = adaptset->Representations;
+
+    if(adaptset->RepresentationBase->width > *max_width)
+      *max_width = adaptset->RepresentationBase->width;
+    if(adaptset->RepresentationBase->height > *max_height)
+      *max_height = adaptset->RepresentationBase->height;
+
+    while(repr_it) {
+      repr = repr_it->data;
+      if(repr->RepresentationBase->width > *max_width)
+        *max_width = repr->RepresentationBase->width;
+      if(repr->RepresentationBase->height > *max_height)
+        *max_height = repr->RepresentationBase->height;
+      repr_it = repr_it->next;
+    }
+
+    period_it = period_it->next;
+  }
+  if(*max_width == 0 && *max_height == 0)
+    return FALSE;
+  else
+    return TRUE;
+}
+
 guint
 gst_mpd_client_get_video_stream_width (GstActiveStream * stream)
 {
@@ -3431,6 +3840,23 @@ gst_mpd_client_get_video_stream_height (GstActiveStream * stream)
 }
 
 guint
+gst_mpd_client_get_video_stream_bandwidth (GstActiveStream * stream)
+{
+  guint bandwidth;
+  
+  if (stream == NULL || stream->cur_adapt_set == NULL
+      || stream->cur_representation == NULL)
+    return 0;
+
+  bandwidth = stream->cur_representation->RepresentationBase->bandwidth;
+  if (bandwidth == 0) {
+    bandwidth = stream->cur_adapt_set->RepresentationBase->bandwidth;
+  }
+
+  return bandwidth;
+}
+
+guint
 gst_mpd_client_get_audio_stream_rate (GstActiveStream * stream)
 {
   const gchar *rate;