New platform API to simply ApiBackend and allow for custom backends on the fly

This commit is contained in:
l1npengtul
2024-12-11 14:46:13 +09:00
parent 096880eb7e
commit 0e2d000842
18 changed files with 215 additions and 197 deletions
+27 -49
View File
@@ -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>;
@@ -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 {}
+4 -1
View File
@@ -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>;
@@ -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
View File
@@ -35,3 +35,4 @@ pub mod traits;
pub mod types;
pub mod utils;
pub mod stream;
mod platform;
+39
View File
@@ -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
View File
@@ -1,10 +0,0 @@
use crate::error::NokhwaError;
use crate::types::CameraInfo;
pub trait Query {
fn query() -> Result<Vec<CameraInfo>, NokhwaError>;
}
pub trait AsyncQuery {
async fn query() -> Result<Vec<CameraInfo>, NokhwaError>;
}
+28 -21
View File
@@ -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 {
@@ -26,12 +26,17 @@ 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()
@@ -39,34 +44,36 @@ impl Stream {
.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()
+53 -53
View File
@@ -414,23 +414,23 @@ impl Display for CameraFormat {
/// `index` is a camera's index given to it by (usually) the OS usually in the order it is known to the system.
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct CameraInfo {
pub struct CameraInformation {
human_name: String,
description: String,
misc: String,
index: CameraIndex,
}
impl CameraInfo {
/// Create a new [`CameraInfo`].
impl CameraInformation {
/// Create a new [`CameraInformation`].
/// # JS-WASM
/// This is exported as a constructor for [`CameraInfo`].
/// This is exported as a constructor for [`CameraInformation`].
#[must_use]
// OK, i just checkeed back on this code. WTF was I on when I wrote `&(impl AsRef<str> + ?Sized)` ????
// I need to get on the same shit that my previous self was on, because holy shit that stuff is strong as FUCK!
// Finally fixed this insanity. Hopefully I didnt torment anyone by actually putting this in a stable release.
pub fn new(human_name: String, description: String, misc: String, index: CameraIndex) -> Self {
CameraInfo {
CameraInformation {
human_name,
description,
misc,
@@ -520,7 +520,7 @@ impl CameraInfo {
// }
}
impl Display for CameraInfo {
impl Display for CameraInformation {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
@@ -540,50 +540,50 @@ impl Display for CameraInfo {
// Ok(())
// }
/// The list of known capture backends to the library. <br>
/// - `Auto` - Use automatic selection.
/// - `AVFoundation` - Uses `AVFoundation` on `MacOSX`
/// - `Video4Linux` - `Video4Linux2`, a linux specific backend.
/// - `UniversalVideoClass` - ***DEPRECATED*** Universal Video Class (please check [libuvc](https://github.com/libuvc/libuvc)). Platform agnostic, although on linux it needs `sudo` permissions or similar to use.
/// - `MediaFoundation` - Microsoft Media Foundation, Windows only,
/// - `OpenCv` - Uses `OpenCV` to capture. Platform agnostic.
/// - `GStreamer` - ***DEPRECATED*** Uses `GStreamer` RTP to capture. Platform agnostic.
/// - `Browser` - Uses browser APIs to capture from a webcam.
pub enum SelectableBackend {
Auto,
Custom(&'static str),
AVFoundation,
Video4Linux,
UniversalVideoClass,
MediaFoundation,
OpenCv,
GStreamer,
Browser,
}
/// The list of known capture backends to the library. <br>
/// - `AVFoundation` - Uses `AVFoundation` on `MacOSX`
/// - `Video4Linux` - `Video4Linux2`, a linux specific backend.
/// - `UniversalVideoClass` - ***DEPRECATED*** Universal Video Class (please check [libuvc](https://github.com/libuvc/libuvc)). Platform agnostic, although on linux it needs `sudo` permissions or similar to use.
/// - `MediaFoundation` - Microsoft Media Foundation, Windows only,
/// - `OpenCv` - Uses `OpenCV` to capture. Platform agnostic.
/// - `GStreamer` - ***DEPRECATED*** Uses `GStreamer` RTP to capture. Platform agnostic.
/// - `Browser` - Uses browser APIs to capture from a webcam.
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub enum ApiBackend {
Custom(&'static str),
AVFoundation,
Video4Linux,
UniversalVideoClass,
MediaFoundation,
OpenCv,
GStreamer,
Browser,
}
impl Display for ApiBackend {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{self:?}")
}
}
// /// The list of known capture backends to the library. <br>
// /// - `Auto` - Use automatic selection.
// /// - `AVFoundation` - Uses `AVFoundation` on `MacOSX`
// /// - `Video4Linux` - `Video4Linux2`, a linux specific backend.
// /// - `UniversalVideoClass` - ***DEPRECATED*** Universal Video Class (please check [libuvc](https://github.com/libuvc/libuvc)). Platform agnostic, although on linux it needs `sudo` permissions or similar to use.
// /// - `MediaFoundation` - Microsoft Media Foundation, Windows only,
// /// - `OpenCv` - Uses `OpenCV` to capture. Platform agnostic.
// /// - `GStreamer` - ***DEPRECATED*** Uses `GStreamer` RTP to capture. Platform agnostic.
// /// - `Browser` - Uses browser APIs to capture from a webcam.
// pub enum SelectableBackend {
// Auto,
// Custom(&'static str),
// AVFoundation,
// Video4Linux,
// UniversalVideoClass,
// MediaFoundation,
// OpenCv,
// GStreamer,
// Browser,
// }
//
// /// The list of known capture backends to the library. <br>
// /// - `AVFoundation` - Uses `AVFoundation` on `MacOSX`
// /// - `Video4Linux` - `Video4Linux2`, a linux specific backend.
// /// - `UniversalVideoClass` - ***DEPRECATED*** Universal Video Class (please check [libuvc](https://github.com/libuvc/libuvc)). Platform agnostic, although on linux it needs `sudo` permissions or similar to use.
// /// - `MediaFoundation` - Microsoft Media Foundation, Windows only,
// /// - `OpenCv` - Uses `OpenCV` to capture. Platform agnostic.
// /// - `GStreamer` - ***DEPRECATED*** Uses `GStreamer` RTP to capture. Platform agnostic.
// /// - `Browser` - Uses browser APIs to capture from a webcam.
// #[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
// pub enum ApiBackend {
// Custom(&'static str),
// AVFoundation,
// Video4Linux,
// UniversalVideoClass,
// MediaFoundation,
// OpenCv,
// GStreamer,
// Browser,
// }
//
// impl Display for ApiBackend {
// fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
// write!(f, "{self:?}")
// }
// }