diff options
author | Alex Ashley <bugzilla@ashley-family.net> | 2013-06-11 14:28:53 +0100 |
---|---|---|
committer | Thiago Santos <thiago.sousa.santos@collabora.com> | 2013-07-03 15:34:30 -0300 |
commit | 5ad2a2d161aad6dc64db53aa5c10daf6ed3d74b4 (patch) | |
tree | 76388f66a064a0f01fde1494154ddf44a2eb8f55 /ext | |
parent | 51d8fa58600bd46b138010339ece326b5ba3f700 (diff) | |
download | gstreamer-plugins-bad-5ad2a2d161aad6dc64db53aa5c10daf6ed3d74b4.tar.gz |
dashdemux: Change first fragment selection for live streams
When dashdemux selects its first fragment, it always selects the
first fragment listed in the manifest. For on-demand content,
this is the correct behaviour. However for live content, this
behaviour is undesirable because the first fragment listed in the
manifest might be some considerable time behind "now".
The commit uses the host's idea of UTC and tries to find the
oldest fragment that contains samples for this time of day.
https://bugzilla.gnome.org/show_bug.cgi?id=701509
Diffstat (limited to 'ext')
-rw-r--r-- | ext/dash/gstdashdemux.c | 48 | ||||
-rw-r--r-- | ext/dash/gstmpdparser.c | 91 | ||||
-rw-r--r-- | ext/dash/gstmpdparser.h | 4 |
3 files changed, 136 insertions, 7 deletions
diff --git a/ext/dash/gstdashdemux.c b/ext/dash/gstdashdemux.c index 746ee88c2..f5416b38b 100644 --- a/ext/dash/gstdashdemux.c +++ b/ext/dash/gstdashdemux.c @@ -793,8 +793,52 @@ gst_dash_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) gst_dash_demux_advance_period (demux); - /* start playing from the first segment */ - gst_mpd_client_set_segment_index_for_all_streams (demux->client, 0); + /* If stream is live, try to find the segment that is closest to current time */ + if (gst_mpd_client_is_live (demux->client)) { + GSList *iter; + GstDateTime *now = gst_date_time_new_now_utc (); + gint seg_idx; + + GST_DEBUG_OBJECT (demux, + "Seeking to current time of day for live stream "); + if (demux->client->mpd_node->suggestedPresentationDelay != -1) { + GstDateTime *target = gst_mpd_client_add_time_difference (now, + demux->client->mpd_node->suggestedPresentationDelay * -1000); + gst_date_time_unref (now); + now = target; + } + for (iter = demux->streams; iter; iter = g_slist_next (iter)) { + GstDashDemuxStream *stream = iter->data; + GstActiveStream *active_stream; + + active_stream = + gst_mpdparser_get_active_stream_by_index (demux->client, + stream->index); + + /* Get segment index corresponding to current time. */ + seg_idx = + gst_mpd_client_get_segment_index_at_time (demux->client, + active_stream, now); + if (seg_idx < 0) { + GST_WARNING_OBJECT (demux, + "Failed to find a segment that is available " + "at this point in time for stream %d.", stream->index); + seg_idx = 0; + } + GST_INFO_OBJECT (demux, + "Segment index corresponding to current time for stream " + "%d is %d.", stream->index, seg_idx); + gst_mpd_client_set_segment_index (active_stream, seg_idx); + } + + gst_date_time_unref (now); + } else { + GST_DEBUG_OBJECT (demux, + "Seeking to first segment for on-demand stream "); + + /* start playing from the first segment */ + gst_mpd_client_set_segment_index_for_all_streams (demux->client, 0); + } /* Send duration message */ if (!gst_mpd_client_is_live (demux->client)) { diff --git a/ext/dash/gstmpdparser.c b/ext/dash/gstmpdparser.c index 319325caa..39e14cacc 100644 --- a/ext/dash/gstmpdparser.c +++ b/ext/dash/gstmpdparser.c @@ -137,6 +137,10 @@ static gboolean gst_mpd_client_add_media_segment (GstActiveStream * stream, static const gchar *gst_mpdparser_mimetype_to_caps (const gchar * mimeType); 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 @@ -3498,6 +3502,87 @@ gst_mpd_client_stream_seek (GstMpdClient * client, GstActiveStream * stream, return TRUE; } +static gint64 +gst_mpd_client_calculate_time_difference (const GstDateTime * t1, + const GstDateTime * t2) +{ + GDateTime *gdt1, *gdt2; + GTimeSpan diff; + + g_assert (t1 != NULL && t2 != NULL); + gdt1 = gst_date_time_to_g_date_time ((GstDateTime *) t1); + gdt2 = gst_date_time_to_g_date_time ((GstDateTime *) t2); + diff = g_date_time_difference (gdt2, gdt1); + g_date_time_unref (gdt1); + g_date_time_unref (gdt2); + return diff * GST_USECOND; +} + +GstDateTime * +gst_mpd_client_add_time_difference (GstDateTime * t1, gint64 usecs) +{ + GDateTime *gdt; + GDateTime *gdt2; + GstDateTime *rv; + + g_assert (t1 != NULL); + gdt = gst_date_time_to_g_date_time (t1); + g_assert (gdt != NULL); + gdt2 = g_date_time_add (gdt, usecs); + g_assert (gdt2 != NULL); + g_date_time_unref (gdt); + rv = gst_date_time_new_from_g_date_time (gdt2); + + /* Don't g_date_time_unref(gdt2) because gst_date_time_new_from_g_date_time takes + * ownership of the GDateTime pointer. + */ + + return rv; +} + +gint +gst_mpd_client_get_segment_index_at_time (GstMpdClient * client, + GstActiveStream * stream, const GstDateTime * time) +{ + GstClockTime seg_duration; + gint64 diff; + GstDateTime *avail_start = + gst_mpd_client_get_availability_start_time (client); + GstStreamPeriod *stream_period = gst_mpdparser_get_stream_period (client); + + if (avail_start == NULL) + return -1; + + if (stream_period && stream_period->period) { + /* intentionally not unreffing avail_start */ + avail_start = gst_mpd_client_add_time_difference (avail_start, + stream_period->period->start * 1000); + } + diff = gst_mpd_client_calculate_time_difference (avail_start, time); + if (diff < 0) + return -2; + if (diff > gst_mpd_client_get_media_presentation_duration (client)) + return -3; + + /* TODO: Assumes all fragments are roughly the same duration */ + seg_duration = gst_mpd_client_get_next_fragment_duration (client, stream); + g_assert (seg_duration > 0); + return diff / seg_duration; +} + +GstDateTime * +gst_mpd_client_get_availability_start_time (GstMpdClient * client) +{ + GstDateTime *t; + + g_return_val_if_fail (client != NULL, NULL); + + GST_MPD_CLIENT_LOCK (client); + t = client->mpd_node->availabilityStartTime; + GST_MPD_CLIENT_UNLOCK (client); + return t; +} + gboolean gst_mpd_client_get_last_fragment_timestamp (GstMpdClient * client, guint stream_idx, GstClockTime * ts) @@ -3790,13 +3875,11 @@ gst_mpd_client_get_current_position (GstMpdClient * client) } GstClockTime -gst_mpd_client_get_next_fragment_duration (GstMpdClient * client) +gst_mpd_client_get_next_fragment_duration (GstMpdClient * client, + GstActiveStream * stream) { - GstActiveStream *stream; GstMediaSegment *media_segment; - GST_DEBUG ("Stream index: %i", client->stream_idx); - stream = g_list_nth_data (client->active_streams, client->stream_idx); g_return_val_if_fail (stream != NULL, 0); media_segment = diff --git a/ext/dash/gstmpdparser.h b/ext/dash/gstmpdparser.h index 64a434e30..0d8d8d9b9 100644 --- a/ext/dash/gstmpdparser.h +++ b/ext/dash/gstmpdparser.h @@ -486,7 +486,7 @@ gboolean gst_mpd_client_setup_media_presentation (GstMpdClient *client); gboolean gst_mpd_client_setup_streaming (GstMpdClient *client, GstStreamMimeType mimeType, const gchar* lang); gboolean gst_mpd_client_setup_representation (GstMpdClient *client, GstActiveStream *stream, GstRepresentationNode *representation); GstClockTime gst_mpd_client_get_current_position (GstMpdClient *client); -GstClockTime gst_mpd_client_get_next_fragment_duration (GstMpdClient * client); +GstClockTime gst_mpd_client_get_next_fragment_duration (GstMpdClient * client, GstActiveStream * stream); 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); @@ -495,6 +495,8 @@ gboolean gst_mpd_client_get_next_header (GstMpdClient *client, gchar **uri, guin 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); gboolean gst_mpd_client_stream_seek (GstMpdClient * client, GstActiveStream * stream, GstClockTime ts); +GstDateTime *gst_mpd_client_add_time_difference (GstDateTime * t1, gint64 usecs); +gint gst_mpd_client_get_segment_index_at_time (GstMpdClient *client, GstActiveStream * stream, const GstDateTime *time); /* Period selection */ gboolean gst_mpd_client_set_period_index (GstMpdClient *client, guint period_idx); |