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
This commit is contained in:
Alex Ashley 2013-06-11 14:28:53 +01:00 committed by Thiago Santos
parent 51d8fa5860
commit 5ad2a2d161
3 changed files with 136 additions and 7 deletions

View file

@ -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)) {

View file

@ -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 =

View file

@ -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);