summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Dröge <sebastian@centricular.com>2014-02-11 18:15:07 +0100
committerSebastian Dröge <sebastian@centricular.com>2014-02-11 18:21:16 +0100
commit15a2aac0aaf14dd775cb0a7fd81999cc8ed640f6 (patch)
tree4b8fc82490b52d6731aa7dfeeeaf739741bcb3ea
parent2ebca071559d9460ccc9fefc6b7537b9aa58b1dc (diff)
downloadgstreamer-plugins-bad-15a2aac0aaf14dd775cb0a7fd81999cc8ed640f6.tar.gz
hlsdemux: Properly parse IV from the playlist
Without this every fragment's first 16 bytes will be corrupted if not the fallback IV is used by the playlist.
-rw-r--r--ext/hls/m3u8.c89
1 files changed, 87 insertions, 2 deletions
diff --git a/ext/hls/m3u8.c b/ext/hls/m3u8.c
index 45f997b96..df9f1d8fd 100644
--- a/ext/hls/m3u8.c
+++ b/ext/hls/m3u8.c
@@ -215,6 +215,53 @@ gst_m3u8_compare_playlist_by_bitrate (gconstpointer a, gconstpointer b)
return ((GstM3U8 *) (a))->bandwidth - ((GstM3U8 *) (b))->bandwidth;
}
+static gint
+hex_char_to_int (const gchar * v)
+{
+ switch (*v) {
+ case '0':
+ return 0;
+ case '1':
+ return 1;
+ case '2':
+ return 2;
+ case '3':
+ return 3;
+ case '4':
+ return 4;
+ case '5':
+ return 5;
+ case '6':
+ return 6;
+ case '7':
+ return 7;
+ case '8':
+ return 8;
+ case '9':
+ return 9;
+ case 'A':
+ case 'a':
+ return 0xa;
+ case 'B':
+ case 'b':
+ return 0xb;
+ case 'C':
+ case 'c':
+ return 0xc;
+ case 'D':
+ case 'd':
+ return 0xd;
+ case 'E':
+ case 'e':
+ return 0xe;
+ case 'F':
+ case 'f':
+ return 0xf;
+ default:
+ return -1;
+ }
+}
+
/*
* @data: a m3u8 playlist text data, taking ownership
*/
@@ -226,6 +273,8 @@ gst_m3u8_update (GstM3U8 * self, gchar * data, gboolean * updated)
gchar *title, *end;
// gboolean discontinuity;
GstM3U8 *list;
+ gboolean have_iv = FALSE;
+ guint8 iv[16] = { 0, };
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (data != NULL, FALSE);
@@ -302,8 +351,12 @@ gst_m3u8_update (GstM3U8 * self, gchar * data, gboolean * updated)
/* set encryption params */
file->key = g_strdup (self->key);
if (file->key) {
- guint8 *iv = file->iv + 12;
- GST_WRITE_UINT32_BE (iv, file->sequence);
+ if (have_iv) {
+ memcpy (file->iv, iv, sizeof (iv));
+ } else {
+ guint8 *iv = file->iv + 12;
+ GST_WRITE_UINT32_BE (iv + 12, file->sequence);
+ }
}
duration = 0;
@@ -366,6 +419,11 @@ gst_m3u8_update (GstM3U8 * self, gchar * data, gboolean * updated)
gchar *v, *a;
data = data + 11;
+
+ /* IV and KEY are only valid until the next #EXT-X-KEY */
+ have_iv = FALSE;
+ g_free (self->key);
+ self->key = NULL;
while (data && parse_attributes (&data, &a, &v)) {
if (g_str_equal (a, "URI")) {
gchar *key = g_strdup (v);
@@ -380,6 +438,33 @@ gst_m3u8_update (GstM3U8 * self, gchar * data, gboolean * updated)
self->key = uri_join (self->uri, key);
g_free (keyp);
+ } else if (g_str_equal (a, "IV")) {
+ gchar *ivp = v;
+ gint i;
+
+ if (strlen (ivp) < 32 + 2 || (!g_str_has_prefix (ivp, "0x")
+ && !g_str_has_prefix (ivp, "0X"))) {
+ GST_WARNING ("Can't read IV");
+ continue;
+ }
+
+ ivp += 2;
+ for (i = 0; i < 16; i++) {
+ gint h, l;
+
+ h = hex_char_to_int (ivp++);
+ l = hex_char_to_int (ivp++);
+ if (h == -1 || l == -1) {
+ i = -1;
+ break;
+ }
+ iv[i] = (h << 4) | l;
+ }
+ if (i == -1) {
+ GST_WARNING ("Can't read IV");
+ continue;
+ }
+ have_iv = TRUE;
}
}
} else if (g_str_has_prefix (data, "#EXTINF:")) {