extern crate libc;
extern crate kernel32;
use kernel32::GetLastError;
#[repr(C)]
struct SimpleCapParams {
buf: *mut libc::c_int,
width: libc::c_uint,
height: libc::c_uint,
}
unsafe impl Send for SimpleCapParams {}
pub fn num_devices() -> usize {
unsafe { countCaptureDevices() as usize }
}
pub fn version() -> u32 {
unsafe { ESCAPIVersion() }
}
pub fn init(index: usize, wdt: u32, hgt: u32, desired_fps: u64) -> Result<Device, Error> {
let mut data = vec![0; (wdt*hgt) as usize].into_boxed_slice();
let mut params = Box::new(SimpleCapParams {
width: wdt,
height: hgt,
buf: data.as_mut_ptr(),
});
let index = index as libc::c_uint;
if unsafe { initCapture(index, &mut *params) } == 1 {
assert!(unsafe { getCaptureErrorCode(index) } == 0);
Ok(Device {
device_idx: index,
buf: data,
params: params,
desired_fps: desired_fps,
})
} else {
Err(Error::CouldNotOpenDevice(unsafe { GetLastError() }))
}
}
pub struct Device {
device_idx: libc::c_uint,
buf: Box<[libc::c_int]>,
params: Box<SimpleCapParams>,
desired_fps: u64,
}
impl Device {
pub fn capture(&self) -> Result<&[u8], Error> {
unsafe { doCapture(self.device_idx) };
const MAX_TRY_ATTEMPTS: usize = 10;
for _ in 0..MAX_TRY_ATTEMPTS {
if unsafe { isCaptureDone(self.device_idx) } == 1 {
let data = &self.buf;
return Ok(unsafe { std::slice::from_raw_parts(data.as_ptr() as *const u8,
data.len() * 4) });
}
std::thread::sleep(std::time::Duration::from_millis(1000 / self.desired_fps));
}
Err(Error::CaptureTimeout)
}
pub fn name(&self) -> String {
let mut v = vec![0u8; 100];
unsafe { getCaptureDeviceName(self.device_idx, v.as_mut_ptr() as *mut i8, v.len() as libc::c_int) };
let null = v.iter().position(|&c| c == 0).expect("null termination character");
v.truncate(null);
String::from_utf8(v).expect("device name contains invalid utf8 characters")
}
pub fn capture_width(&self) -> u32 {
self.params.width
}
pub fn capture_height(&self) -> u32 {
self.params.height
}
}
impl Drop for Device {
fn drop(&mut self) {
unsafe { deinitCapture(self.device_idx) }
}
}
#[derive(Debug)]
pub enum Error {
CouldNotOpenDevice(libc::c_ulong),
CaptureTimeout,
}
impl std::fmt::Display for Error {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
match *self {
Error::CouldNotOpenDevice(i) => write!(fmt, "could not open camera device, errorcode: {}", i),
Error::CaptureTimeout => write!(fmt, "timeout during image capture"),
}
}
}
impl std::error::Error for Error {
fn description(&self) -> &str {
match *self {
Error::CouldNotOpenDevice(_) => "could not open camera device",
Error::CaptureTimeout => "timeout during image capture",
}
}
}
extern "C" {
fn countCaptureDevices() -> libc::c_int;
fn initCapture(_: libc::c_uint, _: *mut SimpleCapParams) -> libc::c_int;
fn deinitCapture(_: libc::c_uint);
fn doCapture(_: libc::c_uint) -> libc::c_int;
fn isCaptureDone(_: libc::c_uint) -> libc::c_int;
fn getCaptureDeviceName(_: libc::c_uint, _: *mut libc::c_char, _: libc::c_int);
fn ESCAPIVersion() -> libc::c_uint;
fn getCapturePropertyValue(_: libc::c_uint, _: libc::c_int) -> libc::c_float;
fn getCapturePropertyAuto(_: libc::c_uint, _: libc::c_int) -> libc::c_int;
fn setCaptureProperty(_: libc::c_uint, _: libc::c_int, _: libc::c_float, _: libc::c_int);
fn getCaptureErrorLine(_: libc::c_uint) -> libc::c_int;
fn getCaptureErrorCode(_: libc::c_uint) -> libc::c_int;
}