new format request type, quartar way wasm cam impl

This commit is contained in:
l1npengtul
2023-08-31 15:23:19 +09:00
parent 074765f012
commit 67139b84cc
9 changed files with 703 additions and 531 deletions
+6 -6
View File
@@ -29,7 +29,8 @@ input-native = ["input-avfoundation", "input-v4l", "input-msmf"]
# Re-enable it once soundness has been proven + mozjpeg is updated to 0.9.x
# input-uvc = ["uvc", "uvc/vendor", "usb_enumeration", "lazy_static"]
input-opencv = ["opencv", "opencv/rgb", "rgb", "nokhwa-core/opencv-mat"]
input-jscam = ["web-sys", "js-sys", "wasm-bindgen-futures", "wasm-bindgen", "wasm-rs-async-executor", "output-async"]
# FIXME: Change me back to web-sys being optional! People will be mad otherwise peg!
input-jscam = [ "wasm-bindgen-futures", "wasm-rs-async-executor", "output-async"]
output-wgpu = ["wgpu", "nokhwa-core/wgpu-types"]
#output-wasm = ["input-jscam"]
output-threaded = []
@@ -65,11 +66,11 @@ version = "0.2"
optional = true
[dependencies.wgpu]
version = "0.16"
version = "0.17"
optional = true
[dependencies.opencv]
version = "0.82"
version = "0.84"
default-features = false
features = ["videoio"]
optional = true
@@ -97,6 +98,7 @@ optional = true
version = "1.7"
optional = true
# TODO: Change me back!
[dependencies.web-sys]
version = "0.3"
features = [
@@ -116,15 +118,13 @@ features = [
"Plugin", "PluginArray",
"Window"
]
optional = true
# FIXME: Change me back! Pls! REMEMBER PEG!
[dependencies.js-sys]
version = "0.3"
optional = true
[dependencies.wasm-bindgen]
version = "0.2"
optional = true
[dependencies.wasm-bindgen-futures]
version = "0.4"
+1 -1
View File
@@ -16,7 +16,7 @@
#[cfg(target_os = "linux")]
mod internal {
use nokhwa_core::format_filter::FormatFilter;
use nokhwa_core::format_request::FormatFilter;
use nokhwa_core::{
buffer::Buffer,
error::NokhwaError,
-230
View File
@@ -1,230 +0,0 @@
use crate::frame_format::SourceFrameFormat;
use crate::{
frame_format::FrameFormat,
types::{ApiBackend, CameraFormat, Resolution},
};
use std::collections::{BTreeMap, BTreeSet};
/// Tells the init function what camera format to pick.
/// - `AbsoluteHighestResolution`: Pick the highest [`Resolution`], then pick the highest frame rate of those provided.
/// - `AbsoluteHighestFrameRate`: Pick the highest frame rate, then the highest [`Resolution`].
/// - `HighestResolution(Resolution)`: Pick the highest [`Resolution`] for the given framerate.
/// - `HighestFrameRate(u32)`: Pick the highest frame rate for the given [`Resolution`].
/// - `Exact`: Pick the exact [`CameraFormat`] provided.
/// - `Closest`: Pick the closest [`CameraFormat`] provided in order of [`Resolution`], and FPS.
/// - `ClosestGreater`: Pick the closest [`CameraFormat`] provided in order of [`Resolution`], and FPS. The returned format's [`Resolution`] **and** FPS will be **greater than or equal to** the provided [`CameraFormat`]
/// - `ClosestLess`: Pick the closest [`CameraFormat`] provided in order of [`Resolution`], and FPS.The returned format's [`Resolution`] **and** FPS will be **less than or equal to** the provided [`CameraFormat`]
/// - `None`: Pick a random [`CameraFormat`]
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
pub enum RequestedFormatType {
AbsoluteHighestResolution,
AbsoluteHighestFrameRate,
HighestResolution(u32),
HighestFrameRate(Resolution),
Exact(CameraFormat),
ClosestGreater(CameraFormat),
ClosestLess(CameraFormat),
Closest(CameraFormat),
None,
}
// TODO: Format Filter Builder to provide more interactive API for fulfillment of formats.
/// How you get your [`FrameFormat`] from the
#[derive(Clone, Debug)]
pub struct FormatFilter {
filter_pref: RequestedFormatType,
fcc_primary: BTreeSet<FrameFormat>,
fcc_platform: BTreeMap<ApiBackend, BTreeSet<u128>>,
}
impl FormatFilter {
pub fn new(fmt_type: RequestedFormatType) -> Self {
Self {
filter_pref: fmt_type,
fcc_primary: Default::default(),
fcc_platform: Default::default(),
}
}
pub fn add_allowed_frame_format(&mut self, frame_format: FrameFormat) {
self.fcc_primary.insert(frame_format);
}
pub fn add_allowed_frame_format_many(&mut self, frame_formats: impl AsRef<[FrameFormat]>) {
self.fcc_primary.extend(frame_formats.as_ref().iter());
}
pub fn add_allowed_platform_specific(&mut self, platform: ApiBackend, frame_format: u128) {
match self.fcc_platform.get_mut(&platform) {
Some(fccs) => {
fccs.insert(frame_format);
}
None => {
self.fcc_platform
.insert(platform, BTreeSet::from([frame_format]));
}
};
}
pub fn add_allowed_platform_specific_many(
&mut self,
platform_specifics: impl AsRef<[(ApiBackend, u128)]>,
) {
for (platform, frame_format) in platform_specifics.as_ref().into_iter() {
match self.fcc_platform.get_mut(&platform) {
Some(fccs) => {
fccs.insert(*frame_format);
}
None => {
self.fcc_platform
.insert(*platform, BTreeSet::from([*frame_format]));
}
};
}
}
pub fn with_allowed_frame_format(mut self, frame_format: FrameFormat) -> Self {
self.fcc_primary.insert(frame_format);
self
}
pub fn with_allowed_frame_format_many(
mut self,
frame_formats: impl AsRef<[FrameFormat]>,
) -> Self {
self.fcc_primary.extend(frame_formats.as_ref().iter());
self
}
pub fn with_allowed_platform_specific(
mut self,
platform: ApiBackend,
frame_format: u128,
) -> Self {
self.add_allowed_platform_specific(platform, frame_format);
self
}
pub fn with_allowed_platform_specific_many(
mut self,
platform_specifics: impl AsRef<[(ApiBackend, u128)]>,
) -> Self {
self.add_allowed_platform_specific_many(platform_specifics);
self
}
}
impl Default for FormatFilter {
fn default() -> Self {
Self {
filter_pref: RequestedFormatType::Closest(CameraFormat::new(
Resolution::new(640, 480),
FrameFormat::Yuv422.into(),
30,
)),
fcc_primary: BTreeSet::from([FrameFormat::Yuv422]),
fcc_platform: Default::default(),
}
}
}
pub fn format_fulfill(
sources: impl AsRef<[CameraFormat]>,
filter: FormatFilter,
) -> Option<CameraFormat> {
let mut sources = sources
.as_ref()
.into_iter()
.filter(|cam_filter| match cam_filter.format() {
SourceFrameFormat::FrameFormat(fmt) => filter.fcc_primary.contains(&fmt),
SourceFrameFormat::PlatformSpecific(plat) => filter
.fcc_platform
.get(&plat.backend())
.map(|x| x.contains(&plat.format()))
.unwrap_or(false),
});
match filter.filter_pref {
RequestedFormatType::AbsoluteHighestResolution => {
let mut sources = sources.collect::<Vec<&CameraFormat>>();
sources.sort_by(|a, b| a.resolution().cmp(&b.resolution()));
sources.last().copied().copied()
}
RequestedFormatType::AbsoluteHighestFrameRate => {
let mut sources = sources.collect::<Vec<&CameraFormat>>();
sources.sort_by(|a, b| a.frame_rate().cmp(&b.frame_rate()));
sources.last().copied().copied()
}
RequestedFormatType::HighestResolution(filter_fps) => {
let mut sources = sources
.filter(|format| format.frame_rate() == filter_fps)
.collect::<Vec<&CameraFormat>>();
sources.sort();
sources.last().copied().copied()
}
RequestedFormatType::HighestFrameRate(filter_res) => {
let mut sources = sources
.filter(|format| format.resolution() == filter_res)
.collect::<Vec<&CameraFormat>>();
sources.sort();
sources.last().copied().copied()
}
RequestedFormatType::Exact(exact) => {
sources.filter(|format| format == &&exact).last().copied()
}
RequestedFormatType::Closest(closest) => {
let mut sources = sources
.map(|format| {
let dist = distance_3d_camerafmt_relative(closest, *format);
(dist, *format)
})
.collect::<Vec<(f64, CameraFormat)>>();
sources.sort_by(|a, b| a.0.total_cmp(&b.0));
sources.first().copied().map(|(_, cf)| cf)
}
RequestedFormatType::ClosestGreater(closest) => {
let mut sources = sources
.filter(|format| {
format.resolution() >= closest.resolution()
&& format.frame_rate() >= closest.frame_rate()
})
.map(|format| {
let dist = distance_3d_camerafmt_relative(closest, *format);
(dist, *format)
})
.collect::<Vec<(f64, CameraFormat)>>();
sources.sort_by(|a, b| a.0.total_cmp(&b.0));
sources.first().copied().map(|(_, cf)| cf)
}
RequestedFormatType::ClosestLess(closest) => {
let mut sources = sources
.filter(|format| {
format.resolution() <= closest.resolution()
&& format.frame_rate() <= closest.frame_rate()
})
.map(|format| {
let dist = distance_3d_camerafmt_relative(closest, *format);
(dist, *format)
})
.collect::<Vec<(f64, CameraFormat)>>();
sources.sort_by(|a, b| a.0.total_cmp(&b.0));
sources.first().copied().map(|(_, cf)| cf)
}
RequestedFormatType::None => sources.nth(0).map(|x| *x),
}
}
fn distance_3d_camerafmt_relative(a: CameraFormat, b: CameraFormat) -> f64 {
let res_x_diff = b.resolution().x() - a.resolution().x();
let res_y_diff = b.resolution().y() - a.resolution().y();
let fps_diff = b.frame_rate() - a.frame_rate();
let x = res_x_diff.pow(2) as f64;
let y = res_y_diff.pow(2) as f64;
let z = fps_diff.pow(2) as f64;
x + y + z
}
+116
View File
@@ -0,0 +1,116 @@
use crate::frame_format::SourceFrameFormat;
use crate::types::Range;
use crate::{
frame_format::FrameFormat,
types::{ApiBackend, CameraFormat, Resolution},
};
use std::collections::{BTreeMap, BTreeSet};
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub enum CustomFormatRequestType {
HighestFPS,
HighestResolution,
Closest,
}
#[derive(Clone, Debug, Default, PartialOrd, PartialEq)]
pub struct FormatRequest {
resolution: Option<Range<Resolution>>,
frame_rate: Option<Range<u32>>,
frame_format: Option<Vec<FrameFormat>>,
req_type: Option<CustomFormatRequestType>,
}
impl FormatRequest {
pub fn new() -> Self {
Self::default()
}
pub fn with_resolution(mut self, resolution: Resolution, exact: bool) -> Self {
self.resolution = Some(resolution);
self.resolution_exact = exact;
self
}
pub fn reset_resolution(mut self) -> Self {
self.resolution = None;
self.resolution_exact = false;
self
}
pub fn with_frame_rate(mut self, frame_rate: u32, exact: bool) -> Self {
self.frame_rate = Some(frame_rate);
self.frame_rate_exact = exact;
self
}
pub fn with_standard_frame_rate() {}
pub fn reset_frame_rate(mut self) -> Self {
self.frame_rate = None;
self.frame_rate_exact = false;
self
}
pub fn with_frame_formats(mut self, frame_formats: Vec<FrameFormat>) -> Self {
self.frame_format = Some(frame_formats);
self
}
pub fn with_standard_frame_formats(mut self) -> Self {
self.append_frame_formats(&mut vec![
FrameFormat::MJpeg,
FrameFormat::Rgb8,
FrameFormat::Yuv422,
FrameFormat::Nv12,
])
}
pub fn push_frame_format(mut self, frame_format: FrameFormat) -> Self {
match &mut self.frame_format {
Some(ffs) => ffs.push(frame_format),
None => self.frame_format = Some(vec![frame_format]),
}
self
}
pub fn remove_frame_format(mut self, frame_format: FrameFormat) -> Self {
if let Some(ffs) = &mut self.frame_format {
if let Some(idx) = ffs.iter().position(frame_format) {
ffs.remove(idx)
}
}
self
}
pub fn append_frame_formats(mut self, frame_formats: &mut Vec<FrameFormat>) -> Self {
match &mut self.frame_format {
Some(ffs) => ffs.append(frame_formats),
None => self.frame_format = Some(frame_formats.clone()),
}
self
}
pub fn reset_frame_formats(mut self) -> Self {
self.frame_format = None;
self
}
pub fn with_request_type(mut self, request_type: CustomFormatRequestType) -> Self {
self.req_type = Some(request_type);
self
}
pub fn reset_request_type(mut self) -> Self {
self.req_type = None;
self
}
}
pub fn resolve_format_request(
request: FormatRequest,
availible_formats: Vec<CameraFormat>,
) -> CameraFormat {
// filter out by
}
+2 -1
View File
@@ -21,8 +21,9 @@
//! Core type definitions for `nokhwa`
pub mod buffer;
pub mod error;
pub mod format_filter;
pub mod format_request;
pub mod frame_format;
pub mod traits;
pub mod types;
pub mod decoder;
pub mod utils;
+1 -12
View File
@@ -17,7 +17,7 @@
use crate::{
buffer::Buffer,
error::NokhwaError,
format_filter::FormatFilter,
format_request::FormatFilter,
frame_format::SourceFrameFormat,
types::{
ApiBackend, CameraControl, CameraFormat, CameraInfo, ControlValueSetter,
@@ -315,17 +315,6 @@ pub trait AsyncCaptureTrait: CaptureTrait {
fourcc: SourceFrameFormat,
) -> Result<(), NokhwaError>;
/// Gets the value of [`KnownCameraControl`].
/// # Errors
/// If the `control` is not supported or there is an error while getting the camera control values (e.g. unexpected value, too high, etc)
/// this will error.
async fn camera_control_async(&self, control: KnownCameraControl) -> Result<CameraControl, NokhwaError>;
/// Gets the current supported list of [`KnownCameraControl`]
/// # Errors
/// If the list cannot be collected, this will error. This can be treated as a "nothing supported".
async fn camera_controls_async(&self) -> Result<Vec<CameraControl>, NokhwaError>;
/// Sets the control to `control` in the camera.
/// Usually, the pipeline is calling [`camera_control()`](CaptureTrait::camera_control), getting a camera control that way
/// then calling [`value()`](CameraControl::value()) to get a [`ControlValueSetter`] and setting the value that way.
+93 -16
View File
@@ -1,25 +1,101 @@
use crate::{
error::NokhwaError,
format_filter::RequestedFormatType,
frame_format::{FrameFormat, SourceFrameFormat},
};
#[cfg(feature = "serialize")]
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
use std::{
borrow::Borrow,
cmp::Ordering,
fmt::{Display, Formatter},
};
impl Default for RequestedFormatType {
fn default() -> Self {
RequestedFormatType::None
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub struct Range<T>
where
T: Copy + Clone + Debug + PartialOrd + PartialEq,
{
minimum: Option<T>,
lower_inclusive: bool,
maximum: Option<T>,
upper_inclusive: bool,
preferred: T,
}
impl<T> Range<T>
where
T: Copy + Clone + Debug + PartialOrd + PartialEq,
{
pub fn new(preferred: T, min: Option<T>, max: Option<T>) -> Self {
Self {
minimum: min,
lower_inclusive: true,
maximum: max,
upper_inclusive: false,
preferred,
}
}
pub fn with_inclusive(
preferred: T,
min: Option<T>,
lower_inclusive: bool,
max: Option<T>,
upper_inclusive: bool,
) -> Self {
Self {
minimum: min,
lower_inclusive,
maximum: max,
upper_inclusive,
preferred,
}
}
pub fn does_fit(&self, item: T) -> bool {
if item == self.preferred {
true
}
if let Some(min) = self.minimum {
let test = if self.lower_inclusive {
min >= item
} else {
min > item
};
if test {
return false;
}
}
if let Some(max) = self.maximum {
let test = if self.lower_inclusive {
max <= item
} else {
max < item
};
if test {
return false;
}
}
true
}
}
impl Display for RequestedFormatType {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{self:?}")
impl<T> Default for Range<T>
where
T: Default,
{
fn default() -> Self {
Range {
minimum: None,
lower_inclusive: true,
maximum: None,
upper_inclusive: false,
preferred: T::default(),
}
}
}
@@ -308,7 +384,7 @@ 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: &str, description: &str, misc: &str, index: &CameraIndex) -> Self {
CameraInfo {
human_name: human_name.to_string(),
description: description.to_string(),
@@ -563,8 +639,8 @@ pub enum ControlValueDescription {
},
StringList {
value: String,
availible: Vec<String>
}
availible: Vec<String>,
},
}
impl ControlValueDescription {
@@ -598,7 +674,9 @@ impl ControlValueDescription {
ControlValueDescription::RGB { value, .. } => {
ControlValueSetter::RGB(value.0, value.1, value.2)
}
ControlValueDescription::StringList { value, .. } => ControlValueSetter::StringList(value.clone()),
ControlValueDescription::StringList { value, .. } => {
ControlValueSetter::StringList(value.clone())
}
}
}
@@ -696,7 +774,7 @@ impl ControlValueDescription {
},
ControlValueDescription::StringList { value, availible } => {
availible.contains(setter.as_str())
},
}
}
// match setter {
@@ -864,7 +942,7 @@ impl Display for ControlValueDescription {
}
ControlValueDescription::StringList { value, availible } => {
write!(f, "Current: {value}, Availible: {availible:?}")
},
}
}
}
}
@@ -1113,7 +1191,7 @@ impl Display for ControlValueSetter {
}
ControlValueSetter::StringList(s) => {
write!(f, "StringListValue: {s}")
},
}
}
}
}
@@ -1346,7 +1424,7 @@ pub fn yuyv422_to_rgb(data: &[u8], rgba: bool) -> Result<Vec<u8>, NokhwaError> {
/// If the stream is invalid Yuv422, or the destination buffer is not large enough, this will error.
#[inline]
pub fn buf_yuyv422_to_rgb(data: &[u8], dest: &mut [u8], rgba: bool) -> Result<(), NokhwaError> {
let mut buf:Vec<u8> = Vec::new();
let mut buf: Vec<u8> = Vec::new();
if data.len() % 4 != 0 {
return Err(NokhwaError::ProcessFrameError {
src: FrameFormat::Yuv422.into(),
@@ -1381,7 +1459,6 @@ pub fn buf_yuyv422_to_rgb(data: &[u8], dest: &mut [u8], rgba: bool) -> Result<()
Ok(())
}
// equation from https://en.wikipedia.org/wiki/YUV#Converting_between_Y%E2%80%B2UV_and_RGB
/// Convert `YCbCr` 4:4:4 to a RGB888. [For further reading](https://en.wikipedia.org/wiki/YUV#Converting_between_Y%E2%80%B2UV_and_RGB)
#[allow(clippy::many_single_char_names)]
+483 -264
View File
@@ -1,25 +1,26 @@
use async_trait::async_trait;
use js_sys::{Array, Object, Reflect, Map, Function};
use js_sys::{Array, Function, Map, Reflect};
use nokhwa_core::buffer::Buffer;
use nokhwa_core::error::NokhwaError;
use nokhwa_core::format_filter::FormatFilter;
use nokhwa_core::format_request::FormatFilter;
use nokhwa_core::frame_format::{FrameFormat, SourceFrameFormat};
use nokhwa_core::traits::{AsyncCaptureTrait, Backend, CaptureTrait};
use nokhwa_core::types::{
ApiBackend, CameraControl, CameraFormat, CameraIndex, CameraInfo, ControlValueSetter,
KnownCameraControl, Resolution, KnownCameraControlFlag,
KnownCameraControl, KnownCameraControlFlag, Resolution,
};
use v4l::Control;
use wasm_bindgen_futures::JsFuture;
use nokhwa_core::utils::min_max_range;
use std::borrow::Cow;
use std::collections::{HashMap, BTreeMap, HashSet};
use std::collections::{BTreeMap, HashMap, HashSet};
use std::future::Future;
use wasm_bindgen::{JsCast, JsValue};
use wasm_bindgen_futures::JsFuture;
use web_sys::{
CanvasRenderingContext2d, Document, Element, MediaDevices, Navigator, OffscreenCanvas, Window, MediaStream, MediaStreamConstraints, HtmlCanvasElement, MediaDeviceInfo, MediaDeviceKind, MediaStreamTrack, MediaTrackSettings,
CanvasRenderingContext2d, Document, Element, HtmlCanvasElement, MediaDeviceInfo,
MediaDeviceKind, MediaDevices, MediaStream, MediaStreamConstraints, MediaStreamTrack,
MediaTrackSettings, Navigator, OffscreenCanvas, Window,
};
macro_rules! jsv {
($value:expr) => {{
JsValue::from($value)
@@ -180,16 +181,17 @@ fn control_to_str(control: KnownCameraControl) -> &'static str {
KnownCameraControl::Exposure => "exposureMode",
KnownCameraControl::Iris => "focusDistance",
KnownCameraControl::Focus => "focusMode",
KnownCameraControl::Other(u) => {
match u {
8 => "aspectRatio",
16 => "facingMode",
32 => "resizeMode",
64 => "attachedCanvasMode",
128 => "pointsOfInterest",
8192 => "torch",
_ => "",
}
KnownCameraControl::Other(u) => match u {
0 => "frameRate",
1 => "width",
2 => "height",
8 => "aspectRatio",
16 => "facingMode",
32 => "resizeMode",
64 => "attachedCanvasMode",
128 => "pointsOfInterest",
8192 => "torch",
_ => "",
},
}
}
@@ -233,7 +235,7 @@ impl AsRef<str> for JSCameraMeteringMode {
JSCameraMeteringMode::Continuous => "continuous",
}
}
}
}
impl Into<JsValue> for JSCameraMeteringMode {
fn into(self) -> JsValue {
@@ -262,12 +264,10 @@ pub struct BrowserCamera {
info: CameraInfo,
format: CameraFormat,
media_stream: MediaStream,
track: MediaStreamTrack,
init: bool,
custom_controls: HashMap<u128, CameraControl>,
controls: HashMap<KnownCameraControl, CameraControl>,
canvas_attachment: Option<String>,
supported_controls: HashSet<KnownCameraControl>,
cavnas: Option<CanvasType>,
cavnas: Option<String>,
context: Option<CanvasRenderingContext2d>,
}
@@ -285,10 +285,9 @@ impl BrowserCamera {
video_constraints.set(&JsValue::from_str("tilt"), &JsValue::TRUE);
video_constraints.set(&JsValue::from_str("zoom"), &JsValue::TRUE);
let stream: MediaStream = match media_devices.get_user_media_with_constraints(&MediaStreamConstraints::new().video(
&video_constraints
))
{
let stream: MediaStream = match media_devices.get_user_media_with_constraints(
&MediaStreamConstraints::new().video(&video_constraints),
) {
Ok(promise) => {
let future = JsFuture::from(promise);
match future.await {
@@ -298,21 +297,23 @@ impl BrowserCamera {
}
Err(why) => {
return Err(NokhwaError::OpenDeviceError(
"MediaDevicesGetUserMediaJsFuture".to_string(), format!("{why:?}"),
"MediaDevicesGetUserMediaJsFuture".to_string(),
format!("{why:?}"),
))
}
}
}
Err(why) => {
return Err(NokhwaError::OpenDeviceError(
"MediaDevicesGetUserMedia".to_string(), format!("{why:?}"),
"MediaDevicesGetUserMedia".to_string(),
format!("{why:?}"),
))
}
};
let media_info = match media_devices.enumerate_devices() {
Ok(i) => {
let future = JsFuture::from(promise);
let future = JsFuture::from(i);
match future.await {
Ok(devs) => {
let arr = Array::from(&devs);
@@ -321,46 +322,69 @@ impl BrowserCamera {
let dr = arr.get(i as u32);
if dr == JsValue::UNDEFINED {
return Err(NokhwaError::StructureError { structure: "MediaDeviceInfo".to_string(), error: "undefined".to_string() })
return Err(NokhwaError::StructureError {
structure: "MediaDeviceInfo".to_string(),
error: "undefined".to_string(),
});
}
MediaDeviceInfo::from(dr)
}
CameraIndex::String(s) => {
match arr.iter().map(MediaDeviceInfo::from)
.filter(|mdi| {
mdi.device_id() == s
}).nth(0) {
match arr
.iter()
.map(MediaDeviceInfo::from)
.filter(|mdi| mdi.device_id() == s)
.nth(0)
{
Some(i) => i,
None => return Err(NokhwaError::StructureError { structure: "MediaDeviceInfo".to_string(), error: "no id".to_string() })
None => {
return Err(NokhwaError::StructureError {
structure: "MediaDeviceInfo".to_string(),
error: "no id".to_string(),
})
}
}
}
}
}
Err(why) => {
return Err(NokhwaError::StructureError { structure: "MediaDeviceInfo Enumerate Devices Promise".to_string(), error: format!("{why:?}") })
return Err(NokhwaError::StructureError {
structure: "MediaDeviceInfo Enumerate Devices Promise".to_string(),
error: format!("{why:?}"),
})
}
}
}
Err(why) => {
return Err(NokhwaError::GetPropertyError { property: "MediaDeviceInfo".to_string(), error: format!("{why:?}") })
},
return Err(NokhwaError::GetPropertyError {
property: "MediaDeviceInfo".to_string(),
error: format!("{why:?}"),
})
}
};
let info = CameraInfo::new(&media_info.label(), media_info.kind().to_string(), &format!("{}:{}", media_info.group_id().to_string(), media_info.device_id().to_string()),index);
let track = stream.get_video_tracks().iter().nth(0).map(|x| element_cast(, name));
Ok(BrowserCamera {
index: index.clone(),
info, format: CameraFormat::default(),
init: false,
cavnas: None,
context: None,
media_stream: stream,
controls: HashMap::new(),
custom_controls: HashMap::new(),
supported_controls: HashSet::new(),
track: todo!(), })
let info = CameraInfo::new(
&media_info.label(),
&*media_info.kind().to_string(),
&format!(
"{}:{}",
media_info.group_id().to_string(),
media_info.device_id().to_string()
),
index,
);
Ok(BrowserCamera {
index: index.clone(),
info,
format: CameraFormat::default(),
init: false,
cavnas: None,
context: None,
media_stream: stream,
supported_controls: HashSet::new(),
canvas_attachment: None,
})
}
}
@@ -369,9 +393,7 @@ impl Backend for BrowserCamera {
}
impl CaptureTrait for BrowserCamera {
fn init(&mut self) -> Result<(), NokhwaError> {
}
fn init(&mut self) -> Result<(), NokhwaError> {}
fn init_with_format(&mut self, format: FormatFilter) -> Result<CameraFormat, NokhwaError> {
self.init()?;
@@ -436,7 +458,191 @@ impl CaptureTrait for BrowserCamera {
}
fn camera_control(&self, control: KnownCameraControl) -> Result<CameraControl, NokhwaError> {
// TODO: Werid Controls like framerate and attach support
if let KnownCameraControl::Other(custom) = control {
if custom == 64 {
// attached canvas mode
return Ok(CameraControl::new(
KnownCameraControl::Other(64),
"AttachedCanvasMode".to_string(),
nokhwa_core::types::ControlValueDescription::String {
value: self.canvas_attachment,
default: None,
},
vec![],
active,
));
}
}
let cam_str = control_to_str(contorl);
let capabilities_fn = match unsafe { Reflect::get(&self.track, "getCapabilities") } {
Ok(v) => match v.dyn_ref::<Function>() {
Some(fx) => fx,
None => {
return Err(NokhwaError::GetPropertyError {
property: "getCapabilities".to_string(),
error: "getCapabilities is not a function!".to_string(),
})
}
},
Err(why) => {
return Err(NokhwaError::GetPropertyError {
property: "getCapabilities".to_string(),
error: why.as_string().unwrap_or_default(),
})
}
};
let capabilities = match capabilities_fn.call0(&self.track) {
Ok(c) => c,
Err(v) => NokhwaError::GetPropertyError {
property: "getCapabilities".to_string(),
error: why.as_string().unwrap_or_default(),
}, // ok i guess, thanks vscode
};
let settings = self.track.get_settings();
let constraint_value = match unsafe { Reflect::get(&constraints, cam_str) } {
Ok(v) => v,
Err(why) => {
return Err(NokhwaError::GetPropertyError {
property: cam_str.to_string(),
error: why.as_string().unwrap_or_default(),
})
}
};
let setting_value = match unsafe { Reflect::get(&settings, cam_str) } {
Ok(v) => v,
Err(why) => {
return Err(NokhwaError::GetPropertyError {
property: cam_str.to_string(),
error: why.as_string().unwrap_or_default(),
})
}
};
// setting range!
if unsafe { Reflect::get(&setting_value, "min").is_ok() } {
let min = match unsafe { Reflect::get(&setting_value, "min") } {
Ok(v) => v.as_f64(),
Err(why) => {
return Err(NokhwaError::GetPropertyError {
property: "min".to_string(),
error: why.as_string().unwrap_or_default(),
})
}
};
let min = match min {
Some(v) => v,
None => {
return Err(NokhwaError::GetPropertyError {
property: "min".to_string(),
error: "Not a f64! Did the API change?".to_string(),
})
}
};
let max = match unsafe { Reflect::get(&setting_value, "max") } {
Ok(v) => v.as_f64(),
Err(why) => {
return Err(NokhwaError::GetPropertyError {
property: "max".to_string(),
error: why.as_string().unwrap_or_default(),
})
}
};
let max = match max {
Some(v) => v,
None => {
return Err(NokhwaError::GetPropertyError {
property: "max".to_string(),
error: "Not a f64! Did the API change?".to_string(),
})
}
};
let step = match unsafe { Reflect::get(&setting_value, "step") } {
Ok(v) => v.as_f64(),
Err(why) => {
return Err(NokhwaError::GetPropertyError {
property: "step".to_string(),
error: why.as_string().unwrap_or_default(),
})
}
};
let step = match step {
Some(v) => v,
None => {
return Err(NokhwaError::GetPropertyError {
property: "step".to_string(),
error: "Not a f64! Did the API change?".to_string(),
})
}
};
let value = match constraint_value.as_f64() {
Some(v) => v,
None => {
return Err(NokhwaError::GetPropertyError {
property: "value".to_string(),
error: "Not a f64! Did the API change?".to_string(),
})
}
};
return Ok(CameraControl::new(
control,
cam_str.to_string(),
nokhwa_core::types::ControlValueDescription::FloatRange {
min,
max,
value,
step,
default: f64::default(),
},
vec![],
true,
));
}
// im a sequence<DOMString>
else if setting_value.is_array() {
let availible = Array::from(&setting_value)
.iter()
.map(|x| match x.as_string() {
Some(v) => format!("{v}:"),
None => String::new(),
})
.collect::<String>();
let value = match constraint_value.as_string() {
Some(v) => v,
None => {
return Err(NokhwaError::GetPropertyError {
property: "value".to_string(),
error: "Not a String! Did the API change?".to_string(),
})
}
};
return Ok(CameraControl::new(
control,
cam_str.to_string(),
nokhwa_core::types::ControlValueDescription::StringList { value, availible },
vec![],
true,
));
}
// nope im a bool
else {
let is_truthy = constraint_value.is_truthy();
return Ok(CameraControl::new(
control,
cam_str.to_string(),
nokhwa_core::types::ControlValueDescription::Boolean {
value: is_truthy,
default: false,
},
flag,
true,
));
}
}
fn camera_controls(&self) -> Result<Vec<CameraControl>, NokhwaError> {
@@ -479,7 +685,6 @@ impl AsyncCaptureTrait for BrowserCamera {
let media_devices = media_devices(&window.navigator())?;
// request permission for camera
// first populate supported controls and see if we have our required controls
// required: FPS, Resolution (width + height)
@@ -490,149 +695,245 @@ impl AsyncCaptureTrait for BrowserCamera {
let mut supported_constraints = HashSet::new();
let defaults_satisfied = {
Reflect::get(&browser_constraints, "frameRate".into()).map(|x| x.is_truthy()).unwrap_or(false) && Reflect::get(&browser_constraints, "width".into()).map(|x| x.is_truthy()).unwrap_or(false) && Reflect::get(&browser_constraints, "height".into()).map(|x| x.is_truthy()).unwrap_or(false)
unsafe { Reflect::get(&browser_constraints, "frameRate".into()) }
.map(|x| x.is_truthy())
.unwrap_or(false)
&& unsafe { Reflect::get(&browser_constraints, "width".into()) }
.map(|x| x.is_truthy())
.unwrap_or(false)
&& unsafe { Reflect::get(&browser_constraints, "height".into()) }
.map(|x| x.is_truthy())
.unwrap_or(false)
};
if !defaults_satisfied {
return Err(NokhwaError::InitializeError { backend: ApiBackend::Browser, error: "Your browser does not support the required constraints! (frameRate, width, height)".to_string() });
}
// STAY ~~WHITE~~ CLEAN WITH US! JOIN ~~WHITE~~ MATCH EXPRESSION SOCIETY!
// aspectRatio
if Reflect::get(&browser_constraints, "aspectRatio".into()).map(|x| x.is_truthy()).unwrap_or(false) {
supported_constraints.insert(KnownCameraControl::Other(8));
}
// SAFETY: /shurg
unsafe {
// aspectRatio
if Reflect::get(&browser_constraints, "aspectRatio".into())
.map(|x| x.is_truthy())
.unwrap_or(false)
{
supported_constraints.insert(KnownCameraControl::Other(8));
}
// facingMode
if Reflect::get(&browser_constraints, "facingMode".into()).map(|x| x.is_truthy()).unwrap_or(false) {
supported_constraints.insert(KnownCameraControl::Other(16));
}
// facingMode
if Reflect::get(&browser_constraints, "facingMode".into())
.map(|x| x.is_truthy())
.unwrap_or(false)
{
supported_constraints.insert(KnownCameraControl::Other(16));
}
// resizeMode
if Reflect::get(&browser_constraints, "resizeMode".into()).map(|x| x.is_truthy()).unwrap_or(false) {
supported_constraints.insert(KnownCameraControl::Other(32));
}
// resizeMode
if Reflect::get(&browser_constraints, "resizeMode".into())
.map(|x| x.is_truthy())
.unwrap_or(false)
{
supported_constraints.insert(KnownCameraControl::Other(32));
}
// attachedCanvasMode
supported_constraints.insert(KnownCameraControl::Other(64));
// attachedCanvasMode
supported_constraints.insert(KnownCameraControl::Other(64));
// whiteBalanceMode
if Reflect::get(&browser_constraints, "whiteBalanceMode".into()).map(|x| x.is_truthy()).unwrap_or(false) {
supported_constraints.insert(KnownCameraControl::WhiteBalance);
}
// whiteBalanceMode
if Reflect::get(&browser_constraints, "whiteBalanceMode".into())
.map(|x| x.is_truthy())
.unwrap_or(false)
{
supported_constraints.insert(KnownCameraControl::WhiteBalance);
}
// exposureMode
if Reflect::get(&browser_constraints, "exposureMode".into()).map(|x| x.is_truthy()).unwrap_or(false) {
supported_constraints.insert(KnownCameraControl::Exposure);
}
// exposureMode
if Reflect::get(&browser_constraints, "exposureMode".into())
.map(|x| x.is_truthy())
.unwrap_or(false)
{
supported_constraints.insert(KnownCameraControl::Exposure);
}
// focusMode
if Reflect::get(&browser_constraints, "focusMode".into()).map(|x| x.is_truthy()).unwrap_or(false) {
supported_constraints.insert(KnownCameraControl::Focus);
}
// focusMode
if Reflect::get(&browser_constraints, "focusMode".into())
.map(|x| x.is_truthy())
.unwrap_or(false)
{
supported_constraints.insert(KnownCameraControl::Focus);
}
// pointsOfInterest
if Reflect::get(&browser_constraints, "pointsOfInterest".into()).map(|x| x.is_truthy()).unwrap_or(false) {
supported_constraints.insert(KnownCameraControl::Other(128));
}
// pointsOfInterest
if Reflect::get(&browser_constraints, "pointsOfInterest".into())
.map(|x| x.is_truthy())
.unwrap_or(false)
{
supported_constraints.insert(KnownCameraControl::Other(128));
}
// exposureCompensation
if Reflect::get(&browser_constraints, "exposureCompensation".into()).map(|x| x.is_truthy()).unwrap_or(false) {
supported_constraints.insert(KnownCameraControl::BacklightComp);
}
// exposureCompensation
if Reflect::get(&browser_constraints, "exposureCompensation".into())
.map(|x| x.is_truthy())
.unwrap_or(false)
{
supported_constraints.insert(KnownCameraControl::BacklightComp);
}
// exposureTime
if Reflect::get(&browser_constraints, "exposureTime".into()).map(|x| x.is_truthy()).unwrap_or(false) {
supported_constraints.insert(KnownCameraControl::Gamma);
}
// exposureTime
if Reflect::get(&browser_constraints, "exposureTime".into())
.map(|x| x.is_truthy())
.unwrap_or(false)
{
supported_constraints.insert(KnownCameraControl::Gamma);
}
// colorTemprature
if Reflect::get(&browser_constraints, "colorTemprature".into()).map(|x| x.is_truthy()).unwrap_or(false) {
supported_constraints.insert(KnownCameraControl::Hue);
}
// colorTemprature
if Reflect::get(&browser_constraints, "colorTemprature".into())
.map(|x| x.is_truthy())
.unwrap_or(false)
{
supported_constraints.insert(KnownCameraControl::Hue);
}
// iso
if Reflect::get(&browser_constraints, "iso".into()).map(|x| x.is_truthy()).unwrap_or(false) {
supported_constraints.insert(KnownCameraControl::Gain);
}
// iso
if Reflect::get(&browser_constraints, "iso".into())
.map(|x| x.is_truthy())
.unwrap_or(false)
{
supported_constraints.insert(KnownCameraControl::Gain);
}
// brightness
if Reflect::get(&browser_constraints, "brightness".into()).map(|x| x.is_truthy()).unwrap_or(false) {
supported_constraints.insert(KnownCameraControl::Brightness);
}
// brightness
if Reflect::get(&browser_constraints, "brightness".into())
.map(|x| x.is_truthy())
.unwrap_or(false)
{
supported_constraints.insert(KnownCameraControl::Brightness);
}
// contrast
if Reflect::get(&browser_constraints, "contrast".into()).map(|x| x.is_truthy()).unwrap_or(false) {
supported_constraints.insert(KnownCameraControl::Contrast);
}
// contrast
if Reflect::get(&browser_constraints, "contrast".into())
.map(|x| x.is_truthy())
.unwrap_or(false)
{
supported_constraints.insert(KnownCameraControl::Contrast);
}
// pan
if Reflect::get(&browser_constraints, "pan".into()).map(|x| x.is_truthy()).unwrap_or(false) {
supported_constraints.insert(KnownCameraControl::Pan);
}
// pan
if Reflect::get(&browser_constraints, "pan".into())
.map(|x| x.is_truthy())
.unwrap_or(false)
{
supported_constraints.insert(KnownCameraControl::Pan);
}
// saturation
if Reflect::get(&browser_constraints, "saturation".into()).map(|x| x.is_truthy()).unwrap_or(false) {
supported_constraints.insert(KnownCameraControl::Saturation);
}
// saturation
if Reflect::get(&browser_constraints, "saturation".into())
.map(|x| x.is_truthy())
.unwrap_or(false)
{
supported_constraints.insert(KnownCameraControl::Saturation);
}
// sharpness
if Reflect::get(&browser_constraints, "sharpness".into()).map(|x| x.is_truthy()).unwrap_or(false) {
supported_constraints.insert(KnownCameraControl::Sharpness);
}
// sharpness
if Reflect::get(&browser_constraints, "sharpness".into())
.map(|x| x.is_truthy())
.unwrap_or(false)
{
supported_constraints.insert(KnownCameraControl::Sharpness);
}
// focusDistance
if Reflect::get(&browser_constraints, "focusDistance".into()).map(|x| x.is_truthy()).unwrap_or(false) {
supported_constraints.insert(KnownCameraControl::Iris);
}
// focusDistance
if Reflect::get(&browser_constraints, "focusDistance".into())
.map(|x| x.is_truthy())
.unwrap_or(false)
{
supported_constraints.insert(KnownCameraControl::Iris);
}
// tilt
if Reflect::get(&browser_constraints, "tilt".into()).map(|x| x.is_truthy()).unwrap_or(false) {
supported_constraints.insert(KnownCameraControl::Tilt);
}
// tilt
if Reflect::get(&browser_constraints, "tilt".into())
.map(|x| x.is_truthy())
.unwrap_or(false)
{
supported_constraints.insert(KnownCameraControl::Tilt);
}
// zoom
if Reflect::get(&browser_constraints, "zoom".into()).map(|x| x.is_truthy()).unwrap_or(false) {
supported_constraints.insert(KnownCameraControl::Zoom);
}
// zoom
if Reflect::get(&browser_constraints, "zoom".into())
.map(|x| x.is_truthy())
.unwrap_or(false)
{
supported_constraints.insert(KnownCameraControl::Zoom);
}
// torch
if Reflect::get(&browser_constraints, "torch".into()).map(|x| x.is_truthy()).unwrap_or(false) {
supported_constraints.insert(KnownCameraControl::Other(8192));
// torch
if Reflect::get(&browser_constraints, "torch".into())
.map(|x| x.is_truthy())
.unwrap_or(false)
{
supported_constraints.insert(KnownCameraControl::Other(8192));
}
}
// PUT ME INTO THE CHARLOTTE VESSEL COACH I'LL PROVE FREE WILL IS REAL
self.supported_controls = supported_constraints;
self.init = true;
// get values for supported controls
for control in self.supported_controls {
match control {
KnownCameraControl::Brightness => {
}
KnownCameraControl::Contrast => todo!(),
KnownCameraControl::Hue => todo!(),
KnownCameraControl::Saturation => todo!(),
KnownCameraControl::Sharpness => todo!(),
KnownCameraControl::Gamma => todo!(),
KnownCameraControl::WhiteBalance => todo!(),
KnownCameraControl::BacklightComp => todo!(),
KnownCameraControl::Gain => todo!(),
KnownCameraControl::Pan => todo!(),
KnownCameraControl::Tilt => todo!(),
KnownCameraControl::Zoom => todo!(),
KnownCameraControl::Exposure => todo!(),
KnownCameraControl::Iris => todo!(),
KnownCameraControl::Focus => todo!(),
KnownCameraControl::Other(_) => todo!(),
}
}
todo!()
Ok(())
}
async fn init_with_format_async(&mut self, format: FormatFilter) -> Result<CameraFormat, NokhwaError> {
todo!()
async fn init_with_format_async(
&mut self,
format: FormatFilter,
) -> Result<CameraFormat, NokhwaError> {
self.init_async()?;
// now we need to get all formats possible
let frame_rates = match self
.camera_control(KnownCameraControl::Other(0))?
.description()
{
nokhwa_core::types::ControlValueDescription::FloatRange { min, max, step, .. } => {
min_max_range(min, max, step)
}
_ => Err(NokhwaError::GetPropertyError {
property: "frameRate".to_string(),
error: "Bad FrameRate Type".to_string(),
}),
};
let widths = match self
.camera_control(KnownCameraControl::Other(1))?
.description()
{
nokhwa_core::types::ControlValueDescription::FloatRange { min, max, step, .. } => {
min_max_range(min, max, step)
}
_ => Err(NokhwaError::GetPropertyError {
property: "width".to_string(),
error: "Bad width Type".to_string(),
}),
};
let heights = match self
.camera_control(KnownCameraControl::Other(2))?
.description()
{
nokhwa_core::types::ControlValueDescription::FloatRange { min, max, step, .. } => {
min_max_range(min, max, step)
}
_ => Err(NokhwaError::GetPropertyError {
property: "height".to_string(),
error: "Bad height Type".to_string(),
}),
};
}
async fn refresh_camera_format_async(&mut self) -> Result<(), NokhwaError> {
@@ -643,7 +944,10 @@ impl AsyncCaptureTrait for BrowserCamera {
todo!()
}
async fn compatible_list_by_resolution_async(&mut self, fourcc: SourceFrameFormat) -> Result<HashMap<Resolution, Vec<u32>>, NokhwaError> {
async fn compatible_list_by_resolution_async(
&mut self,
fourcc: SourceFrameFormat,
) -> Result<HashMap<Resolution, Vec<u32>>, NokhwaError> {
todo!()
}
@@ -663,103 +967,18 @@ impl AsyncCaptureTrait for BrowserCamera {
todo!()
}
async fn set_frame_format_async(&mut self, fourcc: SourceFrameFormat) -> Result<(), NokhwaError> {
async fn set_frame_format_async(
&mut self,
fourcc: SourceFrameFormat,
) -> Result<(), NokhwaError> {
todo!()
}
// TODO: Verify that constraint_value and setting_value are in the right place and order!
async fn camera_control_async(&self, control: KnownCameraControl) -> Result<CameraControl, NokhwaError> {
// TODO: Werid Controls like framerate and attach support
let cam_str = control_to_str(contorl);
let capabilities_fn = match Reflect::get(&self.track, "getCapabilities") {
Ok(v) => match v.dyn_ref::<Function>() {
Some(fx) => fx,
None => return Err(NokhwaError::GetPropertyError{ property: "getCapabilities".to_string(), error: "getCapabilities is not a function!".to_string() }),
},
Err(why) => return Err(NokhwaError::GetPropertyError{ property: "getCapabilities".to_string(), error: why.as_string().unwrap_or_default() }),
};
let capabilities = match capabilities_fn.call0(&self.track) {
Ok(c) => c,
Err(V4L2_HDR10_MASTERING_WHITE_POINT_Y_HIGH) => NokhwaError::GetPropertyError{ property: "getCapabilities".to_string(), error: why.as_string().unwrap_or_default() }, // ok i guess, thanks vscode
};
let settings = self.track.get_settings();
let constraint_value = match Reflect::get(&constraints, cam_str) {
Ok(v) => v,
Err(why) => return Err(NokhwaError::GetPropertyError{ property: cam_str.to_string(), error: why.as_string().unwrap_or_default() }),
};
let setting_value = match Reflect::get(&settings, cam_str) {
Ok(v) => v,
Err(why) => return Err(NokhwaError::GetPropertyError{ property: cam_str.to_string(), error: why.as_string().unwrap_or_default() }),
};
// setting range!
if Reflect::get(&setting_value, "min").is_ok() {
let min = match Reflect::get(&setting_value, "min") {
Ok(v) => v.as_f64(),
Err(why) => return Err(NokhwaError::GetPropertyError{ property: "min".to_string(), error: why.as_string().unwrap_or_default() }),
};
let min = match min {
Some(v) => v,
None => return Err(NokhwaError::GetPropertyError{ property: "min".to_string(), error: "Not a f64! Did the API change?".to_string() }),
};
let max = match Reflect::get(&setting_value, "max") {
Ok(v) => v.as_f64(),
Err(why) => return Err(NokhwaError::GetPropertyError{ property: "max".to_string(), error: why.as_string().unwrap_or_default() }),
};
let max = match max {
Some(v) => v,
None => return Err(NokhwaError::GetPropertyError{ property: "max".to_string(), error: "Not a f64! Did the API change?".to_string() }),
};
let step = match Reflect::get(&setting_value, "step") {
Ok(v) => v.as_f64(),
Err(why) => return Err(NokhwaError::GetPropertyError{ property: "step".to_string(), error: why.as_string().unwrap_or_default() }),
};
let step = match step {
Some(v) => v,
None => return Err(NokhwaError::GetPropertyError{ property: "step".to_string(), error: "Not a f64! Did the API change?".to_string() }),
};
let value = match constraint_value.as_f64() {
Some(v) => v,
None => return Err(NokhwaError::GetPropertyError{ property: "value".to_string(), error: "Not a f64! Did the API change?".to_string() }),
};
return Ok(
CameraControl::new(control, cam_str.to_string(), nokhwa_core::types::ControlValueDescription::FloatRange { min, max, value, step, default: f64::default() }, vec![], true)
)
}
// im a sequence<DOMString>
else if setting_value.is_array() {
let availible = Array::from(&setting_value).iter().map(|x| {
match x.as_string() {
Some(v) => format!("{v}:"),
None => String::new(),
}
}).collect::<String>();
let value = match constraint_value.as_string() {
Some(v) => v,
None => return Err(NokhwaError::GetPropertyError{ property: "value".to_string(), error: "Not a String! Did the API change?".to_string() }),
};
return Ok(
CameraControl::new(control, cam_str.to_string(), nokhwa_core::types::ControlValueDescription::StringList { value, availible }, vec![], true)
)
}
// nope im a bool
else {
let is_truthy = constraint_value.is_truthy();
return Ok(
CameraControl::new(control, cam_str.to_string(), nokhwa_core::types::ControlValueDescription::Boolean { value: is_truthy, default: false }, flag, true)
)
}
}
async fn camera_controls_async(&self) -> Result<Vec<CameraControl>, NokhwaError> {
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: ControlValueSetter,
) -> Result<(), NokhwaError> {
todo!()
}
+1 -1
View File
@@ -14,7 +14,7 @@
* limitations under the License.
*/
use nokhwa_core::format_filter::FormatFilter;
use nokhwa_core::format_request::FormatFilter;
use nokhwa_core::frame_format::SourceFrameFormat;
use nokhwa_core::traits::Backend;
use nokhwa_core::{