use std::{
collections::HashMap,
ffi::CStr,
io,
marker::PhantomData,
ops::{Deref, DerefMut},
ptr::NonNull,
sync::Mutex,
};
use libcamera_sys::*;
use crate::{
control::{ControlInfoMap, ControlList, PropertyList},
request::Request,
stream::{StreamConfigurationRef, StreamRole},
utils::Immutable,
};
#[derive(Debug, Clone, Copy)]
pub enum CameraConfigurationStatus {
Valid,
Adjusted,
Invalid,
}
impl CameraConfigurationStatus {
pub fn is_valid(&self) -> bool {
matches!(self, Self::Valid)
}
pub fn is_adjusted(&self) -> bool {
matches!(self, Self::Adjusted)
}
pub fn is_invalid(&self) -> bool {
matches!(self, Self::Invalid)
}
}
impl TryFrom<libcamera_camera_configuration_status_t> for CameraConfigurationStatus {
type Error = ();
fn try_from(value: libcamera_camera_configuration_status_t) -> Result<Self, Self::Error> {
match value {
libcamera_camera_configuration_status::LIBCAMERA_CAMERA_CONFIGURATION_STATUS_VALID => Ok(Self::Valid),
libcamera_camera_configuration_status::LIBCAMERA_CAMERA_CONFIGURATION_STATUS_ADJUSTED => Ok(Self::Adjusted),
libcamera_camera_configuration_status::LIBCAMERA_CAMERA_CONFIGURATION_STATUS_INVALID => Ok(Self::Invalid),
_ => Err(()),
}
}
}
pub struct CameraConfiguration {
ptr: NonNull<libcamera_camera_configuration_t>,
}
impl CameraConfiguration {
pub(crate) unsafe fn from_ptr(ptr: NonNull<libcamera_camera_configuration_t>) -> Self {
Self { ptr }
}
pub fn get(&self, index: usize) -> Option<Immutable<StreamConfigurationRef<'_>>> {
let ptr = unsafe { libcamera_camera_configuration_at(self.ptr.as_ptr(), index as _) };
NonNull::new(ptr).map(|p| Immutable(unsafe { StreamConfigurationRef::from_ptr(p) }))
}
pub fn get_mut(&mut self, index: usize) -> Option<StreamConfigurationRef<'_>> {
let ptr = unsafe { libcamera_camera_configuration_at(self.ptr.as_ptr(), index as _) };
NonNull::new(ptr).map(|p| unsafe { StreamConfigurationRef::from_ptr(p) })
}
pub fn len(&self) -> usize {
unsafe { libcamera_camera_configuration_size(self.ptr.as_ptr()) }
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn validate(&mut self) -> CameraConfigurationStatus {
unsafe { libcamera_camera_configuration_validate(self.ptr.as_ptr()) }
.try_into()
.unwrap()
}
}
impl core::fmt::Debug for CameraConfiguration {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut list = f.debug_list();
for i in 0..self.len() {
list.entry(&self.get(i).unwrap().0);
}
list.finish()
}
}
impl Drop for CameraConfiguration {
fn drop(&mut self) {
unsafe { libcamera_camera_configuration_destroy(self.ptr.as_ptr()) }
}
}
pub struct Camera<'d> {
pub(crate) ptr: NonNull<libcamera_camera_t>,
_phantom: PhantomData<&'d ()>,
}
impl<'d> Camera<'d> {
pub(crate) unsafe fn from_ptr(ptr: NonNull<libcamera_camera_t>) -> Self {
Self {
ptr,
_phantom: Default::default(),
}
}
pub fn id(&self) -> &str {
unsafe { CStr::from_ptr(libcamera_camera_id(self.ptr.as_ptr())) }
.to_str()
.unwrap()
}
pub fn controls(&self) -> &ControlInfoMap {
unsafe {
ControlInfoMap::from_ptr(NonNull::new(libcamera_camera_controls(self.ptr.as_ptr()).cast_mut()).unwrap())
}
}
pub fn properties(&self) -> &PropertyList {
unsafe {
PropertyList::from_ptr(NonNull::new(libcamera_camera_properties(self.ptr.as_ptr()).cast_mut()).unwrap())
}
}
pub fn generate_configuration(&self, roles: &[StreamRole]) -> Option<CameraConfiguration> {
let roles: Vec<libcamera_stream_role::Type> = roles.iter().map(|r| (*r).into()).collect();
let cfg =
unsafe { libcamera_camera_generate_configuration(self.ptr.as_ptr(), roles.as_ptr(), roles.len() as _) };
NonNull::new(cfg).map(|p| unsafe { CameraConfiguration::from_ptr(p) })
}
pub fn acquire(&self) -> io::Result<ActiveCamera<'_>> {
let ret = unsafe { libcamera_camera_acquire(self.ptr.as_ptr()) };
if ret < 0 {
Err(io::Error::from_raw_os_error(ret))
} else {
Ok(unsafe { ActiveCamera::from_ptr(NonNull::new(libcamera_camera_copy(self.ptr.as_ptr())).unwrap()) })
}
}
}
impl<'d> Drop for Camera<'d> {
fn drop(&mut self) {
unsafe { libcamera_camera_destroy(self.ptr.as_ptr()) }
}
}
extern "C" fn camera_request_completed_cb(ptr: *mut core::ffi::c_void, req: *mut libcamera_request_t) {
let mut state = unsafe { &*(ptr as *const Mutex<ActiveCameraState<'_>>) }
.lock()
.unwrap();
let req = state.requests.remove(&req).unwrap();
if let Some(cb) = &mut state.request_completed_cb {
cb(req);
}
}
#[derive(Default)]
struct ActiveCameraState<'d> {
requests: HashMap<*mut libcamera_request_t, Request>,
request_completed_cb: Option<Box<dyn FnMut(Request) + Send + 'd>>,
}
pub struct ActiveCamera<'d> {
cam: Camera<'d>,
request_completed_handle: *mut libcamera_callback_handle_t,
state: Box<Mutex<ActiveCameraState<'d>>>,
}
impl<'d> ActiveCamera<'d> {
pub(crate) unsafe fn from_ptr(ptr: NonNull<libcamera_camera_t>) -> Self {
let mut state = Box::new(Mutex::new(ActiveCameraState::default()));
let request_completed_handle = unsafe {
libcamera_camera_request_completed_connect(
ptr.as_ptr(),
Some(camera_request_completed_cb),
state.as_mut() as *mut Mutex<ActiveCameraState<'_>> as *mut _,
)
};
Self {
cam: Camera::from_ptr(ptr),
request_completed_handle,
state,
}
}
pub fn on_request_completed(&mut self, cb: impl FnMut(Request) + Send + 'd) {
let mut state = self.state.lock().unwrap();
state.request_completed_cb = Some(Box::new(cb));
}
pub fn configure(&mut self, config: &mut CameraConfiguration) -> io::Result<()> {
let ret = unsafe { libcamera_camera_configure(self.ptr.as_ptr(), config.ptr.as_ptr()) };
if ret < 0 {
Err(io::Error::from_raw_os_error(ret))
} else {
Ok(())
}
}
pub fn create_request(&mut self, cookie: Option<u64>) -> Option<Request> {
let req = unsafe { libcamera_camera_create_request(self.ptr.as_ptr(), cookie.unwrap_or(0)) };
NonNull::new(req).map(|p| unsafe { Request::from_ptr(p) })
}
pub fn queue_request(&self, req: Request) -> io::Result<()> {
let ptr = req.ptr.as_ptr();
self.state.lock().unwrap().requests.insert(ptr, req);
let ret = unsafe { libcamera_camera_queue_request(self.ptr.as_ptr(), ptr) };
if ret < 0 {
Err(io::Error::from_raw_os_error(ret))
} else {
Ok(())
}
}
pub fn start(&mut self, controls: Option<&ControlList>) -> io::Result<()> {
let ctrl_ptr = controls.map(|c| c.ptr()).unwrap_or(core::ptr::null_mut());
let ret = unsafe { libcamera_camera_start(self.ptr.as_ptr(), ctrl_ptr) };
if ret < 0 {
Err(io::Error::from_raw_os_error(ret))
} else {
Ok(())
}
}
pub fn stop(&mut self) -> io::Result<()> {
let ret = unsafe { libcamera_camera_stop(self.ptr.as_ptr()) };
if ret < 0 {
Err(io::Error::from_raw_os_error(ret))
} else {
Ok(())
}
}
}
impl<'d> Deref for ActiveCamera<'d> {
type Target = Camera<'d>;
fn deref(&self) -> &Self::Target {
&self.cam
}
}
impl<'d> DerefMut for ActiveCamera<'d> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.cam
}
}
impl<'d> Drop for ActiveCamera<'d> {
fn drop(&mut self) {
unsafe {
libcamera_camera_request_completed_disconnect(self.ptr.as_ptr(), self.request_completed_handle);
libcamera_camera_stop(self.ptr.as_ptr());
libcamera_camera_release(self.ptr.as_ptr());
}
}
}