try to make kid:key support
This commit is contained in:
parent
3ddf77aacd
commit
5511102b0c
|
@ -27,6 +27,7 @@
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#include "avio_internal.h"
|
#include "avio_internal.h"
|
||||||
#include "dash.h"
|
#include "dash.h"
|
||||||
|
#include "libavformat/isom.h"
|
||||||
|
|
||||||
#define INITIAL_BUFFER_SIZE 32768
|
#define INITIAL_BUFFER_SIZE 32768
|
||||||
#define MAX_MANIFEST_SIZE 50 * 1024
|
#define MAX_MANIFEST_SIZE 50 * 1024
|
||||||
|
@ -1878,6 +1879,7 @@ static int reopen_demux_for_component(AVFormatContext *s, struct representation
|
||||||
ff_const59 AVInputFormat *in_fmt = NULL;
|
ff_const59 AVInputFormat *in_fmt = NULL;
|
||||||
AVDictionary *in_fmt_opts = NULL;
|
AVDictionary *in_fmt_opts = NULL;
|
||||||
uint8_t *avio_ctx_buffer = NULL;
|
uint8_t *avio_ctx_buffer = NULL;
|
||||||
|
|
||||||
int ret = 0, i;
|
int ret = 0, i;
|
||||||
|
|
||||||
if (pls->ctx) {
|
if (pls->ctx) {
|
||||||
|
@ -1926,7 +1928,28 @@ static int reopen_demux_for_component(AVFormatContext *s, struct representation
|
||||||
pls->ctx->io_open = nested_io_open;
|
pls->ctx->io_open = nested_io_open;
|
||||||
|
|
||||||
if (c->cenc_decryption_key)
|
if (c->cenc_decryption_key)
|
||||||
|
// if cenc_decryption_key not contains any : or , it is a hex string
|
||||||
|
if (strchr(c->cenc_decryption_key, ':') == NULL && strchr(c->cenc_decryption_key, ',') == NULL) {
|
||||||
av_dict_set(&in_fmt_opts, "decryption_key", c->cenc_decryption_key, 0);
|
av_dict_set(&in_fmt_opts, "decryption_key", c->cenc_decryption_key, 0);
|
||||||
|
} else {
|
||||||
|
DecryptionKey *decryption_key_map = av_mallocz(sizeof(DecryptionKey *) * 2);
|
||||||
|
// if cenc_decryption_key contains : or , split it based on ,
|
||||||
|
char *key_id = av_strtok(c->cenc_decryption_key, ",", &c->cenc_decryption_key);
|
||||||
|
// if cenc_decryption_key contains : split it based on :
|
||||||
|
//create DecryptionKey array
|
||||||
|
*key_count = 0;
|
||||||
|
while (key_id != NULL && *key_count < 2) {
|
||||||
|
char* colon = strchr(key_id, ':');
|
||||||
|
if (colon != NULL) {
|
||||||
|
*colon = '\0'; // Replace ':' with null-terminator
|
||||||
|
strncpy(decryption_key_map[*key_count].key_id, key_id, MAX_STRING_LENGTH - 1);
|
||||||
|
strncpy(decryption_key_map[*key_count].second, colon + 1, MAX_STRING_LENGTH - 1);
|
||||||
|
(*key_count)++;
|
||||||
|
}
|
||||||
|
key_id = av_strtok(NULL, ",");
|
||||||
|
}
|
||||||
|
av_dict_set(&in_fmt_opts, "decryption_key_map", decryption_key_map, 0);
|
||||||
|
}
|
||||||
|
|
||||||
// provide additional information from mpd if available
|
// provide additional information from mpd if available
|
||||||
ret = avformat_open_input(&pls->ctx, "", in_fmt, &in_fmt_opts); //pls->init_section->url
|
ret = avformat_open_input(&pls->ctx, "", in_fmt, &in_fmt_opts); //pls->init_section->url
|
||||||
|
|
|
@ -155,6 +155,11 @@ typedef struct MOVIndexRange {
|
||||||
int64_t end;
|
int64_t end;
|
||||||
} MOVIndexRange;
|
} MOVIndexRange;
|
||||||
|
|
||||||
|
typedef struct DecryptionKey {
|
||||||
|
uint8_t key_id;
|
||||||
|
uint8_t decryption_key;
|
||||||
|
} DecryptionKey;
|
||||||
|
|
||||||
typedef struct MOVStreamContext {
|
typedef struct MOVStreamContext {
|
||||||
AVIOContext *pb;
|
AVIOContext *pb;
|
||||||
int pb_is_copied;
|
int pb_is_copied;
|
||||||
|
@ -291,6 +296,8 @@ typedef struct MOVContext {
|
||||||
int decryption_key_len;
|
int decryption_key_len;
|
||||||
int enable_drefs;
|
int enable_drefs;
|
||||||
int32_t movie_display_matrix[3][3]; ///< display matrix from mvhd
|
int32_t movie_display_matrix[3][3]; ///< display matrix from mvhd
|
||||||
|
DecryptionKey *decryption_key_map; // array of decryption keys for each track
|
||||||
|
int decryption_key_map_size;
|
||||||
} MOVContext;
|
} MOVContext;
|
||||||
|
|
||||||
int ff_mp4_read_descr_len(AVIOContext *pb);
|
int ff_mp4_read_descr_len(AVIOContext *pb);
|
||||||
|
|
|
@ -6700,6 +6700,62 @@ static int cenc_decrypt(MOVContext *c, MOVStreamContext *sc, AVEncryptionInfo *s
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int cenc_decrypt_with_key(MOVContext *c, MOVStreamContext *sc, AVEncryptionInfo *sample, uint8_t *input, uint8_t *decryption_key, int size)
|
||||||
|
{
|
||||||
|
int i, ret;
|
||||||
|
|
||||||
|
if (sample->scheme != MKBETAG('c','e','n','c') || sample->crypt_byte_block != 0 || sample->skip_byte_block != 0) {
|
||||||
|
av_log(c->fc, AV_LOG_ERROR, "Only the 'cenc' encryption scheme is supported\n");
|
||||||
|
return AVERROR_PATCHWELCOME;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sc->cenc.aes_ctr) {
|
||||||
|
/* initialize the cipher */
|
||||||
|
sc->cenc.aes_ctr = av_aes_ctr_alloc();
|
||||||
|
if (!sc->cenc.aes_ctr) {
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = av_aes_ctr_init(sc->cenc.aes_ctr, decryption_key);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
av_aes_ctr_set_full_iv(sc->cenc.aes_ctr, sample->iv);
|
||||||
|
|
||||||
|
if (!sample->subsample_count)
|
||||||
|
{
|
||||||
|
/* decrypt the whole packet */
|
||||||
|
av_aes_ctr_crypt(sc->cenc.aes_ctr, input, input, size);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < sample->subsample_count; i++)
|
||||||
|
{
|
||||||
|
if (sample->subsamples[i].bytes_of_clear_data + sample->subsamples[i].bytes_of_protected_data > size) {
|
||||||
|
av_log(c->fc, AV_LOG_ERROR, "subsample size exceeds the packet size left\n");
|
||||||
|
return AVERROR_INVALIDDATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* skip the clear bytes */
|
||||||
|
input += sample->subsamples[i].bytes_of_clear_data;
|
||||||
|
size -= sample->subsamples[i].bytes_of_clear_data;
|
||||||
|
|
||||||
|
/* decrypt the encrypted bytes */
|
||||||
|
av_aes_ctr_crypt(sc->cenc.aes_ctr, input, input, sample->subsamples[i].bytes_of_protected_data);
|
||||||
|
input += sample->subsamples[i].bytes_of_protected_data;
|
||||||
|
size -= sample->subsamples[i].bytes_of_protected_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size > 0) {
|
||||||
|
av_log(c->fc, AV_LOG_ERROR, "leftover packet bytes after subsample processing\n");
|
||||||
|
return AVERROR_INVALIDDATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int cenc_filter(MOVContext *mov, AVStream* st, MOVStreamContext *sc, AVPacket *pkt, int current_index)
|
static int cenc_filter(MOVContext *mov, AVStream* st, MOVStreamContext *sc, AVPacket *pkt, int current_index)
|
||||||
{
|
{
|
||||||
MOVFragmentStreamInfo *frag_stream_info;
|
MOVFragmentStreamInfo *frag_stream_info;
|
||||||
|
@ -6749,6 +6805,40 @@ static int cenc_filter(MOVContext *mov, AVStream* st, MOVStreamContext *sc, AVPa
|
||||||
|
|
||||||
if (mov->decryption_key) {
|
if (mov->decryption_key) {
|
||||||
return cenc_decrypt(mov, sc, encrypted_sample, pkt->data, pkt->size);
|
return cenc_decrypt(mov, sc, encrypted_sample, pkt->data, pkt->size);
|
||||||
|
} else if (mov->decryption_key_map) {
|
||||||
|
uint8_t *key_id = encrypted_sample->key_id;
|
||||||
|
uint8_t *dec_key = NULL;
|
||||||
|
// check size of decryption_key_map size
|
||||||
|
if (mov->decryption_key_map_size == 1) {
|
||||||
|
dec_key = mov->decryption_key_map[0].decryption_key;
|
||||||
|
} else {
|
||||||
|
// find the decryption key for the given key ID
|
||||||
|
for (int i = 0; i < mov->decryption_key_map_size; i++) {
|
||||||
|
// if the key id is equals with the key id in the map
|
||||||
|
if (key_id == mov->decryption_key_map[i].key_id) {
|
||||||
|
dec_key = mov->decryption_key_map[i].decryption_key;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!dec_key) {
|
||||||
|
av_log(mov->fc, AV_LOG_ERROR, "No decryption key found for the given key ID\n");
|
||||||
|
return AVERROR_INVALIDDATA;
|
||||||
|
}
|
||||||
|
if (!encrypted_sample->subsample_count) {
|
||||||
|
// Decrypt the whole packet.
|
||||||
|
ret = av_aes_ctr_init(&sc->cenc.aes_ctr, dec_key);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
av_aes_ctr_crypt(&sc->cenc.aes_ctr, pkt->data, pkt->data, pkt->size);
|
||||||
|
} else {
|
||||||
|
// Decrypt the subsamples.
|
||||||
|
ret = cenc_decrypt_with_key(mov, sc, encrypted_sample, pkt->data, dec_key, pkt->size);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
size_t size;
|
size_t size;
|
||||||
uint8_t *side_data = av_encryption_info_add_side_data(encrypted_sample, &size);
|
uint8_t *side_data = av_encryption_info_add_side_data(encrypted_sample, &size);
|
||||||
|
@ -8219,6 +8309,7 @@ static const AVOption mov_options[] = {
|
||||||
AV_OPT_TYPE_BINARY, {.str="77214d4b196a87cd520045fd20a51d67"},
|
AV_OPT_TYPE_BINARY, {.str="77214d4b196a87cd520045fd20a51d67"},
|
||||||
.flags = AV_OPT_FLAG_DECODING_PARAM },
|
.flags = AV_OPT_FLAG_DECODING_PARAM },
|
||||||
{ "decryption_key", "The media decryption key (hex)", OFFSET(decryption_key), AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_DECODING_PARAM },
|
{ "decryption_key", "The media decryption key (hex)", OFFSET(decryption_key), AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_DECODING_PARAM },
|
||||||
|
{ "decryption_key_map", "The media decryption kid:key (hex) support up to 2", OFFSET(decryption_key_map), AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_DECODING_PARAM },
|
||||||
{ "enable_drefs", "Enable external track support.", OFFSET(enable_drefs), AV_OPT_TYPE_BOOL,
|
{ "enable_drefs", "Enable external track support.", OFFSET(enable_drefs), AV_OPT_TYPE_BOOL,
|
||||||
{.i64 = 0}, 0, 1, FLAGS },
|
{.i64 = 0}, 0, 1, FLAGS },
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue