use std::path::Path;
use std::sync::Arc;
use crate::callback::FrameCallback;
use crate::frame::Frame;
use crate::port::VmbRuntime;
use crate::types::{CameraHandle, FrameCallbackId, FrameSlotId};
use crate::{Result, VmbError};
const FEATURE_ACQUISITION_START: &str = "AcquisitionStart";
const FEATURE_ACQUISITION_STOP: &str = "AcquisitionStop";
struct CaptureSession {
callback_id: FrameCallbackId,
#[allow(dead_code)]
slots: Vec<FrameSlotId>,
}
pub struct Camera<R: VmbRuntime> {
runtime: Arc<R>,
handle: CameraHandle,
id: String,
session: Option<CaptureSession>,
}
impl<R: VmbRuntime> Camera<R> {
pub fn open(runtime: Arc<R>, id: &str) -> Result<Self> {
let handle = runtime.open_camera(id)?;
Ok(Self {
runtime,
handle,
id: id.to_string(),
session: None,
})
}
pub fn id(&self) -> &str {
&self.id
}
pub fn load_settings(&self, path: &Path) -> Result<()> {
self.runtime.load_settings(self.handle, path)
}
pub fn start_capture<F>(&mut self, num_buffers: usize, callback: F) -> Result<()>
where
F: for<'a> Fn(&Frame<'a>) + Send + Sync + 'static,
{
if self.session.is_some() {
return Err(VmbError::CaptureAlreadyRunning);
}
let payload = self.runtime.payload_size(self.handle)?;
let callback = Arc::new(FrameCallback::new(callback));
let callback_id = self.runtime.install_frame_callback(callback);
let mut slots: Vec<FrameSlotId> = Vec::with_capacity(num_buffers);
let result: Result<()> = (|| {
for _ in 0..num_buffers {
let slot = self.runtime.announce_frame(self.handle, payload)?;
slots.push(slot);
}
self.runtime.capture_start(self.handle)?;
for slot in &slots {
self.runtime.queue_frame(self.handle, *slot, callback_id)?;
}
self.runtime
.run_feature_command(self.handle, FEATURE_ACQUISITION_START)?;
Ok(())
})();
match result {
Ok(()) => {
self.session = Some(CaptureSession { callback_id, slots });
Ok(())
}
Err(e) => {
self.runtime.capture_end(self.handle);
self.runtime.capture_queue_flush(self.handle);
self.runtime.frame_revoke_all(self.handle);
self.runtime.uninstall_frame_callback(callback_id);
Err(e)
}
}
}
pub fn stop_capture(&mut self) -> Result<()> {
let Some(session) = self.session.take() else {
return Ok(());
};
let _ = self
.runtime
.run_feature_command(self.handle, FEATURE_ACQUISITION_STOP);
self.runtime.capture_end(self.handle);
self.runtime.capture_queue_flush(self.handle);
self.runtime.frame_revoke_all(self.handle);
self.runtime.uninstall_frame_callback(session.callback_id);
Ok(())
}
}
impl<R: VmbRuntime> Drop for Camera<R> {
fn drop(&mut self) {
if self.session.is_some() {
let _ = self.stop_capture();
}
self.runtime.close_camera(self.handle);
}
}
impl<R: VmbRuntime> std::fmt::Debug for Camera<R> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Camera")
.field("id", &self.id)
.field("handle", &self.handle)
.field("capture_running", &self.session.is_some())
.finish()
}
}