mssdemux: support manifests with repetition fragments

Read the "r" attribute from fragments to support fragments nodes
that use repetition to have a shorter Manifest xml.

Instead of doing:
<c d="100" />
<c d="100" />

You can use:
<c d="100" r="2" />
This commit is contained in:
Thiago Santos 2014-12-02 23:27:29 -03:00
parent b418c88b26
commit a2c31e38d1

View file

@ -44,6 +44,7 @@ GST_DEBUG_CATEGORY_EXTERN (mssdemux_debug);
#define MSS_PROP_DURATION "d"
#define MSS_PROP_LANGUAGE "Language"
#define MSS_PROP_NUMBER "n"
#define MSS_PROP_REPETITIONS "r"
#define MSS_PROP_STREAM_DURATION "Duration"
#define MSS_PROP_TIME "t"
#define MSS_PROP_TIMESCALE "TimeScale"
@ -54,6 +55,7 @@ typedef struct _GstMssStreamFragment
guint number;
guint64 time;
guint64 duration;
guint repetitions;
} GstMssStreamFragment;
typedef struct _GstMssStreamQuality
@ -77,6 +79,7 @@ struct _GstMssStream
gchar *url;
gchar *lang;
guint fragment_repetition_index;
GList *current_fragment;
GList *current_quality;
@ -158,11 +161,14 @@ _gst_mss_stream_init (GstMssStream * stream, xmlNodePtr node)
gchar *duration_str;
gchar *time_str;
gchar *seqnum_str;
gchar *repetition_str;
GstMssStreamFragment *fragment = g_new (GstMssStreamFragment, 1);
duration_str = (gchar *) xmlGetProp (iter, (xmlChar *) MSS_PROP_DURATION);
time_str = (gchar *) xmlGetProp (iter, (xmlChar *) MSS_PROP_TIME);
seqnum_str = (gchar *) xmlGetProp (iter, (xmlChar *) MSS_PROP_NUMBER);
repetition_str =
(gchar *) xmlGetProp (iter, (xmlChar *) MSS_PROP_REPETITIONS);
/* use the node's seq number or use the previous + 1 */
if (seqnum_str) {
@ -174,6 +180,13 @@ _gst_mss_stream_init (GstMssStream * stream, xmlNodePtr node)
}
fragment_number = fragment->number + 1;
if (repetition_str) {
fragment->repetitions = g_ascii_strtoull (repetition_str, NULL, 10);
xmlFree (repetition_str);
} else {
fragment->repetitions = 1;
}
if (time_str) {
fragment->time = g_ascii_strtoull (time_str, NULL, 10);
@ -185,13 +198,15 @@ _gst_mss_stream_init (GstMssStream * stream, xmlNodePtr node)
/* if we have a previous fragment, means we need to set its duration */
if (previous_fragment)
previous_fragment->duration = fragment->time - previous_fragment->time;
previous_fragment->duration =
(fragment->time -
previous_fragment->time) / previous_fragment->repetitions;
if (duration_str) {
fragment->duration = g_ascii_strtoull (duration_str, NULL, 10);
previous_fragment = NULL;
fragment_time_accum += fragment->duration;
fragment_time_accum += fragment->duration * fragment->repetitions;
xmlFree (duration_str);
} else {
/* store to set the duration at the next iteration */
@ -200,6 +215,10 @@ _gst_mss_stream_init (GstMssStream * stream, xmlNodePtr node)
/* we reverse it later */
stream->fragments = g_list_prepend (stream->fragments, fragment);
GST_LOG ("Adding fragment number: %u, time: %" G_GUINT64_FORMAT
", duration: %" G_GUINT64_FORMAT ", repetitions: %u",
fragment->number, fragment->time, fragment->duration,
fragment->repetitions);
} else if (node_has_type (iter, MSS_NODE_STREAM_QUALITY)) {
GstMssStreamQuality *quality = gst_mss_stream_quality_new (iter);
stream->qualities = g_list_prepend (stream->qualities, quality);
@ -798,6 +817,7 @@ gst_mss_stream_get_fragment_url (GstMssStream * stream, gchar ** url)
{
gchar *tmp;
gchar *start_time_str;
guint64 time;
GstMssStreamFragment *fragment;
GstMssStreamQuality *quality = stream->current_quality->data;
@ -808,7 +828,9 @@ gst_mss_stream_get_fragment_url (GstMssStream * stream, gchar ** url)
fragment = stream->current_fragment->data;
start_time_str = g_strdup_printf ("%" G_GUINT64_FORMAT, fragment->time);
time =
fragment->time + fragment->duration * stream->fragment_repetition_index;
start_time_str = g_strdup_printf ("%" G_GUINT64_FORMAT, time);
tmp = g_regex_replace_literal (stream->regex_bitrate, stream->url,
strlen (stream->url), 0, quality->bitrate_str, 0, NULL);
@ -838,7 +860,8 @@ gst_mss_stream_get_fragment_gst_timestamp (GstMssStream * stream)
fragment = stream->current_fragment->data;
time = fragment->time;
time =
fragment->time + (fragment->duration * stream->fragment_repetition_index);
timescale = gst_mss_stream_get_timescale (stream);
return (GstClockTime) gst_util_uint64_scale_round (time, GST_SECOND,
timescale);
@ -867,11 +890,19 @@ gst_mss_stream_get_fragment_gst_duration (GstMssStream * stream)
GstFlowReturn
gst_mss_stream_advance_fragment (GstMssStream * stream)
{
GstMssStreamFragment *fragment;
g_return_val_if_fail (stream->active, GST_FLOW_ERROR);
if (stream->current_fragment == NULL)
return GST_FLOW_EOS;
fragment = stream->current_fragment->data;
stream->fragment_repetition_index++;
if (stream->fragment_repetition_index < fragment->repetitions) {
return GST_FLOW_OK;
}
stream->fragment_repetition_index = 0;
stream->current_fragment = g_list_next (stream->current_fragment);
if (stream->current_fragment == NULL)
return GST_FLOW_EOS;
@ -881,14 +912,23 @@ gst_mss_stream_advance_fragment (GstMssStream * stream)
GstFlowReturn
gst_mss_stream_regress_fragment (GstMssStream * stream)
{
GstMssStreamFragment *fragment;
g_return_val_if_fail (stream->active, GST_FLOW_ERROR);
if (stream->current_fragment == NULL)
return GST_FLOW_EOS;
fragment = stream->current_fragment->data;
stream->fragment_repetition_index--;
if (stream->fragment_repetition_index >= 0) {
return GST_FLOW_OK;
}
stream->current_fragment = g_list_previous (stream->current_fragment);
fragment = stream->current_fragment->data;
if (stream->current_fragment == NULL)
return GST_FLOW_EOS;
stream->fragment_repetition_index = fragment->repetitions - 1;
return GST_FLOW_OK;
}
@ -931,6 +971,7 @@ gst_mss_stream_seek (GstMssStream * stream, guint64 time)
{
GList *iter;
guint64 timescale;
GstMssStreamFragment *fragment = NULL;
timescale = gst_mss_stream_get_timescale (stream);
time = gst_util_uint64_scale_round (time, timescale, GST_SECOND);
@ -938,15 +979,15 @@ gst_mss_stream_seek (GstMssStream * stream, guint64 time)
for (iter = stream->fragments; iter; iter = g_list_next (iter)) {
GList *next = g_list_next (iter);
if (next) {
GstMssStreamFragment *fragment = next->data;
fragment = next->data;
if (fragment->time > time) {
stream->current_fragment = iter;
break;
}
} else {
GstMssStreamFragment *fragment = iter->data;
if (fragment->time + fragment->duration > time) {
fragment = iter->data;
if (fragment->time + fragment->repetitions * fragment->duration > time) {
stream->current_fragment = iter;
} else {
stream->current_fragment = NULL; /* EOS */
@ -954,6 +995,13 @@ gst_mss_stream_seek (GstMssStream * stream, guint64 time)
break;
}
}
/* position inside the repetitions */
if (stream->current_fragment) {
fragment = stream->current_fragment->data;
stream->fragment_repetition_index =
(time - fragment->time) / fragment->duration;
}
}
guint64