summaryrefslogtreecommitdiff
path: root/libavformat
diff options
context:
space:
mode:
authorMartin Storsjö <martin@martin.st>2011-01-23 23:42:18 +0200
committerMartin Storsjö <martin@martin.st>2011-04-23 00:27:21 +0300
commit84465f2180308a3e998089517e76586563fd6162 (patch)
tree5ccfe1baae3968d13c97511560976b07a42368ac /libavformat
parent6e4f70a8de69884ce0caa8735d7a88915b4391d4 (diff)
applehttp: Handle AES-128 encrypted streams
This should hopefully fix roundup issue 2586. This commit only implements it in the demuxer, not in the protocol handler. If desired, some of the code could be refactored to be shared by both implementations. Signed-off-by: Martin Storsjö <martin@martin.st>
Diffstat (limited to 'libavformat')
-rw-r--r--libavformat/applehttp.c108
-rw-r--r--libavformat/version.h2
2 files changed, 106 insertions, 4 deletions
diff --git a/libavformat/applehttp.c b/libavformat/applehttp.c
index 90b86a8733..2e0e8a1b3a 100644
--- a/libavformat/applehttp.c
+++ b/libavformat/applehttp.c
@@ -27,6 +27,8 @@
#define _XOPEN_SOURCE 600
#include "libavutil/avstring.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/opt.h"
#include "avformat.h"
#include "internal.h"
#include <unistd.h>
@@ -47,9 +49,17 @@
* one anonymous toplevel variant for this, to maintain the structure.
*/
+enum KeyType {
+ KEY_NONE,
+ KEY_AES_128,
+};
+
struct segment {
int duration;
char url[MAX_URL_SIZE];
+ char key[MAX_URL_SIZE];
+ enum KeyType key_type;
+ uint8_t iv[16];
};
/*
@@ -77,6 +87,9 @@ struct variant {
int needed, cur_needed;
int cur_seq_no;
int64_t last_load_time;
+
+ char key_url[MAX_URL_SIZE];
+ uint8_t key[16];
};
typedef struct AppleHTTPContext {
@@ -160,10 +173,35 @@ static void handle_variant_args(struct variant_info *info, const char *key,
}
}
+struct key_info {
+ char uri[MAX_URL_SIZE];
+ char method[10];
+ char iv[35];
+};
+
+static void handle_key_args(struct key_info *info, const char *key,
+ int key_len, char **dest, int *dest_len)
+{
+ if (!strncmp(key, "METHOD=", key_len)) {
+ *dest = info->method;
+ *dest_len = sizeof(info->method);
+ } else if (!strncmp(key, "URI=", key_len)) {
+ *dest = info->uri;
+ *dest_len = sizeof(info->uri);
+ } else if (!strncmp(key, "IV=", key_len)) {
+ *dest = info->iv;
+ *dest_len = sizeof(info->iv);
+ }
+}
+
static int parse_playlist(AppleHTTPContext *c, const char *url,
struct variant *var, AVIOContext *in)
{
int ret = 0, duration = 0, is_segment = 0, is_variant = 0, bandwidth = 0;
+ enum KeyType key_type = KEY_NONE;
+ uint8_t iv[16] = "";
+ int has_iv = 0;
+ char key[MAX_URL_SIZE];
char line[1024];
const char *ptr;
int close_in = 0;
@@ -192,6 +230,19 @@ static int parse_playlist(AppleHTTPContext *c, const char *url,
ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_variant_args,
&info);
bandwidth = atoi(info.bandwidth);
+ } else if (av_strstart(line, "#EXT-X-KEY:", &ptr)) {
+ struct key_info info = {{0}};
+ ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_key_args,
+ &info);
+ key_type = KEY_NONE;
+ has_iv = 0;
+ if (!strcmp(info.method, "AES-128"))
+ key_type = KEY_AES_128;
+ if (!strncmp(info.iv, "0x", 2) || !strncmp(info.iv, "0X", 2)) {
+ ff_hex_to_data(iv, info.iv + 2);
+ has_iv = 1;
+ }
+ av_strlcpy(key, info.uri, sizeof(key));
} else if (av_strstart(line, "#EXT-X-TARGETDURATION:", &ptr)) {
if (!var) {
var = new_variant(c, 0, url, NULL);
@@ -242,6 +293,15 @@ static int parse_playlist(AppleHTTPContext *c, const char *url,
goto fail;
}
seg->duration = duration;
+ seg->key_type = key_type;
+ if (has_iv) {
+ memcpy(seg->iv, iv, sizeof(iv));
+ } else {
+ int seq = var->start_seq_no + var->n_segments;
+ memset(seg->iv, 0, sizeof(seg->iv));
+ AV_WB32(seg->iv + 12, seq);
+ }
+ ff_make_absolute_url(seg->key, sizeof(seg->key), url, key);
ff_make_absolute_url(seg->url, sizeof(seg->url), url, line);
dynarray_add(&var->segments, &var->n_segments, seg);
is_segment = 0;
@@ -257,6 +317,50 @@ fail:
return ret;
}
+static int open_input(struct variant *var)
+{
+ struct segment *seg = var->segments[var->cur_seq_no - var->start_seq_no];
+ if (seg->key_type == KEY_NONE) {
+ return ffurl_open(&var->input, seg->url, AVIO_FLAG_READ);
+ } else if (seg->key_type == KEY_AES_128) {
+ char iv[33], key[33], url[MAX_URL_SIZE];
+ int ret;
+ if (strcmp(seg->key, var->key_url)) {
+ URLContext *uc;
+ if (ffurl_open(&uc, seg->key, AVIO_FLAG_READ) == 0) {
+ if (ffurl_read_complete(uc, var->key, sizeof(var->key))
+ != sizeof(var->key)) {
+ av_log(NULL, AV_LOG_ERROR, "Unable to read key file %s\n",
+ seg->key);
+ }
+ ffurl_close(uc);
+ } else {
+ av_log(NULL, AV_LOG_ERROR, "Unable to open key file %s\n",
+ seg->key);
+ }
+ av_strlcpy(var->key_url, seg->key, sizeof(var->key_url));
+ }
+ ff_data_to_hex(iv, seg->iv, sizeof(seg->iv), 0);
+ ff_data_to_hex(key, var->key, sizeof(var->key), 0);
+ iv[32] = key[32] = '\0';
+ if (strstr(seg->url, "://"))
+ snprintf(url, sizeof(url), "crypto+%s", seg->url);
+ else
+ snprintf(url, sizeof(url), "crypto:%s", seg->url);
+ if ((ret = ffurl_alloc(&var->input, url, AVIO_FLAG_READ)) < 0)
+ return ret;
+ av_set_string3(var->input->priv_data, "key", key, 0, NULL);
+ av_set_string3(var->input->priv_data, "iv", iv, 0, NULL);
+ if ((ret = ffurl_connect(var->input)) < 0) {
+ ffurl_close(var->input);
+ var->input = NULL;
+ return ret;
+ }
+ return 0;
+ }
+ return AVERROR(ENOSYS);
+}
+
static int read_data(void *opaque, uint8_t *buf, int buf_size)
{
struct variant *v = opaque;
@@ -291,9 +395,7 @@ reload:
goto reload;
}
- ret = ffurl_open(&v->input,
- v->segments[v->cur_seq_no - v->start_seq_no]->url,
- AVIO_FLAG_READ);
+ ret = open_input(v);
if (ret < 0)
return ret;
}
diff --git a/libavformat/version.h b/libavformat/version.h
index 04c5d73f50..9041f92626 100644
--- a/libavformat/version.h
+++ b/libavformat/version.h
@@ -25,7 +25,7 @@
#define LIBAVFORMAT_VERSION_MAJOR 53
#define LIBAVFORMAT_VERSION_MINOR 0
-#define LIBAVFORMAT_VERSION_MICRO 1
+#define LIBAVFORMAT_VERSION_MICRO 2
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
LIBAVFORMAT_VERSION_MINOR, \