diff --git a/ext/dash/gstdashdemux.c b/ext/dash/gstdashdemux.c index 746ee88c24..f5416b38b8 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 319325caae..39e14cacce 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 64a434e30a..0d8d8d9b9a 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);