diff mbox

[FFmpeg-devel,RFC] avcodec/avcodec.h: Add encryption info side data

Message ID CAO7y9i_A5bs6JVLeH0xU7HjehfvRaS8qfvqFpB9tBCxGJpzELw@mail.gmail.com
State Superseded
Headers show

Commit Message

Jacob Trimble Jan. 5, 2018, 6:22 p.m. UTC
On Tue, Jan 2, 2018 at 9:57 AM, Jacob Trimble <modmaker@google.com> wrote:
> On Wed, Dec 20, 2017 at 4:31 PM, wm4 <nfxjfg@googlemail.com> wrote:
>> On Wed, 20 Dec 2017 15:10:43 -0800
>> Jacob Trimble <modmaker-at-google.com@ffmpeg.org> wrote:
>>
>>> From 1508d19e9f7acf43d76010ce54d59ff204613601 Mon Sep 17 00:00:00 2001
>>> From: Jacob Trimble <modmaker@google.com>
>>> Date: Tue, 5 Dec 2017 14:52:22 -0800
>>> Subject: [PATCH] avcodec/avcodec.h: Add encryption info side data.
>>>
>>> This new side-data will contain info on how a packet is encrypted.
>>> This allows the app to handle packet decryption.
>>>
>>> Signed-off-by: Jacob Trimble <modmaker@google.com>
>>> ---
>>
>> Looks generally good to me, a few minor cosmetic comments below.
>>
>>>  libavcodec/Makefile          |   2 +
>>>  libavcodec/avcodec.h         |  13 ++++
>>>  libavcodec/encryption_info.c | 139 +++++++++++++++++++++++++++++++++++++++++++
>>>  libavcodec/encryption_info.h | 121 +++++++++++++++++++++++++++++++++++++
>>>  4 files changed, 275 insertions(+)
>>>  create mode 100644 libavcodec/encryption_info.c
>>>  create mode 100644 libavcodec/encryption_info.h
>>>
>>> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
>>> index ab7893f560..11ad642c6c 100644
>>> --- a/libavcodec/Makefile
>>> +++ b/libavcodec/Makefile
>>> @@ -10,6 +10,7 @@ HEADERS = ac3_parser.h                                                  \
>>>            dirac.h                                                       \
>>>            dv_profile.h                                                  \
>>>            dxva2.h                                                       \
>>> +          encryption_info.h                                             \
>>>            jni.h                                                         \
>>>            mediacodec.h                                                  \
>>>            qsv.h                                                         \
>>> @@ -36,6 +37,7 @@ OBJS = ac3_parser.o                                                     \
>>>         dirac.o                                                          \
>>>         dv_profile.o                                                     \
>>>         encode.o                                                         \
>>> +       encryption_info.o                                                \
>>>         imgconvert.o                                                     \
>>>         jni.o                                                            \
>>>         mathtables.o                                                     \
>>> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
>>> index 5db6a81320..b43638ebc5 100644
>>> --- a/libavcodec/avcodec.h
>>> +++ b/libavcodec/avcodec.h
>>> @@ -1327,6 +1327,19 @@ enum AVPacketSideDataType {
>>>       */
>>>      AV_PKT_DATA_A53_CC,
>>>
>>> +    /**
>>> +     * This side data is encryption "initialization data".
>>> +     * For MP4 this is the entire 'pssh' box.
>>> +     * For WebM this is the key ID.
>>> +     */
>>> +    AV_PKT_DATA_ENCRYPTION_INIT_DATA,
>>> +
>>> +    /**
>>> +     * This side data contains encryption info for how to decrypt the packet.
>>> +     * The format is not part of ABI, use av_encryption_info_* methods to access.
>>> +     */
>>> +    AV_PKT_DATA_ENCRYPTION_INFO,
>>> +
>>>      /**
>>>       * The number of side data types.
>>>       * This is not part of the public API/ABI in the sense that it may
>>> diff --git a/libavcodec/encryption_info.c b/libavcodec/encryption_info.c
>>> new file mode 100644
>>> index 0000000000..59ee4c41a9
>>> --- /dev/null
>>> +++ b/libavcodec/encryption_info.c
>>> @@ -0,0 +1,139 @@
>>> +/**
>>> + * This file is part of FFmpeg.
>>> + *
>>> + * FFmpeg is free software; you can redistribute it and/or
>>> + * modify it under the terms of the GNU Lesser General Public
>>> + * License as published by the Free Software Foundation; either
>>> + * version 2.1 of the License, or (at your option) any later version.
>>> + *
>>> + * FFmpeg is distributed in the hope that it will be useful,
>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>>> + * Lesser General Public License for more details.
>>> + *
>>> + * You should have received a copy of the GNU Lesser General Public
>>> + * License along with FFmpeg; if not, write to the Free Software
>>> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
>>> + */
>>> +
>>> +#include "encryption_info.h"
>>> +#include "libavutil/avassert.h"
>>> +#include "libavutil/intreadwrite.h"
>>> +
>>> +#define FF_ENCRYPTION_INFO_EXTRA 24
>>> +
>>> +// The format of the side data:
>>> +// u32be scheme
>>> +// u32be crypt_byte_block
>>> +// u32be skip_byte_block
>>> +// u32be key_id_size
>>> +// u32be iv_size
>>> +// u32be subsample_count
>>> +// u8[key_id_size] key_id
>>> +// u8[iv_size] iv
>>> +// {
>>> +//   u32be bytes_of_clear_data
>>> +//   u32be bytes_of_protected_data
>>> +// }[subsample_count]
>>> +
>>> +AVEncryptionInfo* av_encryption_info_alloc(uint32_t subsample_count, uint32_t key_id_size, uint32_t iv_size)
>>
>> I think we generally put the "*" to the name, to reflect the actual C
>> syntax. (Here and in other places where pointers are in the function
>> return or argument types.)
>>
>>> +{
>>> +    AVEncryptionInfo *info;
>>> +
>>> +    info = av_mallocz(sizeof(AVEncryptionInfo));
>>> +    if (!info)
>>> +        return NULL;
>>> +
>>> +    info->key_id = av_mallocz(key_id_size);
>>> +    info->key_id_size = key_id_size;
>>> +    info->iv = av_mallocz(iv_size);
>>> +    info->iv_size = iv_size;
>>> +    info->subsamples = av_mallocz_array(sizeof(AVSubsampleEncryptionInfo), subsample_count);
>>> +    info->subsample_count = subsample_count;
>>> +
>>> +    // Allow info->subsamples to be NULL if there are no subsamples.
>>> +    if (!info->key_id || !info->iv || (!info->subsamples && subsample_count)) {
>>> +        av_free(info->key_id);
>>> +        av_free(info->iv);
>>> +        av_free(info->subsamples);
>>
>> Couldn't this just call av_encryption_info_free()?
>>
>>> +        av_freep(&info);
>>> +    }
>>> +
>>> +    return info;
>>> +}
>>> +
>>> +void av_encryption_info_free(AVEncryptionInfo* info)
>>> +{
>>> +    if (info) {
>>> +        av_free(info->key_id);
>>> +        av_free(info->iv);
>>> +        av_free(info->subsamples);
>>> +        av_free(info);
>>> +    }
>>> +}
>>> +
>>> +AVEncryptionInfo* av_encryption_info_copy_side_data(const AVPacket* packet)
>>
>> Could still be called "get" instead of "copy". I get the intention that
>> this returns a copy of the data, but "copy" still sounds like it's
>> being copied somewhere else. But I have no strong feelings about it.
>>
>>> +{
>>> +    AVEncryptionInfo *info;
>>> +    uint8_t *buffer;
>>> +    unsigned int size;
>>> +    uint32_t key_id_size, iv_size, subsample_count, i;
>>> +
>>> +    buffer = av_packet_get_side_data(packet, AV_PKT_DATA_ENCRYPTION_INFO, &size);
>>> +    if (!buffer)
>>> +        return NULL;
>>> +
>>> +    key_id_size = AV_RB32(buffer + 12);
>>> +    iv_size = AV_RB32(buffer + 16);
>>> +    subsample_count = AV_RB32(buffer + 20);
>>> +
>>> +    info = av_encryption_info_alloc(subsample_count, key_id_size, iv_size);
>>> +    if (!info)
>>> +        return NULL;
>>> +
>>> +    info->scheme = AV_RB32(buffer);
>>> +    info->crypt_byte_block = AV_RB32(buffer + 4);
>>> +    info->skip_byte_block = AV_RB32(buffer + 8);
>>> +    memcpy(info->key_id, buffer + 24, key_id_size);
>>> +    memcpy(info->iv, buffer + key_id_size + 24, iv_size);
>>> +
>>> +    buffer += key_id_size + iv_size + 24;
>>> +    for (i = 0; i < subsample_count; i++) {
>>> +        info->subsamples[i].bytes_of_clear_data = AV_RB32(buffer);
>>> +        info->subsamples[i].bytes_of_protected_data = AV_RB32(buffer + 4);
>>> +        buffer += 8;
>>> +    }
>>> +
>>> +    return info;
>>> +}
>>> +
>>> +int av_encryption_info_add_side_data(AVPacket* packet, const AVEncryptionInfo* info) {
>>
>> We put the "{" on a separate line for functions.
>>
>>> +    uint8_t *buffer;
>>> +    size_t size;
>>> +    uint32_t i;
>>> +
>>> +    size = FF_ENCRYPTION_INFO_EXTRA + info->key_id_size + info->iv_size +
>>> +           (sizeof(AVSubsampleEncryptionInfo) * info->subsample_count);
>>> +    buffer = av_packet_new_side_data(packet, AV_PKT_DATA_ENCRYPTION_INFO, size);
>>> +    if (!buffer)
>>> +        return AVERROR(ENOMEM);
>>> +
>>> +    AV_WB32(buffer,      info->scheme);
>>> +    AV_WB32(buffer +  4, info->crypt_byte_block);
>>> +    AV_WB32(buffer +  8, info->skip_byte_block);
>>> +    AV_WB32(buffer + 12, info->key_id_size);
>>> +    AV_WB32(buffer + 16, info->iv_size);
>>> +    AV_WB32(buffer + 20, info->subsample_count);
>>> +    buffer += 24;
>>> +    memcpy(buffer, info->key_id, info->key_id_size);
>>> +    buffer += info->key_id_size;
>>> +    memcpy(buffer, info->iv, info->iv_size);
>>> +    buffer += info->iv_size;
>>> +    for (i = 0; i < info->subsample_count; i++) {
>>> +        AV_WB32(buffer, info->subsamples[i].bytes_of_clear_data);
>>> +        AV_WB32(buffer + 4, info->subsamples[i].bytes_of_protected_data);
>>> +        buffer += 8;
>>> +    }
>>> +
>>> +    return 0;
>>> +}
>>> diff --git a/libavcodec/encryption_info.h b/libavcodec/encryption_info.h
>>> new file mode 100644
>>> index 0000000000..4fc9b6d3f1
>>> --- /dev/null
>>> +++ b/libavcodec/encryption_info.h
>>> @@ -0,0 +1,121 @@
>>> +/**
>>> + * This file is part of FFmpeg.
>>> + *
>>> + * FFmpeg is free software; you can redistribute it and/or
>>> + * modify it under the terms of the GNU Lesser General Public
>>> + * License as published by the Free Software Foundation; either
>>> + * version 2.1 of the License, or (at your option) any later version.
>>> + *
>>> + * FFmpeg is distributed in the hope that it will be useful,
>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>>> + * Lesser General Public License for more details.
>>> + *
>>> + * You should have received a copy of the GNU Lesser General Public
>>> + * License along with FFmpeg; if not, write to the Free Software
>>> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
>>> + */
>>> +
>>> +#ifndef AVUTIL_ENCRYPTION_INFO_H
>>> +#define AVUTIL_ENCRYPTION_INFO_H
>>> +
>>> +#include "avcodec.h"
>>> +
>>> +typedef struct AVSubsampleEncryptionInfo {
>>> +    /** The number of bytes that are clear. */
>>> +    unsigned int bytes_of_clear_data;
>>> +
>>> +    /**
>>> +     * The number of bytes that are protected.  If using pattern encryption,
>>> +     * the pattern applies to only the protected bytes; if not using pattern
>>> +     * encryption, all these bytes are encrypted.
>>> +     */
>>> +    unsigned int bytes_of_protected_data;
>>> +} AVSubsampleEncryptionInfo;
>>> +
>>> +/**
>>> + * This describes encryption info for a packet.  This contains frame-specific
>>> + * info for how to decrypt the packet before passing it to the decoder.
>>> + *
>>> + * The size of this struct is not part of the public ABI.
>>> + */
>>> +typedef struct AVEncryptionInfo {
>>> +    /** The fourcc encryption scheme. */
>>> +    uint32_t scheme;
>>> +
>>> +    /**
>>> +     * Only used for pattern encryption.  This is the number of 16-byte blocks
>>> +     * that are encrypted.
>>> +     */
>>> +    uint32_t crypt_byte_block;
>>> +
>>> +    /**
>>> +     * Only used for pattern encryption.  This is the number of 16-byte blocks
>>> +     * that are clear.
>>> +     */
>>> +    uint32_t skip_byte_block;
>>> +
>>> +    /**
>>> +     * The ID of the key used to encrypt the packet.  This should always be
>>> +     * 16 bytes long, but may be changed in the future.
>>> +     */
>>> +    uint8_t *key_id;
>>> +    uint32_t key_id_size;
>>> +
>>> +    /**
>>> +     * The initialization vector.  This may have been zero-filled to be the
>>> +     * correct block size.  This should always be 16 bytes long, but may be
>>> +     * changed in the future.
>>> +     */
>>> +    uint8_t *iv;
>>> +    uint32_t iv_size;
>>> +
>>> +    /**
>>> +     * An array of subsample encryption info specifying how parts of the sample
>>> +     * are encrypted.  If there are no subsamples, then the whole sample is
>>> +     * encrypted.
>>> +     */
>>> +    AVSubsampleEncryptionInfo* subsamples;
>>> +    uint32_t subsample_count;
>>> +} AVEncryptionInfo;
>>> +
>>> +/**
>>> + * Allocates an AVEncryptionInfo structure and sub-pointers to hold the given
>>> + * number of subsamples.  This will allocate pointers for the key ID, IV,
>>> + * and subsample entries, set the size members, and zero-initialize the rest.
>>> + *
>>> + * @param subsample_count The number of subsamples.
>>> + * @param key_id_size The number of bytes in the key ID, should be 16.
>>> + * @param key_id_size The number of bytes in the IV, should be 16.
>>> + *
>>> + * @return The new AVEncryptionInfo structure, or NULL on error.
>>> + */
>>> +AVEncryptionInfo* av_encryption_info_alloc(uint32_t subsample_count, uint32_t key_id_size, uint32_t iv_size);
>>> +
>>> +/**
>>> + * Frees the given encryption info object.  This MUST NOT be used to free the
>>> + * side-data data pointer, that should use normal side-data methods.
>>> + */
>>> +void av_encryption_info_free(AVEncryptionInfo* info);
>>> +
>>> +/**
>>> + * Creates a copy of the AVEncryptionInfo that is contained in the side data of
>>> + * the given packet.  The resulting object should be passed to
>>> + * av_encryption_info_free() when done.
>>> + *
>>> + * This returns NULL if there is a memory error or if the packet isn't encrypted.
>>> + * To detect if the packet is encrypted, use av_packet_get_side_data.
>>> + *
>>> + * @return The new AVEncryptionInfo structure, or NULL on error.
>>> + */
>>> +AVEncryptionInfo* av_encryption_info_copy_side_data(const AVPacket* packet);
>>> +
>>> +/**
>>> + * Adds a new side data to the given packet that holds a copy of the given
>>> + * encryption info.
>>> + *
>>> + * @return 0 on success, or a negative error code on error.
>>> + */
>>> +int av_encryption_info_add_side_data(AVPacket* packet, const AVEncryptionInfo* info);
>>> +
>>> +#endif /* AVUTIL_ENCRYPTION_INFO_H */
>>
>> So as far as the side data management goes, this should be good. No
>> comment about the crypto stuff or the byte array (de)serialization
>> stuff, didn't take a close look at it. The final patch should also
>> include a minor libavutil bump and an doc/APIchanges entry,
>
> Leaving version bump and changelog entry to whoever pushes it, but
> other comments done.

Just noticed the new files were in libavcodec, moved to libavutil.
Can someone please review this so it can be pushed.  I have the MP4
implementation ready and I would like to get that reviewed and pushed
as soon as possible.

Thanks.

Comments

wm4 Jan. 5, 2018, 7:27 p.m. UTC | #1
On Fri, 5 Jan 2018 10:22:31 -0800
Jacob Trimble <modmaker-at-google.com@ffmpeg.org> wrote:

> Just noticed the new files were in libavcodec, moved to libavutil.
> Can someone please review this so it can be pushed.  I have the MP4
> implementation ready and I would like to get that reviewed and pushed
> as soon as possible.

I'd assume we'd wait with applying this until the mp4 patch that uses
it is reviewed. I'm fine with this patch and I think it can be pushed
as it is, although I just noticed an APIchanges entry and minor version
bump is actually missing. You could add them when sending the final
patch set.

Maybe getting confirmation from Michael Niedermayer that it's safe to
proceed would be good (i.e. that the patch will be accepted without
major changes).

It's also possible that others are fine with pushing it now, but I'd
argue it should wait until something uses it.

(Personally I don't really appreciate the complexity of exporting this
metadata, when libavformat can already decrypt the data internally. But
I suppose it has valid use cases.)
Michael Niedermayer Jan. 5, 2018, 10:24 p.m. UTC | #2
On Fri, Jan 05, 2018 at 10:22:31AM -0800, Jacob Trimble wrote:
> On Tue, Jan 2, 2018 at 9:57 AM, Jacob Trimble <modmaker@google.com> wrote:
> > On Wed, Dec 20, 2017 at 4:31 PM, wm4 <nfxjfg@googlemail.com> wrote:
> >> On Wed, 20 Dec 2017 15:10:43 -0800
> >> Jacob Trimble <modmaker-at-google.com@ffmpeg.org> wrote:
> >>
> >>> From 1508d19e9f7acf43d76010ce54d59ff204613601 Mon Sep 17 00:00:00 2001
> >>> From: Jacob Trimble <modmaker@google.com>
> >>> Date: Tue, 5 Dec 2017 14:52:22 -0800
> >>> Subject: [PATCH] avcodec/avcodec.h: Add encryption info side data.
> >>>
> >>> This new side-data will contain info on how a packet is encrypted.
> >>> This allows the app to handle packet decryption.
> >>>
> >>> Signed-off-by: Jacob Trimble <modmaker@google.com>
> >>> ---
> >>
> >> Looks generally good to me, a few minor cosmetic comments below.
> >>
> >>>  libavcodec/Makefile          |   2 +
> >>>  libavcodec/avcodec.h         |  13 ++++
> >>>  libavcodec/encryption_info.c | 139 +++++++++++++++++++++++++++++++++++++++++++
> >>>  libavcodec/encryption_info.h | 121 +++++++++++++++++++++++++++++++++++++
> >>>  4 files changed, 275 insertions(+)
> >>>  create mode 100644 libavcodec/encryption_info.c
> >>>  create mode 100644 libavcodec/encryption_info.h
> >>>
> >>> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> >>> index ab7893f560..11ad642c6c 100644
> >>> --- a/libavcodec/Makefile
> >>> +++ b/libavcodec/Makefile
> >>> @@ -10,6 +10,7 @@ HEADERS = ac3_parser.h                                                  \
> >>>            dirac.h                                                       \
> >>>            dv_profile.h                                                  \
> >>>            dxva2.h                                                       \
> >>> +          encryption_info.h                                             \
> >>>            jni.h                                                         \
> >>>            mediacodec.h                                                  \
> >>>            qsv.h                                                         \
> >>> @@ -36,6 +37,7 @@ OBJS = ac3_parser.o                                                     \
> >>>         dirac.o                                                          \
> >>>         dv_profile.o                                                     \
> >>>         encode.o                                                         \
> >>> +       encryption_info.o                                                \
> >>>         imgconvert.o                                                     \
> >>>         jni.o                                                            \
> >>>         mathtables.o                                                     \
> >>> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
> >>> index 5db6a81320..b43638ebc5 100644
> >>> --- a/libavcodec/avcodec.h
> >>> +++ b/libavcodec/avcodec.h
> >>> @@ -1327,6 +1327,19 @@ enum AVPacketSideDataType {
> >>>       */
> >>>      AV_PKT_DATA_A53_CC,
> >>>
> >>> +    /**
> >>> +     * This side data is encryption "initialization data".
> >>> +     * For MP4 this is the entire 'pssh' box.
> >>> +     * For WebM this is the key ID.
> >>> +     */
> >>> +    AV_PKT_DATA_ENCRYPTION_INIT_DATA,
> >>> +
> >>> +    /**
> >>> +     * This side data contains encryption info for how to decrypt the packet.
> >>> +     * The format is not part of ABI, use av_encryption_info_* methods to access.
> >>> +     */
> >>> +    AV_PKT_DATA_ENCRYPTION_INFO,
> >>> +
> >>>      /**
> >>>       * The number of side data types.
> >>>       * This is not part of the public API/ABI in the sense that it may
> >>> diff --git a/libavcodec/encryption_info.c b/libavcodec/encryption_info.c
> >>> new file mode 100644
> >>> index 0000000000..59ee4c41a9
> >>> --- /dev/null
> >>> +++ b/libavcodec/encryption_info.c
> >>> @@ -0,0 +1,139 @@
> >>> +/**
> >>> + * This file is part of FFmpeg.
> >>> + *
> >>> + * FFmpeg is free software; you can redistribute it and/or
> >>> + * modify it under the terms of the GNU Lesser General Public
> >>> + * License as published by the Free Software Foundation; either
> >>> + * version 2.1 of the License, or (at your option) any later version.
> >>> + *
> >>> + * FFmpeg is distributed in the hope that it will be useful,
> >>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> >>> + * Lesser General Public License for more details.
> >>> + *
> >>> + * You should have received a copy of the GNU Lesser General Public
> >>> + * License along with FFmpeg; if not, write to the Free Software
> >>> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> >>> + */
> >>> +
> >>> +#include "encryption_info.h"
> >>> +#include "libavutil/avassert.h"
> >>> +#include "libavutil/intreadwrite.h"
> >>> +
> >>> +#define FF_ENCRYPTION_INFO_EXTRA 24
> >>> +
> >>> +// The format of the side data:
> >>> +// u32be scheme
> >>> +// u32be crypt_byte_block
> >>> +// u32be skip_byte_block
> >>> +// u32be key_id_size
> >>> +// u32be iv_size
> >>> +// u32be subsample_count
> >>> +// u8[key_id_size] key_id
> >>> +// u8[iv_size] iv
> >>> +// {
> >>> +//   u32be bytes_of_clear_data
> >>> +//   u32be bytes_of_protected_data
> >>> +// }[subsample_count]
> >>> +
> >>> +AVEncryptionInfo* av_encryption_info_alloc(uint32_t subsample_count, uint32_t key_id_size, uint32_t iv_size)
> >>
> >> I think we generally put the "*" to the name, to reflect the actual C
> >> syntax. (Here and in other places where pointers are in the function
> >> return or argument types.)
> >>
> >>> +{
> >>> +    AVEncryptionInfo *info;
> >>> +
> >>> +    info = av_mallocz(sizeof(AVEncryptionInfo));
> >>> +    if (!info)
> >>> +        return NULL;
> >>> +
> >>> +    info->key_id = av_mallocz(key_id_size);
> >>> +    info->key_id_size = key_id_size;
> >>> +    info->iv = av_mallocz(iv_size);
> >>> +    info->iv_size = iv_size;
> >>> +    info->subsamples = av_mallocz_array(sizeof(AVSubsampleEncryptionInfo), subsample_count);
> >>> +    info->subsample_count = subsample_count;
> >>> +
> >>> +    // Allow info->subsamples to be NULL if there are no subsamples.
> >>> +    if (!info->key_id || !info->iv || (!info->subsamples && subsample_count)) {
> >>> +        av_free(info->key_id);
> >>> +        av_free(info->iv);
> >>> +        av_free(info->subsamples);
> >>
> >> Couldn't this just call av_encryption_info_free()?
> >>
> >>> +        av_freep(&info);
> >>> +    }
> >>> +
> >>> +    return info;
> >>> +}
> >>> +
> >>> +void av_encryption_info_free(AVEncryptionInfo* info)
> >>> +{
> >>> +    if (info) {
> >>> +        av_free(info->key_id);
> >>> +        av_free(info->iv);
> >>> +        av_free(info->subsamples);
> >>> +        av_free(info);
> >>> +    }
> >>> +}
> >>> +
> >>> +AVEncryptionInfo* av_encryption_info_copy_side_data(const AVPacket* packet)
> >>
> >> Could still be called "get" instead of "copy". I get the intention that
> >> this returns a copy of the data, but "copy" still sounds like it's
> >> being copied somewhere else. But I have no strong feelings about it.
> >>
> >>> +{
> >>> +    AVEncryptionInfo *info;
> >>> +    uint8_t *buffer;
> >>> +    unsigned int size;
> >>> +    uint32_t key_id_size, iv_size, subsample_count, i;
> >>> +
> >>> +    buffer = av_packet_get_side_data(packet, AV_PKT_DATA_ENCRYPTION_INFO, &size);
> >>> +    if (!buffer)
> >>> +        return NULL;
> >>> +
> >>> +    key_id_size = AV_RB32(buffer + 12);
> >>> +    iv_size = AV_RB32(buffer + 16);
> >>> +    subsample_count = AV_RB32(buffer + 20);
> >>> +
> >>> +    info = av_encryption_info_alloc(subsample_count, key_id_size, iv_size);
> >>> +    if (!info)
> >>> +        return NULL;
> >>> +
> >>> +    info->scheme = AV_RB32(buffer);
> >>> +    info->crypt_byte_block = AV_RB32(buffer + 4);
> >>> +    info->skip_byte_block = AV_RB32(buffer + 8);
> >>> +    memcpy(info->key_id, buffer + 24, key_id_size);
> >>> +    memcpy(info->iv, buffer + key_id_size + 24, iv_size);
> >>> +
> >>> +    buffer += key_id_size + iv_size + 24;
> >>> +    for (i = 0; i < subsample_count; i++) {
> >>> +        info->subsamples[i].bytes_of_clear_data = AV_RB32(buffer);
> >>> +        info->subsamples[i].bytes_of_protected_data = AV_RB32(buffer + 4);
> >>> +        buffer += 8;
> >>> +    }
> >>> +
> >>> +    return info;
> >>> +}
> >>> +
> >>> +int av_encryption_info_add_side_data(AVPacket* packet, const AVEncryptionInfo* info) {
> >>
> >> We put the "{" on a separate line for functions.
> >>
> >>> +    uint8_t *buffer;
> >>> +    size_t size;
> >>> +    uint32_t i;
> >>> +
> >>> +    size = FF_ENCRYPTION_INFO_EXTRA + info->key_id_size + info->iv_size +
> >>> +           (sizeof(AVSubsampleEncryptionInfo) * info->subsample_count);
> >>> +    buffer = av_packet_new_side_data(packet, AV_PKT_DATA_ENCRYPTION_INFO, size);
> >>> +    if (!buffer)
> >>> +        return AVERROR(ENOMEM);
> >>> +
> >>> +    AV_WB32(buffer,      info->scheme);
> >>> +    AV_WB32(buffer +  4, info->crypt_byte_block);
> >>> +    AV_WB32(buffer +  8, info->skip_byte_block);
> >>> +    AV_WB32(buffer + 12, info->key_id_size);
> >>> +    AV_WB32(buffer + 16, info->iv_size);
> >>> +    AV_WB32(buffer + 20, info->subsample_count);
> >>> +    buffer += 24;
> >>> +    memcpy(buffer, info->key_id, info->key_id_size);
> >>> +    buffer += info->key_id_size;
> >>> +    memcpy(buffer, info->iv, info->iv_size);
> >>> +    buffer += info->iv_size;
> >>> +    for (i = 0; i < info->subsample_count; i++) {
> >>> +        AV_WB32(buffer, info->subsamples[i].bytes_of_clear_data);
> >>> +        AV_WB32(buffer + 4, info->subsamples[i].bytes_of_protected_data);
> >>> +        buffer += 8;
> >>> +    }
> >>> +
> >>> +    return 0;
> >>> +}
> >>> diff --git a/libavcodec/encryption_info.h b/libavcodec/encryption_info.h
> >>> new file mode 100644
> >>> index 0000000000..4fc9b6d3f1
> >>> --- /dev/null
> >>> +++ b/libavcodec/encryption_info.h
> >>> @@ -0,0 +1,121 @@
> >>> +/**
> >>> + * This file is part of FFmpeg.
> >>> + *
> >>> + * FFmpeg is free software; you can redistribute it and/or
> >>> + * modify it under the terms of the GNU Lesser General Public
> >>> + * License as published by the Free Software Foundation; either
> >>> + * version 2.1 of the License, or (at your option) any later version.
> >>> + *
> >>> + * FFmpeg is distributed in the hope that it will be useful,
> >>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> >>> + * Lesser General Public License for more details.
> >>> + *
> >>> + * You should have received a copy of the GNU Lesser General Public
> >>> + * License along with FFmpeg; if not, write to the Free Software
> >>> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> >>> + */
> >>> +
> >>> +#ifndef AVUTIL_ENCRYPTION_INFO_H
> >>> +#define AVUTIL_ENCRYPTION_INFO_H
> >>> +
> >>> +#include "avcodec.h"
> >>> +
> >>> +typedef struct AVSubsampleEncryptionInfo {
> >>> +    /** The number of bytes that are clear. */
> >>> +    unsigned int bytes_of_clear_data;
> >>> +
> >>> +    /**
> >>> +     * The number of bytes that are protected.  If using pattern encryption,
> >>> +     * the pattern applies to only the protected bytes; if not using pattern
> >>> +     * encryption, all these bytes are encrypted.
> >>> +     */
> >>> +    unsigned int bytes_of_protected_data;
> >>> +} AVSubsampleEncryptionInfo;
> >>> +
> >>> +/**
> >>> + * This describes encryption info for a packet.  This contains frame-specific
> >>> + * info for how to decrypt the packet before passing it to the decoder.
> >>> + *
> >>> + * The size of this struct is not part of the public ABI.
> >>> + */
> >>> +typedef struct AVEncryptionInfo {
> >>> +    /** The fourcc encryption scheme. */
> >>> +    uint32_t scheme;
> >>> +
> >>> +    /**
> >>> +     * Only used for pattern encryption.  This is the number of 16-byte blocks
> >>> +     * that are encrypted.
> >>> +     */
> >>> +    uint32_t crypt_byte_block;
> >>> +
> >>> +    /**
> >>> +     * Only used for pattern encryption.  This is the number of 16-byte blocks
> >>> +     * that are clear.
> >>> +     */
> >>> +    uint32_t skip_byte_block;
> >>> +
> >>> +    /**
> >>> +     * The ID of the key used to encrypt the packet.  This should always be
> >>> +     * 16 bytes long, but may be changed in the future.
> >>> +     */
> >>> +    uint8_t *key_id;
> >>> +    uint32_t key_id_size;
> >>> +
> >>> +    /**
> >>> +     * The initialization vector.  This may have been zero-filled to be the
> >>> +     * correct block size.  This should always be 16 bytes long, but may be
> >>> +     * changed in the future.
> >>> +     */
> >>> +    uint8_t *iv;
> >>> +    uint32_t iv_size;
> >>> +
> >>> +    /**
> >>> +     * An array of subsample encryption info specifying how parts of the sample
> >>> +     * are encrypted.  If there are no subsamples, then the whole sample is
> >>> +     * encrypted.
> >>> +     */
> >>> +    AVSubsampleEncryptionInfo* subsamples;
> >>> +    uint32_t subsample_count;
> >>> +} AVEncryptionInfo;
> >>> +
> >>> +/**
> >>> + * Allocates an AVEncryptionInfo structure and sub-pointers to hold the given
> >>> + * number of subsamples.  This will allocate pointers for the key ID, IV,
> >>> + * and subsample entries, set the size members, and zero-initialize the rest.
> >>> + *
> >>> + * @param subsample_count The number of subsamples.
> >>> + * @param key_id_size The number of bytes in the key ID, should be 16.
> >>> + * @param key_id_size The number of bytes in the IV, should be 16.
> >>> + *
> >>> + * @return The new AVEncryptionInfo structure, or NULL on error.
> >>> + */
> >>> +AVEncryptionInfo* av_encryption_info_alloc(uint32_t subsample_count, uint32_t key_id_size, uint32_t iv_size);
> >>> +
> >>> +/**
> >>> + * Frees the given encryption info object.  This MUST NOT be used to free the
> >>> + * side-data data pointer, that should use normal side-data methods.
> >>> + */
> >>> +void av_encryption_info_free(AVEncryptionInfo* info);
> >>> +
> >>> +/**
> >>> + * Creates a copy of the AVEncryptionInfo that is contained in the side data of
> >>> + * the given packet.  The resulting object should be passed to
> >>> + * av_encryption_info_free() when done.
> >>> + *
> >>> + * This returns NULL if there is a memory error or if the packet isn't encrypted.
> >>> + * To detect if the packet is encrypted, use av_packet_get_side_data.
> >>> + *
> >>> + * @return The new AVEncryptionInfo structure, or NULL on error.
> >>> + */
> >>> +AVEncryptionInfo* av_encryption_info_copy_side_data(const AVPacket* packet);
> >>> +
> >>> +/**
> >>> + * Adds a new side data to the given packet that holds a copy of the given
> >>> + * encryption info.
> >>> + *
> >>> + * @return 0 on success, or a negative error code on error.
> >>> + */
> >>> +int av_encryption_info_add_side_data(AVPacket* packet, const AVEncryptionInfo* info);
> >>> +
> >>> +#endif /* AVUTIL_ENCRYPTION_INFO_H */
> >>
> >> So as far as the side data management goes, this should be good. No
> >> comment about the crypto stuff or the byte array (de)serialization
> >> stuff, didn't take a close look at it. The final patch should also
> >> include a minor libavutil bump and an doc/APIchanges entry,
> >
> > Leaving version bump and changelog entry to whoever pushes it, but
> > other comments done.
> 
> Just noticed the new files were in libavcodec, moved to libavutil.
> Can someone please review this so it can be pushed.  I have the MP4
> implementation ready and I would like to get that reviewed and pushed
> as soon as possible.
> 
> Thanks.

>  libavcodec/avcodec.h        |   13 ++++
>  libavutil/Makefile          |    2 
>  libavutil/encryption_info.c |  137 ++++++++++++++++++++++++++++++++++++++++++++
>  libavutil/encryption_info.h |  121 ++++++++++++++++++++++++++++++++++++++
>  4 files changed, 273 insertions(+)
> 44c4062d454970ff3ff037a101beaeab99a4e60b  encryption-info-v7.patch
> From 758b2439e779045fbc82ca8cf91c7f71230e440b Mon Sep 17 00:00:00 2001
> From: Jacob Trimble <modmaker@google.com>
> Date: Tue, 5 Dec 2017 14:52:22 -0800
> Subject: [PATCH] avcodec/avcodec.h: Add encryption info side data.
> 
> This new side-data will contain info on how a packet is encrypted.
> This allows the app to handle packet decryption.
> 
> Signed-off-by: Jacob Trimble <modmaker@google.com>
> ---
>  libavcodec/avcodec.h        |  13 +++++
>  libavutil/Makefile          |   2 +
>  libavutil/encryption_info.c | 137 ++++++++++++++++++++++++++++++++++++++++++++
>  libavutil/encryption_info.h | 121 ++++++++++++++++++++++++++++++++++++++
>  4 files changed, 273 insertions(+)
>  create mode 100644 libavutil/encryption_info.c
>  create mode 100644 libavutil/encryption_info.h
> 
> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
> index c13deb599f..e766f21ca0 100644
> --- a/libavcodec/avcodec.h
> +++ b/libavcodec/avcodec.h
> @@ -1341,6 +1341,19 @@ enum AVPacketSideDataType {
>       */
>      AV_PKT_DATA_A53_CC,
>  
> +    /**
> +     * This side data is encryption "initialization data".
> +     * For MP4 this is the entire 'pssh' box.
> +     * For WebM this is the key ID.
> +     */
> +    AV_PKT_DATA_ENCRYPTION_INIT_DATA,
> +
> +    /**
> +     * This side data contains encryption info for how to decrypt the packet.
> +     * The format is not part of ABI, use av_encryption_info_* methods to access.
> +     */
> +    AV_PKT_DATA_ENCRYPTION_INFO,
> +
>      /**
>       * The number of side data types.
>       * This is not part of the public API/ABI in the sense that it may
> diff --git a/libavutil/Makefile b/libavutil/Makefile
> index 66b894d66e..fed936df7b 100644
> --- a/libavutil/Makefile
> +++ b/libavutil/Makefile
> @@ -24,6 +24,7 @@ HEADERS = adler32.h                                                     \
>            dict.h                                                        \
>            display.h                                                     \
>            downmix_info.h                                                \
> +          encryption_info.h                                             \
>            error.h                                                       \
>            eval.h                                                        \
>            fifo.h                                                        \
> @@ -107,6 +108,7 @@ OBJS = adler32.o                                                        \
>         dict.o                                                           \
>         display.o                                                        \
>         downmix_info.o                                                   \
> +       encryption_info.o                                                \
>         error.o                                                          \
>         eval.o                                                           \
>         fifo.o                                                           \
> diff --git a/libavutil/encryption_info.c b/libavutil/encryption_info.c
> new file mode 100644
> index 0000000000..76796b50ee
> --- /dev/null
> +++ b/libavutil/encryption_info.c
> @@ -0,0 +1,137 @@
> +/**
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#include "encryption_info.h"
> +#include "libavutil/intreadwrite.h"
> +
> +#define FF_ENCRYPTION_INFO_EXTRA 24
> +
> +// The format of the side data:
> +// u32be scheme
> +// u32be crypt_byte_block
> +// u32be skip_byte_block
> +// u32be key_id_size
> +// u32be iv_size
> +// u32be subsample_count
> +// u8[key_id_size] key_id
> +// u8[iv_size] iv
> +// {
> +//   u32be bytes_of_clear_data
> +//   u32be bytes_of_protected_data
> +// }[subsample_count]
> +
> +AVEncryptionInfo *av_encryption_info_alloc(uint32_t subsample_count, uint32_t key_id_size, uint32_t iv_size)
> +{
> +    AVEncryptionInfo *info;
> +
> +    info = av_mallocz(sizeof(AVEncryptionInfo));
> +    if (!info)
> +        return NULL;
> +
> +    info->key_id = av_mallocz(key_id_size);
> +    info->key_id_size = key_id_size;
> +    info->iv = av_mallocz(iv_size);
> +    info->iv_size = iv_size;
> +    info->subsamples = av_mallocz_array(sizeof(AVSubsampleEncryptionInfo), subsample_count);
> +    info->subsample_count = subsample_count;
> +
> +    // Allow info->subsamples to be NULL if there are no subsamples.
> +    if (!info->key_id || !info->iv || (!info->subsamples && subsample_count)) {
> +        av_encryption_info_free(info);
> +        return NULL;
> +    }
> +
> +    return info;
> +}
> +
> +void av_encryption_info_free(AVEncryptionInfo *info)
> +{
> +    if (info) {
> +        av_free(info->key_id);
> +        av_free(info->iv);
> +        av_free(info->subsamples);
> +        av_free(info);
> +    }
> +}
> +

> +AVEncryptionInfo *av_encryption_info_get_side_data(const AVPacket *packet)
> +{
> +    AVEncryptionInfo *info;
> +    uint8_t *buffer;
> +    unsigned int size;
> +    uint32_t key_id_size, iv_size, subsample_count, i;
> +
> +    buffer = av_packet_get_side_data(packet, AV_PKT_DATA_ENCRYPTION_INFO, &size);
> +    if (!buffer)
> +        return NULL;
> +
> +    key_id_size = AV_RB32(buffer + 12);
> +    iv_size = AV_RB32(buffer + 16);
> +    subsample_count = AV_RB32(buffer + 20);

These should be checked against size, making sure the data is consistent


[...]
Michael Niedermayer Jan. 5, 2018, 10:32 p.m. UTC | #3
On Fri, Jan 05, 2018 at 08:27:41PM +0100, wm4 wrote:
> On Fri, 5 Jan 2018 10:22:31 -0800
> Jacob Trimble <modmaker-at-google.com@ffmpeg.org> wrote:
> 
> > Just noticed the new files were in libavcodec, moved to libavutil.
> > Can someone please review this so it can be pushed.  I have the MP4
> > implementation ready and I would like to get that reviewed and pushed
> > as soon as possible.
> 
> I'd assume we'd wait with applying this until the mp4 patch that uses
> it is reviewed. I'm fine with this patch and I think it can be pushed
> as it is, although I just noticed an APIchanges entry and minor version
> bump is actually missing. You could add them when sending the final
> patch set.
> 

> Maybe getting confirmation from Michael Niedermayer that it's safe to
> proceed would be good (i.e. that the patch will be accepted without
> major changes).

if everyone is ok with the design and no regressions are found than iam ok
with it as well


[...]
James Almer Jan. 5, 2018, 10:42 p.m. UTC | #4
On 1/5/2018 7:32 PM, Michael Niedermayer wrote:
> On Fri, Jan 05, 2018 at 08:27:41PM +0100, wm4 wrote:
>> On Fri, 5 Jan 2018 10:22:31 -0800
>> Jacob Trimble <modmaker-at-google.com@ffmpeg.org> wrote:
>>
>>> Just noticed the new files were in libavcodec, moved to libavutil.
>>> Can someone please review this so it can be pushed.  I have the MP4
>>> implementation ready and I would like to get that reviewed and pushed
>>> as soon as possible.
>>
>> I'd assume we'd wait with applying this until the mp4 patch that uses
>> it is reviewed. I'm fine with this patch and I think it can be pushed
>> as it is, although I just noticed an APIchanges entry and minor version
>> bump is actually missing. You could add them when sending the final
>> patch set.
>>
> 
>> Maybe getting confirmation from Michael Niedermayer that it's safe to
>> proceed would be good (i.e. that the patch will be accepted without
>> major changes).
> 
> if everyone is ok with the design and no regressions are found than iam ok
> with it as well

This being in libavutil, the two functions using AVPacket should be
changed to take and return a byte array instead, that the caller
manually either got from side data, or will afterwards adds as side data.
diff mbox

Patch

From 758b2439e779045fbc82ca8cf91c7f71230e440b Mon Sep 17 00:00:00 2001
From: Jacob Trimble <modmaker@google.com>
Date: Tue, 5 Dec 2017 14:52:22 -0800
Subject: [PATCH] avcodec/avcodec.h: Add encryption info side data.

This new side-data will contain info on how a packet is encrypted.
This allows the app to handle packet decryption.

Signed-off-by: Jacob Trimble <modmaker@google.com>
---
 libavcodec/avcodec.h        |  13 +++++
 libavutil/Makefile          |   2 +
 libavutil/encryption_info.c | 137 ++++++++++++++++++++++++++++++++++++++++++++
 libavutil/encryption_info.h | 121 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 273 insertions(+)
 create mode 100644 libavutil/encryption_info.c
 create mode 100644 libavutil/encryption_info.h

diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index c13deb599f..e766f21ca0 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -1341,6 +1341,19 @@  enum AVPacketSideDataType {
      */
     AV_PKT_DATA_A53_CC,
 
+    /**
+     * This side data is encryption "initialization data".
+     * For MP4 this is the entire 'pssh' box.
+     * For WebM this is the key ID.
+     */
+    AV_PKT_DATA_ENCRYPTION_INIT_DATA,
+
+    /**
+     * This side data contains encryption info for how to decrypt the packet.
+     * The format is not part of ABI, use av_encryption_info_* methods to access.
+     */
+    AV_PKT_DATA_ENCRYPTION_INFO,
+
     /**
      * The number of side data types.
      * This is not part of the public API/ABI in the sense that it may
diff --git a/libavutil/Makefile b/libavutil/Makefile
index 66b894d66e..fed936df7b 100644
--- a/libavutil/Makefile
+++ b/libavutil/Makefile
@@ -24,6 +24,7 @@  HEADERS = adler32.h                                                     \
           dict.h                                                        \
           display.h                                                     \
           downmix_info.h                                                \
+          encryption_info.h                                             \
           error.h                                                       \
           eval.h                                                        \
           fifo.h                                                        \
@@ -107,6 +108,7 @@  OBJS = adler32.o                                                        \
        dict.o                                                           \
        display.o                                                        \
        downmix_info.o                                                   \
+       encryption_info.o                                                \
        error.o                                                          \
        eval.o                                                           \
        fifo.o                                                           \
diff --git a/libavutil/encryption_info.c b/libavutil/encryption_info.c
new file mode 100644
index 0000000000..76796b50ee
--- /dev/null
+++ b/libavutil/encryption_info.c
@@ -0,0 +1,137 @@ 
+/**
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "encryption_info.h"
+#include "libavutil/intreadwrite.h"
+
+#define FF_ENCRYPTION_INFO_EXTRA 24
+
+// The format of the side data:
+// u32be scheme
+// u32be crypt_byte_block
+// u32be skip_byte_block
+// u32be key_id_size
+// u32be iv_size
+// u32be subsample_count
+// u8[key_id_size] key_id
+// u8[iv_size] iv
+// {
+//   u32be bytes_of_clear_data
+//   u32be bytes_of_protected_data
+// }[subsample_count]
+
+AVEncryptionInfo *av_encryption_info_alloc(uint32_t subsample_count, uint32_t key_id_size, uint32_t iv_size)
+{
+    AVEncryptionInfo *info;
+
+    info = av_mallocz(sizeof(AVEncryptionInfo));
+    if (!info)
+        return NULL;
+
+    info->key_id = av_mallocz(key_id_size);
+    info->key_id_size = key_id_size;
+    info->iv = av_mallocz(iv_size);
+    info->iv_size = iv_size;
+    info->subsamples = av_mallocz_array(sizeof(AVSubsampleEncryptionInfo), subsample_count);
+    info->subsample_count = subsample_count;
+
+    // Allow info->subsamples to be NULL if there are no subsamples.
+    if (!info->key_id || !info->iv || (!info->subsamples && subsample_count)) {
+        av_encryption_info_free(info);
+        return NULL;
+    }
+
+    return info;
+}
+
+void av_encryption_info_free(AVEncryptionInfo *info)
+{
+    if (info) {
+        av_free(info->key_id);
+        av_free(info->iv);
+        av_free(info->subsamples);
+        av_free(info);
+    }
+}
+
+AVEncryptionInfo *av_encryption_info_get_side_data(const AVPacket *packet)
+{
+    AVEncryptionInfo *info;
+    uint8_t *buffer;
+    unsigned int size;
+    uint32_t key_id_size, iv_size, subsample_count, i;
+
+    buffer = av_packet_get_side_data(packet, AV_PKT_DATA_ENCRYPTION_INFO, &size);
+    if (!buffer)
+        return NULL;
+
+    key_id_size = AV_RB32(buffer + 12);
+    iv_size = AV_RB32(buffer + 16);
+    subsample_count = AV_RB32(buffer + 20);
+
+    info = av_encryption_info_alloc(subsample_count, key_id_size, iv_size);
+    if (!info)
+        return NULL;
+
+    info->scheme = AV_RB32(buffer);
+    info->crypt_byte_block = AV_RB32(buffer + 4);
+    info->skip_byte_block = AV_RB32(buffer + 8);
+    memcpy(info->key_id, buffer + 24, key_id_size);
+    memcpy(info->iv, buffer + key_id_size + 24, iv_size);
+
+    buffer += key_id_size + iv_size + 24;
+    for (i = 0; i < subsample_count; i++) {
+        info->subsamples[i].bytes_of_clear_data = AV_RB32(buffer);
+        info->subsamples[i].bytes_of_protected_data = AV_RB32(buffer + 4);
+        buffer += 8;
+    }
+
+    return info;
+}
+
+int av_encryption_info_add_side_data(AVPacket *packet, const AVEncryptionInfo *info)
+{
+    uint8_t *buffer;
+    size_t size;
+    uint32_t i;
+
+    size = FF_ENCRYPTION_INFO_EXTRA + info->key_id_size + info->iv_size +
+           (sizeof(AVSubsampleEncryptionInfo) * info->subsample_count);
+    buffer = av_packet_new_side_data(packet, AV_PKT_DATA_ENCRYPTION_INFO, size);
+    if (!buffer)
+        return AVERROR(ENOMEM);
+
+    AV_WB32(buffer,      info->scheme);
+    AV_WB32(buffer +  4, info->crypt_byte_block);
+    AV_WB32(buffer +  8, info->skip_byte_block);
+    AV_WB32(buffer + 12, info->key_id_size);
+    AV_WB32(buffer + 16, info->iv_size);
+    AV_WB32(buffer + 20, info->subsample_count);
+    buffer += 24;
+    memcpy(buffer, info->key_id, info->key_id_size);
+    buffer += info->key_id_size;
+    memcpy(buffer, info->iv, info->iv_size);
+    buffer += info->iv_size;
+    for (i = 0; i < info->subsample_count; i++) {
+        AV_WB32(buffer, info->subsamples[i].bytes_of_clear_data);
+        AV_WB32(buffer + 4, info->subsamples[i].bytes_of_protected_data);
+        buffer += 8;
+    }
+
+    return 0;
+}
diff --git a/libavutil/encryption_info.h b/libavutil/encryption_info.h
new file mode 100644
index 0000000000..6c2eee80f6
--- /dev/null
+++ b/libavutil/encryption_info.h
@@ -0,0 +1,121 @@ 
+/**
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVUTIL_ENCRYPTION_INFO_H
+#define AVUTIL_ENCRYPTION_INFO_H
+
+#include "libavcodec/avcodec.h"
+
+typedef struct AVSubsampleEncryptionInfo {
+    /** The number of bytes that are clear. */
+    unsigned int bytes_of_clear_data;
+
+    /**
+     * The number of bytes that are protected.  If using pattern encryption,
+     * the pattern applies to only the protected bytes; if not using pattern
+     * encryption, all these bytes are encrypted.
+     */
+    unsigned int bytes_of_protected_data;
+} AVSubsampleEncryptionInfo;
+
+/**
+ * This describes encryption info for a packet.  This contains frame-specific
+ * info for how to decrypt the packet before passing it to the decoder.
+ *
+ * The size of this struct is not part of the public ABI.
+ */
+typedef struct AVEncryptionInfo {
+    /** The fourcc encryption scheme. */
+    uint32_t scheme;
+
+    /**
+     * Only used for pattern encryption.  This is the number of 16-byte blocks
+     * that are encrypted.
+     */
+    uint32_t crypt_byte_block;
+
+    /**
+     * Only used for pattern encryption.  This is the number of 16-byte blocks
+     * that are clear.
+     */
+    uint32_t skip_byte_block;
+
+    /**
+     * The ID of the key used to encrypt the packet.  This should always be
+     * 16 bytes long, but may be changed in the future.
+     */
+    uint8_t *key_id;
+    uint32_t key_id_size;
+
+    /**
+     * The initialization vector.  This may have been zero-filled to be the
+     * correct block size.  This should always be 16 bytes long, but may be
+     * changed in the future.
+     */
+    uint8_t *iv;
+    uint32_t iv_size;
+
+    /**
+     * An array of subsample encryption info specifying how parts of the sample
+     * are encrypted.  If there are no subsamples, then the whole sample is
+     * encrypted.
+     */
+    AVSubsampleEncryptionInfo *subsamples;
+    uint32_t subsample_count;
+} AVEncryptionInfo;
+
+/**
+ * Allocates an AVEncryptionInfo structure and sub-pointers to hold the given
+ * number of subsamples.  This will allocate pointers for the key ID, IV,
+ * and subsample entries, set the size members, and zero-initialize the rest.
+ *
+ * @param subsample_count The number of subsamples.
+ * @param key_id_size The number of bytes in the key ID, should be 16.
+ * @param key_id_size The number of bytes in the IV, should be 16.
+ *
+ * @return The new AVEncryptionInfo structure, or NULL on error.
+ */
+AVEncryptionInfo *av_encryption_info_alloc(uint32_t subsample_count, uint32_t key_id_size, uint32_t iv_size);
+
+/**
+ * Frees the given encryption info object.  This MUST NOT be used to free the
+ * side-data data pointer, that should use normal side-data methods.
+ */
+void av_encryption_info_free(AVEncryptionInfo *info);
+
+/**
+ * Creates a copy of the AVEncryptionInfo that is contained in the side data of
+ * the given packet.  The resulting object should be passed to
+ * av_encryption_info_free() when done.
+ *
+ * This returns NULL if there is a memory error or if the packet isn't encrypted.
+ * To detect if the packet is encrypted, use av_packet_get_side_data.
+ *
+ * @return The new AVEncryptionInfo structure, or NULL on error.
+ */
+AVEncryptionInfo *av_encryption_info_get_side_data(const AVPacket *packet);
+
+/**
+ * Adds a new side data to the given packet that holds a copy of the given
+ * encryption info.
+ *
+ * @return 0 on success, or a negative error code on error.
+ */
+int av_encryption_info_add_side_data(AVPacket *packet, const AVEncryptionInfo *info);
+
+#endif /* AVUTIL_ENCRYPTION_INFO_H */
-- 
2.16.0.rc0.223.g4a4ac83678-goog