From 85cb742f79bf718f2086070f86f5dde6e2b1d504 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 28 Nov 2018 16:14:45 +0100 Subject: [PATCH] ffmpeg: drain avcodec contexts on close, fixes leak Fixes #398 --- panda/src/ffmpeg/ffmpegAudioCursor.cxx | 27 ++++++++++++++++---------- panda/src/ffmpeg/ffmpegVideoCursor.cxx | 9 ++++++++- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/panda/src/ffmpeg/ffmpegAudioCursor.cxx b/panda/src/ffmpeg/ffmpegAudioCursor.cxx index 809797fb85..4b17800c2b 100644 --- a/panda/src/ffmpeg/ffmpegAudioCursor.cxx +++ b/panda/src/ffmpeg/ffmpegAudioCursor.cxx @@ -210,6 +210,23 @@ FfmpegAudioCursor:: */ void FfmpegAudioCursor:: cleanup() { + if (_audio_ctx && _audio_ctx->codec) { +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 37, 100) + // We need to drain the codec to prevent a memory leak. + avcodec_send_packet(_audio_ctx, nullptr); + while (avcodec_receive_frame(_audio_ctx, _frame) == 0) {} + avcodec_flush_buffers(_audio_ctx); +#endif + + avcodec_close(_audio_ctx); +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 52, 0) + avcodec_free_context(&_audio_ctx); +#else + delete _audio_ctx; +#endif + } + _audio_ctx = nullptr; + if (_frame) { #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 45, 101) av_frame_free(&_frame); @@ -237,16 +254,6 @@ cleanup() { _buffer = nullptr; } - if ((_audio_ctx)&&(_audio_ctx->codec)) { - avcodec_close(_audio_ctx); -#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 52, 0) - avcodec_free_context(&_audio_ctx); -#else - delete _audio_ctx; -#endif - } - _audio_ctx = nullptr; - if (_format_ctx) { _ffvfile.close(); _format_ctx = nullptr; diff --git a/panda/src/ffmpeg/ffmpegVideoCursor.cxx b/panda/src/ffmpeg/ffmpegVideoCursor.cxx index 47c6a54ae2..ef23a9414e 100644 --- a/panda/src/ffmpeg/ffmpegVideoCursor.cxx +++ b/panda/src/ffmpeg/ffmpegVideoCursor.cxx @@ -595,7 +595,14 @@ close_stream() { // Hold the global lock while we free avcodec objects. ReMutexHolder av_holder(_av_lock); - if ((_video_ctx)&&(_video_ctx->codec)) { + if (_video_ctx && _video_ctx->codec) { +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 37, 100) + // We need to drain the codec to prevent a memory leak. + avcodec_send_packet(_video_ctx, nullptr); + while (avcodec_receive_frame(_video_ctx, _frame) == 0) {} + avcodec_flush_buffers(_video_ctx); +#endif + avcodec_close(_video_ctx); #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 52, 0) avcodec_free_context(&_video_ctx);