diff options
author | Sergey Sharybin <sergey.vfx@gmail.com> | 2012-12-07 01:08:24 +0400 |
---|---|---|
committer | Sergey Sharybin <sergey.vfx@gmail.com> | 2012-12-07 01:08:24 +0400 |
commit | 759e96164a8d3f0f3f5606ab5f4801859899dd50 (patch) | |
tree | a35135f1f72b9ef401f8d47a3be2aad7a5bb05bd | |
parent | 77efd71cf8df00cc0fa8f4512c23614fba4fa3ba (diff) |
Fix #33433: Importing video files into movie clip editor crashes Blender
This was a regression in svn rev52718 caused by the fact that we can not
free packet fun until we've finished all manipulation with decoded frame
since frame and packet could share same pointers.
For now restored old behavior of next_packet which seems to be well
tested and better not do bigger refactoring here so close to release.
Memory leak fixed by that revision was fixed by calling av_free_packet
just before avcodec_decode_video2 in cases we're at the end of file.
Tested with valgrind and could not see any memory leaks in ffmpeg
area.
-rw-r--r-- | source/blender/imbuf/intern/IMB_anim.h | 1 | ||||
-rw-r--r-- | source/blender/imbuf/intern/anim_movie.c | 67 |
2 files changed, 44 insertions, 24 deletions
diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h index 684a1476e44..ed349e8f7eb 100644 --- a/source/blender/imbuf/intern/IMB_anim.h +++ b/source/blender/imbuf/intern/IMB_anim.h @@ -178,6 +178,7 @@ struct anim { struct ImBuf *last_frame; int64_t last_pts; int64_t next_pts; + AVPacket next_packet; #endif #ifdef WITH_REDCODE diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index 900ad6c6313..8dfdbd4fddc 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -557,6 +557,7 @@ 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; @@ -763,39 +764,41 @@ static void ffmpeg_postprocess(struct anim *anim) } } -/* decode one video frame */ +/* decode one video frame also considering the packet read into next_packet */ 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"); - while ((rval = av_read_frame(anim->pFormatCtx, &next_packet)) >= 0) { + 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) { av_log(anim->pFormatCtx, AV_LOG_DEBUG, "%sREAD: strID=%d (VID: %d) dts=%lld pts=%lld " "%s\n", - (next_packet.stream_index == anim->videoStream) + (anim->next_packet.stream_index == anim->videoStream) ? "->" : " ", - next_packet.stream_index, + anim->next_packet.stream_index, anim->videoStream, - (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) ? + (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) ? " KEY" : ""); - if (next_packet.stream_index == anim->videoStream) { + if (anim->next_packet.stream_index == anim->videoStream) { anim->pFrameComplete = 0; avcodec_decode_video2( anim->pCodecCtx, anim->pFrame, &anim->pFrameComplete, - &next_packet); + &anim->next_packet); if (anim->pFrameComplete) { anim->next_pts = av_get_pts_from_frame( @@ -813,24 +816,28 @@ static int ffmpeg_decode_video_frame(struct anim *anim) break; } } - av_free_packet(&next_packet); + av_free_packet(&anim->next_packet); + anim->next_packet.stream_index = -1; } - - /* 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) { + /* 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(&anim->next_packet); + + anim->next_packet.size = 0; + anim->next_packet.data = 0; + anim->pFrameComplete = 0; avcodec_decode_video2( anim->pCodecCtx, anim->pFrame, &anim->pFrameComplete, - &next_packet); + &anim->next_packet); if (anim->pFrameComplete) { anim->next_pts = av_get_pts_from_frame( @@ -850,6 +857,8 @@ 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); @@ -1086,6 +1095,13 @@ 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); } @@ -1132,6 +1148,9 @@ 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; } |