[FFmpeg-devel] [PATCH 2/3] libavformat/hls: add support for SAMPLE-AES decryption in HLS demuxer
Anton Khirnov
anton at khirnov.net
Mon Jan 18 22:38:34 EET 2021
Quoting Nachiket Tarate (2021-01-18 18:39:56)
> Apple HTTP Live Streaming Sample Encryption:
>
> https://developer.apple.com/library/ios/documentation/AudioVideo/Conceptual/HLS_Sample_Encryption
>
> Signed-off-by: Nachiket Tarate <nachiket.programmer at gmail.com>
> ---
> libavformat/Makefile | 2 +-
> libavformat/hls.c | 97 ++++++-
> libavformat/hls_sample_aes.c | 497 +++++++++++++++++++++++++++++++++++
> libavformat/hls_sample_aes.h | 64 +++++
> libavformat/mpegts.c | 12 +
> 5 files changed, 658 insertions(+), 14 deletions(-)
> create mode 100644 libavformat/hls_sample_aes.c
> create mode 100644 libavformat/hls_sample_aes.h
>
> diff --git a/libavformat/Makefile b/libavformat/Makefile
> index 3a8fbcbe5f..c97930d98b 100644
> --- a/libavformat/Makefile
> +++ b/libavformat/Makefile
> diff --git a/libavformat/hls_sample_aes.c b/libavformat/hls_sample_aes.c
> new file mode 100644
> index 0000000000..6094ea4ea6
> --- /dev/null
> +++ b/libavformat/hls_sample_aes.c
> @@ -0,0 +1,497 @@
> +void ff_hls_read_audio_setup_info(HLSAudioSetupInfo *info, const uint8_t *buf, size_t size)
> +{
> + info->codec_tag = AV_RL32(buf);
> +
> + if (!strncmp((const char*)&info->codec_tag, "zaac", 4))
> + info->codec_id = AV_CODEC_ID_AAC;
> + else if (!strncmp((const char*)&info->codec_tag, "zac3", 4))
> + info->codec_id = AV_CODEC_ID_AC3;
> + else if (!strncmp((const char*)&info->codec_tag, "zec3", 4))
> + info->codec_id = AV_CODEC_ID_EAC3;
> + else
> + info->codec_id = AV_CODEC_ID_NONE;
> +
> + buf += 4;
> + info->priming = AV_RL16(buf);
> + buf += 2;
> + info->version = *buf++;
> + info->setup_data_length = *buf++;
> +
> + memcpy(info->setup_data, buf, info->setup_data_length);
You are not checking buffer sizes, both for buf and setup_data.
> +}
> +
> +/*
> + * Parse 'dec3' EC3SpecificBox
> + */
> +static int parse_dec3(AC3HeaderInfo **phdr, const uint8_t *buf, size_t size)
> +{
> + GetBitContext gb;
> + AC3HeaderInfo *hdr;
> + int err;
> +
> + int data_rate, fscod, acmod, lfeon;
> +
> + if (!*phdr)
Will this check ever fail?
> +/*
> + * Remove start code emulation prevention 0x03 bytes
> + */
> +static void remove_scep_3_bytes (NALUnit *nalu)
Feels like we have 9001 instances of this kind of code. Can't any of
them be reused?
> +{
> + int i = 0;
> + int j = 0;
> +
> + uint8_t *data = nalu->data;
> +
> + while (i < nalu->length) {
> + if (nalu->length - i > 3 && data[i] == 0x00 && data[i+1] == 0x00 && data[i+2] == 0x03 &&
> + (data[i+3] == 0x00 || data[i+3] == 0x01 || data[i+3] == 0x02 || data[i+3] == 0x03)) {
> + data[j] = 0x00;
> + data[j+1] = 0x00;
> + data[j+2] = data[i+3];
> + i += 4;
> + j += 3;
> + } else {
> + data[j++] = data[i++];
> + }
> + }
> +
> + nalu->length = j;
> +}
> +
> +static int is_start_code (const uint8_t *buf, int zeros_in_start_code)
> +{
> + int i;
> +
> + for (i = 0; i < zeros_in_start_code; i++) {
> + if(*(buf++) != 0x00) {
> + return 0;
> + }
> + }
> +
> + if(*buf != 0x01)
> + return 0;
> +
> + return 1;
> +}
> +
> +static int get_next_nal_unit (AVParserContext *ctx, NALUnit *nalu)
> +{
> + int i;
> + int len = 0;
> + int nalu_start_offset = 0;
> +
> + uint8_t *buf_out = ctx->buf_out;
> +
> + if (ctx->next_start_code_length != 0) {
> + for (i = 0; i < ctx->next_start_code_length - 1; i++) {
> + *buf_out++ = 0;
> + len++;
> + }
> + *buf_out++ = 1;
> + len++;
> + ctx->next_start_code_length = 0;
> + } else {
> + while (ctx->buf_in < ctx->buf_end) {
> + len++;
> + if ((*buf_out++ = *ctx->buf_in++) != 0)
> + break;
> + }
> + }
> +
> + if (ctx->buf_in >= ctx->buf_end) {
> + if (len == 0)
> + return 0;
> + else
> + return -1;
> + }
> +
> + /* No start code at the beginning of the NAL unit */
> + if(*(ctx->buf_in - 1) != 1 || len < 3) {
> + return -1;
> + }
> +
> + nalu_start_offset = len;
> +
> + while (ctx->next_start_code_length == 0) {
> + if (ctx->buf_in >= ctx->buf_end) {
> + nalu->data = ctx->buf_out + nalu_start_offset;
> + nalu->length = len - nalu_start_offset;
> + nalu->type = *nalu->data & 0x1F;
> + ctx->buf_out += nalu_start_offset;
> + return 0;
> + }
> + *buf_out++ = *ctx->buf_in++;
> + len++;
> + if (is_start_code(ctx->buf_in - 4, 3))
> + ctx->next_start_code_length = 4;
> + else if (is_start_code(ctx->buf_in - 3, 2))
> + ctx->next_start_code_length = 3;
> + else
> + ctx->next_start_code_length = 0;
> + }
> +
> + len -= ctx->next_start_code_length;
> +
> + nalu->data = ctx->buf_out + nalu_start_offset;
> + nalu->length = len - nalu_start_offset;
> + nalu->type = *nalu->data & 0x1F;
> + ctx->buf_out += nalu_start_offset;
> + return 0;
> +}
> +
> +static int decrypt_nal_unit (HLSCryptoContext *crypto_ctx, NALUnit *nalu)
> +{
> + int ret = 0;
> + int rem_bytes;
> + uint8_t *data;
> + uint8_t iv[16];
> + uint8_t decrypted_block[16];
> +
> + struct AVAES *aes_ctx = av_aes_alloc();
> + if (!aes_ctx) {
> + return AVERROR(ENOMEM);
> + }
> +
> + ret = av_aes_init(aes_ctx, crypto_ctx->key, 16 * 8, 1);
This error path leaks.
> +static int decrypt_sync_frame (enum AVCodecID codec_id, HLSCryptoContext *crypto_ctx, AudioFrame *frame)
> +{
> + int ret = 0;
> + uint8_t *data;
> + uint8_t *decrypted_data;
> + int num_of_encrypted_blocks;
> +
> + struct AVAES *aes_ctx = av_aes_alloc();
> + if (!aes_ctx) {
> + return AVERROR(ENOMEM);
> + }
> +
> + ret = av_aes_init(aes_ctx, crypto_ctx->key, 16 * 8, 1);
The error paths below leak.
Also, misc style issues like tabs, pointless casts from malloc, brace
placement etc.
--
Anton Khirnov
More information about the ffmpeg-devel
mailing list