dashdemux: fix template based segment generation

When using a template based segment list, do not try to
contruct a finite segment list for the limits of the available periods.

We might not know when the period ends (for live streams) and we can
always create the segment on demand when requested by dashdemux,
avoiding use of some memory and cpu when re-creating this list.
This commit is contained in:
Thiago Santos 2013-07-05 13:22:17 -03:00
parent a8a355108a
commit b316d8a677
2 changed files with 121 additions and 75 deletions

View file

@ -2609,7 +2609,8 @@ gst_mpdparser_free_active_stream (GstActiveStream * active_stream)
active_stream->baseURL = NULL; active_stream->baseURL = NULL;
g_free (active_stream->queryURL); g_free (active_stream->queryURL);
active_stream->queryURL = NULL; active_stream->queryURL = NULL;
g_ptr_array_unref (active_stream->segments); if (active_stream->segments)
g_ptr_array_unref (active_stream->segments);
g_slice_free (GstActiveStream, active_stream); g_slice_free (GstActiveStream, active_stream);
} }
} }
@ -2998,23 +2999,50 @@ gst_mpdparser_get_baseURL (GstMpdClient * client, guint indexStream)
return stream->baseURL; return stream->baseURL;
} }
GstMediaSegment * gboolean
gst_mpdparser_get_chunk_by_index (GstMpdClient * client, guint indexStream, gst_mpdparser_get_chunk_by_index (GstMpdClient * client, guint indexStream,
guint indexChunk) guint indexChunk, GstMediaSegment * segment)
{ {
GstActiveStream *stream; GstActiveStream *stream;
/* select stream */ /* select stream */
g_return_val_if_fail (client != NULL, NULL); g_return_val_if_fail (client != NULL, FALSE);
g_return_val_if_fail (client->active_streams != NULL, NULL); g_return_val_if_fail (client->active_streams != NULL, FALSE);
stream = g_list_nth_data (client->active_streams, indexStream); 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);
g_return_val_if_fail (stream->segments != NULL, NULL);
if (indexChunk >= stream->segments->len) if (stream->segments) {
return NULL; GstMediaSegment *list_segment;
/* fixed list of segments */
if (indexChunk >= stream->segments->len)
return FALSE;
return (GstMediaSegment *) g_ptr_array_index (stream->segments, indexChunk); list_segment = g_ptr_array_index (stream->segments, indexChunk);
segment->SegmentURL = list_segment->SegmentURL;
segment->number = list_segment->number;
segment->start = list_segment->start;
segment->start_time = list_segment->start_time;
segment->duration = list_segment->duration;
} else {
GstClockTime duration;
guint timescale =
stream->cur_seg_template->MultSegBaseType->SegBaseType->timescale;
g_return_val_if_fail (stream->cur_seg_template->MultSegBaseType->
SegmentTimeline == NULL, FALSE);
/* segment template generator */
duration = gst_mpd_client_get_segment_duration (client, stream);
if (!GST_CLOCK_TIME_IS_VALID (duration))
return FALSE;
/* TODO check PeriodEnd for segment beyond end of period */
segment->number = indexChunk;
segment->start_time = duration * indexChunk;
segment->start_time = segment->start_time * timescale / GST_SECOND;
segment->duration = duration;
segment->SegmentURL = NULL;
}
return TRUE;
} }
static gboolean static gboolean
@ -3067,7 +3095,6 @@ gst_mpd_client_setup_representation (GstMpdClient * client,
if (stream->segments) { if (stream->segments) {
g_ptr_array_unref (stream->segments); g_ptr_array_unref (stream->segments);
stream->segments = NULL; stream->segments = NULL;
gst_mpdparser_init_active_stream_segments (stream);
} }
stream_period = gst_mpdparser_get_stream_period (client); stream_period = gst_mpdparser_get_stream_period (client);
@ -3087,6 +3114,10 @@ gst_mpd_client_setup_representation (GstMpdClient * client,
|| representation->SegmentList != NULL) { || representation->SegmentList != NULL) {
GList *SegmentURL; GList *SegmentURL;
/* We have a fixed list of segments for any of the cases here,
* init the segments list */
gst_mpdparser_init_active_stream_segments (stream);
/* get the first segment_base of the selected representation */ /* get the first segment_base of the selected representation */
if ((stream->cur_segment_base = if ((stream->cur_segment_base =
gst_mpdparser_get_segment_base (stream_period->period, gst_mpdparser_get_segment_base (stream_period->period,
@ -3181,6 +3212,8 @@ gst_mpd_client_setup_representation (GstMpdClient * client,
if (stream->cur_seg_template == NULL if (stream->cur_seg_template == NULL
|| stream->cur_seg_template->MultSegBaseType == NULL) { || stream->cur_seg_template->MultSegBaseType == NULL) {
gst_mpdparser_init_active_stream_segments (stream);
/* here we should have a single segment for each representation, whose URL is encoded in the baseURL element */ /* here we should have a single segment for each representation, whose URL is encoded in the baseURL element */
if (!gst_mpd_client_add_media_segment (stream, NULL, 1, 0, 0, PeriodEnd)) { if (!gst_mpd_client_add_media_segment (stream, NULL, 1, 0, 0, PeriodEnd)) {
return FALSE; return FALSE;
@ -3199,6 +3232,7 @@ gst_mpd_client_setup_representation (GstMpdClient * client,
GList *list; GList *list;
timeline = stream->cur_seg_template->MultSegBaseType->SegmentTimeline; timeline = stream->cur_seg_template->MultSegBaseType->SegmentTimeline;
gst_mpdparser_init_active_stream_segments (stream);
for (list = g_queue_peek_head_link (&timeline->S); list; list = g_list_next (list)) { for (list = g_queue_peek_head_link (&timeline->S); list; list = g_list_next (list)) {
guint j, timescale; guint j, timescale;
@ -3228,26 +3262,14 @@ gst_mpd_client_setup_representation (GstMpdClient * client,
} }
} }
} else { } else {
duration = gst_mpd_client_get_segment_duration (client, stream); /* NOP - The segment is created on demand with the template, no need
if (!GST_CLOCK_TIME_IS_VALID (duration) * to build a list */
|| !GST_CLOCK_TIME_IS_VALID (PeriodEnd)
|| duration <= 0)
return FALSE;
while (start_time < PeriodEnd) {
if (!gst_mpd_client_add_media_segment (stream, NULL, i, 0, start_time,
duration)) {
return FALSE;
}
i++;
start_time += duration;
}
} }
} }
} }
/* check duration of last segment */ /* check duration of last segment */
last_media_segment = stream->segments->len ? last_media_segment = (stream->segments && stream->segments->len) ?
g_ptr_array_index (stream->segments, stream->segments->len - 1) : NULL; g_ptr_array_index (stream->segments, stream->segments->len - 1) : NULL;
if (last_media_segment && GST_CLOCK_TIME_IS_VALID (PeriodEnd)) { if (last_media_segment && GST_CLOCK_TIME_IS_VALID (PeriodEnd)) {
@ -3510,18 +3532,30 @@ gst_mpd_client_stream_seek (GstMpdClient * client, GstActiveStream * stream,
g_return_val_if_fail (stream != NULL, 0); g_return_val_if_fail (stream != NULL, 0);
GST_MPD_CLIENT_LOCK (client); GST_MPD_CLIENT_LOCK (client);
for (i = 0; i < stream->segments->len; i++, segment_idx++) { if (stream->segments) {
GstMediaSegment *segment = g_ptr_array_index (stream->segments, i); for (i = 0; i < stream->segments->len; i++, segment_idx++) {
GST_DEBUG ("Looking at fragment sequence chunk %d", segment_idx); GstMediaSegment *segment = g_ptr_array_index (stream->segments, i);
if (segment->start_time >= ts) { GST_DEBUG ("Looking at fragment sequence chunk %d", segment_idx);
selectedChunk = segment; if (segment->start_time >= ts) {
break; selectedChunk = segment;
break;
}
} }
}
if (selectedChunk == NULL) { if (selectedChunk == NULL) {
GST_MPD_CLIENT_UNLOCK (client); GST_MPD_CLIENT_UNLOCK (client);
return FALSE; return FALSE;
}
} else {
GstClockTime duration =
gst_mpd_client_get_segment_duration (client, stream);
g_return_val_if_fail (stream->cur_seg_template->MultSegBaseType->
SegmentTimeline == NULL, FALSE);
if (!GST_CLOCK_TIME_IS_VALID (duration)) {
GST_MPD_CLIENT_UNLOCK (client);
return FALSE;
}
segment_idx = ts / duration;
} }
gst_mpd_client_set_segment_index (stream, segment_idx); gst_mpd_client_set_segment_index (stream, segment_idx);
@ -3619,7 +3653,7 @@ gst_mpd_client_get_last_fragment_timestamp (GstMpdClient * client,
{ {
GstActiveStream *stream; GstActiveStream *stream;
gint segment_idx; gint segment_idx;
GstMediaSegment *currentChunk; GstMediaSegment currentChunk;
GST_DEBUG ("Stream index: %i", stream_idx); GST_DEBUG ("Stream index: %i", stream_idx);
stream = g_list_nth_data (client->active_streams, stream_idx); stream = g_list_nth_data (client->active_streams, stream_idx);
@ -3629,14 +3663,13 @@ gst_mpd_client_get_last_fragment_timestamp (GstMpdClient * client,
segment_idx = gst_mpd_client_get_segments_counts (stream) - 1; segment_idx = gst_mpd_client_get_segments_counts (stream) - 1;
GST_DEBUG ("Looking for fragment sequence chunk %d", segment_idx); GST_DEBUG ("Looking for fragment sequence chunk %d", segment_idx);
currentChunk = if (!gst_mpdparser_get_chunk_by_index (client, stream_idx, segment_idx,
gst_mpdparser_get_chunk_by_index (client, stream_idx, segment_idx); &currentChunk)) {
if (currentChunk == NULL) {
GST_MPD_CLIENT_UNLOCK (client); GST_MPD_CLIENT_UNLOCK (client);
return FALSE; return FALSE;
} }
*ts = currentChunk->start_time; *ts = currentChunk.start_time;
GST_MPD_CLIENT_UNLOCK (client); GST_MPD_CLIENT_UNLOCK (client);
return TRUE; return TRUE;
@ -3648,7 +3681,7 @@ gst_mpd_client_get_next_fragment_timestamp (GstMpdClient * client,
{ {
GstActiveStream *stream; GstActiveStream *stream;
gint segment_idx; gint segment_idx;
GstMediaSegment *currentChunk; GstMediaSegment currentChunk;
GST_DEBUG ("Stream index: %i", stream_idx); GST_DEBUG ("Stream index: %i", stream_idx);
stream = g_list_nth_data (client->active_streams, stream_idx); stream = g_list_nth_data (client->active_streams, stream_idx);
@ -3658,14 +3691,13 @@ gst_mpd_client_get_next_fragment_timestamp (GstMpdClient * client,
segment_idx = gst_mpd_client_get_segment_index (stream); segment_idx = gst_mpd_client_get_segment_index (stream);
GST_DEBUG ("Looking for fragment sequence chunk %d", segment_idx); GST_DEBUG ("Looking for fragment sequence chunk %d", segment_idx);
currentChunk = if (!gst_mpdparser_get_chunk_by_index (client, stream_idx, segment_idx,
gst_mpdparser_get_chunk_by_index (client, stream_idx, segment_idx); &currentChunk)) {
if (currentChunk == NULL) {
GST_MPD_CLIENT_UNLOCK (client); GST_MPD_CLIENT_UNLOCK (client);
return FALSE; return FALSE;
} }
*ts = currentChunk->start_time; *ts = currentChunk.start_time;
GST_MPD_CLIENT_UNLOCK (client); GST_MPD_CLIENT_UNLOCK (client);
return TRUE; return TRUE;
@ -3676,7 +3708,7 @@ gst_mpd_client_get_next_fragment (GstMpdClient * client,
guint indexStream, GstMediaFragmentInfo * fragment) guint indexStream, GstMediaFragmentInfo * fragment)
{ {
GstActiveStream *stream = NULL; GstActiveStream *stream = NULL;
GstMediaSegment *currentChunk; GstMediaSegment currentChunk;
gchar *mediaURL = NULL; gchar *mediaURL = NULL;
gchar *indexURL = NULL; gchar *indexURL = NULL;
guint segment_idx; guint segment_idx;
@ -3692,53 +3724,52 @@ gst_mpd_client_get_next_fragment (GstMpdClient * client,
segment_idx = gst_mpd_client_get_segment_index (stream); segment_idx = gst_mpd_client_get_segment_index (stream);
GST_DEBUG ("Looking for fragment sequence chunk %d", segment_idx); GST_DEBUG ("Looking for fragment sequence chunk %d", segment_idx);
currentChunk = if (!gst_mpdparser_get_chunk_by_index (client, indexStream, segment_idx,
gst_mpdparser_get_chunk_by_index (client, indexStream, segment_idx); &currentChunk)) {
if (currentChunk == NULL) {
GST_MPD_CLIENT_UNLOCK (client); GST_MPD_CLIENT_UNLOCK (client);
return FALSE; return FALSE;
} }
GST_DEBUG ("currentChunk->SegmentURL = %p", currentChunk->SegmentURL); GST_DEBUG ("currentChunk->SegmentURL = %p", currentChunk.SegmentURL);
if (currentChunk->SegmentURL != NULL) { if (currentChunk.SegmentURL != NULL) {
mediaURL = mediaURL =
g_strdup (gst_mpdparser_get_mediaURL (stream, g_strdup (gst_mpdparser_get_mediaURL (stream, currentChunk.SegmentURL));
currentChunk->SegmentURL)); indexURL = currentChunk.SegmentURL->index;
indexURL = currentChunk->SegmentURL->index;
} else if (stream->cur_seg_template != NULL) { } else if (stream->cur_seg_template != NULL) {
mediaURL = mediaURL =
gst_mpdparser_build_URL_from_template (stream->cur_seg_template->media, gst_mpdparser_build_URL_from_template (stream->cur_seg_template->media,
stream->cur_representation->id, currentChunk->number, stream->cur_representation->id, currentChunk.number,
stream->cur_representation->bandwidth, currentChunk->start); stream->cur_representation->bandwidth, currentChunk.start);
if (stream->cur_seg_template->index) { if (stream->cur_seg_template->index) {
indexURL = indexURL =
gst_mpdparser_build_URL_from_template (stream->cur_seg_template-> gst_mpdparser_build_URL_from_template (stream->
index, stream->cur_representation->id, currentChunk->number, cur_seg_template->index, stream->cur_representation->id,
stream->cur_representation->bandwidth, currentChunk->start); currentChunk.number, stream->cur_representation->bandwidth,
currentChunk.start);
} }
} }
GST_DEBUG ("mediaURL = %s", mediaURL); GST_DEBUG ("mediaURL = %s", mediaURL);
GST_DEBUG ("indexURL = %s", indexURL); GST_DEBUG ("indexURL = %s", indexURL);
fragment->timestamp = currentChunk->start_time; fragment->timestamp = currentChunk.start_time;
fragment->duration = currentChunk->duration; fragment->duration = currentChunk.duration;
fragment->discontinuity = segment_idx != currentChunk->number; fragment->discontinuity = segment_idx != currentChunk.number;
fragment->range_start = 0; fragment->range_start = 0;
fragment->range_end = -1; fragment->range_end = -1;
fragment->index_uri = NULL; fragment->index_uri = NULL;
fragment->index_range_start = 0; fragment->index_range_start = 0;
fragment->index_range_end = -1; fragment->index_range_end = -1;
if (currentChunk->SegmentURL) { if (currentChunk.SegmentURL) {
if (currentChunk->SegmentURL->mediaRange) { if (currentChunk.SegmentURL->mediaRange) {
fragment->range_start = fragment->range_start =
currentChunk->SegmentURL->mediaRange->first_byte_pos; currentChunk.SegmentURL->mediaRange->first_byte_pos;
fragment->range_end = currentChunk->SegmentURL->mediaRange->last_byte_pos; fragment->range_end = currentChunk.SegmentURL->mediaRange->last_byte_pos;
} }
if (currentChunk->SegmentURL->indexRange) { if (currentChunk.SegmentURL->indexRange) {
fragment->index_range_start = fragment->index_range_start =
currentChunk->SegmentURL->indexRange->first_byte_pos; currentChunk.SegmentURL->indexRange->first_byte_pos;
fragment->index_range_end = fragment->index_range_end =
currentChunk->SegmentURL->indexRange->last_byte_pos; currentChunk.SegmentURL->indexRange->last_byte_pos;
} }
} }
@ -3898,10 +3929,21 @@ gst_mpd_client_get_next_fragment_duration (GstMpdClient * client,
seg_idx = gst_mpd_client_get_segment_index (stream); seg_idx = gst_mpd_client_get_segment_index (stream);
if (seg_idx < stream->segments->len) if (stream->segments) {
media_segment = g_ptr_array_index (stream->segments, seg_idx); if (seg_idx < stream->segments->len)
media_segment = g_ptr_array_index (stream->segments, seg_idx);
return media_segment == NULL ? 0 : media_segment->duration; 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);
if (GST_CLOCK_TIME_IS_VALID (duration))
return duration;
return 0;
}
} }
GstClockTime GstClockTime
@ -4053,7 +4095,11 @@ gst_mpd_client_get_segments_counts (GstActiveStream * stream)
{ {
g_return_val_if_fail (stream != NULL, 0); g_return_val_if_fail (stream != NULL, 0);
return stream->segments->len; if (stream->segments)
return stream->segments->len;
g_return_val_if_fail (stream->cur_seg_template->MultSegBaseType->
SegmentTimeline == NULL, 0);
return 0;
} }
gboolean gboolean

View file

@ -509,7 +509,7 @@ gint gst_mpdparser_get_rep_idx_with_min_bandwidth (GList * Representations);
/* URL management */ /* URL management */
const gchar *gst_mpdparser_get_baseURL (GstMpdClient *client, guint indexStream); const gchar *gst_mpdparser_get_baseURL (GstMpdClient *client, guint indexStream);
GstMediaSegment *gst_mpdparser_get_chunk_by_index (GstMpdClient *client, guint indexStream, guint indexChunk); gboolean gst_mpdparser_get_chunk_by_index (GstMpdClient *client, guint indexStream, guint indexChunk, GstMediaSegment * segment);
/* Active stream */ /* Active stream */
guint gst_mpdparser_get_nb_active_stream (GstMpdClient *client); guint gst_mpdparser_get_nb_active_stream (GstMpdClient *client);