Commit c4ba5198 authored by Reimar Döffinger's avatar Reimar Döffinger

Fix leaking of side data.

While we correctly "register" the side data when we split it,
the application (in this case FFmpeg) might not update the
AVPacket pool it uses to finally free the packet, thus
causing a leak.
This also makes the av_dup_packet unnecessary which could
cause an even worse leak in this situation.
Also change the code to not modify the user-provide AVPacket at all.
Signed-off-by: 's avatarReimar Döffinger <Reimar.Doeffinger@gmx.de>
parent 45c39e56
...@@ -4297,7 +4297,7 @@ int avcodec_decode_audio4(AVCodecContext *avctx, AVFrame *frame, ...@@ -4297,7 +4297,7 @@ int avcodec_decode_audio4(AVCodecContext *avctx, AVFrame *frame,
*/ */
int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture, int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture,
int *got_picture_ptr, int *got_picture_ptr,
AVPacket *avpkt); const AVPacket *avpkt);
/** /**
* Decode a subtitle message. * Decode a subtitle message.
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
*/ */
#include "avcodec.h" #include "avcodec.h"
#include "internal.h"
#include "libavutil/avassert.h" #include "libavutil/avassert.h"
#include "bytestream.h" #include "bytestream.h"
...@@ -30,19 +31,23 @@ void av_destruct_packet_nofree(AVPacket *pkt) ...@@ -30,19 +31,23 @@ void av_destruct_packet_nofree(AVPacket *pkt)
pkt->side_data_elems = 0; pkt->side_data_elems = 0;
} }
void av_destruct_packet(AVPacket *pkt) void ff_packet_free_side_data(AVPacket *pkt)
{ {
int i; int i;
av_free(pkt->data);
pkt->data = NULL; pkt->size = 0;
for (i = 0; i < pkt->side_data_elems; i++) for (i = 0; i < pkt->side_data_elems; i++)
av_free(pkt->side_data[i].data); av_free(pkt->side_data[i].data);
av_freep(&pkt->side_data); av_freep(&pkt->side_data);
pkt->side_data_elems = 0; pkt->side_data_elems = 0;
} }
void av_destruct_packet(AVPacket *pkt)
{
av_free(pkt->data);
pkt->data = NULL; pkt->size = 0;
ff_packet_free_side_data(pkt);
}
void av_init_packet(AVPacket *pkt) void av_init_packet(AVPacket *pkt)
{ {
pkt->pts = AV_NOPTS_VALUE; pkt->pts = AV_NOPTS_VALUE;
...@@ -239,8 +244,6 @@ int av_packet_split_side_data(AVPacket *pkt){ ...@@ -239,8 +244,6 @@ int av_packet_split_side_data(AVPacket *pkt){
unsigned int size; unsigned int size;
uint8_t *p; uint8_t *p;
av_dup_packet(pkt);
p = pkt->data + pkt->size - 8 - 5; p = pkt->data + pkt->size - 8 - 5;
for (i=1; ; i++){ for (i=1; ; i++){
size = AV_RB32(p); size = AV_RB32(p);
......
...@@ -96,6 +96,11 @@ unsigned int avpriv_toupper4(unsigned int x); ...@@ -96,6 +96,11 @@ unsigned int avpriv_toupper4(unsigned int x);
*/ */
void ff_init_buffer_info(AVCodecContext *s, AVFrame *pic); void ff_init_buffer_info(AVCodecContext *s, AVFrame *pic);
/**
* Remove and free all side data from packet.
*/
void ff_packet_free_side_data(AVPacket *pkt);
int avpriv_lock_avformat(void); int avpriv_lock_avformat(void);
int avpriv_unlock_avformat(void); int avpriv_unlock_avformat(void);
......
...@@ -994,24 +994,26 @@ static void apply_param_change(AVCodecContext *avctx, AVPacket *avpkt) ...@@ -994,24 +994,26 @@ static void apply_param_change(AVCodecContext *avctx, AVPacket *avpkt)
int attribute_align_arg avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture, int attribute_align_arg avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture,
int *got_picture_ptr, int *got_picture_ptr,
AVPacket *avpkt) const AVPacket *avpkt)
{ {
int ret; int ret;
// copy to ensure we do not change avpkt
AVPacket tmp = *avpkt;
*got_picture_ptr= 0; *got_picture_ptr= 0;
if((avctx->coded_width||avctx->coded_height) && av_image_check_size(avctx->coded_width, avctx->coded_height, 0, avctx)) if((avctx->coded_width||avctx->coded_height) && av_image_check_size(avctx->coded_width, avctx->coded_height, 0, avctx))
return -1; return -1;
if((avctx->codec->capabilities & CODEC_CAP_DELAY) || avpkt->size || (avctx->active_thread_type&FF_THREAD_FRAME)){ if((avctx->codec->capabilities & CODEC_CAP_DELAY) || avpkt->size || (avctx->active_thread_type&FF_THREAD_FRAME)){
av_packet_split_side_data(avpkt); int did_split = av_packet_split_side_data(&tmp);
apply_param_change(avctx, avpkt); apply_param_change(avctx, &tmp);
avctx->pkt = avpkt; avctx->pkt = &tmp;
if (HAVE_THREADS && avctx->active_thread_type&FF_THREAD_FRAME) if (HAVE_THREADS && avctx->active_thread_type&FF_THREAD_FRAME)
ret = ff_thread_decode_frame(avctx, picture, got_picture_ptr, ret = ff_thread_decode_frame(avctx, picture, got_picture_ptr,
avpkt); &tmp);
else { else {
ret = avctx->codec->decode(avctx, picture, got_picture_ptr, ret = avctx->codec->decode(avctx, picture, got_picture_ptr,
avpkt); &tmp);
picture->pkt_dts= avpkt->dts; picture->pkt_dts= avpkt->dts;
if(!avctx->has_b_frames){ if(!avctx->has_b_frames){
...@@ -1030,6 +1032,9 @@ int attribute_align_arg avcodec_decode_video2(AVCodecContext *avctx, AVFrame *pi ...@@ -1030,6 +1032,9 @@ int attribute_align_arg avcodec_decode_video2(AVCodecContext *avctx, AVFrame *pi
emms_c(); //needed to avoid an emms_c() call before every return; emms_c(); //needed to avoid an emms_c() call before every return;
avctx->pkt = NULL;
if (did_split)
ff_packet_free_side_data(&tmp);
if (*got_picture_ptr){ if (*got_picture_ptr){
avctx->frame_number++; avctx->frame_number++;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment