173 lines
4.5 KiB
Rust
173 lines
4.5 KiB
Rust
use anyhow::Result;
|
|
use sdl2::{
|
|
event::Event,
|
|
keyboard::Keycode,
|
|
pixels::PixelFormatEnum,
|
|
render::{Texture, TextureCreator},
|
|
surface::Surface,
|
|
video::WindowContext,
|
|
};
|
|
use std::sync::{
|
|
atomic::{AtomicUsize, Ordering},
|
|
Arc, Mutex,
|
|
};
|
|
use uvc::{Context, Device, DeviceHandle};
|
|
|
|
fn log_found_device(device: &Device) -> Result<()> {
|
|
let info = device.description()?;
|
|
|
|
println!(
|
|
"Found device: Bus {:03} Device {:03} : ID {:04x}:{:04x} {} ({})",
|
|
device.bus_number(),
|
|
device.device_address(),
|
|
info.vendor_id,
|
|
info.product_id,
|
|
info.product.unwrap_or_else(|| "Unknown".to_string()),
|
|
info.manufacturer.unwrap_or_else(|| "Unknown".to_string()),
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn log_device_settings(device: &DeviceHandle) {
|
|
println!(
|
|
"Scanning mode: {:?}\nAuto-exposure mode: {:?}\nAuto-exposure priority: {:?}\nAbsolute exposure: {:?}\nRelative exposure: {:?}\nAboslute focus: {:?}\nRelative focus: {:?}",
|
|
device.scanning_mode(),
|
|
device.ae_mode(),
|
|
device.ae_priority(),
|
|
device.exposure_abs(),
|
|
device.exposure_rel(),
|
|
device.focus_abs(),
|
|
device.focus_rel(),
|
|
);
|
|
}
|
|
|
|
fn main() {
|
|
let uvc_ctx = Context::new().expect("Could not create context");
|
|
let device = uvc_ctx
|
|
.find_device(Some(0x07ca), Some(0x313a), None)
|
|
.expect("Unable to find the AVerMedia PW313");
|
|
|
|
log_found_device(&device).unwrap();
|
|
|
|
let device = device.open().expect("Unable to open webcam.");
|
|
let format = device
|
|
.get_preferred_format(|x, y| {
|
|
if x.fps >= y.fps && x.width * x.height >= y.width * y.height {
|
|
x
|
|
} else {
|
|
y
|
|
}
|
|
})
|
|
.unwrap();
|
|
|
|
println!("Chosen format: {:?}", format);
|
|
|
|
let mut stream = device.get_stream_handle_with_format(format).unwrap();
|
|
log_device_settings(&device);
|
|
|
|
let frame_guard = Arc::new(Mutex::new(MyFrame::default()));
|
|
let frame_cpy = frame_guard.clone();
|
|
|
|
let counter = Arc::new(AtomicUsize::new(0));
|
|
let stream = stream
|
|
.start_stream(
|
|
move |frame_ref, count| {
|
|
let mut frame = frame_cpy.lock().unwrap();
|
|
|
|
*frame = MyFrame {
|
|
data: frame_ref.to_rgb().unwrap().to_bytes().to_owned(),
|
|
width: frame_ref.width(),
|
|
height: frame_ref.height(),
|
|
};
|
|
|
|
count.fetch_add(1, Ordering::SeqCst);
|
|
},
|
|
counter.clone(),
|
|
)
|
|
.expect("Could not start stream.");
|
|
|
|
let sdl_ctx = sdl2::init().unwrap();
|
|
let video_subsystem = sdl_ctx.video().unwrap();
|
|
|
|
let window = video_subsystem
|
|
.window("AVerMedia PW313 Web Camera", format.width, format.height)
|
|
.position_centered()
|
|
.build()
|
|
.unwrap();
|
|
|
|
let mut canvas = window
|
|
.into_canvas()
|
|
.present_vsync()
|
|
.accelerated()
|
|
.build()
|
|
.unwrap();
|
|
let texture_creator = canvas.texture_creator();
|
|
|
|
'main: loop {
|
|
for event in sdl_ctx.event_pump().unwrap().poll_iter() {
|
|
match event {
|
|
Event::Quit { .. }
|
|
| Event::KeyDown {
|
|
keycode: Some(Keycode::Escape),
|
|
..
|
|
} => break 'main,
|
|
_ => {}
|
|
}
|
|
}
|
|
|
|
let texture = do_thing(&frame_guard, &texture_creator);
|
|
match texture {
|
|
Some(thing) => {
|
|
canvas.copy(&thing, None, None).unwrap();
|
|
canvas.present();
|
|
}
|
|
None => {}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn do_thing<'a>(
|
|
guard: &'a Arc<Mutex<MyFrame>>,
|
|
creator: &'a TextureCreator<WindowContext>,
|
|
) -> Option<Texture<'a>> {
|
|
let mut frame = guard.lock().ok()?;
|
|
let width = frame.width;
|
|
let height = frame.height;
|
|
|
|
if !frame.data.is_empty() {
|
|
// Flip Image
|
|
let surface = Surface::from_data(
|
|
frame.data.as_mut_slice(),
|
|
width,
|
|
height,
|
|
width * (24 / 8),
|
|
PixelFormatEnum::RGB24,
|
|
)
|
|
.unwrap();
|
|
|
|
Some(Texture::from_surface(&surface, creator).ok()?)
|
|
} else {
|
|
None
|
|
}
|
|
|
|
// let surface = Surface::new(600, 800, PixelFormatEnum::RGB24).unwrap();
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
struct MyFrame {
|
|
data: Vec<u8>,
|
|
width: u32,
|
|
height: u32,
|
|
}
|
|
|
|
impl Default for MyFrame {
|
|
fn default() -> Self {
|
|
Self {
|
|
data: vec![],
|
|
width: 600,
|
|
height: 800,
|
|
}
|
|
}
|
|
}
|