diff --git a/src/capture.rs b/src/capture.rs index 4537a2c..e5def11 100644 --- a/src/capture.rs +++ b/src/capture.rs @@ -23,6 +23,9 @@ impl Capture { let x = Device::open ("/dev/video0")?; + // sudo apt install v4l-utils + // v4l2-ctl -d /dev/video0 --list-formats-ext + let x = x.video_capture (PixFormat::new (1280, 720, PixelFormat::MJPG))?; x.set_frame_interval(linuxvideo::Fract::new(1, 30)).unwrap (); dbg! (x.format ()); @@ -72,4 +75,4 @@ pub enum Error Io (#[from] std::io::Error), #[error ("output buffer too small")] OutputBufferTooSmall, -} \ No newline at end of file +} diff --git a/src/main.rs b/src/main.rs index dae57b4..e2e6d67 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,7 +10,6 @@ use std::{ }; use eframe::egui; -use rayon::ThreadPool; mod capture; mod task; @@ -22,95 +21,25 @@ fn main() -> Result <(), Error> match args.next ().as_deref () { None => main_egui (), - Some ("capture") => + Some ("capture") => { - use std::io::Write; - let mut cap = capture::Capture::new ()?; - let mut buf = vec! [0u8; cap.size_image ()]; - let mut bytesused = 0; + let mut capture = capture::Capture::new ().unwrap (); + let mut buf = vec! [0u8; capture.size_image ()]; - for _ in 0..30 + for _ in 0..10 { - cap.wait_for_frame (&mut buf).unwrap (); + capture.wait_for_frame (&mut buf).unwrap (); } + println! ("Measuring..."); let start = Instant::now (); for _ in 0..30 { - let rc = cap.wait_for_frame (&mut buf); - bytesused = rc.unwrap (); + capture.wait_for_frame (&mut buf).unwrap (); } let stop = Instant::now (); - let capture_fps = 30_000.0f32 / (stop - start).as_millis () as f32; - dbg! (capture_fps); - - let buf = &buf [0..bytesused]; - - let mut f = std::fs::File::create ("data.jpeg").unwrap (); - f.write_all (buf).unwrap (); - - let start = Instant::now (); - let mut pixels = vec! []; - for _ in 0..30 - { - let mut decoder = zune_jpeg::JpegDecoder::new_with_options - ( - buf, - zune_core::options::DecoderOptions::new_fast ().jpeg_set_out_colorspace (zune_core::colorspace::ColorSpace::YCbCr), - ); - decoder.decode_headers ().unwrap (); - pixels.resize (decoder.output_buffer_size ().unwrap (), 0); - - decoder.decode_into (&mut pixels).unwrap (); - } - let stop = Instant::now (); - let decode_mpf = (stop - start).as_millis () as f32 / 30.0f32; - dbg! (decode_mpf); - - let mut f = std::fs::File::create ("data.raw").unwrap (); - f.write_all (&pixels).unwrap (); - }, - Some ("decode") => - { - let jpeg = std::fs::read ("data.jpeg").unwrap (); - let start = Instant::now (); - let mut pixels = vec! []; - for _ in 0..30 - { - let mut decoder = zune_jpeg::JpegDecoder::new_with_options - ( - &jpeg, - zune_core::options::DecoderOptions::new_fast ().jpeg_set_out_colorspace (zune_core::colorspace::ColorSpace::YCbCr), - ); - decoder.decode_headers ().unwrap (); - pixels.resize (decoder.output_buffer_size ().unwrap (), 0); - - decoder.decode_into (&mut pixels).unwrap (); - } - let stop = Instant::now (); - let mpf_ycbcr = (stop - start).as_millis () as f32 / 30.0f32; - dbg! (mpf_ycbcr); - - std::fs::write ("raw.data", &pixels).unwrap (); - - let start = Instant::now (); - let mut pixels = vec! []; - for _ in 0..30 - { - let mut decoder = zune_jpeg::JpegDecoder::new_with_options - ( - &jpeg, - zune_core::options::DecoderOptions::new_fast ().jpeg_set_out_colorspace (zune_core::colorspace::ColorSpace::RGB), - ); - decoder.decode_headers ().unwrap (); - pixels.resize (decoder.output_buffer_size ().unwrap (), 0); - - decoder.decode_into (&mut pixels).unwrap (); - } - let stop = Instant::now (); - let mpf_rgb = (stop - start).as_millis () as f32 / 30.0f32; - dbg! (mpf_rgb); + println! ("{} ms", (stop - start).as_millis ()); }, Some (_) => eprintln! ("Unknown subcommand"), } @@ -252,7 +181,9 @@ enum MsgToGui enum MsgFromController { - Idle, + RepaintGui ((Vec , Instant)), + StartCapture, + StartJpegDecoder (JpegFrame), } #[derive (Clone)] @@ -262,17 +193,12 @@ struct JpegFrame time: Instant, } -struct Driver +struct Controller { - send: mpsc::SyncSender , - recv: mpsc::Receiver , - - gui_ctx: egui::Context, - send_to_gui: mpsc::SyncSender , - gui_rgba_gen: Instant, + gui_rgba_gen: Instant, gui_needs_frame: bool, - capture: task::Task , + capture: task::Task <(), ()>, jpeg_decoder: task::Task <(), Instant>, jpeg_needs_frame: bool, @@ -281,27 +207,16 @@ struct Driver jpeg_frame: JpegFrame, } -impl Driver +impl Controller { - fn new ( - send: mpsc::SyncSender , - recv: mpsc::Receiver , - gui_ctx: egui::Context, - send_to_gui: mpsc::SyncSender , - ) -> Self + fn new (now: Instant) -> Self { - let now = Instant::now (); - - Self { - send, - recv, - gui_ctx, - send_to_gui, + Self + { gui_needs_frame: false, - gui_rgba_gen: now, - capture: capture::Capture::new ().unwrap ().into (), + capture: ().into (), jpeg_decoder: ().into (), jpeg_needs_frame: false, @@ -315,6 +230,87 @@ impl Driver } } + fn handle_rgba_frame (&mut self, data: Vec , gen: Instant) + { + self.jpeg_decoder.stop (()).unwrap (); + self.rgba_frame = (data, gen); + } + + fn handle_capture (&mut self, jpeg: JpegFrame) + { + self.capture.stop (()).unwrap (); + self.jpeg_frame = jpeg; + } + + fn handle_gui_needs_frame (&mut self) + { + self.gui_needs_frame = true; + } + + fn poll (&mut self) -> Option + { + if self.gui_needs_frame && self.rgba_frame.1 > self.gui_rgba_gen + { + self.gui_needs_frame = false; + self.gui_rgba_gen = self.rgba_frame.1; + + Some (MsgFromController::RepaintGui (self.rgba_frame.clone ())) + } + else if self.gui_needs_frame && ! self.jpeg_decoder.is_running () && self.jpeg_frame.time > self.rgba_frame.1 + { + self.jpeg_decoder.start (self.jpeg_frame.time).unwrap (); + self.jpeg_needs_frame = false; + Some (MsgFromController::StartJpegDecoder (self.jpeg_frame.clone ())) + } + else if self.jpeg_needs_frame && ! self.capture.is_running () + { + self.capture.start (()).unwrap (); + Some (MsgFromController::StartCapture) + } + else if self.gui_needs_frame && self.jpeg_frame.time == self.rgba_frame.1 + { + self.jpeg_needs_frame = true; + None + } + else + { + None + } + } +} + +struct Driver +{ + send: mpsc::SyncSender , + recv: mpsc::Receiver , + + gui_ctx: egui::Context, + send_to_gui: mpsc::SyncSender , + + capture: Option , + + ctl: Controller, +} + +impl Driver +{ + fn new ( + send: mpsc::SyncSender , + recv: mpsc::Receiver , + gui_ctx: egui::Context, + send_to_gui: mpsc::SyncSender , + ) -> Self + { + Self { + send, + recv, + gui_ctx, + send_to_gui, + capture: Some (capture::Capture::new ().unwrap ()), + ctl: Controller::new (Instant::now ()), + } + } + fn run (&mut self) { let pool = rayon::ThreadPoolBuilder::new().build().unwrap (); @@ -325,73 +321,62 @@ impl Driver { MsgToController::DecodedJpegToRgba ((data, gen)) => { - self.jpeg_decoder.stop (()).unwrap (); - self.rgba_frame = (data, gen); + self.ctl.handle_rgba_frame (data, gen); }, MsgToController::GotCapture ((capture, jpeg)) => { - self.capture.stop (capture).unwrap (); - self.jpeg_frame = jpeg; + self.ctl.handle_capture (jpeg); + self.capture = Some (capture); }, MsgToController::GuiNeedsRgbaFrame => { - self.gui_needs_frame = true; + self.ctl.handle_gui_needs_frame (); }, } - if self.gui_needs_frame && self.rgba_frame.1 > self.gui_rgba_gen + while let Some (msg) = self.ctl.poll () { - self.send_to_gui.send (MsgToGui::NewRgbaFrame (self.rgba_frame.clone ())).unwrap (); - self.gui_needs_frame = false; - self.gui_rgba_gen = self.rgba_frame.1; - self.gui_ctx.request_repaint(); - } - - if - self.gui_needs_frame && - ! self.jpeg_decoder.is_running () && - self.jpeg_frame.time > self.rgba_frame.1 - { - let send = self.send.clone (); - let jpeg_frame = self.jpeg_frame.clone (); - - self.jpeg_decoder.start(jpeg_frame.time).unwrap (); - self.jpeg_needs_frame = false; - pool.spawn (move || + match msg { - let mut decoder = zune_jpeg::JpegDecoder::new_with_options (&jpeg_frame.data, zune_core::options::DecoderOptions::new_fast().jpeg_set_out_colorspace(zune_core::colorspace::ColorSpace::RGBA)); - - decoder.decode_headers().unwrap (); - let mut rgba = vec![0u8;decoder.output_buffer_size().unwrap ()]; - decoder.decode_into(&mut rgba).unwrap (); - - send.send (MsgToController::DecodedJpegToRgba ((rgba, jpeg_frame.time))).unwrap (); - }); - } - - if self.gui_needs_frame && self.jpeg_frame.time == self.rgba_frame.1 - { - self.jpeg_needs_frame = true; - } - - if self.jpeg_needs_frame && ! self.capture.is_running() - { - let mut capture = self.capture.start (()).unwrap (); - let send = self.send.clone (); - - pool.spawn (move || - { - let mut data = vec! [0u8; capture.size_image()]; - capture.wait_for_frame(&mut data).unwrap (); - - let frame = JpegFrame + MsgFromController::RepaintGui (rgba_frame) => { - data, - time: Instant::now (), - }; - - send.send (MsgToController::GotCapture ((capture, frame))).unwrap (); - }); + self.send_to_gui.send (MsgToGui::NewRgbaFrame (rgba_frame)).unwrap (); + self.gui_ctx.request_repaint(); + }, + MsgFromController::StartJpegDecoder (jpeg_frame) => + { + let send = self.send.clone (); + pool.spawn (move || + { + let mut decoder = zune_jpeg::JpegDecoder::new_with_options (&jpeg_frame.data, zune_core::options::DecoderOptions::new_fast().jpeg_set_out_colorspace(zune_core::colorspace::ColorSpace::RGBA)); + + decoder.decode_headers().unwrap (); + let mut rgba = vec![0u8;decoder.output_buffer_size().unwrap ()]; + decoder.decode_into(&mut rgba).unwrap (); + + send.send (MsgToController::DecodedJpegToRgba ((rgba, jpeg_frame.time))).unwrap (); + }); + }, + MsgFromController::StartCapture => + { + let mut capture = self.capture.take ().unwrap (); + let send = self.send.clone (); + + pool.spawn (move || + { + let mut data = vec! [0u8; capture.size_image()]; + capture.wait_for_frame(&mut data).unwrap (); + + let frame = JpegFrame + { + data, + time: Instant::now (), + }; + + send.send (MsgToController::GotCapture ((capture, frame))).unwrap (); + }); + } + } } } }