Browse Source

ffmpeg: drain avcodec contexts on close, fixes leak

Fixes #398
rdb 7 years ago
parent
commit
85cb742f79
2 changed files with 25 additions and 11 deletions
  1. 17 10
      panda/src/ffmpeg/ffmpegAudioCursor.cxx
  2. 8 1
      panda/src/ffmpeg/ffmpegVideoCursor.cxx

+ 17 - 10
panda/src/ffmpeg/ffmpegAudioCursor.cxx

@@ -210,6 +210,23 @@ FfmpegAudioCursor::
  */
  */
 void FfmpegAudioCursor::
 void FfmpegAudioCursor::
 cleanup() {
 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 (_frame) {
 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 45, 101)
 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 45, 101)
     av_frame_free(&_frame);
     av_frame_free(&_frame);
@@ -237,16 +254,6 @@ cleanup() {
     _buffer = nullptr;
     _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) {
   if (_format_ctx) {
     _ffvfile.close();
     _ffvfile.close();
     _format_ctx = nullptr;
     _format_ctx = nullptr;

+ 8 - 1
panda/src/ffmpeg/ffmpegVideoCursor.cxx

@@ -595,7 +595,14 @@ close_stream() {
   // Hold the global lock while we free avcodec objects.
   // Hold the global lock while we free avcodec objects.
   ReMutexHolder av_holder(_av_lock);
   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);
     avcodec_close(_video_ctx);
 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 52, 0)
 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 52, 0)
     avcodec_free_context(&_video_ctx);
     avcodec_free_context(&_video_ctx);