hlsdemux: Implement handling of byte ranges

This commit is contained in:
Sebastian Dröge 2014-03-05 10:47:01 +01:00
parent 7ed08a1326
commit cd02546089
4 changed files with 99 additions and 21 deletions

View file

@ -774,7 +774,7 @@ gst_hls_demux_stream_loop (GstHLSDemux * demux)
/* Got a new fragment or not live anymore? */
if (gst_m3u8_client_get_next_fragment (demux->client, NULL, NULL,
NULL, NULL, NULL, NULL)
NULL, NULL, NULL, NULL, NULL, NULL)
|| !gst_m3u8_client_is_live (demux->client))
break;
@ -1403,21 +1403,25 @@ gst_hls_demux_get_next_fragment (GstHLSDemux * demux,
GstClockTime timestamp;
GstBuffer *buf;
gboolean discont;
gint64 range_start, range_end;
const gchar *key = NULL;
const guint8 *iv = NULL;
*end_of_playlist = FALSE;
if (!gst_m3u8_client_get_next_fragment (demux->client, &discont,
&next_fragment_uri, &duration, &timestamp, &key, &iv)) {
&next_fragment_uri, &duration, &timestamp, &range_start, &range_end,
&key, &iv)) {
GST_INFO_OBJECT (demux, "This playlist doesn't contain more fragments");
*end_of_playlist = TRUE;
return NULL;
}
GST_INFO_OBJECT (demux, "Fetching next fragment %s", next_fragment_uri);
GST_INFO_OBJECT (demux,
"Fetching next fragment %s (range=%" G_GINT64_FORMAT "-%" G_GINT64_FORMAT
")", next_fragment_uri, range_start, range_end);
download = gst_uri_downloader_fetch_uri (demux->downloader,
next_fragment_uri, FALSE, err);
download = gst_uri_downloader_fetch_uri_with_range (demux->downloader,
next_fragment_uri, FALSE, range_start, range_end, err);
if (download == NULL)
goto error;

View file

