mirror of
https://github.com/l1npengtul/nokhwa.git
synced 2026-07-04 10:37:26 +00:00
ergonomic changes to trait
This commit is contained in:
+17
-11
@@ -1,9 +1,10 @@
|
||||
use crate::error::{NokhwaError};
|
||||
use crate::control::{ControlDescription, ControlId, ControlValue, Controls};
|
||||
use crate::error::NokhwaError;
|
||||
use crate::frame_format::FrameFormat;
|
||||
use crate::control::{ControlId, ControlValue, Controls};
|
||||
use crate::types::{CameraFormat, FrameRate, Resolution};
|
||||
use std::collections::HashMap;
|
||||
use crate::stream::Stream;
|
||||
use crate::types::{CameraFormat, FrameRate, Resolution};
|
||||
use std::collections::hash_map::{Keys, Values};
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub trait Setting {
|
||||
fn enumerate_formats(&self) -> Result<Vec<CameraFormat>, NokhwaError>;
|
||||
@@ -15,15 +16,20 @@ pub trait Setting {
|
||||
|
||||
fn set_format(&self, camera_format: CameraFormat) -> Result<(), NokhwaError>;
|
||||
|
||||
fn controls(&self) -> &Controls;
|
||||
fn control_ids(&self) -> Keys<ControlId, ControlDescription>;
|
||||
|
||||
fn control_descriptions(&self) -> Values<ControlId, ControlDescription>;
|
||||
|
||||
fn control_values(&self) -> Values<ControlId, ControlValue>;
|
||||
|
||||
fn control_value(&self, id: &ControlId) -> Option<&ControlValue>;
|
||||
|
||||
fn control_description(&self, id: &ControlId) -> Option<&ControlDescription>;
|
||||
|
||||
fn set_control(&mut self, property: &ControlId, value: ControlValue)
|
||||
-> Result<(), NokhwaError>;
|
||||
|
||||
fn refresh_controls(&mut self) -> Result<(), NokhwaError>;
|
||||
|
||||
fn set_control(
|
||||
&mut self,
|
||||
property: &ControlId,
|
||||
value: ControlValue,
|
||||
) -> Result<(), NokhwaError>;
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
|
||||
+212
-184
@@ -1,9 +1,10 @@
|
||||
use crate::error::{NokhwaError, NokhwaResult};
|
||||
use crate::ranges::{Range, ValidatableRange};
|
||||
use ordered_float::OrderedFloat;
|
||||
use std::collections::hash_map::{Keys, Values};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use ordered_float::OrderedFloat;
|
||||
use crate::error::{NokhwaError, NokhwaResult};
|
||||
use crate::ranges::{Range, ValidatableRange};
|
||||
|
||||
pub type PlatformSpecificControlId = u64;
|
||||
|
||||
@@ -42,7 +43,7 @@ pub enum ControlId {
|
||||
|
||||
Orientation,
|
||||
|
||||
PlatformSpecific(PlatformSpecificControlId)
|
||||
PlatformSpecific(PlatformSpecificControlId),
|
||||
}
|
||||
|
||||
impl Display for ControlId {
|
||||
@@ -53,49 +54,125 @@ impl Display for ControlId {
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
pub struct Controls {
|
||||
controls: HashMap<ControlId, ControlBody>,
|
||||
values: HashMap<ControlId, ControlId>,
|
||||
descriptions: HashMap<ControlId, ControlDescription>,
|
||||
values: HashMap<ControlId, ControlValue>,
|
||||
}
|
||||
|
||||
impl Controls {
|
||||
pub fn new(device_controls: HashMap<ControlId, ControlBody>) -> Self {
|
||||
Self {
|
||||
controls: device_controls,
|
||||
/// INVARIANTS: All `ControlId` in `device_values` MUST exist in `device_controls`
|
||||
pub fn new(
|
||||
device_controls: HashMap<ControlId, ControlDescription>,
|
||||
device_values: HashMap<ControlId, ControlValue>,
|
||||
) -> Option<Self> {
|
||||
for (id, value) in device_values.iter() {
|
||||
if let Some(description) = device_controls.get(id) {
|
||||
if !description.validate(value) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(Self {
|
||||
descriptions: device_controls,
|
||||
values: device_values,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn empty() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn control_value(&self, control_id: &ControlId) -> Option<&ControlBody> {
|
||||
self.controls.get(control_id)
|
||||
pub fn unchecked_new(
|
||||
device_controls: HashMap<ControlId, ControlDescription>,
|
||||
device_values: HashMap<ControlId, ControlValue>,
|
||||
) -> Self {
|
||||
Self {
|
||||
descriptions: device_controls,
|
||||
values: device_values,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_control_value(&mut self, control_id: &ControlId, value: ControlValue) -> NokhwaResult<()> {
|
||||
pub fn description(&self, control_id: &ControlId) -> Option<&ControlDescription> {
|
||||
self.descriptions.get(control_id)
|
||||
}
|
||||
|
||||
pub fn value(&self, control_id: &ControlId) -> Option<&ControlValue> {
|
||||
self.values.get(control_id)
|
||||
}
|
||||
|
||||
pub fn descriptions(&self) -> Values<ControlId, ControlDescription> {
|
||||
self.descriptions.values()
|
||||
}
|
||||
|
||||
pub fn values(&self) -> Values<ControlId, ControlValue> {
|
||||
self.values.values()
|
||||
}
|
||||
|
||||
pub fn ids(&self) -> Keys<ControlId, ControlDescription> {
|
||||
self.descriptions.keys()
|
||||
}
|
||||
|
||||
pub fn set_control_value(
|
||||
&mut self,
|
||||
control_id: &ControlId,
|
||||
value: ControlValue,
|
||||
) -> NokhwaResult<()> {
|
||||
// see if it exists
|
||||
if let Some(control) = self.controls.get_mut(control_id) {
|
||||
// FIXME: Remove this clone one day!
|
||||
control.set_value(value.clone())?;
|
||||
if let None = self.descriptions.get(control_id) {
|
||||
return Err(NokhwaError::SetPropertyError {
|
||||
property: control_id.to_string(),
|
||||
value: value.to_string(),
|
||||
error: "ID Not Found".to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
match self.values.get_mut(control_id) {
|
||||
Some(old) => {
|
||||
*old = value;
|
||||
Ok(())
|
||||
}
|
||||
// this should not happen,
|
||||
None => Err(NokhwaError::SetPropertyError {
|
||||
property: control_id.to_string(),
|
||||
value: value.to_string(),
|
||||
error: "If you got this, its probably a bug or your camera is _horribly_ bugged :>"
|
||||
.to_string(),
|
||||
}),
|
||||
}
|
||||
Err(NokhwaError::SetPropertyError {
|
||||
property: control_id.to_string(),
|
||||
value: value.to_string(),
|
||||
error: "Not Found/Not Supported".to_string(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct ControlBody {
|
||||
pub struct ControlDescription {
|
||||
flags: HashSet<ControlFlags>,
|
||||
descriptor: ControlValueDescriptor,
|
||||
default_value: Option<ControlValue>,
|
||||
}
|
||||
|
||||
impl ControlBody {
|
||||
pub fn new(control_flags: HashSet<ControlFlags>, control_value_descriptor: ControlValueDescriptor, default_value: Option<ControlValue>) -> Self {
|
||||
impl ControlDescription {
|
||||
pub fn new(
|
||||
control_flags: HashSet<ControlFlags>,
|
||||
control_value_descriptor: ControlValueDescriptor,
|
||||
default_value: Option<ControlValue>,
|
||||
) -> Option<Self> {
|
||||
if let Some(default) = &default_value {
|
||||
if !control_value_descriptor.validate(default) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
Some(Self {
|
||||
flags: control_flags,
|
||||
descriptor: control_value_descriptor,
|
||||
default_value,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn new_unchecked(
|
||||
control_flags: HashSet<ControlFlags>,
|
||||
control_value_descriptor: ControlValueDescriptor,
|
||||
default_value: Option<ControlValue>,
|
||||
) -> Self {
|
||||
Self {
|
||||
flags: control_flags,
|
||||
descriptor: control_value_descriptor,
|
||||
@@ -122,6 +199,10 @@ impl ControlBody {
|
||||
pub fn remove_flag(&mut self, flag: ControlFlags) -> bool {
|
||||
self.flags.remove(&flag)
|
||||
}
|
||||
|
||||
pub fn validate(&self, value: &ControlValue) -> bool {
|
||||
self.descriptor.validate(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
||||
@@ -160,6 +241,10 @@ pub enum ControlValueDescriptor {
|
||||
width_limits: Range<i64>,
|
||||
height_limits: Range<i64>,
|
||||
},
|
||||
// An Orientation
|
||||
// Usually, this is a read-only value.
|
||||
// An empty vec indicates any allowed value.
|
||||
Orientation(Vec<Orientation>),
|
||||
}
|
||||
|
||||
impl ControlValueDescriptor {
|
||||
@@ -167,166 +252,66 @@ impl ControlValueDescriptor {
|
||||
match self {
|
||||
ControlValueDescriptor::Null => {
|
||||
if let &ControlValue::Null = value {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
}
|
||||
ControlValueDescriptor::Integer(int_range) => {
|
||||
if let ControlValue::Integer(i) = value {
|
||||
return int_range.validate(i)
|
||||
return int_range.validate(i);
|
||||
}
|
||||
}
|
||||
ControlValueDescriptor::BitMask => {
|
||||
if let &ControlValue::BitMask(_) = value {
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
}
|
||||
ControlValueDescriptor::Float(float_range) => {
|
||||
if let ControlValue::Float(i) = value {
|
||||
return float_range.validate(i)
|
||||
return float_range.validate(i);
|
||||
}
|
||||
}
|
||||
ControlValueDescriptor::String => {
|
||||
if let &ControlValue::String(_) = value {
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
}
|
||||
ControlValueDescriptor::Boolean => {
|
||||
if let &ControlValue::Boolean(_) = value {
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
}
|
||||
ControlValueDescriptor::Array(arr) => {
|
||||
if let &ControlValue::Array(_) = value {
|
||||
return arr.is_valid_value(value)
|
||||
return arr.is_valid_value(value);
|
||||
}
|
||||
}
|
||||
ControlValueDescriptor::Binary(size_limits) => {
|
||||
if let ControlValue::Binary(bin) = value {
|
||||
return size_limits.validate(bin.len() as u64)
|
||||
return size_limits.validate(bin.len() as u64);
|
||||
}
|
||||
}
|
||||
ControlValueDescriptor::Menu(choices) => {
|
||||
if let ControlValue::EnumPick(choice) = value {
|
||||
return choices.contains_key(choice)
|
||||
return choices.contains_key(choice);
|
||||
}
|
||||
}
|
||||
ControlValueDescriptor::Area { width_limits, height_limits } => {
|
||||
ControlValueDescriptor::Area {
|
||||
width_limits,
|
||||
height_limits,
|
||||
} => {
|
||||
if let ControlValue::Area { width, height } = &value {
|
||||
return width_limits.validate(width) && height_limits.validate(height)
|
||||
return width_limits.validate(width) && height_limits.validate(height);
|
||||
}
|
||||
}
|
||||
ControlValueDescriptor::Orientation(orientations) => {
|
||||
if let ControlValue::Orientation(orientation) = &value {
|
||||
return orientations.contains(orientation) || orientations.is_empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
//
|
||||
// #[derive(Clone, Debug, PartialEq)]
|
||||
// pub enum ControlValuePrimitiveDescriptor {
|
||||
// Null,
|
||||
// Integer(Range<i64>),
|
||||
// BitMask,
|
||||
// Float(Range<f64>),
|
||||
// String,
|
||||
// Binary,
|
||||
// Boolean,
|
||||
// }
|
||||
//
|
||||
// impl ControlValuePrimitiveDescriptor {
|
||||
// pub fn is_valid_primitive_value(&self, other: &ControlValuePrimitive) -> bool {
|
||||
// match self {
|
||||
// ControlValuePrimitiveDescriptor::Null => {
|
||||
// if let ControlValuePrimitive::Null = other {
|
||||
// return true
|
||||
// }
|
||||
// }
|
||||
// ControlValuePrimitiveDescriptor::Integer(i) => {
|
||||
// if let ControlValuePrimitive::Integer(v) = other {
|
||||
// return i.validate(v)
|
||||
// }
|
||||
// }
|
||||
// ControlValuePrimitiveDescriptor::BitMask => {
|
||||
// if let ControlValuePrimitive::BitMask(_) = other {
|
||||
// return true
|
||||
// }
|
||||
// }
|
||||
// ControlValuePrimitiveDescriptor::Float(f) => {
|
||||
// if let ControlValuePrimitive::Float(v) = other {
|
||||
// return f.validate(v)
|
||||
// }
|
||||
// }
|
||||
// ControlValuePrimitiveDescriptor::String => {
|
||||
// if let ControlValuePrimitive::String(_) = other {
|
||||
// return true
|
||||
// }
|
||||
// }
|
||||
// ControlValuePrimitiveDescriptor::Boolean => {
|
||||
// if let ControlValuePrimitive::Boolean(_) = other {
|
||||
// return true
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// false
|
||||
// }
|
||||
//
|
||||
// pub fn is_valid_value(&self, other: &ControlValue) -> bool {
|
||||
// match self {
|
||||
// ControlValuePrimitiveDescriptor::Null => {
|
||||
// if let ControlValue::Null = other {
|
||||
// return true
|
||||
// }
|
||||
// }
|
||||
// ControlValuePrimitiveDescriptor::Integer(i) => {
|
||||
// if let ControlValue::Integer(v) = other {
|
||||
// return i.validate(v)
|
||||
// }
|
||||
// }
|
||||
// ControlValuePrimitiveDescriptor::BitMask => {
|
||||
// if let ControlValue::BitMask(_) = other {
|
||||
// return true
|
||||
// }
|
||||
// }
|
||||
// ControlValuePrimitiveDescriptor::Float(f) => {
|
||||
// if let ControlValue::Float(v) = other {
|
||||
// return f.validate(v)
|
||||
// }
|
||||
// }
|
||||
// ControlValuePrimitiveDescriptor::String => {
|
||||
// if let ControlValue::String(_) = other {
|
||||
// return true
|
||||
// }
|
||||
// }
|
||||
// ControlValuePrimitiveDescriptor::Boolean => {
|
||||
// if let ControlValue::Boolean(_) = other {
|
||||
// return true
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// false
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// #[derive(Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
||||
// pub enum ControlValuePrimitive {
|
||||
// Null,
|
||||
// Integer(i64),
|
||||
// BitMask(i64),
|
||||
// Float(OrderedFloat<f64>),
|
||||
// String(String),
|
||||
// Boolean(bool),
|
||||
// }
|
||||
//
|
||||
// impl From<ControlValuePrimitive> for ControlValue {
|
||||
// fn from(value: ControlValuePrimitive) -> Self {
|
||||
// match value {
|
||||
// ControlValuePrimitive::Null => ControlValue::Null,
|
||||
// ControlValuePrimitive::Integer(i) => ControlValue::Integer(i),
|
||||
// ControlValuePrimitive::BitMask(b) => ControlValue::BitMask(b),
|
||||
// ControlValuePrimitive::Float(f) => ControlValue::Float(f),
|
||||
// ControlValuePrimitive::String(s) => ControlValue::String(s),
|
||||
// ControlValuePrimitive::Boolean(b) => ControlValue::Boolean(b),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
#[derive(Clone, Debug, Hash, Eq, PartialEq, PartialOrd)]
|
||||
pub enum ControlValue {
|
||||
@@ -339,23 +324,22 @@ pub enum ControlValue {
|
||||
Array(Vec<ControlValue>),
|
||||
Binary(Vec<u8>),
|
||||
EnumPick(Box<ControlValue>),
|
||||
Area {
|
||||
width: i64,
|
||||
height: i64,
|
||||
}
|
||||
Area { width: i64, height: i64 },
|
||||
Orientation(Orientation),
|
||||
}
|
||||
|
||||
impl ControlValue {
|
||||
pub fn is_primitive(&self) -> bool {
|
||||
match self {
|
||||
ControlValue::Null |
|
||||
ControlValue::Integer(_) |
|
||||
ControlValue::BitMask(_) |
|
||||
ControlValue::Float(_) |
|
||||
ControlValue::String(_)|
|
||||
ControlValue::Boolean(_) |
|
||||
ControlValue::Binary(_) |
|
||||
ControlValue::Area { .. } => true,
|
||||
ControlValue::Null
|
||||
| ControlValue::Integer(_)
|
||||
| ControlValue::BitMask(_)
|
||||
| ControlValue::Float(_)
|
||||
| ControlValue::String(_)
|
||||
| ControlValue::Boolean(_)
|
||||
| ControlValue::Binary(_)
|
||||
| ControlValue::Area { .. }
|
||||
| ControlValue::Orientation(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@@ -383,39 +367,61 @@ impl ControlValue {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
ControlValue::Integer(_) => {if let ControlValue::Integer(_) = other {
|
||||
return true;
|
||||
}}
|
||||
ControlValue::BitMask(_) => {if let ControlValue::BitMask(_) = other {
|
||||
return true;
|
||||
}}
|
||||
ControlValue::Float(_) => {if let ControlValue::Float(_) = other {
|
||||
return true;
|
||||
}}
|
||||
ControlValue::String(_) => {if let ControlValue::String(_) = other {
|
||||
return true;
|
||||
}}
|
||||
ControlValue::Boolean(_) => {if let ControlValue::Boolean(_) = other {
|
||||
return true;
|
||||
}}
|
||||
ControlValue::Array(_) => {if let ControlValue::Array(_) = other {
|
||||
return true;
|
||||
}}
|
||||
ControlValue::EnumPick(_) => {if let ControlValue::EnumPick(_) = other {
|
||||
return true;
|
||||
}}
|
||||
ControlValue::Binary(_) => {if let ControlValue::Binary(_) = other {
|
||||
return true;
|
||||
}}
|
||||
ControlValue::Area { .. } => {if let ControlValue::Area { .. } = other {
|
||||
return true;
|
||||
}}
|
||||
ControlValue::Integer(_) => {
|
||||
if let ControlValue::Integer(_) = other {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
ControlValue::BitMask(_) => {
|
||||
if let ControlValue::BitMask(_) = other {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
ControlValue::Float(_) => {
|
||||
if let ControlValue::Float(_) = other {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
ControlValue::String(_) => {
|
||||
if let ControlValue::String(_) = other {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
ControlValue::Boolean(_) => {
|
||||
if let ControlValue::Boolean(_) = other {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
ControlValue::Array(_) => {
|
||||
if let ControlValue::Array(_) = other {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
ControlValue::EnumPick(_) => {
|
||||
if let ControlValue::EnumPick(_) = other {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
ControlValue::Binary(_) => {
|
||||
if let ControlValue::Binary(_) = other {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
ControlValue::Area { .. } => {
|
||||
if let ControlValue::Area { .. } = other {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
ControlValue::Orientation(_) => {
|
||||
if let ControlValue::Orientation(_) = other {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
_ => return false,
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
impl Display for ControlValue {
|
||||
@@ -423,3 +429,25 @@ impl Display for ControlValue {
|
||||
write!(f, "Control Value: {self:?}")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
||||
#[non_exhaustive]
|
||||
pub enum Orientation {
|
||||
User,
|
||||
Environment,
|
||||
Up,
|
||||
Down,
|
||||
Left,
|
||||
Right,
|
||||
Center,
|
||||
Near,
|
||||
Far,
|
||||
Other,
|
||||
Custom(i64),
|
||||
}
|
||||
|
||||
impl Display for Orientation {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Orientation {self:?}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::fmt::{Display, Formatter};
|
||||
use crate::camera::{AsyncCamera, Camera};
|
||||
use crate::error::NokhwaResult;
|
||||
use crate::types::{CameraIndex, CameraInformation};
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq)]
|
||||
pub enum Backends {
|
||||
@@ -10,7 +10,7 @@ pub enum Backends {
|
||||
AVFoundation,
|
||||
MicrosoftMediaFoundation,
|
||||
OpenCV,
|
||||
Custom(&'static str)
|
||||
Custom(&'static str),
|
||||
}
|
||||
|
||||
impl Display for Backends {
|
||||
@@ -23,16 +23,15 @@ 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>;
|
||||
fn open(&mut self, index: CameraIndex) -> NokhwaResult<Self::Camera>;
|
||||
|
||||
fn open_dynamic(&mut self, index: &CameraIndex) -> NokhwaResult<Box<dyn Camera>> {
|
||||
fn open_dynamic(&mut self, index: CameraIndex) -> NokhwaResult<Box<dyn Camera>> {
|
||||
self.open(index).map(|cam| Box::new(cam))
|
||||
}
|
||||
}
|
||||
@@ -43,15 +42,13 @@ 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>;
|
||||
|
||||
async fn open_async(&mut self, index: &CameraIndex) -> NokhwaResult<Self::AsyncCamera>;
|
||||
|
||||
async fn open_dynamic_async(&mut self, index: &CameraIndex) -> NokhwaResult<Box<dyn Camera>> {
|
||||
self.open_async(index).await.map(|cam| Box::new(cam))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user