aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorerankor <eran.kornblau@kaltura.com>2016-02-22 16:41:06 +0200
committerMichael Niedermayer <michael@niedermayer.cc>2016-03-06 17:29:32 +0100
commitdd34e89f313bb723bb5b535d399542a50c3436c3 (patch)
tree6e7817a18e4bc5a4c1a1a6c458260b31653afae2
parent23d8b79a1833559dd140b0e9cec7bce1d9f4e46f (diff)
downloadffmpeg-dd34e89f313bb723bb5b535d399542a50c3436c3.tar.gz
mov - support seek in encrypted mp4
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
-rw-r--r--libavformat/isom.h3
-rw-r--r--libavformat/mov.c94
2 files changed, 97 insertions, 0 deletions
diff --git a/libavformat/isom.h b/libavformat/isom.h
index 99bc7bed00..726f350929 100644
--- a/libavformat/isom.h
+++ b/libavformat/isom.h
@@ -177,6 +177,9 @@ typedef struct MOVStreamContext {
uint8_t* auxiliary_info;
uint8_t* auxiliary_info_end;
uint8_t* auxiliary_info_pos;
+ uint8_t auxiliary_info_default_size;
+ uint8_t* auxiliary_info_sizes;
+ size_t auxiliary_info_sizes_count;
struct AVAESCTR* aes_ctr;
} cenc;
} MOVStreamContext;
diff --git a/libavformat/mov.c b/libavformat/mov.c
index 2eddc49f9b..752bc129a6 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -4078,6 +4078,62 @@ static int mov_read_senc(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return av_aes_ctr_init(sc->cenc.aes_ctr, c->decryption_key);
}
+static int mov_read_saiz(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+ AVStream *st;
+ MOVStreamContext *sc;
+ size_t data_size;
+ int atom_header_size;
+ int flags;
+
+ if (c->decryption_key_len == 0 || c->fc->nb_streams < 1)
+ return 0;
+
+ st = c->fc->streams[c->fc->nb_streams - 1];
+ sc = st->priv_data;
+
+ if (sc->cenc.auxiliary_info_sizes || sc->cenc.auxiliary_info_default_size) {
+ av_log(c->fc, AV_LOG_ERROR, "duplicate saiz atom\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ atom_header_size = 9;
+
+ avio_r8(pb); /* version */
+ flags = avio_rb24(pb);
+
+ if ((flags & 0x01) != 0) {
+ atom_header_size += 8;
+
+ avio_rb32(pb); /* info type */
+ avio_rb32(pb); /* info type param */
+ }
+
+ sc->cenc.auxiliary_info_default_size = avio_r8(pb);
+ avio_rb32(pb); /* entries */
+
+ if (atom.size <= atom_header_size) {
+ return 0;
+ }
+
+ /* save the auxiliary info sizes as is */
+ data_size = atom.size - atom_header_size;
+
+ sc->cenc.auxiliary_info_sizes = av_malloc(data_size);
+ if (!sc->cenc.auxiliary_info_sizes) {
+ return AVERROR(ENOMEM);
+ }
+
+ sc->cenc.auxiliary_info_sizes_count = data_size;
+
+ if (avio_read(pb, sc->cenc.auxiliary_info_sizes, data_size) != data_size) {
+ av_log(c->fc, AV_LOG_ERROR, "failed to read the auxiliary info sizes");
+ return AVERROR_INVALIDDATA;
+ }
+
+ return 0;
+}
+
static int cenc_filter(MOVContext *c, MOVStreamContext *sc, uint8_t *input, int size)
{
uint32_t encrypted_bytes;
@@ -4144,6 +4200,36 @@ static int cenc_filter(MOVContext *c, MOVStreamContext *sc, uint8_t *input, int
return 0;
}
+static int mov_seek_auxiliary_info(AVFormatContext *s, MOVStreamContext *sc)
+{
+ size_t auxiliary_info_seek_offset = 0;
+ int i;
+
+ if (sc->cenc.auxiliary_info_default_size) {
+ auxiliary_info_seek_offset = sc->cenc.auxiliary_info_default_size * sc->current_sample;
+ } else if (sc->cenc.auxiliary_info_sizes) {
+ if (sc->current_sample > sc->cenc.auxiliary_info_sizes_count) {
+ av_log(s, AV_LOG_ERROR, "current sample %d greater than the number of auxiliary info sample sizes %zu\n",
+ sc->current_sample, sc->cenc.auxiliary_info_sizes_count);
+ return AVERROR_INVALIDDATA;
+ }
+
+ for (i = 0; i < sc->current_sample; i++) {
+ auxiliary_info_seek_offset += sc->cenc.auxiliary_info_sizes[i];
+ }
+ }
+
+ if (auxiliary_info_seek_offset > sc->cenc.auxiliary_info_end - sc->cenc.auxiliary_info) {
+ av_log(s, AV_LOG_ERROR, "auxiliary info offset %zu greater than auxiliary info size %zu\n",
+ auxiliary_info_seek_offset, (size_t)(sc->cenc.auxiliary_info_end - sc->cenc.auxiliary_info));
+ return AVERROR_INVALIDDATA;
+ }
+
+ sc->cenc.auxiliary_info_pos = sc->cenc.auxiliary_info + auxiliary_info_seek_offset;
+
+ return 0;
+}
+
static const MOVParseTableEntry mov_default_parse_table[] = {
{ MKTAG('A','C','L','R'), mov_read_aclr },
{ MKTAG('A','P','R','G'), mov_read_avid },
@@ -4221,6 +4307,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = {
{ MKTAG('s','i','n','f'), mov_read_default },
{ MKTAG('f','r','m','a'), mov_read_frma },
{ MKTAG('s','e','n','c'), mov_read_senc },
+{ MKTAG('s','a','i','z'), mov_read_saiz },
{ 0, NULL }
};
@@ -4581,6 +4668,7 @@ static int mov_read_close(AVFormatContext *s)
av_freep(&sc->display_matrix);
av_freep(&sc->cenc.auxiliary_info);
+ av_freep(&sc->cenc.auxiliary_info_sizes);
av_aes_ctr_free(sc->cenc.aes_ctr);
}
@@ -5148,6 +5236,12 @@ static int mov_seek_stream(AVFormatContext *s, AVStream *st, int64_t timestamp,
time_sample = next;
}
}
+
+ ret = mov_seek_auxiliary_info(s, sc);
+ if (ret < 0) {
+ return ret;
+ }
+
return sample;
}