diff --git a/Cargo.lock b/Cargo.lock index 8f05a63..a160eb9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1979,7 +1979,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" dependencies = [ "cfg-if 1.0.0", - "windows-targets 0.52.5", + "windows-targets 0.48.5", ] [[package]] @@ -2458,7 +2458,7 @@ dependencies = [ "nokhwa-bindings-macos", "nokhwa-bindings-windows", "nokhwa-core", - "opencv", + "opencv 0.92.0", "paste", "regex", "rgb", @@ -2515,8 +2515,9 @@ dependencies = [ "dcv-color-primitives", "image 0.25.0", "mozjpeg", - "opencv", + "opencv 0.93.1", "paste", + "rgb", "serde", "thiserror", "wgpu 22.0.0", @@ -2688,7 +2689,7 @@ dependencies = [ "libc", "num-traits", "once_cell", - "opencv-binding-generator", + "opencv-binding-generator 0.90.0", "pkg-config", "rgb", "semver", @@ -2697,6 +2698,26 @@ dependencies = [ "windows 0.56.0", ] +[[package]] +name = "opencv" +version = "0.93.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef60b95350049ceccc83f859e1fbf40875fc9b9c4fbffe33b340e099d05a56b2" +dependencies = [ + "cc", + "dunce", + "jobserver", + "libc", + "num-traits", + "once_cell", + "opencv-binding-generator 0.91.0", + "pkg-config", + "semver", + "shlex", + "vcpkg", + "windows 0.58.0", +] + [[package]] name = "opencv-binding-generator" version = "0.90.0" @@ -2711,6 +2732,21 @@ dependencies = [ "regex", ] +[[package]] +name = "opencv-binding-generator" +version = "0.91.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "984e10d6fda4aadda32e3723b7f59775fa7ecef1154a01d8273724e76657fec0" +dependencies = [ + "clang", + "clang-sys", + "dunce", + "once_cell", + "percent-encoding", + "regex", + "shlex", +] + [[package]] name = "ordered-float" version = "3.9.2" @@ -4222,7 +4258,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" dependencies = [ "windows-core 0.52.0", - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -4232,7 +4268,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1de69df01bdf1ead2f4ac895dc77c9351aefff65b2f3db429a343f9cbf05e132" dependencies = [ "windows-core 0.56.0", - "windows-targets 0.52.5", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +dependencies = [ + "windows-core 0.58.0", + "windows-targets 0.52.6", ] [[package]] @@ -4241,7 +4287,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -4250,10 +4296,23 @@ version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4698e52ed2d08f8658ab0c39512a7c00ee5fe2688c65f8c0a4f06750d729f2a6" dependencies = [ - "windows-implement", - "windows-interface", - "windows-result", - "windows-targets 0.52.5", + "windows-implement 0.56.0", + "windows-interface 0.56.0", + "windows-result 0.1.1", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement 0.58.0", + "windows-interface 0.58.0", + "windows-result 0.2.0", + "windows-strings", + "windows-targets 0.52.6", ] [[package]] @@ -4267,6 +4326,17 @@ dependencies = [ "syn 2.0.55", ] +[[package]] +name = "windows-implement" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", +] + [[package]] name = "windows-interface" version = "0.56.0" @@ -4278,13 +4348,43 @@ dependencies = [ "syn 2.0.55", ] +[[package]] +name = "windows-interface" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", +] + [[package]] name = "windows-result" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "749f0da9cc72d82e600d8d2e44cadd0b9eedb9038f71a1c58556ac1c5791813b" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result 0.2.0", + "windows-targets 0.52.6", ] [[package]] @@ -4315,7 +4415,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -4335,18 +4435,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -4363,9 +4463,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -4387,9 +4487,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -4411,15 +4511,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -4441,9 +4541,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -4465,9 +4565,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -4483,9 +4583,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -4507,9 +4607,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winit" @@ -4594,9 +4694,9 @@ checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a" [[package]] name = "yuvutils-rs" -version = "0.3.0" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b579307cc265a693bc908bf2dbde8578ba7e7fe1a7dcc71dbd6b84e063f356" +checksum = "97b0c026d402c14683f21eae52b33dd76ba47c548273a7eb526eed5ce2f46b65" [[package]] name = "zerocopy" diff --git a/devenv.nix b/devenv.nix index d173ab4..6b11a54 100644 --- a/devenv.nix +++ b/devenv.nix @@ -3,15 +3,19 @@ { # https://devenv.sh/basics/ env.GREET = "devenv"; - + env.LIBCLANG_PATH = "${config.env.DEVENV_PROFILE}/lib/libclang.so"; # https://devenv.sh/packages/ - packages = [ pkgs.git pkgs.v4l-utils pkgs.clangStdenv pkgs.mesa pkgs.rustup pkgs.rustfmt pkgs.cargo ]; + packages = [ pkgs.git pkgs.v4l-utils pkgs.clangStdenv pkgs.mesa + pkgs.cmake pkgs.opencv4 pkgs.systemdLibs pkgs.libudev-zero + pkgs.libudev0-shim pkgs.vcpkg pkgs.pkg-config pkgs.libclang + pkgs.fontconfig pkgs.clang-tools pkgs.linuxHeaders + ]; # https://devenv.sh/languages/ - # languages.rust.enable = true; - + languages.rust.enable = true; + languages.c.enable = true; # https://devenv.sh/processes/ - # processes.cargo-watch.exec = "cargo-watch"; + processes.cargo-watch.exec = "cargo-watch"; # https://devenv.sh/services/ # services.postgres.enable = true; @@ -24,6 +28,7 @@ enterShell = '' hello git --version + echo ''${LIBCLANG_PATH} ''; # https://devenv.sh/tests/ @@ -32,6 +37,8 @@ git --version | grep --color=auto "${pkgs.git.version}" ''; + + # https://devenv.sh/pre-commit-hooks/ # pre-commit.hooks.shellcheck.enable = true; diff --git a/nokhwa-bindings-linux/src/lib.rs b/nokhwa-bindings-linux/src/lib.rs index 8344efa..5b016d2 100644 --- a/nokhwa-bindings-linux/src/lib.rs +++ b/nokhwa-bindings-linux/src/lib.rs @@ -22,8 +22,8 @@ mod internal { error::NokhwaError, traits::CaptureTrait, types::{ - ApiBackend, CameraControl, CameraFormat, CameraIndex, CameraInfo, - ControlValueDescription, ControlValueSetter, FrameFormat, KnownCameraControl, + ApiBackend, CameraFormat, CameraIndex, CameraInfo, + FrameFormat, KnownCameraControlFlag, RequestedFormat, RequestedFormatType, Resolution, }, }; @@ -34,8 +34,8 @@ mod internal { }; use v4l::{ control::{Control, Flags, Type, Value}, - frameinterval::FrameIntervalEnum, - framesize::FrameSizeEnum, + frameinterval::FrameIntervalEnum + , io::traits::CaptureStream, prelude::MmapStream, video::{capture::Parameters, Capture}, @@ -47,6 +47,7 @@ mod internal { V4L2_CID_IRIS_RELATIVE, V4L2_CID_PAN_RELATIVE, V4L2_CID_SATURATION, V4L2_CID_SHARPNESS, V4L2_CID_TILT_RELATIVE, V4L2_CID_WHITE_BALANCE_TEMPERATURE, V4L2_CID_ZOOM_RELATIVE, }; + use nokhwa_core::controls::{CameraControl, ControlValueDescription, ControlValueSetter, KnownCameraControl}; /// Attempts to convert a [`KnownCameraControl`] into a V4L2 Control ID. /// If the associated control is not found, this will return `None` (`ColorEnable`, `Roll`) @@ -626,12 +627,13 @@ mod internal { use nokhwa_core::error::NokhwaError; use nokhwa_core::traits::CaptureTrait; use nokhwa_core::types::{ - ApiBackend, CameraControl, CameraFormat, CameraIndex, CameraInfo, ControlValueSetter, - FrameFormat, KnownCameraControl, RequestedFormat, Resolution, + ApiBackend, CameraFormat, CameraIndex, CameraInfo, + FrameFormat, RequestedFormat, Resolution, }; use std::borrow::Cow; use std::collections::HashMap; use std::marker::PhantomData; + use nokhwa_core::controls::{CameraControl, ControlValueSetter, KnownCameraControl}; /// Attempts to convert a [`KnownCameraControl`] into a V4L2 Control ID. /// If the associated control is not found, this will return `None` (`ColorEnable`, `Roll`) diff --git a/nokhwa-bindings-macos/src/lib.rs b/nokhwa-bindings-macos/src/lib.rs index 48df67e..1431c28 100644 --- a/nokhwa-bindings-macos/src/lib.rs +++ b/nokhwa-bindings-macos/src/lib.rs @@ -225,8 +225,8 @@ mod internal { use nokhwa_core::{ error::NokhwaError, types::{ - ApiBackend, CameraControl, CameraFormat, CameraIndex, CameraInfo, - ControlValueDescription, ControlValueSetter, FrameFormat, KnownCameraControl, + ApiBackend, CameraFormat, CameraIndex, CameraInfo, + FrameFormat, KnownCameraControlFlag, Resolution, }, }; @@ -246,6 +246,7 @@ mod internal { ffi::{c_float, c_void, CStr}, sync::Arc, }; + use nokhwa_core::controls::{CameraControl, ControlValueDescription, ControlValueSetter, KnownCameraControl}; const UTF8_ENCODING: usize = 4; type CGFloat = c_float; diff --git a/nokhwa-bindings-windows/src/lib.rs b/nokhwa-bindings-windows/src/lib.rs index 2ae75a8..c7e3476 100644 --- a/nokhwa-bindings-windows/src/lib.rs +++ b/nokhwa-bindings-windows/src/lib.rs @@ -31,8 +31,8 @@ pub mod wmf { use nokhwa_core::error::NokhwaError; use nokhwa_core::types::{ - ApiBackend, CameraControl, CameraFormat, CameraIndex, CameraInfo, ControlValueDescription, - ControlValueSetter, FrameFormat, KnownCameraControl, KnownCameraControlFlag, Resolution, + ApiBackend, CameraFormat, CameraIndex, CameraInfo, + FrameFormat, KnownCameraControlFlag, Resolution, }; use once_cell::sync::Lazy; use std::ffi::c_void; @@ -46,6 +46,7 @@ pub mod wmf { Arc, }, }; + use nokhwa_core::controls::{CameraControl, ControlValueDescription, ControlValueSetter, KnownCameraControl}; use windows::Win32::Media::DirectShow::{CameraControl_Flags_Auto, CameraControl_Flags_Manual}; use windows::Win32::Media::MediaFoundation::{ IMFMediaType, MFCreateSample, MF_SOURCE_READER_FIRST_VIDEO_STREAM, @@ -1225,10 +1226,10 @@ pub mod wmf { pub mod wmf { use nokhwa_core::error::NokhwaError; use nokhwa_core::types::{ - CameraControl, CameraFormat, CameraIndex, CameraInfo, ControlValueSetter, - KnownCameraControl, + CameraFormat, CameraIndex, CameraInfo, }; use std::borrow::Cow; + use nokhwa_core::controls::{CameraControl, ControlValueSetter, KnownCameraControl}; pub fn initialize_mf() -> Result<(), NokhwaError> { Err(NokhwaError::NotImplementedError( diff --git a/nokhwa-core/Cargo.toml b/nokhwa-core/Cargo.toml index 33038ca..42017a3 100644 --- a/nokhwa-core/Cargo.toml +++ b/nokhwa-core/Cargo.toml @@ -40,7 +40,7 @@ version = "22" optional = true [dependencies.opencv] -version = "0.92" +version = "0.93" default-features = false optional = true @@ -57,8 +57,11 @@ version = "0.6" optional = true [dependencies.yuvutils-rs] -version = "0.3" +version = "0.4" optional = true +[dependencies.rgb] +version = "0.8" + [package.metadata.docs.rs] features = ["docs-features"] diff --git a/nokhwa-core/src/controls.rs b/nokhwa-core/src/controls.rs new file mode 100644 index 0000000..6c05b20 --- /dev/null +++ b/nokhwa-core/src/controls.rs @@ -0,0 +1,1238 @@ +use serde::{Deserialize, Serialize}; +use std::{ + fmt::{Display, Formatter}, + collections::{HashMap, HashSet} +}; +use std::cmp::Ordering; +use crate::ranges::{ArrayRange, Options, Range, Simple}; +use crate::utils::{FailedMathOp, FallibleDiv, FallibleSub}; + +#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)] +pub struct ControlValidationFailure; + +// TODO: Replace Controls API with Properties. (this one) +/// Properties of a Camera. +/// +/// If the property is not supported, it is `None`. +/// Custom or platform-specific properties go into `other` +pub struct CameraProperties { + brightness: Option, + contrast: Option, + hue: Option, + saturation: Option, + sharpness: Option, + gamma: Option, + white_balance: Option, + backlight_compensation: Option, + gain: Option, + pan: Option, + tilt: Option, + zoom: Option, + exposure: Option, + iris: Option, + focus: Option, + facing: Option, + other: HashMap, +} + +impl CameraProperties { + pub fn brightness(&self) -> Option<&CameraPropertyDescriptor> { + self.brightness.as_ref() + } + + pub fn contrast(&self) -> Option<&CameraPropertyDescriptor> { + self.contrast.as_ref() + } + + pub fn hue(&self) -> Option<&CameraPropertyDescriptor> { + self.hue.as_ref() + } + + pub fn saturation(&self) -> Option<&CameraPropertyDescriptor> { + self.saturation.as_ref() + } + + pub fn sharpness(&self) -> Option<&CameraPropertyDescriptor> { + self.sharpness.as_ref() + } + + pub fn gamma(&self) -> Option<&CameraPropertyDescriptor> { + self.gamma.as_ref() + } + + pub fn white_balance(&self) -> Option<&CameraPropertyDescriptor> { + self.white_balance.as_ref() + } + + pub fn backlight_compensation(&self) -> Option<&CameraPropertyDescriptor> { + self.backlight_compensation.as_ref() + } + + pub fn gain(&self) -> Option<&CameraPropertyDescriptor> { + self.gain.as_ref() + } + + pub fn pan(&self) -> Option<&CameraPropertyDescriptor> { + self.pan.as_ref() + } + + pub fn tilt(&self) -> Option<&CameraPropertyDescriptor> { + self.tilt.as_ref() + } + + pub fn zoom(&self) -> Option<&CameraPropertyDescriptor> { + self.zoom.as_ref() + } + + pub fn exposure(&self) -> Option<&CameraPropertyDescriptor> { + self.exposure.as_ref() + } + + pub fn iris(&self) -> Option<&CameraPropertyDescriptor> { + self.iris.as_ref() + } + + pub fn focus(&self) -> Option<&CameraPropertyDescriptor> { + self.focus.as_ref() + } + + pub fn facing(&self) -> Option<&CameraPropertyDescriptor> { + self.facing.as_ref() + } + + pub fn other(&self) -> &HashMap { + &self.other + } +} + +/// Describes an individual property. +pub struct CameraPropertyDescriptor { + flags: HashSet, + platform_specific_id: Option, + range: CameraPropertyRange, + value: CameraPropertyValue, +} + + + +/// Platform Specific Camera Property. This is not useful, unless you are manually dealing with +/// camera properties in `other`. +#[derive(Clone, Debug, Hash, PartialOrd, Eq, PartialEq)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub enum CameraCustomPropertyPlatformId { + String(String), + LongInteger(i128), +} + +/// The flags that a camera property may have. +#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub enum CameraPropertyFlag { + /// This is automatically set - you need not interfere + Automatic, + /// This is manually set - you need to interfere + Manual, + /// The value is set continuously by the driver. + Continuous, + /// The value may only be read from - any attempts to change the value will error. + ReadOnly, + /// The value can only be written to. + WriteOnly, + /// May just randomly poof out of existance. + // FIXME: where the fuck did i find this? replace above doc with actual info. + Volatile, + /// While the platform/driver supports this feature, + /// your camera does not. Setting will be ignored. + Disabled, +} + +impl Display for CameraPropertyFlag { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{self:?}") + } +} + +/// Ranges (Available Options of a Camera +#[non_exhaustive] +pub enum CameraPropertyRange { + Null, + Boolean(Simple), + Integer(Range), + LongInteger(Range), + Float(Range), + Double(Range), + String(Simple), + Array(ArrayRange>), + Enumeration(Options>), + Binary(Simple>), + Pair(), + Triple(rgb::RGB), + Quadruple(Box, Box), + KeyValuePair(Box, Box) +} + +/// A possible value of +/// +/// IMPORTANT: Make sure to call [`check_self()`] BEFORE any other operations! +#[derive(Clone, Debug)] +#[non_exhaustive] +pub enum CameraPropertyValue { + Null, + Boolean(bool), + Integer(i64), + LongInteger(i128), + Float(f32), + Double(f64), + String(String), + Array(Vec), + EnumValue(Box), + Binary(Vec), + Pair(Box, Box), + Triple(Box, Box, Box), + Quadruple(Box, Box, Box, Box), +} + +impl CameraPropertyValue { + pub fn check_self(&self) -> Result<(), ControlValidationFailure> { + if self.is_simple_type() { + return Ok(()); + } + + match self { + CameraPropertyValue::Array(v) => { + for value in v { + if !value.is_simple_type() { + return Err(ControlValidationFailure); + } + } + } + CameraPropertyValue::EnumValue(e) => { + if !e.is_simple_type() { + return Err(ControlValidationFailure); + } + } + CameraPropertyValue::Pair(k, v) => { + if !k.is_simple_type() || !v.is_simple_type() { + return Err(ControlValidationFailure); + } + } + CameraPropertyValue::Triple(x, y, z) => { + if !x.is_simple_type() || !y.is_simple_type() || !z.is_simple_type() { + return Err(ControlValidationFailure); + } + } + CameraPropertyValue::Quadruple(x, y, z, w) => { + if !x.is_simple_type() || !y.is_simple_type() || !z.is_simple_type() || !w.is_simple_type() { + return Err(ControlValidationFailure); + } + } + _ => return Err(ControlValidationFailure), + } + Ok(()) + } + + pub fn is_simple_type(&self) -> bool { + if let (CameraPropertyValue::Null | CameraPropertyValue::Boolean(_) | CameraPropertyValue::Integer(_) | CameraPropertyValue::LongInteger(_) | CameraPropertyValue::Float(_) | CameraPropertyValue::Double(_) | CameraPropertyValue::String(_) | CameraPropertyValue::Binary(_)) = self { + return true; + } + false + } +} + +impl PartialEq for CameraPropertyValue { + fn eq(&self, other: &Self) -> bool { + match &self { + CameraPropertyValue::Null => { + if let CameraPropertyValue::Null = other { + return true; + } + } + CameraPropertyValue::Boolean(b) => { + if let CameraPropertyValue::Boolean(ob) = other { + return b == ob; + } + } + CameraPropertyValue::Integer(i) => { + if let CameraPropertyValue::Integer(oi) = other { + return i == oi; + } + } + CameraPropertyValue::LongInteger(i) => { + if let CameraPropertyValue::LongInteger(oi) = other { + return i == oi; + } + } + CameraPropertyValue::Float(f) => { + if let CameraPropertyValue::Float(of) = other { + return f == of; + } + } + CameraPropertyValue::Double(d) => { + if let CameraPropertyValue::Double(od) = other { + return d == od; + } + } + CameraPropertyValue::String(s) => { + if let CameraPropertyValue::String(os) = other { + return s == os; + } + } + CameraPropertyValue::Array(a) => { + if let CameraPropertyValue::Array(oa) = other { + return a == oa; + } + } + CameraPropertyValue::EnumValue(ev) => { + if let CameraPropertyValue::EnumValue(oev) = other { + return ev == oev; + } + } + CameraPropertyValue::Binary(bin) => { + if let CameraPropertyValue::Binary(obin) = other { + return bin == obin; + } + } + CameraPropertyValue::Pair(a, b) => { + if let CameraPropertyValue::Pair(oa, ob) = other { + return (a == oa) && (b == ob) + } + } + CameraPropertyValue::Triple(x, y, z) => { + if let CameraPropertyValue::Triple(ox, oy, oz) = other { + return (x == ox) && (y == oy) && (z == oz) + } + } + CameraPropertyValue::Quadruple(x, y, z, w) => { + if let CameraPropertyValue::Quadruple(ox, oy, oz, ow) = other { + return (x == ox) && (y == oy) && (z == oz) && (w == ow) + } + } + } + false + } +} + +impl PartialOrd for CameraPropertyValue { + fn partial_cmp(&self, other: &Self) -> Option { + match self { + CameraPropertyValue::Null => { + match other { + CameraPropertyValue::Null => Some(Ordering::Greater), + _ => Some(Ordering::Less) + } + } + CameraPropertyValue::Boolean(b) => { + match other { + CameraPropertyValue::Null => Some(Ordering::Greater), + CameraPropertyValue::Boolean(o) => { + if o == b { + Some(Ordering::Equal) + } else if o { + Some(Ordering::Less) + } else { + Some(Ordering::Greater) + } + } + _ => Some(Ordering::Less) + } + } + CameraPropertyValue::Integer(int) => { + match other { + CameraPropertyValue::Null | CameraPropertyValue::Boolean(_) => Some(Ordering::Greater), + CameraPropertyValue::Integer(oth) => { + Some(int.cmp(oth)) + } + CameraPropertyValue::LongInteger(li) => { + let long = match i64::try_from(li) { + Ok(v) => v, + Err(_) => return None, + }; + Some(int.cmp(&long)) + } + _ => Some(Ordering::Less), + } + } + CameraPropertyValue::LongInteger(long) => { + match other { + CameraPropertyValue::Null | CameraPropertyValue::Boolean(_) => Some(Ordering::Greater), + CameraPropertyValue::Integer(oth) => { + Some(long.cmp(&(i128::from(oth)))) + } + CameraPropertyValue::LongInteger(o) => { + Some(long.cmp(o)) + } + _ => Some(Ordering::Less), + } + } + CameraPropertyValue::Float(fl) => { + match other { + CameraPropertyValue::Null | + CameraPropertyValue::Boolean(_) | + CameraPropertyValue::Integer(_) | + CameraPropertyValue::LongInteger(_) => Some(Ordering::Greater), + CameraPropertyValue::Float(f) => { + fl.partial_cmp(f) + } + CameraPropertyValue::Double(d) => { + f64::from(fl).partial_cmp(d) + } + _ => Some(Ordering::Less), + } + } + CameraPropertyValue::Double(d) => { + match other { + CameraPropertyValue::Null | + CameraPropertyValue::Boolean(_) | + CameraPropertyValue::Integer(_) | + CameraPropertyValue::LongInteger(_) => Some(Ordering::Greater), + CameraPropertyValue::Float(f) => { + d.partial_cmp(&(f64::from(f))) + } + CameraPropertyValue::Double(o) => { + d.partial_cmp(o) + } + _ => Some(Ordering::Less), + } + } + CameraPropertyValue::String(s) => { + match other { + CameraPropertyValue::Null | + CameraPropertyValue::Boolean(_) | + CameraPropertyValue::Integer(_) | + CameraPropertyValue::LongInteger(_) | + CameraPropertyValue::Float(_) | + CameraPropertyValue::Double(_) => Some(Ordering::Greater), + CameraPropertyValue::String(os) => { + s.partial_cmp(os) + } + _ => Some(Ordering::Less), + } + } + CameraPropertyValue::Array(a) => { + match other { + CameraPropertyValue::Null | + CameraPropertyValue::Boolean(_) | + CameraPropertyValue::Integer(_) | + CameraPropertyValue::LongInteger(_) | + CameraPropertyValue::Float(_) | + CameraPropertyValue::Double(_) | + CameraPropertyValue::String(_) => Some(Ordering::Greater), + CameraPropertyValue::Array(oa) => { + a.partial_cmp(oa) + } + _ => Some(Ordering::Less), + } + } + CameraPropertyValue::EnumValue(_) => { + match other { + CameraPropertyValue::Null | + CameraPropertyValue::Boolean(_) | + CameraPropertyValue::Integer(_) | + CameraPropertyValue::LongInteger(_) | + CameraPropertyValue::Float(_) | + CameraPropertyValue::Double(_) | + CameraPropertyValue::String(_) | + CameraPropertyValue::Array(_) => Some(Ordering::Greater), + CameraPropertyValue::EnumValue(_) => Some(Ordering::Equal), + _ => Some(Ordering::Less), + } + } + CameraPropertyValue::Binary(b) => { + match other { + CameraPropertyValue::Null| + CameraPropertyValue::Boolean(_)| + CameraPropertyValue::Integer(_)| + CameraPropertyValue::LongInteger(_)| + CameraPropertyValue::Float(_)| + CameraPropertyValue::Double(_)| + CameraPropertyValue::String(_)| + CameraPropertyValue::Array(_)| + CameraPropertyValue::EnumValue(_) => Some(Ordering::Greater), + CameraPropertyValue::Binary(ob) => { + b.partial_cmp(ob) + } + _ => Some(Ordering::Less), + } + } + // FIXME: implement this lole + CameraPropertyValue::Pair(_, _) => { + // match other { + // CameraPropertyValue::Null | + // CameraPropertyValue::Boolean(_) | + // CameraPropertyValue::Integer(_) | + // CameraPropertyValue::LongInteger(_) | + // CameraPropertyValue::Float(_) | + // CameraPropertyValue::Double(_) | + // CameraPropertyValue::String(_) | + // CameraPropertyValue::Array(_) | + // CameraPropertyValue::EnumValue(_) | + // CameraPropertyValue::Binary(_) => Some(Ordering::Greater), + // CameraPropertyValue::Pair(a, b) => { + // match a.partial_cmp(b) { + // Some(_) => {} + // None => {} + // } + // } + // _ => Some(Ordering::Less) + // } + Some(Ordering::Equal) + } + CameraPropertyValue::Triple(_, _, _) => Some(Ordering::Equal), + CameraPropertyValue::Quadruple(_, _, _, _) => Some(Ordering::Equal), + _ => None, + } + } +} + +impl FallibleDiv for CameraPropertyValue { + type Output = CameraPropertyValue; + type Error = FailedMathOp; + + fn fallible_div(&self, rhs: &Self) -> Result { + match self { + CameraPropertyValue::Integer(i) => { + if let CameraPropertyValue::Integer(rhs) = rhs { + return Ok(CameraPropertyValue::Integer(i / rhs)); + } + } + CameraPropertyValue::LongInteger(li) => { + if let CameraPropertyValue::LongInteger(rhs) = rhs { + return Ok(CameraPropertyValue::LongInteger(li / rhs)); + } + } + CameraPropertyValue::Float(f) => { + if let CameraPropertyValue::Float(rhs) = rhs { + return Ok(CameraPropertyValue::Float(f / rhs)); + } + } + CameraPropertyValue::Double(d) => { + if let CameraPropertyValue::Double(rhs) = rhs { + return Ok(CameraPropertyValue::Double(d / rhs)); + } + } + _ => return Err(Default::default()), + } + Err(Default::default()) + } +} + +impl FallibleSub for CameraPropertyValue { + type Output = CameraPropertyValue; + type Error = FailedMathOp; + + fn fallible_sub(&self, rhs: &Self) -> Result { + match self { + CameraPropertyValue::Integer(i) => { + if let CameraPropertyValue::Integer(rhs) = rhs { + return Ok(CameraPropertyValue::Integer(i - rhs)); + } + } + CameraPropertyValue::LongInteger(li) => { + if let CameraPropertyValue::LongInteger(rhs) = rhs { + return Ok(CameraPropertyValue::LongInteger(li - rhs)); + } + } + CameraPropertyValue::Float(f) => { + if let CameraPropertyValue::Float(rhs) = rhs { + return Ok(CameraPropertyValue::Float(f - rhs)); + } + } + CameraPropertyValue::Double(d) => { + if let CameraPropertyValue::Double(rhs) = rhs { + return Ok(CameraPropertyValue::Double(d - rhs)); + } + } + _ => return Err(Self::Error::default()), + } + Err(Self::Error::default()) + } +} + +// /// All camera controls in an array. +// #[must_use] +// pub const fn all_known_camera_controls() -> &'static [KnownCameraControl] { +// &[ +// KnownCameraControl::Brightness, +// KnownCameraControl::Contrast, +// KnownCameraControl::Hue, +// KnownCameraControl::Saturation, +// KnownCameraControl::Sharpness, +// KnownCameraControl::Gamma, +// KnownCameraControl::WhiteBalance, +// KnownCameraControl::BacklightComp, +// KnownCameraControl::Gain, +// KnownCameraControl::Pan, +// KnownCameraControl::Tilt, +// KnownCameraControl::Zoom, +// KnownCameraControl::Exposure, +// KnownCameraControl::Iris, +// KnownCameraControl::Focus, +// KnownCameraControl::Facing, +// ] +// } + +// /// The list of known camera controls to the library.
+// /// These can control the picture brightness, etc.
+// /// Note that not all backends/devices support all these. Run [`supported_camera_controls()`](crate::traits::CaptureTrait::camera_controls) to see which ones can be set. +// #[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)] +// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +// pub enum KnownCameraControl { +// Brightness, +// Contrast, +// Hue, +// Saturation, +// Sharpness, +// Gamma, +// WhiteBalance, +// BacklightComp, +// Gain, +// Pan, +// Tilt, +// Zoom, +// Exposure, +// Iris, +// Focus, +// Facing, +// /// Other camera control. Listed is the ID. +// /// Wasteful, however is needed for a unified API across Windows, Linux, and MacOSX due to Microsoft's usage of GUIDs. +// /// +// /// THIS SHOULD ONLY BE USED WHEN YOU KNOW THE PLATFORM THAT YOU ARE RUNNING ON. +// Other(u128), +// } +// +// impl Display for KnownCameraControl { +// fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { +// write!(f, "{:?}", &self) +// } +// } +// +// /// This tells you weather a [`KnownCameraControl`] is automatically managed by the OS/Driver +// /// or manually managed by you, the programmer. +// #[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)] +// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +// pub enum CameraPropertyFlag { +// Automatic, +// Manual, +// Continuous, +// ReadOnly, +// WriteOnly, +// Volatile, +// Disabled, +// } +// +// impl Display for CameraPropertyFlag { +// fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { +// write!(f, "{self:?}") +// } +// } +// +// impl ControlValueDescription { +// /// Get the value of this [`ControlValueDescription`] +// #[must_use] +// pub fn value(&self) -> ControlValueSetter { +// match self { +// ControlValueDescription::None => ControlValueSetter::None, +// ControlValueDescription::Integer { value, .. } +// | ControlValueDescription::IntegerRange { value, .. } => { +// ControlValueSetter::Integer(*value) +// } +// ControlValueDescription::Float { value, .. } +// | ControlValueDescription::FloatRange { value, .. } => { +// ControlValueSetter::Float(*value) +// } +// ControlValueDescription::Boolean { value, .. } => ControlValueSetter::Boolean(*value), +// ControlValueDescription::String { value, .. } => { +// ControlValueSetter::String(value.clone()) +// } +// ControlValueDescription::Bytes { value, .. } => { +// ControlValueSetter::Bytes(value.clone()) +// } +// ControlValueDescription::KeyValuePair { key, value, .. } => { +// ControlValueSetter::KeyValue(*key, *value) +// } +// ControlValueDescription::Point { value, .. } => { +// ControlValueSetter::Point(value.0, value.1) +// } +// ControlValueDescription::Enum { value, .. } => ControlValueSetter::EnumValue(*value), +// ControlValueDescription::RGB { value, .. } => { +// ControlValueSetter::RGB(value.0, value.1, value.2) +// } +// ControlValueDescription::StringList { value, .. } => { +// ControlValueSetter::StringList(value.clone()) +// } +// } +// } +// +// /// Verifies if the [setter](ControlValueSetter) is valid for the provided [`ControlValueDescription`]. +// /// - `true` => Is valid. +// /// - `false` => Is not valid. +// /// +// /// If the step is 0, it will automatically return `true`. +// #[must_use] +// pub fn verify_setter(&self, setter: &ControlValueSetter) -> bool { +// match self { +// ControlValueDescription::None => setter.as_none().is_some(), +// ControlValueDescription::Integer { +// value, +// default, +// step, +// } => { +// if *step == 0 { +// return true; +// } +// match setter.as_integer() { +// Some(i) => (i + default) % step == 0 || (i + value) % step == 0, +// None => false, +// } +// } +// ControlValueDescription::IntegerRange { +// min, +// max, +// value, +// step, +// default, +// } => { +// if *step == 0 { +// return true; +// } +// match setter.as_integer() { +// Some(i) => { +// ((i + default) % step == 0 || (i + value) % step == 0) +// && i >= min +// && i <= max +// } +// None => false, +// } +// } +// ControlValueDescription::Float { +// value, +// default, +// step, +// } => { +// if step.abs() == 0_f64 { +// return true; +// } +// match setter.as_float() { +// Some(f) => (f - default).abs() % step == 0_f64 || (f - value) % step == 0_f64, +// None => false, +// } +// } +// ControlValueDescription::FloatRange { +// min, +// max, +// value, +// step, +// default, +// } => { +// if step.abs() == 0_f64 { +// return true; +// } +// +// match setter.as_float() { +// Some(f) => { +// ((f - default).abs() % step == 0_f64 || (f - value) % step == 0_f64) +// && f >= min +// && f <= max +// } +// None => false, +// } +// } +// ControlValueDescription::Boolean { .. } => setter.as_boolean().is_some(), +// ControlValueDescription::String { .. } => setter.as_str().is_some(), +// ControlValueDescription::Bytes { .. } => setter.as_bytes().is_some(), +// ControlValueDescription::KeyValuePair { .. } => setter.as_key_value().is_some(), +// ControlValueDescription::Point { .. } => match setter.as_point() { +// Some(pt) => { +// !pt.0.is_nan() && !pt.1.is_nan() && pt.0.is_finite() && pt.1.is_finite() +// } +// None => false, +// }, +// ControlValueDescription::Enum { possible, .. } => match setter.as_enum() { +// Some(e) => possible.contains(e), +// None => false, +// }, +// ControlValueDescription::RGB { max, .. } => match setter.as_rgb() { +// Some(v) => *v.0 >= max.0 && *v.1 >= max.1 && *v.2 >= max.2, +// None => false, +// }, +// ControlValueDescription::StringList { availible, .. } => { +// availible.contains(&(setter.as_str().unwrap_or("").to_string())) // what the fuck?? +// } +// } +// +// // match setter { +// // ControlValueSetter::None => { +// // matches!(self, ControlValueDescription::None) +// // } +// // ControlValueSetter::Integer(i) => match self { +// // ControlValueDescription::Integer { +// // value, +// // default, +// // step, +// // } => (i - default).abs() % step == 0 || (i - value) % step == 0, +// // ControlValueDescription::IntegerRange { +// // min, +// // max, +// // value, +// // step, +// // default, +// // } => { +// // if value > max || value < min { +// // return false; +// // } +// // +// // (i - default) % step == 0 || (i - value) % step == 0 +// // } +// // _ => false, +// // }, +// // ControlValueSetter::Float(f) => match self { +// // ControlValueDescription::Float { +// // value, +// // default, +// // step, +// // } => (f - default).abs() % step == 0_f64 || (f - value) % step == 0_f64, +// // ControlValueDescription::FloatRange { +// // min, +// // max, +// // value, +// // step, +// // default, +// // } => { +// // if value > max || value < min { +// // return false; +// // } +// // +// // (f - default) % step == 0_f64 || (f - value) % step == 0_f64 +// // } +// // _ => false, +// // }, +// // ControlValueSetter::Boolean(b) => { +// // +// // } +// // ControlValueSetter::String(_) => { +// // matches!(self, ControlValueDescription::String { .. }) +// // } +// // ControlValueSetter::Bytes(_) => { +// // matches!(self, ControlValueDescription::Bytes { .. }) +// // } +// // ControlValueSetter::KeyValue(_, _) => { +// // matches!(self, ControlValueDescription::KeyValuePair { .. }) +// // } +// // ControlValueSetter::Point(_, _) => { +// // matches!(self, ControlValueDescription::Point { .. }) +// // } +// // ControlValueSetter::EnumValue(_) => { +// // matches!(self, ControlValueDescription::Enum { .. }) +// // } +// // ControlValueSetter::RGB(_, _, _) => { +// // matches!(self, ControlValueDescription::RGB { .. }) +// // } +// // } +// } +// } +// +// /// This struct tells you everything about a particular [`KnownCameraControl`]. +// /// +// /// However, you should never need to instantiate this struct, since its usually generated for you by `nokhwa`. +// /// The only time you should be modifying this struct is when you need to set a value and pass it back to the camera. +// /// NOTE: Assume the values for `min` and `max` as **non-inclusive**!. +// /// E.g. if the [`CameraControl`] says `min` is 100, the minimum is actually 101. +// #[derive(Clone, Debug, PartialOrd, PartialEq)] +// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +// pub struct CameraControl { +// control: KnownCameraControl, +// name: String, +// description: ControlValueDescription, +// flag: Vec, +// active: bool, +// } +// +// impl CameraControl { +// /// Creates a new [`CameraControl`] +// #[must_use] +// pub fn new( +// control: KnownCameraControl, +// name: String, +// description: ControlValueDescription, +// flag: Vec, +// active: bool, +// ) -> Self { +// CameraControl { +// control, +// name, +// description, +// flag, +// active, +// } +// } +// +// /// Gets the name of this [`CameraControl`] +// #[must_use] +// pub fn name(&self) -> &str { +// &self.name +// } +// +// /// Gets the [`ControlValueDescription`] of this [`CameraControl`] +// #[must_use] +// pub fn description(&self) -> &ControlValueDescription { +// &self.description +// } +// +// /// Gets the [`ControlValueSetter`] of the [`ControlValueDescription`] of this [`CameraControl`] +// #[must_use] +// pub fn value(&self) -> ControlValueSetter { +// self.description.value() +// } +// +// /// Gets the [`KnownCameraControl`] of this [`CameraControl`] +// #[must_use] +// pub fn control(&self) -> KnownCameraControl { +// self.control +// } +// +// /// Gets the [`KnownCameraControlFlag`] of this [`CameraControl`], +// /// telling you weather this control is automatically set or manually set. +// #[must_use] +// pub fn flag(&self) -> &[KnownCameraControlFlag] { +// &self.flag +// } +// +// /// Gets `active` of this [`CameraControl`], +// /// telling you weather this control is currently active(in-use). +// #[must_use] +// pub fn active(&self) -> bool { +// self.active +// } +// +// /// Gets `active` of this [`CameraControl`], +// /// telling you weather this control is currently active(in-use). +// pub fn set_active(&mut self, active: bool) { +// self.active = active; +// } +// } +// +// impl Display for CameraControl { +// fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { +// write!( +// f, +// "Control: {}, Name: {}, Value: {}, Flag: {:?}, Active: {}", +// self.control, self.name, self.description, self.flag, self.active +// ) +// } +// } +// +// /// The setter for a control value +// #[derive(Clone, Debug, PartialEq, PartialOrd)] +// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +// pub enum ControlValueSetter { +// None, +// Integer(i64), +// Float(f64), +// Boolean(bool), +// String(String), +// Bytes(Vec), +// KeyValue(i128, i128), +// Point(f64, f64), +// EnumValue(i64), +// RGB(f64, f64, f64), +// StringList(String), +// } +// +// impl ControlValueSetter { +// #[must_use] +// pub fn as_none(&self) -> Option<()> { +// if let ControlValueSetter::None = self { +// Some(()) +// } else { +// None +// } +// } +// #[must_use] +// +// pub fn as_integer(&self) -> Option<&i64> { +// if let ControlValueSetter::Integer(i) = self { +// Some(i) +// } else { +// None +// } +// } +// #[must_use] +// +// pub fn as_float(&self) -> Option<&f64> { +// if let ControlValueSetter::Float(f) = self { +// Some(f) +// } else { +// None +// } +// } +// #[must_use] +// +// pub fn as_boolean(&self) -> Option<&bool> { +// if let ControlValueSetter::Boolean(f) = self { +// Some(f) +// } else { +// None +// } +// } +// #[must_use] +// +// pub fn as_str(&self) -> Option<&str> { +// if let ControlValueSetter::String(s) = self { +// Some(s) +// } else { +// None +// } +// } +// #[must_use] +// +// pub fn as_bytes(&self) -> Option<&[u8]> { +// if let ControlValueSetter::Bytes(b) = self { +// Some(b) +// } else { +// None +// } +// } +// #[must_use] +// +// pub fn as_key_value(&self) -> Option<(&i128, &i128)> { +// if let ControlValueSetter::KeyValue(k, v) = self { +// Some((k, v)) +// } else { +// None +// } +// } +// #[must_use] +// +// pub fn as_point(&self) -> Option<(&f64, &f64)> { +// if let ControlValueSetter::Point(x, y) = self { +// Some((x, y)) +// } else { +// None +// } +// } +// #[must_use] +// +// pub fn as_enum(&self) -> Option<&i64> { +// if let ControlValueSetter::EnumValue(e) = self { +// Some(e) +// } else { +// None +// } +// } +// #[must_use] +// +// pub fn as_rgb(&self) -> Option<(&f64, &f64, &f64)> { +// if let ControlValueSetter::RGB(r, g, b) = self { +// Some((r, g, b)) +// } else { +// None +// } +// } +// } +// +// impl Display for ControlValueSetter { +// fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { +// match self { +// ControlValueSetter::None => { +// write!(f, "Value: None") +// } +// ControlValueSetter::Integer(i) => { +// write!(f, "IntegerValue: {i}") +// } +// ControlValueSetter::Float(d) => { +// write!(f, "FloatValue: {d}") +// } +// ControlValueSetter::Boolean(b) => { +// write!(f, "BoolValue: {b}") +// } +// ControlValueSetter::String(s) => { +// write!(f, "StrValue: {s}") +// } +// ControlValueSetter::Bytes(b) => { +// write!(f, "BytesValue: {b:x?}") +// } +// ControlValueSetter::KeyValue(k, v) => { +// write!(f, "KVValue: ({k}, {v})") +// } +// ControlValueSetter::Point(x, y) => { +// write!(f, "PointValue: ({x}, {y})") +// } +// ControlValueSetter::EnumValue(v) => { +// write!(f, "EnumValue: {v}") +// } +// ControlValueSetter::RGB(r, g, b) => { +// write!(f, "RGBValue: ({r}, {g}, {b})") +// } +// ControlValueSetter::StringList(s) => { +// write!(f, "StringListValue: {s}") +// } +// } +// } +// } +// +// /// The values for a [`CameraControl`]. +// /// +// /// This provides a wide range of values that can be used to control a camera. +// #[derive(Clone, Debug, PartialEq, PartialOrd)] +// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +// pub enum ControlValueDescription { +// None, +// Integer { +// value: i64, +// default: i64, +// step: i64, +// }, +// IntegerRange { +// min: i64, +// max: i64, +// value: i64, +// step: i64, +// default: i64, +// }, +// Float { +// value: f64, +// default: f64, +// step: f64, +// }, +// FloatRange { +// min: f64, +// max: f64, +// value: f64, +// step: f64, +// default: f64, +// }, +// Boolean { +// value: bool, +// default: bool, +// }, +// String { +// value: String, +// default: Option, +// }, +// Bytes { +// value: Vec, +// default: Vec, +// }, +// KeyValuePair { +// key: i128, +// value: i128, +// default: (i128, i128), +// }, +// Point { +// value: (f64, f64), +// default: (f64, f64), +// }, +// Enum { +// value: i64, +// possible: Vec, +// default: i64, +// }, +// RGB { +// value: (f64, f64, f64), +// max: (f64, f64, f64), +// default: (f64, f64, f64), +// }, +// StringList { +// value: String, +// availible: Vec, +// }, +// } +// +// impl Display for ControlValueDescription { +// fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { +// match self { +// ControlValueDescription::None => { +// write!(f, "(None)") +// } +// ControlValueDescription::Integer { +// value, +// default, +// step, +// } => { +// write!(f, "(Current: {value}, Default: {default}, Step: {step})",) +// } +// ControlValueDescription::IntegerRange { +// min, +// max, +// value, +// step, +// default, +// } => { +// write!( +// f, +// "(Current: {value}, Default: {default}, Step: {step}, Range: ({min}, {max}))", +// ) +// } +// ControlValueDescription::Float { +// value, +// default, +// step, +// } => { +// write!(f, "(Current: {value}, Default: {default}, Step: {step})",) +// } +// ControlValueDescription::FloatRange { +// min, +// max, +// value, +// step, +// default, +// } => { +// write!( +// f, +// "(Current: {value}, Default: {default}, Step: {step}, Range: ({min}, {max}))", +// ) +// } +// ControlValueDescription::Boolean { value, default } => { +// write!(f, "(Current: {value}, Default: {default})") +// } +// ControlValueDescription::String { value, default } => { +// write!(f, "(Current: {value}, Default: {default:?})") +// } +// ControlValueDescription::Bytes { value, default } => { +// write!(f, "(Current: {value:x?}, Default: {default:x?})") +// } +// ControlValueDescription::KeyValuePair { +// key, +// value, +// default, +// } => { +// write!( +// f, +// "Current: ({key}, {value}), Default: ({}, {})", +// default.0, default.1 +// ) +// } +// ControlValueDescription::Point { value, default } => { +// write!( +// f, +// "Current: ({}, {}), Default: ({}, {})", +// value.0, value.1, default.0, default.1 +// ) +// } +// ControlValueDescription::Enum { +// value, +// possible, +// default, +// } => { +// write!( +// f, +// "Current: {value}, Possible Values: {possible:?}, Default: {default}", +// ) +// } +// ControlValueDescription::RGB { +// value, +// max, +// default, +// } => { +// write!( +// f, +// "Current: ({}, {}, {}), Max: ({}, {}, {}), Default: ({}, {}, {})", +// 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:?}") +// } +// } +// } +// } diff --git a/nokhwa-core/src/decoders/general.rs b/nokhwa-core/src/decoders/general.rs index 8696526..d51bc52 100644 --- a/nokhwa-core/src/decoders/general.rs +++ b/nokhwa-core/src/decoders/general.rs @@ -49,10 +49,12 @@ impl Decoder for GeneralPurposeDecoder where D: PixelWithColorType { // already decoded FrameFormat::Rgb8 => PixelFormat::Rgb, FrameFormat::RgbA8 => { - PixelFormat::Rgba + PixelFormat::Rgb } _ => return Err(()), }; + dcv_color_primitives::convert_image(buffer.resolution().width(), buffer.resolution().height(), ) + } } diff --git a/nokhwa-core/src/error.rs b/nokhwa-core/src/error.rs index aacd93c..d7a9622 100644 --- a/nokhwa-core/src/error.rs +++ b/nokhwa-core/src/error.rs @@ -16,6 +16,7 @@ use crate::{frame_format::FrameFormat, types::ApiBackend}; use thiserror::Error; +use crate::ranges::RangeValidationResult; /// All errors in `nokhwa`. #[allow(clippy::module_name_repetitions)] diff --git a/nokhwa-core/src/format_request.rs b/nokhwa-core/src/format_request.rs index 879af66..8379980 100644 --- a/nokhwa-core/src/format_request.rs +++ b/nokhwa-core/src/format_request.rs @@ -4,9 +4,10 @@ use std::{ }; use crate::{ frame_format::FrameFormat, - types::{CameraFormat, Resolution, FrameRate, Range}, - traits::Distance + traits::Distance, + types::{CameraFormat, FrameRate, Resolution} }; +use crate::ranges::Range; #[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] enum ClosestType { diff --git a/nokhwa-core/src/lib.rs b/nokhwa-core/src/lib.rs index fcb459a..a2951e6 100644 --- a/nokhwa-core/src/lib.rs +++ b/nokhwa-core/src/lib.rs @@ -30,3 +30,5 @@ pub mod traits; pub mod types; pub mod decoders; pub mod utils; +pub mod ranges; +pub mod controls; diff --git a/nokhwa-core/src/ranges.rs b/nokhwa-core/src/ranges.rs new file mode 100644 index 0000000..ee8a742 --- /dev/null +++ b/nokhwa-core/src/ranges.rs @@ -0,0 +1,516 @@ +use std::collections::HashMap; +use core::fmt::{ Debug, Display, Formatter}; +use std::collections::hash_map::Keys; +use std::hash::Hash; +use std::ops::{Div, Sub}; +use crate::error::NokhwaError; + +/// Failed to validate. +#[derive(Copy, Clone, Debug, Default, Hash, Ord, PartialOrd, Eq, PartialEq)] +pub struct RangeValidationFailure; + +/// A range type that can be validated. +pub trait ValidatableRange { + /// Input type to validate. + type Validation; + + /// Validates the value. + fn validate(&self, value: Self::Validation) -> Result<(), RangeValidationFailure>; +} + +/// Creates a range of values. +/// +/// Inclusive by default. +#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] +pub struct Range +{ + minimum: Option, + lower_inclusive: bool, + maximum: Option, + upper_inclusive: bool, + preferred: T, +} + +impl Range +where + T: Copy + Clone + Debug + PartialOrd + PartialEq, +{ + /// Create an upper and lower inclusive [`Range`] + pub fn new(preferred: T, min: Option, max: Option) -> Self { + Self { + minimum: min, + lower_inclusive: true, + maximum: max, + upper_inclusive: true, + 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 exact(preferred: T) -> Self { + Self { + minimum: None, + lower_inclusive: true, + maximum: None, + upper_inclusive: true, + preferred, + } + } + + pub fn set_minimum(&mut self, minimum: Option) { + self.minimum = minimum; + } + pub fn set_lower_inclusive(&mut self, lower_inclusive: bool) { + self.lower_inclusive = lower_inclusive; + } + pub fn set_maximum(&mut self, maximum: Option) { + self.maximum = maximum; + } + pub fn set_upper_inclusive(&mut self, upper_inclusive: bool) { + self.upper_inclusive = upper_inclusive; + } + pub fn set_preferred(&mut self, preferred: T) { + self.preferred = preferred; + } + pub fn minimum(&self) -> Option { + self.minimum + } + pub fn lower_inclusive(&self) -> bool { + self.lower_inclusive + } + pub fn maximum(&self) -> Option { + self.maximum + } + pub fn upper_inclusive(&self) -> bool { + self.upper_inclusive + } + pub fn preferred(&self) -> T { + self.preferred + } +} + +impl ValidatableRange for Range where T: PartialEq + PartialOrd { + type Validation = T; + + fn validate(&self, value: Self::Validation) -> Result<(), RangeValidationFailure> { + num_range_validate(self.minimum.as_ref(), self.maximum.as_ref(), &self.preferred, self.lower_inclusive, self.upper_inclusive, &value) + } +} + +impl Default for Range +where + T: Default, +{ + fn default() -> Self { + Range { + minimum: None, + lower_inclusive: true, + maximum: None, + upper_inclusive: true, + preferred: T::default(), + } + } +} + +impl Display for Range where T: Debug { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let lower_inclusive_char = bool_to_inclusive_char(self.lower_inclusive, false); + let upper_inclusive_char = bool_to_inclusive_char(self.upper_inclusive, true); + let default = default_to_string(&self.preferred); + + write!(f, "Range: {lower_inclusive_char}{}, {}{upper_inclusive_char}, Preferred: {default}", self.minimum, self.maximum) + } +} + + +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +pub struct IndicatedRange where T: Copy + Clone + Debug + PartialOrd + PartialEq { + minimum: T, + lower_inclusive: bool, + maximum: T, + upper_inclusive: bool, + step: Option, + default: Option, +} + +impl IndicatedRange +where + T: Copy + Clone + Debug + PartialOrd + PartialEq +{ + pub fn new(minimum: T, lower_inclusive: bool, maximum: T, upper_inclusive: bool, step: Option, default: Option) -> Self { + Self { minimum, lower_inclusive, maximum, upper_inclusive, step, default } + } + + pub fn minimum(&self) -> T { + self.minimum + } + + pub fn lower_inclusive(&self) -> bool { + self.lower_inclusive + } + + pub fn maximum(&self) -> T { + self.maximum + } + + pub fn upper_inclusive(&self) -> bool { + self.upper_inclusive + } + + pub fn step(&self) -> Option { + self.step + } + + pub fn default_value(&self) -> Option { + self.default + } +} + +impl ValidatableRange for IndicatedRange where T: Copy + PartialEq + PartialOrd + Div + Sub + Number { + type Validation = T; + + fn validate(&self, value: Self::Validation) -> Result<(), RangeValidationFailure> { + if let Some(step) = &self.step { + let prepared_value = value - &self.minimum; + // We can check the step if we subtract the value from the minimum value + // then see if the remainder of prepared value and step is zero. + // e.g. 4, 12, value is 7, step is 3 + // 7 - 4 = 3 + // 3 % 3 = 0 Valid! + if prepared_value % step != 0 { + return Err(RangeValidationFailure::default()) + } + } + + num_range_validate(self.minimum.as_ref(), self.maximum.as_ref(), &self.default, self.lower_inclusive, self.upper_inclusive, &value) + } +} + +impl Display for IndicatedRange where T: Debug { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let lower_inclusive_char = bool_to_inclusive_char(self.lower_inclusive, false); + let upper_inclusive_char = bool_to_inclusive_char(self.upper_inclusive, true); + let default = default_to_string(&self.default); + let step = default_to_string(&self.step); + + // Ex) IndicatedRange: (5, 19], Step: 3, Default: 8 + write!(f, "IndicatedRange: {lower_inclusive_char}{}, {}{upper_inclusive_char}, Step: {step}, Default: {default}", self.minimum, self.maximum) + } +} + +#[derive(Clone, Debug, PartialOrd, PartialEq)] +pub struct NonCopyRange where T: Clone + Debug + PartialOrd + PartialEq { + minimum: T, + lower_inclusive: bool, + maximum: T, + upper_inclusive: bool, + step: Option, + default: Option, +} + +impl NonCopyRange +where + T: Clone + Debug + PartialOrd + PartialEq +{ + pub fn new(minimum: T, lower_inclusive: bool, maximum: T, upper_inclusive: bool, step: Option, default: Option) -> Self { + Self { minimum, lower_inclusive, maximum, upper_inclusive, step, default } + } + + pub fn minimum(&self) -> &T { + &self.minimum + } + + pub fn lower_inclusive(&self) -> bool { + self.lower_inclusive + } + + pub fn maximum(&self) -> &T { + &self.maximum + } + + pub fn upper_inclusive(&self) -> bool { + self.upper_inclusive + } + + pub fn step(&self) -> Option<&T> { + self.step.as_ref() + } + + pub fn default_value(&self) -> Option<&T> { + self.default.as_ref() + } +} + +impl ValidatableRange for NonCopyRange where T: Clone + PartialEq + PartialOrd + Div + Sub { + type Validation = T; + + fn validate(&self, value: Self::Validation) -> Result<(), RangeValidationFailure> { + if let Some(step) = &self.step { + let prepared_value = value.clone() - &self.minimum; + // We can check the step if we subtract the value from the minimum value + // then see if the remainder of prepared value and step is zero. + // e.g. 4, 12, value is 7, step is 3 + // 7 - 4 = 3 + // 3 % 3 = 0 Valid! + if prepared_value % step != 0 { + return Err(RangeValidationFailure::default()) + } + } + + num_range_validate(self.minimum.as_ref(), self.maximum.as_ref(), &self.default, self.lower_inclusive, self.upper_inclusive, &value) + } +} + +impl Display for IndicatedRange where T: Debug { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let lower_inclusive_char = bool_to_inclusive_char(self.lower_inclusive, false); + let upper_inclusive_char = bool_to_inclusive_char(self.upper_inclusive, true); + let default = default_to_string(&self.default); + let step = default_to_string(&self.step); + + // Ex) IndicatedRange: (5, 19], Step: 3, Default: 8 + write!(f, "IndicatedRange: {lower_inclusive_char}{}, {}{upper_inclusive_char}, Step: {step}, Default: {default}", self.minimum, self.maximum) + } +} + +#[derive(Clone, Debug)] +pub struct Options where T: Clone + Debug { + default: Option, + available: Vec, +} + +impl Options +where + T: Clone + Debug + PartialEq +{ + pub fn new(values: Vec, default_value: T) -> Self { + Self { + default: default_value, + available: values, + } + } + + pub fn default_value(&self) -> Option<&T> { + self.default.as_ref() + } + + pub fn available(&self) -> &[T] { + &self.available + } +} + +impl ValidatableRange for Options where T: PartialEq { + type Validation = T; + + fn validate(&self, value: Self::Validation) -> Result<(), RangeValidationFailure> { + if self.available.contains(value) { + return Ok(()); + } + Err(RangeValidationFailure::default()) + } +} + +impl Display for Options where T: Debug { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let default = default_to_string(&self.default); + + write!(f, "Options: Available {:?}, Default: {default}", self.available) + } +} + +#[derive(Clone, Debug)] +pub struct KeyValue where K: Clone + Debug + Hash + Eq, V: Clone + Debug { + defaults: HashMap, +} + +impl KeyValue +where + K: Clone + Debug + Hash + Eq, + V: Clone + Debug +{ + pub fn new(default: HashMap) -> Self { + Self { + defaults: default, + } + } + + pub fn available_keys(&self) -> &Keys<'_, K, V> { + &self.defaults.keys() + } + + pub fn by_key(&self, key: &K) -> Option<&V> { + self.defaults.get(key) + } +} + +impl ValidatableRange for KeyValue where T: Eq + Hash { + type Validation = T; + + fn validate(&self, value: Self::Validation) -> Result<(), RangeValidationFailure> { + if self.defaults.contains_key(&value) { + return Ok(()) + } + Err(RangeValidationFailure::default()) + } +} + +impl Display for KeyValue where K: Debug, V: Debug { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + // TODO: pretty print? + write!(f, "Key Value Pairs: {:?}", self.defaults) + } +} + +#[derive(Clone, Debug)] +pub struct ArrayRange where T: Clone + Debug { + appendable_options: Vec, + default_options: Vec, +} + +impl ArrayRange where T: Clone + Debug + PartialEq { + pub fn new(appendable: Vec, default: Vec) -> Result { + for option in &default { + if !appendable.contains(option) { + return Err(NokhwaError::StructureError { structure: "ArrayRange".to_string(), error: "Attempted to add an undependable option to default option - ILLEGAL! - If you got this while using a driver, this is a bug! Please report to https://github.com/l1npengtul/nokhwa/issues!".to_string() }) + } + } + + Ok(Self { + appendable_options: appendable, + default_options: default, + }) + } + + pub fn appendable_options(&self) -> &[T] { + &self.appendable_options + } + + pub fn default_options(&self) -> &[T] { + &self.default_options + } +} + +impl ValidatableRange for ArrayRange where T: PartialEq { + type Validation = T; + + fn validate(&self, value: Self::Validation) -> Result<(), RangeValidationFailure> { + if self.appendable_options.contains(value) { + return Ok(()); + } + Err(RangeValidationFailure::default()) + } +} + +impl Display for ArrayRange where T: Debug { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "ArrayRange: Available Options: {:?}, Default: {:?}", self.appendable_options, self.default_options) + } +} + +#[derive(Clone, Debug)] +pub struct Simple where T: Clone + Debug { + default: Option +} + +impl Simple where T: Clone + Debug { + pub fn new(default: Option) -> Self { + Self { + default, + } + } + + pub fn default_value(&self) -> Option<&T> { + self.default.as_ref() + } +} + +impl ValidatableRange for Simple { + type Validation = T; + + fn validate(&self, _: Self::Validation) -> Result<(), RangeValidationFailure> { + Ok(()) + } +} + +impl Display for Simple where T: Debug { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let default = default_to_string(&self.default); + write!(f, "Simple (Any Value): Default Value: {default}") + } +} + +fn bool_to_inclusive_char(inclusive: bool, upper: bool) -> char { + match inclusive { + true => if upper { ']' } else { '[' }, + false => if upper { ')' } else { '(' }, + } +} + +fn default_to_string(default: &Option) -> String where T: Debug { + match default { + Some(v) => { + format!("{v:?}") + } + None => String::from("None"), + } +} + + +fn num_range_validate(minimum: Option<&T>, maximum: Option<&T>, default: &T, lower_inclusive: bool, upper_inclusive: bool, value: &T) -> Result<(), RangeValidationFailure> where T: PartialEq + PartialOrd { + if value == default { + return Ok(()) + } + + if let Some(min) = minimum { + let test = if lower_inclusive { + min <= value + } else { + min < value + }; + if test { + return Err(RangeValidationFailure::default()); + } + } + + if let Some(max) = maximum { + let test = if upper_inclusive { + max >= value + } else { + max > value + }; + if test { + return Err(RangeValidationFailure::default()); + } + } + + Ok(()) +} + +trait Number {} + +macro_rules! impl_num { + ( $($n:ty, )* ) => { + { + $( + impl Number for $n {} + )* + } + }; +} + +impl_num!( i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, f32, f64, ); diff --git a/nokhwa-core/src/traits.rs b/nokhwa-core/src/traits.rs index 75072e8..3ddb370 100644 --- a/nokhwa-core/src/traits.rs +++ b/nokhwa-core/src/traits.rs @@ -16,10 +16,11 @@ use crate::{ buffer::Buffer, error::NokhwaError, format_request::FormatRequest, types::{ - ApiBackend, CameraControl, CameraFormat, CameraIndex, CameraInfo, ControlValueSetter, KnownCameraControl, Resolution + ApiBackend, CameraFormat, CameraIndex, CameraInfo, Resolution } }; use std::{borrow::Cow, collections::HashMap}; +use crate::controls::{CameraControl, ControlValueSetter, KnownCameraControl}; use crate::frame_format::FrameFormat; use crate::types::FrameRate; diff --git a/nokhwa-core/src/types.rs b/nokhwa-core/src/types.rs index a01170a..6b80886 100644 --- a/nokhwa-core/src/types.rs +++ b/nokhwa-core/src/types.rs @@ -5,147 +5,17 @@ use crate::{ #[cfg(feature = "serialize")] use serde::{Deserialize, Serialize}; use std::{ - borrow::Borrow, cmp::Ordering, fmt::{ + borrow::Borrow, cmp::Ordering, collections::HashSet, fmt::{ Debug, Display, Formatter }, hash::{Hash, Hasher}, ops::{Add, Deref, DerefMut, Sub} }; +use std::collections::HashMap; +use crate::controls::{CameraControl, CameraPropertyFlag, KnownCameraControl}; +use crate::ranges::Range; use crate::traits::Distance; -/// Creates a range of values. -/// -/// Inclusive by default. -#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] -pub struct Range -{ - minimum: Option, - lower_inclusive: bool, - maximum: Option, - upper_inclusive: bool, - preferred: T, -} - -impl Range -where - T: Copy + Clone + Debug + PartialOrd + PartialEq, -{ - /// Create an upper and lower inclusive [`Range`] - pub fn new(preferred: T, min: Option, max: Option) -> Self { - Self { - minimum: min, - lower_inclusive: true, - maximum: max, - upper_inclusive: true, - 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 exact(preferred: T) -> Self { - Self { - minimum: None, - lower_inclusive: true, - maximum: None, - upper_inclusive: true, - preferred, - } - } - - pub fn in_range(&self, item: T) -> bool { - if item == self.preferred { - return 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 - } - - - pub fn set_minimum(&mut self, minimum: Option) { - self.minimum = minimum; - } - pub fn set_lower_inclusive(&mut self, lower_inclusive: bool) { - self.lower_inclusive = lower_inclusive; - } - pub fn set_maximum(&mut self, maximum: Option) { - self.maximum = maximum; - } - pub fn set_upper_inclusive(&mut self, upper_inclusive: bool) { - self.upper_inclusive = upper_inclusive; - } - pub fn set_preferred(&mut self, preferred: T) { - self.preferred = preferred; - } - pub fn minimum(&self) -> Option { - self.minimum - } - pub fn lower_inclusive(&self) -> bool { - self.lower_inclusive - } - pub fn maximum(&self) -> Option { - self.maximum - } - pub fn upper_inclusive(&self) -> bool { - self.upper_inclusive - } - pub fn preferred(&self) -> T { - self.preferred - } -} - -impl Default for Range -where - T: Default, -{ - fn default() -> Self { - Range { - minimum: None, - lower_inclusive: true, - maximum: None, - upper_inclusive: true, - preferred: T::default(), - } - } -} - - /// Describes the index of the camera. /// - Index: A numbered index @@ -626,456 +496,6 @@ impl Display for CameraInfo { } } -/// The list of known camera controls to the library.
-/// These can control the picture brightness, etc.
-/// Note that not all backends/devices support all these. Run [`supported_camera_controls()`](crate::traits::CaptureTrait::camera_controls) to see which ones can be set. -#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)] -#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] -pub enum KnownCameraControl { - Brightness, - Contrast, - Hue, - Saturation, - Sharpness, - Gamma, - WhiteBalance, - BacklightComp, - Gain, - Pan, - Tilt, - Zoom, - Exposure, - Iris, - Focus, - Facing, - /// Other camera control. Listed is the ID. - /// Wasteful, however is needed for a unified API across Windows, Linux, and MacOSX due to Microsoft's usage of GUIDs. - /// - /// THIS SHOULD ONLY BE USED WHEN YOU KNOW THE PLATFORM THAT YOU ARE RUNNING ON. - Other(u128), -} - -/// All camera controls in an array. -#[must_use] -pub const fn all_known_camera_controls() -> &'static [KnownCameraControl] { - &[ - KnownCameraControl::Brightness, - KnownCameraControl::Contrast, - KnownCameraControl::Hue, - KnownCameraControl::Saturation, - KnownCameraControl::Sharpness, - KnownCameraControl::Gamma, - KnownCameraControl::WhiteBalance, - KnownCameraControl::BacklightComp, - KnownCameraControl::Gain, - KnownCameraControl::Pan, - KnownCameraControl::Tilt, - KnownCameraControl::Zoom, - KnownCameraControl::Exposure, - KnownCameraControl::Iris, - KnownCameraControl::Focus, - KnownCameraControl::Facing, - ] -} - -impl Display for KnownCameraControl { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", &self) - } -} - -/// This tells you weather a [`KnownCameraControl`] is automatically managed by the OS/Driver -/// or manually managed by you, the programmer. -#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)] -#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] -pub enum KnownCameraControlFlag { - Automatic, - Manual, - Continuous, - ReadOnly, - WriteOnly, - Volatile, - Disabled, -} - -impl Display for KnownCameraControlFlag { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{self:?}") - } -} - -/// The values for a [`CameraControl`]. -/// -/// This provides a wide range of values that can be used to control a camera. -#[derive(Clone, Debug, PartialEq, PartialOrd)] -#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] -pub enum ControlValueDescription { - None, - Integer { - value: i64, - default: i64, - step: i64, - }, - IntegerRange { - min: i64, - max: i64, - value: i64, - step: i64, - default: i64, - }, - Float { - value: f64, - default: f64, - step: f64, - }, - FloatRange { - min: f64, - max: f64, - value: f64, - step: f64, - default: f64, - }, - Boolean { - value: bool, - default: bool, - }, - String { - value: String, - default: Option, - }, - Bytes { - value: Vec, - default: Vec, - }, - KeyValuePair { - key: i128, - value: i128, - default: (i128, i128), - }, - Point { - value: (f64, f64), - default: (f64, f64), - }, - Enum { - value: i64, - possible: Vec, - default: i64, - }, - RGB { - value: (f64, f64, f64), - max: (f64, f64, f64), - default: (f64, f64, f64), - }, - StringList { - value: String, - availible: Vec, - }, -} - -impl ControlValueDescription { - /// Get the value of this [`ControlValueDescription`] - #[must_use] - pub fn value(&self) -> ControlValueSetter { - match self { - ControlValueDescription::None => ControlValueSetter::None, - ControlValueDescription::Integer { value, .. } - | ControlValueDescription::IntegerRange { value, .. } => { - ControlValueSetter::Integer(*value) - } - ControlValueDescription::Float { value, .. } - | ControlValueDescription::FloatRange { value, .. } => { - ControlValueSetter::Float(*value) - } - ControlValueDescription::Boolean { value, .. } => ControlValueSetter::Boolean(*value), - ControlValueDescription::String { value, .. } => { - ControlValueSetter::String(value.clone()) - } - ControlValueDescription::Bytes { value, .. } => { - ControlValueSetter::Bytes(value.clone()) - } - ControlValueDescription::KeyValuePair { key, value, .. } => { - ControlValueSetter::KeyValue(*key, *value) - } - ControlValueDescription::Point { value, .. } => { - ControlValueSetter::Point(value.0, value.1) - } - ControlValueDescription::Enum { value, .. } => ControlValueSetter::EnumValue(*value), - ControlValueDescription::RGB { value, .. } => { - ControlValueSetter::RGB(value.0, value.1, value.2) - } - ControlValueDescription::StringList { value, .. } => { - ControlValueSetter::StringList(value.clone()) - } - } - } - - /// Verifies if the [setter](ControlValueSetter) is valid for the provided [`ControlValueDescription`]. - /// - `true` => Is valid. - /// - `false` => Is not valid. - /// - /// If the step is 0, it will automatically return `true`. - #[must_use] - pub fn verify_setter(&self, setter: &ControlValueSetter) -> bool { - match self { - ControlValueDescription::None => setter.as_none().is_some(), - ControlValueDescription::Integer { - value, - default, - step, - } => { - if *step == 0 { - return true; - } - match setter.as_integer() { - Some(i) => (i + default) % step == 0 || (i + value) % step == 0, - None => false, - } - } - ControlValueDescription::IntegerRange { - min, - max, - value, - step, - default, - } => { - if *step == 0 { - return true; - } - match setter.as_integer() { - Some(i) => { - ((i + default) % step == 0 || (i + value) % step == 0) - && i >= min - && i <= max - } - None => false, - } - } - ControlValueDescription::Float { - value, - default, - step, - } => { - if step.abs() == 0_f64 { - return true; - } - match setter.as_float() { - Some(f) => (f - default).abs() % step == 0_f64 || (f - value) % step == 0_f64, - None => false, - } - } - ControlValueDescription::FloatRange { - min, - max, - value, - step, - default, - } => { - if step.abs() == 0_f64 { - return true; - } - - match setter.as_float() { - Some(f) => { - ((f - default).abs() % step == 0_f64 || (f - value) % step == 0_f64) - && f >= min - && f <= max - } - None => false, - } - } - ControlValueDescription::Boolean { .. } => setter.as_boolean().is_some(), - ControlValueDescription::String { .. } => setter.as_str().is_some(), - ControlValueDescription::Bytes { .. } => setter.as_bytes().is_some(), - ControlValueDescription::KeyValuePair { .. } => setter.as_key_value().is_some(), - ControlValueDescription::Point { .. } => match setter.as_point() { - Some(pt) => { - !pt.0.is_nan() && !pt.1.is_nan() && pt.0.is_finite() && pt.1.is_finite() - } - None => false, - }, - ControlValueDescription::Enum { possible, .. } => match setter.as_enum() { - Some(e) => possible.contains(e), - None => false, - }, - ControlValueDescription::RGB { max, .. } => match setter.as_rgb() { - Some(v) => *v.0 >= max.0 && *v.1 >= max.1 && *v.2 >= max.2, - None => false, - }, - ControlValueDescription::StringList { availible, .. } => { - availible.contains(&(setter.as_str().unwrap_or("").to_string())) // what the fuck?? - } - } - - // match setter { - // ControlValueSetter::None => { - // matches!(self, ControlValueDescription::None) - // } - // ControlValueSetter::Integer(i) => match self { - // ControlValueDescription::Integer { - // value, - // default, - // step, - // } => (i - default).abs() % step == 0 || (i - value) % step == 0, - // ControlValueDescription::IntegerRange { - // min, - // max, - // value, - // step, - // default, - // } => { - // if value > max || value < min { - // return false; - // } - // - // (i - default) % step == 0 || (i - value) % step == 0 - // } - // _ => false, - // }, - // ControlValueSetter::Float(f) => match self { - // ControlValueDescription::Float { - // value, - // default, - // step, - // } => (f - default).abs() % step == 0_f64 || (f - value) % step == 0_f64, - // ControlValueDescription::FloatRange { - // min, - // max, - // value, - // step, - // default, - // } => { - // if value > max || value < min { - // return false; - // } - // - // (f - default) % step == 0_f64 || (f - value) % step == 0_f64 - // } - // _ => false, - // }, - // ControlValueSetter::Boolean(b) => { - // - // } - // ControlValueSetter::String(_) => { - // matches!(self, ControlValueDescription::String { .. }) - // } - // ControlValueSetter::Bytes(_) => { - // matches!(self, ControlValueDescription::Bytes { .. }) - // } - // ControlValueSetter::KeyValue(_, _) => { - // matches!(self, ControlValueDescription::KeyValuePair { .. }) - // } - // ControlValueSetter::Point(_, _) => { - // matches!(self, ControlValueDescription::Point { .. }) - // } - // ControlValueSetter::EnumValue(_) => { - // matches!(self, ControlValueDescription::Enum { .. }) - // } - // ControlValueSetter::RGB(_, _, _) => { - // matches!(self, ControlValueDescription::RGB { .. }) - // } - // } - } -} - -impl Display for ControlValueDescription { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - ControlValueDescription::None => { - write!(f, "(None)") - } - ControlValueDescription::Integer { - value, - default, - step, - } => { - write!(f, "(Current: {value}, Default: {default}, Step: {step})",) - } - ControlValueDescription::IntegerRange { - min, - max, - value, - step, - default, - } => { - write!( - f, - "(Current: {value}, Default: {default}, Step: {step}, Range: ({min}, {max}))", - ) - } - ControlValueDescription::Float { - value, - default, - step, - } => { - write!(f, "(Current: {value}, Default: {default}, Step: {step})",) - } - ControlValueDescription::FloatRange { - min, - max, - value, - step, - default, - } => { - write!( - f, - "(Current: {value}, Default: {default}, Step: {step}, Range: ({min}, {max}))", - ) - } - ControlValueDescription::Boolean { value, default } => { - write!(f, "(Current: {value}, Default: {default})") - } - ControlValueDescription::String { value, default } => { - write!(f, "(Current: {value}, Default: {default:?})") - } - ControlValueDescription::Bytes { value, default } => { - write!(f, "(Current: {value:x?}, Default: {default:x?})") - } - ControlValueDescription::KeyValuePair { - key, - value, - default, - } => { - write!( - f, - "Current: ({key}, {value}), Default: ({}, {})", - default.0, default.1 - ) - } - ControlValueDescription::Point { value, default } => { - write!( - f, - "Current: ({}, {}), Default: ({}, {})", - value.0, value.1, default.0, default.1 - ) - } - ControlValueDescription::Enum { - value, - possible, - default, - } => { - write!( - f, - "Current: {value}, Possible Values: {possible:?}, Default: {default}", - ) - } - ControlValueDescription::RGB { - value, - max, - default, - } => { - write!( - f, - "Current: ({}, {}, {}), Max: ({}, {}, {}), Default: ({}, {}, {})", - 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:?}") - } - } - } -} - // fn step_chk(val: i64, default: i64, step: i64) -> Result<(), NokhwaError> { // if (val - default) % step != 0 { // return Err(NokhwaError::StructureError { @@ -1086,245 +506,6 @@ impl Display for ControlValueDescription { // Ok(()) // } -/// This struct tells you everything about a particular [`KnownCameraControl`]. -/// -/// However, you should never need to instantiate this struct, since its usually generated for you by `nokhwa`. -/// The only time you should be modifying this struct is when you need to set a value and pass it back to the camera. -/// NOTE: Assume the values for `min` and `max` as **non-inclusive**!. -/// E.g. if the [`CameraControl`] says `min` is 100, the minimum is actually 101. -#[derive(Clone, Debug, PartialOrd, PartialEq)] -#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] -pub struct CameraControl { - control: KnownCameraControl, - name: String, - description: ControlValueDescription, - flag: Vec, - active: bool, -} - -impl CameraControl { - /// Creates a new [`CameraControl`] - #[must_use] - pub fn new( - control: KnownCameraControl, - name: String, - description: ControlValueDescription, - flag: Vec, - active: bool, - ) -> Self { - CameraControl { - control, - name, - description, - flag, - active, - } - } - - /// Gets the name of this [`CameraControl`] - #[must_use] - pub fn name(&self) -> &str { - &self.name - } - - /// Gets the [`ControlValueDescription`] of this [`CameraControl`] - #[must_use] - pub fn description(&self) -> &ControlValueDescription { - &self.description - } - - /// Gets the [`ControlValueSetter`] of the [`ControlValueDescription`] of this [`CameraControl`] - #[must_use] - pub fn value(&self) -> ControlValueSetter { - self.description.value() - } - - /// Gets the [`KnownCameraControl`] of this [`CameraControl`] - #[must_use] - pub fn control(&self) -> KnownCameraControl { - self.control - } - - /// Gets the [`KnownCameraControlFlag`] of this [`CameraControl`], - /// telling you weather this control is automatically set or manually set. - #[must_use] - pub fn flag(&self) -> &[KnownCameraControlFlag] { - &self.flag - } - - /// Gets `active` of this [`CameraControl`], - /// telling you weather this control is currently active(in-use). - #[must_use] - pub fn active(&self) -> bool { - self.active - } - - /// Gets `active` of this [`CameraControl`], - /// telling you weather this control is currently active(in-use). - pub fn set_active(&mut self, active: bool) { - self.active = active; - } -} - -impl Display for CameraControl { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!( - f, - "Control: {}, Name: {}, Value: {}, Flag: {:?}, Active: {}", - self.control, self.name, self.description, self.flag, self.active - ) - } -} - -/// The setter for a control value -#[derive(Clone, Debug, PartialEq, PartialOrd)] -#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] -pub enum ControlValueSetter { - None, - Integer(i64), - Float(f64), - Boolean(bool), - String(String), - Bytes(Vec), - KeyValue(i128, i128), - Point(f64, f64), - EnumValue(i64), - RGB(f64, f64, f64), - StringList(String), -} - -impl ControlValueSetter { - #[must_use] - pub fn as_none(&self) -> Option<()> { - if let ControlValueSetter::None = self { - Some(()) - } else { - None - } - } - #[must_use] - - pub fn as_integer(&self) -> Option<&i64> { - if let ControlValueSetter::Integer(i) = self { - Some(i) - } else { - None - } - } - #[must_use] - - pub fn as_float(&self) -> Option<&f64> { - if let ControlValueSetter::Float(f) = self { - Some(f) - } else { - None - } - } - #[must_use] - - pub fn as_boolean(&self) -> Option<&bool> { - if let ControlValueSetter::Boolean(f) = self { - Some(f) - } else { - None - } - } - #[must_use] - - pub fn as_str(&self) -> Option<&str> { - if let ControlValueSetter::String(s) = self { - Some(s) - } else { - None - } - } - #[must_use] - - pub fn as_bytes(&self) -> Option<&[u8]> { - if let ControlValueSetter::Bytes(b) = self { - Some(b) - } else { - None - } - } - #[must_use] - - pub fn as_key_value(&self) -> Option<(&i128, &i128)> { - if let ControlValueSetter::KeyValue(k, v) = self { - Some((k, v)) - } else { - None - } - } - #[must_use] - - pub fn as_point(&self) -> Option<(&f64, &f64)> { - if let ControlValueSetter::Point(x, y) = self { - Some((x, y)) - } else { - None - } - } - #[must_use] - - pub fn as_enum(&self) -> Option<&i64> { - if let ControlValueSetter::EnumValue(e) = self { - Some(e) - } else { - None - } - } - #[must_use] - - pub fn as_rgb(&self) -> Option<(&f64, &f64, &f64)> { - if let ControlValueSetter::RGB(r, g, b) = self { - Some((r, g, b)) - } else { - None - } - } -} - -impl Display for ControlValueSetter { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - ControlValueSetter::None => { - write!(f, "Value: None") - } - ControlValueSetter::Integer(i) => { - write!(f, "IntegerValue: {i}") - } - ControlValueSetter::Float(d) => { - write!(f, "FloatValue: {d}") - } - ControlValueSetter::Boolean(b) => { - write!(f, "BoolValue: {b}") - } - ControlValueSetter::String(s) => { - write!(f, "StrValue: {s}") - } - ControlValueSetter::Bytes(b) => { - write!(f, "BytesValue: {b:x?}") - } - ControlValueSetter::KeyValue(k, v) => { - write!(f, "KVValue: ({k}, {v})") - } - ControlValueSetter::Point(x, y) => { - write!(f, "PointValue: ({x}, {y})") - } - ControlValueSetter::EnumValue(v) => { - write!(f, "EnumValue: {v}") - } - ControlValueSetter::RGB(r, g, b) => { - write!(f, "RGBValue: ({r}, {g}, {b})") - } - ControlValueSetter::StringList(s) => { - write!(f, "StringListValue: {s}") - } - } - } -} - /// The list of known capture backends to the library.
/// - `Auto` - Use automatic selection. /// - `AVFoundation` - Uses `AVFoundation` on `MacOSX` diff --git a/nokhwa-core/src/utils.rs b/nokhwa-core/src/utils.rs index 3a50ba9..1e4f0a9 100644 --- a/nokhwa-core/src/utils.rs +++ b/nokhwa-core/src/utils.rs @@ -15,4 +15,24 @@ pub fn min_max_range + Sized>(min: N, max: N } nums -} \ No newline at end of file +} + +#[derive(Copy, Clone, Debug, Default)] +pub struct FailedMathOp; + +pub(crate) trait FallibleDiv { + type Output; + + type Error: Default; + + fn fallible_div(&self, other: &Self) -> Result; +} + +pub(crate) trait FallibleSub { + type Output; + + type Error: Default; + + fn fallible_sub(&self, other: &Self) -> Result; +} + diff --git a/src/backends/capture/avfoundation.rs b/src/backends/capture/avfoundation.rs index cfae42d..f622fa5 100644 --- a/src/backends/capture/avfoundation.rs +++ b/src/backends/capture/avfoundation.rs @@ -26,14 +26,15 @@ use nokhwa_core::{ pixel_format::RgbFormat, traits::CaptureTrait, types::{ - ApiBackend, CameraControl, CameraFormat, CameraIndex, CameraInfo, ControlValueSetter, - FrameFormat, KnownCameraControl, RequestedFormat, RequestedFormatType, Resolution, + ApiBackend, CameraFormat, CameraIndex, CameraInfo, + FrameFormat, RequestedFormat, RequestedFormatType, Resolution, }, }; #[cfg(target_os = "macos")] use std::{ffi::CString, sync::Arc}; use std::{borrow::Cow, collections::HashMap}; +use nokhwa_core::controls::{CameraControl, ControlValueSetter, KnownCameraControl}; /// The backend struct that interfaces with V4L2. /// To see what this does, please see [`CaptureTrait`]. diff --git a/src/backends/capture/browser_camera.rs b/src/backends/capture/browser_camera.rs index 92c4b0e..5c06c1d 100644 --- a/src/backends/capture/browser_camera.rs +++ b/src/backends/capture/browser_camera.rs @@ -7,30 +7,31 @@ use serde::{de, Serialize}; use wasm_bindgen_futures::JsFuture; use web_sys::{window, MediaDeviceInfo, MediaDevices, MediaStream, MediaStreamConstraints, MediaStreamTrack, MediaTrackConstraints, Navigator}; use nokhwa_core::buffer::Buffer; +use nokhwa_core::controls::{CameraControl, ControlValueSetter, KnownCameraControl}; use nokhwa_core::error::NokhwaError; use nokhwa_core::frame_format::FrameFormat; use nokhwa_core::traits::{AsyncCaptureTrait, AsyncOpenCaptureTrait, CaptureTrait, OpenCaptureTrait}; -use nokhwa_core::types::{ApiBackend, CameraControl, CameraFormat, CameraIndex, CameraInfo, ControlValueSetter, FrameRate, KnownCameraControl, Resolution}; +use nokhwa_core::types::{ApiBackend, CameraFormat, CameraIndex, CameraInfo, FrameRate, Resolution}; async fn resolve_to(promise: Promise) -> Result { let future = JsFuture::from(promise); let jsv = match future.await { Ok(v) => v, - Err(why) => NokhwaError::ConversionError(why.as_string().unwrap_or_default()) + Err(why) => return Err(NokhwaError::ConversionError(why.as_string().unwrap_or_default())) }; // we do a little checking if !T::has_type(&jsv) { return Err(NokhwaError::ConversionError("Bad Conversion - No Type".to_string())) } - Ok(unsafe { cast_js_value(v) }) + Ok(unsafe { cast_js_value(jsv) }) } fn checked_js_cast(from: JsValue) -> Result { // we do a little checking - if !T::has_type(&jsv) { + if !T::has_type(&from) { return Err(NokhwaError::ConversionError("Bad Conversion - No Type".to_string())) } - Ok(unsafe { cast_js_value(v) }) + Ok(unsafe { cast_js_value(from) }) } // PLEASE CHECK WHAT YOU'RE DOING OH MY GOD @@ -80,6 +81,14 @@ struct ConstrainedULong { pub exact: Option, } +pub enum BrowserCameraControls { + FacingMode, + ResizeMode, + AttachedCanvasId, + AttachedCanvasMode, +} + + pub struct BrowserCaptureDevice { info: CameraInfo, @@ -130,7 +139,7 @@ impl BrowserCaptureDevice { let mut constraint = MediaStreamConstraints::new(); let mut video_constraint = MediaTrackConstraints::new(); - video_constraint = video_constraint.device_id(&JsValue::from_str(&device_id)); + video_constraint.device_id(&JsValue::from_str(&device_id)); match camera_fmt { FormatRequest::Closest { resolution, frame_rate, frame_format } => { @@ -170,9 +179,9 @@ impl BrowserCaptureDevice { None => ConstrainedDouble::default(), }; - video_constraint = video_constraint.width(width.into()); - video_constraint = video_constraint.height(height.into()); - video_constraint = video_constraint.frame_rate(frame_rate.into()); + video_constraint.width(width.into()); + video_constraint.height(height.into()); + video_constraint.frame_rate(frame_rate.into()); } FormatRequest::HighestFrameRate { frame_rate, frame_format } => { let frame_rate = match frame_rate { @@ -185,7 +194,7 @@ impl BrowserCaptureDevice { None => ConstrainedDouble::default(), }; - video_constraint = video_constraint.frame_rate(frame_rate.into()); + video_constraint.frame_rate(frame_rate.into()); } FormatRequest::HighestResolution { resolution, frame_format } => { let (_aspect_ratio, width, height) = match resolution { @@ -214,8 +223,8 @@ impl BrowserCaptureDevice { ), }; - video_constraint = video_constraint.width(width.into()); - video_constraint = video_constraint.height(height.into()); + video_constraint.width(width.into()); + video_constraint.height(height.into()); } FormatRequest::Exact { resolution, frame_rate, frame_format } => { let (_aspect_ratio, width, height) = match resolution { @@ -254,13 +263,13 @@ impl BrowserCaptureDevice { None => ConstrainedDouble::default(), }; - video_constraint = video_constraint.width(width.into()); - video_constraint = video_constraint.height(height.into()); - video_constraint = video_constraint.frame_rate(frame_rate.into()); + video_constraint.width(width.into()); + video_constraint.height(height.into()); + video_constraint.frame_rate(frame_rate.into()); } } - constraint = constraint.video(&video_constraint); + constraint.video(&video_constraint); let media_stream: MediaStream = resolve_to(media_devices.get_user_media_with_constraints(&constraint)).await?; diff --git a/src/backends/capture/msmf_backend.rs b/src/backends/capture/msmf_backend.rs index 2b3ea17..477977d 100644 --- a/src/backends/capture/msmf_backend.rs +++ b/src/backends/capture/msmf_backend.rs @@ -20,12 +20,13 @@ use nokhwa_core::{ pixel_format::RgbFormat, traits::CaptureTrait, types::{ - all_known_camera_controls, ApiBackend, CameraControl, CameraFormat, CameraIndex, - CameraInfo, ControlValueSetter, FrameFormat, KnownCameraControl, RequestedFormat, + ApiBackend, CameraFormat, CameraIndex, + CameraInfo, FrameFormat, RequestedFormat, RequestedFormatType, Resolution, }, }; use std::{borrow::Cow, collections::HashMap}; +use nokhwa_core::controls::{all_known_camera_controls, CameraControl, ControlValueSetter, KnownCameraControl}; /// The backend that deals with Media Foundation on Windows. /// To see what this does, please see [`CaptureTrait`]. diff --git a/src/backends/capture/opencv_backend.rs b/src/backends/capture/opencv_backend.rs index 9c418c1..fe039c5 100644 --- a/src/backends/capture/opencv_backend.rs +++ b/src/backends/capture/opencv_backend.rs @@ -20,8 +20,8 @@ use nokhwa_core::{ error::NokhwaError, traits::CaptureTrait, types::{ - ApiBackend, CameraControl, CameraFormat, CameraIndex, CameraInfo, ControlValueDescription, - ControlValueSetter, FrameFormat, KnownCameraControl, RequestedFormat, Resolution, + ApiBackend, CameraFormat, CameraIndex, CameraInfo, + FrameFormat, RequestedFormat, Resolution, }, }; use opencv::{ @@ -33,6 +33,7 @@ use opencv::{ }, }; use std::{borrow::Cow, collections::HashMap}; +use nokhwa_core::controls::{CameraControl, ControlValueDescription, ControlValueSetter, KnownCameraControl}; /// Attempts to convert a [`KnownCameraControl`] into a `OpenCV` video capture property. /// If the associated control is not found, this will return `Err` diff --git a/src/camera.rs b/src/camera.rs index ffba83e..3959d77 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -23,13 +23,12 @@ use nokhwa_core::{ pixel_format::FormatDecoder, traits::CaptureTrait, types::{ - ApiBackend, CameraControl, CameraFormat, CameraIndex, CameraInfo, ControlValueSetter, - FrameFormat, KnownCameraControl, RequestedFormatType, Resolution, + ApiBackend, CameraFormat, CameraIndex, CameraInfo + , RequestedFormatType, Resolution, }, }; use std::{borrow::Cow, collections::HashMap}; -#[cfg(feature = "output-wgpu")] -use wgpu::{Device as WgpuDevice, Queue as WgpuQueue, Texture as WgpuTexture}; +use nokhwa_core::controls::{CameraControl, ControlValueSetter, KnownCameraControl}; /// The main `Camera` struct. This is the struct that abstracts over all the backends, providing a simplified interface for use. pub struct Camera { diff --git a/src/decoders/mjpeg.rs b/src/decoders/mjpeg.rs deleted file mode 100644 index 6aeb2e1..0000000 --- a/src/decoders/mjpeg.rs +++ /dev/null @@ -1,82 +0,0 @@ -// use image::{ImageBuffer, Rgb}; -// use nokhwa_core::buffer::Buffer; -// use nokhwa_core::r#mod::{Decoder, IdemptDecoder, StaticDecoder}; -// use nokhwa_core::error::NokhwaError; -// use nokhwa_core::frame_format::{FrameFormat, SourceFrameFormat}; -// -// #[inline] -// fn decompress( -// data: &[u8], -// rgba: bool, -// ) -> Result<, NokhwaError> { -// use mozjpeg::Decompress; -// -// match Decompress::new_mem(data) { -// Ok(decompress) => { -// let decompressor_res = if rgba { -// decompress.rgba() -// } else { -// decompress.rgb() -// }; -// match decompressor_res { -// Ok(decompressor) => Ok(decompressor), -// Err(why) => { -// return Err(NokhwaError::ProcessFrameError { -// src: FrameFormat::MJpeg, -// destination: "RGB888".to_string(), -// error: why.to_string(), -// }) -// } -// } -// } -// Err(why) => { -// return Err(NokhwaError::ProcessFrameError { -// src: FrameFormat::MJpeg, -// destination: "RGB888".to_string(), -// error: why.to_string(), -// }) -// } -// } -// } -// -// -// pub struct MJPegDecoder; -// -// impl Decoder for MJPegDecoder { -// const ALLOWED_FORMATS: &'static [SourceFrameFormat] = &[SourceFrameFormat::FrameFormat(FrameFormat::MJpeg)]; -// type Pixel = Rgb; -// type Container = Vec; -// type Error = NokhwaError; -// -// fn decode(&mut self, buffer: Buffer) -> Result, Self::Error> { -// todo!() -// } -// -// fn decode_buffer(&mut self, buffer: &mut [Pixel::Subpixel]) -> Result<(), Self::Error> { -// todo!() -// } -// -// fn predicted_size_of_frame(&mut self) -> Option { -// todo!() -// } -// } -// -// impl StaticDecoder for MJPegDecoder { -// fn decode_static(buffer: Buffer) -> Result, Self::Error> { -// todo!() -// } -// -// fn decode_static_to_buffer(buffer: &mut [Pixel::Subpixel]) -> Result<(), Self::Error> { -// todo!() -// } -// } -// -// impl IdemptDecoder for MJPegDecoder { -// fn decode_nm(&self, buffer: Buffer) -> Result, Self::Error> { -// todo!() -// } -// -// fn decode_nm_to_buffer(&self, buffer: &mut [Pixel::Subpixel]) -> Result<(), Self::Error> { -// todo!() -// } -// } diff --git a/src/decoders/mod.rs b/src/decoders/mod.rs deleted file mode 100644 index e321a45..0000000 --- a/src/decoders/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod mjpeg; -pub mod yuyv; -pub mod nv12; diff --git a/src/decoders/nv12.rs b/src/decoders/nv12.rs deleted file mode 100644 index 04929c0..0000000 --- a/src/decoders/nv12.rs +++ /dev/null @@ -1,41 +0,0 @@ -// use image::{ImageBuffer, Rgb}; -// use nokhwa_core::buffer::Buffer; -// use nokhwa_core::r#mod::{Decoder, IdemptDecoder, StaticDecoder}; -// use nokhwa_core::frame_format::SourceFrameFormat; -// -// pub struct NV12Decoder {} -// -// impl Decoder for NV12Decoder { -// const ALLOWED_FORMATS: &'static [SourceFrameFormat] = &[]; -// type Pixel = Rgb; -// type Container = Vec; -// type Error = (); -// -// fn decode(&mut self, buffer: Buffer) -> Result, Self::Error> { -// todo!() -// } -// -// fn decode_buffer(&mut self, buffer: &mut [Pixel::Subpixel]) -> Result<(), Self::Error> { -// todo!() -// } -// -// fn predicted_size_of_frame(&mut self) -> Option { -// todo!() -// } -// } -// -// impl StaticDecoder for NV12Decoder { -// fn decode_static(buffer: Buffer) -> Result, Self::Error> { -// todo!() -// } -// -// fn decode_static_to_buffer(buffer: &mut [Pixel::Subpixel]) -> Result<(), Self::Error> { -// todo!() -// } -// } -// -// impl IdemptDecoder for NV12Decoder { -// fn decode_nm(buffer: Buffer) -> Result, Self::Error> { -// todo!() -// } -// } \ No newline at end of file diff --git a/src/decoders/yuyv.rs b/src/decoders/yuyv.rs deleted file mode 100644 index 35248a9..0000000 --- a/src/decoders/yuyv.rs +++ /dev/null @@ -1,54 +0,0 @@ -// use image::ImageBuffer; -// use nokhwa_core::buffer::Buffer; -// use nokhwa_core::r#mod::{Decoder, IdemptDecoder, StaticDecoder}; -// use nokhwa_core::frame_format::SourceFrameFormat; -// -// // For those maintaining this, I recommend you read: https://docs.microsoft.com/en-us/windows/win32/medfound/recommended-8-bit-yuv-formats-for-video-rendering#yuy2 -// // https://en.wikipedia.org/wiki/YUV#Converting_between_Y%E2%80%B2UV_and_RGB -// // and this too: https://stackoverflow.com/questions/16107165/convert-from-yuv-420-to-imagebgr-byte -// // The YUY2(Yuv422) format is a 16 bit format. We read 4 bytes at a time to get 6 bytes of RGB888. -// // First, the YUY2 is converted to YCbCr 4:4:4 (4:2:2 -> 4:4:4) -// // then it is converted to 6 bytes (2 pixels) of RGB888 -// /// Converts a Yuv422 4:2:2 datastream to a RGB888 Stream. [For further reading](https://en.wikipedia.org/wiki/YUV#Converting_between_Y%E2%80%B2UV_and_RGB) -// /// # Errors -// /// This may error when the data stream size is not divisible by 4, a i32 -> u8 conversion fails, or it fails to read from a certain index. -// pub struct YUYVDecoder {} -// -// impl Decoder for YUYVDecoder { -// const ALLOWED_FORMATS: &'static [SourceFrameFormat] = &[]; -// type Pixel = (); -// type Container = (); -// type Error = (); -// -// fn decode(&mut self, buffer: Buffer) -> Result, Self::Error> { -// todo!() -// } -// -// fn decode_buffer(&mut self, buffer: &mut [Pixel::Subpixel]) -> Result<(), Self::Error> { -// todo!() -// } -// -// fn predicted_size_of_frame(&mut self) -> Option { -// todo!() -// } -// } -// -// impl StaticDecoder for YUYVDecoder { -// fn decode_static(buffer: Buffer) -> Result, Self::Error> { -// todo!() -// } -// -// fn decode_static_to_buffer(buffer: &mut [Pixel::Subpixel]) -> Result<(), Self::Error> { -// todo!() -// } -// } -// -// impl IdemptDecoder for YUYVDecoder { -// fn decode_nm(&self, buffer: Buffer) -> Result, Self::Error> { -// todo!() -// } -// -// fn decode_nm_to_buffer(&self, buffer: &mut [Pixel::Subpixel]) -> Result<(), Self::Error> { -// todo!() -// } -// } diff --git a/src/lib.rs b/src/lib.rs index 0620e56..4187a1f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,12 +35,8 @@ pub mod backends; mod camera; mod init; /// A camera that uses native browser APIs meant for WASM applications. -#[cfg(feature = "input-jscam")] -#[cfg_attr(feature = "docs-features", doc(cfg(feature = "input-jscam")))] -pub mod js_camera; mod platform_resolver; -pub use nokhwa_core::pixel_format::FormatDecoder; #[cfg(feature = "output-async")] #[cfg_attr(feature = "docs-features", doc(cfg(feature = "output-async")))] pub mod async_camera; @@ -49,7 +45,6 @@ mod query; #[cfg(feature = "output-threaded")] #[cfg_attr(feature = "docs-features", doc(cfg(feature = "output-threaded")))] pub mod threaded; -pub mod decoders; pub use camera::Camera; pub use init::*; @@ -72,10 +67,6 @@ pub mod camera_traits { pub use nokhwa_core::traits::*; } -pub mod pixel_format { - pub use nokhwa_core::pixel_format::*; -} - pub mod buffer { pub use nokhwa_core::buffer::*; } diff --git a/src/threaded.rs b/src/threaded.rs index 725d0a4..eeefd3f 100644 --- a/src/threaded.rs +++ b/src/threaded.rs @@ -19,8 +19,8 @@ use nokhwa_core::{ buffer::Buffer, error::NokhwaError, types::{ - ApiBackend, CameraControl, CameraFormat, CameraIndex, CameraInfo, ControlValueSetter, - FrameFormat, KnownCameraControl, RequestedFormat, RequestedFormatType, Resolution, + ApiBackend, CameraFormat, CameraIndex, CameraInfo, + FrameFormat, RequestedFormat, RequestedFormatType, Resolution, }, }; use std::thread::JoinHandle; @@ -31,6 +31,7 @@ use std::{ Arc, Mutex, }, }; +use nokhwa_core::controls::{CameraControl, ControlValueSetter, KnownCameraControl}; type AtomicLock = Arc>; pub type CallbackFn = fn( @@ -419,7 +420,7 @@ impl CallbackCamera { /// Sets the control to `control` in the camera. /// Usually, the pipeline is calling [`camera_control()`](crate::camera_traits::CaptureTrait::camera_control), getting a camera control that way - /// then calling [`value()`](crate::utils::CameraControl::value()) to get a [`ControlValueSetter`](crate::utils::ControlValueSetter) and setting the value that way. + /// then calling [`value()`](nokhwa_core::controls::CameraControl::value()) to get a [`ControlValueSetter`](nokhwa_core::controls::ControlValueSetter) and setting the value that way. /// # Errors /// If the `control` is not supported, the value is invalid (less than min, greater than max, not in step), or there was an error setting the control, /// this will error.