summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authorThiago Santos <thiagoss@osg.samsung.com>2015-05-07 16:30:48 -0300
committerThiago Santos <thiagoss@osg.samsung.com>2015-05-13 13:35:14 -0300
commit6344f86e44d0c31a169fd5942b61e9126b57027f (patch)
treee78a9580cfad33371954472b571863a5eb8c5b04 /ext
parent61cad123d75cbce137fa8eb3eb305a1ef32a13e4 (diff)
downloadgstreamer-plugins-bad-6344f86e44d0c31a169fd5942b61e9126b57027f.tar.gz
dashdemux: improve mpd parsing for repeated segment entries
Use a single segment to represent it internally to avoid using too much memory. This has the drawback of issuing a linear search to find the correct segment to play but this can be fixed by using binary searches or caching the current position and just looking for the next one. https://bugzilla.gnome.org/show_bug.cgi?id=748369
Diffstat (limited to 'ext')
-rw-r--r--ext/dash/gstmpdparser.c158
-rw-r--r--ext/dash/gstmpdparser.h6
2 files changed, 97 insertions, 67 deletions
diff --git a/ext/dash/gstmpdparser.c b/ext/dash/gstmpdparser.c
index 21f84f119..309dd51b0 100644
--- a/ext/dash/gstmpdparser.c
+++ b/ext/dash/gstmpdparser.c
@@ -131,11 +131,11 @@ static const gchar *gst_mpdparser_get_initializationURL (GstActiveStream *
static gchar *gst_mpdparser_build_URL_from_template (const gchar * url_template,
const gchar * id, guint number, guint bandwidth, guint64 time);
static gboolean gst_mpd_client_add_media_segment (GstActiveStream * stream,
- GstSegmentURLNode * url_node, guint number, guint64 start,
- GstClockTime start_time, GstClockTime duration);
+ GstSegmentURLNode * url_node, guint number, gint repeat, gint64 scale_start,
+ gint64 scale_duration, GstClockTime start, GstClockTime duration);
static const gchar *gst_mpdparser_mimetype_to_caps (const gchar * mimeType);
static GstClockTime gst_mpd_client_get_segment_duration (GstMpdClient * client,
- GstActiveStream * stream);
+ GstActiveStream * stream, gint64 * scale_duration);
static GstDateTime *gst_mpd_client_get_availability_start_time (GstMpdClient *
client);
@@ -2767,7 +2767,7 @@ gst_mpdparser_parse_baseURL (GstMpdClient * client, GstActiveStream * stream,
static GstClockTime
gst_mpd_client_get_segment_duration (GstMpdClient * client,
- GstActiveStream * stream)
+ GstActiveStream * stream, gint64 * scale_dur)
{
GstStreamPeriod *stream_period;
GstMultSegmentBaseType *base = NULL;
@@ -2787,8 +2787,12 @@ gst_mpd_client_get_segment_duration (GstMpdClient * client,
if (base == NULL || base->SegBaseType == NULL) {
/* this may happen when we have a single segment */
duration = stream_period->duration;
+ if (scale_dur)
+ *scale_dur = duration;
} else {
duration = base->duration * GST_SECOND;
+ if (scale_dur)
+ *scale_dur = duration;
timescale = base->SegBaseType->timescale;
if (timescale > 1)
@@ -2916,6 +2920,31 @@ gst_mpdparser_get_baseURL (GstMpdClient * client, guint indexStream)
return stream->baseURL;
}
+static gboolean
+gst_mpdparser_find_segment_by_index (GstMpdClient * client,
+ GPtrArray * segments, gint index, GstMediaSegment * result)
+{
+ gint i;
+ for (i = 0; i < segments->len; i++) {
+ GstMediaSegment *s;
+
+ s = g_ptr_array_index (segments, i);
+ if (s->number + s->repeat >= index) {
+ /* it is in this segment */
+ result->SegmentURL = s->SegmentURL;
+ result->number = index;
+ result->scale_start =
+ s->scale_start + (index - s->number) * s->scale_duration;
+ result->scale_duration = s->scale_duration;
+ result->start = s->start + (index - s->number) * s->duration;
+ result->duration = s->duration;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
gboolean
gst_mpdparser_get_chunk_by_index (GstMpdClient * client, guint indexStream,
guint indexChunk, GstMediaSegment * segment)
@@ -2928,26 +2957,20 @@ gst_mpdparser_get_chunk_by_index (GstMpdClient * client, guint indexStream,
stream = g_list_nth_data (client->active_streams, indexStream);
g_return_val_if_fail (stream != NULL, FALSE);
- if (stream->segments) {
- GstMediaSegment *list_segment;
- /* fixed list of segments */
- if (indexChunk >= stream->segments->len)
- return FALSE;
+ indexChunk += 1;
- list_segment = g_ptr_array_index (stream->segments, indexChunk);
- segment->SegmentURL = list_segment->SegmentURL;
- segment->number = list_segment->number;
- segment->start = list_segment->start;
- segment->start_time = list_segment->start_time;
- segment->duration = list_segment->duration;
+ if (stream->segments) {
+ return gst_mpdparser_find_segment_by_index (client, stream->segments,
+ indexChunk, segment);
} else {
GstClockTime duration;
GstStreamPeriod *stream_period;
+ gint64 scale_dur;
g_return_val_if_fail (stream->cur_seg_template->MultSegBaseType->
SegmentTimeline == NULL, FALSE);
/* segment template generator */
- duration = gst_mpd_client_get_segment_duration (client, stream);
+ duration = gst_mpd_client_get_segment_duration (client, stream, &scale_dur);
if (!GST_CLOCK_TIME_IS_VALID (duration))
return FALSE;
@@ -2955,11 +2978,13 @@ gst_mpdparser_get_chunk_by_index (GstMpdClient * client, guint indexStream,
segment->number = indexChunk
+ stream->cur_seg_template->MultSegBaseType->startNumber;
- segment->start_time = duration * indexChunk;
+ segment->scale_start = indexChunk * scale_dur;
+ segment->scale_duration = scale_dur;
+ segment->start = duration * indexChunk;
segment->duration = duration;
segment->SegmentURL = NULL;
- if (segment->start_time >= stream_period->duration) {
+ if (segment->start >= stream_period->duration) {
return FALSE;
}
}
@@ -2968,8 +2993,9 @@ gst_mpdparser_get_chunk_by_index (GstMpdClient * client, guint indexStream,
static gboolean
gst_mpd_client_add_media_segment (GstActiveStream * stream,
- GstSegmentURLNode * url_node, guint number, guint64 start,
- GstClockTime start_time, GstClockTime duration)
+ GstSegmentURLNode * url_node, guint number, gint repeat,
+ gint64 scale_start, gint64 scale_duration,
+ GstClockTime start, GstClockTime duration)
{
GstMediaSegment *media_segment;
@@ -2983,15 +3009,17 @@ gst_mpd_client_add_media_segment (GstActiveStream * stream,
media_segment->SegmentURL = url_node;
media_segment->number = number;
+ media_segment->scale_start = scale_start;
+ media_segment->scale_duration = scale_duration;
media_segment->start = start;
- media_segment->start_time = start_time;
media_segment->duration = duration;
+ media_segment->repeat = repeat;
g_ptr_array_add (stream->segments, media_segment);
- GST_LOG ("Added new segment: number %d, ts: %" GST_TIME_FORMAT ", dur: %"
- GST_TIME_FORMAT " start time %" GST_TIME_FORMAT, number,
- GST_TIME_ARGS (start), GST_TIME_ARGS (duration),
- GST_TIME_ARGS (start_time));
+ GST_LOG ("Added new segment: number %d, repeat %d, "
+ "ts: %" GST_TIME_FORMAT ", dur: %"
+ GST_TIME_FORMAT, number, repeat,
+ GST_TIME_ARGS (start), GST_TIME_ARGS (duration));
return TRUE;
}
@@ -3056,8 +3084,8 @@ gst_mpd_client_setup_representation (GstMpdClient * client,
stream->cur_adapt_set, representation)) == NULL) {
GST_DEBUG ("No useful SegmentList node for the current Representation");
/* here we should have a single segment for each representation, whose URL is encoded in the baseURL element */
- if (!gst_mpd_client_add_media_segment (stream, NULL, 1, 0, PeriodStart,
- PeriodEnd)) {
+ if (!gst_mpd_client_add_media_segment (stream, NULL, 1, 0, 0,
+ PeriodEnd - PeriodStart, PeriodStart, PeriodEnd)) {
return FALSE;
}
} else {
@@ -3083,7 +3111,7 @@ gst_mpd_client_setup_representation (GstMpdClient * client,
timeline = stream->cur_segment_list->MultSegBaseType->SegmentTimeline;
for (list = g_queue_peek_head_link (&timeline->S); list;
list = g_list_next (list)) {
- guint j, timescale;
+ guint timescale;
S = (GstSNode *) list->data;
GST_LOG ("Processing S node: d=%" G_GUINT64_FORMAT " r=%d t=%"
@@ -3100,28 +3128,30 @@ gst_mpd_client_setup_representation (GstMpdClient * client,
start_time /= timescale;
}
- for (j = 0; j <= S->r && SegmentURL != NULL; j++) {
- if (!gst_mpd_client_add_media_segment (stream, SegmentURL->data, i,
- start, start_time, duration)) {
- return FALSE;
- }
- i++;
- start += S->d;
- start_time += duration;
- SegmentURL = g_list_next (SegmentURL);
+ if (!gst_mpd_client_add_media_segment (stream, SegmentURL->data, i,
+ S->r, start, S->d, start_time, duration)) {
+ return FALSE;
}
+ i += S->r + 1;
+ start_time += duration * (S->r + 1);
+ start += S->d * (S->r + 1);
+ SegmentURL = g_list_next (SegmentURL);
}
} else {
- duration = gst_mpd_client_get_segment_duration (client, stream);
+ gint64 scale_dur;
+
+ duration =
+ gst_mpd_client_get_segment_duration (client, stream, &scale_dur);
if (!GST_CLOCK_TIME_IS_VALID (duration))
return FALSE;
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, scale_dur, start_time, duration)) {
return FALSE;
}
i++;
+ start += scale_dur;
start_time += duration;
SegmentURL = g_list_next (SegmentURL);
}
@@ -3141,7 +3171,8 @@ gst_mpd_client_setup_representation (GstMpdClient * client,
gst_mpdparser_init_active_stream_segments (stream);
/* here we should have a single segment for each representation, whose URL is encoded in the baseURL element */
- if (!gst_mpd_client_add_media_segment (stream, NULL, 1, 0, 0, PeriodEnd)) {
+ if (!gst_mpd_client_add_media_segment (stream, NULL, 1, 0, 0, PeriodEnd,
+ 0, PeriodEnd)) {
return FALSE;
}
} else {
@@ -3173,7 +3204,7 @@ gst_mpd_client_setup_representation (GstMpdClient * client,
gst_mpdparser_init_active_stream_segments (stream);
for (list = g_queue_peek_head_link (&timeline->S); list;
list = g_list_next (list)) {
- guint j, timescale;
+ guint timescale;
S = (GstSNode *) list->data;
GST_LOG ("Processing S node: d=%" G_GUINT64_FORMAT " r=%u t=%"
@@ -3189,15 +3220,13 @@ gst_mpd_client_setup_representation (GstMpdClient * client,
start_time /= timescale;
}
- for (j = 0; j <= S->r; j++) {
- if (!gst_mpd_client_add_media_segment (stream, NULL, i, start,
- start_time, duration)) {
- return FALSE;
- }
- i++;
- start += S->d;
- start_time += duration;
+ if (!gst_mpd_client_add_media_segment (stream, NULL, i, S->r, start,
+ S->d, start_time, duration)) {
+ return FALSE;
}
+ i += S->r + 1;
+ start += S->d * (S->r + 1);
+ start_time += duration * (S->r + 1);
}
} else {
/* NOP - The segment is created on demand with the template, no need
@@ -3211,9 +3240,8 @@ gst_mpd_client_setup_representation (GstMpdClient * client,
g_ptr_array_index (stream->segments, stream->segments->len - 1) : NULL;
if (last_media_segment && GST_CLOCK_TIME_IS_VALID (PeriodEnd)) {
- if (last_media_segment->start_time + last_media_segment->duration >
- PeriodEnd) {
- last_media_segment->duration = PeriodEnd - last_media_segment->start_time;
+ if (last_media_segment->start + last_media_segment->duration > PeriodEnd) {
+ last_media_segment->duration = PeriodEnd - last_media_segment->start;
GST_LOG ("Fixed duration of last segment: %" GST_TIME_FORMAT,
GST_TIME_ARGS (last_media_segment->duration));
}
@@ -3434,9 +3462,10 @@ gst_mpd_client_stream_seek (GstMpdClient * client, GstActiveStream * stream,
GstMediaSegment *segment = g_ptr_array_index (stream->segments, index);
GST_DEBUG ("Looking at fragment sequence chunk %d", index);
- if (segment->start_time <= ts
- && ts < segment->start_time + segment->duration) {
+ if (segment->start <= ts
+ && ts < segment->start + (segment->repeat + 1) * segment->duration) {
selectedChunk = segment;
+ index = segment->number + (ts - segment->start) / segment->duration;
break;
}
}
@@ -3446,7 +3475,7 @@ gst_mpd_client_stream_seek (GstMpdClient * client, GstActiveStream * stream,
}
} else {
GstClockTime duration =
- gst_mpd_client_get_segment_duration (client, stream);
+ gst_mpd_client_get_segment_duration (client, stream, NULL);
g_return_val_if_fail (stream->cur_seg_template->
MultSegBaseType->SegmentTimeline == NULL, FALSE);
if (!GST_CLOCK_TIME_IS_VALID (duration)) {
@@ -3457,7 +3486,6 @@ gst_mpd_client_stream_seek (GstMpdClient * client, GstActiveStream * stream,
gst_mpd_client_set_segment_index (stream, index);
-
return TRUE;
}
@@ -3569,7 +3597,7 @@ gst_mpd_client_get_last_fragment_timestamp (GstMpdClient * client,
return FALSE;
}
- *ts = currentChunk.start_time;
+ *ts = currentChunk.start;
return TRUE;
}
@@ -3594,7 +3622,7 @@ gst_mpd_client_get_next_fragment_timestamp (GstMpdClient * client,
return FALSE;
}
- *ts = currentChunk.start_time;
+ *ts = currentChunk.start;
return TRUE;
}
@@ -3648,19 +3676,19 @@ gst_mpd_client_get_next_fragment (GstMpdClient * client,
mediaURL =
gst_mpdparser_build_URL_from_template (stream->cur_seg_template->media,
stream->cur_representation->id, currentChunk.number,
- stream->cur_representation->bandwidth, currentChunk.start);
+ stream->cur_representation->bandwidth, currentChunk.scale_start);
if (stream->cur_seg_template->index) {
indexURL =
gst_mpdparser_build_URL_from_template (stream->
cur_seg_template->index, stream->cur_representation->id,
currentChunk.number, stream->cur_representation->bandwidth,
- currentChunk.start);
+ currentChunk.scale_start);
}
}
GST_DEBUG ("mediaURL = %s", mediaURL);
GST_DEBUG ("indexURL = %s", indexURL);
- fragment->timestamp = currentChunk.start_time;
+ fragment->timestamp = currentChunk.start;
fragment->duration = currentChunk.duration;
fragment->discontinuity = segment_idx != currentChunk.number;
fragment->range_start = 0;
@@ -3859,7 +3887,7 @@ gst_mpd_client_get_next_fragment_duration (GstMpdClient * client,
return media_segment == NULL ? 0 : media_segment->duration;
} else {
GstClockTime duration =
- gst_mpd_client_get_segment_duration (client, stream);
+ gst_mpd_client_get_segment_duration (client, stream, NULL);
g_return_val_if_fail (stream->cur_seg_template->MultSegBaseType->
SegmentTimeline == NULL, 0);
@@ -4227,7 +4255,7 @@ gst_mpd_client_get_next_segment_availability_end_time (GstMpdClient * client,
stream_period = gst_mpdparser_get_stream_period (client);
seg_idx = gst_mpd_client_get_segment_index (stream);
- seg_duration = gst_mpd_client_get_segment_duration (client, stream);
+ seg_duration = gst_mpd_client_get_segment_duration (client, stream, NULL);
if (seg_duration == 0)
return NULL;
availability_start_time = gst_mpd_client_get_availability_start_time (client);
@@ -4262,7 +4290,7 @@ gst_mpd_client_check_time_position (GstMpdClient * client,
g_return_val_if_fail (gst_mpd_client_is_live (client), 0);
- duration = gst_mpd_client_get_segment_duration (client, stream);
+ duration = gst_mpd_client_get_segment_duration (client, stream, NULL);
stream_now = g_date_time_difference (now, start);
g_date_time_unref (now);
g_date_time_unref (start);
diff --git a/ext/dash/gstmpdparser.h b/ext/dash/gstmpdparser.h
index 7a098c3bc..ddafd4b01 100644
--- a/ext/dash/gstmpdparser.h
+++ b/ext/dash/gstmpdparser.h
@@ -414,8 +414,10 @@ struct _GstMediaSegment
{
GstSegmentURLNode *SegmentURL; /* this is NULL when using a SegmentTemplate */
guint number; /* segment number */
- guint64 start; /* segment start time in timescale units */
- GstClockTime start_time; /* segment start time */
+ gint repeat; /* number of extra repetitions (0 = played only once) */
+ gint64 scale_start; /* start time in timescale units */
+ gint64 scale_duration; /* duration in timescale units */
+ GstClockTime start; /* segment start time */
GstClockTime duration; /* segment duration */
};