@ -135,6 +135,31 @@ int_from_string (gchar * ptr, gchar ** endptr, gint * val)
return end != ptr;
}
static gboolean
int64_from_string (gchar * ptr, gchar ** endptr, gint64 * val)
{
gchar *end;
gint64 ret;
g_return_val_if_fail (ptr != NULL, FALSE);
g_return_val_if_fail (val != NULL, FALSE);
errno = 0;
ret = g_ascii_strtoll (ptr, &end, 10);
if ((errno == ERANGE && (ret == G_MAXINT64 || ret == G_MININT64))
|| (errno != 0 && ret == 0)) {
GST_WARNING ("%s", g_strerror (errno));
return FALSE;
}
if (endptr)
*endptr = end;
*val = ret;
return end != ptr;
}
static gboolean
double_from_string (gchar * ptr, gchar ** endptr, gdouble * val)
{
@ -168,7 +193,7 @@ double_from_string (gchar * ptr, gchar ** endptr, gdouble * val)
static gboolean
parse_attributes (gchar ** ptr, gchar ** a, gchar ** v)
{
gchar *end=NULL, *p;
gchar *end = NULL, *p;
g_return_val_if_fail (ptr != NULL, FALSE);
g_return_val_if_fail (*ptr != NULL, FALSE);
@ -179,18 +204,18 @@ parse_attributes (gchar ** ptr, gchar ** a, gchar ** v)
*a = *ptr;
end = p = g_utf8_strchr (*ptr, -1, ',');
if(end){
gchar *q = g_utf8_strchr (*ptr, -1, '"');
if(q && q<end){
/* special case, such as CODECS="avc1.77.30, mp4a.40.2" */
q = g_utf8_next_char (q);
if(q){
q = g_utf8_strchr (q, -1, '"');
}
if(q){
end = p = g_utf8_strchr (q, -1, ',');
}
}
if (end) {
gchar *q = g_utf8_strchr (*ptr, -1, '"');
if (q && q < end) {
/* special case, such as CODECS="avc1.77.30, mp4a.40.2" */
q = g_utf8_next_char (q);
if (q) {
q = g_utf8_strchr (q, -1, '"');
}
if (q) {
end = p = g_utf8_strchr (q, -1, ',');
}
}
}
if (end) {
do {
@ -240,6 +265,7 @@ gst_m3u8_update (GstM3U8 * self, gchar * data, gboolean * updated)
GstM3U8 *list;
gboolean have_iv = FALSE;
guint8 iv[16] = { 0, };
gint64 size = -1, offset = -1;
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (data != NULL, FALSE);
@ -324,11 +350,31 @@ gst_m3u8_update (GstM3U8 * self, gchar * data, gboolean * updated)
}
}
if (size != -1) {
file->size = size;
if (offset != -1) {
file->offset = offset;
} else {
GstM3U8MediaFile *prev =
self->files ? g_list_last (self->files)->data : NULL;
if (!prev) {
offset = 0;
} else {
offset = prev->offset + prev->size;
}
}
} else {
file->size = -1;
file->offset = 0;
}
file->discont = discontinuity;
duration = 0;
title = NULL;
discontinuity = FALSE;
size = offset = -1;
self->files = g_list_append (self->files, file);
}
@ -459,6 +505,15 @@ gst_m3u8_update (GstM3U8 * self, gchar * data, gboolean * updated)
g_free (title);
title = g_strdup (data);
}
} else if (g_str_has_prefix (data, "#EXT-X-BYTERANGE:")) {
gchar *v = data + 17;
if (int64_from_string (v, &v, &size)) {
if (*v == '@' && !int64_from_string (v + 1, &v, &offset))
goto next_line;
} else {
goto next_line;
}
} else {
GST_LOG ("Ignored line: %s", data);
}
@ -596,7 +651,8 @@ _find_next (GstM3U8MediaFile * file, GstM3U8Client * client)
gboolean
gst_m3u8_client_get_next_fragment (GstM3U8Client * client,
gboolean * discontinuity, const gchar ** uri, GstClockTime * duration,
GstClockTime * timestamp, const gchar ** key, const guint8 ** iv)
GstClockTime * timestamp, gint64 * range_start, gint64 * range_end,
const gchar ** key, const guint8 ** iv)
{
GList *l;
GstM3U8MediaFile *file;
@ -626,6 +682,10 @@ gst_m3u8_client_get_next_fragment (GstM3U8Client * client,
*uri = file->uri;
if (duration)
*duration = file->duration;
if (range_start)
*range_start = file->offset;
if (range_end)
*range_end = file->size != -1 ? file->offset + file->size : -1;
if (key)
*key = file->key;
if (iv)

View file

@ -69,6 +69,7 @@ struct _GstM3U8MediaFile
gboolean discont; /* this file marks a discontinuity */
gchar *key;
guint8 iv[16];
gint64 offset, size;
};
struct _GstM3U8Client
@ -88,7 +89,8 @@ gboolean gst_m3u8_client_update (GstM3U8Client * client, gchar * data);
void gst_m3u8_client_set_current (GstM3U8Client * client, GstM3U8 * m3u8);
gboolean gst_m3u8_client_get_next_fragment (GstM3U8Client * client,
gboolean * discontinuity, const gchar ** uri, GstClockTime * duration,
GstClockTime * timestamp, const gchar ** key, const guint8 ** iv);
GstClockTime * timestamp, gint64 * range_start, gint64 * range_end,
const gchar ** key, const guint8 ** iv);
void gst_m3u8_client_advance_fragment (GstM3U8Client * client);
GstClockTime gst_m3u8_client_get_duration (GstM3U8Client * client);
GstClockTime gst_m3u8_client_get_target_duration (GstM3U8Client * client);

View file

@ -235,9 +235,21 @@ gst_fragment_get_caps (GstFragment * fragment)
return NULL;
g_mutex_lock (&fragment->priv->lock);
if (fragment->priv->caps == NULL)
if (fragment->priv->caps == NULL) {
guint64 offset, offset_end;
/* FIXME: This is currently necessary as typefinding only
* works with 0 offsets... need to find a better way to
* do that */
offset = GST_BUFFER_OFFSET (fragment->priv->buffer);
offset_end = GST_BUFFER_OFFSET_END (fragment->priv->buffer);
GST_BUFFER_OFFSET (fragment->priv->buffer) = GST_BUFFER_OFFSET_NONE;
GST_BUFFER_OFFSET_END (fragment->priv->buffer) = GST_BUFFER_OFFSET_NONE;
fragment->priv->caps =
gst_type_find_helper_for_buffer (NULL, fragment->priv->buffer, NULL);
GST_BUFFER_OFFSET (fragment->priv->buffer) = offset;
GST_BUFFER_OFFSET_END (fragment->priv->buffer) = offset_end;
}
gst_caps_ref (fragment->priv->caps);
g_mutex_unlock (&fragment->priv->lock);