new controls

This commit is contained in:
l1npengtul
2024-10-02 22:10:31 +09:00
parent d5eab8bbf2
commit 4adf68c85f
26 changed files with 2004 additions and 1105 deletions
Generated
+140 -40
View File
@@ -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"
+12 -5
View File
@@ -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;
+8 -6
View File
@@ -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`)
+3 -2
View File
@@ -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;
+5 -4
View File
@@ -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(
+5 -2
View File
@@ -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"]
File diff suppressed because it is too large Load Diff
+3 -1
View File
@@ -49,10 +49,12 @@ impl<D> Decoder for GeneralPurposeDecoder<D> 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(), )
}
}
+1
View File
@@ -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)]
+3 -2
View File
@@ -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 {
+2
View File
@@ -30,3 +30,5 @@ pub mod traits;
pub mod types;
pub mod decoders;
pub mod utils;
pub mod ranges;
pub mod controls;
+516
View File
@@ -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<T>
{
minimum: Option<T>,
lower_inclusive: bool,
maximum: Option<T>,
upper_inclusive: bool,
preferred: T,
}
impl<T> Range<T>
where
T: Copy + Clone + Debug + PartialOrd + PartialEq,
{
/// Create an upper and lower inclusive [`Range`]
pub fn new(preferred: T, min: Option<T>, max: Option<T>) -> Self {
Self {
minimum: min,
lower_inclusive: true,
maximum: max,
upper_inclusive: true,
preferred,
}
}
pub fn with_inclusive(
preferred: T,
min: Option<T>,
lower_inclusive: bool,
max: Option<T>,
upper_inclusive: bool,
) -> Self {
Self {
minimum: min,
lower_inclusive,
maximum: max,
upper_inclusive,
preferred,
}
}
pub fn exact(preferred: T) -> Self {
Self {
minimum: None,
lower_inclusive: true,
maximum: None,
upper_inclusive: true,
preferred,
}
}
pub fn set_minimum(&mut self, minimum: Option<T>) {
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<T>) {
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<T> {
self.minimum
}
pub fn lower_inclusive(&self) -> bool {
self.lower_inclusive
}
pub fn maximum(&self) -> Option<T> {
self.maximum
}
pub fn upper_inclusive(&self) -> bool {
self.upper_inclusive
}
pub fn preferred(&self) -> T {
self.preferred
}
}
impl<T> ValidatableRange for Range<T> 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<T> Default for Range<T>
where
T: Default,
{
fn default() -> Self {
Range {
minimum: None,
lower_inclusive: true,
maximum: None,
upper_inclusive: true,
preferred: T::default(),
}
}
}
impl<T> Display for Range<T> 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<T> where T: Copy + Clone + Debug + PartialOrd + PartialEq {
minimum: T,
lower_inclusive: bool,
maximum: T,
upper_inclusive: bool,
step: Option<T>,
default: Option<T>,
}
impl<T> IndicatedRange<T>
where
T: Copy + Clone + Debug + PartialOrd + PartialEq
{
pub fn new(minimum: T, lower_inclusive: bool, maximum: T, upper_inclusive: bool, step: Option<T>, default: Option<T>) -> 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
}
pub fn default_value(&self) -> Option<T> {
self.default
}
}
impl<T> ValidatableRange for IndicatedRange<T> where T: Copy + PartialEq + PartialOrd + Div<Output = T> + Sub<Output = T> + 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<T> Display for IndicatedRange<T> 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<T> where T: Clone + Debug + PartialOrd + PartialEq {
minimum: T,
lower_inclusive: bool,
maximum: T,
upper_inclusive: bool,
step: Option<T>,
default: Option<T>,
}
impl<T> NonCopyRange<T>
where
T: Clone + Debug + PartialOrd + PartialEq
{
pub fn new(minimum: T, lower_inclusive: bool, maximum: T, upper_inclusive: bool, step: Option<T>, default: Option<T>) -> 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<T> ValidatableRange for NonCopyRange<T> where T: Clone + PartialEq + PartialOrd + Div<Output = T> + Sub<Output = T> {
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<T> Display for IndicatedRange<T> 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<T> where T: Clone + Debug {
default: Option<T>,
available: Vec<T>,
}
impl<T> Options<T>
where
T: Clone + Debug + PartialEq
{
pub fn new(values: Vec<T>, 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<T> ValidatableRange for Options<T> 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<T> Display for Options<T> 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<K, V> where K: Clone + Debug + Hash + Eq, V: Clone + Debug {
defaults: HashMap<K, V>,
}
impl<K, V> KeyValue<K, V>
where
K: Clone + Debug + Hash + Eq,
V: Clone + Debug
{
pub fn new(default: HashMap<K, V>) -> 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<T> ValidatableRange for KeyValue<T, _> 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<K, V> Display for KeyValue<K, V> 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<T> where T: Clone + Debug {
appendable_options: Vec<T>,
default_options: Vec<T>,
}
impl<T> ArrayRange<T> where T: Clone + Debug + PartialEq {
pub fn new(appendable: Vec<T>, default: Vec<T>) -> Result<Self, NokhwaError> {
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<T> ValidatableRange for ArrayRange<T> 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<T> Display for ArrayRange<T> 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<T> where T: Clone + Debug {
default: Option<T>
}
impl<T> Simple<T> where T: Clone + Debug {
pub fn new(default: Option<T>) -> Self {
Self {
default,
}
}
pub fn default_value(&self) -> Option<&T> {
self.default.as_ref()
}
}
impl<T> ValidatableRange for Simple<T> {
type Validation = T;
fn validate(&self, _: Self::Validation) -> Result<(), RangeValidationFailure> {
Ok(())
}
}
impl<T> Display for Simple<T> 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<T>(default: &Option<T>) -> String where T: Debug {
match default {
Some(v) => {
format!("{v:?}")
}
None => String::from("None"),
}
}
fn num_range_validate<T>(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, );
+2 -1
View File
@@ -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;
+4 -823
View File
@@ -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<T>
{
minimum: Option<T>,
lower_inclusive: bool,
maximum: Option<T>,
upper_inclusive: bool,
preferred: T,
}
impl<T> Range<T>
where
T: Copy + Clone + Debug + PartialOrd + PartialEq,
{
/// Create an upper and lower inclusive [`Range`]
pub fn new(preferred: T, min: Option<T>, max: Option<T>) -> Self {
Self {
minimum: min,
lower_inclusive: true,
maximum: max,
upper_inclusive: true,
preferred,
}
}
pub fn with_inclusive(
preferred: T,
min: Option<T>,
lower_inclusive: bool,
max: Option<T>,
upper_inclusive: bool,
) -> Self {
Self {
minimum: min,
lower_inclusive,
maximum: max,
upper_inclusive,
preferred,
}
}
pub fn 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<T>) {
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<T>) {
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<T> {
self.minimum
}
pub fn lower_inclusive(&self) -> bool {
self.lower_inclusive
}
pub fn maximum(&self) -> Option<T> {
self.maximum
}
pub fn upper_inclusive(&self) -> bool {
self.upper_inclusive
}
pub fn preferred(&self) -> T {
self.preferred
}
}
impl<T> Default for Range<T>
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. <br>
/// These can control the picture brightness, etc. <br>
/// 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<String>,
},
Bytes {
value: Vec<u8>,
default: Vec<u8>,
},
KeyValuePair {
key: i128,
value: i128,
default: (i128, i128),
},
Point {
value: (f64, f64),
default: (f64, f64),
},
Enum {
value: i64,
possible: Vec<i64>,
default: i64,
},
RGB {
value: (f64, f64, f64),
max: (f64, f64, f64),
default: (f64, f64, f64),
},
StringList {
value: String,
availible: Vec<String>,
},
}
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<KnownCameraControlFlag>,
active: bool,
}
impl CameraControl {
/// Creates a new [`CameraControl`]
#[must_use]
pub fn new(
control: KnownCameraControl,
name: String,
description: ControlValueDescription,
flag: Vec<KnownCameraControlFlag>,
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<u8>),
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. <br>
/// - `Auto` - Use automatic selection.
/// - `AVFoundation` - Uses `AVFoundation` on `MacOSX`
+21 -1
View File
@@ -15,4 +15,24 @@ pub fn min_max_range<N: Copy + PartialOrd + AddAssign<N> + Sized>(min: N, max: N
}
nums
}
}
#[derive(Copy, Clone, Debug, Default)]
pub struct FailedMathOp;
pub(crate) trait FallibleDiv {
type Output;
type Error: Default;
fn fallible_div(&self, other: &Self) -> Result<Self::Output, Self::Error>;
}
pub(crate) trait FallibleSub {
type Output;
type Error: Default;
fn fallible_sub(&self, other: &Self) -> Result<Self::Output, Self::Error>;
}
+3 -2
View File
@@ -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`].
+25 -16
View File
@@ -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<T: JsCast>(promise: Promise) -> Result<T, NokhwaError> {
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<T: JsCast>(from: JsValue) -> Result<T, NokhwaError> {
// 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<u64>,
}
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?;
+3 -2
View File
@@ -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`].
+3 -2
View File
@@ -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`
+3 -4
View File
@@ -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 {
-82
View File
@@ -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<u8>;
// type Container = Vec<u8>;
// type Error = NokhwaError;
//
// fn decode(&mut self, buffer: Buffer) -> Result<ImageBuffer<Self::Pixel, Self::Container>, Self::Error> {
// todo!()
// }
//
// fn decode_buffer(&mut self, buffer: &mut [Pixel::Subpixel]) -> Result<(), Self::Error> {
// todo!()
// }
//
// fn predicted_size_of_frame(&mut self) -> Option<usize> {
// todo!()
// }
// }
//
// impl StaticDecoder for MJPegDecoder {
// fn decode_static(buffer: Buffer) -> Result<ImageBuffer<Self::Pixel, Self::Container>, 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<ImageBuffer<Self::Pixel, Self::Container>, Self::Error> {
// todo!()
// }
//
// fn decode_nm_to_buffer(&self, buffer: &mut [Pixel::Subpixel]) -> Result<(), Self::Error> {
// todo!()
// }
// }
-3
View File
@@ -1,3 +0,0 @@
pub mod mjpeg;
pub mod yuyv;
pub mod nv12;
-41
View File
@@ -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<u8>;
// type Container = Vec<u8>;
// type Error = ();
//
// fn decode(&mut self, buffer: Buffer) -> Result<ImageBuffer<Self::Pixel, Self::Container>, Self::Error> {
// todo!()
// }
//
// fn decode_buffer(&mut self, buffer: &mut [Pixel::Subpixel]) -> Result<(), Self::Error> {
// todo!()
// }
//
// fn predicted_size_of_frame(&mut self) -> Option<usize> {
// todo!()
// }
// }
//
// impl StaticDecoder for NV12Decoder {
// fn decode_static(buffer: Buffer) -> Result<ImageBuffer<Self::Pixel, Self::Container>, 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<ImageBuffer<Self::Pixel, Self::Container>, Self::Error> {
// todo!()
// }
// }
-54
View File
@@ -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<ImageBuffer<Self::Pixel, Self::Container>, Self::Error> {
// todo!()
// }
//
// fn decode_buffer(&mut self, buffer: &mut [Pixel::Subpixel]) -> Result<(), Self::Error> {
// todo!()
// }
//
// fn predicted_size_of_frame(&mut self) -> Option<usize> {
// todo!()
// }
// }
//
// impl StaticDecoder for YUYVDecoder {
// fn decode_static(buffer: Buffer) -> Result<ImageBuffer<Self::Pixel, Self::Container>, 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<ImageBuffer<Self::Pixel, Self::Container>, Self::Error> {
// todo!()
// }
//
// fn decode_nm_to_buffer(&self, buffer: &mut [Pixel::Subpixel]) -> Result<(), Self::Error> {
// todo!()
// }
// }
-9
View File
@@ -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::*;
}
+4 -3
View File
@@ -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<T> = Arc<Mutex<T>>;
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.