diff --git a/Cargo.toml b/Cargo.toml index 4e768c9..60617af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/nokhwa-bindings-linux/src/lib.rs b/nokhwa-bindings-linux/src/lib.rs index 9684b0e..f879f23 100644 --- a/nokhwa-bindings-linux/src/lib.rs +++ b/nokhwa-bindings-linux/src/lib.rs @@ -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, diff --git a/nokhwa-core/src/format_filter.rs b/nokhwa-core/src/format_filter.rs deleted file mode 100644 index b2408d0..0000000 --- a/nokhwa-core/src/format_filter.rs +++ /dev/null @@ -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, - fcc_platform: BTreeMap>, - -} - -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 { - 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::>(); - sources.sort_by(|a, b| a.resolution().cmp(&b.resolution())); - sources.last().copied().copied() - } - RequestedFormatType::AbsoluteHighestFrameRate => { - let mut sources = sources.collect::>(); - 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::>(); - sources.sort(); - sources.last().copied().copied() - } - RequestedFormatType::HighestFrameRate(filter_res) => { - let mut sources = sources - .filter(|format| format.resolution() == filter_res) - .collect::>(); - 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::>(); - 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::>(); - 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::>(); - 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 -} diff --git a/nokhwa-core/src/format_request.rs b/nokhwa-core/src/format_request.rs new file mode 100644 index 0000000..b0d2b42 --- /dev/null +++ b/nokhwa-core/src/format_request.rs @@ -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>, + frame_rate: Option>, + frame_format: Option>, + req_type: Option, +} + +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) -> 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) -> 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 { + // filter out by +} diff --git a/nokhwa-core/src/lib.rs b/nokhwa-core/src/lib.rs index 8742091..f4fdf47 100644 --- a/nokhwa-core/src/lib.rs +++ b/nokhwa-core/src/lib.rs @@ -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; diff --git a/nokhwa-core/src/traits.rs b/nokhwa-core/src/traits.rs index a35b89a..af6d171 100644 --- a/nokhwa-core/src/traits.rs +++ b/nokhwa-core/src/traits.rs @@ -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; - - /// 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, 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. diff --git a/nokhwa-core/src/types.rs b/nokhwa-core/src/types.rs index 2b45f51..37113ed 100644 --- a/nokhwa-core/src/types.rs +++ b/nokhwa-core/src/types.rs @@ -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 +where + T: Copy + Clone + Debug + PartialOrd + PartialEq, +{ + minimum: Option, + lower_inclusive: bool, + maximum: Option, + upper_inclusive: bool, + preferred: T, +} + +impl Range +where + T: Copy + Clone + Debug + PartialOrd + PartialEq, +{ + pub fn new(preferred: T, min: Option, max: Option) -> Self { + Self { + minimum: min, + lower_inclusive: true, + maximum: max, + upper_inclusive: false, + preferred, + } + } + + pub fn with_inclusive( + preferred: T, + min: Option, + lower_inclusive: bool, + max: Option, + 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 Default for Range +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 + ?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 - } + availible: Vec, + }, } 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, 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 = Vec::new(); + let mut buf: Vec = 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)] diff --git a/src/backends/capture/browser_camera.rs b/src/backends/capture/browser_camera.rs index 154c813..bdf815e 100644 --- a/src/backends/capture/browser_camera.rs +++ b/src/backends/capture/browser_camera.rs @@ -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 for JSCameraMeteringMode { JSCameraMeteringMode::Continuous => "continuous", } } -} +} impl Into 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, - controls: HashMap, + canvas_attachment: Option, supported_controls: HashSet, - cavnas: Option, + cavnas: Option, context: Option, } @@ -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 { self.init()?; @@ -436,7 +458,191 @@ impl CaptureTrait for BrowserCamera { } fn camera_control(&self, control: KnownCameraControl) -> Result { - + // 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::() { + 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 + 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::(); + + 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, 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 + Ok(()) + } - 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!(), + async fn init_with_format_async( + &mut self, + format: FormatFilter, + ) -> Result { + 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(), + }), + }; - todo!() - } + 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(), + }), + }; - async fn init_with_format_async(&mut self, format: FormatFilter) -> Result { - todo!() + 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>, NokhwaError> { + async fn compatible_list_by_resolution_async( + &mut self, + fourcc: SourceFrameFormat, + ) -> Result>, NokhwaError> { todo!() } @@ -663,103 +967,18 @@ impl AsyncCaptureTrait for BrowserCamera { todo!() } - 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 { - // 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::() { - 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 - 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::(); - - 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, NokhwaError> { + async fn set_frame_format_async( + &mut self, + fourcc: SourceFrameFormat, + ) -> Result<(), 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!() } diff --git a/src/camera.rs b/src/camera.rs index 0ddbaa9..ffba83e 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -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::{