80 lines
1.8 KiB
Rust
80 lines
1.8 KiB
Rust
/// Wraps non-thread-safe capture device like a v4l webcam
|
|
|
|
use linuxvideo::
|
|
{
|
|
format::
|
|
{
|
|
PixFormat,
|
|
PixelFormat,
|
|
},
|
|
Device,
|
|
stream::ReadStream,
|
|
};
|
|
|
|
pub struct Capture
|
|
{
|
|
size_image: usize,
|
|
stream: ReadStream,
|
|
}
|
|
|
|
impl Capture
|
|
{
|
|
pub fn new () -> Result <Self, Error>
|
|
{
|
|
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))?;
|
|
let interval = x.set_frame_interval(linuxvideo::Fract::new(1, 30)).unwrap ();
|
|
dbg! (interval);
|
|
dbg! (x.format ());
|
|
let size_image = usize::try_from (x.format ().size_image ()).unwrap ();
|
|
let stream = x.into_stream ()?;
|
|
|
|
Ok (Self
|
|
{
|
|
size_image,
|
|
stream,
|
|
})
|
|
}
|
|
|
|
pub fn size_image (&self) -> usize
|
|
{
|
|
self.size_image
|
|
}
|
|
|
|
/// Blocks until the capture device gets us a frame
|
|
|
|
pub fn wait_for_frame (&mut self, output: &mut [u8]) -> Result <usize, Error>
|
|
{
|
|
if output.len () < self.size_image ()
|
|
{
|
|
return Err (Error::OutputBufferTooSmall);
|
|
}
|
|
|
|
Ok (self.stream.dequeue (|view|
|
|
{
|
|
let bytesused = usize::try_from (view.bytesused ()).unwrap ();
|
|
let input = &view [0..bytesused];
|
|
let _ = &mut output [0..bytesused].copy_from_slice (&input);
|
|
Ok (input.len ())
|
|
})?)
|
|
}
|
|
|
|
pub fn will_block (&self) -> std::io::Result <bool>
|
|
{
|
|
self.stream.will_block ()
|
|
}
|
|
}
|
|
|
|
#[derive (Debug, thiserror::Error)]
|
|
pub enum Error
|
|
{
|
|
#[error ("I/O")]
|
|
Io (#[from] std::io::Error),
|
|
#[error ("output buffer too small")]
|
|
OutputBufferTooSmall,
|
|
}
|