mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-30 12:10:37 +00:00
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:
parent
b418c88b26
commit
a2c31e38d1
1 changed files with 55 additions and 7 deletions
|
@ -44,6 +44,7 @@ GST_DEBUG_CATEGORY_EXTERN (mssdemux_debug);
|
||||||
#define MSS_PROP_DURATION "d"
|
#define MSS_PROP_DURATION "d"
|
||||||
#define MSS_PROP_LANGUAGE "Language"
|
#define MSS_PROP_LANGUAGE "Language"
|
||||||
#define MSS_PROP_NUMBER "n"
|
#define MSS_PROP_NUMBER "n"
|
||||||
|
#define MSS_PROP_REPETITIONS "r"
|
||||||
#define MSS_PROP_STREAM_DURATION "Duration"
|
#define MSS_PROP_STREAM_DURATION "Duration"
|
||||||
#define MSS_PROP_TIME "t"
|
#define MSS_PROP_TIME "t"
|
||||||
#define MSS_PROP_TIMESCALE "TimeScale"
|
#define MSS_PROP_TIMESCALE "TimeScale"
|
||||||
|
@ -54,6 +55,7 @@ typedef struct _GstMssStreamFragment
|
||||||
guint number;
|
guint number;
|
||||||
guint64 time;
|
guint64 time;
|
||||||
guint64 duration;
|
guint64 duration;
|
||||||
|
guint repetitions;
|
||||||
} GstMssStreamFragment;
|
} GstMssStreamFragment;
|
||||||
|
|
||||||
typedef struct _GstMssStreamQuality
|
typedef struct _GstMssStreamQuality
|
||||||
|
@ -77,6 +79,7 @@ struct _GstMssStream
|
||||||
gchar *url;
|
gchar *url;
|
||||||
gchar *lang;
|
gchar *lang;
|
||||||
|
|
||||||
|
guint fragment_repetition_index;
|
||||||
GList *current_fragment;
|
GList *current_fragment;
|
||||||
GList *current_quality;
|
GList *current_quality;
|
||||||
|
|
||||||
|
@ -158,11 +161,14 @@ _gst_mss_stream_init (GstMssStream * stream, xmlNodePtr node)
|
||||||
gchar *duration_str;
|
gchar *duration_str;
|
||||||
gchar *time_str;
|
gchar *time_str;
|
||||||
gchar *seqnum_str;
|
gchar *seqnum_str;
|
||||||
|
gchar *repetition_str;
|
||||||
GstMssStreamFragment *fragment = g_new (GstMssStreamFragment, 1);
|
GstMssStreamFragment *fragment = g_new (GstMssStreamFragment, 1);
|
||||||
|
|
||||||
duration_str = (gchar *) xmlGetProp (iter, (xmlChar *) MSS_PROP_DURATION);
|
duration_str = (gchar *) xmlGetProp (iter, (xmlChar *) MSS_PROP_DURATION);
|
||||||
time_str = (gchar *) xmlGetProp (iter, (xmlChar *) MSS_PROP_TIME);
|
time_str = (gchar *) xmlGetProp (iter, (xmlChar *) MSS_PROP_TIME);
|
||||||
seqnum_str = (gchar *) xmlGetProp (iter, (xmlChar *) MSS_PROP_NUMBER);
|
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 */
|
/* use the node's seq number or use the previous + 1 */
|
||||||
if (seqnum_str) {
|
if (seqnum_str) {
|
||||||
|
@ -174,6 +180,13 @@ _gst_mss_stream_init (GstMssStream * stream, xmlNodePtr node)
|
||||||
}
|
}
|
||||||
fragment_number = fragment->number + 1;
|
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) {
|
if (time_str) {
|
||||||
fragment->time = g_ascii_strtoull (time_str, NULL, 10);
|
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 we have a previous fragment, means we need to set its duration */
|
||||||
if (previous_fragment)
|
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) {
|
if (duration_str) {
|
||||||
fragment->duration = g_ascii_strtoull (duration_str, NULL, 10);
|
fragment->duration = g_ascii_strtoull (duration_str, NULL, 10);
|
||||||
|
|
||||||
previous_fragment = NULL;
|
previous_fragment = NULL;
|
||||||
fragment_time_accum += fragment->duration;
|
fragment_time_accum += fragment->duration * fragment->repetitions;
|
||||||
xmlFree (duration_str);
|
xmlFree (duration_str);
|
||||||
} else {
|
} else {
|
||||||
/* store to set the duration at the next iteration */
|
/* 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 */
|
/* we reverse it later */
|
||||||
stream->fragments = g_list_prepend (stream->fragments, fragment);
|
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)) {
|
} else if (node_has_type (iter, MSS_NODE_STREAM_QUALITY)) {
|
||||||
GstMssStreamQuality *quality = gst_mss_stream_quality_new (iter);
|
GstMssStreamQuality *quality = gst_mss_stream_quality_new (iter);
|
||||||
stream->qualities = g_list_prepend (stream->qualities, quality);
|
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 *tmp;
|
||||||
gchar *start_time_str;
|
gchar *start_time_str;
|
||||||
|
guint64 time;
|
||||||
GstMssStreamFragment *fragment;
|
GstMssStreamFragment *fragment;
|
||||||
GstMssStreamQuality *quality = stream->current_quality->data;
|
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;
|
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,
|
tmp = g_regex_replace_literal (stream->regex_bitrate, stream->url,
|
||||||
strlen (stream->url), 0, quality->bitrate_str, 0, NULL);
|
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;
|
fragment = stream->current_fragment->data;
|
||||||
|
|
||||||
time = fragment->time;
|
time =
|
||||||
|
fragment->time + (fragment->duration * stream->fragment_repetition_index);
|
||||||
timescale = gst_mss_stream_get_timescale (stream);
|
timescale = gst_mss_stream_get_timescale (stream);
|
||||||
return (GstClockTime) gst_util_uint64_scale_round (time, GST_SECOND,
|
return (GstClockTime) gst_util_uint64_scale_round (time, GST_SECOND,
|
||||||
timescale);
|
timescale);
|
||||||
|
@ -867,11 +890,19 @@ gst_mss_stream_get_fragment_gst_duration (GstMssStream * stream)
|
||||||
GstFlowReturn
|
GstFlowReturn
|
||||||
gst_mss_stream_advance_fragment (GstMssStream * stream)
|
gst_mss_stream_advance_fragment (GstMssStream * stream)
|
||||||
{
|
{
|
||||||
|
GstMssStreamFragment *fragment;
|
||||||
g_return_val_if_fail (stream->active, GST_FLOW_ERROR);
|
g_return_val_if_fail (stream->active, GST_FLOW_ERROR);
|
||||||
|
|
||||||
if (stream->current_fragment == NULL)
|
if (stream->current_fragment == NULL)
|
||||||
return GST_FLOW_EOS;
|
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);
|
stream->current_fragment = g_list_next (stream->current_fragment);
|
||||||
if (stream->current_fragment == NULL)
|
if (stream->current_fragment == NULL)
|
||||||
return GST_FLOW_EOS;
|
return GST_FLOW_EOS;
|
||||||
|
@ -881,14 +912,23 @@ gst_mss_stream_advance_fragment (GstMssStream * stream)
|
||||||
GstFlowReturn
|
GstFlowReturn
|
||||||
gst_mss_stream_regress_fragment (GstMssStream * stream)
|
gst_mss_stream_regress_fragment (GstMssStream * stream)
|
||||||
{
|
{
|
||||||
|
GstMssStreamFragment *fragment;
|
||||||
g_return_val_if_fail (stream->active, GST_FLOW_ERROR);
|
g_return_val_if_fail (stream->active, GST_FLOW_ERROR);
|
||||||
|
|
||||||
if (stream->current_fragment == NULL)
|
if (stream->current_fragment == NULL)
|
||||||
return GST_FLOW_EOS;
|
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);
|
stream->current_fragment = g_list_previous (stream->current_fragment);
|
||||||
|
fragment = stream->current_fragment->data;
|
||||||
if (stream->current_fragment == NULL)
|
if (stream->current_fragment == NULL)
|
||||||
return GST_FLOW_EOS;
|
return GST_FLOW_EOS;
|
||||||
|
stream->fragment_repetition_index = fragment->repetitions - 1;
|
||||||
return GST_FLOW_OK;
|
return GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -931,6 +971,7 @@ gst_mss_stream_seek (GstMssStream * stream, guint64 time)
|
||||||
{
|
{
|
||||||
GList *iter;
|
GList *iter;
|
||||||
guint64 timescale;
|
guint64 timescale;
|
||||||
|
GstMssStreamFragment *fragment = NULL;
|
||||||
|
|
||||||
timescale = gst_mss_stream_get_timescale (stream);
|
timescale = gst_mss_stream_get_timescale (stream);
|
||||||
time = gst_util_uint64_scale_round (time, timescale, GST_SECOND);
|
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)) {
|
for (iter = stream->fragments; iter; iter = g_list_next (iter)) {
|
||||||
GList *next = g_list_next (iter);
|
GList *next = g_list_next (iter);
|
||||||
if (next) {
|
if (next) {
|
||||||
GstMssStreamFragment *fragment = next->data;
|
fragment = next->data;
|
||||||
|
|
||||||
if (fragment->time > time) {
|
if (fragment->time > time) {
|
||||||
stream->current_fragment = iter;
|
stream->current_fragment = iter;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
GstMssStreamFragment *fragment = iter->data;
|
fragment = iter->data;
|
||||||
if (fragment->time + fragment->duration > time) {
|
if (fragment->time + fragment->repetitions * fragment->duration > time) {
|
||||||
stream->current_fragment = iter;
|
stream->current_fragment = iter;
|
||||||
} else {
|
} else {
|
||||||
stream->current_fragment = NULL; /* EOS */
|
stream->current_fragment = NULL; /* EOS */
|
||||||
|
@ -954,6 +995,13 @@ gst_mss_stream_seek (GstMssStream * stream, guint64 time)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* position inside the repetitions */
|
||||||
|
if (stream->current_fragment) {
|
||||||
|
fragment = stream->current_fragment->data;
|
||||||
|
stream->fragment_repetition_index =
|
||||||
|
(time - fragment->time) / fragment->duration;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
guint64
|
guint64
|
||||||
|
|
Loading…
Reference in a new issue