mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-19 16:21:17 +00:00
hlsdemux: Implement handling of byte ranges
This commit is contained in:
parent
7ed08a1326
commit
cd02546089
4 changed files with 99 additions and 21 deletions
|
@ -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, ×tamp, &key, &iv)) {
|
||||
&next_fragment_uri, &duration, ×tamp, &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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue