diff mbox

[FFmpeg-devel,1/4] avcodec/avpacket: add av_packet_copy_side_data()

Message ID 20170925010612.9824-1-jamrial@gmail.com
State New
Headers show

Commit Message

James Almer Sept. 25, 2017, 1:06 a.m. UTC
It's added as a replacemet of av_copy_packet_side_data() using the proper
av_packet_* namespace, and differs from it in the following ways:

- Side data already allocated and copied is properly freed in case of failure.
- The dst packet is unchanged in case of failure instead of being unreffed.

Signed-off-by: James Almer <jamrial@gmail.com>
---
 doc/APIchanges        |  3 +++
 libavcodec/avcodec.h  | 16 ++++++++++++++++
 libavcodec/avpacket.c | 41 +++++++++++++++++++++++++++++++++++++++++
 libavcodec/version.h  |  4 ++--
 4 files changed, 62 insertions(+), 2 deletions(-)

Comments

wm4 Sept. 25, 2017, 9:50 a.m. UTC | #1
On Sun, 24 Sep 2017 22:06:09 -0300
James Almer <jamrial@gmail.com> wrote:

> It's added as a replacemet of av_copy_packet_side_data() using the proper
> av_packet_* namespace, and differs from it in the following ways:
> 
> - Side data already allocated and copied is properly freed in case of failure.
> - The dst packet is unchanged in case of failure instead of being unreffed.
> 
> Signed-off-by: James Almer <jamrial@gmail.com>
> ---
>  doc/APIchanges        |  3 +++
>  libavcodec/avcodec.h  | 16 ++++++++++++++++
>  libavcodec/avpacket.c | 41 +++++++++++++++++++++++++++++++++++++++++
>  libavcodec/version.h  |  4 ++--
>  4 files changed, 62 insertions(+), 2 deletions(-)
> 
> diff --git a/doc/APIchanges b/doc/APIchanges
> index d06144f1e9..2d3f470186 100644
> --- a/doc/APIchanges
> +++ b/doc/APIchanges
> @@ -15,6 +15,9 @@ libavutil:     2015-08-28
>  
>  API changes, most recent first:
>  
> +2017-09-xx - xxxxxxx - lavc 57.107.100 - avcodec.h
> +  Add av_packet_copy_side_data().
> +
>  2017-xx-xx - xxxxxxx - lavu 55.76.100 / 56.6.0 - pixdesc.h
>    Add av_color_range_from_name(), av_color_primaries_from_name(),
>    av_color_transfer_from_name(), av_color_space_from_name(), and
> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
> index 07d9f3e255..655e6abbde 100644
> --- a/libavcodec/avcodec.h
> +++ b/libavcodec/avcodec.h
> @@ -4624,7 +4624,10 @@ int av_copy_packet(AVPacket *dst, const AVPacket *src);
>   * Copy packet side data
>   *
>   * @return 0 on success, negative AVERROR on fail
> + *
> + * @deprecated Use av_packet_copy_side_data
>   */
> +attribute_deprecated
>  int av_copy_packet_side_data(AVPacket *dst, const AVPacket *src);
>  
>  /**
> @@ -4664,6 +4667,19 @@ uint8_t* av_packet_new_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
>  int av_packet_add_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
>                              uint8_t *data, size_t size);
>  
> +/**
> + * Copy packet side data from src to dst.
> + *
> + * @see av_packet_copy_props
> + * @see av_packet_free_side_data
> + *
> + * @param dst Destination packet
> + * @param src Source packet
> + *
> + * @return 0 on success, a negative AVERROR on error. On failure, dst is unchanged.
> + */
> +int av_packet_copy_side_data(AVPacket *dst, const AVPacket *src);
> +
>  /**
>   * Shrink the already allocated side data buffer
>   *
> diff --git a/libavcodec/avpacket.c b/libavcodec/avpacket.c
> index b07180eac8..33e325c9ed 100644
> --- a/libavcodec/avpacket.c
> +++ b/libavcodec/avpacket.c
> @@ -582,6 +582,47 @@ int av_packet_shrink_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
>      return AVERROR(ENOENT);
>  }
>  
> +int av_packet_copy_side_data(AVPacket *dst, const AVPacket *src)
> +{
> +    AVPacketSideData *side_data;
> +    int i, side_data_elems = 0;
> +
> +    if (!src->side_data_elems)
> +        return 0;
> +
> +    side_data = av_malloc_array(src->side_data_elems, sizeof(*src->side_data));
> +    if (!side_data)
> +        return AVERROR(ENOMEM);
> +
> +    for (i = 0; i < src->side_data_elems; i++) {
> +        AVPacketSideData *sd_src = &src->side_data[i];
> +        AVPacketSideData *sd_dst = &side_data[i];
> +
> +        if ((unsigned)sd_src->size > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE)
> +            goto fail;
> +
> +        sd_dst->data = av_mallocz(sd_src->size + AV_INPUT_BUFFER_PADDING_SIZE);
> +        if (!sd_dst->data)
> +            goto fail;
> +
> +        memcpy(sd_dst->data, sd_src->data, sd_src->size);
> +        sd_dst->size = sd_src->size;
> +        sd_dst->type = sd_src->type;
> +        side_data_elems++;
> +    }
> +    dst->side_data = side_data;
> +    dst->side_data_elems = side_data_elems;
> +
> +    return 0;
> +
> +fail:
> +    for (i = 0; i < side_data_elems; i++)
> +        av_free(side_data[i].data);
> +    av_free(side_data);
> +
> +    return AVERROR(ENOMEM);;
> +}
> +
>  int av_packet_copy_props(AVPacket *dst, const AVPacket *src)
>  {
>      int i;
> diff --git a/libavcodec/version.h b/libavcodec/version.h
> index e1224752bd..10d9ac4eb3 100644
> --- a/libavcodec/version.h
> +++ b/libavcodec/version.h
> @@ -28,8 +28,8 @@
>  #include "libavutil/version.h"
>  
>  #define LIBAVCODEC_VERSION_MAJOR  57
> -#define LIBAVCODEC_VERSION_MINOR 106
> -#define LIBAVCODEC_VERSION_MICRO 101
> +#define LIBAVCODEC_VERSION_MINOR 107
> +#define LIBAVCODEC_VERSION_MICRO 100
>  
>  #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
>                                                 LIBAVCODEC_VERSION_MINOR, \

Using av_packet_copy_props() instead of introducing yet another weird
function would be better.
James Almer Sept. 25, 2017, 1:58 p.m. UTC | #2
On 9/25/2017 6:50 AM, wm4 wrote:
> On Sun, 24 Sep 2017 22:06:09 -0300
> James Almer <jamrial@gmail.com> wrote:
> 
>> It's added as a replacemet of av_copy_packet_side_data() using the proper
>> av_packet_* namespace, and differs from it in the following ways:
>>
>> - Side data already allocated and copied is properly freed in case of failure.
>> - The dst packet is unchanged in case of failure instead of being unreffed.
>>
>> Signed-off-by: James Almer <jamrial@gmail.com>
>> ---
>>  doc/APIchanges        |  3 +++
>>  libavcodec/avcodec.h  | 16 ++++++++++++++++
>>  libavcodec/avpacket.c | 41 +++++++++++++++++++++++++++++++++++++++++
>>  libavcodec/version.h  |  4 ++--
>>  4 files changed, 62 insertions(+), 2 deletions(-)
>>
>> diff --git a/doc/APIchanges b/doc/APIchanges
>> index d06144f1e9..2d3f470186 100644
>> --- a/doc/APIchanges
>> +++ b/doc/APIchanges
>> @@ -15,6 +15,9 @@ libavutil:     2015-08-28
>>  
>>  API changes, most recent first:
>>  
>> +2017-09-xx - xxxxxxx - lavc 57.107.100 - avcodec.h
>> +  Add av_packet_copy_side_data().
>> +
>>  2017-xx-xx - xxxxxxx - lavu 55.76.100 / 56.6.0 - pixdesc.h
>>    Add av_color_range_from_name(), av_color_primaries_from_name(),
>>    av_color_transfer_from_name(), av_color_space_from_name(), and
>> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
>> index 07d9f3e255..655e6abbde 100644
>> --- a/libavcodec/avcodec.h
>> +++ b/libavcodec/avcodec.h
>> @@ -4624,7 +4624,10 @@ int av_copy_packet(AVPacket *dst, const AVPacket *src);
>>   * Copy packet side data
>>   *
>>   * @return 0 on success, negative AVERROR on fail
>> + *
>> + * @deprecated Use av_packet_copy_side_data
>>   */
>> +attribute_deprecated
>>  int av_copy_packet_side_data(AVPacket *dst, const AVPacket *src);
>>  
>>  /**
>> @@ -4664,6 +4667,19 @@ uint8_t* av_packet_new_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
>>  int av_packet_add_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
>>                              uint8_t *data, size_t size);
>>  
>> +/**
>> + * Copy packet side data from src to dst.
>> + *
>> + * @see av_packet_copy_props
>> + * @see av_packet_free_side_data
>> + *
>> + * @param dst Destination packet
>> + * @param src Source packet
>> + *
>> + * @return 0 on success, a negative AVERROR on error. On failure, dst is unchanged.
>> + */
>> +int av_packet_copy_side_data(AVPacket *dst, const AVPacket *src);
>> +
>>  /**
>>   * Shrink the already allocated side data buffer
>>   *
>> diff --git a/libavcodec/avpacket.c b/libavcodec/avpacket.c
>> index b07180eac8..33e325c9ed 100644
>> --- a/libavcodec/avpacket.c
>> +++ b/libavcodec/avpacket.c
>> @@ -582,6 +582,47 @@ int av_packet_shrink_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
>>      return AVERROR(ENOENT);
>>  }
>>  
>> +int av_packet_copy_side_data(AVPacket *dst, const AVPacket *src)
>> +{
>> +    AVPacketSideData *side_data;
>> +    int i, side_data_elems = 0;
>> +
>> +    if (!src->side_data_elems)
>> +        return 0;
>> +
>> +    side_data = av_malloc_array(src->side_data_elems, sizeof(*src->side_data));
>> +    if (!side_data)
>> +        return AVERROR(ENOMEM);
>> +
>> +    for (i = 0; i < src->side_data_elems; i++) {
>> +        AVPacketSideData *sd_src = &src->side_data[i];
>> +        AVPacketSideData *sd_dst = &side_data[i];
>> +
>> +        if ((unsigned)sd_src->size > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE)
>> +            goto fail;
>> +
>> +        sd_dst->data = av_mallocz(sd_src->size + AV_INPUT_BUFFER_PADDING_SIZE);
>> +        if (!sd_dst->data)
>> +            goto fail;
>> +
>> +        memcpy(sd_dst->data, sd_src->data, sd_src->size);
>> +        sd_dst->size = sd_src->size;
>> +        sd_dst->type = sd_src->type;
>> +        side_data_elems++;
>> +    }
>> +    dst->side_data = side_data;
>> +    dst->side_data_elems = side_data_elems;
>> +
>> +    return 0;
>> +
>> +fail:
>> +    for (i = 0; i < side_data_elems; i++)
>> +        av_free(side_data[i].data);
>> +    av_free(side_data);
>> +
>> +    return AVERROR(ENOMEM);;
>> +}
>> +
>>  int av_packet_copy_props(AVPacket *dst, const AVPacket *src)
>>  {
>>      int i;
>> diff --git a/libavcodec/version.h b/libavcodec/version.h
>> index e1224752bd..10d9ac4eb3 100644
>> --- a/libavcodec/version.h
>> +++ b/libavcodec/version.h
>> @@ -28,8 +28,8 @@
>>  #include "libavutil/version.h"
>>  
>>  #define LIBAVCODEC_VERSION_MAJOR  57
>> -#define LIBAVCODEC_VERSION_MINOR 106
>> -#define LIBAVCODEC_VERSION_MICRO 101
>> +#define LIBAVCODEC_VERSION_MINOR 107
>> +#define LIBAVCODEC_VERSION_MICRO 100
>>  
>>  #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
>>                                                 LIBAVCODEC_VERSION_MINOR, \
> 
> Using av_packet_copy_props() instead of introducing yet another weird
> function would be better.

It can't be used in some cases. Look at the last two patches in the set.
copy_props can't be used there without some extra pointless work.
This functionality is only part of what copy_props does. I'm simply
splitting it out from it.
wm4 Sept. 25, 2017, 4:43 p.m. UTC | #3
On Mon, 25 Sep 2017 10:58:31 -0300
James Almer <jamrial@gmail.com> wrote:

> > Using av_packet_copy_props() instead of introducing yet another weird
> > function would be better.  
> 
> It can't be used in some cases. Look at the last two patches in the set.
> copy_props can't be used there without some extra pointless work.

Well, you need to copy the props first, before you write any fields
that are touched by the function. But that's true for the various side
data types too. What if you want to copy a specific set of side data
values, but not others? You could add arbitrary permutations of this,
one for every use case you could think of.
James Almer Sept. 25, 2017, 5:07 p.m. UTC | #4
On 9/25/2017 1:43 PM, wm4 wrote:
> On Mon, 25 Sep 2017 10:58:31 -0300
> James Almer <jamrial@gmail.com> wrote:
> 
>>> Using av_packet_copy_props() instead of introducing yet another weird
>>> function would be better.  
>>
>> It can't be used in some cases. Look at the last two patches in the set.
>> copy_props can't be used there without some extra pointless work.
> 
> Well, you need to copy the props first, before you write any fields
> that are touched by the function.

How so? The function only looks at side_data and side_data_size from a
const src packet, then writes those same two fields to the dst packet
if copying was successful. av_packet_free_side_data() also only cares
about those two fields.

I don't know why whoever wrote the code in ffmpeg.c and movenc.c didn't
use copy_props(), but a quick read hints they didn't want to copy any
other property except side data, apparently as it would break whatever
pts/duration calculations they were doing with their tmp packets.
They evidently added av_copy_packet_side_data() for a reason, and
replacing it with a saner, correctly named and less leaky/destructive
equivalent function is the entire point of this patch.

> But that's true for the various side
> data types too. What if you want to copy a specific set of side data
> values, but not others? You could add arbitrary permutations of this,
> one for every use case you could think of.

That's outside of the scope of generic convenience functions like all
these copy-every-whatever and free-every-whatever. You're supposed to
use get_side_data() to find specific elements of your choice.
wm4 Sept. 25, 2017, 5:29 p.m. UTC | #5
On Mon, 25 Sep 2017 14:07:54 -0300
James Almer <jamrial@gmail.com> wrote:

> On 9/25/2017 1:43 PM, wm4 wrote:
> > On Mon, 25 Sep 2017 10:58:31 -0300
> > James Almer <jamrial@gmail.com> wrote:
> >   
> >>> Using av_packet_copy_props() instead of introducing yet another weird
> >>> function would be better.    
> >>
> >> It can't be used in some cases. Look at the last two patches in the set.
> >> copy_props can't be used there without some extra pointless work.  
> > 
> > Well, you need to copy the props first, before you write any fields
> > that are touched by the function.  
> 
> How so? The function only looks at side_data and side_data_size from a
> const src packet, then writes those same two fields to the dst packet
> if copying was successful. av_packet_free_side_data() also only cares
> about those two fields.
> 
> I don't know why whoever wrote the code in ffmpeg.c and movenc.c didn't
> use copy_props(), but a quick read hints they didn't want to copy any
> other property except side data, apparently as it would break whatever
> pts/duration calculations they were doing with their tmp packets.

So, copy pts/duration after "copying" (ref-ing) the entire packet. I
have to do similar things in my code with AVFrame.
James Almer Sept. 25, 2017, 5:37 p.m. UTC | #6
On 9/25/2017 2:29 PM, wm4 wrote:
> On Mon, 25 Sep 2017 14:07:54 -0300
> James Almer <jamrial@gmail.com> wrote:
> 
>> On 9/25/2017 1:43 PM, wm4 wrote:
>>> On Mon, 25 Sep 2017 10:58:31 -0300
>>> James Almer <jamrial@gmail.com> wrote:
>>>   
>>>>> Using av_packet_copy_props() instead of introducing yet another weird
>>>>> function would be better.    
>>>>
>>>> It can't be used in some cases. Look at the last two patches in the set.
>>>> copy_props can't be used there without some extra pointless work.  
>>>
>>> Well, you need to copy the props first, before you write any fields
>>> that are touched by the function.  
>>
>> How so? The function only looks at side_data and side_data_size from a
>> const src packet, then writes those same two fields to the dst packet
>> if copying was successful. av_packet_free_side_data() also only cares
>> about those two fields.
>>
>> I don't know why whoever wrote the code in ffmpeg.c and movenc.c didn't
>> use copy_props(), but a quick read hints they didn't want to copy any
>> other property except side data, apparently as it would break whatever
>> pts/duration calculations they were doing with their tmp packets.
> 
> So, copy pts/duration after "copying" (ref-ing) the entire packet. I
> have to do similar things in my code with AVFrame.

ffmpeg.c in this case doesn't ref the packet. It inits it, writes some
fields based on (but without directly copying them from) the source
packet, then copies the side data.

If you really don't want functions this specific and are willing to fix
the two cases in ffmpeg.c and movenc.c to use copy_props then i can
repurpose this patchset to only deprecate the existing
av_copy_packet_side_data().
Keep in mind however that by deprecating and removing said function
without adding a direct replacement we'll probably be annoying existing
users of said function (Chromium is one it seems) by forcing them to
also work around the extra stuff copy_props() would do to their packets.
wm4 Sept. 25, 2017, 5:45 p.m. UTC | #7
On Mon, 25 Sep 2017 14:37:52 -0300
James Almer <jamrial@gmail.com> wrote:

> On 9/25/2017 2:29 PM, wm4 wrote:
> > On Mon, 25 Sep 2017 14:07:54 -0300
> > James Almer <jamrial@gmail.com> wrote:
> >   
> >> On 9/25/2017 1:43 PM, wm4 wrote:  
> >>> On Mon, 25 Sep 2017 10:58:31 -0300
> >>> James Almer <jamrial@gmail.com> wrote:
> >>>     
> >>>>> Using av_packet_copy_props() instead of introducing yet another weird
> >>>>> function would be better.      
> >>>>
> >>>> It can't be used in some cases. Look at the last two patches in the set.
> >>>> copy_props can't be used there without some extra pointless work.    
> >>>
> >>> Well, you need to copy the props first, before you write any fields
> >>> that are touched by the function.    
> >>
> >> How so? The function only looks at side_data and side_data_size from a
> >> const src packet, then writes those same two fields to the dst packet
> >> if copying was successful. av_packet_free_side_data() also only cares
> >> about those two fields.
> >>
> >> I don't know why whoever wrote the code in ffmpeg.c and movenc.c didn't
> >> use copy_props(), but a quick read hints they didn't want to copy any
> >> other property except side data, apparently as it would break whatever
> >> pts/duration calculations they were doing with their tmp packets.  
> > 
> > So, copy pts/duration after "copying" (ref-ing) the entire packet. I
> > have to do similar things in my code with AVFrame.  
> 
> ffmpeg.c in this case doesn't ref the packet. It inits it, writes some
> fields based on (but without directly copying them from) the source
> packet, then copies the side data.
> 
> If you really don't want functions this specific and are willing to fix
> the two cases in ffmpeg.c and movenc.c to use copy_props then i can
> repurpose this patchset to only deprecate the existing
> av_copy_packet_side_data().
> Keep in mind however that by deprecating and removing said function
> without adding a direct replacement we'll probably be annoying existing
> users of said function (Chromium is one it seems) by forcing them to
> also work around the extra stuff copy_props() would do to their packets.

What exactly is the trouble of just moving setting pts/duration below
the function call?

Also adding a function with very similar name and subtly different
semantics (whose differences aren't even explained) is a very bad idea.
James Almer Sept. 25, 2017, 5:51 p.m. UTC | #8
On 9/25/2017 2:45 PM, wm4 wrote:
> On Mon, 25 Sep 2017 14:37:52 -0300
> James Almer <jamrial@gmail.com> wrote:
> 
>> On 9/25/2017 2:29 PM, wm4 wrote:
>>> On Mon, 25 Sep 2017 14:07:54 -0300
>>> James Almer <jamrial@gmail.com> wrote:
>>>   
>>>> On 9/25/2017 1:43 PM, wm4 wrote:  
>>>>> On Mon, 25 Sep 2017 10:58:31 -0300
>>>>> James Almer <jamrial@gmail.com> wrote:
>>>>>     
>>>>>>> Using av_packet_copy_props() instead of introducing yet another weird
>>>>>>> function would be better.      
>>>>>>
>>>>>> It can't be used in some cases. Look at the last two patches in the set.
>>>>>> copy_props can't be used there without some extra pointless work.    
>>>>>
>>>>> Well, you need to copy the props first, before you write any fields
>>>>> that are touched by the function.    
>>>>
>>>> How so? The function only looks at side_data and side_data_size from a
>>>> const src packet, then writes those same two fields to the dst packet
>>>> if copying was successful. av_packet_free_side_data() also only cares
>>>> about those two fields.
>>>>
>>>> I don't know why whoever wrote the code in ffmpeg.c and movenc.c didn't
>>>> use copy_props(), but a quick read hints they didn't want to copy any
>>>> other property except side data, apparently as it would break whatever
>>>> pts/duration calculations they were doing with their tmp packets.  
>>>
>>> So, copy pts/duration after "copying" (ref-ing) the entire packet. I
>>> have to do similar things in my code with AVFrame.  
>>
>> ffmpeg.c in this case doesn't ref the packet. It inits it, writes some
>> fields based on (but without directly copying them from) the source
>> packet, then copies the side data.
>>
>> If you really don't want functions this specific and are willing to fix
>> the two cases in ffmpeg.c and movenc.c to use copy_props then i can
>> repurpose this patchset to only deprecate the existing
>> av_copy_packet_side_data().
>> Keep in mind however that by deprecating and removing said function
>> without adding a direct replacement we'll probably be annoying existing
>> users of said function (Chromium is one it seems) by forcing them to
>> also work around the extra stuff copy_props() would do to their packets.
> 
> What exactly is the trouble of just moving setting pts/duration below
> the function call?

Ask users of the existing function, not me who just wants to get rid of
it for being awful.

> 
> Also adding a function with very similar name and subtly different
> semantics (whose differences aren't even explained) is a very bad idea.

The differences are stated in both the commit message and the doxy:
There will be no leaks and no changes to the dst packet in case of
failure. Otherwise, it's functionally the same.

Again, do you want me to just deprecate the existing function without
adding a direct replacement? I'll do that. But please fix the two
existing uses before the deprecation period is over.
diff mbox

Patch

diff --git a/doc/APIchanges b/doc/APIchanges
index d06144f1e9..2d3f470186 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -15,6 +15,9 @@  libavutil:     2015-08-28
 
 API changes, most recent first:
 
+2017-09-xx - xxxxxxx - lavc 57.107.100 - avcodec.h
+  Add av_packet_copy_side_data().
+
 2017-xx-xx - xxxxxxx - lavu 55.76.100 / 56.6.0 - pixdesc.h
   Add av_color_range_from_name(), av_color_primaries_from_name(),
   av_color_transfer_from_name(), av_color_space_from_name(), and
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 07d9f3e255..655e6abbde 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -4624,7 +4624,10 @@  int av_copy_packet(AVPacket *dst, const AVPacket *src);
  * Copy packet side data
  *
  * @return 0 on success, negative AVERROR on fail
+ *
+ * @deprecated Use av_packet_copy_side_data
  */
+attribute_deprecated
 int av_copy_packet_side_data(AVPacket *dst, const AVPacket *src);
 
 /**
@@ -4664,6 +4667,19 @@  uint8_t* av_packet_new_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
 int av_packet_add_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
                             uint8_t *data, size_t size);
 
+/**
+ * Copy packet side data from src to dst.
+ *
+ * @see av_packet_copy_props
+ * @see av_packet_free_side_data
+ *
+ * @param dst Destination packet
+ * @param src Source packet
+ *
+ * @return 0 on success, a negative AVERROR on error. On failure, dst is unchanged.
+ */
+int av_packet_copy_side_data(AVPacket *dst, const AVPacket *src);
+
 /**
  * Shrink the already allocated side data buffer
  *
diff --git a/libavcodec/avpacket.c b/libavcodec/avpacket.c
index b07180eac8..33e325c9ed 100644
--- a/libavcodec/avpacket.c
+++ b/libavcodec/avpacket.c
@@ -582,6 +582,47 @@  int av_packet_shrink_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
     return AVERROR(ENOENT);
 }
 
+int av_packet_copy_side_data(AVPacket *dst, const AVPacket *src)
+{
+    AVPacketSideData *side_data;
+    int i, side_data_elems = 0;
+
+    if (!src->side_data_elems)
+        return 0;
+
+    side_data = av_malloc_array(src->side_data_elems, sizeof(*src->side_data));
+    if (!side_data)
+        return AVERROR(ENOMEM);
+
+    for (i = 0; i < src->side_data_elems; i++) {
+        AVPacketSideData *sd_src = &src->side_data[i];
+        AVPacketSideData *sd_dst = &side_data[i];
+
+        if ((unsigned)sd_src->size > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE)
+            goto fail;
+
+        sd_dst->data = av_mallocz(sd_src->size + AV_INPUT_BUFFER_PADDING_SIZE);
+        if (!sd_dst->data)
+            goto fail;
+
+        memcpy(sd_dst->data, sd_src->data, sd_src->size);
+        sd_dst->size = sd_src->size;
+        sd_dst->type = sd_src->type;
+        side_data_elems++;
+    }
+    dst->side_data = side_data;
+    dst->side_data_elems = side_data_elems;
+
+    return 0;
+
+fail:
+    for (i = 0; i < side_data_elems; i++)
+        av_free(side_data[i].data);
+    av_free(side_data);
+
+    return AVERROR(ENOMEM);;
+}
+
 int av_packet_copy_props(AVPacket *dst, const AVPacket *src)
 {
     int i;
diff --git a/libavcodec/version.h b/libavcodec/version.h
index e1224752bd..10d9ac4eb3 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -28,8 +28,8 @@ 
 #include "libavutil/version.h"
 
 #define LIBAVCODEC_VERSION_MAJOR  57
-#define LIBAVCODEC_VERSION_MINOR 106
-#define LIBAVCODEC_VERSION_MICRO 101
+#define LIBAVCODEC_VERSION_MINOR 107
+#define LIBAVCODEC_VERSION_MICRO 100
 
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
                                                LIBAVCODEC_VERSION_MINOR, \