From 0735660298c4777fa664e6a90335951eba22f306 Mon Sep 17 00:00:00 2001
From: Janne Mareike Koschinski <janne@kuschku.de>
Date: Sun, 23 Feb 2020 14:49:54 +0100
Subject: [PATCH] even more improvements

---
 src/ffmpeg_api/api.rs |  93 ++++++++++++++++++---
 src/main.rs           | 183 ++++++++++++++++++++----------------------
 2 files changed, 170 insertions(+), 106 deletions(-)

diff --git a/src/ffmpeg_api/api.rs b/src/ffmpeg_api/api.rs
index 10ceeff..2598ba0 100644
--- a/src/ffmpeg_api/api.rs
+++ b/src/ffmpeg_api/api.rs
@@ -60,7 +60,7 @@ impl<'a> AVFormatContext {
         }
             .iter()
             .map(|stream| {
-                AVStream::new(unsafe { (*stream).as_mut() }.expect("not null"), self)
+                AVStream::new(unsafe { (*stream).as_mut() }.expect("not null"), &self)
             })
             .collect();
     }
@@ -264,30 +264,30 @@ impl<'a> AVStream<'a> {
         )
     }
 
-    pub fn duration(self: &AVStream<'a>) -> std::time::Duration {
+    pub fn duration(&self) -> std::time::Duration {
         self.timestamp(self.base.duration)
     }
 
-    pub fn frame_count(self: &AVStream<'a>) -> i64 {
+    pub fn frame_count(&self) -> i64 {
         self.base.nb_frames
     }
 
-    pub fn discard(self: &AVStream<'a>) -> Option<AVDiscard> {
+    pub fn discard(&self) -> Option<AVDiscard> {
         AVDiscard::from_i32(self.base.discard)
     }
 
-    pub fn set_discard(self: &mut AVStream<'a>, value: AVDiscard) {
+    pub fn set_discard(&mut self, value: AVDiscard) {
         self.base.discard = value as ffi::AVDiscard;
     }
 
-    pub fn sample_aspect_ratio(self: &AVStream<'a>) -> Fraction {
+    pub fn sample_aspect_ratio(&self) -> Fraction {
         Fraction::new(
             self.base.sample_aspect_ratio.num as u32,
             self.base.sample_aspect_ratio.den as u32,
         )
     }
 
-    pub fn codec_parameters(self: &AVStream<'a>) -> AVCodecParameters {
+    pub fn codec_parameters(&self) -> AVCodecParameters {
         AVCodecParameters::new(unsafe { self.base.codecpar.as_mut() }.expect("not null"), self)
     }
 }
@@ -307,15 +307,15 @@ impl<'a> AVCodecParameters<'a> {
         self.base
     }
 
-    pub fn codec_type(self: &AVCodecParameters<'a>) -> AVMediaType {
+    pub fn codec_type(&self) -> AVMediaType {
         AVMediaType::from_i32(self.base.codec_type).unwrap_or(AVMediaType::Unknown)
     }
 
-    pub fn codec_id(self: &AVCodecParameters<'a>) -> Option<AVCodecID> {
+    pub fn codec_id(&self) -> Option<AVCodecID> {
         AVCodecID::from_u32(self.base.codec_id)
     }
 
-    pub fn find_decoder(self: &AVCodecParameters<'a>) -> AVCodec {
+    pub fn find_decoder(&self) -> AVCodec {
         AVCodec::new(
             unsafe { ffi::avcodec_find_decoder(self.base.codec_id).as_mut() }.expect("Decoder not found"),
             self,
@@ -342,3 +342,76 @@ impl<'a> AVCodec<'a> {
         String::from(unsafe { std::ffi::CStr::from_ptr(self.base.name) }.to_str().unwrap())
     }
 }
+
+pub struct AVCodecContext {
+    base: *mut ffi::AVCodecContext,
+}
+
+impl AVCodecContext {
+    pub fn new(codec: &AVCodec) -> Result<Self, failure::Error> {
+        let base = unsafe { ffi::avcodec_alloc_context3(codec.base) };
+        if base.is_null() {
+            bail!("avcodec_alloc_context3() failed");
+        }
+        Ok(AVCodecContext { base })
+    }
+
+    // TODO: Just for testing
+    pub unsafe fn raw(&self) -> *mut ffi::AVCodecContext {
+        self.base
+    }
+
+    pub fn skip_loop_filter(&self) -> Option<AVDiscard> {
+        let base = unsafe { self.base.as_ref() }.expect("not null");
+
+        AVDiscard::from_i32(base.skip_loop_filter)
+    }
+
+    pub fn set_skip_loop_filter(&mut self, value: AVDiscard) {
+        let base = unsafe { self.base.as_mut() }.expect("not null");
+
+        base.skip_loop_filter = value as ffi::AVDiscard
+    }
+
+    pub fn skip_idct(&self) -> Option<AVDiscard> {
+        let base = unsafe { self.base.as_ref() }.expect("not null");
+
+        AVDiscard::from_i32(base.skip_idct)
+    }
+
+    pub fn set_skip_idct(&mut self, value: AVDiscard) {
+        let base = unsafe { self.base.as_mut() }.expect("not null");
+
+        base.skip_idct = value as ffi::AVDiscard
+    }
+
+    pub fn skip_frame(&self) -> Option<AVDiscard> {
+        let base = unsafe { self.base.as_ref() }.expect("not null");
+
+        AVDiscard::from_i32(base.skip_frame)
+    }
+
+    pub fn set_skip_frame(&mut self, value: AVDiscard) {
+        let base = unsafe { self.base.as_mut() }.expect("not null");
+
+        base.skip_frame = value as ffi::AVDiscard
+    }
+
+    pub fn set_parameters(&mut self, params: &AVCodecParameters) {
+        unsafe {
+            ffi::avcodec_parameters_to_context(self.base, params.base);
+        }
+    }
+
+    pub fn open(&mut self, codec: &AVCodec) {
+        unsafe {
+            ffi::avcodec_open2(self.base, codec.base, std::ptr::null_mut());
+        }
+    }
+}
+
+impl Drop for AVCodecContext {
+    fn drop(&mut self) {
+        unsafe { ffi::avcodec_free_context(&mut self.base) }
+    }
+}
\ No newline at end of file
diff --git a/src/main.rs b/src/main.rs
index c9208c9..707ae42 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -37,107 +37,98 @@ fn main() -> Result<(), std::io::Error> {
             panic!("Could not init output frame: {:?}", error)
         });
 
-        match codec_parameters.codec_type() {
-            AVMediaType::Video => {
-
-                // TODO: HERE BE DRAGONS
-
-                let avc_ctx: &mut ffi::AVCodecContext = unsafe {
-                    ffi::avcodec_alloc_context3(local_codec.as_ref()).as_mut()
-                }.expect("not null");
-
-                avc_ctx.skip_loop_filter = ffi::AVDiscard_AVDISCARD_NONKEY;
-                avc_ctx.skip_idct = ffi::AVDiscard_AVDISCARD_NONKEY;
-                avc_ctx.skip_frame = ffi::AVDiscard_AVDISCARD_NONKEY;
-
-                unsafe {
-                    ffi::avcodec_parameters_to_context(avc_ctx, codec_parameters.as_ref());
-                    ffi::avcodec_open2(avc_ctx, local_codec.as_ref(), std::ptr::null_mut());
-                }
-
-                let packet: &mut ffi::AVPacket = unsafe {
-                    ffi::av_packet_alloc().as_mut()
-                }.expect("not null");
-
-                let mut frame = AVFrame::new().unwrap_or_else(|error| {
-                    panic!("Could not create input frame: {:?}", error)
-                });
-
-                let mut i = 0;
-
-                println!("Time: {:#?}", before.elapsed().unwrap());
-                before = std::time::SystemTime::now();
-
-                let mut sws_context: *mut ffi::SwsContext = std::ptr::null_mut();
-
-                while unsafe { ffi::av_read_frame(avformat_context.raw(), packet) } >= 0 && i < 10 {
-                    if packet.stream_index == stream.index() {
-                        unsafe {
-                            ffi::avcodec_send_packet(avc_ctx, packet);
+        if codec_parameters.codec_type() == AVMediaType::Video {
+            let mut codec_context = AVCodecContext::new(&local_codec).unwrap_or_else(|error| {
+                panic!("Could not init codec context: {:?}", error)
+            });
+            codec_context.set_parameters(&codec_parameters);
+            codec_context.open(&local_codec);
+
+            codec_context.set_skip_loop_filter(AVDiscard::NonKey);
+            codec_context.set_skip_idct(AVDiscard::NonKey);
+            codec_context.set_skip_frame(AVDiscard::NonKey);
+
+            // TODO: HERE BE DRAGONS
+            let packet: &mut ffi::AVPacket = unsafe {
+                ffi::av_packet_alloc().as_mut()
+            }.expect("not null");
+            // TODO: END DRAGONS
+
+            let mut frame = AVFrame::new().unwrap_or_else(|error| {
+                panic!("Could not create input frame: {:?}", error)
+            });
+
+            let mut i = 0;
+
+            println!("Time: {:#?}", before.elapsed().unwrap());
+            before = std::time::SystemTime::now();
+
+            //TODO: HERE BE DRAGONS
+            while unsafe { ffi::av_read_frame(avformat_context.raw(), packet) } >= 0 && i < 10 {
+                if packet.stream_index == stream.index() {
+                    unsafe { ffi::avcodec_send_packet(codec_context.raw(), packet) };
+                    while unsafe { ffi::avcodec_receive_frame(codec_context.raw(), frame.as_mut()) } >= 0 {
+                        // TODO: END DRAGONS
+
+                        println!(
+                            "Frame {}: {:?} @ {}",
+                            frame.coded_picture_number(),
+                            stream.timestamp(frame.pts()),
+                            frame.key_frame()
+                        );
+                        println!("Reading Time: {:#?}", before.elapsed().unwrap());
+                        before = std::time::SystemTime::now();
+
+                        // TODO: HERE BE DRAGONS
+                        let sws_context = unsafe {
+                            ffi::sws_getContext(
+                                frame.width(),
+                                frame.height(),
+                                frame.format() as ffi::AVPixelFormat,
+                                output_frame.width(),
+                                output_frame.height(),
+                                output_frame.format() as ffi::AVPixelFormat,
+                                ffi::SWS_FAST_BILINEAR as i32,
+                                std::ptr::null_mut(),
+                                std::ptr::null_mut(),
+                                std::ptr::null(),
+                            ).as_mut()
+                        }.expect("not null");
+
+                        let success = unsafe {
+                            ffi::sws_scale(
+                                sws_context,
+                                frame.data_ptr(),
+                                frame.linesize().as_ptr(),
+                                0,
+                                frame.height(),
+                                output_frame.data_mut_ptr(),
+                                output_frame.linesize().as_ptr(),
+                            )
+                        };
+                        // TODO: END DRAGONS
+
+                        println!("success: {}", success);
+                        println!("Processing Time: {:#?}", before.elapsed().unwrap());
+                        before = std::time::SystemTime::now();
+
+                        if success > 0 {
+                            image::save_buffer(
+                                format!("/home/janne/Workspace/justflix/data/test/image_{}.png", i),
+                                output_frame.data(0),
+                                output_frame.width() as u32,
+                                output_frame.height() as u32,
+                                image::ColorType::Rgb8,
+                            ).unwrap();
+
+                            i += 1;
                         }
 
-                        while unsafe { ffi::avcodec_receive_frame(avc_ctx, frame.as_mut()) } >= 0 {
-                            println!(
-                                "Frame {}: {:?} @ {}",
-                                frame.coded_picture_number(),
-                                stream.timestamp(frame.pts()),
-                                frame.key_frame()
-                            );
-                            println!("Reading Time: {:#?}", before.elapsed().unwrap());
-                            before = std::time::SystemTime::now();
-
-                            if sws_context.is_null() {
-                                sws_context = unsafe {
-                                    ffi::sws_getContext(
-                                        frame.width(),
-                                        frame.height(),
-                                        frame.format() as ffi::AVPixelFormat,
-                                        160,
-                                        90,
-                                        ffi::AVPixelFormat_AV_PIX_FMT_RGB24,
-                                        ffi::SWS_FAST_BILINEAR as i32,
-                                        std::ptr::null_mut(),
-                                        std::ptr::null_mut(),
-                                        std::ptr::null(),
-                                    ).as_mut()
-                                }.expect("not null");
-                            }
-
-                            let success = unsafe {
-                                ffi::sws_scale(
-                                    sws_context,
-                                    frame.data_ptr(),
-                                    frame.linesize().as_ptr(),
-                                    0,
-                                    frame.height(),
-                                    output_frame.data_mut_ptr(),
-                                    output_frame.linesize().as_ptr(),
-                                )
-                            };
-
-                            println!("success: {}", success);
-                            println!("Processing Time: {:#?}", before.elapsed().unwrap());
-                            before = std::time::SystemTime::now();
-
-                            if success > 0 {
-                                image::save_buffer(
-                                    format!("/home/janne/Workspace/justflix/data/test/image_{}.png", i),
-                                    output_frame.data(0),
-                                    output_frame.width() as u32,
-                                    output_frame.height() as u32,
-                                    image::ColorType::Rgb8,
-                                ).unwrap();
-
-                                i += 1;
-                            }
-
-                            println!("Writing Time: {:#?}", before.elapsed().unwrap());
-                            before = std::time::SystemTime::now();
-                        }
+                        println!("Writing Time: {:#?}", before.elapsed().unwrap());
+                        before = std::time::SystemTime::now();
                     }
                 }
             }
-            _ => {}
         }
     }
 
-- 
GitLab