diff --git a/ext/dash/gstdashdemux.c b/ext/dash/gstdashdemux.c index 3d909da711..4156bd59ed 100644 --- a/ext/dash/gstdashdemux.c +++ b/ext/dash/gstdashdemux.c @@ -146,6 +146,7 @@ #include #include +#include #include #include #include @@ -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 3d01a0bf2e..5ed96205b3 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 953e207d41..3a1cb82569 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 6e29d22e12..f76b37959b 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); diff --git a/tests/check/elements/dash_mpd.c b/tests/check/elements/dash_mpd.c index 633beb277f..00799faf5d 100644 --- a/tests/check/elements/dash_mpd.c +++ b/tests/check/elements/dash_mpd.c @@ -4750,6 +4750,49 @@ GST_START_TEST (dash_mpdparser_unmatched_segmentTimeline_segmentURL) GST_END_TEST; +/* + * Test parsing of the default presentation delay property + */ +GST_START_TEST (dash_mpdparser_default_presentation_delay) +{ + const gchar *xml = + "" + "" + " "; + + gboolean ret; + GstMpdClient *mpdclient = gst_mpd_client_new (); + gint64 value; + + ret = gst_mpd_parse (mpdclient, xml, (gint) strlen (xml)); + assert_equals_int (ret, TRUE); + value = gst_mpd_client_parse_default_presentation_delay (mpdclient, "5s"); + assert_equals_int64 (value, 5000); + value = gst_mpd_client_parse_default_presentation_delay (mpdclient, "5S"); + assert_equals_int64 (value, 5000); + value = + gst_mpd_client_parse_default_presentation_delay (mpdclient, "5 seconds"); + assert_equals_int64 (value, 5000); + value = gst_mpd_client_parse_default_presentation_delay (mpdclient, "2500ms"); + assert_equals_int64 (value, 2500); + value = gst_mpd_client_parse_default_presentation_delay (mpdclient, "3f"); + assert_equals_int64 (value, 6000); + value = gst_mpd_client_parse_default_presentation_delay (mpdclient, "3F"); + assert_equals_int64 (value, 6000); + value = gst_mpd_client_parse_default_presentation_delay (mpdclient, ""); + assert_equals_int64 (value, 0); + value = gst_mpd_client_parse_default_presentation_delay (mpdclient, "10"); + assert_equals_int64 (value, 0); + value = + gst_mpd_client_parse_default_presentation_delay (mpdclient, + "not a number"); + assert_equals_int64 (value, 0); +} + +GST_END_TEST; + /* * create a test suite containing all dash testcases */ @@ -4871,6 +4914,7 @@ dash_suite (void) tcase_add_test (tc_simpleMPD, dash_mpdparser_isoff_ondemand_profile); tcase_add_test (tc_simpleMPD, dash_mpdparser_GstDateTime); tcase_add_test (tc_simpleMPD, dash_mpdparser_various_duration_formats); + tcase_add_test (tc_simpleMPD, dash_mpdparser_default_presentation_delay); /* tests checking the MPD management * (eg. setting active streams, obtaining attributes values)