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);
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
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,
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");
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");
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;
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;
}
}
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;
/* 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;
}
}
}
- 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);
client = g_new0 (GstMpdClient, 1);
client->lock = g_mutex_new ();
+ client->download_failed_count = 0;
+
return client;
}
}
/* free the document */
xmlFreeDoc (doc);
- /* cleanup function for the XML library */
- xmlCleanupParser ();
/* dump XML library memory for debugging */
xmlMemoryDump ();
}
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
}
}
} 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;
}
}
} 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 */
}
}
}
} 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;
/* 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;
}
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 =
}
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, ¤tChunk)) {
+ 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,
+ ¤tChunk)) {
+ 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;
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, ¤tChunk)) {
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));
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
{
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
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)
}
}
-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);
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)
{
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)
{
}
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;