diff options
author | Alex Ashley <bugzilla@ashley-family.net> | 2015-07-07 15:38:08 +0100 |
---|---|---|
committer | Vincent Penquerc'h <vincent.penquerch@collabora.co.uk> | 2015-10-29 13:26:46 +0000 |
commit | c8ef39cac7337b55901bfb38ca5a8ecda07376a8 (patch) | |
tree | 6b4382513df46bab80bd991147f68119f18317a2 /ext/dash | |
parent | d7a167c5b4e4aee7078119e8c963abaf1a29111b (diff) | |
download | gstreamer-plugins-bad-c8ef39cac7337b55901bfb38ca5a8ecda07376a8.tar.gz |
dashdemux: provide a default suggestedPresentationDelay
If MPD@suggestedPresentationDelay is not present in the manifest,
dashdemux selects the fragment closest to the most recently generated
fragment. This causes a playback issue because this choice does not allow
the DASH client to build up any buffer of downloaded fragments without
pausing playback. This is because by definition new fragments appear on
the server in real-time (e.g. if segment duration is 4 seconds, a new
fragment will appear on the server every 4 seconds). If the starting
playback position was n*segmentDuration seconds behind "now", the DASH
client could download up to 'n' fragments faster than realtime before it
reached the point where it needed to wait for fragments to appear on the
server.
The MPD@suggestedPresentationDelay attribute allows a content publisher
to provide a suggested starting position that is behind the current
"live" position.
If the MPD@suggestedPresentationDelay attribute is not present, provide
a suitable default value as a property of the dashdemux element. To
allow the default presentation delay to be specified either using
fragments or seconds, the property is a string that contains a number
and a unit (e.g. "10 seconds", "4 fragments", "2500ms").
Diffstat (limited to 'ext/dash')
-rw-r--r-- | ext/dash/gstdashdemux.c | 28 | ||||
-rw-r--r-- | ext/dash/gstdashdemux.h | 1 | ||||
-rw-r--r-- | ext/dash/gstmpdparser.c | 40 | ||||
-rw-r--r-- | ext/dash/gstmpdparser.h | 1 |
4 files changed, 70 insertions, 0 deletions
diff --git a/ext/dash/gstdashdemux.c b/ext/dash/gstdashdemux.c index 3d909da71..4156bd59e 100644 --- a/ext/dash/gstdashdemux.c +++ b/ext/dash/gstdashdemux.c @@ -146,6 +146,7 @@ #include <string.h> #include <stdio.h> +#include <stdlib.h> #include <inttypes.h> #include <gio/gio.h> #include <gst/base/gsttypefindhelper.h> @@ -188,6 +189,7 @@ enum PROP_MAX_BUFFERING_TIME, PROP_BANDWIDTH_USAGE, PROP_MAX_BITRATE, + PROP_PRESENTATION_DELAY, PROP_LAST }; @@ -195,6 +197,7 @@ enum #define DEFAULT_MAX_BUFFERING_TIME 30 /* in seconds */ #define DEFAULT_BANDWIDTH_USAGE 0.8 /* 0 to 1 */ #define DEFAULT_MAX_BITRATE 24000000 /* in bit/s */ +#define DEFAULT_PRESENTATION_DELAY NULL /* zero */ /* Clock drift compensation for live streams */ #define SLOW_CLOCK_UPDATE_INTERVAL (1000000 * 30 * 60) /* 30 minutes */ @@ -299,6 +302,7 @@ gst_dash_demux_dispose (GObject * obj) gst_dash_demux_clock_drift_free (demux->clock_drift); demux->clock_drift = NULL; + g_free (demux->default_presentation_delay); G_OBJECT_CLASS (parent_class)->dispose (obj); } @@ -379,6 +383,12 @@ gst_dash_demux_class_init (GstDashDemuxClass * klass) 1000, G_MAXUINT, DEFAULT_MAX_BITRATE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_PRESENTATION_DELAY, + g_param_spec_string ("presentation-delay", "Presentation delay", + "Default presentation delay (in seconds, milliseconds or fragments) (e.g. 12s, 2500ms, 3f)", + DEFAULT_PRESENTATION_DELAY, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_element_class_add_pad_template (gstelement_class, gst_static_pad_template_get (&gst_dash_demux_audiosrc_template)); gst_element_class_add_pad_template (gstelement_class, @@ -441,6 +451,7 @@ gst_dash_demux_init (GstDashDemux * demux) /* Properties */ demux->max_buffering_time = DEFAULT_MAX_BUFFERING_TIME * GST_SECOND; demux->max_bitrate = DEFAULT_MAX_BITRATE; + demux->default_presentation_delay = DEFAULT_PRESENTATION_DELAY; g_mutex_init (&demux->client_lock); @@ -465,6 +476,10 @@ gst_dash_demux_set_property (GObject * object, guint prop_id, case PROP_MAX_BITRATE: demux->max_bitrate = g_value_get_uint (value); break; + case PROP_PRESENTATION_DELAY: + g_free (demux->default_presentation_delay); + demux->default_presentation_delay = g_value_dup_string (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -488,6 +503,12 @@ gst_dash_demux_get_property (GObject * object, guint prop_id, GValue * value, case PROP_MAX_BITRATE: g_value_set_uint (value, demux->max_bitrate); break; + case PROP_PRESENTATION_DELAY: + if (demux->default_presentation_delay == NULL) + g_value_set_static_string (value, ""); + else + g_value_set_string (value, demux->default_presentation_delay); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -684,6 +705,13 @@ gst_dash_demux_setup_streams (GstAdaptiveDemux * demux) dashdemux->client->mpd_node->suggestedPresentationDelay * -1000); gst_date_time_unref (now); now = target; + } else if (dashdemux->default_presentation_delay) { + gint64 dfp = + gst_mpd_client_parse_default_presentation_delay (dashdemux->client, + dashdemux->default_presentation_delay); + GstDateTime *target = gst_mpd_client_add_time_difference (now, dfp); + gst_date_time_unref (now); + now = target; } period_idx = gst_mpd_client_get_period_index_at_time (dashdemux->client, now); diff --git a/ext/dash/gstdashdemux.h b/ext/dash/gstdashdemux.h index 3d01a0bf2..5ed96205b 100644 --- a/ext/dash/gstdashdemux.h +++ b/ext/dash/gstdashdemux.h @@ -96,6 +96,7 @@ struct _GstDashDemux /* Properties */ GstClockTime max_buffering_time; /* Maximum buffering time accumulated during playback */ guint64 max_bitrate; /* max of bitrate supported by target decoder */ + gchar* default_presentation_delay; /* presentation time delay if MPD@suggestedPresentationDelay is not present */ gint n_audio_streams; gint n_video_streams; diff --git a/ext/dash/gstmpdparser.c b/ext/dash/gstmpdparser.c index 953e207d4..3a1cb8256 100644 --- a/ext/dash/gstmpdparser.c +++ b/ext/dash/gstmpdparser.c @@ -5807,3 +5807,43 @@ gst_mpd_client_has_isoff_ondemand_profile (GstMpdClient * client) { return client->profile_isoff_ondemand; } + +/** + * gst_mpd_client_parse_default_presentation_delay: + * @client: #GstMpdClient that has a parsed manifest + * @default_presentation_delay: A string that specifies a time period + * in fragments (e.g. "5 f"), seconds ("12 s") or milliseconds + * ("12000 ms") + * Returns: the parsed string in milliseconds + * + * Since: 1.6 + */ +gint64 +gst_mpd_client_parse_default_presentation_delay (GstMpdClient * client, + const gchar * default_presentation_delay) +{ + gint64 value; + char *endptr = NULL; + + g_return_val_if_fail (client != NULL, 0); + g_return_val_if_fail (default_presentation_delay != NULL, 0); + value = strtol (default_presentation_delay, &endptr, 10); + if (endptr == default_presentation_delay || value == 0) { + return 0; + } + while (*endptr == ' ') + endptr++; + if (*endptr == 's' || *endptr == 'S') { + value *= 1000; /* convert to ms */ + } else if (*endptr == 'f' || *endptr == 'F') { + gint64 segment_duration; + g_assert (client->mpd_node != NULL); + segment_duration = client->mpd_node->maxSegmentDuration; + value *= segment_duration; + } else if (*endptr != 'm' && *endptr != 'M') { + GST_ERROR ("Unable to parse default presentation delay: %s", + default_presentation_delay); + value = 0; + } + return value; +} diff --git a/ext/dash/gstmpdparser.h b/ext/dash/gstmpdparser.h index 6e29d22e1..f76b37959 100644 --- a/ext/dash/gstmpdparser.h +++ b/ext/dash/gstmpdparser.h @@ -594,6 +594,7 @@ guint gst_mpdparser_get_list_and_nb_of_audio_language (GstMpdClient *client, GLi gint64 gst_mpd_client_calculate_time_difference (const GstDateTime * t1, const GstDateTime * t2); GstDateTime *gst_mpd_client_add_time_difference (GstDateTime * t1, gint64 usecs); +gint64 gst_mpd_client_parse_default_presentation_delay(GstMpdClient * client, const gchar * default_presentation_delay); /* profiles */ gboolean gst_mpd_client_has_isoff_ondemand_profile (GstMpdClient *client); |