oddity-ai / video-rs

Video readers, writers, muxers, encoders and decoders for Rust based on ffmpeg libraries.
Apache License 2.0
248 stars 31 forks source link

Rendering video using rust's `sdl2` crate #18

Closed Miraj98 closed 1 year ago

Miraj98 commented 1 year ago

Is the ability to render video frames using something like sdl2 within the scope of this crate? Can have it behind a feature flag. I don't mind making a PR and having a basic support for such a thing. Here is a working example -

use std::{collections::VecDeque, time::Duration};

use ndarray::Array3;
use video_rs::{self, Decoder, Locator, Time};
use sdl2::{event::Event, keyboard::Keycode, pixels::{PixelFormatEnum, self}};

fn main() {
    video_rs::init().unwrap();
    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let window = video_subsystem.window("rust-sdl2 demo", 800, 600)
        .position_centered()
        .build()
        .unwrap();

    let mut canvas = window.into_canvas().build().unwrap();

    let path = Locator::Path(
        "path/to/some/videofile.mp4"
            .parse()
            .unwrap(),
    );

    let mut decoder = Decoder::new(&path)
        .expect("failed to create decoder");
    let (width, height) = decoder.size();

    let mut frames = VecDeque::<(Time, Array3<u8>)>::with_capacity(1000);

    decoder.decode_iter().take_while(Result::is_ok).for_each(|frame| {
        let frame = frame.unwrap();
        frames.push_back(frame);
    });

    println!("Frames loaded: {}", frames.len());

    let texture_creator = canvas.texture_creator();
    let mut texture = texture_creator
        .create_texture_streaming(PixelFormatEnum::RGB24, width, height)
        .unwrap();
    canvas.set_draw_color(pixels::Color::RGB(0, 0, 0));
    let mut event_pump = sdl_context.event_pump().unwrap();

    let mut i = 0;
    'running: loop {
        texture.update(None, frames[i].1.as_slice().unwrap(), width as usize * 3).unwrap();
        canvas.clear();

        for event in event_pump.poll_iter() {
            match event {
                Event::Quit {..} |
                Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                    break 'running
                },
                _ => {}
            }
        }

        let rect = sdl2::rect::Rect::new(0, 0, width, height);
        canvas.copy(&texture, None, Some(rect)).unwrap();
        canvas.present();

        if i == frames.len() { break; }
        i += 1;

        std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 60));
    }

}
Type1J commented 1 year ago

That seems like an example rather than a crate feature.

gerwin3 commented 1 year ago

Out-of-scope for this crate.