init
This commit is contained in:
commit
31a352c524
6 changed files with 2690 additions and 0 deletions
147
src/main.rs
Normal file
147
src/main.rs
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
extern crate ffmpeg_next as ffmpeg;
|
||||
|
||||
use ffmpeg::format::{input, Pixel};
|
||||
use ffmpeg::media::Type;
|
||||
use ffmpeg::software::scaling::{context::Context, flag::Flags};
|
||||
use ffmpeg::util::frame::video::Video;
|
||||
use std::cmp;
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use std::num::NonZeroU32;
|
||||
use std::rc::Rc;
|
||||
use std::thread;
|
||||
use winit::event::{Event, KeyEvent, WindowEvent};
|
||||
use winit::event_loop::{ControlFlow, EventLoopBuilder, EventLoopProxy};
|
||||
use winit::keyboard::{Key, NamedKey};
|
||||
use winit::window::WindowBuilder;
|
||||
|
||||
fn ffmpeg(event_loop_proxy: EventLoopProxy<Video>) -> Result<(), ffmpeg::Error> {
|
||||
ffmpeg::init().unwrap();
|
||||
|
||||
if let Ok(mut ictx) = input(&env::args().nth(1).expect("Cannot open file.")) {
|
||||
let input = ictx
|
||||
.streams()
|
||||
.best(Type::Video)
|
||||
.ok_or(ffmpeg::Error::StreamNotFound)?;
|
||||
let video_stream_index = input.index();
|
||||
|
||||
let context_decoder = ffmpeg::codec::context::Context::from_parameters(input.parameters())?;
|
||||
let mut decoder = context_decoder.decoder().video()?;
|
||||
|
||||
let mut scaler = Context::get(
|
||||
decoder.format(),
|
||||
decoder.width(),
|
||||
decoder.height(),
|
||||
Pixel::RGB24,
|
||||
1280, //TODO decoder.width(),
|
||||
720, //TODO decoder.height(),
|
||||
Flags::BILINEAR,
|
||||
)?;
|
||||
|
||||
let mut receive_and_process_decoded_frames =
|
||||
|decoder: &mut ffmpeg::decoder::Video| -> Result<(), ffmpeg::Error> {
|
||||
let mut decoded = Video::empty();
|
||||
while decoder.receive_frame(&mut decoded).is_ok() {
|
||||
let mut rgb_frame = Video::empty();
|
||||
scaler.run(&decoded, &mut rgb_frame)?;
|
||||
match event_loop_proxy.send_event(rgb_frame) {
|
||||
Ok(()) => {}
|
||||
Err(_err) => {
|
||||
panic!("event loop closed");
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
};
|
||||
|
||||
for (stream, packet) in ictx.packets() {
|
||||
if stream.index() == video_stream_index {
|
||||
decoder.send_packet(&packet)?;
|
||||
receive_and_process_decoded_frames(&mut decoder)?;
|
||||
}
|
||||
}
|
||||
decoder.send_eof()?;
|
||||
receive_and_process_decoded_frames(&mut decoder)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let event_loop = EventLoopBuilder::<Video>::with_user_event()
|
||||
.build()
|
||||
.unwrap();
|
||||
let event_loop_proxy = event_loop.create_proxy();
|
||||
thread::spawn(move || {
|
||||
ffmpeg(event_loop_proxy).unwrap();
|
||||
});
|
||||
|
||||
let window = Rc::new(WindowBuilder::new().build(&event_loop).unwrap());
|
||||
let context = softbuffer::Context::new(window.clone()).unwrap();
|
||||
let mut surface = softbuffer::Surface::new(&context, window.clone()).unwrap();
|
||||
|
||||
let mut rgb_frame_opt: Option<Video> = None;
|
||||
event_loop
|
||||
.run(move |event, elwt| {
|
||||
elwt.set_control_flow(ControlFlow::Wait);
|
||||
|
||||
match event {
|
||||
Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::RedrawRequested,
|
||||
} if window_id == window.id() => {
|
||||
if let (Some(width), Some(height)) = {
|
||||
let size = window.inner_size();
|
||||
(NonZeroU32::new(size.width), NonZeroU32::new(size.height))
|
||||
} {
|
||||
surface.resize(width, height).unwrap();
|
||||
//TODO: send size back to ffmpeg thread
|
||||
|
||||
let mut buffer = surface.buffer_mut().unwrap();
|
||||
let buffer_width = width.get() as usize;
|
||||
let buffer_height = height.get() as usize;
|
||||
if let Some(rgb_frame) = &rgb_frame_opt {
|
||||
let data = rgb_frame.data(0);
|
||||
let data_width = rgb_frame.width() as usize;
|
||||
let data_height = rgb_frame.height() as usize;
|
||||
//TODO: stride?
|
||||
for y in 0..cmp::min(buffer_height, data_height) {
|
||||
for x in 0..cmp::min(buffer_width, data_width) {
|
||||
let data_index = (y * data_width + x) * 3;
|
||||
let red = data[data_index] as u32;
|
||||
let green = data[data_index + 1] as u32;
|
||||
let blue = data[data_index + 2] as u32;
|
||||
let buffer_index = y * buffer_width + x;
|
||||
buffer[buffer_index] = blue | (green << 8) | (red << 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buffer.present().unwrap();
|
||||
}
|
||||
}
|
||||
Event::WindowEvent {
|
||||
event:
|
||||
WindowEvent::CloseRequested
|
||||
| WindowEvent::KeyboardInput {
|
||||
event:
|
||||
KeyEvent {
|
||||
logical_key: Key::Named(NamedKey::Escape),
|
||||
..
|
||||
},
|
||||
..
|
||||
},
|
||||
window_id,
|
||||
} if window_id == window.id() => {
|
||||
elwt.exit();
|
||||
}
|
||||
Event::UserEvent(rgb_frame) => {
|
||||
rgb_frame_opt = Some(rgb_frame);
|
||||
window.request_redraw();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue