mirror of
https://github.com/l1npengtul/nokhwa.git
synced 2026-07-04 02:27:26 +00:00
add new control value type: StringList, in prog control support for BrowserCamera
This commit is contained in:
@@ -561,6 +561,10 @@ pub enum ControlValueDescription {
|
||||
max: (f64, f64, f64),
|
||||
default: (f64, f64, f64),
|
||||
},
|
||||
StringList {
|
||||
value: String,
|
||||
availible: Vec<String>
|
||||
}
|
||||
}
|
||||
|
||||
impl ControlValueDescription {
|
||||
@@ -594,6 +598,7 @@ impl ControlValueDescription {
|
||||
ControlValueDescription::RGB { value, .. } => {
|
||||
ControlValueSetter::RGB(value.0, value.1, value.2)
|
||||
}
|
||||
ControlValueDescription::StringList { value, .. } => ControlValueSetter::StringList(value.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -689,6 +694,9 @@ impl ControlValueDescription {
|
||||
Some(v) => *v.0 >= max.0 && *v.1 >= max.1 && *v.2 >= max.2,
|
||||
None => false,
|
||||
},
|
||||
ControlValueDescription::StringList { value, availible } => {
|
||||
availible.contains(setter.as_str())
|
||||
},
|
||||
}
|
||||
|
||||
// match setter {
|
||||
@@ -854,6 +862,9 @@ impl Display for ControlValueDescription {
|
||||
value.0, value.1, value.2, max.0, max.1, max.2, default.0, default.1, default.2
|
||||
)
|
||||
}
|
||||
ControlValueDescription::StringList { value, availible } => {
|
||||
write!(f, "Current: {value}, Availible: {availible:?}")
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -972,6 +983,7 @@ pub enum ControlValueSetter {
|
||||
Point(f64, f64),
|
||||
EnumValue(i64),
|
||||
RGB(f64, f64, f64),
|
||||
StringList(String),
|
||||
}
|
||||
|
||||
impl ControlValueSetter {
|
||||
@@ -1099,6 +1111,9 @@ impl Display for ControlValueSetter {
|
||||
ControlValueSetter::RGB(r, g, b) => {
|
||||
write!(f, "RGBValue: ({r}, {g}, {b})")
|
||||
}
|
||||
ControlValueSetter::StringList(s) => {
|
||||
write!(f, "StringListValue: {s}")
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use async_trait::async_trait;
|
||||
use js_sys::{Array, Object, Reflect};
|
||||
use js_sys::{Array, Object, Reflect, Map, Function};
|
||||
use nokhwa_core::buffer::Buffer;
|
||||
use nokhwa_core::error::NokhwaError;
|
||||
use nokhwa_core::format_filter::FormatFilter;
|
||||
@@ -7,15 +7,16 @@ 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,
|
||||
KnownCameraControl, Resolution, KnownCameraControlFlag,
|
||||
};
|
||||
use v4l::Control;
|
||||
use wasm_bindgen_futures::JsFuture;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::{HashMap, BTreeMap, HashSet};
|
||||
use std::future::Future;
|
||||
use wasm_bindgen::{JsCast, JsValue};
|
||||
use web_sys::{
|
||||
CanvasRenderingContext2d, Document, Element, MediaDevices, Navigator, OffscreenCanvas, Window, MediaStream, MediaStreamConstraints, HtmlCanvasElement, MediaDeviceInfo, MediaDeviceKind, MediaStreamTrack,
|
||||
CanvasRenderingContext2d, Document, Element, MediaDevices, Navigator, OffscreenCanvas, Window, MediaStream, MediaStreamConstraints, HtmlCanvasElement, MediaDeviceInfo, MediaDeviceKind, MediaStreamTrack, MediaTrackSettings,
|
||||
};
|
||||
|
||||
|
||||
@@ -162,7 +163,38 @@ fn set_autoplay_inline(element: &Element) -> Result<(), NokhwaError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
||||
fn control_to_str(control: KnownCameraControl) -> &'static str {
|
||||
match control {
|
||||
KnownCameraControl::Brightness => "brightness",
|
||||
KnownCameraControl::Contrast => "contrast",
|
||||
KnownCameraControl::Hue => "colorTemprature",
|
||||
KnownCameraControl::Saturation => "saturation",
|
||||
KnownCameraControl::Sharpness => "sharpness",
|
||||
KnownCameraControl::Gamma => "exposureTime",
|
||||
KnownCameraControl::WhiteBalance => "whiteBalanceMode",
|
||||
KnownCameraControl::BacklightComp => "exposureCompensation",
|
||||
KnownCameraControl::Gain => "iso",
|
||||
KnownCameraControl::Pan => "pan",
|
||||
KnownCameraControl::Tilt => "tilt",
|
||||
KnownCameraControl::Zoom => "zoom",
|
||||
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",
|
||||
_ => "",
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq::Zoom)]
|
||||
pub enum JSCameraFacingMode {
|
||||
Any,
|
||||
Environment,
|
||||
@@ -230,6 +262,7 @@ pub struct BrowserCamera {
|
||||
info: CameraInfo,
|
||||
format: CameraFormat,
|
||||
media_stream: MediaStream,
|
||||
track: MediaStreamTrack,
|
||||
init: bool,
|
||||
custom_controls: HashMap<u128, CameraControl>,
|
||||
controls: HashMap<KnownCameraControl, CameraControl>,
|
||||
@@ -247,7 +280,14 @@ impl BrowserCamera {
|
||||
let window = window()?;
|
||||
let media_devices = media_devices(&window.navigator())?;
|
||||
|
||||
let stream: MediaStream = match media_devices.get_user_media_with_constraints(&constraints)
|
||||
let mut video_constraints = Map::new();
|
||||
video_constraints.set(&JsValue::from_str("pan"), &JsValue::TRUE);
|
||||
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
|
||||
))
|
||||
{
|
||||
Ok(promise) => {
|
||||
let future = JsFuture::from(promise);
|
||||
@@ -308,9 +348,19 @@ impl BrowserCamera {
|
||||
},
|
||||
};
|
||||
|
||||
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.clone(),);
|
||||
|
||||
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() })
|
||||
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!(), })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -386,22 +436,7 @@ impl CaptureTrait for BrowserCamera {
|
||||
}
|
||||
|
||||
fn camera_control(&self, control: KnownCameraControl) -> Result<CameraControl, NokhwaError> {
|
||||
// controls
|
||||
|
||||
if self.supported_controls.get(&control).is_none() {
|
||||
return Err(NokhwaError::GetPropertyError { property: control.to_string(), error: "Not Supported".to_string() });
|
||||
}
|
||||
|
||||
// get the data!
|
||||
|
||||
let track =self.media_stream.get_video_tracks().get(0);
|
||||
|
||||
if track.is_undefined() || track.is_null() {
|
||||
return Err(NokhwaError::GetPropertyError { property: "MediaStreamTrack".to_string(), error: "Null".to_string() });
|
||||
}
|
||||
|
||||
let track = MediaStreamTrack::from(track);
|
||||
track.
|
||||
|
||||
}
|
||||
|
||||
fn camera_controls(&self) -> Result<Vec<CameraControl>, NokhwaError> {
|
||||
@@ -500,22 +535,22 @@ impl AsyncCaptureTrait for BrowserCamera {
|
||||
|
||||
// exposureCompensation
|
||||
if Reflect::get(&browser_constraints, "exposureCompensation".into()).map(|x| x.is_truthy()).unwrap_or(false) {
|
||||
supported_constraints.insert(KnownCameraControl::Exposure);
|
||||
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::Other(256));
|
||||
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::Other(512));
|
||||
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::Other(1024));
|
||||
supported_constraints.insert(KnownCameraControl::Gain);
|
||||
}
|
||||
|
||||
// brightness
|
||||
@@ -545,7 +580,7 @@ impl AsyncCaptureTrait for BrowserCamera {
|
||||
|
||||
// focusDistance
|
||||
if Reflect::get(&browser_constraints, "focusDistance".into()).map(|x| x.is_truthy()).unwrap_or(false) {
|
||||
supported_constraints.insert(KnownCameraControl::Other(2048));
|
||||
supported_constraints.insert(KnownCameraControl::Iris);
|
||||
}
|
||||
|
||||
// tilt
|
||||
@@ -555,7 +590,7 @@ impl AsyncCaptureTrait for BrowserCamera {
|
||||
|
||||
// zoom
|
||||
if Reflect::get(&browser_constraints, "zoom".into()).map(|x| x.is_truthy()).unwrap_or(false) {
|
||||
supported_constraints.insert(KnownCameraControl::Other(4096));
|
||||
supported_constraints.insert(KnownCameraControl::Zoom);
|
||||
}
|
||||
|
||||
// torch
|
||||
@@ -565,10 +600,6 @@ impl AsyncCaptureTrait for BrowserCamera {
|
||||
|
||||
// PUT ME INTO THE CHARLOTTE VESSEL COACH I'LL PROVE FREE WILL IS REAL
|
||||
|
||||
if supported_constraints.contains(&KnownCameraControl::Pan) || supported_constraints.contains(&KnownCameraControl::Tilt) || supported_constraints.contains(&KnownCameraControl::Other(4096)) {
|
||||
// TODO: Zoom pan and Tilt MUST BE REQUESTED HERE!!
|
||||
}
|
||||
|
||||
self.supported_controls = supported_constraints;
|
||||
|
||||
// get values for supported controls
|
||||
@@ -636,8 +667,92 @@ impl AsyncCaptureTrait for BrowserCamera {
|
||||
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!()
|
||||
// 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> {
|
||||
|
||||
Reference in New Issue
Block a user