diff --git a/libavformat/mov.c b/libavformat/mov.c index 10117636414f2702fecdd6a8506488b0731af41f..1346ffe4805c337355ac361362ebd092e347d28d 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -6198,6 +6198,114 @@ static int mov_read_saio(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } +static int mov_read_pssh(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + AVEncryptionInitInfo *info, *old_init_info; + uint8_t **key_ids; + AVStream *st; + uint8_t *side_data, *extra_data, *old_side_data; + size_t side_data_size; + int ret = 0, old_side_data_size; + unsigned int version, kid_count, extra_data_size, alloc_size = 0; + + if (c->fc->nb_streams < 1) + return 0; + st = c->fc->streams[c->fc->nb_streams-1]; + + version = avio_r8(pb); /* version */ + avio_rb24(pb); /* flags */ + + info = av_encryption_init_info_alloc(/* system_id_size */ 16, /* num_key_ids */ 0, + /* key_id_size */ 16, /* data_size */ 0); + if (!info) + return AVERROR(ENOMEM); + + if (avio_read(pb, info->system_id, 16) != 16) { + av_log(c->fc, AV_LOG_ERROR, "Failed to read the system id\n"); + ret = AVERROR_INVALIDDATA; + goto finish; + } + + if (version > 0) { + kid_count = avio_rb32(pb); + if (kid_count >= INT_MAX / sizeof(*key_ids)) + return AVERROR(ENOMEM); + + for (unsigned int i = 0; i < kid_count && !pb->eof_reached; i++) { + unsigned int min_kid_count = FFMIN(FFMAX(i + 1, 1024), kid_count); + key_ids = av_fast_realloc(info->key_ids, &alloc_size, + min_kid_count * sizeof(*key_ids)); + if (!key_ids) { + ret = AVERROR(ENOMEM); + goto finish; + } + info->key_ids = key_ids; + + info->key_ids[i] = av_mallocz(16); + if (!info->key_ids[i]) { + ret = AVERROR(ENOMEM); + goto finish; + } + info->num_key_ids = i + 1; + + if (avio_read(pb, info->key_ids[i], 16) != 16) { + av_log(c->fc, AV_LOG_ERROR, "Failed to read the key id\n"); + ret = AVERROR_INVALIDDATA; + goto finish; + } + } + + if (pb->eof_reached) { + av_log(c->fc, AV_LOG_ERROR, "Hit EOF while reading pssh\n"); + ret = AVERROR_INVALIDDATA; + goto finish; + } + } + + extra_data_size = avio_rb32(pb); + ret = mov_try_read_block(pb, extra_data_size, &extra_data); + if (ret < 0) + goto finish; + + av_freep(&info->data); // malloc(0) may still allocate something. + info->data = extra_data; + info->data_size = extra_data_size; + + // If there is existing initialization data, append to the list. + old_side_data = av_stream_get_side_data(st, AV_PKT_DATA_ENCRYPTION_INIT_INFO, &old_side_data_size); + if (old_side_data) { + old_init_info = av_encryption_init_info_get_side_data(old_side_data, old_side_data_size); + if (old_init_info) { + // Append to the end of the list. + for (AVEncryptionInitInfo *cur = old_init_info;; cur = cur->next) { + if (!cur->next) { + cur->next = info; + break; + } + } + info = old_init_info; + } else { + // Assume existing side-data will be valid, so the only error we could get is OOM. + ret = AVERROR(ENOMEM); + goto finish; + } + } + + side_data = av_encryption_init_info_add_side_data(info, &side_data_size); + if (!side_data) { + ret = AVERROR(ENOMEM); + goto finish; + } + ret = av_stream_add_side_data(st, AV_PKT_DATA_ENCRYPTION_INIT_INFO, + side_data, side_data_size); + if (ret < 0) + av_free(side_data); + +finish: + av_encryption_init_info_free(info); + return ret; +} + static int mov_read_schm(MOVContext *c, AVIOContext *pb, MOVAtom atom) { AVStream *st; @@ -6398,7 +6506,7 @@ static int cenc_filter(MOVContext *mov, MOVStreamContext *sc, AVPacket *pkt, int MOVFragmentStreamInfo *frag_stream_info; MOVEncryptionIndex *encryption_index; AVEncryptionInfo *encrypted_sample; - int encrypted_index; + int encrypted_index, ret; frag_stream_info = get_current_frag_stream_info(&mov->frag_index); encrypted_index = current_index; @@ -6442,6 +6550,15 @@ static int cenc_filter(MOVContext *mov, MOVStreamContext *sc, AVPacket *pkt, int if (mov->decryption_key) { return cenc_decrypt(mov, sc, encrypted_sample, pkt->data, pkt->size); + } else { + size_t size; + uint8_t *side_data = av_encryption_info_add_side_data(encrypted_sample, &size); + if (!side_data) + return AVERROR(ENOMEM); + ret = av_packet_add_side_data(pkt, AV_PKT_DATA_ENCRYPTION_INFO, side_data, size); + if (ret < 0) + av_free(side_data); + return ret; } } @@ -6575,6 +6692,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = { { MKTAG('s','e','n','c'), mov_read_senc }, { MKTAG('s','a','i','z'), mov_read_saiz }, { MKTAG('s','a','i','o'), mov_read_saio }, +{ MKTAG('p','s','s','h'), mov_read_pssh }, { MKTAG('s','c','h','m'), mov_read_schm }, { MKTAG('s','c','h','i'), mov_read_default }, { MKTAG('t','e','n','c'), mov_read_tenc },