#include <string.h>
#include <stdio.h>
+#include <stdlib.h>
#include <inttypes.h>
#include <gio/gio.h>
#include <gst/base/gsttypefindhelper.h>
PROP_MAX_BUFFERING_TIME,
PROP_BANDWIDTH_USAGE,
PROP_MAX_BITRATE,
+ PROP_PRESENTATION_DELAY,
PROP_LAST
};
#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 */
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);
}
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,
/* 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);
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;
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;
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);
/* 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;
{
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;
+}
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);
GST_END_TEST;
/*
+ * Test parsing of the default presentation delay property
+ */
+GST_START_TEST (dash_mpdparser_default_presentation_delay)
+{
+ const gchar *xml =
+ "<?xml version=\"1.0\"?>"
+ "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
+ " profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
+ " maxSegmentDuration=\"PT2S\">"
+ " <Period id=\"Period0\" start=\"P0S\"></Period></MPD>";
+
+ 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
*/
static Suite *
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)