From b316d8a67736afb52b1e9527c3c8a147d445a6b7 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Fri, 5 Jul 2013 13:22:17 -0300 Subject: [PATCH] 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. --- ext/dash/gstmpdparser.c | 194 +++++++++++++++++++++++++--------------- ext/dash/gstmpdparser.h | 2 +- 2 files changed, 121 insertions(+), 75 deletions(-) diff --git a/ext/dash/gstmpdparser.c b/ext/dash/gstmpdparser.c index 479c679ee5..bc6152f13a 100644 --- a/ext/dash/gstmpdparser.c +++ b/ext/dash/gstmpdparser.c @@ -2609,7 +2609,8 @@ gst_mpdparser_free_active_stream (GstActiveStream * active_stream) active_stream->baseURL = NULL; g_free (active_stream->queryURL); 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); } } @@ -2998,23 +2999,50 @@ gst_mpdparser_get_baseURL (GstMpdClient * client, guint indexStream) 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 (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->segments != NULL, NULL); + g_return_val_if_fail (stream != NULL, FALSE); - if (indexChunk >= stream->segments->len) - return NULL; + if (stream->segments) { + 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 @@ -3067,7 +3095,6 @@ gst_mpd_client_setup_representation (GstMpdClient * client, if (stream->segments) { g_ptr_array_unref (stream->segments); stream->segments = NULL; - gst_mpdparser_init_active_stream_segments (stream); } stream_period = gst_mpdparser_get_stream_period (client); @@ -3087,6 +3114,10 @@ gst_mpd_client_setup_representation (GstMpdClient * client, || representation->SegmentList != NULL) { 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 */ if ((stream->cur_segment_base = 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 || 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 */ if (!gst_mpd_client_add_media_segment (stream, NULL, 1, 0, 0, PeriodEnd)) { return FALSE; @@ -3199,6 +3232,7 @@ gst_mpd_client_setup_representation (GstMpdClient * client, GList *list; 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)) { guint j, timescale; @@ -3228,26 +3262,14 @@ gst_mpd_client_setup_representation (GstMpdClient * client, } } } else { - duration = gst_mpd_client_get_segment_duration (client, stream); - if (!GST_CLOCK_TIME_IS_VALID (duration) - || !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; - } + /* NOP - The segment is created on demand with the template, no need + * to build a list */ } } } /* 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; 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); GST_MPD_CLIENT_LOCK (client); - for (i = 0; i < stream->segments->len; i++, segment_idx++) { - GstMediaSegment *segment = g_ptr_array_index (stream->segments, i); - GST_DEBUG ("Looking at fragment sequence chunk %d", segment_idx); - if (segment->start_time >= ts) { - selectedChunk = segment; - break; + if (stream->segments) { + for (i = 0; i < stream->segments->len; i++, segment_idx++) { + GstMediaSegment *segment = g_ptr_array_index (stream->segments, i); + GST_DEBUG ("Looking at fragment sequence chunk %d", segment_idx); + if (segment->start_time >= ts) { + selectedChunk = segment; + break; + } } - } - if (selectedChunk == NULL) { - GST_MPD_CLIENT_UNLOCK (client); - return FALSE; + if (selectedChunk == NULL) { + GST_MPD_CLIENT_UNLOCK (client); + 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); @@ -3619,7 +3653,7 @@ gst_mpd_client_get_last_fragment_timestamp (GstMpdClient * client, { GstActiveStream *stream; gint segment_idx; - GstMediaSegment *currentChunk; + GstMediaSegment currentChunk; GST_DEBUG ("Stream index: %i", 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; GST_DEBUG ("Looking for fragment sequence chunk %d", segment_idx); - currentChunk = - gst_mpdparser_get_chunk_by_index (client, stream_idx, segment_idx); - if (currentChunk == NULL) { + if (!gst_mpdparser_get_chunk_by_index (client, stream_idx, segment_idx, + ¤tChunk)) { GST_MPD_CLIENT_UNLOCK (client); return FALSE; } - *ts = currentChunk->start_time; + *ts = currentChunk.start_time; GST_MPD_CLIENT_UNLOCK (client); return TRUE; @@ -3648,7 +3681,7 @@ gst_mpd_client_get_next_fragment_timestamp (GstMpdClient * client, { GstActiveStream *stream; gint segment_idx; - GstMediaSegment *currentChunk; + GstMediaSegment currentChunk; GST_DEBUG ("Stream index: %i", 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); GST_DEBUG ("Looking for fragment sequence chunk %d", segment_idx); - currentChunk = - gst_mpdparser_get_chunk_by_index (client, stream_idx, segment_idx); - if (currentChunk == NULL) { + if (!gst_mpdparser_get_chunk_by_index (client, stream_idx, segment_idx, + ¤tChunk)) { GST_MPD_CLIENT_UNLOCK (client); return FALSE; } - *ts = currentChunk->start_time; + *ts = currentChunk.start_time; GST_MPD_CLIENT_UNLOCK (client); return TRUE; @@ -3676,7 +3708,7 @@ gst_mpd_client_get_next_fragment (GstMpdClient * client, guint indexStream, GstMediaFragmentInfo * fragment) { GstActiveStream *stream = NULL; - GstMediaSegment *currentChunk; + GstMediaSegment currentChunk; gchar *mediaURL = NULL; gchar *indexURL = NULL; guint segment_idx; @@ -3692,53 +3724,52 @@ 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, + ¤tChunk)) { GST_MPD_CLIENT_UNLOCK (client); return FALSE; } - GST_DEBUG ("currentChunk->SegmentURL = %p", currentChunk->SegmentURL); - if (currentChunk->SegmentURL != NULL) { + GST_DEBUG ("currentChunk->SegmentURL = %p", currentChunk.SegmentURL); + if (currentChunk.SegmentURL != NULL) { mediaURL = - g_strdup (gst_mpdparser_get_mediaURL (stream, - currentChunk->SegmentURL)); - indexURL = currentChunk->SegmentURL->index; + g_strdup (gst_mpdparser_get_mediaURL (stream, currentChunk.SegmentURL)); + indexURL = currentChunk.SegmentURL->index; } 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); if (stream->cur_seg_template->index) { indexURL = - gst_mpdparser_build_URL_from_template (stream->cur_seg_template-> - index, stream->cur_representation->id, currentChunk->number, - stream->cur_representation->bandwidth, currentChunk->start); + gst_mpdparser_build_URL_from_template (stream-> + cur_seg_template->index, stream->cur_representation->id, + currentChunk.number, stream->cur_representation->bandwidth, + currentChunk.start); } } GST_DEBUG ("mediaURL = %s", mediaURL); GST_DEBUG ("indexURL = %s", indexURL); - fragment->timestamp = currentChunk->start_time; - fragment->duration = currentChunk->duration; - fragment->discontinuity = segment_idx != currentChunk->number; + fragment->timestamp = currentChunk.start_time; + fragment->duration = currentChunk.duration; + fragment->discontinuity = segment_idx != currentChunk.number; fragment->range_start = 0; fragment->range_end = -1; fragment->index_uri = NULL; fragment->index_range_start = 0; fragment->index_range_end = -1; - if (currentChunk->SegmentURL) { - if (currentChunk->SegmentURL->mediaRange) { + if (currentChunk.SegmentURL) { + if (currentChunk.SegmentURL->mediaRange) { fragment->range_start = - currentChunk->SegmentURL->mediaRange->first_byte_pos; - fragment->range_end = currentChunk->SegmentURL->mediaRange->last_byte_pos; + currentChunk.SegmentURL->mediaRange->first_byte_pos; + fragment->range_end = currentChunk.SegmentURL->mediaRange->last_byte_pos; } - if (currentChunk->SegmentURL->indexRange) { + if (currentChunk.SegmentURL->indexRange) { fragment->index_range_start = - currentChunk->SegmentURL->indexRange->first_byte_pos; + currentChunk.SegmentURL->indexRange->first_byte_pos; 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); - if (seg_idx < stream->segments->len) - media_segment = g_ptr_array_index (stream->segments, seg_idx); + if (stream->segments) { + 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 @@ -4053,7 +4095,11 @@ gst_mpd_client_get_segments_counts (GstActiveStream * stream) { 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 diff --git a/ext/dash/gstmpdparser.h b/ext/dash/gstmpdparser.h index 56ad4862d9..8a346aaad2 100644 --- a/ext/dash/gstmpdparser.h +++ b/ext/dash/gstmpdparser.h @@ -509,7 +509,7 @@ gint gst_mpdparser_get_rep_idx_with_min_bandwidth (GList * Representations); /* URL management */ 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 */ guint gst_mpdparser_get_nb_active_stream (GstMpdClient *client);