pub mod capture;
pub mod controls;
use self::controls::MediaFoundationControls;
use crate::errors::CameraError;
use crate::types::{CameraCapabilities, CameraControls, CameraFormat, CameraFrame};
use nokhwa::Camera;
type FrameCallback = Box<dyn Fn(CameraFrame) + Send + 'static>;
pub struct WindowsCamera {
pub nokhwa_camera: Camera,
pub mf_controls: MediaFoundationControls,
pub device_id: String,
pub callback: std::sync::Mutex<Option<FrameCallback>>,
}
impl WindowsCamera {
pub fn new(device_id: String, format: CameraFormat) -> Result<Self, CameraError> {
log::info!(
"Initializing Windows camera {} with MediaFoundation controls",
device_id
);
let nokhwa_camera = capture::initialize_camera(&device_id, format)?;
let device_index = device_id
.parse::<u32>()
.map_err(|_| CameraError::InitializationError("Invalid device ID".to_string()))?;
let mf_controls = MediaFoundationControls::new(device_index)?;
Ok(WindowsCamera {
nokhwa_camera,
mf_controls,
device_id,
callback: std::sync::Mutex::new(None),
})
}
pub fn capture_frame(&mut self) -> Result<CameraFrame, CameraError> {
let frame = capture::capture_frame(&mut self.nokhwa_camera, &self.device_id)?;
if let Some(ref cb) = *self.callback.lock().map_err(|_| CameraError::InitializationError("Mutex poisoned".to_string()))? {
cb(frame.clone());
}
Ok(frame)
}
pub fn apply_controls(
&mut self,
controls: &CameraControls,
) -> Result<Vec<String>, CameraError> {
self.mf_controls.apply_controls(controls)
}
pub fn get_controls(&self) -> Result<CameraControls, CameraError> {
self.mf_controls.get_controls()
}
pub fn test_capabilities(&self) -> Result<CameraCapabilities, CameraError> {
self.mf_controls.get_capabilities()
}
pub fn start_stream(&mut self) -> Result<(), CameraError> {
log::debug!("Opening camera stream for device {}", self.device_id);
self.nokhwa_camera
.open_stream()
.map_err(|e| CameraError::StreamError(format!("Failed to open stream: {}", e)))
}
pub fn stop_stream(&mut self) -> Result<(), CameraError> {
log::debug!("Stopping camera stream for device {}", self.device_id);
self.nokhwa_camera
.stop_stream()
.map_err(|e| CameraError::StreamError(format!("Failed to stop stream: {}", e)))
}
pub fn is_stream_open(&self) -> bool {
self.nokhwa_camera.is_stream_open()
}
pub fn is_available(&self) -> bool {
true
}
pub fn get_device_id(&self) -> &str {
&self.device_id
}
pub fn set_callback<F>(&self, callback: F) -> Result<(), CameraError>
where
F: Fn(CameraFrame) + Send + 'static,
{
*self.callback.lock().map_err(|_| CameraError::InitializationError("Mutex poisoned".to_string()))? = Some(Box::new(callback));
Ok(())
}
}
pub use capture::{capture_frame, initialize_camera, list_cameras};