From 42fd04ce48a356d92fe373ac53185211839b1318 Mon Sep 17 00:00:00 2001 From: Alex Ashley Date: Thu, 26 Sep 2013 16:13:33 -0300 Subject: [PATCH] dashdemux: stop fetching live fragments that don't yet exist There is an issue for live streams where download_loop will keep downloading segments until it gets a 404 error for a segment that has not yet been published. This is a problem because this request for a segment that doesn't exist will propagate all the way back to the origin server(s). This means that dashdemux causes extra load on the origin server(s) for segments that aren't yet available. This patch uses availabilityStartTime, period and the host's idea of UTC to decide if a fragment is available to be requested from an HTTP server and filter out requests for fragments that are not yet available. https://bugzilla.gnome.org/show_bug.cgi?id=701404 --- ext/dash/gstdashdemux.c | 30 ++++++++++++++++++++++ ext/dash/gstmpdparser.c | 57 ++++++++++++++++++++++++++++++++++------- ext/dash/gstmpdparser.h | 4 +++ 3 files changed, 82 insertions(+), 9 deletions(-) diff --git a/ext/dash/gstdashdemux.c b/ext/dash/gstdashdemux.c index 25ee3307e1..a78c0e579a 100644 --- a/ext/dash/gstdashdemux.c +++ b/ext/dash/gstdashdemux.c @@ -2113,6 +2113,36 @@ gst_dash_demux_get_next_fragment (GstDashDemux * demux, gst_mpdparser_get_active_stream_by_index (demux->client, selected_stream->index); + /* If this is a live stream, check the segment end time to make sure + * it is available to download + */ + if (selected_stream && gst_mpd_client_is_live (demux->client) && + demux->client->mpd_node->minimumUpdatePeriod != -1) { + GstDateTime *seg_end_time; + GstDateTime *cur_time = gst_date_time_new_now_utc (); + + seg_end_time = + gst_mpd_client_get_next_segment_availability_end_time (demux->client, + *stream); + + if (seg_end_time) { + gint64 diff; + + cur_time = gst_date_time_new_now_utc (); + diff = gst_mpd_client_calculate_time_difference (cur_time, seg_end_time) + / GST_MSECOND; + gst_date_time_unref (seg_end_time); + gst_date_time_unref (cur_time); + if (diff > 0) { + GST_DEBUG_OBJECT (demux, + "Selected fragment has end timestamp > now (%" PRIi64 + "), delaying download", diff); + end_of_period = FALSE; + gst_dash_demux_download_wait (demux, diff); + } + } + } + /* Get the fragment corresponding to each stream index */ if (selected_stream) { guint stream_idx = selected_stream->index; diff --git a/ext/dash/gstmpdparser.c b/ext/dash/gstmpdparser.c index 955f046f0b..9fac7d8bb0 100644 --- a/ext/dash/gstmpdparser.c +++ b/ext/dash/gstmpdparser.c @@ -138,8 +138,6 @@ static GstClockTime gst_mpd_client_get_segment_duration (GstMpdClient * client, GstActiveStream * stream); static GstDateTime *gst_mpd_client_get_availability_start_time (GstMpdClient * client); -static gint64 gst_mpd_client_calculate_time_difference (const GstDateTime * t1, - const GstDateTime * t2); /* Adaptation Set */ static GstAdaptationSetNode @@ -2863,7 +2861,7 @@ gst_mpd_client_get_segment_duration (GstMpdClient * client, { GstStreamPeriod *stream_period; GstMultSegmentBaseType *base = NULL; - GstClockTime duration; + GstClockTime duration = 0; guint timescale; g_return_val_if_fail (stream != NULL, GST_CLOCK_TIME_NONE); @@ -3564,7 +3562,7 @@ gst_mpd_client_stream_seek (GstMpdClient * client, GstActiveStream * stream, return TRUE; } -static gint64 +gint64 gst_mpd_client_calculate_time_difference (const GstDateTime * t1, const GstDateTime * t2) { @@ -3633,17 +3631,19 @@ gst_mpd_client_get_segment_index_at_time (GstMpdClient * client, return diff / seg_duration; } -GstDateTime * +static GstDateTime * gst_mpd_client_get_availability_start_time (GstMpdClient * client) { - GstDateTime *t; + GstDateTime *start_time; - g_return_val_if_fail (client != NULL, NULL); + if (client == NULL) + return (GstDateTime *) NULL; GST_MPD_CLIENT_LOCK (client); - t = client->mpd_node->availabilityStartTime; + start_time = client->mpd_node->availabilityStartTime; + gst_date_time_ref (start_time); GST_MPD_CLIENT_UNLOCK (client); - return t; + return start_time; } gboolean @@ -4283,6 +4283,45 @@ gst_mpdparser_get_list_and_nb_of_audio_language (GstMpdClient * client, return nb_adapatation_set; } + +GstDateTime * +gst_mpd_client_get_next_segment_availability_end_time (GstMpdClient * client, + GstActiveStream * stream) +{ + GstDateTime *availability_start_time, *rv; + guint seg_idx; + GstClockTime seg_duration; + gint64 offset; + GstStreamPeriod *stream_period; + + g_return_val_if_fail (client != NULL, NULL); + g_return_val_if_fail (stream != NULL, NULL); + + stream_period = gst_mpdparser_get_stream_period (client); + + seg_idx = gst_mpd_client_get_segment_index (stream); + seg_duration = gst_mpd_client_get_segment_duration (client, stream); + if (seg_duration == 0) + return NULL; + availability_start_time = gst_mpd_client_get_availability_start_time (client); + if (availability_start_time == NULL) + return (GstDateTime *) NULL; + + if (stream_period && stream_period->period) { + GstDateTime *t = + gst_mpd_client_add_time_difference (availability_start_time, + stream_period->period->start * 1000); + gst_date_time_unref (availability_start_time); + availability_start_time = t; + } + + offset = (1 + seg_idx) * seg_duration; + rv = gst_mpd_client_add_time_difference (availability_start_time, + offset / GST_USECOND); + gst_date_time_unref (availability_start_time); + return rv; +} + gint gst_mpd_client_check_time_position (GstMpdClient * client, GstActiveStream * stream, GstClockTime ts, gint64 * diff) diff --git a/ext/dash/gstmpdparser.h b/ext/dash/gstmpdparser.h index 57c1d31321..ea2c953a37 100644 --- a/ext/dash/gstmpdparser.h +++ b/ext/dash/gstmpdparser.h @@ -504,6 +504,7 @@ gboolean gst_mpd_client_set_period_id (GstMpdClient *client, const gchar * perio guint gst_mpd_client_get_period_index (GstMpdClient *client); const gchar *gst_mpd_client_get_period_id (GstMpdClient *client); gboolean gst_mpd_client_has_next_period (GstMpdClient *client); +GstDateTime *gst_mpd_client_get_next_segment_availability_end_time (GstMpdClient * client, GstActiveStream * stream); /* Representation selection */ gint gst_mpdparser_get_rep_idx_with_max_bandwidth (GList *Representations, gint max_bandwidth); @@ -535,6 +536,9 @@ guint gst_mpd_client_get_audio_stream_num_channels (GstActiveStream * stream); /* Support multi language */ guint gst_mpdparser_get_list_and_nb_of_audio_language (GstMpdClient *client, GList **lang); + +gint64 gst_mpd_client_calculate_time_difference (const GstDateTime * t1, const GstDateTime * t2); + G_END_DECLS #endif /* __GST_MPDPARSER_H__ */