From aa1fe88a082d55b7cd7dfe46e8aceee1316f648d Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 1 Jul 2013 17:50:37 -0300 Subject: [PATCH] dashdemux: each fragment can have its own index Return index URI/range to dashdemux from the mpdparser to be able to download and deliver them downstream for playback. --- ext/dash/gstdashdemux.c | 52 ++++++++++++++++------ ext/dash/gstmpdparser.c | 98 ++++++++++++++++++++++++++++++----------- ext/dash/gstmpdparser.h | 19 +++++++- 3 files changed, 129 insertions(+), 40 deletions(-) diff --git a/ext/dash/gstdashdemux.c b/ext/dash/gstdashdemux.c index a56896e363..0efd04a661 100644 --- a/ext/dash/gstdashdemux.c +++ b/ext/dash/gstdashdemux.c @@ -1854,10 +1854,6 @@ gst_dash_demux_get_next_fragment (GstDashDemux * demux) GstActiveStream *active_stream; GstFragment *download; GstBuffer *header_buffer; - gchar *next_fragment_uri; - GstClockTime duration; - GstClockTime timestamp; - gboolean discont; GTimeVal now; GTimeVal start; GstClockTime diff; @@ -1916,33 +1912,35 @@ gst_dash_demux_get_next_fragment (GstDashDemux * demux) if (selected_stream) { guint stream_idx = selected_stream->index; GstBuffer *buffer; - gint64 range_start, range_end; + GstMediaFragmentInfo fragment; if (gst_mpd_client_get_next_fragment (demux->client, - stream_idx, &discont, &next_fragment_uri, &range_start, &range_end, - &duration, ×tamp)) { + stream_idx, &fragment)) { g_get_current_time (&start); GST_INFO_OBJECT (demux, "Next fragment for stream #%i", stream_idx); GST_INFO_OBJECT (demux, "Fetching next fragment %s ts:%" GST_TIME_FORMAT " dur:%" GST_TIME_FORMAT " Range:%" G_GINT64_FORMAT "-%" G_GINT64_FORMAT, - next_fragment_uri, GST_TIME_ARGS (timestamp), - GST_TIME_ARGS (duration), range_start, range_end); + fragment.uri, GST_TIME_ARGS (fragment.timestamp), + GST_TIME_ARGS (fragment.duration), + fragment.range_start, fragment.range_end); /* got a fragment to fetch, no end of period */ end_of_period = FALSE; download = gst_uri_downloader_fetch_uri_with_range (demux->downloader, - next_fragment_uri, range_start, range_end); - g_free (next_fragment_uri); + fragment.uri, fragment.range_start, fragment.range_end); - if (download == NULL) + if (download == NULL) { + gst_media_fragment_info_clear (&fragment); return FALSE; + } active_stream = gst_mpdparser_get_active_stream_by_index (demux->client, stream_idx); if (active_stream == NULL) { + gst_media_fragment_info_clear (&fragment); g_object_unref (download); return FALSE; } @@ -1950,6 +1948,30 @@ gst_dash_demux_get_next_fragment (GstDashDemux * demux) buffer = gst_fragment_get_buffer (download); g_object_unref (download); + /* it is possible to have an index per fragment, so check and download */ + if (fragment.index_uri || fragment.index_range_start + || fragment.index_range_end != -1) { + const gchar *uri = fragment.index_uri; + GstBuffer *index_buffer; + + if (!uri) /* fallback to default media uri */ + uri = fragment.uri; + + GST_DEBUG_OBJECT (demux, + "Fragment index download: %s %" G_GINT64_FORMAT "-%" + G_GINT64_FORMAT, uri, fragment.index_range_start, + fragment.index_range_end); + download = + gst_uri_downloader_fetch_uri_with_range (demux->downloader, uri, + fragment.index_range_start, fragment.index_range_end); + if (download) { + index_buffer = gst_fragment_get_buffer (download); + if (index_buffer) + buffer = gst_buffer_append (index_buffer, buffer); + g_object_unref (download); + } + } + if (selected_stream->need_header) { /* We need to fetch a new header */ if ((header_buffer = @@ -1964,11 +1986,13 @@ gst_dash_demux_get_next_fragment (GstDashDemux * demux) buffer = gst_buffer_make_writable (buffer); - GST_BUFFER_TIMESTAMP (buffer) = timestamp; - GST_BUFFER_DURATION (buffer) = duration; + GST_BUFFER_TIMESTAMP (buffer) = fragment.timestamp; + GST_BUFFER_DURATION (buffer) = fragment.duration; GST_BUFFER_OFFSET (buffer) = gst_mpd_client_get_segment_index (active_stream) - 1; + gst_media_fragment_info_clear (&fragment); + gst_dash_demux_stream_push_data (selected_stream, buffer); selected_stream->has_data_queued = TRUE; size_buffer += gst_buffer_get_size (buffer); diff --git a/ext/dash/gstmpdparser.c b/ext/dash/gstmpdparser.c index 92eaa1159e..05fed0318a 100644 --- a/ext/dash/gstmpdparser.c +++ b/ext/dash/gstmpdparser.c @@ -3281,13 +3281,12 @@ gst_mpd_client_get_next_fragment_timestamp (GstMpdClient * client, 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) + guint indexStream, GstMediaFragmentInfo * fragment) { GstActiveStream *stream = NULL; GstMediaSegment *currentChunk; gchar *mediaURL = NULL; + gchar *indexURL = NULL; guint segment_idx; /* select stream */ @@ -3296,7 +3295,6 @@ gst_mpd_client_get_next_fragment (GstMpdClient * client, stream = g_list_nth_data (client->active_streams, indexStream); g_return_val_if_fail (stream != NULL, FALSE); g_return_val_if_fail (stream->cur_representation != NULL, FALSE); - g_return_val_if_fail (discontinuity != NULL, FALSE); GST_MPD_CLIENT_LOCK (client); segment_idx = gst_mpd_client_get_segment_index (stream); @@ -3311,38 +3309,83 @@ gst_mpd_client_get_next_fragment (GstMpdClient * client, GST_DEBUG ("currentChunk->SegmentURL = %p", currentChunk->SegmentURL); if (currentChunk->SegmentURL != NULL) { - mediaURL = g_strdup (gst_mpdparser_get_mediaURL (stream, currentChunk->SegmentURL)); + mediaURL = + 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); + 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_DEBUG ("mediaURL = %s", mediaURL); + GST_DEBUG ("indexURL = %s", indexURL); - *timestamp = currentChunk->start_time; - *duration = currentChunk->duration; - *discontinuity = segment_idx != currentChunk->number; - *range_start = 0; - *range_end = -1; - if (currentChunk->SegmentURL && currentChunk->SegmentURL->mediaRange) { - *range_start = currentChunk->SegmentURL->mediaRange->first_byte_pos; - *range_end = currentChunk->SegmentURL->mediaRange->last_byte_pos; + 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) { + fragment->range_start = + currentChunk->SegmentURL->mediaRange->first_byte_pos; + fragment->range_end = currentChunk->SegmentURL->mediaRange->last_byte_pos; + } + if (currentChunk->SegmentURL->indexRange) { + fragment->index_range_start = + currentChunk->SegmentURL->indexRange->first_byte_pos; + fragment->index_range_end = + currentChunk->SegmentURL->indexRange->last_byte_pos; + } } if (mediaURL == NULL) { /* single segment with URL encoded in the baseURL syntax element */ - *uri = g_strdup (stream->baseURL); + fragment->uri = g_strdup (stream->baseURL); } else if (strncmp (mediaURL, "http://", 7) != 0) { - *uri = g_strconcat (stream->baseURL, mediaURL, stream->queryURL, NULL); + fragment->uri = + g_strconcat (stream->baseURL, mediaURL, stream->queryURL, NULL); } else { - *uri = g_strconcat (mediaURL, stream->queryURL, NULL); + fragment->uri = g_strconcat (mediaURL, stream->queryURL, NULL); } g_free (mediaURL); + + if (indexURL != NULL) { + if (strncmp (indexURL, "http://", 7) != 0) { + fragment->index_uri = + g_strconcat (stream->baseURL, indexURL, stream->queryURL, NULL); + } else { + fragment->index_uri = g_strconcat (indexURL, stream->queryURL, NULL); + } + g_free (indexURL); + } else if (fragment->index_range_start || fragment->index_range_end != -1) { + /* index has no specific URL but has a range, we should only use this if + * the media also has a range, otherwise we are serving some data twice + * (in the media fragment and again in the index) */ + if (!(fragment->range_start || fragment->range_end != -1)) { + GST_WARNING ("Ignoring index ranges because there isn't a media range " + "and URIs would be the same"); + /* removing index information */ + fragment->index_range_start = 0; + fragment->index_range_end = -1; + } + } + gst_mpd_client_set_segment_index (stream, segment_idx + 1); GST_MPD_CLIENT_UNLOCK (client); - GST_DEBUG ("Loading chunk with URL %s", *uri); + GST_DEBUG ("Loading chunk with URL %s", fragment->uri); return TRUE; } @@ -3369,8 +3412,8 @@ gst_mpd_client_get_next_header (GstMpdClient * client, gchar ** uri, *uri = NULL; if (stream->cur_segment_base && stream->cur_segment_base->Initialization) { *uri = - g_strdup (gst_mpdparser_get_initializationURL (stream, stream->cur_segment_base-> - Initialization)); + g_strdup (gst_mpdparser_get_initializationURL (stream, + stream->cur_segment_base->Initialization)); if (stream->cur_segment_base->Initialization->range) { *range_start = stream->cur_segment_base->Initialization->range->first_byte_pos; @@ -3419,12 +3462,10 @@ gst_mpd_client_get_next_header_index (GstMpdClient * client, gchar ** uri, *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; + 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) { @@ -3812,3 +3853,10 @@ gst_mpdparser_get_list_and_nb_of_audio_language (GstMpdClient * client, return nb_adapatation_set; } + +void +gst_media_fragment_info_clear (GstMediaFragmentInfo * fragment) +{ + g_free (fragment->uri); + g_free (fragment->index_uri); +} diff --git a/ext/dash/gstmpdparser.h b/ext/dash/gstmpdparser.h index f7582f9922..64a434e30a 100644 --- a/ext/dash/gstmpdparser.h +++ b/ext/dash/gstmpdparser.h @@ -34,6 +34,7 @@ G_BEGIN_DECLS typedef struct _GstMpdClient GstMpdClient; typedef struct _GstActiveStream GstActiveStream; typedef struct _GstStreamPeriod GstStreamPeriod; +typedef struct _GstMediaFragmentInfo GstMediaFragmentInfo; typedef struct _GstMediaSegment GstMediaSegment; typedef struct _GstMPDNode GstMPDNode; typedef struct _GstPeriodNode GstPeriodNode; @@ -417,6 +418,21 @@ struct _GstMediaSegment GstClockTime duration; /* segment duration */ }; +struct _GstMediaFragmentInfo +{ + gchar *uri; + gint64 range_start; + gint64 range_end; + + gchar *index_uri; + gint64 index_range_start; + gint64 index_range_end; + + gboolean discontinuity; + GstClockTime timestamp; + GstClockTime duration; +}; + /** * GstActiveStream: * @@ -460,6 +476,7 @@ struct _GstMpdClient GstMpdClient *gst_mpd_client_new (void); void gst_active_streams_free (GstMpdClient * client); void gst_mpd_client_free (GstMpdClient * client); +void gst_media_fragment_info_clear (GstMediaFragmentInfo * fragment); /* MPD file parsing */ gboolean gst_mpd_parse (GstMpdClient *client, const gchar *data, gint size); @@ -473,7 +490,7 @@ GstClockTime gst_mpd_client_get_next_fragment_duration (GstMpdClient * client); GstClockTime gst_mpd_client_get_media_presentation_duration (GstMpdClient *client); gboolean gst_mpd_client_get_last_fragment_timestamp (GstMpdClient * client, guint stream_idx, GstClockTime * ts); 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_fragment (GstMpdClient *client, guint indexStream, GstMediaFragmentInfo * fragment); 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);