use crate::{
Camera, CameraControl, CameraFormat, CameraInfo, CaptureAPIBackend, FrameFormat,
KnownCameraControls, NokhwaError, Resolution,
};
use image::{ImageBuffer, Rgb};
use parking_lot::FairMutex;
use std::{
any::Any,
collections::HashMap,
ops::Deref,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
};
#[cfg_attr(feature = "docs-features", doc(cfg(feature = "output-threaded")))]
#[derive(Clone)]
pub struct ThreadedCamera {
camera: Arc<FairMutex<Camera>>,
frame_callback: Arc<FairMutex<Option<fn(ImageBuffer<Rgb<u8>, Vec<u8>>)>>>,
last_frame_captured: Arc<FairMutex<ImageBuffer<Rgb<u8>, Vec<u8>>>>,
die_bool: Arc<AtomicBool>,
}
impl ThreadedCamera {
pub fn new(index: usize, format: Option<CameraFormat>) -> Result<Self, NokhwaError> {
ThreadedCamera::with_backend(index, format, CaptureAPIBackend::Auto)
}
pub fn with_backend(
index: usize,
format: Option<CameraFormat>,
backend: CaptureAPIBackend,
) -> Result<Self, NokhwaError> {
let camera = Arc::new(FairMutex::new(Camera::with_backend(
index, format, backend,
)?));
let format = match format {
Some(fmt) => fmt,
None => CameraFormat::default(),
};
let frame_callback = Arc::new(FairMutex::new(None));
let die_bool = Arc::new(AtomicBool::new(false));
let holding_cell = Arc::new(FairMutex::new(ImageBuffer::new(
format.width(),
format.height(),
)));
let die_clone = die_bool.clone();
let camera_clone = camera.clone();
let callback_clone = frame_callback.clone();
let holding_cell_clone = holding_cell.clone();
std::thread::spawn(move || {
camera_frame_thread_loop(camera_clone, callback_clone, holding_cell_clone, die_clone)
});
Ok(ThreadedCamera {
camera,
frame_callback,
last_frame_captured: holding_cell,
die_bool,
})
}
pub fn new_with(
index: usize,
width: u32,
height: u32,
fps: u32,
fourcc: FrameFormat,
backend: CaptureAPIBackend,
) -> Result<Self, NokhwaError> {
let camera_format = CameraFormat::new_from(width, height, fourcc, fps);
ThreadedCamera::with_backend(index, Some(camera_format), backend)
}
#[must_use]
pub fn index(&self) -> usize {
self.camera.lock().index()
}
pub fn set_index(&mut self, new_idx: usize) -> Result<(), NokhwaError> {
self.camera.lock().set_index(new_idx)
}
#[must_use]
pub fn backend(&self) -> CaptureAPIBackend {
self.camera.lock().backend()
}
pub fn set_backend(&mut self, new_backend: CaptureAPIBackend) -> Result<(), NokhwaError> {
self.camera.lock().set_backend(new_backend)
}
#[must_use]
pub fn info(&self) -> CameraInfo {
self.camera.lock().info().clone()
}
#[must_use]
pub fn camera_format(&self) -> CameraFormat {
self.camera.lock().camera_format()
}
pub fn set_camera_format(&mut self, new_fmt: CameraFormat) -> Result<(), NokhwaError> {
*self.last_frame_captured.lock() = ImageBuffer::new(new_fmt.width(), new_fmt.height());
self.camera.lock().set_camera_format(new_fmt)
}
pub fn compatible_list_by_resolution(
&mut self,
fourcc: FrameFormat,
) -> Result<HashMap<Resolution, Vec<u32>>, NokhwaError> {
self.camera.lock().compatible_list_by_resolution(fourcc)
}
pub fn compatible_fourcc(&mut self) -> Result<Vec<FrameFormat>, NokhwaError> {
self.camera.lock().compatible_fourcc()
}
#[must_use]
pub fn resolution(&self) -> Resolution {
self.camera.lock().resolution()
}
pub fn set_resolution(&mut self, new_res: Resolution) -> Result<(), NokhwaError> {
*self.last_frame_captured.lock() = ImageBuffer::new(new_res.width(), new_res.height());
self.camera.lock().set_resolution(new_res)
}
#[must_use]
pub fn frame_rate(&self) -> u32 {
self.camera.lock().frame_rate()
}
pub fn set_frame_rate(&mut self, new_fps: u32) -> Result<(), NokhwaError> {
self.camera.lock().set_frame_rate(new_fps)
}
#[must_use]
pub fn frame_format(&self) -> FrameFormat {
self.camera.lock().frame_format()
}
pub fn set_frame_format(&mut self, fourcc: FrameFormat) -> Result<(), NokhwaError> {
self.camera.lock().set_frame_format(fourcc)
}
pub fn supported_camera_controls(&self) -> Result<Vec<KnownCameraControls>, NokhwaError> {
self.camera.lock().supported_camera_controls()
}
pub fn camera_controls(&self) -> Result<Vec<CameraControl>, NokhwaError> {
let known_controls = self.supported_camera_controls()?;
let maybe_camera_controls = known_controls
.iter()
.map(|x| self.camera_control(*x))
.filter(Result::is_ok)
.map(Result::unwrap)
.collect::<Vec<CameraControl>>();
Ok(maybe_camera_controls)
}
pub fn camera_controls_string(&self) -> Result<HashMap<String, CameraControl>, NokhwaError> {
let known_controls = self.supported_camera_controls()?;
let maybe_camera_controls = known_controls
.iter()
.map(|x| (x.to_string(), self.camera_control(*x)))
.filter(|(_, x)| x.is_ok())
.map(|(c, x)| (c, Result::unwrap(x)))
.collect::<Vec<(String, CameraControl)>>();
let mut control_map = HashMap::with_capacity(maybe_camera_controls.len());
for (kc, cc) in maybe_camera_controls.into_iter() {
control_map.insert(kc, cc);
}
Ok(control_map)
}
pub fn camera_controls_known_camera_controls(
&self,
) -> Result<HashMap<KnownCameraControls, CameraControl>, NokhwaError> {
let known_controls = self.supported_camera_controls()?;
let maybe_camera_controls = known_controls
.iter()
.map(|x| (*x, self.camera_control(*x)))
.filter(|(_, x)| x.is_ok())
.map(|(c, x)| (c, Result::unwrap(x)))
.collect::<Vec<(KnownCameraControls, CameraControl)>>();
let mut control_map = HashMap::with_capacity(maybe_camera_controls.len());
for (kc, cc) in maybe_camera_controls.into_iter() {
control_map.insert(kc, cc);
}
Ok(control_map)
}
pub fn camera_control(
&self,
control: KnownCameraControls,
) -> Result<CameraControl, NokhwaError> {
self.camera.lock().camera_control(control)
}
pub fn set_camera_control(&mut self, control: CameraControl) -> Result<(), NokhwaError> {
self.camera.lock().set_camera_control(control)
}
pub fn raw_supported_camera_controls(&self) -> Result<Vec<Box<dyn Any>>, NokhwaError> {
self.camera.lock().raw_supported_camera_controls()
}
pub fn raw_camera_control(&self, control: &dyn Any) -> Result<Box<dyn Any>, NokhwaError> {
self.camera.lock().raw_camera_control(control)
}
pub fn set_raw_camera_control(
&mut self,
control: &dyn Any,
value: &dyn Any,
) -> Result<(), NokhwaError> {
self.camera.lock().set_raw_camera_control(control, value)
}
pub fn open_stream(
&mut self,
callback: fn(ImageBuffer<Rgb<u8>, Vec<u8>>),
) -> Result<(), NokhwaError> {
*self.frame_callback.lock() = Some(callback);
self.camera.lock().open_stream()
}
pub fn set_callback(&mut self, callback: fn(ImageBuffer<Rgb<u8>, Vec<u8>>)) {
*self.frame_callback.lock() = Some(callback);
}
pub fn poll_frame(&mut self) -> Result<ImageBuffer<Rgb<u8>, Vec<u8>>, NokhwaError> {
self.camera.lock().frame()
}
pub fn last_frame(&self) -> ImageBuffer<Rgb<u8>, Vec<u8>> {
self.last_frame_captured.lock().clone()
}
pub fn is_stream_open(&self) -> bool {
self.camera.lock().is_stream_open()
}
pub fn stop_stream(&mut self) -> Result<(), NokhwaError> {
self.camera.lock().stop_stream()
}
}
impl Drop for ThreadedCamera {
fn drop(&mut self) {
let _ = self.stop_stream();
self.die_bool.store(true, Ordering::SeqCst);
}
}
fn camera_frame_thread_loop(
camera: Arc<FairMutex<Camera>>,
callback: Arc<FairMutex<Option<fn(ImageBuffer<Rgb<u8>, Vec<u8>>)>>>,
holding_cell: Arc<FairMutex<ImageBuffer<Rgb<u8>, Vec<u8>>>>,
die_bool: Arc<AtomicBool>,
) {
loop {
if let Ok(img) = camera.lock().frame() {
*holding_cell.lock() = img.clone();
if let Some(cb) = callback.lock().deref() {
cb(img)
}
}
if die_bool.load(Ordering::SeqCst) {
break;
}
}
}