From f9dc67c37279110ae67c9210a1720bb707cee003 Mon Sep 17 00:00:00 2001 From: Seungha Yang Date: Sat, 4 Nov 2017 20:15:33 +0900 Subject: hls: m3u8: Parsing EXT-X-MAP tag to store initialization data EXT-X-MAP tag informs media initialization data, such as moov box in ISOBMFF case and PAT/PMT for MPEG TS stream. https://bugzilla.gnome.org/show_bug.cgi?id=776928 --- ext/hls/m3u8.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ext/hls/m3u8.h | 9 +++++++ 2 files changed, 91 insertions(+) (limited to 'ext/hls') diff --git a/ext/hls/m3u8.c b/ext/hls/m3u8.c index 594a963eb..679e28876 100644 --- a/ext/hls/m3u8.c +++ b/ext/hls/m3u8.c @@ -33,6 +33,7 @@ static GstM3U8MediaFile *gst_m3u8_media_file_new (gchar * uri, gchar * title, GstClockTime duration, guint sequence); +static void gst_m3u8_init_file_unref (GstM3U8InitFile * self); static gchar *uri_join (const gchar * uri, const gchar * path); GstM3U8 * @@ -144,6 +145,8 @@ gst_m3u8_media_file_unref (GstM3U8MediaFile * self) g_return_if_fail (self != NULL && self->ref_count > 0); if (g_atomic_int_dec_and_test (&self->ref_count)) { + if (self->init_file) + gst_m3u8_init_file_unref (self->init_file); g_free (self->title); g_free (self->uri); g_free (self->key); @@ -151,6 +154,38 @@ gst_m3u8_media_file_unref (GstM3U8MediaFile * self) } } +static GstM3U8InitFile * +gst_m3u8_init_file_new (gchar * uri) +{ + GstM3U8InitFile *file; + + file = g_new0 (GstM3U8InitFile, 1); + file->uri = uri; + file->ref_count = 1; + + return file; +} + +static GstM3U8InitFile * +gst_m3u8_init_file_ref (GstM3U8InitFile * ifile) +{ + g_assert (ifile != NULL && ifile->ref_count > 0); + + g_atomic_int_add (&ifile->ref_count, 1); + return ifile; +} + +static void +gst_m3u8_init_file_unref (GstM3U8InitFile * self) +{ + g_return_if_fail (self != NULL && self->ref_count > 0); + + if (g_atomic_int_dec_and_test (&self->ref_count)) { + g_free (self->uri); + g_free (self); + } +} + static gboolean int_from_string (gchar * ptr, gchar ** endptr, gint * val) { @@ -458,6 +493,7 @@ gst_m3u8_update (GstM3U8 * self, gchar * data) gint64 mediasequence; GList *previous_files = NULL; gboolean have_mediasequence = FALSE; + GstM3U8InitFile *last_init_file = NULL; g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (data != NULL, FALSE); @@ -555,6 +591,8 @@ gst_m3u8_update (GstM3U8 * self, gchar * data) } file->discont = discontinuity; + if (last_init_file) + file->init_file = gst_m3u8_init_file_ref (last_init_file); duration = 0; title = NULL; @@ -672,6 +710,47 @@ gst_m3u8_update (GstM3U8 * self, gchar * data) } else { goto next_line; } + } else if (g_str_has_prefix (data_ext_x, "MAP:")) { + gchar *v, *a, *header_uri = NULL; + + data = data + 11; + + while (data != NULL && parse_attributes (&data, &a, &v)) { + if (strcmp (a, "URI") == 0) { + header_uri = + uri_join (self->base_uri ? self->base_uri : self->uri, v); + } else if (strcmp (a, "BYTERANGE") == 0) { + if (int64_from_string (v, &v, &size)) { + if (*v == '@' && !int64_from_string (v + 1, &v, &offset)) { + g_free (header_uri); + goto next_line; + } + } else { + g_free (header_uri); + goto next_line; + } + } + } + + if (header_uri) { + GstM3U8InitFile *init_file; + init_file = gst_m3u8_init_file_new (header_uri); + + if (size != -1) { + init_file->size = size; + if (offset != -1) + init_file->offset = offset; + else + init_file->offset = 0; + } else { + init_file->size = -1; + init_file->offset = 0; + } + if (last_init_file) + gst_m3u8_init_file_unref (last_init_file); + + last_init_file = init_file; + } } else { GST_LOG ("Ignored line: %s", data); } @@ -690,6 +769,9 @@ gst_m3u8_update (GstM3U8 * self, gchar * data) self->files = g_list_reverse (self->files); + if (last_init_file) + gst_m3u8_init_file_unref (last_init_file); + if (previous_files) { gboolean consistent = TRUE; diff --git a/ext/hls/m3u8.h b/ext/hls/m3u8.h index 195ec2ab8..a7af61f1f 100644 --- a/ext/hls/m3u8.h +++ b/ext/hls/m3u8.h @@ -30,6 +30,7 @@ G_BEGIN_DECLS typedef struct _GstM3U8 GstM3U8; typedef struct _GstM3U8MediaFile GstM3U8MediaFile; +typedef struct _GstM3U8InitFile GstM3U8InitFile; typedef struct _GstHLSMedia GstHLSMedia; typedef struct _GstM3U8Client GstM3U8Client; typedef struct _GstHLSVariantStream GstHLSVariantStream; @@ -99,6 +100,14 @@ struct _GstM3U8MediaFile guint8 iv[16]; gint64 offset, size; gint ref_count; /* ATOMIC */ + GstM3U8InitFile *init_file; /* Media Initialization (hold ref) */ +}; + +struct _GstM3U8InitFile +{ + gchar *uri; + gint64 offset, size; + guint ref_count; /* ATOMIC */ }; GstM3U8MediaFile * gst_m3u8_media_file_ref (GstM3U8MediaFile * mfile); -- cgit v1.2.1