mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-10-05 10:12:20 +00:00
dashdemux: reworked the API to retrieve fragment timestamp, fragment duration and media presentation duration
This was necessary to support variable-duration Fragments. in the new API: - gst_mpd_client_get_current_position returns the timestamp of the NEXT fragment to download; - gst_mpd_client_get_next_fragment_duration returns the duration of the next fragment to download; - gst_mpd_client_get_media_presentation_duration returns the mediaPresentationDuration from the MPD file; also there is a new internal parser function: - gst_mpd_client_get_segment_duration extracts the constant segment duration from the MPD file (only used when there is no SegmentTimeline syntax element in the current representation) In gst_mpd_client_get_next_fragment, we set the timestamp/duration of the fragment just downloaded copying the values from the corresponding GstMediaSegment. TODO: rework SEEKING to support seeking across different Periods.
This commit is contained in:
parent
dc5d7d258e
commit
9387365fc9
3 changed files with 82 additions and 62 deletions
|
@ -507,6 +507,7 @@ gst_dash_demux_src_event (GstPad * pad, GstEvent * event)
|
||||||
GST_MPD_CLIENT_LOCK (demux->client);
|
GST_MPD_CLIENT_LOCK (demux->client);
|
||||||
stream = gst_mpdparser_get_active_stream_by_index (demux->client, 0);
|
stream = gst_mpdparser_get_active_stream_by_index (demux->client, 0);
|
||||||
|
|
||||||
|
/* FIXME: support seeking across periods */
|
||||||
current_pos = 0;
|
current_pos = 0;
|
||||||
target_pos = (GstClockTime) start;
|
target_pos = (GstClockTime) start;
|
||||||
for (walk = stream->segments; walk; walk = walk->next) {
|
for (walk = stream->segments; walk; walk = walk->next) {
|
||||||
|
@ -551,6 +552,7 @@ gst_dash_demux_src_event (GstPad * pad, GstEvent * event)
|
||||||
|
|
||||||
GST_MPD_CLIENT_LOCK (demux->client);
|
GST_MPD_CLIENT_LOCK (demux->client);
|
||||||
GST_DEBUG_OBJECT (demux, "Seeking to sequence %d", current_sequence);
|
GST_DEBUG_OBJECT (demux, "Seeking to sequence %d", current_sequence);
|
||||||
|
/* FIXME: support seeking across periods */
|
||||||
stream_idx = 0;
|
stream_idx = 0;
|
||||||
/* Update the current sequence on all streams */
|
/* Update the current sequence on all streams */
|
||||||
while (stream_idx < nb_active_stream) {
|
while (stream_idx < nb_active_stream) {
|
||||||
|
@ -562,7 +564,7 @@ gst_dash_demux_src_event (GstPad * pad, GstEvent * event)
|
||||||
stream_idx++;
|
stream_idx++;
|
||||||
}
|
}
|
||||||
/* Calculate offset in the next fragment */
|
/* Calculate offset in the next fragment */
|
||||||
gst_mpd_client_get_current_position (demux->client, &demux->position);
|
demux->position = gst_mpd_client_get_current_position (demux->client);
|
||||||
demux->position_shift = start - demux->position;
|
demux->position_shift = start - demux->position;
|
||||||
demux->need_segment = TRUE;
|
demux->need_segment = TRUE;
|
||||||
GST_MPD_CLIENT_UNLOCK (demux->client);
|
GST_MPD_CLIENT_UNLOCK (demux->client);
|
||||||
|
@ -685,7 +687,7 @@ gst_dash_demux_sink_event (GstPad * pad, GstEvent * event)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
/* Send duration message */
|
/* Send duration message */
|
||||||
if (!gst_mpd_client_is_live (demux->client)) {
|
if (!gst_mpd_client_is_live (demux->client)) {
|
||||||
GstClockTime duration = gst_mpd_client_get_duration (demux->client);
|
GstClockTime duration = gst_mpd_client_get_media_presentation_duration (demux->client);
|
||||||
|
|
||||||
if (duration != GST_CLOCK_TIME_NONE) {
|
if (duration != GST_CLOCK_TIME_NONE) {
|
||||||
GST_DEBUG_OBJECT (demux, "Sending duration message : %" GST_TIME_FORMAT,
|
GST_DEBUG_OBJECT (demux, "Sending duration message : %" GST_TIME_FORMAT,
|
||||||
|
@ -731,7 +733,7 @@ gst_dash_demux_src_query (GstPad * pad, GstQuery * query)
|
||||||
|
|
||||||
gst_query_parse_duration (query, &fmt, NULL);
|
gst_query_parse_duration (query, &fmt, NULL);
|
||||||
if (fmt == GST_FORMAT_TIME) {
|
if (fmt == GST_FORMAT_TIME) {
|
||||||
duration = gst_mpd_client_get_duration (dashdemux->client);
|
duration = gst_mpd_client_get_media_presentation_duration (dashdemux->client);
|
||||||
if (GST_CLOCK_TIME_IS_VALID (duration) && duration > 0) {
|
if (GST_CLOCK_TIME_IS_VALID (duration) && duration > 0) {
|
||||||
gst_query_set_duration (query, GST_FORMAT_TIME, duration);
|
gst_query_set_duration (query, GST_FORMAT_TIME, duration);
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
|
@ -752,7 +754,7 @@ gst_dash_demux_src_query (GstPad * pad, GstQuery * query)
|
||||||
if (fmt == GST_FORMAT_TIME) {
|
if (fmt == GST_FORMAT_TIME) {
|
||||||
GstClockTime duration;
|
GstClockTime duration;
|
||||||
|
|
||||||
duration = gst_mpd_client_get_duration (dashdemux->client);
|
duration = gst_mpd_client_get_media_presentation_duration (dashdemux->client);
|
||||||
if (GST_CLOCK_TIME_IS_VALID (duration) && duration > 0)
|
if (GST_CLOCK_TIME_IS_VALID (duration) && duration > 0)
|
||||||
stop = duration;
|
stop = duration;
|
||||||
|
|
||||||
|
@ -1151,7 +1153,7 @@ gst_dash_demux_download_loop (GstDashDemux * demux)
|
||||||
* buffering time */
|
* buffering time */
|
||||||
GstClockTime target_buffering_time =
|
GstClockTime target_buffering_time =
|
||||||
demux->min_buffering_time +
|
demux->min_buffering_time +
|
||||||
gst_mpd_client_get_target_duration (demux->client);
|
gst_mpd_client_get_next_fragment_duration (demux->client);
|
||||||
if (demux->max_buffering_time > target_buffering_time)
|
if (demux->max_buffering_time > target_buffering_time)
|
||||||
target_buffering_time = demux->max_buffering_time;
|
target_buffering_time = demux->max_buffering_time;
|
||||||
if (!demux->end_of_manifest
|
if (!demux->end_of_manifest
|
||||||
|
|
|
@ -83,6 +83,7 @@ static gchar *gst_mpdparser_get_initializationURL (GstURLType *InitializationURL
|
||||||
static gchar *gst_mpdparser_build_URL_from_template (const gchar *url_template, const gchar *id, guint number, guint bandwidth, guint time);
|
static gchar *gst_mpdparser_build_URL_from_template (const gchar *url_template, const gchar *id, guint number, guint bandwidth, guint time);
|
||||||
static gboolean gst_mpd_client_add_media_segment (GstActiveStream *stream, GstSegmentURLNode *url_node, guint number, guint start, GstClockTime start_time, GstClockTime duration);
|
static gboolean gst_mpd_client_add_media_segment (GstActiveStream *stream, GstSegmentURLNode *url_node, guint number, guint start, GstClockTime start_time, GstClockTime duration);
|
||||||
static const gchar *gst_mpdparser_mimetype_to_caps (const gchar * mimeType);
|
static const gchar *gst_mpdparser_mimetype_to_caps (const gchar * mimeType);
|
||||||
|
static GstClockTime gst_mpd_client_get_segment_duration (GstMpdClient * client);
|
||||||
|
|
||||||
/* Adaptation Set */
|
/* Adaptation Set */
|
||||||
static GstAdaptationSetNode *gst_mpdparser_get_first_adapt_set_with_mimeType (GList *AdaptationSets, const gchar *mimeType);
|
static GstAdaptationSetNode *gst_mpdparser_get_first_adapt_set_with_mimeType (GList *AdaptationSets, const gchar *mimeType);
|
||||||
|
@ -2331,6 +2332,40 @@ gst_mpdparser_parse_baseURL (GstMpdClient * client)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GstClockTime
|
||||||
|
gst_mpd_client_get_segment_duration (GstMpdClient * client)
|
||||||
|
{
|
||||||
|
GstActiveStream *stream;
|
||||||
|
GstStreamPeriod *stream_period;
|
||||||
|
GstMultSegmentBaseType *base = NULL;
|
||||||
|
GstClockTime duration;
|
||||||
|
guint timescale;
|
||||||
|
|
||||||
|
stream = gst_mpdparser_get_active_stream_by_index (client, client->stream_idx);
|
||||||
|
g_return_val_if_fail (stream != NULL, GST_CLOCK_TIME_NONE);
|
||||||
|
stream_period = gst_mpdparser_get_stream_period (client);
|
||||||
|
g_return_val_if_fail (stream_period != NULL, GST_CLOCK_TIME_NONE);
|
||||||
|
|
||||||
|
if (stream->cur_segment_list) {
|
||||||
|
base = stream->cur_segment_list->MultSegBaseType;
|
||||||
|
} else if (stream->cur_seg_template) {
|
||||||
|
base = stream->cur_seg_template->MultSegBaseType;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (base == NULL || base->SegBaseType == NULL) {
|
||||||
|
/* this may happen when we have a single segment */
|
||||||
|
duration = stream_period->duration;
|
||||||
|
} else {
|
||||||
|
duration = base->duration * GST_SECOND;
|
||||||
|
timescale = base->SegBaseType->timescale;
|
||||||
|
|
||||||
|
if (timescale > 1)
|
||||||
|
duration /= timescale;
|
||||||
|
}
|
||||||
|
|
||||||
|
return duration;
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************/
|
/*****************************/
|
||||||
/******* API functions *******/
|
/******* API functions *******/
|
||||||
/*****************************/
|
/*****************************/
|
||||||
|
@ -2504,7 +2539,10 @@ gst_mpd_client_setup_representation (GstMpdClient * client, GstActiveStream *str
|
||||||
g_return_val_if_fail (stream_period->period != NULL, FALSE);
|
g_return_val_if_fail (stream_period->period != NULL, FALSE);
|
||||||
|
|
||||||
PeriodStart = stream_period->start;
|
PeriodStart = stream_period->start;
|
||||||
PeriodEnd = stream_period->start + stream_period->duration;
|
if (GST_CLOCK_TIME_IS_VALID (stream_period->duration))
|
||||||
|
PeriodEnd = stream_period->start + stream_period->duration;
|
||||||
|
else
|
||||||
|
PeriodEnd = GST_CLOCK_TIME_NONE;
|
||||||
|
|
||||||
GST_LOG ("Building segment list for Period from %" GST_TIME_FORMAT " to %"
|
GST_LOG ("Building segment list for Period from %" GST_TIME_FORMAT " to %"
|
||||||
GST_TIME_FORMAT, GST_TIME_ARGS (PeriodStart), GST_TIME_ARGS (PeriodEnd));
|
GST_TIME_FORMAT, GST_TIME_ARGS (PeriodStart), GST_TIME_ARGS (PeriodEnd));
|
||||||
|
@ -2573,7 +2611,9 @@ gst_mpd_client_setup_representation (GstMpdClient * client, GstActiveStream *str
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
duration = gst_mpd_client_get_target_duration (client);
|
duration = gst_mpd_client_get_segment_duration (client);
|
||||||
|
if (!GST_CLOCK_TIME_IS_VALID (duration))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
while (SegmentURL) {
|
while (SegmentURL) {
|
||||||
if (!gst_mpd_client_add_media_segment (stream, SegmentURL->data, i, 0, start_time, duration)) {
|
if (!gst_mpd_client_add_media_segment (stream, SegmentURL->data, i, 0, start_time, duration)) {
|
||||||
|
@ -2638,7 +2678,9 @@ gst_mpd_client_setup_representation (GstMpdClient * client, GstActiveStream *str
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
duration = gst_mpd_client_get_target_duration (client);
|
duration = gst_mpd_client_get_segment_duration (client);
|
||||||
|
if (!GST_CLOCK_TIME_IS_VALID (duration) || !GST_CLOCK_TIME_IS_VALID (PeriodEnd))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
while (PeriodStart + start_time < PeriodEnd) {
|
while (PeriodStart + start_time < PeriodEnd) {
|
||||||
if (!gst_mpd_client_add_media_segment (stream, NULL, i, 0, start_time, duration)) {
|
if (!gst_mpd_client_add_media_segment (stream, NULL, i, 0, start_time, duration)) {
|
||||||
|
@ -2653,7 +2695,7 @@ gst_mpd_client_setup_representation (GstMpdClient * client, GstActiveStream *str
|
||||||
|
|
||||||
/* check duration of last segment */
|
/* check duration of last segment */
|
||||||
last_media_segment = g_list_last (stream->segments)->data;
|
last_media_segment = g_list_last (stream->segments)->data;
|
||||||
if (last_media_segment) {
|
if (last_media_segment && GST_CLOCK_TIME_IS_VALID (PeriodEnd)) {
|
||||||
if (last_media_segment->start_time + last_media_segment->duration > PeriodEnd) {
|
if (last_media_segment->start_time + last_media_segment->duration > PeriodEnd) {
|
||||||
last_media_segment->duration = PeriodEnd - last_media_segment->start_time;
|
last_media_segment->duration = PeriodEnd - last_media_segment->start_time;
|
||||||
GST_LOG ("Fixed duration of last segment: %" GST_TIME_FORMAT, GST_TIME_ARGS (last_media_segment->duration));
|
GST_LOG ("Fixed duration of last segment: %" GST_TIME_FORMAT, GST_TIME_ARGS (last_media_segment->duration));
|
||||||
|
@ -2908,12 +2950,9 @@ gst_mpd_client_get_next_fragment (GstMpdClient * client,
|
||||||
stream->cur_representation->id, currentChunk->number, stream->cur_representation->bandwidth, currentChunk->start);
|
stream->cur_representation->id, currentChunk->number, stream->cur_representation->bandwidth, currentChunk->start);
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_mpd_client_get_current_position (client, timestamp);
|
*timestamp = currentChunk->start_time;
|
||||||
*duration = gst_mpd_client_get_target_duration (client);
|
*duration = currentChunk->duration;
|
||||||
//*timestamp = currentChunk->start_time;
|
|
||||||
//*duration = currentChunk->duration;
|
|
||||||
*discontinuity = stream->segment_idx != currentChunk->number;
|
*discontinuity = stream->segment_idx != currentChunk->number;
|
||||||
stream->segment_idx += 1;
|
|
||||||
if (mediaURL == NULL) {
|
if (mediaURL == NULL) {
|
||||||
/* single segment with URL encoded in the baseURL syntax element */
|
/* single segment with URL encoded in the baseURL syntax element */
|
||||||
*uri = g_strdup (gst_mpdparser_get_baseURL (client));
|
*uri = g_strdup (gst_mpdparser_get_baseURL (client));
|
||||||
|
@ -2923,6 +2962,7 @@ gst_mpd_client_get_next_fragment (GstMpdClient * client,
|
||||||
} else {
|
} else {
|
||||||
*uri = mediaURL;
|
*uri = mediaURL;
|
||||||
}
|
}
|
||||||
|
stream->segment_idx += 1;
|
||||||
GST_MPD_CLIENT_UNLOCK (client);
|
GST_MPD_CLIENT_UNLOCK (client);
|
||||||
|
|
||||||
GST_DEBUG ("Loading chunk with URL %s", *uri);
|
GST_DEBUG ("Loading chunk with URL %s", *uri);
|
||||||
|
@ -2965,24 +3005,37 @@ gst_mpd_client_get_next_header (GstMpdClient * client, const gchar **uri, guint
|
||||||
return *uri == NULL ? FALSE : TRUE;
|
return *uri == NULL ? FALSE : TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
GstClockTime
|
||||||
gst_mpd_client_get_current_position (GstMpdClient * client,
|
gst_mpd_client_get_current_position (GstMpdClient * client)
|
||||||
GstClockTime * timestamp)
|
|
||||||
{
|
{
|
||||||
GstActiveStream *stream;
|
GstActiveStream *stream;
|
||||||
GstClockTime duration;
|
GstMediaSegment *media_segment;
|
||||||
|
|
||||||
*timestamp = GST_CLOCK_TIME_NONE;
|
|
||||||
|
|
||||||
stream = g_list_nth_data (client->active_streams, client->stream_idx);
|
stream = g_list_nth_data (client->active_streams, client->stream_idx);
|
||||||
g_return_if_fail (stream != NULL);
|
g_return_val_if_fail (stream != NULL, GST_CLOCK_TIME_NONE);
|
||||||
|
|
||||||
duration = gst_mpd_client_get_target_duration (client);
|
media_segment = g_list_nth_data (stream->segments, stream->segment_idx);
|
||||||
*timestamp = duration == GST_CLOCK_TIME_NONE ? GST_CLOCK_TIME_NONE : stream->segment_idx * duration;
|
g_return_val_if_fail (media_segment != NULL, GST_CLOCK_TIME_NONE);
|
||||||
|
|
||||||
|
return media_segment->start_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
GstClockTime
|
GstClockTime
|
||||||
gst_mpd_client_get_duration (GstMpdClient * client)
|
gst_mpd_client_get_next_fragment_duration (GstMpdClient * client)
|
||||||
|
{
|
||||||
|
GstActiveStream *stream;
|
||||||
|
GstMediaSegment *media_segment;
|
||||||
|
|
||||||
|
stream = g_list_nth_data (client->active_streams, client->stream_idx);
|
||||||
|
g_return_val_if_fail (stream != NULL, 0);
|
||||||
|
|
||||||
|
media_segment = g_list_nth_data (stream->segments, stream->segment_idx);
|
||||||
|
|
||||||
|
return media_segment == NULL ? 0 : media_segment->duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
GstClockTime
|
||||||
|
gst_mpd_client_get_media_presentation_duration (GstMpdClient * client)
|
||||||
{
|
{
|
||||||
GstClockTime duration;
|
GstClockTime duration;
|
||||||
|
|
||||||
|
@ -3000,41 +3053,6 @@ gst_mpd_client_get_duration (GstMpdClient * client)
|
||||||
return duration;
|
return duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
GstClockTime
|
|
||||||
gst_mpd_client_get_target_duration (GstMpdClient * client)
|
|
||||||
{
|
|
||||||
GstActiveStream *stream;
|
|
||||||
GstStreamPeriod *stream_period;
|
|
||||||
GstMultSegmentBaseType *base = NULL;
|
|
||||||
GstClockTime duration;
|
|
||||||
guint timescale;
|
|
||||||
|
|
||||||
stream = gst_mpdparser_get_active_stream_by_index (client, client->stream_idx);
|
|
||||||
g_return_val_if_fail (stream != NULL, GST_CLOCK_TIME_NONE);
|
|
||||||
stream_period = gst_mpdparser_get_stream_period (client);
|
|
||||||
g_return_val_if_fail (stream_period != NULL, GST_CLOCK_TIME_NONE);
|
|
||||||
|
|
||||||
if (stream->cur_segment_list) {
|
|
||||||
base = stream->cur_segment_list->MultSegBaseType;
|
|
||||||
} else if (stream->cur_seg_template) {
|
|
||||||
base = stream->cur_seg_template->MultSegBaseType;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (base == NULL || base->SegBaseType == NULL) {
|
|
||||||
/* this may happen when we have a single segment */
|
|
||||||
/* TODO: support SegmentTimeline */
|
|
||||||
duration = stream_period->duration;
|
|
||||||
} else {
|
|
||||||
duration = base->duration * GST_SECOND;
|
|
||||||
timescale = base->SegBaseType->timescale;
|
|
||||||
|
|
||||||
if (timescale > 1)
|
|
||||||
duration /= timescale;
|
|
||||||
}
|
|
||||||
|
|
||||||
return duration;
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gst_mpd_client_get_next_period (GstMpdClient *client)
|
gst_mpd_client_get_next_period (GstMpdClient *client)
|
||||||
{
|
{
|
||||||
|
|
|
@ -467,9 +467,9 @@ gboolean gst_mpd_parse (GstMpdClient *client, const gchar *data, gint size);
|
||||||
gboolean gst_mpd_client_setup_media_presentation (GstMpdClient *client);
|
gboolean gst_mpd_client_setup_media_presentation (GstMpdClient *client);
|
||||||
gboolean gst_mpd_client_setup_streaming (GstMpdClient *client, GstStreamMimeType mimeType, gchar* lang);
|
gboolean gst_mpd_client_setup_streaming (GstMpdClient *client, GstStreamMimeType mimeType, gchar* lang);
|
||||||
gboolean gst_mpd_client_setup_representation (GstMpdClient *client, GstActiveStream *stream, GstRepresentationNode *representation);
|
gboolean gst_mpd_client_setup_representation (GstMpdClient *client, GstActiveStream *stream, GstRepresentationNode *representation);
|
||||||
void gst_mpd_client_get_current_position (GstMpdClient *client, GstClockTime * timestamp);
|
GstClockTime gst_mpd_client_get_current_position (GstMpdClient *client);
|
||||||
GstClockTime gst_mpd_client_get_duration (GstMpdClient *client);
|
GstClockTime gst_mpd_client_get_next_fragment_duration (GstMpdClient * client);
|
||||||
GstClockTime gst_mpd_client_get_target_duration (GstMpdClient *client);
|
GstClockTime gst_mpd_client_get_media_presentation_duration (GstMpdClient *client);
|
||||||
gboolean gst_mpd_client_get_next_fragment (GstMpdClient *client, guint indexStream, gboolean *discontinuity, gchar **uri, GstClockTime *duration, GstClockTime *timestamp);
|
gboolean gst_mpd_client_get_next_fragment (GstMpdClient *client, guint indexStream, gboolean *discontinuity, gchar **uri, GstClockTime *duration, GstClockTime *timestamp);
|
||||||
gboolean gst_mpd_client_get_next_header (GstMpdClient *client, const gchar **uri, guint stream_idx);
|
gboolean gst_mpd_client_get_next_header (GstMpdClient *client, const gchar **uri, guint stream_idx);
|
||||||
gboolean gst_mpd_client_is_live (GstMpdClient * client);
|
gboolean gst_mpd_client_is_live (GstMpdClient * client);
|
||||||
|
|
Loading…
Reference in a new issue