mirror of
https://github.com/l1npengtul/nokhwa.git
synced 2026-07-04 10:37:26 +00:00
new controls
This commit is contained in:
Generated
+140
-40
@@ -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
@@ -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;
|
||||
|
||||
|
||||
@@ -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`)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
@@ -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(), )
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -30,3 +30,5 @@ pub mod traits;
|
||||
pub mod types;
|
||||
pub mod decoders;
|
||||
pub mod utils;
|
||||
pub mod ranges;
|
||||
pub mod controls;
|
||||
|
||||
@@ -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, );
|
||||
@@ -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
@@ -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`
|
||||
|
||||
@@ -16,3 +16,23 @@ 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>;
|
||||
}
|
||||
|
||||
|
||||
@@ -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`].
|
||||
|
||||
@@ -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?;
|
||||
|
||||
|
||||
@@ -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`].
|
||||
|
||||
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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!()
|
||||
// }
|
||||
// }
|
||||
@@ -1,3 +0,0 @@
|
||||
pub mod mjpeg;
|
||||
pub mod yuyv;
|
||||
pub mod nv12;
|
||||
@@ -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!()
|
||||
// }
|
||||
// }
|
||||
@@ -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!()
|
||||
// }
|
||||
// }
|
||||
@@ -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
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user