[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