From 7ba854939da916ca08dfb7afcbaa31ad5ae18fa9 Mon Sep 17 00:00:00 2001
From: Janne Koschinski <janne@kuschku.de>
Date: Thu, 24 Sep 2020 21:53:50 +0200
Subject: [PATCH] Resolve some memory leaks

---
 lib/ffmpeg_api/src/api.rs | 48 ++++++++++++++++++++++++++-------------
 1 file changed, 32 insertions(+), 16 deletions(-)

diff --git a/lib/ffmpeg_api/src/api.rs b/lib/ffmpeg_api/src/api.rs
index 63dbb37..6343af1 100644
--- a/lib/ffmpeg_api/src/api.rs
+++ b/lib/ffmpeg_api/src/api.rs
@@ -3,8 +3,8 @@ use std::path::{Path, PathBuf};
 
 use ffmpeg_dev::sys as ffi;
 use fraction::Fraction;
-use num_traits::FromPrimitive;
 use media_time::MediaTimeError;
+use num_traits::FromPrimitive;
 use thiserror::Error;
 
 use crate::enums::*;
@@ -21,7 +21,7 @@ pub enum StringError {
     #[error("String is unexpectedly null")]
     NullError,
     #[error(transparent)]
-    Utf8Error(#[from] std::str::Utf8Error)
+    Utf8Error(#[from] std::str::Utf8Error),
 }
 
 fn native_string(ptr: *const std::os::raw::c_char) -> Result<String, StringError> {
@@ -48,7 +48,7 @@ pub enum AVFormatContextError {
     #[error("Path {0} contains null byte")]
     PathContainsNull(PathBuf, #[source] std::ffi::NulError),
     #[error("Opening media file {0} failed")]
-    OpenInputFailed(PathBuf, #[source] AVError)
+    OpenInputFailed(PathBuf, #[source] AVError),
 }
 
 impl AVFormatContext {
@@ -58,7 +58,7 @@ impl AVFormatContext {
             Err(AVAllocError::AllocFailed("AVFormatContext".to_string()))
         } else {
             Ok(AVFormatContext { base })
-        }
+        };
     }
 
     pub fn open_input(&mut self, path: &Path) -> Result<(), AVFormatContextError> {
@@ -85,16 +85,17 @@ impl AVFormatContext {
         Ok(AVInputFormat::new(base))
     }
 
-    pub fn streams(&self) -> impl Iterator<Item = AVStream> {
+    pub fn streams(&self) -> impl Iterator<Item=AVStream> {
         unsafe {
             std::slice::from_raw_parts((*self.base).streams, (*self.base).nb_streams as usize)
         }
-        .iter()
-        .filter_map(|stream: &*mut ffi::AVStream| unsafe { (*stream).as_mut() })
-        .map(|stream| AVStream::new(stream))
+            .iter()
+            .filter_map(|stream: &*mut ffi::AVStream| unsafe { (*stream).as_mut() })
+            .map(|stream| AVStream::new(stream))
     }
 
     pub fn read_frame(&mut self, packet: &mut AVPacket) -> Result<(), AVFrameError> {
+        unsafe { ffi::av_packet_unref(packet.base) }
         AVError::from_errno(unsafe { ffi::av_read_frame(self.base, packet.base) })
             .map_err(|err| AVFrameError::DecodingFailed(packet.stream_index(), packet.pts(), err))
     }
@@ -171,7 +172,7 @@ impl AVBuffer {
             Err(AVAllocError::AllocFailed("AVBufferContext".to_string()))
         } else {
             Ok(AVBuffer { base, size })
-        }
+        };
     }
 
     pub fn empty() -> Self {
@@ -190,6 +191,14 @@ impl AVBuffer {
     }
 }
 
+impl Drop for AVBuffer {
+    fn drop(&mut self) {
+        unsafe {
+            ffi::av_free(self.base as *mut std::ffi::c_void)
+        }
+    }
+}
+
 pub struct AVPacket {
     base: *mut ffi::AVPacket,
 }
@@ -207,7 +216,7 @@ impl AVPacket {
             Err(AVAllocError::AllocFailed("AVPacket".to_string()))
         } else {
             Ok(AVPacket { base })
-        }
+        };
     }
 
     fn as_ref(&self) -> &ffi::AVPacket {
@@ -229,7 +238,10 @@ impl AVPacket {
 
 impl Drop for AVPacket {
     fn drop(&mut self) {
-        unsafe { ffi::av_packet_free(&mut self.base) }
+        unsafe {
+            ffi::av_packet_unref(self.base);
+            ffi::av_packet_free(&mut self.base);
+        }
     }
 }
 
@@ -243,7 +255,7 @@ pub enum AVFrameError {
     #[error(transparent)]
     AllocFailed(#[from] AVAllocError),
     #[error("Decoding a frame from packet of stream {0} at timestamp {1} failed")]
-    DecodingFailed(i32, i64, #[source] AVError)
+    DecodingFailed(i32, i64, #[source] AVError),
 }
 
 impl AVFrame {
@@ -252,8 +264,8 @@ impl AVFrame {
         return if base.is_null() {
             Err(AVAllocError::AllocFailed("AVFrame".to_string()))
         } else {
-            Ok(AVFrame { base, buffer: AVBuffer::empty(), })
-        }
+            Ok(AVFrame { base, buffer: AVBuffer::empty() })
+        };
     }
 
     pub fn init(&mut self, width: i32, height: i32, format: AVPixelFormat) -> Result<(), AVFrameError> {
@@ -345,7 +357,10 @@ impl AVFrame {
 
 impl Drop for AVFrame {
     fn drop(&mut self) {
-        unsafe { ffi::av_frame_free(&mut self.base) }
+        unsafe {
+            ffi::av_frame_unref(self.base);
+            ffi::av_frame_free(&mut self.base);
+        }
     }
 }
 
@@ -511,7 +526,8 @@ impl AVCodecContext {
     }
 
     pub fn out_frame(&mut self, frame: &mut AVFrame) -> Result<(), AVCodecContextError> {
-        AVError::from_errno( unsafe { ffi::avcodec_receive_frame(self.base, frame.base) })
+        unsafe { ffi::av_frame_unref(frame.base) }
+        AVError::from_errno(unsafe { ffi::avcodec_receive_frame(self.base, frame.base) })
             .map_err(|err| AVCodecContextError::FrameError(err))
     }
 
-- 
GitLab