make control api simpler, because most platforms arnt v4l2

This commit is contained in:
l1npengtul
2024-12-05 12:52:50 +09:00
parent 5d79e46d06
commit 0646b0abf5
18 changed files with 148 additions and 720 deletions
Generated
+2 -20
View File
@@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
version = 4
[[package]]
name = "ab_glyph"
@@ -2516,6 +2516,7 @@ dependencies = [
"futures",
"image 0.25.0",
"num-rational 0.4.2",
"num-traits",
"opencv 0.93.1",
"paste",
"rgb",
@@ -2524,16 +2525,6 @@ dependencies = [
"wgpu 23.0.1",
]
[[package]]
name = "nokhwa-decoder"
version = "0.1.0"
dependencies = [
"dcv-color-primitives",
"mozjpeg",
"nokhwa-core",
"yuvutils-rs",
]
[[package]]
name = "nokhwactl"
version = "0.10.0"
@@ -4745,15 +4736,6 @@ version = "0.8.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a"
[[package]]
name = "yuvutils-rs"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b30a62ce6c5fbf13dbf8d92e7cd805d74574a7f84d0e81462ca3cb8192be5de2"
dependencies = [
"num-traits",
]
[[package]]
name = "zerocopy"
version = "0.7.32"
+1 -1
View File
@@ -12,7 +12,7 @@ repository = "https://github.com/l1npengtul/nokhwa"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[workspace]
members = ["nokhwa-bindings-macos", "nokhwa-bindings-windows", "nokhwa-bindings-linux", "nokhwa-core", "examples/*", "nokhwa-decoder"]
members = ["nokhwa-bindings-macos", "nokhwa-bindings-windows", "nokhwa-bindings-linux", "nokhwa-core", "examples/*"]
exclude = ["examples/jscam"]
[lib]
Generated
+9 -9
View File
@@ -5,11 +5,11 @@
"systems": "systems"
},
"locked": {
"lastModified": 1726560853,
"narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
@@ -20,11 +20,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1730958623,
"narHash": "sha256-JwQZIGSYnRNOgDDoIgqKITrPVil+RMWHsZH1eE1VGN0=",
"lastModified": 1733097829,
"narHash": "sha256-9hbb1rqGelllb4kVUCZ307G2k3/UhmA8PPGBoyuWaSw=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "85f7e662eda4fa3a995556527c87b2524b691933",
"rev": "2c15aa59df0017ca140d9ba302412298ab4bf22a",
"type": "github"
},
"original": {
@@ -62,11 +62,11 @@
"nixpkgs": "nixpkgs_2"
},
"locked": {
"lastModified": 1731292155,
"narHash": "sha256-fYVoUUtSadbOrH0z0epVQDsStBDS/S/fAK//0ECQAAI=",
"lastModified": 1733193245,
"narHash": "sha256-nwvKoPi3S6XyliqBRuC+01QFF0k94ZOvnoZtbGi/ObM=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "7c4cd99ed7604b79e8cb721099ac99c66f656b3a",
"rev": "3458f7f946ba61d1a1069aedcc17d7b7616f23cd",
"type": "github"
},
"original": {
+2 -2
View File
@@ -246,7 +246,7 @@ mod internal {
ffi::{c_float, c_void, CStr},
sync::Arc,
};
use nokhwa_core::properties::{CameraControl, ControlValueDescription, ControlValueSetter, KnownCameraControl};
use nokhwa_core::properties::{CameraControl, ControlValueDescription, ControlValue, KnownCameraControl};
const UTF8_ENCODING: usize = 4;
type CGFloat = c_float;
@@ -1492,7 +1492,7 @@ mod internal {
pub fn set_control(
&mut self,
id: KnownCameraControl,
value: ControlValueSetter,
value: ControlValue,
) -> Result<(), NokhwaError> {
let rc = self.get_controls()?;
let controls = rc
+6 -6
View File
@@ -46,7 +46,7 @@ pub mod wmf {
Arc,
},
};
use nokhwa_core::properties::{CameraControl, ControlValueDescription, ControlValueSetter, KnownCameraControl};
use nokhwa_core::properties::{CameraControl, ControlValueDescription, ControlValue, KnownCameraControl};
use windows::Win32::Media::DirectShow::{CameraControl_Flags_Auto, CameraControl_Flags_Manual};
use windows::Win32::Media::MediaFoundation::{
IMFMediaType, MFCreateSample, MF_SOURCE_READER_FIRST_VIDEO_STREAM,
@@ -849,7 +849,7 @@ pub mod wmf {
pub fn set_control(
&mut self,
control: KnownCameraControl,
value: ControlValueSetter,
value: ControlValue,
) -> Result<(), NokhwaError> {
let current_value = self.control(control)?;
@@ -897,8 +897,8 @@ pub mod wmf {
})?;
let ctrl_value = match value {
ControlValueSetter::Integer(i) => i as i32,
ControlValueSetter::Boolean(b) => i32::from(b),
ControlValue::Integer(i) => i as i32,
ControlValue::Boolean(b) => i32::from(b),
v => {
return Err(NokhwaError::StructureError {
structure: format!("ControlValueSetter {}", v),
@@ -1229,7 +1229,7 @@ pub mod wmf {
CameraFormat, CameraIndex, CameraInfo,
};
use std::borrow::Cow;
use nokhwa_core::properties::{CameraControl, ControlValueSetter, KnownCameraControl};
use nokhwa_core::properties::{CameraControl, ControlValue, KnownCameraControl};
pub fn initialize_mf() -> Result<(), NokhwaError> {
Err(NokhwaError::NotImplementedError(
@@ -1287,7 +1287,7 @@ pub mod wmf {
pub fn set_control(
&mut self,
_control: KnownCameraControl,
_value: ControlValueSetter,
_value: ControlValue,
) -> Result<(), NokhwaError> {
Err(NokhwaError::NotImplementedError(
"Only on Windows".to_string(),
+1
View File
@@ -25,6 +25,7 @@ thiserror = "2.0"
bytes = "1.3"
paste = "1.0"
flume = "0.11"
num-traits = "0.2"
[dependencies.num-rational]
version = "0.4"
-1
View File
@@ -1,5 +1,4 @@
use crate::error::{NokhwaError, NokhwaResult};
use crate::frame_buffer::FrameBuffer;
use crate::frame_format::FrameFormat;
use crate::properties::{CameraProperties, CameraPropertyId, CameraPropertyValue};
use crate::types::{CameraFormat, CameraIndex, FrameRate, Resolution};
-2
View File
@@ -1,8 +1,6 @@
use crate::{error::NokhwaError, frame_buffer::FrameBuffer, frame_format::FrameFormat};
use image::{ImageBuffer, Pixel};
use std::{
error::Error,
fmt::{Debug, Display},
ops::{ControlFlow, Deref},
};
+19 -13
View File
@@ -5,6 +5,7 @@ use crate::{
types::{CameraFormat, FrameRate, Resolution},
};
use std::cmp::Ordering;
use crate::ranges::ValidatableRange;
#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)]
enum ClosestType {
@@ -60,24 +61,29 @@ impl FormatRequest {
frame_rate,
frame_format,
} => {
let resolution_point = resolution.map(|x| x.preferred())?;
let frame_rate_point = frame_rate.map(|x| x.preferred())?;
let resolution_point = resolution.map(|x| x.preferred());
let frame_rate_point = frame_rate.map(|x| x.preferred());
// lets calcuate distance in 3 dimensions (add both resolution and frame_rate together)
let mut distances: Vec<(f32, CameraFormat)> = list_of_formats
let mut distances = list_of_formats
.iter()
.filter(|x| frame_format.contains(&x.format()))
.map(|fmt| {
(
(fmt.frame_rate() - frame_rate_point).abs()
+ fmt.resolution().distance_from(&resolution_point) as f32,
fmt,
)
let frame_rate_distance = match frame_rate_point {
Some(f_point) => (fmt.frame_rate() - f_point).approximate_float().unwrap_or(f32::INFINITY).abs(),
None => 0_f32,
};
let resolution_point_distance = match resolution_point {
Some(res_pt) => fmt.resolution().distance_from(&res_pt) as f32,
None => 0_f32,
};
(frame_rate_distance + resolution_point_distance, fmt)
})
.collect::<Vec<_>>();
.collect::<Vec<(f32, &CameraFormat)>>();
distances.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(Ordering::Equal));
distances.into_iter().map(|x| x.1).collect()
distances.into_iter().map(|x| x.1).copied().collect()
}
FormatRequest::HighestFrameRate {
frame_rate,
@@ -86,7 +92,7 @@ impl FormatRequest {
let mut formats = list_of_formats
.iter()
.filter(|x| {
frame_format.contains(&x.format()) && frame_rate.in_range(x.frame_rate())
frame_format.contains(&x.format()) && frame_rate.validate(&x.frame_rate()).is_ok()
})
.collect::<Vec<_>>();
formats.sort();
@@ -99,7 +105,7 @@ impl FormatRequest {
let mut formats = list_of_formats
.iter()
.filter(|x| {
frame_format.contains(&x.format()) && resolution.in_range(x.resolution())
frame_format.contains(&x.format()) && resolution.validate(&x.resolution()).is_ok()
})
.collect::<Vec<_>>();
formats.sort();
+75 -646
View File
@@ -1,676 +1,105 @@
use crate::error::NokhwaError;
use crate::ranges::{ArrayRange, KeyValue, Options, Range, RangeValidationFailure, Simple, ValidatableRange};
use serde::{Deserialize, Serialize};
use std::cmp::Ordering;
use std::{
collections::{HashMap, HashSet},
fmt::{Display, Formatter},
};
use std::collections::HashMap;
use crate::ranges::Range;
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub struct ControlValidationFailure;
impl From<RangeValidationFailure> for ControlValidationFailure {
fn from(_: RangeValidationFailure) -> Self {
Self
}
}
#[derive(Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub enum CameraPropertyId {
Brightness,
Contrast,
Hue,
Saturation,
Sharpness,
Gamma,
WhiteBalance,
BacklightCompensation,
ISO,
Pan,
Tilt,
Zoom,
Exposure,
Iris,
pub enum ControlId {
Focus,
Facing,
Custom(String),
}
impl Display for CameraPropertyId {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{self:?}")
}
}
// TODO: Replace Controls API with Properties. (this one)
/// Properties of a Camera.
///
/// If the property is not supported, it is `None`.
/// Custom or platform-specific properties go into `other`
pub struct CameraProperties {
props: HashMap<CameraPropertyId, CameraPropertyDescriptor>,
}
macro_rules! def_camera_props {
( $($property:ident, )* ) => {
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.set_property(&CameraPropertyId::$property, value)
}
)*
}
}
};
}
def_camera_props!(
Brightness,
Contrast,
Hue,
Saturation,
Sharpness,
Gamma,
WhiteBalance,
BacklightCompensation,
ISO,
Pan,
Tilt,
Zoom,
Exposure,
Iris,
Focus,
Facing,
);
impl CameraProperties {
pub fn property(&self, property: &CameraPropertyId) -> Option<&CameraPropertyDescriptor> {
self.props.get(property)
}
pub fn set_property(
&mut self,
property: &CameraPropertyId,
value: CameraPropertyValue,
) -> Result<(), NokhwaError> {
match self.props.get_mut(property) {
Some(prop) => {
prop.set_value(value)?;
Ok(())
}
None => Err(NokhwaError::SetPropertyError {
property: property.to_string(),
value: value.to_string(),
error: String::from("Is null."),
}),
}
}
WhiteBalance,
Zoom,
Lighting,
Other(u64)
}
/// Describes an individual property.
#[derive(Clone, Debug)]
pub struct CameraPropertyDescriptor {
flags: HashSet<CameraPropertyFlag>,
mode: CameraPropertyMode,
range: CameraPropertyRange,
value: CameraPropertyValue,
value_type: CameraPropertyValueType,
#[derive(Clone, Debug, PartialEq)]
pub enum ControlGroup {
ModeMultipleValue(ModeAndValuesControl),
Simple(SimpleControl),
}
impl 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) -> bool {
self.flags.contains(&CameraPropertyFlag::ReadOnly)
}
pub fn is_write_only(&self) -> bool {
self.flags.contains(&CameraPropertyFlag::WriteOnly)
}
pub fn is_disabled(&self) -> Result<(), NokhwaError> {
if self.flags.contains(&CameraPropertyFlag::Disabled) {
return Err(NokhwaError::StructureError {
structure: "CameraPropertyDescriptor".to_string(),
error: "Disabled".to_string(),
});
}
Ok(())
}
pub fn flags(&self) -> Result<&HashSet<CameraPropertyFlag>, NokhwaError> {
self.is_disabled()?;
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
}
pub fn value(&self) -> &CameraPropertyValue {
&self.value
}
pub fn set_value(&mut self, value: CameraPropertyValue) -> Result<(), NokhwaError> {
self.range
.check_value(&value)
.map_err(|_| NokhwaError::SetPropertyError {
property: "CameraPropertyValue".to_string(),
value: value.to_string(),
error: "Bad Type".to_string(),
})?;
self.value = value;
Ok(())
}
#[derive(Clone, Debug, PartialEq)]
pub struct ModeAndValuesControl {
id: ControlId,
mode_id: u64,
mode_body: ControlBody,
values: HashMap<String, SimpleControl>
}
/// Platform Specific Camera Property. This is not useful, unless you are manually dealing with
/// camera properties in `other`.
#[derive(Clone, Debug, Hash, PartialOrd, Eq, PartialEq)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub enum CameraCustomPropertyPlatformId {
String(String),
LongInteger(i128),
#[derive(Clone, Debug, PartialEq)]
pub struct SimpleControl {
id: u64,
body: ControlBody,
}
#[derive(Clone, Debug, PartialEq)]
pub struct ControlBody {
pub typ: ControlType,
pub class: ControlClass,
pub flags: Vec<ControlFlags>,
pub descriptor: ControlValueDescriptor,
pub value: Option<ControlValue>
}
#[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,
pub enum ControlType {
Button,
Integer,
Menu,
IntegerMenu,
BinaryMenu,
Bitmask,
String,
}
#[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,
pub enum ControlClass {
User,
Camera,
Other(u64),
}
/// 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 {
/// The value may only be read from - any attempts to change the value will error.
ReadOnly,
/// The value can only be written to.
WriteOnly,
/// May just randomly poof out of existance.
// FIXME: where the fuck did i find this? replace above doc with actual info.
Volatile,
/// While the platform/driver supports this feature,
/// your camera does not. Setting will be ignored.
pub enum ControlFlags {
Disabled,
Busy,
ReadOnly,
CascadingUpdates,
Inactive,
Slider,
WriteOnly,
ContinuousChange,
ExecuteOnWrite,
}
impl Display for CameraPropertyFlag {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{self:?}")
}
}
/// Ranges (Available Options of a Camera
#[non_exhaustive]
#[derive(Clone, Debug)]
pub enum CameraPropertyRange {
#[derive(Clone, Debug, PartialEq)]
pub enum ControlValueDescriptor {
Null,
Boolean(Simple<bool>),
Integer(Range<i64>),
LongInteger(Range<i128>),
Float(Range<f32>),
Double(Range<f64>),
String(Simple<String>),
Array(ArrayRange<Vec<CameraPropertyValue>>),
Enumeration(Options<CameraPropertyValue>),
Binary(Simple<Vec<u8>>),
Pair(Range<f32>, Range<f32>),
Triple(
Range<f32>,
Range<f32>,
Range<f32>,
),
Quadruple(
Range<f32>,
Range<f32>,
Range<f32>,
Range<f32>,
),
KeyValuePair(KeyValue<String, CameraPropertyValue>),
}
impl CameraPropertyRange {
pub fn check_value(&self, value: &CameraPropertyValue) -> Result<(), ControlValidationFailure> {
match self {
CameraPropertyRange::Null => {
if let CameraPropertyValue::Null = value {
return Ok(());
}
}
CameraPropertyRange::Boolean(chk_b) => {
if let CameraPropertyValue::Boolean(b) = value {
chk_b.validate(b)?
}
}
CameraPropertyRange::Integer(chk_i) => {
if let CameraPropertyValue::Integer(i) = value {
chk_i.validate(i)?
}
}
CameraPropertyRange::LongInteger(chk_long) => {
if let CameraPropertyValue::LongInteger(long) = value {
chk_long.validate(long)?
}
}
CameraPropertyRange::Float(chk_float) => {
if let CameraPropertyValue::Float(fl) = value {
chk_float.validate(fl)?;
}
}
CameraPropertyRange::Double(chk_double) => {
if let CameraPropertyValue::Double(dl) = value {
chk_double.validate(dl)?;
}
}
CameraPropertyRange::String(chk_string) => {
if let CameraPropertyValue::String(st) = value {
chk_string.validate(st)?;
}
}
CameraPropertyRange::Array(chk_array) => {
if let CameraPropertyValue::Array(arr) = value {
chk_array.validate(arr)?;
}
}
CameraPropertyRange::Enumeration(chk_enum) => {
if let CameraPropertyValue::EnumValue(en) = value {
chk_enum.validate(en)?;
}
}
CameraPropertyRange::Binary(chk_bin) => {
if let CameraPropertyValue::Binary(bin) = value {
chk_bin.validate(bin)?;
}
}
CameraPropertyRange::Pair(chk_a, chk_b) => {
if let CameraPropertyValue::Pair(a, b) = value {
chk_a.validate(a)?;
chk_b.validate(b)?;
}
}
CameraPropertyRange::Triple(chk_x, chk_y, chk_z) => {
if let CameraPropertyValue::Triple(x, y, z) = value {
chk_x.validate(x)?;
chk_y.validate(y)?;
chk_z.validate(z)?;
}
}
CameraPropertyRange::Quadruple(chk_x, chk_y, chk_z, chk_w) => {
if let CameraPropertyValue::Quadruple(x, y, z, w) = value {
chk_x.validate(x)?;
chk_y.validate(y)?;
chk_z.validate(z)?;
chk_w.validate(w)?;
}
}
CameraPropertyRange::KeyValuePair(kv) => {
if let CameraPropertyValue::KeyValue(st, va) = value {
if let Some(vk) = kv.by_key(st) {
if vk.is_same_type(va) {
return Ok(());
}
}
}
}
_ => return Err(ControlValidationFailure),
}
Err(ControlValidationFailure)
}
}
/// A possible value of
///
/// IMPORTANT: Make sure to call [`check_self()`] BEFORE any other operations!
#[derive(Clone, Debug)]
#[non_exhaustive]
pub enum CameraPropertyValue {
Null,
Boolean(bool),
Integer(i64),
LongInteger(i128),
Float(f32),
Double(f64),
Bitmap(i64),
Float(Range<i64>),
String(String),
Array(Vec<CameraPropertyValue>),
EnumValue(Box<CameraPropertyValue>),
Binary(Vec<u8>),
Pair(f32, f32),
Triple(f32, f32, f32),
Quadruple(f32, f32, f32, f32),
KeyValue(String, Box<CameraPropertyValue>),
Boolean(bool),
Array(Vec<ControlValuePrimitive>),
Map(HashMap<String, ControlValuePrimitive>)
}
impl CameraPropertyValue {
pub fn is_same_type(&self, other: &CameraPropertyValue) -> bool {
match (self, other) {
(CameraPropertyValue::Null, CameraPropertyValue::Null) => true,
(CameraPropertyValue::Boolean(_), CameraPropertyValue::Boolean(_)) => true,
(CameraPropertyValue::Integer(_), CameraPropertyValue::Integer(_)) => true,
(CameraPropertyValue::LongInteger(_), CameraPropertyValue::LongInteger(_)) => true,
(CameraPropertyValue::Float(_), CameraPropertyValue::Float(_)) => true,
(CameraPropertyValue::Double(_), CameraPropertyValue::Double(_)) => true,
(CameraPropertyValue::String(_), CameraPropertyValue::String(_)) => true,
(CameraPropertyValue::Array(_), CameraPropertyValue::Array(_)) => true,
(CameraPropertyValue::EnumValue(_), CameraPropertyValue::EnumValue(_)) => true,
(CameraPropertyValue::Binary(_), CameraPropertyValue::Binary(_)) => true,
(CameraPropertyValue::Pair(..), CameraPropertyValue::Pair(..)) => true,
(CameraPropertyValue::Triple(..), CameraPropertyValue::Triple(..)) => true,
(CameraPropertyValue::Quadruple(..), CameraPropertyValue::Quadruple(..)) => true,
(CameraPropertyValue::KeyValue(..), CameraPropertyValue::KeyValue(..)) => true,
(_, _) => false,
}
}
#[derive(Clone, Debug, PartialEq, PartialOrd)]
pub enum ControlValuePrimitive {
Null,
Integer(i64),
Bitmap(i64),
Float(f64),
String(String),
Boolean(bool),
}
impl PartialEq for CameraPropertyValue {
fn eq(&self, other: &Self) -> bool {
match &self {
CameraPropertyValue::Null => {
if let CameraPropertyValue::Null = other {
return true;
}
}
CameraPropertyValue::Boolean(b) => {
if let CameraPropertyValue::Boolean(ob) = other {
return b == ob;
}
}
CameraPropertyValue::Integer(i) => {
if let CameraPropertyValue::Integer(oi) = other {
return i == oi;
}
}
CameraPropertyValue::LongInteger(i) => {
if let CameraPropertyValue::LongInteger(oi) = other {
return i == oi;
}
}
CameraPropertyValue::Float(f) => {
if let CameraPropertyValue::Float(of) = other {
return f == of;
}
}
CameraPropertyValue::Double(d) => {
if let CameraPropertyValue::Double(od) = other {
return d == od;
}
}
CameraPropertyValue::String(s) => {
if let CameraPropertyValue::String(os) = other {
return s == os;
}
}
CameraPropertyValue::Array(a) => {
if let CameraPropertyValue::Array(oa) = other {
return a == oa;
}
}
CameraPropertyValue::EnumValue(ev) => {
if let CameraPropertyValue::EnumValue(oev) = other {
return ev == oev;
}
}
CameraPropertyValue::Binary(bin) => {
if let CameraPropertyValue::Binary(obin) = other {
return bin == obin;
}
}
CameraPropertyValue::Pair(a, b) => {
if let CameraPropertyValue::Pair(oa, ob) = other {
return (a == oa) && (b == ob);
}
}
CameraPropertyValue::Triple(x, y, z) => {
if let CameraPropertyValue::Triple(ox, oy, oz) = other {
return (x == ox) && (y == oy) && (z == oz);
}
}
CameraPropertyValue::Quadruple(x, y, z, w) => {
if let CameraPropertyValue::Quadruple(ox, oy, oz, ow) = other {
return (x == ox) && (y == oy) && (z == oz) && (w == ow);
}
}
CameraPropertyValue::KeyValue(k, v) => {
if let CameraPropertyValue::KeyValue(ok, ov) = other {
return (k == ok) && (v == ov);
}
}
_ => {}
}
false
}
}
impl PartialOrd for CameraPropertyValue {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
match self {
CameraPropertyValue::Null => match other {
CameraPropertyValue::Null => Some(Ordering::Greater),
_ => Some(Ordering::Less),
},
CameraPropertyValue::Boolean(b) => match other {
CameraPropertyValue::Null => Some(Ordering::Greater),
CameraPropertyValue::Boolean(o) => {
if o == b {
Some(Ordering::Equal)
} else if o {
Some(Ordering::Less)
} else {
Some(Ordering::Greater)
}
}
_ => Some(Ordering::Less),
},
CameraPropertyValue::Integer(int) => match other {
CameraPropertyValue::Null | CameraPropertyValue::Boolean(_) => {
Some(Ordering::Greater)
}
CameraPropertyValue::Integer(oth) => Some(int.cmp(oth)),
CameraPropertyValue::LongInteger(li) => {
let long = match i64::try_from(li) {
Ok(v) => v,
Err(_) => return None,
};
Some(int.cmp(&long))
}
_ => Some(Ordering::Less),
},
CameraPropertyValue::LongInteger(long) => match other {
CameraPropertyValue::Null | CameraPropertyValue::Boolean(_) => {
Some(Ordering::Greater)
}
CameraPropertyValue::Integer(oth) => Some(long.cmp(&(i128::from(oth)))),
CameraPropertyValue::LongInteger(o) => Some(long.cmp(o)),
_ => Some(Ordering::Less),
},
CameraPropertyValue::Float(fl) => match other {
CameraPropertyValue::Null
| CameraPropertyValue::Boolean(_)
| CameraPropertyValue::Integer(_)
| CameraPropertyValue::LongInteger(_) => Some(Ordering::Greater),
CameraPropertyValue::Float(f) => fl.partial_cmp(f),
CameraPropertyValue::Double(d) => f64::from(fl).partial_cmp(d),
_ => Some(Ordering::Less),
},
CameraPropertyValue::Double(d) => match other {
CameraPropertyValue::Null
| CameraPropertyValue::Boolean(_)
| CameraPropertyValue::Integer(_)
| CameraPropertyValue::LongInteger(_) => Some(Ordering::Greater),
CameraPropertyValue::Float(f) => d.partial_cmp(&(f64::from(f))),
CameraPropertyValue::Double(o) => d.partial_cmp(o),
_ => Some(Ordering::Less),
},
CameraPropertyValue::String(s) => match other {
CameraPropertyValue::Null
| CameraPropertyValue::Boolean(_)
| CameraPropertyValue::Integer(_)
| CameraPropertyValue::LongInteger(_)
| CameraPropertyValue::Float(_)
| CameraPropertyValue::Double(_) => Some(Ordering::Greater),
CameraPropertyValue::String(os) => s.partial_cmp(os),
_ => Some(Ordering::Less),
},
CameraPropertyValue::Array(a) => match other {
CameraPropertyValue::Null
| CameraPropertyValue::Boolean(_)
| CameraPropertyValue::Integer(_)
| CameraPropertyValue::LongInteger(_)
| CameraPropertyValue::Float(_)
| CameraPropertyValue::Double(_)
| CameraPropertyValue::String(_) => Some(Ordering::Greater),
CameraPropertyValue::Array(oa) => a.partial_cmp(oa),
_ => Some(Ordering::Less),
},
CameraPropertyValue::EnumValue(_) => match other {
CameraPropertyValue::Null
| CameraPropertyValue::Boolean(_)
| CameraPropertyValue::Integer(_)
| CameraPropertyValue::LongInteger(_)
| CameraPropertyValue::Float(_)
| CameraPropertyValue::Double(_)
| CameraPropertyValue::String(_)
| CameraPropertyValue::Array(_) => Some(Ordering::Greater),
CameraPropertyValue::EnumValue(_) => Some(Ordering::Equal),
_ => Some(Ordering::Less),
},
CameraPropertyValue::Binary(b) => match other {
CameraPropertyValue::Null
| CameraPropertyValue::Boolean(_)
| CameraPropertyValue::Integer(_)
| CameraPropertyValue::LongInteger(_)
| CameraPropertyValue::Float(_)
| CameraPropertyValue::Double(_)
| CameraPropertyValue::String(_)
| CameraPropertyValue::Array(_)
| CameraPropertyValue::EnumValue(_) => Some(Ordering::Greater),
CameraPropertyValue::Binary(ob) => b.partial_cmp(ob),
_ => Some(Ordering::Less),
},
// FIXME: implement this lole
CameraPropertyValue::Pair(_, _) => {
// match other {
// CameraPropertyValue::Null |
// CameraPropertyValue::Boolean(_) |
// CameraPropertyValue::Integer(_) |
// CameraPropertyValue::LongInteger(_) |
// CameraPropertyValue::Float(_) |
// CameraPropertyValue::Double(_) |
// CameraPropertyValue::String(_) |
// CameraPropertyValue::Array(_) |
// CameraPropertyValue::EnumValue(_) |
// CameraPropertyValue::Binary(_) => Some(Ordering::Greater),
// CameraPropertyValue::Pair(a, b) => {
// match a.partial_cmp(b) {
// Some(_) => {}
// None => {}
// }
// }
// _ => Some(Ordering::Less)
// }
Some(Ordering::Equal)
}
CameraPropertyValue::Triple(_, _, _) => Some(Ordering::Equal),
CameraPropertyValue::Quadruple(_, _, _, _) => Some(Ordering::Equal),
_ => None,
}
}
}
impl Display for CameraPropertyValue {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
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,
// }
// }
// }
};
#[derive(Clone, Debug, PartialEq, PartialOrd)]
pub enum ControlValue {
Null,
Integer(i64),
Bitmap(i64),
Float(f64),
String(String),
Boolean(bool),
KeyValue(String, ControlValuePrimitive),
}
+2 -1
View File
@@ -1,7 +1,6 @@
use crate::error::{NokhwaError, NokhwaResult};
use crate::frame_buffer::FrameBuffer;
use flume::Receiver;
use futures::TryFutureExt;
use std::sync::Arc;
pub trait StreamInnerTrait {
@@ -61,6 +60,8 @@ impl Stream {
#[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(),
+13 -1
View File
@@ -13,6 +13,7 @@ use std::num::NonZeroI32;
use std::ops::{Div, Rem};
use num_rational::Rational32;
use crate::ranges::{SimpleRangeItem};
use num_traits::FromPrimitive;
/// Describes the index of the camera.
/// - Index: A numbered index
@@ -247,6 +248,17 @@ impl FrameRate {
pub fn denominator(&self) -> &i32 {
self.rational.denom()
}
pub fn as_raw(&self) -> &Rational32 {
&self.rational
}
pub fn approximate_float(&self) -> Option<f32> {
let numerator_float = f32::from_i32(*self.numerator())?;
let denominator_float = f32::from_i32(*self.denominator())?;
Some(numerator_float / denominator_float)
}
}
impl Default for FrameRate {
@@ -299,7 +311,7 @@ impl From<Rational32> for FrameRate {
/// 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`].
#[derive(Copy, Clone, Debug, Hash, PartialEq, PartialOrd)]
#[derive(Copy, Clone, Debug, Hash, PartialEq, PartialOrd, Eq, Ord)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct CameraFormat {
resolution: Resolution,
+3 -3
View File
@@ -34,7 +34,7 @@ use nokhwa_core::{
use std::{ffi::CString, sync::Arc};
use std::{borrow::Cow, collections::HashMap};
use nokhwa_core::properties::{CameraControl, ControlValueSetter, KnownCameraControl};
use nokhwa_core::properties::{CameraControl, ControlValue, KnownCameraControl};
/// The backend struct that interfaces with V4L2.
/// To see what this does, please see [`CaptureTrait`].
@@ -231,7 +231,7 @@ impl CaptureTrait for AVFoundationCaptureDevice {
fn set_camera_control(
&mut self,
id: KnownCameraControl,
value: ControlValueSetter,
value: ControlValue,
) -> Result<(), NokhwaError> {
self.device.lock()?;
let res = self.device.set_control(id, value);
@@ -463,7 +463,7 @@ impl CaptureTrait for AVFoundationCaptureDevice {
fn set_camera_control(
&mut self,
_: KnownCameraControl,
_: ControlValueSetter,
_: ControlValue,
) -> Result<(), NokhwaError> {
todo!()
}
+3 -3
View File
@@ -7,7 +7,7 @@ use serde::{de, Serialize};
use wasm_bindgen_futures::JsFuture;
use web_sys::{window, MediaDeviceInfo, MediaDevices, MediaStream, MediaStreamConstraints, MediaStreamTrack, MediaTrackConstraints, Navigator};
use nokhwa_core::frame_buffer::FrameBuffer;
use nokhwa_core::properties::{CameraControl, ControlValueSetter, KnownCameraControl};
use nokhwa_core::properties::{CameraControl, ControlValue, KnownCameraControl};
use nokhwa_core::error::NokhwaError;
use nokhwa_core::frame_format::FrameFormat;
use nokhwa_core::traits::{AsyncCaptureTrait, AsyncOpenCaptureTrait, CaptureTrait, OpenCaptureTrait};
@@ -360,7 +360,7 @@ impl CaptureTrait for BrowserCaptureDevice {
fn set_camera_control(
&mut self,
id: KnownCameraControl,
value: ControlValueSetter,
value: ControlValue,
) -> Result<(), NokhwaError> {
todo!()
}
@@ -414,7 +414,7 @@ impl AsyncCaptureTrait for BrowserCaptureDevice {
todo!()
}
async fn set_camera_control_async(&mut self, id: KnownCameraControl, value: ControlValueSetter) -> Result<(), NokhwaError> {
async fn set_camera_control_async(&mut self, id: KnownCameraControl, value: ControlValue) -> Result<(), NokhwaError> {
todo!()
}
+2 -2
View File
@@ -26,7 +26,7 @@ use nokhwa_core::{
},
};
use std::{borrow::Cow, collections::HashMap};
use nokhwa_core::properties::{all_known_camera_controls, CameraControl, ControlValueSetter, KnownCameraControl};
use nokhwa_core::properties::{all_known_camera_controls, CameraControl, ControlValue, KnownCameraControl};
/// The backend that deals with Media Foundation on Windows.
/// To see what this does, please see [`CaptureTrait`].
@@ -229,7 +229,7 @@ impl CaptureTrait for MediaFoundationCaptureDevice {
fn set_camera_control(
&mut self,
id: KnownCameraControl,
value: ControlValueSetter,
value: ControlValue,
) -> Result<(), NokhwaError> {
self.inner.set_control(id, value)
}
+5 -5
View File
@@ -33,7 +33,7 @@ use opencv::{
},
};
use std::{borrow::Cow, collections::HashMap};
use nokhwa_core::properties::{CameraControl, ControlValueDescription, ControlValueSetter, KnownCameraControl};
use nokhwa_core::properties::{CameraControl, ControlValueDescription, ControlValue, KnownCameraControl};
/// Attempts to convert a [`KnownCameraControl`] into a `OpenCV` video capture property.
/// If the associated control is not found, this will return `Err`
@@ -434,12 +434,12 @@ impl CaptureTrait for OpenCvCaptureDevice {
fn set_camera_control(
&mut self,
id: KnownCameraControl,
value: ControlValueSetter,
value: ControlValue,
) -> Result<(), NokhwaError> {
let control_val = match value {
ControlValueSetter::Integer(i) => i as f64,
ControlValueSetter::Float(f) => f,
ControlValueSetter::Boolean(b) => u8::from(b) as f64,
ControlValue::Integer(i) => i as f64,
ControlValue::Float(f) => f,
ControlValue::Boolean(b) => u8::from(b) as f64,
val => {
return Err(NokhwaError::SetPropertyError {
property: "Camera Control".to_string(),
+2 -2
View File
@@ -28,7 +28,7 @@ use nokhwa_core::{
},
};
use std::{borrow::Cow, collections::HashMap};
use nokhwa_core::properties::{CameraControl, ControlValueSetter, KnownCameraControl};
use nokhwa_core::properties::{CameraControl, ControlValue, KnownCameraControl};
/// The main `Camera` struct. This is the struct that abstracts over all the backends, providing a simplified interface for use.
pub struct Camera {
@@ -123,7 +123,7 @@ impl CaptureTrait for Camera {
fn set_camera_control(
&mut self,
id: KnownCameraControl,
value: ControlValueSetter,
value: ControlValue,
) -> Result<(), NokhwaError> {
todo!()
}
+3 -3
View File
@@ -31,7 +31,7 @@ use std::{
Arc, Mutex,
},
};
use nokhwa_core::properties::{CameraControl, ControlValueSetter, KnownCameraControl};
use nokhwa_core::properties::{CameraControl, ControlValue, KnownCameraControl};
type AtomicLock<T> = Arc<Mutex<T>>;
pub type CallbackFn = fn(
@@ -420,14 +420,14 @@ impl CallbackCamera {
/// Sets the control to `control` in the camera.
/// Usually, the pipeline is calling [`camera_control()`](crate::camera_traits::CaptureTrait::camera_control), getting a camera control that way
/// then calling [`value()`](nokhwa_core::properties::CameraControl::value()) to get a [`ControlValueSetter`](nokhwa_core::properties::ControlValueSetter) and setting the value that way.
/// then calling [`value()`](nokhwa_core::properties::CameraControl::value()) to get a [`ControlValueSetter`](nokhwa_core::properties::ControlValue) and setting the value that way.
/// # Errors
/// If the `control` is not supported, the value is invalid (less than min, greater than max, not in step), or there was an error setting the control,
/// this will error.
pub fn set_camera_control(
&mut self,
id: KnownCameraControl,
control: ControlValueSetter,
control: ControlValue,
) -> Result<(), NokhwaError> {
self.camera
.lock()