diff --git a/src/ffmpeg_api/api.rs b/src/ffmpeg_api/api.rs index de5e47e68207334188824cebf7dddc2f71d5a419..217da9bdffafd5801191ce2e6b2e255a91b5fca8 100644 --- a/src/ffmpeg_api/api.rs +++ b/src/ffmpeg_api/api.rs @@ -36,17 +36,30 @@ impl<'a> AVFormatContext { } pub fn streams(&self) -> Vec<AVStream> { - return unsafe { - std::slice::from_raw_parts( - (*self.base).streams, - (*self.base).nb_streams as usize, - ) - } - .iter() - .map(|stream| { - AVStream::new(unsafe { (*stream).as_mut() }.expect("not null"), &self) - }) - .collect(); + Vec::from( + unsafe { + std::slice::from_raw_parts( + (*self.base).streams, + (*self.base).nb_streams as usize, + ) + } + ).iter().map(|stream| { + AVStream::new(unsafe { (*stream).as_mut() }.expect("not null"), &self) + }).collect() + } + + pub fn find_stream<P>(&self, predicate: P) -> Option<AVStream> where + P: FnMut(&AVStream) -> bool { + Vec::from( + unsafe { + std::slice::from_raw_parts( + (*self.base).streams, + (*self.base).nb_streams as usize, + ) + } + ).iter().map(|stream| { + AVStream::new(unsafe { (*stream).as_mut() }.expect("not null"), &self) + }).find(predicate) } pub fn read_frame(&/*TODO:mut*/ self, packet: &mut AVPacket) -> Result<(), failure::Error> { diff --git a/src/main.rs b/src/main.rs index 5a6acb0ec6f340ecb441c8f4f538fc433844e250..4dbce7f9d08fa3f823489a01b0cd7ff7145abaa3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ pub(crate) mod ffmpeg_api; use crate::ffmpeg_api::enums::*; use crate::ffmpeg_api::api::*; +use image::{ImageBuffer, RgbImage}; fn main() -> Result<(), std::io::Error> { let mut before = std::time::SystemTime::now(); @@ -15,91 +16,117 @@ fn main() -> Result<(), std::io::Error> { panic!("Could not open video input: {:?}", error) }); - for mut stream in avformat_context.streams() { - stream.set_discard(AVDiscard::NonKey); + let x = 5; + let y = 5; + let mut spritesheet: RgbImage = ImageBuffer::new(160 * x, 90 * x); - let codec_parameters = stream.codec_parameters(); - let local_codec = codec_parameters.find_decoder(); - - println!( - "Stream #{}, type: {:#?}, codec: {:#?}", - stream.index(), - codec_parameters.codec_type(), - local_codec.name() - ); + let mut stream: AVStream = avformat_context.find_stream(|stream| { + stream.codec_parameters().codec_type() == AVMediaType::Video + }).unwrap_or_else(|| { + panic!("Could not find video stream") + }); - let mut output_frame = AVFrame::new().unwrap_or_else(|error| { - panic!("Could not create output frame: {:?}", error) - }); - output_frame.init(160, 90, AVPixelFormat::RGB24).unwrap_or_else(|error| { - panic!("Could not init output frame: {:?}", error) - }); + stream.set_discard(AVDiscard::NonKey); - 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); + let codec_parameters = stream.codec_parameters(); + let local_codec = codec_parameters.find_decoder(); - codec_context.set_skip_loop_filter(AVDiscard::NonKey); - codec_context.set_skip_idct(AVDiscard::NonKey); - codec_context.set_skip_frame(AVDiscard::NonKey); + println!( + "Stream #{}, type: {:#?}, codec: {:#?}", + stream.index(), + codec_parameters.codec_type(), + local_codec.name() + ); - let mut packet = AVPacket::new().unwrap_or_else(|error| { - panic!("Could not init temporary packet: {:?}", error) - }); + let mut output_frame = AVFrame::new().unwrap_or_else(|error| { + panic!("Could not create output frame: {:?}", error) + }); + output_frame.init(160, 90, AVPixelFormat::RGB24).unwrap_or_else(|error| { + panic!("Could not init output frame: {:?}", error) + }); - let mut frame = AVFrame::new().unwrap_or_else(|error| { - panic!("Could not create input frame: {:?}", error) - }); + 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); - let mut i = 0; + codec_context.set_skip_loop_filter(AVDiscard::NonKey); + codec_context.set_skip_idct(AVDiscard::NonKey); + codec_context.set_skip_frame(AVDiscard::NonKey); - println!("Time: {:#?}", before.elapsed().unwrap()); - before = std::time::SystemTime::now(); + let mut packet = AVPacket::new().unwrap_or_else(|error| { + panic!("Could not init temporary packet: {:?}", error) + }); - let mut scale_context = SwsContext::new(); + let mut frame = AVFrame::new().unwrap_or_else(|error| { + panic!("Could not create input frame: {:?}", error) + }); - while avformat_context.read_frame(&mut packet).is_ok() && i < 16 { - if packet.stream_index() == stream.index() { - codec_context.in_packet(&mut packet).unwrap_or_else(|error| { - panic!("Could not load packet: {:?}", error) + let mut i = 0; + + println!("Time: {:#?}", before.elapsed().unwrap()); + before = std::time::SystemTime::now(); + + let mut scale_context = SwsContext::new(); + + while avformat_context.read_frame(&mut packet).is_ok() { + if packet.stream_index() == stream.index() { + codec_context.in_packet(&mut packet).unwrap_or_else(|error| { + panic!("Could not load packet: {:?}", error) + }); + while codec_context.out_frame(&mut frame).is_ok() { + println!( + "Frame {}: {:?} @ {}", + frame.coded_picture_number(), + stream.timestamp(frame.pts()), + frame.key_frame() + ); + println!("Reading Time: {:#?}", before.elapsed().unwrap()); + before = std::time::SystemTime::now(); + + scale_context.reinit(&frame, &output_frame, SwsScaler::FastBilinear).unwrap_or_else(|error| { + panic!("Could not reinit scale context: {:?}", error) }); - while codec_context.out_frame(&mut frame).is_ok() { - println!( - "Frame {}: {:?} @ {}", - frame.coded_picture_number(), - stream.timestamp(frame.pts()), - frame.key_frame() - ); - println!("Reading Time: {:#?}", before.elapsed().unwrap()); - before = std::time::SystemTime::now(); + scale_context.scale(&frame, &mut output_frame); - 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!("Processing Time: {:#?}", before.elapsed().unwrap()); + before = std::time::SystemTime::now(); - println!("Processing Time: {:#?}", before.elapsed().unwrap()); - before = std::time::SystemTime::now(); + let current: RgbImage = ImageBuffer::from_raw(160, 90, output_frame.data(0).to_vec()).unwrap(); + + image::imageops::overlay( + &mut spritesheet, + ¤t, + (i % x) * 160, + ((i / x) % y) * 90, + ); + + println!("Writing Time: {:#?}", before.elapsed().unwrap()); + before = std::time::SystemTime::now(); - 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; + if i % (x * y) == 0 { + spritesheet.save(format!("/home/janne/Workspace/justflix/data/spritesheets/spritesheet_{}.png", (i / (x*y)) - 1)).unwrap_or_else(|error| { + panic!("Could not write spritesheet: {}", error) + }); + spritesheet = ImageBuffer::new(160 * x, 90 * x); println!("Writing Time: {:#?}", before.elapsed().unwrap()); before = std::time::SystemTime::now(); - - i += 1; } } } } + + if i % (x * y) != 0 { + spritesheet.save(format!("/home/janne/Workspace/justflix/data/spritesheets/spritesheet_{}.png", i / (x*y))).unwrap_or_else(|error| { + panic!("Could not write spritesheet: {}", error) + }); + println!("Writing Time: {:#?}", before.elapsed().unwrap()); + before = std::time::SystemTime::now(); + } } Ok(())