Skip to content

Commit

Permalink
New platform API to simply ApiBackend and allow for custom backends o…
Browse files Browse the repository at this point in the history
…n the fly
  • Loading branch information
l1npengtul committed Dec 11, 2024
1 parent 096880e commit 0e2d000
Show file tree
Hide file tree
Showing 18 changed files with 215 additions and 197 deletions.
2 changes: 1 addition & 1 deletion nokhwa-bindings-linux/src/v4l2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use nokhwa_core::properties::{CameraProperties, CameraPropertyFlag, CameraProper
use nokhwa_core::{define_back_and_fourth_control, define_back_and_fourth_frame_format};
use nokhwa_core::error::{NokhwaError, NokhwaResult};
use nokhwa_core::frame_format::FrameFormat;
use nokhwa_core::types::{CameraFormat, CameraIndex, CameraInfo, FrameRate, Resolution};
use nokhwa_core::types::{CameraFormat, CameraIndex, CameraInformation, FrameRate, Resolution};

const NULL_FCC: &'static [u8; 4] = &[0x00, 0x00, 0x00, 0x00];

Expand Down
14 changes: 7 additions & 7 deletions nokhwa-bindings-macos/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ mod internal {
use nokhwa_core::{
error::NokhwaError,
types::{
ApiBackend, CameraFormat, CameraIndex, CameraInfo,
ApiBackend, CameraFormat, CameraIndex, CameraInformation,
FrameFormat,
KnownCameraControlFlag, Resolution,
},
Expand Down Expand Up @@ -509,7 +509,7 @@ mod internal {
}

// fuck it, use deprecated APIs
pub fn query_avfoundation() -> Result<Vec<CameraInfo>, NokhwaError> {
pub fn query_avfoundation() -> Result<Vec<CameraInformation>, NokhwaError> {
Ok(AVCaptureDeviceDiscoverySession::new(vec![
AVCaptureDeviceType::UltraWide,
AVCaptureDeviceType::WideAngle,
Expand All @@ -520,7 +520,7 @@ mod internal {
.devices())
}

pub fn get_raw_device_info(index: CameraIndex, device: *mut Object) -> CameraInfo {
pub fn get_raw_device_info(index: CameraIndex, device: *mut Object) -> CameraInformation {
let name = nsstr_to_str(unsafe { msg_send![device, localizedName] });
let manufacturer = nsstr_to_str(unsafe { msg_send![device, manufacturer] });
let position: AVCaptureDevicePosition = unsafe { msg_send![device, position] };
Expand All @@ -533,7 +533,7 @@ mod internal {
);
let misc = nsstr_to_str(unsafe { msg_send![device, uniqueID] });

CameraInfo::new(name.as_ref(), &description, misc.as_ref(), index)
CameraInformation::new(name.as_ref(), &description, misc.as_ref(), index)
}

#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
Expand Down Expand Up @@ -818,7 +818,7 @@ mod internal {
])
}

pub fn devices(&self) -> Vec<CameraInfo> {
pub fn devices(&self) -> Vec<CameraInformation> {
let device_ns_array: *mut Object = unsafe { msg_send![self.inner, devices] };
let objects_len: NSUInteger = unsafe { NSArray::count(device_ns_array) };
let mut devices = Vec::with_capacity(objects_len as usize);
Expand All @@ -836,7 +836,7 @@ mod internal {

pub struct AVCaptureDevice {
inner: *mut Object,
device: CameraInfo,
device: CameraInformation,
locked: bool,
}

Expand Down Expand Up @@ -890,7 +890,7 @@ mod internal {
})
}

pub fn info(&self) -> &CameraInfo {
pub fn info(&self) -> &CameraInformation {
&self.device
}

Expand Down
14 changes: 7 additions & 7 deletions nokhwa-bindings-windows/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
pub mod wmf {
use nokhwa_core::error::NokhwaError;
use nokhwa_core::types::{
ApiBackend, CameraFormat, CameraIndex, CameraInfo,
ApiBackend, CameraFormat, CameraIndex, CameraInformation,
FrameFormat, KnownCameraControlFlag, Resolution,
};
use once_cell::sync::Lazy;
Expand Down Expand Up @@ -295,7 +295,7 @@ pub mod wmf {
fn activate_to_descriptors(
index: CameraIndex,
imf_activate: &IMFActivate,
) -> Result<CameraInfo, NokhwaError> {
) -> Result<CameraInformation, NokhwaError> {
let mut pwstr_name = PWSTR(&mut 0_u16);
let mut len_pwstrname = 0;
let mut pwstr_symlink = PWSTR(&mut 0_u16);
Expand Down Expand Up @@ -357,15 +357,15 @@ pub mod wmf {
})?
};

Ok(CameraInfo::new(
Ok(CameraInformation::new(
&name,
"MediaFoundation Camera",
&symlink,
index,
))
}

pub fn query_media_foundation_descriptors() -> Result<Vec<CameraInfo>, NokhwaError> {
pub fn query_media_foundation_descriptors() -> Result<Vec<CameraInformation>, NokhwaError> {
let mut device_list = vec![];

for (index, activate_ptr) in query_activate_pointers()?.into_iter().enumerate() {
Expand Down Expand Up @@ -421,7 +421,7 @@ pub mod wmf {

pub struct MediaFoundationDevice {
is_open: Cell<bool>,
device_specifier: CameraInfo,
device_specifier: CameraInformation,
device_format: CameraFormat,
source_reader: IMFSourceReader,
}
Expand Down Expand Up @@ -1226,7 +1226,7 @@ pub mod wmf {
pub mod wmf {
use nokhwa_core::error::NokhwaError;
use nokhwa_core::types::{
CameraFormat, CameraIndex, CameraInfo,
CameraFormat, CameraIndex, CameraInformation,
};
use std::borrow::Cow;
use nokhwa_core::properties::{CameraControl, ControlValue, KnownCameraControl};
Expand All @@ -1243,7 +1243,7 @@ pub mod wmf {
))
}

pub fn query_msmf() -> Result<Vec<CameraInfo>, NokhwaError> {
pub fn query_msmf() -> Result<Vec<CameraInformation>, NokhwaError> {
Err(NokhwaError::NotImplementedError(
"Not on windows".to_string(),
))
Expand Down
76 changes: 27 additions & 49 deletions nokhwa-core/src/camera.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,10 @@
use crate::error::{NokhwaError, NokhwaResult};
use crate::error::{NokhwaError};
use crate::frame_format::FrameFormat;
use crate::properties::{ControlId, ControlValue, Properties};
use crate::types::{CameraFormat, CameraIndex, FrameRate, Resolution};
use crate::types::{CameraFormat, FrameRate, Resolution};
use std::collections::HashMap;
use crate::frame_buffer::FrameBuffer;
use crate::stream::Stream;

pub trait Open {
fn open(index: CameraIndex) -> NokhwaResult<Self> where Self: Sized;
}

#[cfg(feature = "async")]
pub trait AsyncOpen: Sized {
async fn open_async(index: CameraIndex) -> NokhwaResult<Self>;
}


pub trait Setting {
fn enumerate_formats(&self) -> Result<Vec<CameraFormat>, NokhwaError>;

Expand All @@ -35,53 +24,42 @@ pub trait Setting {
) -> Result<(), NokhwaError>;
}

// #[cfg(feature = "async")]
// pub trait AsyncSetting {
// async fn set_format_async(&self, camera_format: CameraFormat) -> Result<(), NokhwaError>;
//
// async fn set_property_async(
// &mut self,
// property: &CameraPropertyId,
// value: CameraPropertyValue,
// ) -> Result<(), NokhwaError>;
//
// def_camera_props_async!(
// Brightness,
// Contrast,
// Hue,
// Saturation,
// Sharpness,
// Gamma,
// WhiteBalance,
// BacklightCompensation,
// Pan,
// Tilt,
// Zoom,
// Exposure,
// Iris,
// Focus,
// Facing,
// );
// }
#[cfg(feature = "async")]
pub trait AsyncSetting {
async fn enumerate_formats_async(&self) -> Result<Vec<CameraFormat>, NokhwaError>;

async fn enumerate_resolution_and_frame_rates_async(
&self,
frame_format: FrameFormat,
) -> Result<HashMap<Resolution, Vec<FrameRate>>, NokhwaError>;

async fn set_format_async(&self, camera_format: CameraFormat) -> Result<(), NokhwaError>;

async fn properties_async(&self) -> &Properties;

async fn set_property_async(
&mut self,
property: &ControlId,
value: ControlValue,
) -> Result<(), NokhwaError>;
}

pub trait Capture {
// Implementations MUST guarantee that there can only ever be one stream open at once.
fn open_stream(&mut self) -> Result<Stream, NokhwaError>;

// Implementations MUST be multi-close tolerant.
fn close_stream(&mut self) -> Result<(), NokhwaError>;
}

#[cfg(feature = "async")]
pub trait AsyncStream {
async fn open_stream(&mut self) -> Result<(), NokhwaError>;
async fn open_stream_async(&mut self) -> Result<Stream, NokhwaError>;

async fn await_frame(&mut self) -> Result<FrameBuffer, NokhwaError>;

async fn close_stream(&mut self) -> Result<(), NokhwaError>;
async fn close_stream_async(&mut self) -> Result<(), NokhwaError>;
}

pub trait CameraVtable: Setting + Capture {}

pub trait Camera: Open + CameraVtable {}
pub trait Camera: Setting + Capture {}

#[cfg(feature = "async")]
pub trait AsyncCapture: Camera + AsyncOpen + AsyncStream {}
pub trait AsyncCamera: Camera + AsyncSetting + AsyncStream {}
5 changes: 4 additions & 1 deletion nokhwa-core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use crate::{frame_format::FrameFormat, types::ApiBackend};
use std::fmt::{Debug};
use thiserror::Error;
use crate::platform::Backends;

pub type NokhwaResult<T> = Result<T, NokhwaError>;

Expand Down Expand Up @@ -56,9 +57,11 @@ pub enum NokhwaError {
#[error("Could not stop stream: {0}")]
StreamShutdownError(String),
#[error("This operation is not supported by backend {0}.")]
UnsupportedOperationError(ApiBackend),
UnsupportedOperationError(Backends),
#[error("This operation is not implemented yet: {0}")]
NotImplementedError(String),
#[error("Failed To Convert: {0}")]
ConversionError(String),
#[error("Permission denied by user.")]
PermissionDenied,
}
1 change: 1 addition & 0 deletions nokhwa-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,4 @@ pub mod traits;
pub mod types;
pub mod utils;
pub mod stream;
mod platform;
39 changes: 39 additions & 0 deletions nokhwa-core/src/platform.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use crate::camera::{AsyncCamera, Camera};
use crate::error::NokhwaResult;
use crate::types::{CameraIndex, CameraInformation};

#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq)]
pub enum Backends {
Video4Linux2,
WebWASM,
AVFoundation,
MicrosoftMediaFoundation,
Custom(&'static str)
}

pub trait PlatformTrait {
const PLATFORM: Backends;
type Camera: Camera;


fn block_on_permission(&mut self) -> NokhwaResult<()>;

fn check_permission_given(&mut self) -> bool;

fn query(&mut self) -> NokhwaResult<Vec<CameraInformation>>;

fn open(&mut self, index: &CameraIndex) -> NokhwaResult<Self::Camera>;
}

#[cfg(feature = "async")]
pub trait AsyncPlatformTrait {
const PLATFORM: Backends;
type AsyncCamera: AsyncCamera;


async fn await_permission(&mut self) -> NokhwaResult<()>;

async fn query_async(&mut self) -> NokhwaResult<Vec<CameraInformation>>;

async fn open_async (&mut self, index: &CameraIndex) -> NokhwaResult<Self::AsyncCamera>;
}
10 changes: 0 additions & 10 deletions nokhwa-core/src/query.rs

This file was deleted.

49 changes: 28 additions & 21 deletions nokhwa-core/src/stream.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::error::{NokhwaError, NokhwaResult};
use crate::frame_buffer::FrameBuffer;
use flume::Receiver;
use flume::{Receiver, TryRecvError};
use std::sync::Arc;

pub trait StreamInnerTrait {
Expand All @@ -26,47 +26,54 @@ impl Stream {
// }
// }

pub fn poll_frame(&self) -> NokhwaResult<FrameBuffer> {
pub fn check_disconnected(&self) -> NokhwaResult<()> {
if self.inner.receiver().is_disconnected() {
return Err(NokhwaError::ReadFrameError(
"stream is disconnected!".to_string(),
));
))
}
Ok(())
}

pub fn poll_frame(&self) -> NokhwaResult<FrameBuffer> {
self.check_disconnected()?;

self.inner
.receiver()
.recv()
.map_err(|why| NokhwaError::ReadFrameError(why.to_string()))
}

pub fn try_poll_frame(&self) -> Option<NokhwaResult<FrameBuffer>> {
if self.inner.receiver().is_disconnected() {
return Some(Err(NokhwaError::ReadFrameError(
"stream is disconnected!".to_string(),
)));
}
pub fn try_poll_frame(&self) -> NokhwaResult<Option<FrameBuffer>> {
self.check_disconnected()?;

if self.inner.receiver().is_empty() {
return None;
return Ok(None);
}

let possible_frame = self.inner
.receiver()
.try_recv();

match possible_frame {
Ok(f) => Ok(Some(f)),
Err(why) => {
match why {
TryRecvError::Empty => Ok(None),
TryRecvError::Disconnected => Err(NokhwaError::ReadFrameError(
"stream is disconnected!".to_string(),
))
}
}
}

Some(
self.inner
.receiver()
.try_recv()
.map_err(|why| NokhwaError::ReadFrameError(why.to_string())),
)
}

#[cfg(feature = "async")]
pub async fn await_frame(&self) -> NokhwaResult<FrameBuffer> {
use futures::TryFutureExt;

if self.inner.receiver().is_disconnected() {
return Err(NokhwaError::ReadFrameError(
"stream is disconnected!".to_string(),
));
}
self.check_disconnected()?;

self.inner
.receiver()
Expand Down
Loading

0 comments on commit 0e2d000

Please sign in to comment.