== FFMPEG ==

This fixes a memory leak caused by the last packet on stream EOF not freed.
(Memory leak occurs on ffmpeg heap managed by av_malloc / av_free, so it is
invisible to Blender)

Also: clean up the code a little bit (anim->next_packet was never really used,
so could be moved into a local variable)
This commit is contained in:
2012-12-02 15:15:44 +00:00
parent d7960b8fd4
commit ecf89326e1
3 changed files with 30 additions and 39 deletions

View File

@@ -178,7 +178,6 @@ struct anim {
struct ImBuf *last_frame;
int64_t last_pts;
int64_t next_pts;
AVPacket next_packet;
#endif
#ifdef WITH_REDCODE

View File

@@ -557,7 +557,6 @@ static int startffmpeg(struct anim *anim)
anim->last_frame = 0;
anim->last_pts = -1;
anim->next_pts = -1;
anim->next_packet.stream_index = -1;
anim->pFormatCtx = pFormatCtx;
anim->pCodecCtx = pCodecCtx;
@@ -764,41 +763,39 @@ static void ffmpeg_postprocess(struct anim *anim)
}
}
/* decode one video frame also considering the packet read into next_packet */
/* decode one video frame */
static int ffmpeg_decode_video_frame(struct anim *anim)
{
int rval = 0;
AVPacket next_packet;
memset(&next_packet, 0, sizeof(AVPacket));
av_log(anim->pFormatCtx, AV_LOG_DEBUG, " DECODE VIDEO FRAME\n");
if (anim->next_packet.stream_index == anim->videoStream) {
av_free_packet(&anim->next_packet);
anim->next_packet.stream_index = -1;
}
while ((rval = av_read_frame(anim->pFormatCtx, &anim->next_packet)) >= 0) {
while ((rval = av_read_frame(anim->pFormatCtx, &next_packet)) >= 0) {
av_log(anim->pFormatCtx,
AV_LOG_DEBUG,
"%sREAD: strID=%d (VID: %d) dts=%lld pts=%lld "
"%s\n",
(anim->next_packet.stream_index == anim->videoStream)
(next_packet.stream_index == anim->videoStream)
? "->" : " ",
anim->next_packet.stream_index,
next_packet.stream_index,
anim->videoStream,
(anim->next_packet.dts == AV_NOPTS_VALUE) ? -1 :
(long long int)anim->next_packet.dts,
(anim->next_packet.pts == AV_NOPTS_VALUE) ? -1 :
(long long int)anim->next_packet.pts,
(anim->next_packet.flags & AV_PKT_FLAG_KEY) ?
(next_packet.dts == AV_NOPTS_VALUE) ? -1 :
(long long int)next_packet.dts,
(next_packet.pts == AV_NOPTS_VALUE) ? -1 :
(long long int)next_packet.pts,
(next_packet.flags & AV_PKT_FLAG_KEY) ?
" KEY" : "");
if (anim->next_packet.stream_index == anim->videoStream) {
if (next_packet.stream_index == anim->videoStream) {
anim->pFrameComplete = 0;
avcodec_decode_video2(
anim->pCodecCtx,
anim->pFrame, &anim->pFrameComplete,
&anim->next_packet);
&next_packet);
if (anim->pFrameComplete) {
anim->next_pts = av_get_pts_from_frame(
@@ -816,20 +813,24 @@ static int ffmpeg_decode_video_frame(struct anim *anim)
break;
}
}
av_free_packet(&anim->next_packet);
anim->next_packet.stream_index = -1;
av_free_packet(&next_packet);
}
/* this sets size and data fields to zero,
which is necessary to decode the remaining data
in the decoder engine after EOF. It also prevents a memory
leak, since av_read_frame spills out a full size packet even
on EOF... (and: it's save to call on NULL packets) */
av_free_packet(&next_packet);
if (rval == AVERROR_EOF) {
anim->next_packet.size = 0;
anim->next_packet.data = 0;
anim->pFrameComplete = 0;
avcodec_decode_video2(
anim->pCodecCtx,
anim->pFrame, &anim->pFrameComplete,
&anim->next_packet);
&next_packet);
if (anim->pFrameComplete) {
anim->next_pts = av_get_pts_from_frame(
@@ -849,8 +850,6 @@ static int ffmpeg_decode_video_frame(struct anim *anim)
}
if (rval < 0) {
anim->next_packet.stream_index = -1;
av_log(anim->pFormatCtx,
AV_LOG_ERROR, " DECODE READ FAILED: av_read_frame() "
"returned error: %d\n", rval);
@@ -1087,13 +1086,6 @@ static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position,
anim->next_pts = -1;
if (anim->next_packet.stream_index == anim->videoStream) {
av_free_packet(&anim->next_packet);
anim->next_packet.stream_index = -1;
}
/* memset(anim->pFrame, ...) ?? */
if (ret >= 0) {
ffmpeg_decode_video_frame_scan(anim, pts_to_search);
}
@@ -1140,9 +1132,6 @@ static void free_anim_ffmpeg(struct anim *anim)
av_free(anim->pFrameDeinterlaced);
sws_freeContext(anim->img_convert_ctx);
IMB_freeImBuf(anim->last_frame);
if (anim->next_packet.stream_index != -1) {
av_free_packet(&anim->next_packet);
}
}
anim->duration = 0;
}

View File

@@ -912,6 +912,8 @@ static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context,
AVPacket next_packet;
uint64_t stream_size;
memset(&next_packet, 0, sizeof(AVPacket));
in_frame = avcodec_alloc_frame();
stream_size = avio_size(context->iFormatCtx->pb);
@@ -959,12 +961,13 @@ static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context,
* according to ffmpeg docs using 0-size packets.
*
* At least, if we haven't already stopped... */
/* this creates the 0-size packet and prevents a memory leak. */
av_free_packet(&next_packet);
if (!*stop) {
int frame_finished;
next_packet.size = 0;
next_packet.data = 0;
do {
frame_finished = 0;