From 504f4e9408d6db6c4a20e58c2877e902d836968c Mon Sep 17 00:00:00 2001 From: Janne Mareike Koschinski <janne@kuschku.de> Date: Sun, 23 Feb 2020 15:41:03 +0100 Subject: [PATCH] Improve safety yet again --- src/ffmpeg_api/api.rs | 101 ++++++++++++++++++++++++++++++++++++++++ src/ffmpeg_api/enums.rs | 40 +++++++++++----- src/main.rs | 73 ++++++++++------------------- 3 files changed, 155 insertions(+), 59 deletions(-) diff --git a/src/ffmpeg_api/api.rs b/src/ffmpeg_api/api.rs index 2598ba0..52ccc88 100644 --- a/src/ffmpeg_api/api.rs +++ b/src/ffmpeg_api/api.rs @@ -103,6 +103,49 @@ impl AVBuffer { } } +pub struct AVPacket { + base: *mut ffi::AVPacket, +} + +impl AVPacket { + pub fn new() -> Result<Self, failure::Error> { + let base = unsafe { ffi::av_packet_alloc() }; + if base.is_null() { + bail!("av_packet_alloc() failed"); + } + Ok(AVPacket { base }) + } + + // TODO: Just for testing + pub unsafe fn as_mut(&mut self) -> &mut ffi::AVPacket { + self.base.as_mut().expect("not null") + } + + pub fn pts(&self) -> i64 { + let base = unsafe { self.base.as_ref() }.expect("not null"); + + base.pts + } + + pub fn dts(&self) -> i64 { + let base = unsafe { self.base.as_ref() }.expect("not null"); + + base.dts + } + + pub fn stream_index(&self) -> i32 { + let base = unsafe { self.base.as_ref() }.expect("not null"); + + base.stream_index + } +} + +impl Drop for AVPacket { + fn drop(&mut self) { + unsafe { ffi::av_packet_free(&mut self.base) } + } +} + pub struct AVFrame { base: *mut ffi::AVFrame, buffer: AVBuffer, @@ -414,4 +457,62 @@ impl Drop for AVCodecContext { fn drop(&mut self) { unsafe { ffi::avcodec_free_context(&mut self.base) } } +} + +pub struct SwsContext { + base: *mut ffi::SwsContext, +} + +impl SwsContext { + pub fn new() -> Self { + SwsContext { base: std::ptr::null_mut() } + } + + pub fn reinit(&mut self, source: &AVFrame, target: &AVFrame, scaler: SwsScaler) -> Result<(), failure::Error> { + let base = unsafe { + ffi::sws_getCachedContext( + self.base, + source.width(), + source.height(), + source.format() as ffi::AVPixelFormat, + target.width(), + target.height(), + target.format() as ffi::AVPixelFormat, + scaler as i32, + std::ptr::null_mut(), + std::ptr::null_mut(), + std::ptr::null(), + ) + }; + if base.is_null() { + bail!("sws_getCachedContext() failed"); + } + self.base = base; + + Ok(()) + } + + pub fn scale(&self, source: &AVFrame, target: &mut AVFrame) -> i32 { + self.scale_slice(source, target, 0, source.height()) + } + + pub fn scale_slice(&self, source: &AVFrame, target: &mut AVFrame, slice_from: i32, slice_to: i32) -> i32 { + unsafe { + ffi::sws_scale( + self.base, + source.data_ptr(), + source.linesize().as_ptr(), + slice_from, + slice_to, + target.data_mut_ptr(), + target.linesize().as_ptr(), + ) + } + } +} + +impl Drop for SwsContext { + fn drop(&mut self) { + unsafe { ffi::sws_freeContext(self.base) } + } } \ No newline at end of file diff --git a/src/ffmpeg_api/enums.rs b/src/ffmpeg_api/enums.rs index 85de4af..ad915a0 100644 --- a/src/ffmpeg_api/enums.rs +++ b/src/ffmpeg_api/enums.rs @@ -913,22 +913,40 @@ enum_from_primitive! { } enum_from_primitive! { - # [derive(Debug, Copy, Clone, PartialEq)] - # [repr(i32)] + #[derive(Debug, Copy, Clone, PartialEq)] + #[repr(i32)] pub enum AVDiscard { - # [doc = "< discard nothing"] + #[doc = "< discard nothing"] None = ffi::AVDiscard_AVDISCARD_NONE, - # [doc = "< discard useless packets like 0 size packets in avi"] - Default =ffi::AVDiscard_AVDISCARD_DEFAULT, - # [doc = "< discard all non reference"] + #[doc = "< discard useless packets like 0 size packets in avi"] + Default = ffi::AVDiscard_AVDISCARD_DEFAULT, + #[doc = "< discard all non reference"] NonReference = ffi::AVDiscard_AVDISCARD_NONREF, - # [doc = "< discard all bidirectional frames"] + #[doc = "< discard all bidirectional frames"] BiDirectional = ffi::AVDiscard_AVDISCARD_BIDIR, - # [doc = "< discard all non intra frames"] + #[doc = "< discard all non intra frames"] NonIntra = ffi::AVDiscard_AVDISCARD_NONINTRA, - # [doc = "< discard all frames except keyframes"] + #[doc = "< discard all frames except keyframes"] NonKey = ffi::AVDiscard_AVDISCARD_NONKEY, - # [doc = "< discard all"] - All =ffi::AVDiscard_AVDISCARD_ALL + #[doc = "< discard all"] + All = ffi::AVDiscard_AVDISCARD_ALL, + } +} + +enum_from_primitive! { + #[derive(Debug, Copy, Clone, PartialEq)] + #[repr(u32)] + pub enum SwsScaler { + FastBilinear = ffi::SWS_FAST_BILINEAR, + Bilinear = ffi::SWS_BILINEAR, + Bicubic = ffi::SWS_BICUBIC, + X = ffi::SWS_X, + Point = ffi::SWS_POINT, + Area = ffi::SWS_AREA, + Bicublin = ffi::SWS_BICUBLIN, + Gauss = ffi::SWS_GAUSS, + Sinc = ffi::SWS_SINC, + Lanczos = ffi::SWS_LANCZOS, + Spline = ffi::SWS_SPLINE, } } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 707ae42..3dcc9b5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -48,11 +48,9 @@ fn main() -> Result<(), std::io::Error> { 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 packet = AVPacket::new().unwrap_or_else(|error| { + panic!("Could not init temporary packet: {:?}", error) + }); let mut frame = AVFrame::new().unwrap_or_else(|error| { panic!("Could not create input frame: {:?}", error) @@ -63,10 +61,16 @@ fn main() -> Result<(), std::io::Error> { println!("Time: {:#?}", before.elapsed().unwrap()); before = std::time::SystemTime::now(); + let mut scale_context = SwsContext::new(); + //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::av_read_frame(avformat_context.raw(), packet.as_mut()) } >= 0 && i < 16 { + // TODO: END DRAGONS + + if packet.stream_index() == stream.index() { + + //TODO: HERE BE DRAGONS + unsafe { ffi::avcodec_send_packet(codec_context.raw(), packet.as_mut()) }; while unsafe { ffi::avcodec_receive_frame(codec_context.raw(), frame.as_mut()) } >= 0 { // TODO: END DRAGONS @@ -79,53 +83,26 @@ fn main() -> Result<(), std::io::Error> { 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 + scale_context.reinit(&frame, &output_frame, SwsScaler::FastBilinear).unwrap_or_else(|error| { + panic!("Could not reinit scale context: {:?}", error) + }); + scale_context.scale(&frame, &mut output_frame); - 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; - } + 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(); println!("Writing Time: {:#?}", before.elapsed().unwrap()); before = std::time::SystemTime::now(); + + i += 1; } } } -- GitLab