From d68fffc21758399c401593f1bd5915cbcf74e131 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 1 Jul 2013 13:19:15 -0300 Subject: [PATCH] dashdemux: handle top-level index urls Parse and provide access to top-level index segments if available. dashdemux should push those whenever a header is pushed. Fixes #700489 --- ext/dash/gstdashdemux.c | 72 +++++++++++++++++++++++++++-------------- ext/dash/gstmpdparser.c | 52 +++++++++++++++++++++++++++-- ext/dash/gstmpdparser.h | 3 +- 3 files changed, 100 insertions(+), 27 deletions(-) diff --git a/ext/dash/gstdashdemux.c b/ext/dash/gstdashdemux.c index 70f7aadac3..a56896e363 100644 --- a/ext/dash/gstdashdemux.c +++ b/ext/dash/gstdashdemux.c @@ -1686,35 +1686,63 @@ gst_dash_demux_select_representations (GstDashDemux * demux) return ret; } -static GstFragment * +static GstBuffer * +gst_dash_demux_download_header_fragment (GstDashDemux * demux, guint stream_idx, + gchar * path, gint64 range_start, gint64 range_end) +{ + GstBuffer *buffer; + gchar *next_header_uri; + GstFragment *fragment; + + if (strncmp (path, "http://", 7) != 0) { + next_header_uri = + g_strconcat (gst_mpdparser_get_baseURL (demux->client, stream_idx), + path, NULL); + g_free (path); + } else { + next_header_uri = path; + } + + fragment = gst_uri_downloader_fetch_uri_with_range (demux->downloader, + next_header_uri, range_start, range_end); + g_free (next_header_uri); + buffer = gst_fragment_get_buffer (fragment); + g_object_unref (fragment); + return buffer; +} + +static GstBuffer * gst_dash_demux_get_next_header (GstDashDemux * demux, guint stream_idx) { gchar *initializationURL; - gchar *next_header_uri; - GstFragment *fragment; + GstBuffer *header_buffer, *index_buffer = NULL; gint64 range_start, range_end; if (!gst_mpd_client_get_next_header (demux->client, &initializationURL, stream_idx, &range_start, &range_end)) return NULL; - if (strncmp (initializationURL, "http://", 7) != 0) { - next_header_uri = - g_strconcat (gst_mpdparser_get_baseURL (demux->client, stream_idx), - initializationURL, NULL); - g_free (initializationURL); - } else { - next_header_uri = initializationURL; + GST_INFO_OBJECT (demux, "Fetching header %s %" G_GINT64_FORMAT "-%" + G_GINT64_FORMAT, initializationURL, range_start, range_end); + header_buffer = gst_dash_demux_download_header_fragment (demux, stream_idx, + initializationURL, range_start, range_end); + + /* check if we have an index */ + if (gst_mpd_client_get_next_header_index (demux->client, &initializationURL, + stream_idx, &range_start, &range_end)) { + GST_INFO_OBJECT (demux, "Fetching index %s %" G_GINT64_FORMAT "-%" + G_GINT64_FORMAT, initializationURL, range_start, range_end); + index_buffer = gst_dash_demux_download_header_fragment (demux, stream_idx, + initializationURL, range_start, range_end); } - GST_INFO_OBJECT (demux, "Fetching header %s %" G_GINT64_FORMAT "-%" - G_GINT64_FORMAT, next_header_uri, range_start, range_end); + if (index_buffer && header_buffer) { + header_buffer = gst_buffer_append (header_buffer, index_buffer); + } else if (index_buffer) { + gst_buffer_unref (index_buffer); + } - fragment = gst_uri_downloader_fetch_uri_with_range (demux->downloader, - next_header_uri, range_start, range_end); - g_free (next_header_uri); - - return fragment; + return header_buffer; } static GstCaps * @@ -1824,7 +1852,8 @@ static gboolean gst_dash_demux_get_next_fragment (GstDashDemux * demux) { GstActiveStream *active_stream; - GstFragment *download, *header; + GstFragment *download; + GstBuffer *header_buffer; gchar *next_fragment_uri; GstClockTime duration; GstClockTime timestamp; @@ -1923,16 +1952,11 @@ gst_dash_demux_get_next_fragment (GstDashDemux * demux) if (selected_stream->need_header) { /* We need to fetch a new header */ - if ((header = + if ((header_buffer = gst_dash_demux_get_next_header (demux, stream_idx)) == NULL) { GST_WARNING_OBJECT (demux, "Unable to fetch header"); } else { - GstBuffer *header_buffer; - /* Replace fragment with a new one including the header */ - - header_buffer = gst_fragment_get_buffer (header); buffer = gst_buffer_append (header_buffer, buffer); - g_object_unref (header); } selected_stream->need_header = FALSE; } diff --git a/ext/dash/gstmpdparser.c b/ext/dash/gstmpdparser.c index c1a03b929a..92eaa1159e 100644 --- a/ext/dash/gstmpdparser.c +++ b/ext/dash/gstmpdparser.c @@ -1098,7 +1098,7 @@ gst_mpdparser_parse_seg_base_type_ext (GstSegmentBaseType ** pointer, gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "presentationTimeOffset", 0); seg_base_type->indexRange = - gst_mpdparser_get_xml_prop_string (a_node, "indexRange"); + gst_mpdparser_get_xml_prop_range (a_node, "indexRange"); seg_base_type->indexRangeExact = gst_mpdparser_get_xml_prop_boolean (a_node, "indexRangeExact"); @@ -2227,7 +2227,7 @@ gst_mpdparser_free_seg_base_type_ext (GstSegmentBaseType * seg_base_type) { if (seg_base_type) { if (seg_base_type->indexRange) - xmlFree (seg_base_type->indexRange); + g_slice_free (GstRange, seg_base_type->indexRange); gst_mpdparser_free_url_type_node (seg_base_type->Initialization); gst_mpdparser_free_url_type_node (seg_base_type->RepresentationIndex); g_slice_free (GstSegmentBaseType, seg_base_type); @@ -3397,6 +3397,54 @@ gst_mpd_client_get_next_header (GstMpdClient * client, gchar ** uri, return *uri == NULL ? FALSE : TRUE; } +gboolean +gst_mpd_client_get_next_header_index (GstMpdClient * client, gchar ** uri, + guint stream_idx, gint64 * range_start, gint64 * range_end) +{ + GstActiveStream *stream; + GstStreamPeriod *stream_period; + + stream = gst_mpdparser_get_active_stream_by_index (client, stream_idx); + g_return_val_if_fail (stream != NULL, FALSE); + g_return_val_if_fail (stream->cur_representation != NULL, FALSE); + stream_period = gst_mpdparser_get_stream_period (client); + g_return_val_if_fail (stream_period != NULL, FALSE); + g_return_val_if_fail (stream_period->period != NULL, FALSE); + + *range_start = 0; + *range_end = -1; + + GST_DEBUG ("Looking for current representation index"); + GST_MPD_CLIENT_LOCK (client); + *uri = NULL; + if (stream->cur_segment_base && stream->cur_segment_base->indexRange) { + *uri = + g_strdup (gst_mpdparser_get_initializationURL (stream, stream->cur_segment_base-> + Initialization)); + *range_start = + stream->cur_segment_base->indexRange->first_byte_pos; + *range_end = + stream->cur_segment_base->indexRange->last_byte_pos; + } else if (stream->cur_seg_template) { + const gchar *initialization = NULL; + if (stream->cur_seg_template->index) { + initialization = stream->cur_seg_template->index; + } else if (stream->cur_adapt_set->SegmentTemplate + && stream->cur_adapt_set->SegmentTemplate->index) { + initialization = stream->cur_adapt_set->SegmentTemplate->index; + } else if (stream_period->period->SegmentTemplate + && stream_period->period->SegmentTemplate->index) { + initialization = stream_period->period->SegmentTemplate->index; + } + *uri = gst_mpdparser_build_URL_from_template (initialization, + stream->cur_representation->id, 0, + stream->cur_representation->bandwidth, 0); + } + GST_MPD_CLIENT_UNLOCK (client); + + return *uri == NULL ? FALSE : TRUE; +} + GstClockTime gst_mpd_client_get_current_position (GstMpdClient * client) { diff --git a/ext/dash/gstmpdparser.h b/ext/dash/gstmpdparser.h index 9f005ba125..f7582f9922 100644 --- a/ext/dash/gstmpdparser.h +++ b/ext/dash/gstmpdparser.h @@ -142,7 +142,7 @@ struct _GstSegmentBaseType { guint timescale; guint presentationTimeOffset; - gchar *indexRange; + GstRange *indexRange; gboolean indexRangeExact; /* Initialization node */ GstURLType *Initialization; @@ -475,6 +475,7 @@ gboolean gst_mpd_client_get_last_fragment_timestamp (GstMpdClient * client, guin gboolean gst_mpd_client_get_next_fragment_timestamp (GstMpdClient * client, guint stream_idx, GstClockTime * ts); gboolean gst_mpd_client_get_next_fragment (GstMpdClient *client, guint indexStream, gboolean *discontinuity, gchar **uri, gint64 * range_start, gint64 * range_end, GstClockTime *duration, GstClockTime *timestamp); gboolean gst_mpd_client_get_next_header (GstMpdClient *client, gchar **uri, guint stream_idx, gint64 * range_start, gint64 * range_end); +gboolean gst_mpd_client_get_next_header_index (GstMpdClient *client, gchar **uri, guint stream_idx, gint64 * range_start, gint64 * range_end); gboolean gst_mpd_client_is_live (GstMpdClient * client); gboolean gst_mpd_client_stream_seek (GstMpdClient * client, GstActiveStream * stream, GstClockTime ts);