mirror of
https://github.com/l1npengtul/nokhwa.git
synced 2026-07-04 10:37:26 +00:00
intermidiary commit
This commit is contained in:
@@ -22,7 +22,7 @@ test-fail-warnings = []
|
||||
|
||||
|
||||
[dependencies]
|
||||
thiserror = "1.0"
|
||||
thiserror = "2.0"
|
||||
bytes = "1.3"
|
||||
paste = "1.0"
|
||||
|
||||
@@ -60,6 +60,10 @@ optional = true
|
||||
version = "0.4"
|
||||
optional = true
|
||||
|
||||
[dependencies.futures]
|
||||
version = "0.3"
|
||||
optional = true
|
||||
|
||||
[dependencies.rgb]
|
||||
version = "0.8"
|
||||
|
||||
|
||||
+33
-23
@@ -1,42 +1,52 @@
|
||||
use std::collections::HashMap;
|
||||
use crate::buffer::Buffer;
|
||||
use crate::controls::{CameraProperties, CameraPropertyId, CameraPropertyValue};
|
||||
use crate::error::NokhwaError;
|
||||
use crate::types::{CameraFormat, CameraIndex, Resolution};
|
||||
use crate::properties::{CameraProperties, CameraPropertyId, CameraPropertyValue};
|
||||
use crate::error::{NokhwaError, NokhwaResult};
|
||||
use crate::frame_format::FrameFormat;
|
||||
use crate::stream::CaptureStream;
|
||||
use crate::types::{CameraFormat, CameraIndex, FrameRate, Resolution};
|
||||
|
||||
pub trait Open {
|
||||
fn open(index: CameraIndex) -> Self;
|
||||
fn open(index: CameraIndex) -> NokhwaResult<Self>;
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
pub trait AsyncOpen {
|
||||
async fn open_async(index: CameraIndex) -> Self;
|
||||
async fn open_async(index: CameraIndex) -> NokhwaResult<Self>;
|
||||
}
|
||||
|
||||
macro_rules! def_camera_props {
|
||||
( $($property:ident, )* ) => {
|
||||
$(
|
||||
fn paste::paste! { [<$property:snake>] } (&self) -> Option<&CameraPropertyDescriptor> {
|
||||
self.properties().paste::paste! { [<$property:snake>] }
|
||||
paste::paste! {
|
||||
$(
|
||||
fn [<$property:snake>] (&self) -> Option<&CameraPropertyDescriptor> {
|
||||
self.properties().[<$property:snake>]
|
||||
}
|
||||
|
||||
fn [<set_ $property:snake>] (&mut self, value: CameraPropertyValue) -> Result<(), NokhwaError> {
|
||||
self.properties().[<set_ $property:snake >](value)
|
||||
}
|
||||
)*
|
||||
}
|
||||
|
||||
fn paste::paste! { [<set_ $property:snake>] } (&mut self, value: CameraPropertyValue) -> Result<(), NokhwaError>;
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! def_camera_props_async {
|
||||
( $($property:ident, )* ) => {
|
||||
$(
|
||||
async fn paste::paste! { [<set_ $property:snake>] } (&mut self, value: CameraPropertyValue) -> Result<(), NokhwaError>;
|
||||
)*
|
||||
paste::paste! {
|
||||
$(
|
||||
async fn [<set_ $property:snake _async>] (&mut self, value: CameraPropertyValue) -> Result<(), NokhwaError> {
|
||||
self.properties().[<set_ $property:snake >](value)
|
||||
}
|
||||
)*
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub trait Setting {
|
||||
fn enumerate_formats(&self) -> Vec<CameraFormat>;
|
||||
fn enumerate_formats(&self) -> Result<Vec<CameraFormat>, NokhwaError>;
|
||||
|
||||
fn enumerate_formats_by_resolution(&self) -> HashMap<Resolution, CameraFormat>;
|
||||
fn enumerate_resolution_and_frame_rates(&self, frame_format: FrameFormat) -> Result<HashMap<Resolution, Vec<FrameRate>>, NokhwaError>;
|
||||
|
||||
fn set_format(&self, camera_format: CameraFormat) -> Result<(), NokhwaError>;
|
||||
|
||||
@@ -66,9 +76,9 @@ pub trait Setting {
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
pub trait AsyncSetting {
|
||||
async fn set_format(&self, camera_format: CameraFormat) -> Result<(), NokhwaError>;
|
||||
async fn set_format_async(&self, camera_format: CameraFormat) -> Result<(), NokhwaError>;
|
||||
|
||||
async fn set_property(&mut self, property: &CameraPropertyId, value: CameraPropertyValue) -> Result<(), NokhwaError>;
|
||||
async fn set_property_async(&mut self, property: &CameraPropertyId, value: CameraPropertyValue) -> Result<(), NokhwaError>;
|
||||
|
||||
def_camera_props_async!(
|
||||
Brightness,
|
||||
@@ -91,10 +101,8 @@ pub trait AsyncSetting {
|
||||
}
|
||||
|
||||
pub trait Stream {
|
||||
fn open_stream(&mut self) -> Result<(), NokhwaError>;
|
||||
|
||||
fn poll_frame(&mut self) -> Result<Buffer, NokhwaError>;
|
||||
|
||||
fn open_stream(&mut self) -> Result<CaptureStream, NokhwaError>;
|
||||
|
||||
fn close_stream(&mut self) -> Result<(), NokhwaError>;
|
||||
}
|
||||
|
||||
@@ -102,7 +110,7 @@ pub trait Stream {
|
||||
pub trait AsyncStream {
|
||||
async fn open_stream(&mut self) -> Result<(), NokhwaError>;
|
||||
|
||||
async fn poll_frame(&mut self) -> Result<Buffer, NokhwaError>;
|
||||
async fn await_frame(&mut self) -> Result<Buffer, NokhwaError>;
|
||||
|
||||
async fn close_stream(&mut self) -> Result<(), NokhwaError>;}
|
||||
|
||||
@@ -110,3 +118,5 @@ pub trait Capture: Open + Setting + Stream {}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
pub trait AsyncCapture: Capture + AsyncOpen + AsyncSetting + AsyncStream {}
|
||||
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@ pub struct GeneralPurposeDecoder<D> where D: PixelWithColorType;
|
||||
|
||||
impl<D> Decoder for GeneralPurposeDecoder<D> where D: PixelWithColorType {
|
||||
const ALLOWED_FORMATS: &'static [FrameFormat] = &[
|
||||
FrameFormat::MJpeg, FrameFormat::Luma8, FrameFormat::Luma16, FrameFormat::Rgb8, FrameFormat::RgbA8,
|
||||
FrameFormat::MJpeg, FrameFormat::Luma8, FrameFormat::Luma16, FrameFormat::Rgb332, FrameFormat::RgbA8888,
|
||||
FrameFormat::Nv12, FrameFormat::Nv21, FrameFormat::Uyvy422, FrameFormat::Yuy2_422, FrameFormat::Yv12,
|
||||
FrameFormat::Yuv444, FrameFormat::I420, FrameFormat::I422, FrameFormat::I444
|
||||
FrameFormat::Ayuv444, FrameFormat::I420, FrameFormat::I422, FrameFormat::I444
|
||||
];
|
||||
|
||||
type OutputPixels = D;
|
||||
@@ -41,14 +41,14 @@ impl<D> Decoder for GeneralPurposeDecoder<D> where D: PixelWithColorType {
|
||||
FrameFormat::MJpeg => PixelFormat::Rgb, // => JPEG decoder
|
||||
FrameFormat::Yuy2_422 => PixelFormat::I422,
|
||||
FrameFormat::Uyvy422 => PixelFormat::I422,
|
||||
FrameFormat::Yuv444 => PixelFormat::I444,
|
||||
FrameFormat::Ayuv444 => PixelFormat::I444,
|
||||
FrameFormat::Nv12 => PixelFormat::Nv12,
|
||||
FrameFormat::Nv21 => PixelFormat::Nv12,
|
||||
FrameFormat::Yv12 => PixelFormat::I420,
|
||||
FrameFormat::I420 => PixelFormat::I420,
|
||||
// already decoded
|
||||
FrameFormat::Rgb8 => PixelFormat::Rgb,
|
||||
FrameFormat::RgbA8 => {
|
||||
FrameFormat::Rgb332 => PixelFormat::Rgb,
|
||||
FrameFormat::RgbA8888 => {
|
||||
PixelFormat::Rgb
|
||||
}
|
||||
_ => return Err(()),
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
use crate::{frame_format::FrameFormat, types::ApiBackend};
|
||||
use thiserror::Error;
|
||||
|
||||
pub type NokhwaResult<T> = Result<T, NokhwaError>;
|
||||
|
||||
/// All errors in `nokhwa`.
|
||||
#[allow(clippy::module_name_repetitions)]
|
||||
#[derive(Error, Debug, Clone)]
|
||||
|
||||
@@ -21,12 +21,14 @@ use crate::types::ApiBackend;
|
||||
/// Describes a frame format (i.e. how the bytes themselves are encoded). Often called `FourCC`.
|
||||
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[non_exhaustive]
|
||||
pub enum FrameFormat {
|
||||
// Compressed Formats
|
||||
H265,
|
||||
H264,
|
||||
H263,
|
||||
Avc1,
|
||||
H263,
|
||||
Av1,
|
||||
Mpeg1,
|
||||
Mpeg2,
|
||||
Mpeg4,
|
||||
@@ -35,40 +37,60 @@ pub enum FrameFormat {
|
||||
VP8,
|
||||
VP9,
|
||||
|
||||
// YCbCr formats
|
||||
|
||||
Yuv444,
|
||||
// YCbCr Formats
|
||||
|
||||
// -> 422 16 BPP
|
||||
Yuyv422,
|
||||
Uyvy422,
|
||||
// 8 bit per pixel, 4:4:4
|
||||
|
||||
// 420
|
||||
Ayuv444,
|
||||
|
||||
// -> 4:2:2
|
||||
Yuyv422, // AKA YUY2
|
||||
Uyvy422, // UYUV
|
||||
Yvyu422,
|
||||
Yv12,
|
||||
|
||||
|
||||
// 4:2:0
|
||||
Nv12,
|
||||
Nv21,
|
||||
Yv12,
|
||||
I420,
|
||||
I422,
|
||||
I444,
|
||||
|
||||
// 16:1:1
|
||||
|
||||
Yvu9,
|
||||
|
||||
// Grayscale Formats
|
||||
Luma8,
|
||||
Luma16,
|
||||
|
||||
// Depth
|
||||
Depth16,
|
||||
|
||||
// RGB Formats
|
||||
Rgb8,
|
||||
RgbA8,
|
||||
Rgb332,
|
||||
Rgb555,
|
||||
Rgb565,
|
||||
|
||||
Rgb888,
|
||||
|
||||
RgbA8888,
|
||||
ARgb8888,
|
||||
|
||||
// Bayer Formats
|
||||
Bayer8,
|
||||
Bayer16,
|
||||
|
||||
// Custom
|
||||
Custom(u128),
|
||||
PlatformSpecificCustomFormat(PlatformSpecific),
|
||||
Custom([u8; 8]),
|
||||
}
|
||||
|
||||
// FIXME: Fix these frame format lists! Maybe move to using a macro..?
|
||||
impl FrameFormat {
|
||||
pub const ALL: &'static [FrameFormat] = &[
|
||||
FrameFormat::H263,
|
||||
FrameFormat::H264,
|
||||
FrameFormat::H265,
|
||||
FrameFormat::Av1,
|
||||
FrameFormat::Avc1,
|
||||
FrameFormat::Mpeg1,
|
||||
FrameFormat::Mpeg2,
|
||||
@@ -84,14 +106,15 @@ impl FrameFormat {
|
||||
FrameFormat::Yv12,
|
||||
FrameFormat::Luma8,
|
||||
FrameFormat::Luma16,
|
||||
FrameFormat::Rgb8,
|
||||
FrameFormat::RgbA8,
|
||||
FrameFormat::Rgb332,
|
||||
FrameFormat::RgbA8888,
|
||||
];
|
||||
|
||||
pub const COMPRESSED: &'static [FrameFormat] = &[
|
||||
FrameFormat::H263,
|
||||
FrameFormat::H264,
|
||||
FrameFormat::H265,
|
||||
FrameFormat::Av1,
|
||||
FrameFormat::Avc1,
|
||||
FrameFormat::Mpeg1,
|
||||
FrameFormat::Mpeg2,
|
||||
@@ -112,12 +135,13 @@ impl FrameFormat {
|
||||
|
||||
pub const LUMA: &'static [FrameFormat] = &[FrameFormat::Luma8, FrameFormat::Luma16];
|
||||
|
||||
pub const RGB: &'static [FrameFormat] = &[FrameFormat::Rgb8, FrameFormat::RgbA8];
|
||||
pub const RGB: &'static [FrameFormat] = &[FrameFormat::Rgb332, FrameFormat::RgbA8888];
|
||||
|
||||
pub const COLOR_FORMATS: &'static [FrameFormat] = &[
|
||||
FrameFormat::H265,
|
||||
FrameFormat::H264,
|
||||
FrameFormat::H263,
|
||||
FrameFormat::Av1,
|
||||
FrameFormat::Avc1,
|
||||
FrameFormat::Mpeg1,
|
||||
FrameFormat::Mpeg2,
|
||||
@@ -131,8 +155,8 @@ impl FrameFormat {
|
||||
FrameFormat::Nv12,
|
||||
FrameFormat::Nv21,
|
||||
FrameFormat::Yv12,
|
||||
FrameFormat::Rgb8,
|
||||
FrameFormat::RgbA8,
|
||||
FrameFormat::Rgb332,
|
||||
FrameFormat::RgbA8888,
|
||||
];
|
||||
|
||||
pub const GRAYSCALE: &'static [FrameFormat] = &[FrameFormat::Luma8, FrameFormat::Luma16];
|
||||
@@ -144,55 +168,30 @@ impl Display for FrameFormat {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct PlatformSpecific {
|
||||
backend: ApiBackend,
|
||||
format: u128,
|
||||
}
|
||||
|
||||
impl PlatformSpecific {
|
||||
#[must_use]
|
||||
pub fn new(backend: ApiBackend, format: u128) -> Self {
|
||||
Self { backend, format }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn backend(&self) -> ApiBackend {
|
||||
self.backend
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn format(&self) -> u128 {
|
||||
self.format
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn as_tuple(&self) -> (ApiBackend, u128) {
|
||||
(self.backend, self.format)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(ApiBackend, u128)> for PlatformSpecific {
|
||||
fn from(value: (ApiBackend, u128)) -> Self {
|
||||
PlatformSpecific::new(value.0, value.1)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PlatformSpecific> for (ApiBackend, u128) {
|
||||
fn from(value: PlatformSpecific) -> Self {
|
||||
value.as_tuple()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<(ApiBackend, u128)> for PlatformSpecific {
|
||||
fn eq(&self, other: &(ApiBackend, u128)) -> bool {
|
||||
&self.as_tuple() == other
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for PlatformSpecific {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{self:?}")
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! define_back_and_fourth_frame_format {
|
||||
($fourcc_type:ty, { $( $frame_format:expr => $value:literal, )* }, $func_u8_8_to_fcc:expr, $func_fcc_to_u8_8:expr, $value_to_fcc_type:expr) => {
|
||||
pub struct FrameFormatIntermediate(pub $fourcc_type);
|
||||
|
||||
impl FrameFormatIntermediate {
|
||||
pub fn from_frame_format(frame_format: FrameFormat) -> Option<Self> {
|
||||
match frame_format {
|
||||
$(
|
||||
$frame_format => Some(Self($value_to_fcc_type($value))),
|
||||
)*
|
||||
FrameFormat::Custom(cv) => Some($func_u8_8_to_fcc(cv))
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_frame_format(fourcc: $fourcc_type) -> FrameFormat {
|
||||
match fourcc.0 {
|
||||
$(
|
||||
$value => $frame_format,
|
||||
)*
|
||||
cv => FrameFormat::Custom($func_fcc_to_u8_8(cv)),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -31,5 +31,9 @@ pub mod types;
|
||||
pub mod decoders;
|
||||
pub mod utils;
|
||||
pub mod ranges;
|
||||
pub mod controls;
|
||||
mod capture;
|
||||
pub mod properties;
|
||||
pub mod capture;
|
||||
pub mod query;
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
pub mod stream;
|
||||
|
||||
@@ -5,7 +5,7 @@ use std::{
|
||||
};
|
||||
use std::cmp::Ordering;
|
||||
use crate::error::NokhwaError;
|
||||
use crate::ranges::{ArrayRange, IndicatedRange, KeyValue, Options, Range, RangeValidationFailure, Simple, ValidatableRange};
|
||||
use crate::ranges::{ArrayRange, IndicatedRange, KeyValue, Options, RangeValidationFailure, Simple, ValidatableRange};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
||||
pub struct ControlValidationFailure;
|
||||
@@ -26,7 +26,7 @@ pub enum CameraPropertyId {
|
||||
Gamma,
|
||||
WhiteBalance,
|
||||
BacklightCompensation,
|
||||
Gain,
|
||||
ISO,
|
||||
Pan,
|
||||
Tilt,
|
||||
Zoom,
|
||||
@@ -48,16 +48,18 @@ pub struct CameraProperties {
|
||||
|
||||
macro_rules! def_camera_props {
|
||||
( $($property:ident, )* ) => {
|
||||
impl CameraProperties {
|
||||
$(
|
||||
pub fn paste::paste! { [<$property:snake>] } (&self) -> Option<&CameraPropertyDescriptor> {
|
||||
self.props.get(&CameraPropertyId::$property)
|
||||
paste::paste! {
|
||||
impl CameraProperties {
|
||||
$(
|
||||
pub fn [<$property:snake>] (&self) -> Option<&CameraPropertyDescriptor> {
|
||||
self.props.get(&CameraPropertyId::$property)
|
||||
}
|
||||
|
||||
pub fn [<set_ $property:snake>] (&mut self, value: CameraPropertyValue) -> Result<(), NokhwaError> {
|
||||
self.props.set_property(&CameraPropertyId::$property, value)
|
||||
}
|
||||
)*
|
||||
}
|
||||
|
||||
pub fn paste::paste! { [<set_ $property:snake>] } (&mut self, value: CameraPropertyValue) -> Result<(), NokhwaError> {
|
||||
self.props.set_property(&CameraPropertyId::$property, value)
|
||||
}
|
||||
)*
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -71,7 +73,7 @@ def_camera_props!(
|
||||
Gamma,
|
||||
WhiteBalance,
|
||||
BacklightCompensation,
|
||||
Gain,
|
||||
ISO,
|
||||
Pan,
|
||||
Tilt,
|
||||
Zoom,
|
||||
@@ -107,38 +109,34 @@ impl CameraProperties {
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CameraPropertyDescriptor {
|
||||
flags: HashSet<CameraPropertyFlag>,
|
||||
mode: CameraPropertyMode,
|
||||
range: CameraPropertyRange,
|
||||
value: CameraPropertyValue,
|
||||
value_type: CameraPropertyValueType,
|
||||
}
|
||||
|
||||
impl CameraPropertyDescriptor {
|
||||
pub fn new(flags: &[CameraPropertyFlag], range: CameraPropertyRange, value: CameraPropertyValue) -> Self {
|
||||
CameraPropertyDescriptor {
|
||||
pub fn new(flags: &[CameraPropertyFlag], mode: CameraPropertyMode, range: CameraPropertyRange, value: CameraPropertyValue, value_type: CameraPropertyValueType) -> Result<Self, NokhwaError> {
|
||||
|
||||
if flags.contains(&CameraPropertyFlag::ReadOnly) && flags.contains(&CameraPropertyFlag::WriteOnly) {
|
||||
return Err(NokhwaError::StructureError { structure: "CameraPropertyDescriptor".to_string(), error: "conflicting flags".to_string() })
|
||||
}
|
||||
|
||||
Ok(CameraPropertyDescriptor {
|
||||
flags: HashSet::from(flags),
|
||||
mode,
|
||||
range,
|
||||
value,
|
||||
}
|
||||
value_type,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn is_read_only(&self) -> Result<(), NokhwaError> {
|
||||
if self.flags.contains(&CameraPropertyFlag::ReadOnly) {
|
||||
return Err(NokhwaError::SetPropertyError {
|
||||
property: "Flag".to_string(),
|
||||
value: "N/A".to_string(),
|
||||
error: "Read Only".to_string(),
|
||||
})
|
||||
}
|
||||
Ok(())
|
||||
pub fn is_read_only(&self) -> bool {
|
||||
self.flags.contains(&CameraPropertyFlag::ReadOnly)
|
||||
}
|
||||
|
||||
pub fn is_write_only(&self) -> Result<(), NokhwaError> {
|
||||
if self.flags.contains(&CameraPropertyFlag::WriteOnly) {
|
||||
return Err(NokhwaError::GetPropertyError {
|
||||
property: "Flag".to_string(),
|
||||
error: "Write Only".to_string(),
|
||||
})
|
||||
}
|
||||
Ok(())
|
||||
pub fn is_write_only(&self) -> bool {
|
||||
self.flags.contains(&CameraPropertyFlag::WriteOnly)
|
||||
}
|
||||
|
||||
pub fn is_disabled(&self) -> Result<(), NokhwaError> {
|
||||
@@ -153,6 +151,14 @@ impl CameraPropertyDescriptor {
|
||||
Ok(&self.flags)
|
||||
}
|
||||
|
||||
pub fn mode(&self) -> CameraPropertyMode {
|
||||
self.mode
|
||||
}
|
||||
|
||||
pub fn value_type(&self) -> CameraPropertyValueType {
|
||||
self.value_type
|
||||
}
|
||||
|
||||
pub fn range(&self) -> &CameraPropertyRange {
|
||||
&self.range
|
||||
}
|
||||
@@ -181,16 +187,34 @@ pub enum CameraCustomPropertyPlatformId {
|
||||
LongInteger(i128),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
|
||||
pub enum CameraPropertyMode {
|
||||
///
|
||||
None,
|
||||
/// Automatically Set
|
||||
Automatic,
|
||||
/// Manually Set
|
||||
Manual,
|
||||
/// Continuously Set
|
||||
Continuous,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
|
||||
pub enum CameraPropertyValueType {
|
||||
/// Relative
|
||||
Relative,
|
||||
/// Absolute
|
||||
Absolute,
|
||||
/// Unknown/Unused/Not Applicable
|
||||
None,
|
||||
}
|
||||
|
||||
/// The flags that a camera property may have.
|
||||
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
|
||||
pub enum CameraPropertyFlag {
|
||||
/// This is automatically set - you need not interfere
|
||||
Automatic,
|
||||
/// This is manually set - you need to interfere
|
||||
Manual,
|
||||
/// The value is set continuously by the driver.
|
||||
Continuous,
|
||||
/// The value may only be read from - any attempts to change the value will error.
|
||||
ReadOnly,
|
||||
/// The value can only be written to.
|
||||
@@ -618,3 +642,39 @@ impl Display for CameraPropertyValue {
|
||||
write!(f, "{self:?}")
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! define_back_and_fourth_control {
|
||||
($id_type:ty, { $( $control:expr [ $mode:expr, $value_type:expr, $value:expr ] => $control_id:expr, )* }, $id_to_str:expr, $str_to_id:expr) => {
|
||||
pub struct ControlIntermediate {
|
||||
pub mode: Option<$id_type>,
|
||||
pub value_type: Option<$id_type>,
|
||||
pub value: $id_type,
|
||||
}
|
||||
|
||||
impl ControlIntermediate {
|
||||
pub fn
|
||||
}
|
||||
|
||||
// impl ControlIntermediate {
|
||||
// pub fn into_control(native_ctrl: $id_type) -> (crate::properties::CameraPropertyId, Option<crate::properties::CameraPropertyFlag>) {
|
||||
// match native_ctrl {
|
||||
// $(
|
||||
// $control_id => ($control, $flag)
|
||||
// )*
|
||||
// nc => (crate::properties::CameraPropertyId::Custom($id_to_str(nc)), None)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// pub fn into_native(property_id: &crate::properties::CameraPropertyId, flag: Option<crate::properties::CameraPropertyFlag>) -> Option<$id_type> {
|
||||
// match (property_id, flag) {
|
||||
// $(
|
||||
// ($control, $flag) => Some($control_id),
|
||||
// )*
|
||||
// (crate::properties::CameraPropertyId::Custom(str_id), _) => $str_to_id(str_id),
|
||||
// _ => None,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
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>;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
use std::{
|
||||
future::Future,
|
||||
pin::Pin,
|
||||
sync::{Arc, Mutex},
|
||||
task::{Context, Poll},
|
||||
sync::mpsc::Receiver
|
||||
};
|
||||
use futures::Stream as AsyncStreamTrait;
|
||||
use crate::{
|
||||
buffer::Buffer,
|
||||
error::NokhwaError
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ChannelState {
|
||||
Frame(Buffer),
|
||||
Error(NokhwaError),
|
||||
ClosedWithError(NokhwaError),
|
||||
Closed,
|
||||
}
|
||||
|
||||
pub enum StreamType {
|
||||
Channel(Arc<Receiver<ChannelState>>),
|
||||
Callback(Arc<Mutex<Option<ChannelState>>>),
|
||||
}
|
||||
|
||||
pub struct CaptureStream {}
|
||||
|
||||
impl Future for CaptureStream {
|
||||
type Output = ChannelState;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncStreamTrait for CaptureStream {
|
||||
type Item = ChannelState;
|
||||
|
||||
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
+46
-66
@@ -98,8 +98,8 @@ impl TryFrom<CameraIndex> for usize {
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
|
||||
#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
|
||||
pub struct Resolution {
|
||||
pub width_x: u32,
|
||||
pub height_y: u32,
|
||||
width_x: u32,
|
||||
height_y: u32,
|
||||
}
|
||||
|
||||
impl Resolution {
|
||||
@@ -180,97 +180,77 @@ impl Distance<u32> for Resolution {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
|
||||
pub struct FrameRate(pub f32);
|
||||
#[derive(Copy, Clone, Debug, Hash)]
|
||||
pub struct FrameRate {
|
||||
numerator: u32,
|
||||
denominator: u32
|
||||
}
|
||||
|
||||
impl FrameRate {
|
||||
#[must_use]
|
||||
pub fn new(fps: f32) -> Self {
|
||||
Self(fps)
|
||||
pub fn new(numerator: u32, denominator: u32) -> Self {
|
||||
Self {
|
||||
numerator,
|
||||
denominator,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn frame_rate(&self) -> f32 {
|
||||
self.0
|
||||
pub fn frame_rate(fps: u32) -> Self {
|
||||
Self {
|
||||
numerator: fps,
|
||||
denominator: 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for FrameRate {
|
||||
type Target = f32;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
pub fn numerator(&self) -> u32 {
|
||||
self.numerator
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for FrameRate {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
pub fn denominator(&self) -> u32 {
|
||||
self.denominator
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for FrameRate {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
state.write_u32(self.0.to_bits());
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FrameRate {
|
||||
fn default() -> Self {
|
||||
FrameRate(30.0)
|
||||
FrameRate::new(30, 1)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for FrameRate {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{} FPS", self.0)
|
||||
write!(f, "{}/{} FPS", self.numerator, self.denominator)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for FrameRate {
|
||||
type Output = FrameRate;
|
||||
impl Eq for FrameRate {}
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
(self.0 + rhs.0).into()
|
||||
impl PartialEq<Self> for FrameRate {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
(self.numerator * other.denominator) == (other.numerator * self.numerator)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for &FrameRate {
|
||||
type Output = FrameRate;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
(self.0 + rhs.0).into()
|
||||
impl PartialOrd<Self> for FrameRate {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for FrameRate {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
if self.numerator == 0 && other.denominator == 0 {
|
||||
return Ordering::Equal;
|
||||
}
|
||||
|
||||
if self.denominator == other.denominator {
|
||||
return self.numerator.cmp(&other.numerator);
|
||||
}
|
||||
|
||||
impl Sub for FrameRate {
|
||||
type Output = FrameRate;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
(self.0 - rhs.0).into()
|
||||
(self.numerator * other.denominator).cmp(&(other.numerator * self.denominator))
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for &FrameRate {
|
||||
type Output = FrameRate;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
(self.0 - rhs.0).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f32> for FrameRate {
|
||||
fn from(value: f32) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FrameRate> for f32 {
|
||||
fn from(value: FrameRate) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
/// This is a convenience struct that holds all information about the format of a webcam stream.
|
||||
/// It consists of a [`Resolution`], [`FrameFormat`], and a [`FrameRate`].
|
||||
@@ -357,7 +337,7 @@ impl Default for CameraFormat {
|
||||
CameraFormat {
|
||||
resolution: Resolution::new(640, 480),
|
||||
format: FrameFormat::MJpeg,
|
||||
frame_rate: FrameRate(30.),
|
||||
frame_rate: FrameRate::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -392,12 +372,12 @@ impl CameraInfo {
|
||||
// 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: &str, description: &str, misc: &str, index: &CameraIndex) -> Self {
|
||||
pub fn new(human_name: String, description: String, misc: String, index: CameraIndex) -> Self {
|
||||
CameraInfo {
|
||||
human_name: human_name.to_string(),
|
||||
description: description.to_string(),
|
||||
misc: misc.to_string(),
|
||||
index: index.clone(),
|
||||
human_name,
|
||||
description,
|
||||
misc,
|
||||
index,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user