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