mirror of
https://github.com/l1npengtul/nokhwa.git
synced 2026-07-04 02:27:26 +00:00
start fixing core
This commit is contained in:
Generated
+134
-99
@@ -243,11 +243,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bit-set"
|
name = "bit-set"
|
||||||
version = "0.6.0"
|
version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f0481a0e032742109b1133a095184ee93d88f3dc9e0d28a5d033dc77a073f44f"
|
checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bit-vec 0.7.0",
|
"bit-vec 0.8.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -258,9 +258,9 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bit-vec"
|
name = "bit-vec"
|
||||||
version = "0.7.0"
|
version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d2c54ff287cfc0a34f38a6b832ea1bd8e448a330b3e40a50859e6488bee07f22"
|
checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bit_field"
|
name = "bit_field"
|
||||||
@@ -309,9 +309,9 @@ checksum = "e1e5f035d16fc623ae5f74981db80a439803888314e3a555fd6f04acd51a3205"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytemuck"
|
name = "bytemuck"
|
||||||
version = "1.15.0"
|
version = "1.20.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15"
|
checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck_derive",
|
"bytemuck_derive",
|
||||||
]
|
]
|
||||||
@@ -349,7 +349,7 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"nix 0.25.1",
|
"nix 0.25.1",
|
||||||
"slotmap",
|
"slotmap",
|
||||||
"thiserror 1.0.63",
|
"thiserror 1.0.69",
|
||||||
"vec_map",
|
"vec_map",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -973,17 +973,6 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "d3d12"
|
|
||||||
version = "22.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bdbd1f579714e3c809ebd822c81ef148b1ceaeb3d535352afc73fd0c4c6a0017"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.6.0",
|
|
||||||
"libloading 0.8.3",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "darling"
|
name = "darling"
|
||||||
version = "0.13.4"
|
version = "0.13.4"
|
||||||
@@ -1525,6 +1514,18 @@ dependencies = [
|
|||||||
"web-sys",
|
"web-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "glow"
|
||||||
|
version = "0.14.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d51fa363f025f5c111e03f13eda21162faeacb6911fe8caa0c0349f9cf0c4483"
|
||||||
|
dependencies = [
|
||||||
|
"js-sys",
|
||||||
|
"slotmap",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"web-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glutin_wgl_sys"
|
name = "glutin_wgl_sys"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
@@ -1627,22 +1628,21 @@ checksum = "6f56f6318968d03c18e1bcf4857ff88c61157e9da8e47c5f29055d60e1228884"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"presser",
|
"presser",
|
||||||
"thiserror 1.0.63",
|
"thiserror 1.0.69",
|
||||||
"winapi",
|
"winapi",
|
||||||
"windows 0.52.0",
|
"windows 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gpu-allocator"
|
name = "gpu-allocator"
|
||||||
version = "0.26.0"
|
version = "0.27.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fdd4240fc91d3433d5e5b0fc5b67672d771850dc19bbee03c1381e19322803d7"
|
checksum = "c151a2a5ef800297b4e79efa4f4bec035c5f51d5ae587287c9b952bdf734cacd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"presser",
|
"presser",
|
||||||
"thiserror 1.0.63",
|
"thiserror 1.0.69",
|
||||||
"winapi",
|
"windows 0.58.0",
|
||||||
"windows 0.52.0",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1721,7 +1721,7 @@ dependencies = [
|
|||||||
"com",
|
"com",
|
||||||
"libc",
|
"libc",
|
||||||
"libloading 0.8.3",
|
"libloading 0.8.3",
|
||||||
"thiserror 1.0.63",
|
"thiserror 1.0.69",
|
||||||
"widestring",
|
"widestring",
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
@@ -1763,7 +1763,7 @@ dependencies = [
|
|||||||
"byteorder",
|
"byteorder",
|
||||||
"color_quant",
|
"color_quant",
|
||||||
"num-iter",
|
"num-iter",
|
||||||
"num-rational",
|
"num-rational 0.3.2",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1888,9 +1888,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.69"
|
version = "0.3.72"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
|
checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
@@ -2288,7 +2288,7 @@ dependencies = [
|
|||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"spirv 0.2.0+1.5.4",
|
"spirv 0.2.0+1.5.4",
|
||||||
"termcolor",
|
"termcolor",
|
||||||
"thiserror 1.0.63",
|
"thiserror 1.0.69",
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2309,18 +2309,18 @@ dependencies = [
|
|||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"spirv 0.3.0+sdk-1.3.268.0",
|
"spirv 0.3.0+sdk-1.3.268.0",
|
||||||
"termcolor",
|
"termcolor",
|
||||||
"thiserror 1.0.63",
|
"thiserror 1.0.69",
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "naga"
|
name = "naga"
|
||||||
version = "22.0.0"
|
version = "23.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "09eeccb9b50f4f7839b214aa3e08be467159506a986c18e0702170ccf720a453"
|
checksum = "3d5941e45a15b53aad4375eedf02033adb7a28931eedc31117faffa52e6a857e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec 0.7.4",
|
"arrayvec 0.7.4",
|
||||||
"bit-set 0.6.0",
|
"bit-set 0.8.0",
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"codespan-reporting",
|
"codespan-reporting",
|
||||||
@@ -2330,7 +2330,7 @@ dependencies = [
|
|||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"spirv 0.3.0+sdk-1.3.268.0",
|
"spirv 0.3.0+sdk-1.3.268.0",
|
||||||
"termcolor",
|
"termcolor",
|
||||||
"thiserror 1.0.63",
|
"thiserror 1.0.69",
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2363,7 +2363,7 @@ dependencies = [
|
|||||||
"ndk-sys 0.4.1+23.1.7779620",
|
"ndk-sys 0.4.1+23.1.7779620",
|
||||||
"num_enum",
|
"num_enum",
|
||||||
"raw-window-handle 0.5.2",
|
"raw-window-handle 0.5.2",
|
||||||
"thiserror 1.0.63",
|
"thiserror 1.0.69",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2464,7 +2464,7 @@ dependencies = [
|
|||||||
"rgb",
|
"rgb",
|
||||||
"serde",
|
"serde",
|
||||||
"serde-wasm-bindgen",
|
"serde-wasm-bindgen",
|
||||||
"thiserror 1.0.63",
|
"thiserror 1.0.69",
|
||||||
"usb_enumeration",
|
"usb_enumeration",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
@@ -2512,16 +2512,25 @@ version = "0.2.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"bytes",
|
"bytes",
|
||||||
"dcv-color-primitives",
|
"flume 0.11.0",
|
||||||
"futures",
|
"futures",
|
||||||
"image 0.25.0",
|
"image 0.25.0",
|
||||||
"mozjpeg",
|
"num-rational 0.4.2",
|
||||||
"opencv 0.93.1",
|
"opencv 0.93.1",
|
||||||
"paste",
|
"paste",
|
||||||
"rgb",
|
"rgb",
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror 2.0.0",
|
"thiserror 2.0.0",
|
||||||
"wgpu 22.0.0",
|
"wgpu 23.0.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nokhwa-decoder"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"dcv-color-primitives",
|
||||||
|
"mozjpeg",
|
||||||
|
"nokhwa-core",
|
||||||
"yuvutils-rs",
|
"yuvutils-rs",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2548,6 +2557,16 @@ dependencies = [
|
|||||||
"minimal-lexical",
|
"minimal-lexical",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-bigint"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
|
||||||
|
dependencies = [
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-integer"
|
name = "num-integer"
|
||||||
version = "0.1.46"
|
version = "0.1.46"
|
||||||
@@ -2580,10 +2599,22 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-rational"
|
||||||
version = "0.2.18"
|
version = "0.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
|
checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
|
||||||
|
dependencies = [
|
||||||
|
"num-bigint",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"libm",
|
"libm",
|
||||||
@@ -2674,9 +2705,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.19.0"
|
version = "1.20.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "opencv"
|
name = "opencv"
|
||||||
@@ -3049,7 +3080,7 @@ checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"getrandom",
|
||||||
"libredox",
|
"libredox",
|
||||||
"thiserror 1.0.63",
|
"thiserror 1.0.69",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3436,11 +3467,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.63"
|
version = "1.0.69"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
|
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl 1.0.63",
|
"thiserror-impl 1.0.69",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3454,9 +3485,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror-impl"
|
name = "thiserror-impl"
|
||||||
version = "1.0.63"
|
version = "1.0.69"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
|
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -3651,9 +3682,9 @@ checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-xid"
|
name = "unicode-xid"
|
||||||
version = "0.2.4"
|
version = "0.2.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "usb_enumeration"
|
name = "usb_enumeration"
|
||||||
@@ -3737,19 +3768,20 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
version = "0.2.92"
|
version = "0.2.95"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
|
checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
|
"once_cell",
|
||||||
"wasm-bindgen-macro",
|
"wasm-bindgen-macro",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-backend"
|
name = "wasm-bindgen-backend"
|
||||||
version = "0.2.92"
|
version = "0.2.95"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
|
checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"log",
|
"log",
|
||||||
@@ -3762,9 +3794,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-futures"
|
name = "wasm-bindgen-futures"
|
||||||
version = "0.4.42"
|
version = "0.4.45"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0"
|
checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
@@ -3774,9 +3806,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro"
|
name = "wasm-bindgen-macro"
|
||||||
version = "0.2.92"
|
version = "0.2.95"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
|
checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"wasm-bindgen-macro-support",
|
"wasm-bindgen-macro-support",
|
||||||
@@ -3784,9 +3816,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro-support"
|
name = "wasm-bindgen-macro-support"
|
||||||
version = "0.2.92"
|
version = "0.2.95"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
|
checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -3797,9 +3829,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-shared"
|
name = "wasm-bindgen-shared"
|
||||||
version = "0.2.92"
|
version = "0.2.95"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
|
checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-rs-async-executor"
|
name = "wasm-rs-async-executor"
|
||||||
@@ -3885,9 +3917,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "web-sys"
|
name = "web-sys"
|
||||||
version = "0.3.69"
|
version = "0.3.72"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef"
|
checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
@@ -3949,16 +3981,16 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wgpu"
|
name = "wgpu"
|
||||||
version = "22.0.0"
|
version = "23.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c87e07e87a179614940ad845397e03201847453a37b43a31a3b54eee2e6e32ce"
|
checksum = "80f70000db37c469ea9d67defdc13024ddf9a5f1b89cb2941b812ad7cde1735a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec 0.7.4",
|
"arrayvec 0.7.4",
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"document-features",
|
"document-features",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"log",
|
"log",
|
||||||
"naga 22.0.0",
|
"naga 23.0.0",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"profiling",
|
"profiling",
|
||||||
"raw-window-handle 0.6.0",
|
"raw-window-handle 0.6.0",
|
||||||
@@ -3967,9 +3999,9 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"wgpu-core 22.0.0",
|
"wgpu-core 23.0.1",
|
||||||
"wgpu-hal 22.0.0",
|
"wgpu-hal 23.0.1",
|
||||||
"wgpu-types 22.0.0",
|
"wgpu-types 23.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3990,7 +4022,7 @@ dependencies = [
|
|||||||
"profiling",
|
"profiling",
|
||||||
"raw-window-handle 0.5.2",
|
"raw-window-handle 0.5.2",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"thiserror 1.0.63",
|
"thiserror 1.0.69",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"wgpu-hal 0.14.1",
|
"wgpu-hal 0.14.1",
|
||||||
"wgpu-types 0.14.1",
|
"wgpu-types 0.14.1",
|
||||||
@@ -4017,7 +4049,7 @@ dependencies = [
|
|||||||
"raw-window-handle 0.6.0",
|
"raw-window-handle 0.6.0",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"thiserror 1.0.63",
|
"thiserror 1.0.69",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"wgpu-hal 0.20.0",
|
"wgpu-hal 0.20.0",
|
||||||
"wgpu-types 0.20.0",
|
"wgpu-types 0.20.0",
|
||||||
@@ -4025,27 +4057,27 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wgpu-core"
|
name = "wgpu-core"
|
||||||
version = "22.0.0"
|
version = "23.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e0f191908a21968991463fcf3b42cb6c9648c0fb7fa301b8fc733bc21a9ed9bd"
|
checksum = "d63c3c478de8e7e01786479919c8769f62a22eec16788d8c2ac77ce2c132778a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec 0.7.4",
|
"arrayvec 0.7.4",
|
||||||
"bit-vec 0.7.0",
|
"bit-vec 0.8.0",
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"document-features",
|
"document-features",
|
||||||
"indexmap 2.2.6",
|
"indexmap 2.2.6",
|
||||||
"log",
|
"log",
|
||||||
"naga 22.0.0",
|
"naga 23.0.0",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"profiling",
|
"profiling",
|
||||||
"raw-window-handle 0.6.0",
|
"raw-window-handle 0.6.0",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"thiserror 1.0.63",
|
"thiserror 1.0.69",
|
||||||
"wgpu-hal 22.0.0",
|
"wgpu-hal 23.0.1",
|
||||||
"wgpu-types 22.0.0",
|
"wgpu-types 23.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4080,7 +4112,7 @@ dependencies = [
|
|||||||
"raw-window-handle 0.5.2",
|
"raw-window-handle 0.5.2",
|
||||||
"renderdoc-sys 0.7.1",
|
"renderdoc-sys 0.7.1",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"thiserror 1.0.63",
|
"thiserror 1.0.69",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"wgpu-types 0.14.1",
|
"wgpu-types 0.14.1",
|
||||||
@@ -4125,7 +4157,7 @@ dependencies = [
|
|||||||
"renderdoc-sys 1.1.0",
|
"renderdoc-sys 1.1.0",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"thiserror 1.0.63",
|
"thiserror 1.0.69",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"wgpu-types 0.20.0",
|
"wgpu-types 0.20.0",
|
||||||
@@ -4134,32 +4166,31 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wgpu-hal"
|
name = "wgpu-hal"
|
||||||
version = "22.0.0"
|
version = "23.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f6bbf4b4de8b2a83c0401d9e5ae0080a2792055f25859a02bf9be97952bbed4f"
|
checksum = "89364b8a0b211adc7b16aeaf1bd5ad4a919c1154b44c9ce27838213ba05fd821"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"android_system_properties",
|
"android_system_properties",
|
||||||
"arrayvec 0.7.4",
|
"arrayvec 0.7.4",
|
||||||
"ash 0.38.0+1.3.281",
|
"ash 0.38.0+1.3.281",
|
||||||
"bit-set 0.6.0",
|
"bit-set 0.8.0",
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"block",
|
"block",
|
||||||
|
"bytemuck",
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"core-graphics-types",
|
"core-graphics-types",
|
||||||
"d3d12 22.0.0",
|
"glow 0.14.2",
|
||||||
"glow 0.13.1",
|
|
||||||
"glutin_wgl_sys 0.6.0",
|
"glutin_wgl_sys 0.6.0",
|
||||||
"gpu-alloc 0.6.0",
|
"gpu-alloc 0.6.0",
|
||||||
"gpu-allocator 0.26.0",
|
"gpu-allocator 0.27.0",
|
||||||
"gpu-descriptor 0.3.0",
|
"gpu-descriptor 0.3.0",
|
||||||
"hassle-rs",
|
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"khronos-egl 6.0.0",
|
"khronos-egl 6.0.0",
|
||||||
"libc",
|
"libc",
|
||||||
"libloading 0.8.3",
|
"libloading 0.8.3",
|
||||||
"log",
|
"log",
|
||||||
"metal 0.29.0",
|
"metal 0.29.0",
|
||||||
"naga 22.0.0",
|
"naga 23.0.0",
|
||||||
"ndk-sys 0.5.0+25.2.9519653",
|
"ndk-sys 0.5.0+25.2.9519653",
|
||||||
"objc",
|
"objc",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
@@ -4170,11 +4201,12 @@ dependencies = [
|
|||||||
"renderdoc-sys 1.1.0",
|
"renderdoc-sys 1.1.0",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"thiserror 1.0.63",
|
"thiserror 1.0.69",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"wgpu-types 22.0.0",
|
"wgpu-types 23.0.0",
|
||||||
"winapi",
|
"windows 0.58.0",
|
||||||
|
"windows-core 0.58.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4199,9 +4231,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wgpu-types"
|
name = "wgpu-types"
|
||||||
version = "22.0.0"
|
version = "23.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bc9d91f0e2c4b51434dfa6db77846f2793149d8e73f800fa2e41f52b8eac3c5d"
|
checksum = "610f6ff27778148c31093f3b03abc4840f9636d58d597ca2f5977433acfe0068"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
@@ -4715,9 +4747,12 @@ checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yuvutils-rs"
|
name = "yuvutils-rs"
|
||||||
version = "0.4.7"
|
version = "0.5.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "97b0c026d402c14683f21eae52b33dd76ba47c548273a7eb526eed5ce2f46b65"
|
checksum = "b30a62ce6c5fbf13dbf8d92e7cd805d74574a7f84d0e81462ca3cb8192be5de2"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@ repository = "https://github.com/l1npengtul/nokhwa"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["nokhwa-bindings-macos", "nokhwa-bindings-windows", "nokhwa-bindings-linux", "nokhwa-core", "examples/*"]
|
members = ["nokhwa-bindings-macos", "nokhwa-bindings-windows", "nokhwa-bindings-linux", "nokhwa-core", "examples/*", "nokhwa-decoder"]
|
||||||
exclude = ["examples/jscam"]
|
exclude = ["examples/jscam"]
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
|
|||||||
@@ -34,14 +34,14 @@ use nokhwa::{
|
|||||||
frame_formats, yuyv422_predicted_size, CameraFormat, CameraIndex, FrameFormat,
|
frame_formats, yuyv422_predicted_size, CameraFormat, CameraIndex, FrameFormat,
|
||||||
RequestedFormat, RequestedFormatType, Resolution,
|
RequestedFormat, RequestedFormatType, Resolution,
|
||||||
},
|
},
|
||||||
Buffer, CallbackCamera, Camera,
|
FrameBuffer, CallbackCamera, Camera,
|
||||||
};
|
};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
struct CaptureState {
|
struct CaptureState {
|
||||||
receiver: Arc<Receiver<Buffer>>,
|
receiver: Arc<Receiver<FrameBuffer>>,
|
||||||
buffer: Vec<u8>,
|
buffer: Vec<u8>,
|
||||||
format: CameraFormat,
|
format: CameraFormat,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use nokhwa_core::buffer::Buffer;
|
use nokhwa_core::frame_buffer::FrameBuffer;
|
||||||
use nokhwa_core::pixel_format::RgbFormat;
|
use nokhwa_core::pixel_format::RgbFormat;
|
||||||
use nokhwa_core::types::{FrameFormat, Resolution};
|
use nokhwa_core::types::{FrameFormat, Resolution};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
@@ -11,7 +11,7 @@ fn main() {
|
|||||||
.read_to_end(&mut nv12)
|
.read_to_end(&mut nv12)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let buffer = Buffer::new(Resolution::new(1920, 1080), &nv12, FrameFormat::NV12);
|
let buffer = FrameBuffer::new(Resolution::new(1920, 1080), &nv12, FrameFormat::NV12);
|
||||||
buffer
|
buffer
|
||||||
.decode_image::<RgbFormat>()
|
.decode_image::<RgbFormat>()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|||||||
@@ -40,7 +40,8 @@
|
|||||||
rustPlatform.bindgenHook
|
rustPlatform.bindgenHook
|
||||||
llvmPackages.libclang.lib
|
llvmPackages.libclang.lib
|
||||||
llvmPackages.clang
|
llvmPackages.clang
|
||||||
v4l-utils.override { withUtils = true; }
|
v4l-utils
|
||||||
|
libv4l
|
||||||
];
|
];
|
||||||
LIBCLANG_PATH = "${pkgs.llvmPackages.libclang.lib}/lib";
|
LIBCLANG_PATH = "${pkgs.llvmPackages.libclang.lib}/lib";
|
||||||
shellHook = ''
|
shellHook = ''
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ use v4l::frameinterval::FrameIntervalEnum;
|
|||||||
use v4l::prelude::MmapStream;
|
use v4l::prelude::MmapStream;
|
||||||
use v4l::video::{Capture as V4lCapture, Output};
|
use v4l::video::{Capture as V4lCapture, Output};
|
||||||
use v4l::video::output::Parameters;
|
use v4l::video::output::Parameters;
|
||||||
use nokhwa_core::buffer::Buffer;
|
use nokhwa_core::frame_buffer::FrameBuffer;
|
||||||
use nokhwa_core::capture::{Capture, Open, Setting, Stream};
|
use nokhwa_core::camera::{Camera, Open, Setting, Capture};
|
||||||
use nokhwa_core::properties::{CameraProperties, CameraPropertyFlag, CameraPropertyId, CameraPropertyValue};
|
use nokhwa_core::properties::{CameraProperties, CameraPropertyFlag, CameraPropertyId, CameraPropertyValue};
|
||||||
use nokhwa_core::{define_back_and_fourth_control, define_back_and_fourth_frame_format};
|
use nokhwa_core::{define_back_and_fourth_control, define_back_and_fourth_frame_format};
|
||||||
use nokhwa_core::error::{NokhwaError, NokhwaResult};
|
use nokhwa_core::error::{NokhwaError, NokhwaResult};
|
||||||
|
|||||||
+9
-16
@@ -14,10 +14,9 @@ repository = "https://github.com/l1npengtul/nokhwa"
|
|||||||
default = []
|
default = []
|
||||||
serialize = ["serde"]
|
serialize = ["serde"]
|
||||||
wgpu-types = ["wgpu"]
|
wgpu-types = ["wgpu"]
|
||||||
opencv-mat = ["opencv"]
|
opencv-mat = ["opencv", "opencv/clang-runtime"]
|
||||||
docs-features = ["serialize", "wgpu-types"]
|
docs-features = ["serialize", "wgpu-types"]
|
||||||
conversions = ["dcv-color-primitives", "yuvutils-rs", "mozjpeg"]
|
async = ["async-trait", "flume/async"]
|
||||||
async = ["async-trait"]
|
|
||||||
test-fail-warnings = []
|
test-fail-warnings = []
|
||||||
|
|
||||||
|
|
||||||
@@ -25,6 +24,12 @@ test-fail-warnings = []
|
|||||||
thiserror = "2.0"
|
thiserror = "2.0"
|
||||||
bytes = "1.3"
|
bytes = "1.3"
|
||||||
paste = "1.0"
|
paste = "1.0"
|
||||||
|
flume = "0.11"
|
||||||
|
|
||||||
|
[dependencies.num-rational]
|
||||||
|
version = "0.4"
|
||||||
|
default-features = false
|
||||||
|
features = ["serde", "std"]
|
||||||
|
|
||||||
[dependencies.image]
|
[dependencies.image]
|
||||||
version = "0.25"
|
version = "0.25"
|
||||||
@@ -36,7 +41,7 @@ features = ["derive"]
|
|||||||
optional = true
|
optional = true
|
||||||
|
|
||||||
[dependencies.wgpu]
|
[dependencies.wgpu]
|
||||||
version = "22"
|
version = "23"
|
||||||
optional = true
|
optional = true
|
||||||
|
|
||||||
[dependencies.opencv]
|
[dependencies.opencv]
|
||||||
@@ -44,22 +49,10 @@ version = "0.93"
|
|||||||
default-features = false
|
default-features = false
|
||||||
optional = true
|
optional = true
|
||||||
|
|
||||||
[dependencies.mozjpeg]
|
|
||||||
version = "0.10"
|
|
||||||
optional = true
|
|
||||||
|
|
||||||
[dependencies.async-trait]
|
[dependencies.async-trait]
|
||||||
version = "0.1"
|
version = "0.1"
|
||||||
optional = true
|
optional = true
|
||||||
|
|
||||||
[dependencies.dcv-color-primitives]
|
|
||||||
version = "0.6"
|
|
||||||
optional = true
|
|
||||||
|
|
||||||
[dependencies.yuvutils-rs]
|
|
||||||
version = "0.4"
|
|
||||||
optional = true
|
|
||||||
|
|
||||||
[dependencies.futures]
|
[dependencies.futures]
|
||||||
version = "0.3"
|
version = "0.3"
|
||||||
optional = true
|
optional = true
|
||||||
|
|||||||
@@ -0,0 +1,132 @@
|
|||||||
|
use crate::error::{NokhwaError, NokhwaResult};
|
||||||
|
use crate::frame_buffer::FrameBuffer;
|
||||||
|
use crate::frame_format::FrameFormat;
|
||||||
|
use crate::properties::{CameraProperties, CameraPropertyId, CameraPropertyValue};
|
||||||
|
use crate::types::{CameraFormat, CameraIndex, FrameRate, Resolution};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use crate::stream::Stream;
|
||||||
|
|
||||||
|
pub trait Open {
|
||||||
|
fn open(index: CameraIndex) -> NokhwaResult<Self> where Self: Sized;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
pub trait AsyncOpen: Sized {
|
||||||
|
async fn open_async(index: CameraIndex) -> NokhwaResult<Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! def_camera_props {
|
||||||
|
( $($property:ident, )* ) => {
|
||||||
|
paste::paste! {
|
||||||
|
$(
|
||||||
|
fn [<$property:snake>] (&self) -> Option<&crate::properties::CameraPropertyDescriptor> {
|
||||||
|
self.properties().[<$property:snake>]()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn [<set_ $property:snake>] (&mut self, value: crate::properties::CameraPropertyValue) -> Result<(), crate::error::NokhwaError> {
|
||||||
|
self.set_property(&crate::properties::CameraPropertyId::$property, value)
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// macro_rules! def_camera_props_async {
|
||||||
|
// ( $($property:ident, )* ) => {
|
||||||
|
// paste::paste! {
|
||||||
|
// $(
|
||||||
|
// async fn [<set_ $property:snake _async>] (&mut self, value: CameraPropertyValue) -> Result<(), NokhwaError> {
|
||||||
|
// self.[<set_ $property:snake >](value)
|
||||||
|
// }
|
||||||
|
// )*
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
|
pub trait Setting {
|
||||||
|
fn enumerate_formats(&self) -> Result<Vec<CameraFormat>, NokhwaError>;
|
||||||
|
|
||||||
|
fn enumerate_resolution_and_frame_rates(
|
||||||
|
&self,
|
||||||
|
frame_format: FrameFormat,
|
||||||
|
) -> Result<HashMap<Resolution, Vec<FrameRate>>, NokhwaError>;
|
||||||
|
|
||||||
|
fn set_format(&self, camera_format: CameraFormat) -> Result<(), NokhwaError>;
|
||||||
|
|
||||||
|
fn properties(&self) -> &CameraProperties;
|
||||||
|
|
||||||
|
fn set_property(
|
||||||
|
&mut self,
|
||||||
|
property: &CameraPropertyId,
|
||||||
|
value: CameraPropertyValue,
|
||||||
|
) -> Result<(), NokhwaError>;
|
||||||
|
|
||||||
|
def_camera_props!(
|
||||||
|
Brightness,
|
||||||
|
Contrast,
|
||||||
|
Hue,
|
||||||
|
Saturation,
|
||||||
|
Sharpness,
|
||||||
|
Gamma,
|
||||||
|
WhiteBalance,
|
||||||
|
BacklightCompensation,
|
||||||
|
Pan,
|
||||||
|
Tilt,
|
||||||
|
Zoom,
|
||||||
|
Exposure,
|
||||||
|
Iris,
|
||||||
|
Focus,
|
||||||
|
Facing,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// #[cfg(feature = "async")]
|
||||||
|
// pub trait AsyncSetting {
|
||||||
|
// async fn set_format_async(&self, camera_format: CameraFormat) -> Result<(), NokhwaError>;
|
||||||
|
//
|
||||||
|
// async fn set_property_async(
|
||||||
|
// &mut self,
|
||||||
|
// property: &CameraPropertyId,
|
||||||
|
// value: CameraPropertyValue,
|
||||||
|
// ) -> Result<(), NokhwaError>;
|
||||||
|
//
|
||||||
|
// def_camera_props_async!(
|
||||||
|
// Brightness,
|
||||||
|
// Contrast,
|
||||||
|
// Hue,
|
||||||
|
// Saturation,
|
||||||
|
// Sharpness,
|
||||||
|
// Gamma,
|
||||||
|
// WhiteBalance,
|
||||||
|
// BacklightCompensation,
|
||||||
|
// Pan,
|
||||||
|
// Tilt,
|
||||||
|
// Zoom,
|
||||||
|
// Exposure,
|
||||||
|
// Iris,
|
||||||
|
// Focus,
|
||||||
|
// Facing,
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
pub trait Capture {
|
||||||
|
fn open_stream(&mut self) -> Result<Stream, NokhwaError>;
|
||||||
|
|
||||||
|
fn close_stream(&mut self) -> Result<(), NokhwaError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
pub trait AsyncStream {
|
||||||
|
async fn open_stream(&mut self) -> Result<(), NokhwaError>;
|
||||||
|
|
||||||
|
async fn await_frame(&mut self) -> Result<FrameBuffer, NokhwaError>;
|
||||||
|
|
||||||
|
async fn close_stream(&mut self) -> Result<(), NokhwaError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait CameraVtable: Setting + Capture {}
|
||||||
|
|
||||||
|
pub trait Camera: Open + CameraVtable {}
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
pub trait AsyncCapture: Camera + AsyncOpen + AsyncStream {}
|
||||||
@@ -1,122 +0,0 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
use crate::buffer::Buffer;
|
|
||||||
use crate::properties::{CameraProperties, CameraPropertyId, CameraPropertyValue};
|
|
||||||
use crate::error::{NokhwaError, NokhwaResult};
|
|
||||||
use crate::frame_format::FrameFormat;
|
|
||||||
use crate::stream::CaptureStream;
|
|
||||||
use crate::types::{CameraFormat, CameraIndex, FrameRate, Resolution};
|
|
||||||
|
|
||||||
pub trait Open {
|
|
||||||
fn open(index: CameraIndex) -> NokhwaResult<Self>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "async")]
|
|
||||||
pub trait AsyncOpen {
|
|
||||||
async fn open_async(index: CameraIndex) -> NokhwaResult<Self>;
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! def_camera_props {
|
|
||||||
( $($property:ident, )* ) => {
|
|
||||||
paste::paste! {
|
|
||||||
$(
|
|
||||||
fn [<$property:snake>] (&self) -> Option<&CameraPropertyDescriptor> {
|
|
||||||
self.properties().[<$property:snake>]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn [<set_ $property:snake>] (&mut self, value: CameraPropertyValue) -> Result<(), NokhwaError> {
|
|
||||||
self.properties().[<set_ $property:snake >](value)
|
|
||||||
}
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! def_camera_props_async {
|
|
||||||
( $($property:ident, )* ) => {
|
|
||||||
paste::paste! {
|
|
||||||
$(
|
|
||||||
async fn [<set_ $property:snake _async>] (&mut self, value: CameraPropertyValue) -> Result<(), NokhwaError> {
|
|
||||||
self.properties().[<set_ $property:snake >](value)
|
|
||||||
}
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Setting {
|
|
||||||
fn enumerate_formats(&self) -> Result<Vec<CameraFormat>, NokhwaError>;
|
|
||||||
|
|
||||||
fn enumerate_resolution_and_frame_rates(&self, frame_format: FrameFormat) -> Result<HashMap<Resolution, Vec<FrameRate>>, NokhwaError>;
|
|
||||||
|
|
||||||
fn set_format(&self, camera_format: CameraFormat) -> Result<(), NokhwaError>;
|
|
||||||
|
|
||||||
fn properties(&self) -> &CameraProperties;
|
|
||||||
|
|
||||||
fn set_property(&mut self, property: &CameraPropertyId, value: CameraPropertyValue) -> Result<(), NokhwaError>;
|
|
||||||
|
|
||||||
def_camera_props!(
|
|
||||||
Brightness,
|
|
||||||
Contrast,
|
|
||||||
Hue,
|
|
||||||
Saturation,
|
|
||||||
Sharpness,
|
|
||||||
Gamma,
|
|
||||||
WhiteBalance,
|
|
||||||
BacklightCompensation,
|
|
||||||
Gain,
|
|
||||||
Pan,
|
|
||||||
Tilt,
|
|
||||||
Zoom,
|
|
||||||
Exposure,
|
|
||||||
Iris,
|
|
||||||
Focus,
|
|
||||||
Facing,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "async")]
|
|
||||||
pub trait AsyncSetting {
|
|
||||||
async fn set_format_async(&self, camera_format: CameraFormat) -> Result<(), NokhwaError>;
|
|
||||||
|
|
||||||
async fn set_property_async(&mut self, property: &CameraPropertyId, value: CameraPropertyValue) -> Result<(), NokhwaError>;
|
|
||||||
|
|
||||||
def_camera_props_async!(
|
|
||||||
Brightness,
|
|
||||||
Contrast,
|
|
||||||
Hue,
|
|
||||||
Saturation,
|
|
||||||
Sharpness,
|
|
||||||
Gamma,
|
|
||||||
WhiteBalance,
|
|
||||||
BacklightCompensation,
|
|
||||||
Gain,
|
|
||||||
Pan,
|
|
||||||
Tilt,
|
|
||||||
Zoom,
|
|
||||||
Exposure,
|
|
||||||
Iris,
|
|
||||||
Focus,
|
|
||||||
Facing,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Stream {
|
|
||||||
fn open_stream(&mut self) -> Result<CaptureStream, NokhwaError>;
|
|
||||||
|
|
||||||
fn close_stream(&mut self) -> Result<(), NokhwaError>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "async")]
|
|
||||||
pub trait AsyncStream {
|
|
||||||
async fn open_stream(&mut self) -> Result<(), NokhwaError>;
|
|
||||||
|
|
||||||
async fn await_frame(&mut self) -> Result<Buffer, NokhwaError>;
|
|
||||||
|
|
||||||
async fn close_stream(&mut self) -> Result<(), NokhwaError>;}
|
|
||||||
|
|
||||||
pub trait Capture: Open + Setting + Stream {}
|
|
||||||
|
|
||||||
#[cfg(feature = "async")]
|
|
||||||
pub trait AsyncCapture: Capture + AsyncOpen + AsyncSetting + AsyncStream {}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
use crate::{error::NokhwaError, frame_buffer::FrameBuffer, frame_format::FrameFormat};
|
||||||
|
use image::{ImageBuffer, Pixel};
|
||||||
|
use std::{
|
||||||
|
error::Error,
|
||||||
|
fmt::{Debug, Display},
|
||||||
|
ops::{ControlFlow, Deref},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Trait to define a struct that can decode a [`FrameBuffer`]
|
||||||
|
pub trait Decoder {
|
||||||
|
/// Formats that the decoder can decode.
|
||||||
|
const ALLOWED_FORMATS: &'static [FrameFormat];
|
||||||
|
/// Output pixel type (e.g. [`Rgb<u8>`](image::Rgb))
|
||||||
|
type OutputPixels: Pixel;
|
||||||
|
|
||||||
|
/// Container type for the decoder. Will be used for ImageBuffer
|
||||||
|
type PixelContainer: Deref<Target = [<<Self as Decoder>::OutputPixels as Pixel>::Subpixel]>;
|
||||||
|
|
||||||
|
fn check_format(buffer: &FrameBuffer) -> ControlFlow<NokhwaError> {
|
||||||
|
if !Self::ALLOWED_FORMATS.contains(&buffer.source_frame_format()) {
|
||||||
|
return ControlFlow::Break(NokhwaError::ConversionError("unsupported".to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decode function.
|
||||||
|
fn decode(
|
||||||
|
&mut self,
|
||||||
|
buffer: &FrameBuffer,
|
||||||
|
) -> Result<ImageBuffer<Self::OutputPixels, Self::PixelContainer>, NokhwaError>;
|
||||||
|
|
||||||
|
/// Decode to user-provided Buffer
|
||||||
|
///
|
||||||
|
/// Incase that the buffer is not large enough this should error.
|
||||||
|
fn decode_buffer(
|
||||||
|
&mut self,
|
||||||
|
buffer: &FrameBuffer,
|
||||||
|
output: &mut [<<Self as Decoder>::OutputPixels as Pixel>::Subpixel],
|
||||||
|
) -> Result<(), NokhwaError>;
|
||||||
|
|
||||||
|
/// Decoder Predicted Size
|
||||||
|
fn predicted_size_of_frame(buffer: &FrameBuffer) -> Option<usize> {
|
||||||
|
if !Self::ALLOWED_FORMATS.contains(&buffer.source_frame_format()) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let res = buffer.resolution();
|
||||||
|
Some(
|
||||||
|
res.x() as usize
|
||||||
|
* res.y() as usize
|
||||||
|
* size_of::<<<Self as Decoder>::OutputPixels as Pixel>::Subpixel>()
|
||||||
|
* <<Self as Decoder>::OutputPixels as Pixel>::CHANNEL_COUNT as usize,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decoder that can be used statically (struct contains no state)
|
||||||
|
///
|
||||||
|
/// This is useful for times that a simple function is all that is required.
|
||||||
|
pub trait StaticDecoder: Decoder {
|
||||||
|
fn decode_static(
|
||||||
|
buffer: &FrameBuffer,
|
||||||
|
) -> Result<ImageBuffer<Self::OutputPixels, Self::PixelContainer>, NokhwaError>;
|
||||||
|
|
||||||
|
fn decode_static_to_buffer(
|
||||||
|
buffer: &FrameBuffer,
|
||||||
|
output: &mut [<<Self as Decoder>::OutputPixels as Pixel>::Subpixel],
|
||||||
|
) -> Result<(), NokhwaError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
#[cfg_attr(feature = "async", async_trait::async_trait)]
|
||||||
|
pub trait AsyncDecoder: Decoder {
|
||||||
|
/// Asynchronous decoder
|
||||||
|
async fn decode_async(
|
||||||
|
&mut self,
|
||||||
|
buffer: &FrameBuffer,
|
||||||
|
) -> Result<ImageBuffer<Self::OutputPixels, Self::PixelContainer>, NokhwaError>;
|
||||||
|
|
||||||
|
/// Asynchronous decoder to user buffer.
|
||||||
|
async fn decode_buffer(
|
||||||
|
&mut self,
|
||||||
|
buffer: &FrameBuffer,
|
||||||
|
output: &mut [<<Self as Decoder>::OutputPixels as Pixel>::Subpixel],
|
||||||
|
) -> Result<(), NokhwaError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
#[cfg_attr(feature = "async", async_trait::async_trait)]
|
||||||
|
pub trait AsyncStaticDecoder: Decoder {
|
||||||
|
/// Asynchronous decoder
|
||||||
|
async fn decode_static_async(
|
||||||
|
buffer: &FrameBuffer,
|
||||||
|
) -> Result<ImageBuffer<Self::OutputPixels, Self::PixelContainer>, NokhwaError>;
|
||||||
|
|
||||||
|
/// Asynchronous decoder to user buffer.
|
||||||
|
async fn decode_static_buffer(
|
||||||
|
&mut self,
|
||||||
|
buffer: &FrameBuffer,
|
||||||
|
output: &mut [<<Self as Decoder>::OutputPixels as Pixel>::Subpixel],
|
||||||
|
) -> Result<(), NokhwaError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// #[cfg(feature = "decoders")]
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
use dcv_color_primitives::PixelFormat;
|
|
||||||
use image::{ExtendedColorType, ImageBuffer, Pixel, PixelWithColorType};
|
|
||||||
use crate::buffer::Buffer;
|
|
||||||
use crate::decoders::Decoder;
|
|
||||||
use crate::error::NokhwaError;
|
|
||||||
use crate::frame_format::FrameFormat;
|
|
||||||
|
|
||||||
pub struct GeneralPurposeDecoder<D> where D: PixelWithColorType;
|
|
||||||
|
|
||||||
impl<D> Decoder for GeneralPurposeDecoder<D> where D: PixelWithColorType {
|
|
||||||
const ALLOWED_FORMATS: &'static [FrameFormat] = &[
|
|
||||||
FrameFormat::MJpeg, FrameFormat::Luma8, FrameFormat::Luma16, FrameFormat::Rgb332, FrameFormat::RgbA8888,
|
|
||||||
FrameFormat::Nv12, FrameFormat::Nv21, FrameFormat::Uyvy422, FrameFormat::Yuy2_422, FrameFormat::Yv12,
|
|
||||||
FrameFormat::Ayuv444, FrameFormat::I420, FrameFormat::I422, FrameFormat::I444
|
|
||||||
];
|
|
||||||
|
|
||||||
type OutputPixels = D;
|
|
||||||
type PixelContainer = Vec<D::Subpixel>;
|
|
||||||
type Error = NokhwaError;
|
|
||||||
|
|
||||||
fn decode(&mut self, buffer: Buffer) -> Result<ImageBuffer<Self::OutputPixels, Self::PixelContainer>, Self::Error> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn decode_buffer(&mut self, buffer: &Buffer, output: &mut [<<Self as Decoder>::OutputPixels as Pixel>::Subpixel]) -> Result<(), Self::Error> {
|
|
||||||
if !Self::ALLOWED_FORMATS.contains(&buffer.source_frame_format()) {
|
|
||||||
return Err(NokhwaError::ConversionError(format!("Invaid frame format {} (allowed formats: {:?})", buffer.source_frame_format(), Self::ALLOWED_FORMATS)))
|
|
||||||
}
|
|
||||||
|
|
||||||
let destination = match D::COLOR_TYPE {
|
|
||||||
ExtendedColorType::Rgb8 => PixelFormat::Rgb,
|
|
||||||
ExtendedColorType::Rgba8 => PixelFormat::Rgba,
|
|
||||||
ExtendedColorType::Bgr8 => PixelFormat::Bgr,
|
|
||||||
ExtendedColorType::Bgra8 => PixelFormat::Bgra,
|
|
||||||
_ => return Err(())
|
|
||||||
};
|
|
||||||
|
|
||||||
// some extra processing needed for some formats
|
|
||||||
|
|
||||||
let source = match buffer.source_frame_format() {
|
|
||||||
FrameFormat::MJpeg => PixelFormat::Rgb, // => JPEG decoder
|
|
||||||
FrameFormat::Yuy2_422 => PixelFormat::I422,
|
|
||||||
FrameFormat::Uyvy422 => PixelFormat::I422,
|
|
||||||
FrameFormat::Ayuv444 => PixelFormat::I444,
|
|
||||||
FrameFormat::Nv12 => PixelFormat::Nv12,
|
|
||||||
FrameFormat::Nv21 => PixelFormat::Nv12,
|
|
||||||
FrameFormat::Yv12 => PixelFormat::I420,
|
|
||||||
FrameFormat::I420 => PixelFormat::I420,
|
|
||||||
// already decoded
|
|
||||||
FrameFormat::Rgb332 => PixelFormat::Rgb,
|
|
||||||
FrameFormat::RgbA8888 => {
|
|
||||||
PixelFormat::Rgb
|
|
||||||
}
|
|
||||||
_ => return Err(()),
|
|
||||||
};
|
|
||||||
|
|
||||||
dcv_color_primitives::convert_image(buffer.resolution().width(), buffer.resolution().height(), )
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
|
|
||||||
use std::ops::Deref;
|
|
||||||
use image::{ExtendedColorType, ImageBuffer, Pixel};
|
|
||||||
use crate::buffer::Buffer;
|
|
||||||
use crate::error::NokhwaError;
|
|
||||||
use crate::frame_format::FrameFormat;
|
|
||||||
|
|
||||||
/// Trait to define a struct that can decode a [`Buffer`]
|
|
||||||
pub trait Decoder {
|
|
||||||
/// Formats that the decoder can decode.
|
|
||||||
const ALLOWED_FORMATS: &'static [FrameFormat];
|
|
||||||
/// Output pixel type (e.g. [`Rgb<u8>`](image::Rgb))
|
|
||||||
type OutputPixels: Pixel;
|
|
||||||
|
|
||||||
type PixelContainer: Deref<Target = [<<Self as Decoder>::OutputPixels as Pixel>::Subpixel]>;
|
|
||||||
/// Error that the decoder will output (use [`NokhwaError`] if you're not sure)
|
|
||||||
type Error;
|
|
||||||
|
|
||||||
/// Decode function.
|
|
||||||
fn decode(&mut self, buffer: &Buffer) -> Result<ImageBuffer<Self::OutputPixels, Self::PixelContainer>, Self::Error>;
|
|
||||||
|
|
||||||
/// Decode to user-provided Buffer
|
|
||||||
///
|
|
||||||
/// Incase that the buffer is not large enough this should error.
|
|
||||||
fn decode_buffer(&mut self, buffer: &Buffer, output: &mut [<<Self as Decoder>::OutputPixels as Pixel>::Subpixel]) -> Result<(), Self::Error>;
|
|
||||||
|
|
||||||
/// Decoder Predicted Size
|
|
||||||
fn predicted_size_of_frame(buffer: &Buffer) -> Option<usize> {
|
|
||||||
if !Self::ALLOWED_FORMATS.contains(&buffer.source_frame_format()) {
|
|
||||||
return None
|
|
||||||
}
|
|
||||||
let res = buffer.resolution();
|
|
||||||
Some(res.x() as usize * res.y() as usize * core::mem::size_of::<<<Self as Decoder>::OutputPixels as Pixel>::Subpixel>() * <<Self as Decoder>::OutputPixels as Pixel>::CHANNEL_COUNT as usize)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Decoder that can be used statically (struct contains no state)
|
|
||||||
///
|
|
||||||
/// This is useful for times that a simple function is all that is required.
|
|
||||||
pub trait StaticDecoder: Decoder {
|
|
||||||
fn decode_static(buffer: &Buffer) -> Result<ImageBuffer<Self::OutputPixels, Self::PixelContainer>, Self::Error>;
|
|
||||||
|
|
||||||
fn decode_static_to_buffer(&mut self, buffer: &Buffer, output: &mut [<<Self as Decoder>::OutputPixels as Pixel>::Subpixel]) -> Result<(), Self::Error>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "async")]
|
|
||||||
#[cfg_attr(feature = "async", async_trait::async_trait)]
|
|
||||||
pub trait AsyncDecoder: Decoder {
|
|
||||||
/// Asynchronous decoder
|
|
||||||
async fn decode_async(&mut self, buffer: &Buffer) -> Result<ImageBuffer<Self::OutputPixels, Self::PixelContainer>, Self::Error>;
|
|
||||||
|
|
||||||
/// Asynchronous decoder to user buffer.
|
|
||||||
async fn decode_buffer(&mut self, buffer: &Buffer, output: &mut [<<Self as Decoder>::OutputPixels as Pixel>::Subpixel]) -> Result<(), Self::Error>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "async")]
|
|
||||||
#[cfg_attr(feature = "async", async_trait::async_trait)]
|
|
||||||
pub trait AsyncStaticDecoder: Decoder {
|
|
||||||
/// Asynchronous decoder
|
|
||||||
async fn decode_static_async(buffer: &Buffer) -> Result<ImageBuffer<Self::OutputPixels, Self::PixelContainer>, Self::Error>;
|
|
||||||
|
|
||||||
/// Asynchronous decoder to user buffer.
|
|
||||||
async fn decode_static_buffer(&mut self, buffer: &Buffer, output: &mut [<<Self as Decoder>::OutputPixels as Pixel>::Subpixel]) -> Result<(), Self::Error>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "conversions")]
|
|
||||||
pub mod general;
|
|
||||||
@@ -13,8 +13,8 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use crate::{frame_format::FrameFormat, types::ApiBackend};
|
use crate::{frame_format::FrameFormat, types::ApiBackend};
|
||||||
|
use std::fmt::{Debug};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
pub type NokhwaResult<T> = Result<T, NokhwaError>;
|
pub type NokhwaResult<T> = Result<T, NokhwaError>;
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
use std::{
|
use crate::utils::Distance;
|
||||||
cmp::Ordering,
|
|
||||||
collections::VecDeque
|
|
||||||
};
|
|
||||||
use crate::{
|
use crate::{
|
||||||
frame_format::FrameFormat,
|
frame_format::FrameFormat,
|
||||||
traits::Distance,
|
ranges::Range,
|
||||||
types::{CameraFormat, FrameRate, Resolution}
|
types::{CameraFormat, FrameRate, Resolution},
|
||||||
};
|
};
|
||||||
use crate::ranges::Range;
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)]
|
||||||
enum ClosestType {
|
enum ClosestType {
|
||||||
@@ -25,7 +22,12 @@ pub enum CustomFormatRequestType {
|
|||||||
Exact,
|
Exact,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A helper for choosing a [`CameraFormat`].
|
||||||
|
/// The use of this is completely optional - for a simpler way try [`crate::camera::Camera::enumerate_formats`].
|
||||||
|
///
|
||||||
|
/// The `frame_format` field filters out the [`CameraFormat`]s by [`FrameFormat`].
|
||||||
pub enum FormatRequest {
|
pub enum FormatRequest {
|
||||||
|
/// Pick the closest [`CameraFormat`] to the one requested
|
||||||
Closest {
|
Closest {
|
||||||
resolution: Option<Range<Resolution>>,
|
resolution: Option<Range<Resolution>>,
|
||||||
frame_rate: Option<Range<FrameRate>>,
|
frame_rate: Option<Range<FrameRate>>,
|
||||||
@@ -47,51 +49,88 @@ pub enum FormatRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FormatRequest {
|
impl FormatRequest {
|
||||||
|
pub fn sort_formats(&self, list_of_formats: &[CameraFormat]) -> Vec<CameraFormat> {
|
||||||
|
if list_of_formats.is_empty() {
|
||||||
|
return vec![];
|
||||||
|
}
|
||||||
|
|
||||||
|
match self {
|
||||||
|
FormatRequest::Closest {
|
||||||
|
resolution,
|
||||||
|
frame_rate,
|
||||||
|
frame_format,
|
||||||
|
} => {
|
||||||
|
let resolution_point = resolution.map(|x| x.preferred())?;
|
||||||
|
|
||||||
|
let frame_rate_point = frame_rate.map(|x| x.preferred())?;
|
||||||
|
// lets calcuate distance in 3 dimensions (add both resolution and frame_rate together)
|
||||||
|
|
||||||
|
let mut distances: Vec<(f32, CameraFormat)> = list_of_formats
|
||||||
|
.iter()
|
||||||
|
.filter(|x| frame_format.contains(&x.format()))
|
||||||
|
.map(|fmt| {
|
||||||
|
(
|
||||||
|
(fmt.frame_rate() - frame_rate_point).abs()
|
||||||
|
+ fmt.resolution().distance_from(&resolution_point) as f32,
|
||||||
|
fmt,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
distances.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(Ordering::Equal));
|
||||||
|
distances.into_iter().map(|x| x.1).collect()
|
||||||
|
}
|
||||||
|
FormatRequest::HighestFrameRate {
|
||||||
|
frame_rate,
|
||||||
|
frame_format,
|
||||||
|
} => {
|
||||||
|
let mut formats = list_of_formats
|
||||||
|
.iter()
|
||||||
|
.filter(|x| {
|
||||||
|
frame_format.contains(&x.format()) && frame_rate.in_range(x.frame_rate())
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
formats.sort();
|
||||||
|
formats.into_iter().copied().collect()
|
||||||
|
}
|
||||||
|
FormatRequest::HighestResolution {
|
||||||
|
resolution,
|
||||||
|
frame_format,
|
||||||
|
} => {
|
||||||
|
let mut formats = list_of_formats
|
||||||
|
.iter()
|
||||||
|
.filter(|x| {
|
||||||
|
frame_format.contains(&x.format()) && resolution.in_range(x.resolution())
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
formats.sort();
|
||||||
|
formats.into_iter().copied().collect()
|
||||||
|
}
|
||||||
|
FormatRequest::Exact {
|
||||||
|
resolution,
|
||||||
|
frame_rate,
|
||||||
|
frame_format,
|
||||||
|
} => {
|
||||||
|
let mut formats = list_of_formats
|
||||||
|
.iter()
|
||||||
|
.filter(|x| {
|
||||||
|
frame_format.contains(&x.format())
|
||||||
|
&& resolution == &x.resolution()
|
||||||
|
&& frame_rate == &x.frame_rate()
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
formats.sort();
|
||||||
|
formats.into_iter().copied().collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn resolve(&self, list_of_formats: &[CameraFormat]) -> Option<CameraFormat> {
|
pub fn resolve(&self, list_of_formats: &[CameraFormat]) -> Option<CameraFormat> {
|
||||||
if list_of_formats.is_empty() {
|
if list_of_formats.is_empty() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
match self {
|
Some(self.sort_formats(list_of_formats).remove(0))
|
||||||
FormatRequest::Closest { resolution, frame_rate, frame_format } => {
|
|
||||||
let resolution_point = resolution.map(|x| x.preferred())?;
|
|
||||||
|
|
||||||
let frame_rate_point = frame_rate.map(|x| x.preferred())?;
|
|
||||||
// lets calcuate distance in 3 dimensions (add both resolution and frame_rate together)
|
|
||||||
|
|
||||||
let mut distances = list_of_formats.iter()
|
|
||||||
.filter(|x| {
|
|
||||||
frame_format.contains(&x.format())
|
|
||||||
})
|
|
||||||
.map(|fmt| {
|
|
||||||
((fmt.frame_rate() - frame_rate_point).abs() + fmt.resolution().distance_from(&resolution_point) as f32, fmt)
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
distances.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(Ordering::Equal));
|
|
||||||
VecDeque::from(distances).pop_front().map(|x| x.1).copied()
|
|
||||||
}
|
|
||||||
FormatRequest::HighestFrameRate { frame_rate, frame_format } => {
|
|
||||||
let mut formats = list_of_formats.iter().filter(|x| {
|
|
||||||
frame_format.contains(&x.format()) && frame_rate.in_range(x.frame_rate())
|
|
||||||
}).collect::<Vec<_>>();
|
|
||||||
formats.sort();
|
|
||||||
formats.first().copied().copied()
|
|
||||||
}
|
|
||||||
FormatRequest::HighestResolution { resolution, frame_format } => {
|
|
||||||
let mut formats = list_of_formats.iter().filter(|x| {
|
|
||||||
frame_format.contains(&x.format()) && resolution.in_range(x.resolution())
|
|
||||||
}).collect::<Vec<_>>();
|
|
||||||
formats.sort();
|
|
||||||
formats.first().copied().copied()
|
|
||||||
}
|
|
||||||
FormatRequest::Exact { resolution, frame_rate, frame_format } => {
|
|
||||||
let mut formats = list_of_formats.iter().filter(|x| {
|
|
||||||
frame_format.contains(&x.format()) && resolution == &x.resolution() && frame_rate == &x.frame_rate()
|
|
||||||
}).collect::<Vec<_>>();
|
|
||||||
formats.sort();
|
|
||||||
formats.first().copied().copied()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,22 +14,22 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use crate::frame_format::FrameFormat;
|
||||||
use crate::types::Resolution;
|
use crate::types::Resolution;
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use crate::frame_format::FrameFormat;
|
|
||||||
|
|
||||||
/// A buffer returned by a camera to accommodate custom decoding.
|
/// A buffer returned by a camera to accommodate custom decoding.
|
||||||
/// Contains information of Resolution, the buffer's [`FrameFormat`], and the buffer.
|
/// Contains information of Resolution, the buffer's [`FrameFormat`], and the buffer.
|
||||||
///
|
///
|
||||||
/// Note that decoding on the main thread **will** decrease your performance and lead to dropped frames.
|
/// Note that decoding on the main thread **will** decrease your performance and lead to dropped frames.
|
||||||
#[derive(Clone, Debug, Hash, PartialOrd, PartialEq, Eq)]
|
#[derive(Clone, Debug, Hash, PartialOrd, PartialEq, Eq)]
|
||||||
pub struct Buffer {
|
pub struct FrameBuffer {
|
||||||
resolution: Resolution,
|
resolution: Resolution,
|
||||||
buffer: Bytes,
|
buffer: Bytes,
|
||||||
source_frame_format: FrameFormat,
|
source_frame_format: FrameFormat,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Buffer {
|
impl FrameBuffer {
|
||||||
/// Creates a new buffer with a [`&[u8]`].
|
/// Creates a new buffer with a [`&[u8]`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -53,7 +53,7 @@ impl Buffer {
|
|||||||
&self.buffer
|
&self.buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get an owned version of this buffer. Note: This is the equivalent
|
/// Get an owned version of this buffer. Note: This is the equivalent
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn buffer_bytes(&self) -> Bytes {
|
pub fn buffer_bytes(&self) -> Bytes {
|
||||||
self.buffer.clone()
|
self.buffer.clone()
|
||||||
@@ -16,8 +16,6 @@
|
|||||||
|
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
|
|
||||||
use crate::types::ApiBackend;
|
|
||||||
|
|
||||||
/// Describes a frame format (i.e. how the bytes themselves are encoded). Often called `FourCC`.
|
/// Describes a frame format (i.e. how the bytes themselves are encoded). Often called `FourCC`.
|
||||||
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
||||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||||
@@ -40,7 +38,6 @@ pub enum FrameFormat {
|
|||||||
// YCbCr Formats
|
// YCbCr Formats
|
||||||
|
|
||||||
// 8 bit per pixel, 4:4:4
|
// 8 bit per pixel, 4:4:4
|
||||||
|
|
||||||
Ayuv444,
|
Ayuv444,
|
||||||
|
|
||||||
// -> 4:2:2
|
// -> 4:2:2
|
||||||
@@ -49,14 +46,12 @@ pub enum FrameFormat {
|
|||||||
Yvyu422,
|
Yvyu422,
|
||||||
Yv12,
|
Yv12,
|
||||||
|
|
||||||
|
|
||||||
// 4:2:0
|
// 4:2:0
|
||||||
Nv12,
|
Nv12,
|
||||||
Nv21,
|
Nv21,
|
||||||
I420,
|
I420,
|
||||||
|
|
||||||
// 16:1:1
|
// 16:1:1
|
||||||
|
|
||||||
Yvu9,
|
Yvu9,
|
||||||
|
|
||||||
// Grayscale Formats
|
// Grayscale Formats
|
||||||
@@ -70,7 +65,7 @@ pub enum FrameFormat {
|
|||||||
Rgb332,
|
Rgb332,
|
||||||
Rgb555,
|
Rgb555,
|
||||||
Rgb565,
|
Rgb565,
|
||||||
|
|
||||||
Rgb888,
|
Rgb888,
|
||||||
|
|
||||||
RgbA8888,
|
RgbA8888,
|
||||||
@@ -136,7 +131,7 @@ impl FrameFormat {
|
|||||||
pub const LUMA: &'static [FrameFormat] = &[FrameFormat::Luma8, FrameFormat::Luma16];
|
pub const LUMA: &'static [FrameFormat] = &[FrameFormat::Luma8, FrameFormat::Luma16];
|
||||||
|
|
||||||
pub const RGB: &'static [FrameFormat] = &[FrameFormat::Rgb332, FrameFormat::RgbA8888];
|
pub const RGB: &'static [FrameFormat] = &[FrameFormat::Rgb332, FrameFormat::RgbA8888];
|
||||||
|
|
||||||
pub const COLOR_FORMATS: &'static [FrameFormat] = &[
|
pub const COLOR_FORMATS: &'static [FrameFormat] = &[
|
||||||
FrameFormat::H265,
|
FrameFormat::H265,
|
||||||
FrameFormat::H264,
|
FrameFormat::H264,
|
||||||
@@ -158,7 +153,7 @@ impl FrameFormat {
|
|||||||
FrameFormat::Rgb332,
|
FrameFormat::Rgb332,
|
||||||
FrameFormat::RgbA8888,
|
FrameFormat::RgbA8888,
|
||||||
];
|
];
|
||||||
|
|
||||||
pub const GRAYSCALE: &'static [FrameFormat] = &[FrameFormat::Luma8, FrameFormat::Luma16];
|
pub const GRAYSCALE: &'static [FrameFormat] = &[FrameFormat::Luma8, FrameFormat::Luma16];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,7 +167,7 @@ impl Display for FrameFormat {
|
|||||||
macro_rules! define_back_and_fourth_frame_format {
|
macro_rules! define_back_and_fourth_frame_format {
|
||||||
($fourcc_type:ty, { $( $frame_format:expr => $value:literal, )* }, $func_u8_8_to_fcc:expr, $func_fcc_to_u8_8:expr, $value_to_fcc_type:expr) => {
|
($fourcc_type:ty, { $( $frame_format:expr => $value:literal, )* }, $func_u8_8_to_fcc:expr, $func_fcc_to_u8_8:expr, $value_to_fcc_type:expr) => {
|
||||||
pub struct FrameFormatIntermediate(pub $fourcc_type);
|
pub struct FrameFormatIntermediate(pub $fourcc_type);
|
||||||
|
|
||||||
impl FrameFormatIntermediate {
|
impl FrameFormatIntermediate {
|
||||||
pub fn from_frame_format(frame_format: FrameFormat) -> Option<Self> {
|
pub fn from_frame_format(frame_format: FrameFormat) -> Option<Self> {
|
||||||
match frame_format {
|
match frame_format {
|
||||||
@@ -183,7 +178,7 @@ macro_rules! define_back_and_fourth_frame_format {
|
|||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_frame_format(fourcc: $fourcc_type) -> FrameFormat {
|
pub fn into_frame_format(fourcc: $fourcc_type) -> FrameFormat {
|
||||||
match fourcc.0 {
|
match fourcc.0 {
|
||||||
$(
|
$(
|
||||||
|
|||||||
@@ -22,18 +22,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
//! Core type definitions for `nokhwa`
|
//! Core type definitions for `nokhwa`
|
||||||
pub mod buffer;
|
pub mod camera;
|
||||||
|
pub mod decoder;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod format_request;
|
pub mod format_request;
|
||||||
|
pub mod frame_buffer;
|
||||||
pub mod frame_format;
|
pub mod frame_format;
|
||||||
|
pub mod properties;
|
||||||
|
pub mod query;
|
||||||
|
pub mod ranges;
|
||||||
pub mod traits;
|
pub mod traits;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
pub mod decoders;
|
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
pub mod ranges;
|
|
||||||
pub mod properties;
|
|
||||||
pub mod capture;
|
|
||||||
pub mod query;
|
|
||||||
|
|
||||||
#[cfg(feature = "async")]
|
|
||||||
pub mod stream;
|
pub mod stream;
|
||||||
|
|||||||
+183
-187
@@ -1,11 +1,11 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use std::{
|
|
||||||
fmt::{Display, Formatter},
|
|
||||||
collections::{HashMap, HashSet}
|
|
||||||
};
|
|
||||||
use std::cmp::Ordering;
|
|
||||||
use crate::error::NokhwaError;
|
use crate::error::NokhwaError;
|
||||||
use crate::ranges::{ArrayRange, IndicatedRange, KeyValue, Options, RangeValidationFailure, Simple, ValidatableRange};
|
use crate::ranges::{ArrayRange, KeyValue, Options, Range, RangeValidationFailure, Simple, ValidatableRange};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
use std::{
|
||||||
|
collections::{HashMap, HashSet},
|
||||||
|
fmt::{Display, Formatter},
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
||||||
pub struct ControlValidationFailure;
|
pub struct ControlValidationFailure;
|
||||||
@@ -34,12 +34,18 @@ pub enum CameraPropertyId {
|
|||||||
Iris,
|
Iris,
|
||||||
Focus,
|
Focus,
|
||||||
Facing,
|
Facing,
|
||||||
Custom(String)
|
Custom(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for CameraPropertyId {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{self:?}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Replace Controls API with Properties. (this one)
|
// TODO: Replace Controls API with Properties. (this one)
|
||||||
/// Properties of a Camera.
|
/// Properties of a Camera.
|
||||||
///
|
///
|
||||||
/// If the property is not supported, it is `None`.
|
/// If the property is not supported, it is `None`.
|
||||||
/// Custom or platform-specific properties go into `other`
|
/// Custom or platform-specific properties go into `other`
|
||||||
pub struct CameraProperties {
|
pub struct CameraProperties {
|
||||||
@@ -54,9 +60,9 @@ macro_rules! def_camera_props {
|
|||||||
pub fn [<$property:snake>] (&self) -> Option<&CameraPropertyDescriptor> {
|
pub fn [<$property:snake>] (&self) -> Option<&CameraPropertyDescriptor> {
|
||||||
self.props.get(&CameraPropertyId::$property)
|
self.props.get(&CameraPropertyId::$property)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn [<set_ $property:snake>] (&mut self, value: CameraPropertyValue) -> Result<(), NokhwaError> {
|
pub fn [<set_ $property:snake>] (&mut self, value: CameraPropertyValue) -> Result<(), NokhwaError> {
|
||||||
self.props.set_property(&CameraPropertyId::$property, value)
|
self.set_property(&CameraPropertyId::$property, value)
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
@@ -80,27 +86,29 @@ def_camera_props!(
|
|||||||
Exposure,
|
Exposure,
|
||||||
Iris,
|
Iris,
|
||||||
Focus,
|
Focus,
|
||||||
Facing,
|
Facing,
|
||||||
);
|
);
|
||||||
|
|
||||||
impl CameraProperties {
|
impl CameraProperties {
|
||||||
pub fn property(&self, property: &CameraPropertyId) -> Option<&CameraPropertyDescriptor> {
|
pub fn property(&self, property: &CameraPropertyId) -> Option<&CameraPropertyDescriptor> {
|
||||||
self.props.get(property)
|
self.props.get(property)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_property(&mut self, property: &CameraPropertyId, value: CameraPropertyValue) -> Result<(), NokhwaError> {
|
pub fn set_property(
|
||||||
|
&mut self,
|
||||||
|
property: &CameraPropertyId,
|
||||||
|
value: CameraPropertyValue,
|
||||||
|
) -> Result<(), NokhwaError> {
|
||||||
match self.props.get_mut(property) {
|
match self.props.get_mut(property) {
|
||||||
Some(prop) => {
|
Some(prop) => {
|
||||||
prop.set_value(value)?;
|
prop.set_value(value)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
None => {
|
None => Err(NokhwaError::SetPropertyError {
|
||||||
Err(NokhwaError::SetPropertyError {
|
property: property.to_string(),
|
||||||
property: property.to_string(),
|
value: value.to_string(),
|
||||||
value: value.to_string(),
|
error: String::from("Is null."),
|
||||||
error: String::from("Is null."),
|
}),
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -116,10 +124,20 @@ pub struct CameraPropertyDescriptor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CameraPropertyDescriptor {
|
impl CameraPropertyDescriptor {
|
||||||
pub fn new(flags: &[CameraPropertyFlag], mode: CameraPropertyMode, range: CameraPropertyRange, value: CameraPropertyValue, value_type: CameraPropertyValueType) -> Result<Self, NokhwaError> {
|
pub fn new(
|
||||||
|
flags: &[CameraPropertyFlag],
|
||||||
if flags.contains(&CameraPropertyFlag::ReadOnly) && flags.contains(&CameraPropertyFlag::WriteOnly) {
|
mode: CameraPropertyMode,
|
||||||
return Err(NokhwaError::StructureError { structure: "CameraPropertyDescriptor".to_string(), error: "conflicting flags".to_string() })
|
range: CameraPropertyRange,
|
||||||
|
value: CameraPropertyValue,
|
||||||
|
value_type: CameraPropertyValueType,
|
||||||
|
) -> Result<Self, NokhwaError> {
|
||||||
|
if flags.contains(&CameraPropertyFlag::ReadOnly)
|
||||||
|
&& flags.contains(&CameraPropertyFlag::WriteOnly)
|
||||||
|
{
|
||||||
|
return Err(NokhwaError::StructureError {
|
||||||
|
structure: "CameraPropertyDescriptor".to_string(),
|
||||||
|
error: "conflicting flags".to_string(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(CameraPropertyDescriptor {
|
Ok(CameraPropertyDescriptor {
|
||||||
@@ -130,18 +148,21 @@ impl CameraPropertyDescriptor {
|
|||||||
value_type,
|
value_type,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_read_only(&self) -> bool {
|
pub fn is_read_only(&self) -> bool {
|
||||||
self.flags.contains(&CameraPropertyFlag::ReadOnly)
|
self.flags.contains(&CameraPropertyFlag::ReadOnly)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_write_only(&self) -> bool {
|
pub fn is_write_only(&self) -> bool {
|
||||||
self.flags.contains(&CameraPropertyFlag::WriteOnly)
|
self.flags.contains(&CameraPropertyFlag::WriteOnly)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_disabled(&self) -> Result<(), NokhwaError> {
|
pub fn is_disabled(&self) -> Result<(), NokhwaError> {
|
||||||
if self.flags.contains(&CameraPropertyFlag::Disabled) {
|
if self.flags.contains(&CameraPropertyFlag::Disabled) {
|
||||||
return Err(NokhwaError::StructureError { structure: "CameraPropertyDescriptor".to_string(), error: "Disabled".to_string() })
|
return Err(NokhwaError::StructureError {
|
||||||
|
structure: "CameraPropertyDescriptor".to_string(),
|
||||||
|
error: "Disabled".to_string(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -168,11 +189,13 @@ impl CameraPropertyDescriptor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_value(&mut self, value: CameraPropertyValue) -> Result<(), NokhwaError> {
|
pub fn set_value(&mut self, value: CameraPropertyValue) -> Result<(), NokhwaError> {
|
||||||
self.range.check_value(&value).map_err(|_| NokhwaError::SetPropertyError {
|
self.range
|
||||||
property: "CameraPropertyValue".to_string(),
|
.check_value(&value)
|
||||||
value: value.to_string(),
|
.map_err(|_| NokhwaError::SetPropertyError {
|
||||||
error: "Bad Type".to_string(),
|
property: "CameraPropertyValue".to_string(),
|
||||||
})?;
|
value: value.to_string(),
|
||||||
|
error: "Bad Type".to_string(),
|
||||||
|
})?;
|
||||||
self.value = value;
|
self.value = value;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -239,18 +262,27 @@ impl Display for CameraPropertyFlag {
|
|||||||
pub enum CameraPropertyRange {
|
pub enum CameraPropertyRange {
|
||||||
Null,
|
Null,
|
||||||
Boolean(Simple<bool>),
|
Boolean(Simple<bool>),
|
||||||
Integer(IndicatedRange<i64>),
|
Integer(Range<i64>),
|
||||||
LongInteger(IndicatedRange<i128>),
|
LongInteger(Range<i128>),
|
||||||
Float(IndicatedRange<f32>),
|
Float(Range<f32>),
|
||||||
Double(IndicatedRange<f64>),
|
Double(Range<f64>),
|
||||||
String(Simple<String>),
|
String(Simple<String>),
|
||||||
Array(ArrayRange<Vec<CameraPropertyValue>>),
|
Array(ArrayRange<Vec<CameraPropertyValue>>),
|
||||||
Enumeration(Options<CameraPropertyValue>),
|
Enumeration(Options<CameraPropertyValue>),
|
||||||
Binary(Simple<Vec<u8>>),
|
Binary(Simple<Vec<u8>>),
|
||||||
Pair(IndicatedRange<f32>, IndicatedRange<f32>),
|
Pair(Range<f32>, Range<f32>),
|
||||||
Triple(IndicatedRange<f32>, IndicatedRange<f32>, IndicatedRange<f32>),
|
Triple(
|
||||||
Quadruple(IndicatedRange<f32>, IndicatedRange<f32>, IndicatedRange<f32>, IndicatedRange<f32>),
|
Range<f32>,
|
||||||
KeyValuePair(KeyValue<String, CameraPropertyValue>)
|
Range<f32>,
|
||||||
|
Range<f32>,
|
||||||
|
),
|
||||||
|
Quadruple(
|
||||||
|
Range<f32>,
|
||||||
|
Range<f32>,
|
||||||
|
Range<f32>,
|
||||||
|
Range<f32>,
|
||||||
|
),
|
||||||
|
KeyValuePair(KeyValue<String, CameraPropertyValue>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CameraPropertyRange {
|
impl CameraPropertyRange {
|
||||||
@@ -258,7 +290,7 @@ impl CameraPropertyRange {
|
|||||||
match self {
|
match self {
|
||||||
CameraPropertyRange::Null => {
|
CameraPropertyRange::Null => {
|
||||||
if let CameraPropertyValue::Null = value {
|
if let CameraPropertyValue::Null = value {
|
||||||
return Ok(())
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CameraPropertyRange::Boolean(chk_b) => {
|
CameraPropertyRange::Boolean(chk_b) => {
|
||||||
@@ -331,7 +363,7 @@ impl CameraPropertyRange {
|
|||||||
if let CameraPropertyValue::KeyValue(st, va) = value {
|
if let CameraPropertyValue::KeyValue(st, va) = value {
|
||||||
if let Some(vk) = kv.by_key(st) {
|
if let Some(vk) = kv.by_key(st) {
|
||||||
if vk.is_same_type(va) {
|
if vk.is_same_type(va) {
|
||||||
return Ok(())
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -361,7 +393,7 @@ pub enum CameraPropertyValue {
|
|||||||
Pair(f32, f32),
|
Pair(f32, f32),
|
||||||
Triple(f32, f32, f32),
|
Triple(f32, f32, f32),
|
||||||
Quadruple(f32, f32, f32, f32),
|
Quadruple(f32, f32, f32, f32),
|
||||||
KeyValue(String, Box<CameraPropertyValue>)
|
KeyValue(String, Box<CameraPropertyValue>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CameraPropertyValue {
|
impl CameraPropertyValue {
|
||||||
@@ -441,22 +473,22 @@ impl PartialEq for CameraPropertyValue {
|
|||||||
}
|
}
|
||||||
CameraPropertyValue::Pair(a, b) => {
|
CameraPropertyValue::Pair(a, b) => {
|
||||||
if let CameraPropertyValue::Pair(oa, ob) = other {
|
if let CameraPropertyValue::Pair(oa, ob) = other {
|
||||||
return (a == oa) && (b == ob)
|
return (a == oa) && (b == ob);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CameraPropertyValue::Triple(x, y, z) => {
|
CameraPropertyValue::Triple(x, y, z) => {
|
||||||
if let CameraPropertyValue::Triple(ox, oy, oz) = other {
|
if let CameraPropertyValue::Triple(ox, oy, oz) = other {
|
||||||
return (x == ox) && (y == oy) && (z == oz)
|
return (x == ox) && (y == oy) && (z == oz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CameraPropertyValue::Quadruple(x, y, z, w) => {
|
CameraPropertyValue::Quadruple(x, y, z, w) => {
|
||||||
if let CameraPropertyValue::Quadruple(ox, oy, oz, ow) = other {
|
if let CameraPropertyValue::Quadruple(ox, oy, oz, ow) = other {
|
||||||
return (x == ox) && (y == oy) && (z == oz) && (w == ow)
|
return (x == ox) && (y == oy) && (z == oz) && (w == ow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CameraPropertyValue::KeyValue(k, v) => {
|
CameraPropertyValue::KeyValue(k, v) => {
|
||||||
if let CameraPropertyValue::KeyValue(ok, ov ) = other {
|
if let CameraPropertyValue::KeyValue(ok, ov) = other {
|
||||||
return (k == ok) && (v == ov)
|
return (k == ok) && (v == ov);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@@ -468,145 +500,109 @@ impl PartialEq for CameraPropertyValue {
|
|||||||
impl PartialOrd for CameraPropertyValue {
|
impl PartialOrd for CameraPropertyValue {
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
match self {
|
match self {
|
||||||
CameraPropertyValue::Null => {
|
CameraPropertyValue::Null => match other {
|
||||||
match other {
|
CameraPropertyValue::Null => Some(Ordering::Greater),
|
||||||
CameraPropertyValue::Null => Some(Ordering::Greater),
|
_ => Some(Ordering::Less),
|
||||||
_ => Some(Ordering::Less)
|
},
|
||||||
|
CameraPropertyValue::Boolean(b) => match other {
|
||||||
|
CameraPropertyValue::Null => Some(Ordering::Greater),
|
||||||
|
CameraPropertyValue::Boolean(o) => {
|
||||||
|
if o == b {
|
||||||
|
Some(Ordering::Equal)
|
||||||
|
} else if o {
|
||||||
|
Some(Ordering::Less)
|
||||||
|
} else {
|
||||||
|
Some(Ordering::Greater)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
_ => Some(Ordering::Less),
|
||||||
CameraPropertyValue::Boolean(b) => {
|
},
|
||||||
match other {
|
CameraPropertyValue::Integer(int) => match other {
|
||||||
CameraPropertyValue::Null => Some(Ordering::Greater),
|
CameraPropertyValue::Null | CameraPropertyValue::Boolean(_) => {
|
||||||
CameraPropertyValue::Boolean(o) => {
|
Some(Ordering::Greater)
|
||||||
if o == b {
|
|
||||||
Some(Ordering::Equal)
|
|
||||||
} else if o {
|
|
||||||
Some(Ordering::Less)
|
|
||||||
} else {
|
|
||||||
Some(Ordering::Greater)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => Some(Ordering::Less)
|
|
||||||
}
|
}
|
||||||
}
|
CameraPropertyValue::Integer(oth) => Some(int.cmp(oth)),
|
||||||
CameraPropertyValue::Integer(int) => {
|
CameraPropertyValue::LongInteger(li) => {
|
||||||
match other {
|
let long = match i64::try_from(li) {
|
||||||
CameraPropertyValue::Null | CameraPropertyValue::Boolean(_) => Some(Ordering::Greater),
|
Ok(v) => v,
|
||||||
CameraPropertyValue::Integer(oth) => {
|
Err(_) => return None,
|
||||||
Some(int.cmp(oth))
|
};
|
||||||
}
|
Some(int.cmp(&long))
|
||||||
CameraPropertyValue::LongInteger(li) => {
|
|
||||||
let long = match i64::try_from(li) {
|
|
||||||
Ok(v) => v,
|
|
||||||
Err(_) => return None,
|
|
||||||
};
|
|
||||||
Some(int.cmp(&long))
|
|
||||||
}
|
|
||||||
_ => Some(Ordering::Less),
|
|
||||||
}
|
}
|
||||||
}
|
_ => Some(Ordering::Less),
|
||||||
CameraPropertyValue::LongInteger(long) => {
|
},
|
||||||
match other {
|
CameraPropertyValue::LongInteger(long) => match other {
|
||||||
CameraPropertyValue::Null | CameraPropertyValue::Boolean(_) => Some(Ordering::Greater),
|
CameraPropertyValue::Null | CameraPropertyValue::Boolean(_) => {
|
||||||
CameraPropertyValue::Integer(oth) => {
|
Some(Ordering::Greater)
|
||||||
Some(long.cmp(&(i128::from(oth))))
|
|
||||||
}
|
|
||||||
CameraPropertyValue::LongInteger(o) => {
|
|
||||||
Some(long.cmp(o))
|
|
||||||
}
|
|
||||||
_ => Some(Ordering::Less),
|
|
||||||
}
|
}
|
||||||
}
|
CameraPropertyValue::Integer(oth) => Some(long.cmp(&(i128::from(oth)))),
|
||||||
CameraPropertyValue::Float(fl) => {
|
CameraPropertyValue::LongInteger(o) => Some(long.cmp(o)),
|
||||||
match other {
|
_ => Some(Ordering::Less),
|
||||||
CameraPropertyValue::Null |
|
},
|
||||||
CameraPropertyValue::Boolean(_) |
|
CameraPropertyValue::Float(fl) => match other {
|
||||||
CameraPropertyValue::Integer(_) |
|
CameraPropertyValue::Null
|
||||||
CameraPropertyValue::LongInteger(_) => Some(Ordering::Greater),
|
| CameraPropertyValue::Boolean(_)
|
||||||
CameraPropertyValue::Float(f) => {
|
| CameraPropertyValue::Integer(_)
|
||||||
fl.partial_cmp(f)
|
| CameraPropertyValue::LongInteger(_) => Some(Ordering::Greater),
|
||||||
}
|
CameraPropertyValue::Float(f) => fl.partial_cmp(f),
|
||||||
CameraPropertyValue::Double(d) => {
|
CameraPropertyValue::Double(d) => f64::from(fl).partial_cmp(d),
|
||||||
f64::from(fl).partial_cmp(d)
|
_ => Some(Ordering::Less),
|
||||||
}
|
},
|
||||||
_ => Some(Ordering::Less),
|
CameraPropertyValue::Double(d) => match other {
|
||||||
}
|
CameraPropertyValue::Null
|
||||||
}
|
| CameraPropertyValue::Boolean(_)
|
||||||
CameraPropertyValue::Double(d) => {
|
| CameraPropertyValue::Integer(_)
|
||||||
match other {
|
| CameraPropertyValue::LongInteger(_) => Some(Ordering::Greater),
|
||||||
CameraPropertyValue::Null |
|
CameraPropertyValue::Float(f) => d.partial_cmp(&(f64::from(f))),
|
||||||
CameraPropertyValue::Boolean(_) |
|
CameraPropertyValue::Double(o) => d.partial_cmp(o),
|
||||||
CameraPropertyValue::Integer(_) |
|
_ => Some(Ordering::Less),
|
||||||
CameraPropertyValue::LongInteger(_) => Some(Ordering::Greater),
|
},
|
||||||
CameraPropertyValue::Float(f) => {
|
CameraPropertyValue::String(s) => match other {
|
||||||
d.partial_cmp(&(f64::from(f)))
|
CameraPropertyValue::Null
|
||||||
}
|
| CameraPropertyValue::Boolean(_)
|
||||||
CameraPropertyValue::Double(o) => {
|
| CameraPropertyValue::Integer(_)
|
||||||
d.partial_cmp(o)
|
| CameraPropertyValue::LongInteger(_)
|
||||||
}
|
| CameraPropertyValue::Float(_)
|
||||||
_ => Some(Ordering::Less),
|
| CameraPropertyValue::Double(_) => Some(Ordering::Greater),
|
||||||
}
|
CameraPropertyValue::String(os) => s.partial_cmp(os),
|
||||||
}
|
_ => Some(Ordering::Less),
|
||||||
CameraPropertyValue::String(s) => {
|
},
|
||||||
match other {
|
CameraPropertyValue::Array(a) => match other {
|
||||||
CameraPropertyValue::Null |
|
CameraPropertyValue::Null
|
||||||
CameraPropertyValue::Boolean(_) |
|
| CameraPropertyValue::Boolean(_)
|
||||||
CameraPropertyValue::Integer(_) |
|
| CameraPropertyValue::Integer(_)
|
||||||
CameraPropertyValue::LongInteger(_) |
|
| CameraPropertyValue::LongInteger(_)
|
||||||
CameraPropertyValue::Float(_) |
|
| CameraPropertyValue::Float(_)
|
||||||
CameraPropertyValue::Double(_) => Some(Ordering::Greater),
|
| CameraPropertyValue::Double(_)
|
||||||
CameraPropertyValue::String(os) => {
|
| CameraPropertyValue::String(_) => Some(Ordering::Greater),
|
||||||
s.partial_cmp(os)
|
CameraPropertyValue::Array(oa) => a.partial_cmp(oa),
|
||||||
}
|
_ => Some(Ordering::Less),
|
||||||
_ => Some(Ordering::Less),
|
},
|
||||||
}
|
CameraPropertyValue::EnumValue(_) => match other {
|
||||||
}
|
CameraPropertyValue::Null
|
||||||
CameraPropertyValue::Array(a) => {
|
| CameraPropertyValue::Boolean(_)
|
||||||
match other {
|
| CameraPropertyValue::Integer(_)
|
||||||
CameraPropertyValue::Null |
|
| CameraPropertyValue::LongInteger(_)
|
||||||
CameraPropertyValue::Boolean(_) |
|
| CameraPropertyValue::Float(_)
|
||||||
CameraPropertyValue::Integer(_) |
|
| CameraPropertyValue::Double(_)
|
||||||
CameraPropertyValue::LongInteger(_) |
|
| CameraPropertyValue::String(_)
|
||||||
CameraPropertyValue::Float(_) |
|
| CameraPropertyValue::Array(_) => Some(Ordering::Greater),
|
||||||
CameraPropertyValue::Double(_) |
|
CameraPropertyValue::EnumValue(_) => Some(Ordering::Equal),
|
||||||
CameraPropertyValue::String(_) => Some(Ordering::Greater),
|
_ => Some(Ordering::Less),
|
||||||
CameraPropertyValue::Array(oa) => {
|
},
|
||||||
a.partial_cmp(oa)
|
CameraPropertyValue::Binary(b) => match other {
|
||||||
}
|
CameraPropertyValue::Null
|
||||||
_ => Some(Ordering::Less),
|
| CameraPropertyValue::Boolean(_)
|
||||||
}
|
| CameraPropertyValue::Integer(_)
|
||||||
}
|
| CameraPropertyValue::LongInteger(_)
|
||||||
CameraPropertyValue::EnumValue(_) => {
|
| CameraPropertyValue::Float(_)
|
||||||
match other {
|
| CameraPropertyValue::Double(_)
|
||||||
CameraPropertyValue::Null |
|
| CameraPropertyValue::String(_)
|
||||||
CameraPropertyValue::Boolean(_) |
|
| CameraPropertyValue::Array(_)
|
||||||
CameraPropertyValue::Integer(_) |
|
| CameraPropertyValue::EnumValue(_) => Some(Ordering::Greater),
|
||||||
CameraPropertyValue::LongInteger(_) |
|
CameraPropertyValue::Binary(ob) => b.partial_cmp(ob),
|
||||||
CameraPropertyValue::Float(_) |
|
_ => Some(Ordering::Less),
|
||||||
CameraPropertyValue::Double(_) |
|
},
|
||||||
CameraPropertyValue::String(_) |
|
|
||||||
CameraPropertyValue::Array(_) => Some(Ordering::Greater),
|
|
||||||
CameraPropertyValue::EnumValue(_) => Some(Ordering::Equal),
|
|
||||||
_ => Some(Ordering::Less),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CameraPropertyValue::Binary(b) => {
|
|
||||||
match other {
|
|
||||||
CameraPropertyValue::Null|
|
|
||||||
CameraPropertyValue::Boolean(_)|
|
|
||||||
CameraPropertyValue::Integer(_)|
|
|
||||||
CameraPropertyValue::LongInteger(_)|
|
|
||||||
CameraPropertyValue::Float(_)|
|
|
||||||
CameraPropertyValue::Double(_)|
|
|
||||||
CameraPropertyValue::String(_)|
|
|
||||||
CameraPropertyValue::Array(_)|
|
|
||||||
CameraPropertyValue::EnumValue(_) => Some(Ordering::Greater),
|
|
||||||
CameraPropertyValue::Binary(ob) => {
|
|
||||||
b.partial_cmp(ob)
|
|
||||||
}
|
|
||||||
_ => Some(Ordering::Less),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// FIXME: implement this lole
|
// FIXME: implement this lole
|
||||||
CameraPropertyValue::Pair(_, _) => {
|
CameraPropertyValue::Pair(_, _) => {
|
||||||
// match other {
|
// match other {
|
||||||
@@ -655,7 +651,7 @@ macro_rules! define_back_and_fourth_control {
|
|||||||
impl ControlIntermediate {
|
impl ControlIntermediate {
|
||||||
pub fn
|
pub fn
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl ControlIntermediate {
|
// impl ControlIntermediate {
|
||||||
// pub fn into_control(native_ctrl: $id_type) -> (crate::properties::CameraPropertyId, Option<crate::properties::CameraPropertyFlag>) {
|
// pub fn into_control(native_ctrl: $id_type) -> (crate::properties::CameraPropertyId, Option<crate::properties::CameraPropertyFlag>) {
|
||||||
// match native_ctrl {
|
// match native_ctrl {
|
||||||
|
|||||||
+165
-136
@@ -1,9 +1,9 @@
|
|||||||
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;
|
use crate::error::NokhwaError;
|
||||||
|
use core::fmt::{Debug, Display, Formatter};
|
||||||
|
use std::collections::hash_map::Keys;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::hash::Hash;
|
||||||
|
use std::ops::{Div, Rem, Sub};
|
||||||
|
|
||||||
/// Failed to validate.
|
/// Failed to validate.
|
||||||
#[derive(Copy, Clone, Debug, Default, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Default, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
||||||
@@ -22,27 +22,25 @@ pub trait ValidatableRange {
|
|||||||
///
|
///
|
||||||
/// Inclusive by default.
|
/// Inclusive by default.
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
|
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
|
||||||
pub struct Range<T>
|
pub struct Range<T> {
|
||||||
{
|
|
||||||
minimum: Option<T>,
|
minimum: Option<T>,
|
||||||
lower_inclusive: bool,
|
lower_inclusive: bool,
|
||||||
maximum: Option<T>,
|
maximum: Option<T>,
|
||||||
upper_inclusive: bool,
|
upper_inclusive: bool,
|
||||||
preferred: T,
|
preferred: T,
|
||||||
|
step: Option<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Range<T>
|
impl<T> Range<T> where T: Copy {
|
||||||
where
|
|
||||||
T: Copy + Clone + Debug + PartialOrd + PartialEq,
|
|
||||||
{
|
|
||||||
/// Create an upper and lower inclusive [`Range`]
|
/// Create an upper and lower inclusive [`Range`]
|
||||||
pub fn new(preferred: T, min: Option<T>, max: Option<T>) -> Self {
|
pub fn new(preferred: T, min: Option<T>, max: Option<T>, step: Option<T>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
minimum: min,
|
minimum: min,
|
||||||
lower_inclusive: true,
|
lower_inclusive: true,
|
||||||
maximum: max,
|
maximum: max,
|
||||||
upper_inclusive: true,
|
upper_inclusive: true,
|
||||||
preferred,
|
preferred,
|
||||||
|
step,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,6 +50,7 @@ where
|
|||||||
lower_inclusive: bool,
|
lower_inclusive: bool,
|
||||||
max: Option<T>,
|
max: Option<T>,
|
||||||
upper_inclusive: bool,
|
upper_inclusive: bool,
|
||||||
|
step: Option<T>
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
minimum: min,
|
minimum: min,
|
||||||
@@ -59,6 +58,7 @@ where
|
|||||||
maximum: max,
|
maximum: max,
|
||||||
upper_inclusive,
|
upper_inclusive,
|
||||||
preferred,
|
preferred,
|
||||||
|
step,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,6 +69,7 @@ where
|
|||||||
maximum: None,
|
maximum: None,
|
||||||
upper_inclusive: true,
|
upper_inclusive: true,
|
||||||
preferred,
|
preferred,
|
||||||
|
step: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,6 +85,9 @@ where
|
|||||||
pub fn set_upper_inclusive(&mut self, upper_inclusive: bool) {
|
pub fn set_upper_inclusive(&mut self, upper_inclusive: bool) {
|
||||||
self.upper_inclusive = upper_inclusive;
|
self.upper_inclusive = upper_inclusive;
|
||||||
}
|
}
|
||||||
|
pub fn set_step(&mut self, step: T) {
|
||||||
|
self.step = Some(step);
|
||||||
|
}
|
||||||
pub fn set_preferred(&mut self, preferred: T) {
|
pub fn set_preferred(&mut self, preferred: T) {
|
||||||
self.preferred = preferred;
|
self.preferred = preferred;
|
||||||
}
|
}
|
||||||
@@ -102,13 +106,27 @@ where
|
|||||||
pub fn preferred(&self) -> T {
|
pub fn preferred(&self) -> T {
|
||||||
self.preferred
|
self.preferred
|
||||||
}
|
}
|
||||||
|
pub fn step(&self) -> Option<T> {
|
||||||
|
self.step
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ValidatableRange for Range<T> where T: PartialEq + PartialOrd {
|
impl<T> ValidatableRange for Range<T>
|
||||||
|
where
|
||||||
|
T: SimpleRangeItem,
|
||||||
|
{
|
||||||
type Validation = T;
|
type Validation = T;
|
||||||
|
|
||||||
fn validate(&self, value: Self::Validation) -> Result<(), RangeValidationFailure> {
|
fn validate(&self, value: &T) -> Result<(), RangeValidationFailure> {
|
||||||
num_range_validate(self.minimum.as_ref(), self.maximum.as_ref(), &self.preferred, self.lower_inclusive, self.upper_inclusive, &value)
|
num_range_validate(
|
||||||
|
self.minimum,
|
||||||
|
self.maximum,
|
||||||
|
self.preferred,
|
||||||
|
self.lower_inclusive,
|
||||||
|
self.upper_inclusive,
|
||||||
|
self.step,
|
||||||
|
*value,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,107 +141,39 @@ where
|
|||||||
maximum: None,
|
maximum: None,
|
||||||
upper_inclusive: true,
|
upper_inclusive: true,
|
||||||
preferred: T::default(),
|
preferred: T::default(),
|
||||||
|
step: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Display for Range<T> where T: Debug {
|
impl<T> Display for Range<T>
|
||||||
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
|
where
|
||||||
T: Copy + Clone + Debug + PartialOrd + PartialEq
|
T: Debug,
|
||||||
{
|
{
|
||||||
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 {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
let lower_inclusive_char = bool_to_inclusive_char(self.lower_inclusive, false);
|
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 upper_inclusive_char = bool_to_inclusive_char(self.upper_inclusive, true);
|
||||||
let default = default_to_string(&self.default);
|
let default = &self.preferred;
|
||||||
let step = default_to_string(&self.step);
|
|
||||||
|
|
||||||
// Ex) IndicatedRange: (5, 19], Step: 3, Default: 8
|
write!(
|
||||||
write!(f, "IndicatedRange: {lower_inclusive_char}{}, {}{upper_inclusive_char}, Step: {step}, Default: {default}", self.minimum, self.maximum)
|
f,
|
||||||
|
"Range: {lower_inclusive_char}{:?}, {:?}{upper_inclusive_char}, Preferred: {default:?}",
|
||||||
|
self.minimum, self.maximum
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Options<T> where T: Clone + Debug {
|
pub struct Options<T> {
|
||||||
default: Option<T>,
|
default: Option<T>,
|
||||||
available: Vec<T>,
|
available: Vec<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Options<T>
|
impl<T> Options<T>
|
||||||
where
|
where
|
||||||
T: Clone + Debug + PartialEq
|
T: Clone + Debug + PartialEq,
|
||||||
{
|
{
|
||||||
pub fn new(values: Vec<T>, default_value: T) -> Self {
|
pub fn new(values: Vec<T>, default_value: Option<T>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
default: default_value,
|
default: default_value,
|
||||||
available: values,
|
available: values,
|
||||||
@@ -239,7 +189,10 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ValidatableRange for Options<T> where T: PartialEq {
|
impl<T> ValidatableRange for Options<T>
|
||||||
|
where
|
||||||
|
T: Clone + PartialEq,
|
||||||
|
{
|
||||||
type Validation = T;
|
type Validation = T;
|
||||||
|
|
||||||
fn validate(&self, value: &Self::Validation) -> Result<(), RangeValidationFailure> {
|
fn validate(&self, value: &Self::Validation) -> Result<(), RangeValidationFailure> {
|
||||||
@@ -250,40 +203,53 @@ impl<T> ValidatableRange for Options<T> where T: PartialEq {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Display for Options<T> where T: Debug {
|
impl<T> Display for Options<T>
|
||||||
|
where
|
||||||
|
T: Debug,
|
||||||
|
{
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
let default = default_to_string(&self.default);
|
let default = default_to_string(&self.default);
|
||||||
|
|
||||||
write!(f, "Options: Available {:?}, Default: {default}", self.available)
|
write!(
|
||||||
|
f,
|
||||||
|
"Options: Available {:?}, Default: {default}",
|
||||||
|
self.available
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct KeyValue<K, V> where K: Clone + Debug + Hash + Eq, V: Clone + Debug {
|
pub struct KeyValue<K, V>
|
||||||
|
where
|
||||||
|
K: Clone + Debug + Hash + Eq,
|
||||||
|
V: Clone + Debug,
|
||||||
|
{
|
||||||
defaults: HashMap<K, V>,
|
defaults: HashMap<K, V>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K, V> KeyValue<K, V>
|
impl<K, V> KeyValue<K, V>
|
||||||
where
|
where
|
||||||
K: Clone + Debug + Hash + Eq,
|
K: Clone + Debug + Hash + Eq,
|
||||||
V: Clone + Debug
|
V: Clone + Debug,
|
||||||
{
|
{
|
||||||
pub fn new(default: HashMap<K, V>) -> Self {
|
pub fn new(default: HashMap<K, V>) -> Self {
|
||||||
Self {
|
Self { defaults: default }
|
||||||
defaults: default,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn available_keys(&self) -> &Keys<'_, K, V> {
|
pub fn available_keys(&self) -> Keys<'_, K, V> {
|
||||||
&self.defaults.keys()
|
self.defaults.keys()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn by_key(&self, key: &K) -> Option<&V> {
|
pub fn by_key(&self, key: &K) -> Option<&V> {
|
||||||
self.defaults.get(key)
|
self.defaults.get(key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K, V> Display for KeyValue<K, V> where K: Debug, V: Debug {
|
impl<K, V> Display for KeyValue<K, V>
|
||||||
|
where
|
||||||
|
K: Clone + Debug + Hash + Eq,
|
||||||
|
V: Clone + Debug,
|
||||||
|
{
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
// TODO: pretty print?
|
// TODO: pretty print?
|
||||||
write!(f, "Key Value Pairs: {:?}", self.defaults)
|
write!(f, "Key Value Pairs: {:?}", self.defaults)
|
||||||
@@ -291,16 +257,19 @@ impl<K, V> Display for KeyValue<K, V> where K: Debug, V: Debug {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ArrayRange<T> where T: Clone + Debug {
|
pub struct ArrayRange<T> {
|
||||||
appendable_options: Vec<T>,
|
appendable_options: Vec<T>,
|
||||||
default_options: Vec<T>,
|
default_options: Vec<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ArrayRange<T> where T: Clone + Debug + PartialEq {
|
impl<T> ArrayRange<T>
|
||||||
|
where
|
||||||
|
T: Clone + Debug + PartialEq,
|
||||||
|
{
|
||||||
pub fn new(appendable: Vec<T>, default: Vec<T>) -> Result<Self, NokhwaError> {
|
pub fn new(appendable: Vec<T>, default: Vec<T>) -> Result<Self, NokhwaError> {
|
||||||
for option in &default {
|
for option in &default {
|
||||||
if !appendable.contains(option) {
|
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() })
|
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() });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,7 +288,10 @@ impl<T> ArrayRange<T> where T: Clone + Debug + PartialEq {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ValidatableRange for ArrayRange<T> where T: PartialEq {
|
impl<T> ValidatableRange for ArrayRange<T>
|
||||||
|
where
|
||||||
|
T: PartialEq,
|
||||||
|
{
|
||||||
type Validation = T;
|
type Validation = T;
|
||||||
|
|
||||||
fn validate(&self, value: &Self::Validation) -> Result<(), RangeValidationFailure> {
|
fn validate(&self, value: &Self::Validation) -> Result<(), RangeValidationFailure> {
|
||||||
@@ -330,22 +302,30 @@ impl<T> ValidatableRange for ArrayRange<T> where T: PartialEq {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Display for ArrayRange<T> where T: Debug {
|
impl<T> Display for ArrayRange<T>
|
||||||
|
where
|
||||||
|
T: Debug,
|
||||||
|
{
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "ArrayRange: Available Options: {:?}, Default: {:?}", self.appendable_options, self.default_options)
|
write!(
|
||||||
|
f,
|
||||||
|
"ArrayRange: Available Options: {:?}, Default: {:?}",
|
||||||
|
self.appendable_options, self.default_options
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Simple<T> where T: Clone + Debug {
|
pub struct Simple<T> {
|
||||||
default: Option<T>
|
default: Option<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Simple<T> where T: Clone + Debug {
|
impl<T> Simple<T>
|
||||||
|
where
|
||||||
|
T: Clone + Debug,
|
||||||
|
{
|
||||||
pub fn new(default: Option<T>) -> Self {
|
pub fn new(default: Option<T>) -> Self {
|
||||||
Self {
|
Self { default }
|
||||||
default,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn default_value(&self) -> Option<&T> {
|
pub fn default_value(&self) -> Option<&T> {
|
||||||
@@ -361,7 +341,10 @@ impl<T> ValidatableRange for Simple<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Display for Simple<T> where T: Debug {
|
impl<T> Display for Simple<T>
|
||||||
|
where
|
||||||
|
T: Debug,
|
||||||
|
{
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
let default = default_to_string(&self.default);
|
let default = default_to_string(&self.default);
|
||||||
write!(f, "Simple (Any Value): Default Value: {default}")
|
write!(f, "Simple (Any Value): Default Value: {default}")
|
||||||
@@ -370,12 +353,27 @@ impl<T> Display for Simple<T> where T: Debug {
|
|||||||
|
|
||||||
fn bool_to_inclusive_char(inclusive: bool, upper: bool) -> char {
|
fn bool_to_inclusive_char(inclusive: bool, upper: bool) -> char {
|
||||||
match inclusive {
|
match inclusive {
|
||||||
true => if upper { ']' } else { '[' },
|
true => {
|
||||||
false => if upper { ')' } else { '(' },
|
if upper {
|
||||||
|
']'
|
||||||
|
} else {
|
||||||
|
'['
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false => {
|
||||||
|
if upper {
|
||||||
|
')'
|
||||||
|
} else {
|
||||||
|
'('
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_to_string<T>(default: &Option<T>) -> String where T: Debug {
|
fn default_to_string<T>(default: &Option<T>) -> String
|
||||||
|
where
|
||||||
|
T: Debug,
|
||||||
|
{
|
||||||
match default {
|
match default {
|
||||||
Some(v) => {
|
Some(v) => {
|
||||||
format!("{v:?}")
|
format!("{v:?}")
|
||||||
@@ -384,10 +382,33 @@ fn default_to_string<T>(default: &Option<T>) -> String where T: Debug {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn num_range_validate<T>(
|
||||||
|
minimum: Option<T>,
|
||||||
|
maximum: Option<T>,
|
||||||
|
default: T,
|
||||||
|
lower_inclusive: bool,
|
||||||
|
upper_inclusive: bool,
|
||||||
|
step: Option<T>,
|
||||||
|
value: T,
|
||||||
|
) -> Result<(), RangeValidationFailure>
|
||||||
|
where
|
||||||
|
T: SimpleRangeItem,
|
||||||
|
{
|
||||||
|
|
||||||
|
if let (Some(step), Some(min)) = (step, minimum) {
|
||||||
|
let prepared_value: T = value - min;
|
||||||
|
// 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 != T::ZERO {
|
||||||
|
return Err(RangeValidationFailure::default());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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 {
|
if value == default {
|
||||||
return Ok(())
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(min) = minimum {
|
if let Some(min) = minimum {
|
||||||
@@ -415,16 +436,24 @@ fn num_range_validate<T>(minimum: Option<&T>, maximum: Option<&T>, default: &T,
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
trait Number {}
|
pub trait SimpleRangeItem: Copy + Clone + Debug + Div<Output = Self> + Sub<Output = Self> + Rem<Output = Self> + PartialOrd + PartialEq {
|
||||||
|
const ZERO: Self;
|
||||||
macro_rules! impl_num {
|
|
||||||
( $($n:ty, )* ) => {
|
|
||||||
{
|
|
||||||
$(
|
|
||||||
impl Number for $n {}
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_num!( i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, f32, f64, );
|
macro_rules! impl_num {
|
||||||
|
($($n:ty)*) => ($(
|
||||||
|
impl SimpleRangeItem for $n {
|
||||||
|
const ZERO: $n = 0;
|
||||||
|
}
|
||||||
|
)*)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_num! { i8 u8 i16 u16 i32 u32 i64 u64 i128 u128 }
|
||||||
|
|
||||||
|
impl SimpleRangeItem for f32 {
|
||||||
|
const ZERO: Self = 0_f32;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimpleRangeItem for f64 {
|
||||||
|
const ZERO: Self = 0_f64;
|
||||||
|
}
|
||||||
+75
-32
@@ -1,43 +1,86 @@
|
|||||||
use std::{
|
use crate::error::{NokhwaError, NokhwaResult};
|
||||||
future::Future,
|
use crate::frame_buffer::FrameBuffer;
|
||||||
pin::Pin,
|
use flume::Receiver;
|
||||||
sync::{Arc, Mutex},
|
use futures::TryFutureExt;
|
||||||
task::{Context, Poll},
|
use std::sync::Arc;
|
||||||
sync::mpsc::Receiver
|
|
||||||
};
|
|
||||||
use futures::Stream as AsyncStreamTrait;
|
|
||||||
use crate::{
|
|
||||||
buffer::Buffer,
|
|
||||||
error::NokhwaError
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
pub trait StreamInnerTrait {
|
||||||
pub enum ChannelState {
|
fn receiver(&self) -> Arc<Receiver<FrameBuffer>>;
|
||||||
Frame(Buffer),
|
fn stop(&mut self) -> NokhwaResult<()>;
|
||||||
Error(NokhwaError),
|
|
||||||
ClosedWithError(NokhwaError),
|
|
||||||
Closed,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum StreamType {
|
pub struct Stream {
|
||||||
Channel(Arc<Receiver<ChannelState>>),
|
inner: Box<dyn StreamInnerTrait>,
|
||||||
Callback(Arc<Mutex<Option<ChannelState>>>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CaptureStream {}
|
impl Stream {
|
||||||
|
pub fn new(inner: Box<dyn StreamInnerTrait>) -> Self {
|
||||||
|
Self {
|
||||||
|
inner,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Future for CaptureStream {
|
// pub unsafe fn erase_lifetime(self) -> Stream<'static> {
|
||||||
type Output = ChannelState;
|
// Self {
|
||||||
|
// inner: self.inner,
|
||||||
|
// phantom_data: Default::default(),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
pub fn poll_frame(&self) -> NokhwaResult<FrameBuffer> {
|
||||||
todo!()
|
if self.inner.receiver().is_disconnected() {
|
||||||
|
return Err(NokhwaError::ReadFrameError(
|
||||||
|
"stream is disconnected!".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.inner
|
||||||
|
.receiver()
|
||||||
|
.recv()
|
||||||
|
.map_err(|why| NokhwaError::ReadFrameError(why.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_poll_frame(&self) -> Option<NokhwaResult<FrameBuffer>> {
|
||||||
|
if self.inner.receiver().is_disconnected() {
|
||||||
|
return Some(Err(NokhwaError::ReadFrameError(
|
||||||
|
"stream is disconnected!".to_string(),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.inner.receiver().is_empty() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(
|
||||||
|
self.inner
|
||||||
|
.receiver()
|
||||||
|
.try_recv()
|
||||||
|
.map_err(|why| NokhwaError::ReadFrameError(why.to_string())),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
pub async fn await_frame(&self) -> NokhwaResult<FrameBuffer> {
|
||||||
|
if self.inner.receiver().is_disconnected() {
|
||||||
|
return Err(NokhwaError::ReadFrameError(
|
||||||
|
"stream is disconnected!".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.inner
|
||||||
|
.receiver()
|
||||||
|
.recv_async()
|
||||||
|
.map_err(|why| NokhwaError::ReadFrameError(why.to_string())).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stop_stream(mut self) -> NokhwaResult<()> {
|
||||||
|
self.inner.stop()?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsyncStreamTrait for CaptureStream {
|
impl Drop for Stream {
|
||||||
type Item = ChannelState;
|
fn drop(&mut self) {
|
||||||
|
let _ = self.inner.stop();
|
||||||
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
|
||||||
todo!()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,3 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// pub trait VirtualBackendTrait {}
|
// pub trait VirtualBackendTrait {}
|
||||||
|
|
||||||
pub trait Distance<T> where T: PartialEq {
|
|
||||||
fn distance_from(&self, other: &Self) -> T;
|
|
||||||
}
|
|
||||||
|
|||||||
+93
-419
@@ -1,18 +1,18 @@
|
|||||||
use crate::{
|
use crate::utils::Distance;
|
||||||
error::NokhwaError,
|
use crate::{error::NokhwaError, frame_format::FrameFormat};
|
||||||
frame_format::FrameFormat,
|
|
||||||
};
|
|
||||||
#[cfg(feature = "serialize")]
|
#[cfg(feature = "serialize")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
borrow::Borrow, cmp::Ordering, fmt::{
|
borrow::Borrow,
|
||||||
Debug,
|
cmp::Ordering,
|
||||||
Display,
|
fmt::{Debug, Display, Formatter},
|
||||||
Formatter
|
hash::{Hash},
|
||||||
}, hash::{Hash, Hasher}, ops::{Add, Deref, DerefMut, Sub}
|
ops::{Sub},
|
||||||
};
|
};
|
||||||
use crate::traits::Distance;
|
use std::num::NonZeroI32;
|
||||||
|
use std::ops::{Div, Rem};
|
||||||
|
use num_rational::Rational32;
|
||||||
|
use crate::ranges::{SimpleRangeItem};
|
||||||
|
|
||||||
/// Describes the index of the camera.
|
/// Describes the index of the camera.
|
||||||
/// - Index: A numbered index
|
/// - Index: A numbered index
|
||||||
@@ -105,7 +105,7 @@ pub struct Resolution {
|
|||||||
impl Resolution {
|
impl Resolution {
|
||||||
/// Create a new resolution from 2 image size coordinates.
|
/// Create a new resolution from 2 image size coordinates.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(x: u32, y: u32) -> Self {
|
pub const fn new(x: u32, y: u32) -> Self {
|
||||||
Resolution {
|
Resolution {
|
||||||
width_x: x,
|
width_x: x,
|
||||||
height_y: y,
|
height_y: y,
|
||||||
@@ -180,78 +180,123 @@ impl Distance<u32> for Resolution {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Hash)]
|
impl Div for Resolution {
|
||||||
|
type Output = Resolution;
|
||||||
|
|
||||||
|
fn div(self, rhs: Self) -> Self::Output {
|
||||||
|
let x_div = self.x().div(rhs.x());
|
||||||
|
let y_div = self.y().div(rhs.y());
|
||||||
|
Resolution::new(x_div, y_div)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub for Resolution {
|
||||||
|
type Output = Resolution;
|
||||||
|
|
||||||
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
|
let x_sub = self.x().sub(rhs.x());
|
||||||
|
let y_sub = self.y().sub(rhs.y());
|
||||||
|
Resolution::new(x_sub, y_sub)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Rem for Resolution {
|
||||||
|
type Output = Resolution;
|
||||||
|
|
||||||
|
fn rem(self, rhs: Self) -> Self::Output {
|
||||||
|
let x_rem = self.x().rem(rhs.x());
|
||||||
|
let y_rem = self.y().rem(rhs.y());
|
||||||
|
Resolution::new(x_rem, y_rem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimpleRangeItem for Resolution {
|
||||||
|
const ZERO: Self = Resolution::new(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Framerate of a camera, backed by a num-rational Ratio type.
|
||||||
|
///
|
||||||
|
/// Note that while constructing negative is allowed, the absolute value
|
||||||
|
/// will be passed to the driver.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
/// If denominator is 0, any attempt to use the [`FrameRate`] will **panic.**
|
||||||
|
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
|
||||||
pub struct FrameRate {
|
pub struct FrameRate {
|
||||||
numerator: u32,
|
rational: Rational32,
|
||||||
denominator: u32
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FrameRate {
|
impl FrameRate {
|
||||||
pub fn new(numerator: u32, denominator: u32) -> Self {
|
pub const fn new(numerator: i32, denominator: NonZeroI32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
numerator,
|
rational: Rational32::new_raw(numerator, denominator.get()),
|
||||||
denominator,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn frame_rate(fps: u32) -> Self {
|
pub const fn frame_rate(fps: i32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
numerator: fps,
|
rational: Rational32::new_raw(fps, 1),
|
||||||
denominator: 1,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn numerator(&self) -> u32 {
|
pub fn numerator(&self) -> &i32 {
|
||||||
self.numerator
|
self.rational.numer()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn denominator(&self) -> u32 {
|
pub fn denominator(&self) -> &i32 {
|
||||||
self.denominator
|
self.rational.denom()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for FrameRate {
|
impl Default for FrameRate {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
FrameRate::new(30, 1)
|
FrameRate::new(30, NonZeroI32::new(1).unwrap())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for FrameRate {
|
impl Display for FrameRate {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "{}/{} FPS", self.numerator, self.denominator)
|
write!(f, "{}/{} FPS", self.numerator(), self.denominator())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eq for FrameRate {}
|
impl Div for FrameRate {
|
||||||
|
type Output = FrameRate;
|
||||||
|
|
||||||
impl PartialEq<Self> for FrameRate {
|
fn div(self, rhs: Self) -> Self::Output {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
self.rational.div(rhs.rational).into()
|
||||||
(self.numerator * other.denominator) == (other.numerator * self.numerator)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialOrd<Self> for FrameRate {
|
impl Sub for FrameRate {
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
type Output = FrameRate;
|
||||||
Some(self.cmp(other))
|
|
||||||
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
|
self.rational.sub(rhs.rational).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ord for FrameRate {
|
impl Rem for FrameRate {
|
||||||
fn cmp(&self, other: &Self) -> Ordering {
|
type Output = FrameRate;
|
||||||
if self.numerator == 0 && other.denominator == 0 {
|
|
||||||
return Ordering::Equal;
|
fn rem(self, rhs: Self) -> Self::Output {
|
||||||
|
self.rational.rem(rhs.rational).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimpleRangeItem for FrameRate {
|
||||||
|
const ZERO: Self = FrameRate::frame_rate(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Rational32> for FrameRate {
|
||||||
|
fn from(value: Rational32) -> Self {
|
||||||
|
FrameRate {
|
||||||
|
rational: value,
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.denominator == other.denominator {
|
|
||||||
return self.numerator.cmp(&other.numerator);
|
|
||||||
}
|
|
||||||
|
|
||||||
(self.numerator * other.denominator).cmp(&(other.numerator * self.denominator))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// This is a convenience struct that holds all information about the format of a webcam stream.
|
/// This is a convenience struct that holds all information about the format of a webcam stream.
|
||||||
/// It consists of a [`Resolution`], [`FrameFormat`], and a [`FrameRate`].
|
/// It consists of a [`Resolution`], [`FrameFormat`], and a [`FrameRate`].
|
||||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, PartialOrd)]
|
#[derive(Copy, Clone, Debug, Hash, PartialEq, PartialOrd)]
|
||||||
@@ -265,7 +310,7 @@ pub struct CameraFormat {
|
|||||||
impl CameraFormat {
|
impl CameraFormat {
|
||||||
/// Construct a new [`CameraFormat`]
|
/// Construct a new [`CameraFormat`]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(resolution: Resolution, format: FrameFormat, frame_rate: FrameRate) -> Self {
|
pub const fn new(resolution: Resolution, format: FrameFormat, frame_rate: FrameRate) -> Self {
|
||||||
CameraFormat {
|
CameraFormat {
|
||||||
resolution,
|
resolution,
|
||||||
format,
|
format,
|
||||||
@@ -275,7 +320,7 @@ impl CameraFormat {
|
|||||||
|
|
||||||
/// [`CameraFormat::new()`], but raw.
|
/// [`CameraFormat::new()`], but raw.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new_from(res_x: u32, res_y: u32, format: FrameFormat, fps: FrameRate) -> Self {
|
pub const fn new_from(res_x: u32, res_y: u32, format: FrameFormat, fps: FrameRate) -> Self {
|
||||||
CameraFormat {
|
CameraFormat {
|
||||||
resolution: Resolution {
|
resolution: Resolution {
|
||||||
width_x: res_x,
|
width_x: res_x,
|
||||||
@@ -530,374 +575,3 @@ impl Display for ApiBackend {
|
|||||||
write!(f, "{self:?}")
|
write!(f, "{self:?}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// /// A webcam index that supports both strings and integers. Most backends take an int, but `IPCamera`s take a URL (string).
|
|
||||||
// #[derive(Clone, Debug, Hash, PartialEq, PartialOrd)]
|
|
||||||
// pub enum CameraIndex {
|
|
||||||
// Index(u32),
|
|
||||||
// String(String),
|
|
||||||
// }
|
|
||||||
|
|
||||||
// impl CameraIndex {
|
|
||||||
// /// Gets the device info's index as an `u32`.
|
|
||||||
// /// # Errors
|
|
||||||
// /// If the index is not parsable as a `u32`, this will error.
|
|
||||||
// pub fn as_index(&self) -> Result<u32, NokhwaError> {
|
|
||||||
// match self {
|
|
||||||
// CameraIndex::Index(i) => Ok(*i),
|
|
||||||
// CameraIndex::String(s) => match s.parse::<u32>() {
|
|
||||||
// Ok(p) => Ok(p),
|
|
||||||
// Err(why) => Err(NokhwaError::GetPropertyError {
|
|
||||||
// property: "index-int".to_string(),
|
|
||||||
// error: why.to_string(),
|
|
||||||
// }),
|
|
||||||
// },
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// impl Display for CameraIndex {
|
|
||||||
// fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
||||||
// match self {
|
|
||||||
// CameraIndex::Index(idx) => {
|
|
||||||
// write!(f, "{}", idx)
|
|
||||||
// }
|
|
||||||
// CameraIndex::String(ip) => {
|
|
||||||
// write!(f, "{}", ip)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// impl From<u32> for CameraIndex {
|
|
||||||
// fn from(v: u32) -> Self {
|
|
||||||
// CameraIndex::Index(v)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// /// Trait for strings that can be converted to [`CameraIndex`]es.
|
|
||||||
// pub trait ValidString: AsRef<str> {}
|
|
||||||
//
|
|
||||||
// impl ValidString for String {}
|
|
||||||
// impl<'a> ValidString for &'a String {}
|
|
||||||
// impl<'a> ValidString for &'a mut String {}
|
|
||||||
// impl<'a> ValidString for Cow<'a, str> {}
|
|
||||||
// impl<'a> ValidString for &'a Cow<'a, str> {}
|
|
||||||
// impl<'a> ValidString for &'a mut Cow<'a, str> {}
|
|
||||||
// impl<'a> ValidString for &'a str {}
|
|
||||||
// impl<'a> ValidString for &'a mut str {}
|
|
||||||
|
|
||||||
// impl<T> From<T> for CameraIndex
|
|
||||||
// where
|
|
||||||
// T: ValidString,
|
|
||||||
// {
|
|
||||||
// fn from(v: T) -> Self {
|
|
||||||
// CameraIndex::String(v.as_ref().to_string())
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
#[cfg(all(feature = "conversions", not(target_arch = "wasm32")))]
|
|
||||||
#[cfg_attr(feature = "docs-features", doc(cfg(feature = "mjpeg")))]
|
|
||||||
#[inline]
|
|
||||||
fn decompress<'a>(
|
|
||||||
data: &'a [u8],
|
|
||||||
rgba: bool,
|
|
||||||
) -> Result<mozjpeg::decompress::DecompressStarted<'a>, 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(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts a MJpeg stream of `&[u8]` into a `Vec<u8>` of RGB888. (R,G,B,R,G,B,...)
|
|
||||||
/// # Errors
|
|
||||||
/// If `mozjpeg` fails to read scanlines or setup the decompressor, this will error.
|
|
||||||
/// # Safety
|
|
||||||
/// This function uses `unsafe`. The caller must ensure that:
|
|
||||||
/// - The input data is of the right size, does not exceed bounds, and/or the final size matches with the initial size.
|
|
||||||
#[cfg(all(feature = "conversions", not(target_arch = "wasm32")))]
|
|
||||||
#[cfg_attr(feature = "docs-features", doc(cfg(feature = "mjpeg")))]
|
|
||||||
#[inline]
|
|
||||||
pub fn mjpeg_to_rgb(data: &[u8], rgba: bool) -> Result<Vec<u8>, NokhwaError> {
|
|
||||||
let mut jpeg_decompress = decompress(data, rgba)?;
|
|
||||||
|
|
||||||
let scanlines_res: Option<Vec<u8>> = jpeg_decompress.read_scanlines_flat();
|
|
||||||
// assert!(jpeg_decompress.finish_decompress());
|
|
||||||
if !jpeg_decompress.finish_decompress() {
|
|
||||||
return Err(NokhwaError::ProcessFrameError {
|
|
||||||
src: FrameFormat::MJpeg,
|
|
||||||
destination: "RGB888".to_string(),
|
|
||||||
error: "JPEG Decompressor did not finish.".to_string(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
match scanlines_res {
|
|
||||||
Some(pixels) => Ok(pixels),
|
|
||||||
None => Err(NokhwaError::ProcessFrameError {
|
|
||||||
src: FrameFormat::MJpeg,
|
|
||||||
destination: "RGB888".to_string(),
|
|
||||||
error: "Failed to get read readlines into RGB888 pixels!".to_string(),
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Equivalent to [`mjpeg_to_rgb`] except with a destination buffer.
|
|
||||||
/// # Errors
|
|
||||||
/// If the decoding fails (e.g. invalid MJpeg stream), the buffer is not large enough, or you are doing this on `WebAssembly`, this will error.
|
|
||||||
#[cfg(not(all(feature = "conversions", not(target_arch = "wasm32"))))]
|
|
||||||
pub fn mjpeg_to_rgb(_data: &[u8], _rgba: bool) -> Result<Vec<u8>, NokhwaError> {
|
|
||||||
Err(NokhwaError::NotImplementedError(
|
|
||||||
"Not available on WASM".to_string(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Equivalent to [`mjpeg_to_rgb`] except with a destination buffer.
|
|
||||||
/// # Errors
|
|
||||||
/// If the decoding fails (e.g. invalid MJpeg stream), the buffer is not large enough, or you are doing this on `WebAssembly`, this will error.
|
|
||||||
#[cfg(not(all(feature = "conversions", not(target_arch = "wasm32"))))]
|
|
||||||
#[cfg_attr(feature = "docs-features", doc(cfg(feature = "mjpeg")))]
|
|
||||||
#[inline]
|
|
||||||
pub fn buf_mjpeg_to_rgb(data: &[u8], dest: &mut [u8], rgba: bool) -> Result<(), NokhwaError> {
|
|
||||||
let mut jpeg_decompress = mozjpeg::decompress(data, rgba)?;
|
|
||||||
|
|
||||||
// assert_eq!(dest.len(), jpeg_decompress.min_flat_buffer_size());
|
|
||||||
if dest.len() != jpeg_decompress.min_flat_buffer_size() {
|
|
||||||
return Err(NokhwaError::ProcessFrameError {
|
|
||||||
src: FrameFormat::MJpeg,
|
|
||||||
destination: "RGB888".to_string(),
|
|
||||||
error: "Bad decoded buffer size".to_string(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
jpeg_decompress.read_scanlines_flat_into(dest);
|
|
||||||
// assert!(jpeg_decompress.finish_decompress());
|
|
||||||
if !jpeg_decompress.finish_decompress() {
|
|
||||||
return Err(NokhwaError::ProcessFrameError {
|
|
||||||
src: FrameFormat::MJpeg,
|
|
||||||
destination: "RGB888".to_string(),
|
|
||||||
error: "JPEG Decompressor did not finish.".to_string(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: deprecate?
|
|
||||||
/// Equivalent to [`mjpeg_to_rgb`] except with a destination buffer.
|
|
||||||
/// # Errors
|
|
||||||
/// If the decoding fails (e.g. invalid MJpeg stream), the buffer is not large enough, or you are doing this on `WebAssembly`, this will error.
|
|
||||||
#[cfg(all(feature = "conversions", not(target_arch = "wasm32")))]
|
|
||||||
pub fn buf_mjpeg_to_rgb(_data: &[u8], _dest: &mut [u8], _rgba: bool) -> Result<(), NokhwaError> {
|
|
||||||
Err(NokhwaError::NotImplementedError(
|
|
||||||
"Not available on WASM".to_string(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the predicted size of the destination Yuv422422 buffer.
|
|
||||||
#[inline]
|
|
||||||
pub fn yuyv422_predicted_size(size: usize, rgba: bool) -> usize {
|
|
||||||
let pixel_size = if rgba { 4 } else { 3 };
|
|
||||||
// yuyv yields 2 3-byte pixels per yuyv chunk
|
|
||||||
(size / 4) * (2 * pixel_size)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn yuyv422_to_rgb(data: &[u8], rgba: bool) -> Result<Vec<u8>, NokhwaError> {
|
|
||||||
let capacity = yuyv422_predicted_size(data.len(), rgba);
|
|
||||||
let mut rgb = vec![0; capacity];
|
|
||||||
buf_yuyv422_to_rgb(data, &mut rgb, rgba)?;
|
|
||||||
Ok(rgb)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Same as [`yuyv422_to_rgb`] but with a destination buffer instead of a return `Vec<u8>`
|
|
||||||
/// # Errors
|
|
||||||
/// If the stream is invalid Yuv422, or the destination buffer is not large enough, this will error.
|
|
||||||
#[inline]
|
|
||||||
pub fn buf_yuyv422_to_rgb(data: &[u8], dest: &mut [u8], rgba: bool) -> Result<(), NokhwaError> {
|
|
||||||
let mut buf: Vec<u8> = Vec::new();
|
|
||||||
if data.len() % 4 != 0 {
|
|
||||||
return Err(NokhwaError::ProcessFrameError {
|
|
||||||
src: FrameFormat::Yuy2_422,
|
|
||||||
destination: "RGB888".to_string(),
|
|
||||||
error: "Assertion failure, the YUV stream isn't 4:2:2! (wrong number of bytes)"
|
|
||||||
.to_string(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
for chunk in data.chunks_exact(4) {
|
|
||||||
let y0 = f32::from(chunk[0]);
|
|
||||||
let u = f32::from(chunk[1]);
|
|
||||||
let y1 = f32::from(chunk[2]);
|
|
||||||
let v = f32::from(chunk[3]);
|
|
||||||
|
|
||||||
let r0 = y0 + 1.370_705 * (v - 128.);
|
|
||||||
let g0 = y0 - 0.698_001 * (v - 128.) - 0.337_633 * (u - 128.);
|
|
||||||
let b0 = y0 + 1.732_446 * (u - 128.);
|
|
||||||
|
|
||||||
let r1 = y1 + 1.370_705 * (v - 128.);
|
|
||||||
let g1 = y1 - 0.698_001 * (v - 128.) - 0.337_633 * (u - 128.);
|
|
||||||
let b1 = y1 + 1.732_446 * (u - 128.);
|
|
||||||
|
|
||||||
if rgba {
|
|
||||||
buf.extend_from_slice(&[
|
|
||||||
r0 as u8, g0 as u8, b0 as u8, 255, r1 as u8, g1 as u8, b1 as u8, 255,
|
|
||||||
]);
|
|
||||||
} else {
|
|
||||||
buf.extend_from_slice(&[r0 as u8, g0 as u8, b0 as u8, r1 as u8, g1 as u8, b1 as u8]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dest.copy_from_slice(&buf);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// equation from https://en.wikipedia.org/wiki/YUV#Converting_between_Y%E2%80%B2UV_and_RGB
|
|
||||||
/// Convert `YCbCr` 4:4:4 to a RGB888. [For further reading](https://en.wikipedia.org/wiki/YUV#Converting_between_Y%E2%80%B2UV_and_RGB)
|
|
||||||
#[allow(clippy::many_single_char_names)]
|
|
||||||
#[allow(clippy::cast_possible_truncation)]
|
|
||||||
#[allow(clippy::cast_sign_loss)]
|
|
||||||
#[must_use]
|
|
||||||
#[inline]
|
|
||||||
pub fn yuyv444_to_rgb(y: i32, u: i32, v: i32) -> [u8; 3] {
|
|
||||||
let c298 = (y - 16) * 298;
|
|
||||||
let d = u - 128;
|
|
||||||
let e = v - 128;
|
|
||||||
let r = ((c298 + 409 * e + 128) >> 8).clamp(0, 255) as u8;
|
|
||||||
let g = ((c298 - 100 * d - 208 * e + 128) >> 8).clamp(0, 255) as u8;
|
|
||||||
let b = ((c298 + 516 * d + 128) >> 8).clamp(0, 255) as u8;
|
|
||||||
[r, g, b]
|
|
||||||
}
|
|
||||||
|
|
||||||
// equation from https://en.wikipedia.org/wiki/YUV#Converting_between_Y%E2%80%B2UV_and_RGB
|
|
||||||
/// Convert `YCbCr` 4:4:4 to a RGBA8888. [For further reading](https://en.wikipedia.org/wiki/YUV#Converting_between_Y%E2%80%B2UV_and_RGB)
|
|
||||||
///
|
|
||||||
/// Equivalent to [`yuyv444_to_rgb`] but with an alpha channel attached.
|
|
||||||
#[allow(clippy::many_single_char_names)]
|
|
||||||
#[must_use]
|
|
||||||
#[inline]
|
|
||||||
pub fn yuyv444_to_rgba(y: i32, u: i32, v: i32) -> [u8; 4] {
|
|
||||||
let [r, g, b] = yuyv444_to_rgb(y, u, v);
|
|
||||||
[r, g, b, 255]
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts a Yuv422 4:2:0 bi-planar (NV12) 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 wrong.
|
|
||||||
#[inline]
|
|
||||||
pub fn nv12_to_rgb(
|
|
||||||
resolution: Resolution,
|
|
||||||
data: &[u8],
|
|
||||||
rgba: bool,
|
|
||||||
) -> Result<Vec<u8>, NokhwaError> {
|
|
||||||
let pxsize = if rgba { 4 } else { 3 };
|
|
||||||
let mut dest = vec![0; (pxsize * resolution.width() * resolution.height()) as usize];
|
|
||||||
buf_nv12_to_rgb(resolution, data, &mut dest, rgba)?;
|
|
||||||
Ok(dest)
|
|
||||||
}
|
|
||||||
|
|
||||||
// this depresses me
|
|
||||||
// like, everytime i open this codebase all the life is sucked out of me
|
|
||||||
// i hate it
|
|
||||||
/// Converts a Yuv422 4:2:0 bi-planar (NV12) datastream to a RGB888 Stream and outputs it into a destination buffer. [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 wrong.
|
|
||||||
#[allow(clippy::similar_names)]
|
|
||||||
#[inline]
|
|
||||||
pub fn buf_nv12_to_rgb(
|
|
||||||
resolution: Resolution,
|
|
||||||
data: &[u8],
|
|
||||||
out: &mut [u8],
|
|
||||||
rgba: bool,
|
|
||||||
) -> Result<(), NokhwaError> {
|
|
||||||
if resolution.width() % 2 != 0 || resolution.height() % 2 != 0 {
|
|
||||||
return Err(NokhwaError::ProcessFrameError {
|
|
||||||
src: FrameFormat::Nv12,
|
|
||||||
destination: "RGB".to_string(),
|
|
||||||
error: "bad resolution".to_string(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if data.len() != ((resolution.width() * resolution.height() * 3) / 2) as usize {
|
|
||||||
return Err(NokhwaError::ProcessFrameError {
|
|
||||||
src: FrameFormat::Nv12,
|
|
||||||
destination: "RGB".to_string(),
|
|
||||||
error: "bad input buffer size".to_string(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let pxsize = if rgba { 4 } else { 3 };
|
|
||||||
|
|
||||||
if out.len() != (pxsize * resolution.width() * resolution.height()) as usize {
|
|
||||||
return Err(NokhwaError::ProcessFrameError {
|
|
||||||
src: FrameFormat::Nv12,
|
|
||||||
destination: "RGB".to_string(),
|
|
||||||
error: "bad output buffer size".to_string(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let rgba_size = if rgba { 4 } else { 3 };
|
|
||||||
|
|
||||||
let y_section = (resolution.width() * resolution.height()) as usize;
|
|
||||||
|
|
||||||
let width_usize = resolution.width() as usize;
|
|
||||||
// let height_usize = resolution.height() as usize;
|
|
||||||
|
|
||||||
for (hidx, horizontal_row) in data[0..y_section].chunks_exact(width_usize).enumerate() {
|
|
||||||
for (cidx, column) in horizontal_row.chunks_exact(2).enumerate() {
|
|
||||||
let u = data[(y_section) + ((hidx / 2) * width_usize) + (cidx * 2)];
|
|
||||||
let v = data[(y_section) + ((hidx / 2) * width_usize) + (cidx * 2) + 1];
|
|
||||||
|
|
||||||
let y0 = column[0];
|
|
||||||
let y1 = column[1];
|
|
||||||
let base_index = (hidx * width_usize * rgba_size) + cidx * rgba_size * 2;
|
|
||||||
|
|
||||||
if rgba {
|
|
||||||
let px0 = yuyv444_to_rgba(y0 as i32, u as i32, v as i32);
|
|
||||||
let px1 = yuyv444_to_rgba(y1 as i32, u as i32, v as i32);
|
|
||||||
|
|
||||||
out[base_index] = px0[0];
|
|
||||||
out[base_index + 1] = px0[1];
|
|
||||||
out[base_index + 2] = px0[2];
|
|
||||||
out[base_index + 3] = px0[3];
|
|
||||||
out[base_index + 4] = px1[0];
|
|
||||||
out[base_index + 5] = px1[1];
|
|
||||||
out[base_index + 6] = px1[2];
|
|
||||||
out[base_index + 7] = px1[3];
|
|
||||||
} else {
|
|
||||||
let px0 = yuyv444_to_rgb(y0 as i32, u as i32, v as i32);
|
|
||||||
let px1 = yuyv444_to_rgb(y1 as i32, u as i32, v as i32);
|
|
||||||
|
|
||||||
out[base_index] = px0[0];
|
|
||||||
out[base_index + 1] = px0[1];
|
|
||||||
out[base_index + 2] = px0[2];
|
|
||||||
out[base_index + 3] = px1[0];
|
|
||||||
out[base_index + 4] = px1[1];
|
|
||||||
out[base_index + 5] = px1[2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
use core::ops::AddAssign;
|
use core::ops::AddAssign;
|
||||||
|
|
||||||
pub fn min_max_range<N: Copy + PartialOrd + AddAssign<N> + Sized>(min: N, max: N, step: N) -> Vec<N> {
|
pub fn min_max_range<N: Copy + PartialOrd + AddAssign<N> + Sized>(
|
||||||
|
min: N,
|
||||||
|
max: N,
|
||||||
|
step: N,
|
||||||
|
) -> Vec<N> {
|
||||||
let mut counter = min;
|
let mut counter = min;
|
||||||
let mut nums = vec![min];
|
let mut nums = vec![min];
|
||||||
|
|
||||||
@@ -8,7 +12,7 @@ pub fn min_max_range<N: Copy + PartialOrd + AddAssign<N> + Sized>(min: N, max: N
|
|||||||
counter += step;
|
counter += step;
|
||||||
|
|
||||||
if counter > max {
|
if counter > max {
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
nums.push(counter);
|
nums.push(counter);
|
||||||
@@ -16,3 +20,10 @@ pub fn min_max_range<N: Copy + PartialOrd + AddAssign<N> + Sized>(min: N, max: N
|
|||||||
|
|
||||||
nums
|
nums
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait Distance<T>
|
||||||
|
where
|
||||||
|
T: PartialEq,
|
||||||
|
{
|
||||||
|
fn distance_from(&self, other: &Self) -> T;
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ use nokhwa_bindings_macos::{
|
|||||||
AVCaptureVideoDataOutput,
|
AVCaptureVideoDataOutput,
|
||||||
};
|
};
|
||||||
use nokhwa_core::{
|
use nokhwa_core::{
|
||||||
buffer::Buffer,
|
frame_buffer::FrameBuffer,
|
||||||
error::NokhwaError,
|
error::NokhwaError,
|
||||||
pixel_format::RgbFormat,
|
pixel_format::RgbFormat,
|
||||||
traits::CaptureTrait,
|
traits::CaptureTrait,
|
||||||
@@ -278,11 +278,11 @@ impl CaptureTrait for AVFoundationCaptureDevice {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn frame(&mut self) -> Result<Buffer, NokhwaError> {
|
fn frame(&mut self) -> Result<FrameBuffer, NokhwaError> {
|
||||||
self.refresh_camera_format()?;
|
self.refresh_camera_format()?;
|
||||||
let cfmt = self.camera_format();
|
let cfmt = self.camera_format();
|
||||||
let b = self.frame_raw()?;
|
let b = self.frame_raw()?;
|
||||||
let buffer = Buffer::new(cfmt.resolution(), b.as_ref(), cfmt.format());
|
let buffer = FrameBuffer::new(cfmt.resolution(), b.as_ref(), cfmt.format());
|
||||||
let _ = self.frame_buffer_receiver.drain();
|
let _ = self.frame_buffer_receiver.drain();
|
||||||
Ok(buffer)
|
Ok(buffer)
|
||||||
}
|
}
|
||||||
@@ -476,7 +476,7 @@ impl CaptureTrait for AVFoundationCaptureDevice {
|
|||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn frame(&mut self) -> Result<Buffer, NokhwaError> {
|
fn frame(&mut self) -> Result<FrameBuffer, NokhwaError> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use nokhwa_core::format_request::FormatRequest;
|
|||||||
use serde::{de, Serialize};
|
use serde::{de, Serialize};
|
||||||
use wasm_bindgen_futures::JsFuture;
|
use wasm_bindgen_futures::JsFuture;
|
||||||
use web_sys::{window, MediaDeviceInfo, MediaDevices, MediaStream, MediaStreamConstraints, MediaStreamTrack, MediaTrackConstraints, Navigator};
|
use web_sys::{window, MediaDeviceInfo, MediaDevices, MediaStream, MediaStreamConstraints, MediaStreamTrack, MediaTrackConstraints, Navigator};
|
||||||
use nokhwa_core::buffer::Buffer;
|
use nokhwa_core::frame_buffer::FrameBuffer;
|
||||||
use nokhwa_core::properties::{CameraControl, ControlValueSetter, KnownCameraControl};
|
use nokhwa_core::properties::{CameraControl, ControlValueSetter, KnownCameraControl};
|
||||||
use nokhwa_core::error::NokhwaError;
|
use nokhwa_core::error::NokhwaError;
|
||||||
use nokhwa_core::frame_format::FrameFormat;
|
use nokhwa_core::frame_format::FrameFormat;
|
||||||
@@ -373,7 +373,7 @@ impl CaptureTrait for BrowserCaptureDevice {
|
|||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn frame(&mut self) -> Result<Buffer, NokhwaError> {
|
fn frame(&mut self) -> Result<FrameBuffer, NokhwaError> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -422,7 +422,7 @@ impl AsyncCaptureTrait for BrowserCaptureDevice {
|
|||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn frame_async(&mut self) -> Result<Buffer, NokhwaError> {
|
async fn frame_async(&mut self) -> Result<FrameBuffer, NokhwaError> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
use nokhwa_bindings_windows::wmf::MediaFoundationDevice;
|
use nokhwa_bindings_windows::wmf::MediaFoundationDevice;
|
||||||
use nokhwa_core::{
|
use nokhwa_core::{
|
||||||
buffer::Buffer,
|
frame_buffer::FrameBuffer,
|
||||||
error::NokhwaError,
|
error::NokhwaError,
|
||||||
pixel_format::RgbFormat,
|
pixel_format::RgbFormat,
|
||||||
traits::CaptureTrait,
|
traits::CaptureTrait,
|
||||||
@@ -242,10 +242,10 @@ impl CaptureTrait for MediaFoundationCaptureDevice {
|
|||||||
self.inner.is_stream_open()
|
self.inner.is_stream_open()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn frame(&mut self) -> Result<Buffer, NokhwaError> {
|
fn frame(&mut self) -> Result<FrameBuffer, NokhwaError> {
|
||||||
self.refresh_camera_format()?;
|
self.refresh_camera_format()?;
|
||||||
let self_ctrl = self.camera_format();
|
let self_ctrl = self.camera_format();
|
||||||
Ok(Buffer::new(
|
Ok(FrameBuffer::new(
|
||||||
self_ctrl.resolution(),
|
self_ctrl.resolution(),
|
||||||
&self.inner.raw_bytes()?,
|
&self.inner.raw_bytes()?,
|
||||||
self_ctrl.format(),
|
self_ctrl.format(),
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
use nokhwa_core::types::RequestedFormatType;
|
use nokhwa_core::types::RequestedFormatType;
|
||||||
use nokhwa_core::{
|
use nokhwa_core::{
|
||||||
buffer::Buffer,
|
frame_buffer::FrameBuffer,
|
||||||
error::NokhwaError,
|
error::NokhwaError,
|
||||||
traits::CaptureTrait,
|
traits::CaptureTrait,
|
||||||
types::{
|
types::{
|
||||||
@@ -525,7 +525,7 @@ impl CaptureTrait for OpenCvCaptureDevice {
|
|||||||
self.video_capture.is_opened().unwrap_or(false)
|
self.video_capture.is_opened().unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn frame(&mut self) -> Result<Buffer, NokhwaError> {
|
fn frame(&mut self) -> Result<FrameBuffer, NokhwaError> {
|
||||||
let camera_resolution = self.camera_format.resolution();
|
let camera_resolution = self.camera_format.resolution();
|
||||||
let image_data = {
|
let image_data = {
|
||||||
let mut data = self.frame_raw()?.to_vec();
|
let mut data = self.frame_raw()?.to_vec();
|
||||||
@@ -535,7 +535,7 @@ impl CaptureTrait for OpenCvCaptureDevice {
|
|||||||
);
|
);
|
||||||
data
|
data
|
||||||
};
|
};
|
||||||
Ok(Buffer::new(
|
Ok(FrameBuffer::new(
|
||||||
camera_resolution,
|
camera_resolution,
|
||||||
&image_data,
|
&image_data,
|
||||||
self.camera_format.format(),
|
self.camera_format.format(),
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ use nokhwa_bindings_linux::{
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
use nokhwa_core::{
|
use nokhwa_core::{
|
||||||
capture::{Open, Setting},
|
camera::{Open, Setting},
|
||||||
error::{NokhwaError, NokhwaResult},
|
error::{NokhwaError, NokhwaResult},
|
||||||
frame_format::FrameFormat,
|
frame_format::FrameFormat,
|
||||||
properties::CameraProperties,
|
properties::CameraProperties,
|
||||||
|
|||||||
+2
-2
@@ -18,7 +18,7 @@ use nokhwa_core::format_request::FormatFilter;
|
|||||||
use nokhwa_core::frame_format::SourceFrameFormat;
|
use nokhwa_core::frame_format::SourceFrameFormat;
|
||||||
use nokhwa_core::traits::Backend;
|
use nokhwa_core::traits::Backend;
|
||||||
use nokhwa_core::{
|
use nokhwa_core::{
|
||||||
buffer::Buffer,
|
frame_buffer::FrameBuffer,
|
||||||
error::NokhwaError,
|
error::NokhwaError,
|
||||||
pixel_format::FormatDecoder,
|
pixel_format::FormatDecoder,
|
||||||
traits::CaptureTrait,
|
traits::CaptureTrait,
|
||||||
@@ -136,7 +136,7 @@ impl CaptureTrait for Camera {
|
|||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn frame(&mut self) -> Result<Buffer, NokhwaError> {
|
fn frame(&mut self) -> Result<FrameBuffer, NokhwaError> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -48,7 +48,7 @@ pub mod threaded;
|
|||||||
|
|
||||||
pub use camera::Camera;
|
pub use camera::Camera;
|
||||||
pub use init::*;
|
pub use init::*;
|
||||||
pub use nokhwa_core::buffer::Buffer;
|
pub use nokhwa_core::frame_buffer::FrameBuffer;
|
||||||
pub use nokhwa_core::error::NokhwaError;
|
pub use nokhwa_core::error::NokhwaError;
|
||||||
pub use query::*;
|
pub use query::*;
|
||||||
#[cfg(feature = "output-threaded")]
|
#[cfg(feature = "output-threaded")]
|
||||||
@@ -68,5 +68,5 @@ pub mod camera_traits {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub mod buffer {
|
pub mod buffer {
|
||||||
pub use nokhwa_core::buffer::*;
|
pub use nokhwa_core::frame_buffer::*;
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-15
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
use crate::Camera;
|
use crate::Camera;
|
||||||
use nokhwa_core::{
|
use nokhwa_core::{
|
||||||
buffer::Buffer,
|
frame_buffer::FrameBuffer,
|
||||||
error::NokhwaError,
|
error::NokhwaError,
|
||||||
types::{
|
types::{
|
||||||
ApiBackend, CameraFormat, CameraIndex, CameraInfo,
|
ApiBackend, CameraFormat, CameraIndex, CameraInfo,
|
||||||
@@ -36,11 +36,11 @@ use nokhwa_core::properties::{CameraControl, ControlValueSetter, KnownCameraCont
|
|||||||
type AtomicLock<T> = Arc<Mutex<T>>;
|
type AtomicLock<T> = Arc<Mutex<T>>;
|
||||||
pub type CallbackFn = fn(
|
pub type CallbackFn = fn(
|
||||||
_camera: &Arc<Mutex<Camera>>,
|
_camera: &Arc<Mutex<Camera>>,
|
||||||
_frame_callback: &Arc<Mutex<Option<Box<dyn FnMut(Buffer) + Send + 'static>>>>,
|
_frame_callback: &Arc<Mutex<Option<Box<dyn FnMut(FrameBuffer) + Send + 'static>>>>,
|
||||||
_last_frame_captured: &Arc<Mutex<Buffer>>,
|
_last_frame_captured: &Arc<Mutex<FrameBuffer>>,
|
||||||
_die_bool: &Arc<AtomicBool>,
|
_die_bool: &Arc<AtomicBool>,
|
||||||
);
|
);
|
||||||
type HeldCallbackType = Arc<Mutex<Box<dyn FnMut(Buffer) + Send + 'static>>>;
|
type HeldCallbackType = Arc<Mutex<Box<dyn FnMut(FrameBuffer) + Send + 'static>>>;
|
||||||
|
|
||||||
/// Creates a camera that runs in a different thread that you can use a callback to access the frames of.
|
/// Creates a camera that runs in a different thread that you can use a callback to access the frames of.
|
||||||
/// It uses a `Arc` and a `Mutex` to ensure that this feels like a normal camera, but callback based.
|
/// It uses a `Arc` and a `Mutex` to ensure that this feels like a normal camera, but callback based.
|
||||||
@@ -58,7 +58,7 @@ type HeldCallbackType = Arc<Mutex<Box<dyn FnMut(Buffer) + Send + 'static>>>;
|
|||||||
pub struct CallbackCamera {
|
pub struct CallbackCamera {
|
||||||
camera: AtomicLock<Camera>,
|
camera: AtomicLock<Camera>,
|
||||||
frame_callback: HeldCallbackType,
|
frame_callback: HeldCallbackType,
|
||||||
last_frame_captured: AtomicLock<Buffer>,
|
last_frame_captured: AtomicLock<FrameBuffer>,
|
||||||
die_bool: Arc<AtomicBool>,
|
die_bool: Arc<AtomicBool>,
|
||||||
current_camera: CameraInfo,
|
current_camera: CameraInfo,
|
||||||
handle: AtomicLock<Option<JoinHandle<()>>>,
|
handle: AtomicLock<Option<JoinHandle<()>>>,
|
||||||
@@ -72,7 +72,7 @@ impl CallbackCamera {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
index: CameraIndex,
|
index: CameraIndex,
|
||||||
format: RequestedFormat,
|
format: RequestedFormat,
|
||||||
callback: impl FnMut(Buffer) + Send + 'static,
|
callback: impl FnMut(FrameBuffer) + Send + 'static,
|
||||||
) -> Result<Self, NokhwaError> {
|
) -> Result<Self, NokhwaError> {
|
||||||
let arc_camera = Arc::new(Mutex::new(Camera::new(index, format)?));
|
let arc_camera = Arc::new(Mutex::new(Camera::new(index, format)?));
|
||||||
let current_camera = arc_camera
|
let current_camera = arc_camera
|
||||||
@@ -86,7 +86,7 @@ impl CallbackCamera {
|
|||||||
Ok(CallbackCamera {
|
Ok(CallbackCamera {
|
||||||
camera: arc_camera,
|
camera: arc_camera,
|
||||||
frame_callback: Arc::new(Mutex::new(Box::new(callback))),
|
frame_callback: Arc::new(Mutex::new(Box::new(callback))),
|
||||||
last_frame_captured: Arc::new(Mutex::new(Buffer::new(
|
last_frame_captured: Arc::new(Mutex::new(FrameBuffer::new(
|
||||||
Resolution::new(0, 0),
|
Resolution::new(0, 0),
|
||||||
&vec![],
|
&vec![],
|
||||||
FrameFormat::GRAY,
|
FrameFormat::GRAY,
|
||||||
@@ -100,12 +100,12 @@ impl CallbackCamera {
|
|||||||
/// Allows creation of a [`Camera`] with a custom backend. This is useful if you are creating e.g. a custom module.
|
/// Allows creation of a [`Camera`] with a custom backend. This is useful if you are creating e.g. a custom module.
|
||||||
///
|
///
|
||||||
/// You **must** have set a format beforehand.
|
/// You **must** have set a format beforehand.
|
||||||
pub fn with_custom(camera: Camera, callback: impl FnMut(Buffer) + Send + 'static) -> Self {
|
pub fn with_custom(camera: Camera, callback: impl FnMut(FrameBuffer) + Send + 'static) -> Self {
|
||||||
let current_camera = camera.info().clone();
|
let current_camera = camera.info().clone();
|
||||||
CallbackCamera {
|
CallbackCamera {
|
||||||
camera: Arc::new(Mutex::new(camera)),
|
camera: Arc::new(Mutex::new(camera)),
|
||||||
frame_callback: Arc::new(Mutex::new(Box::new(callback))),
|
frame_callback: Arc::new(Mutex::new(Box::new(callback))),
|
||||||
last_frame_captured: Arc::new(Mutex::new(Buffer::new(
|
last_frame_captured: Arc::new(Mutex::new(FrameBuffer::new(
|
||||||
Resolution::new(0, 0),
|
Resolution::new(0, 0),
|
||||||
&vec![],
|
&vec![],
|
||||||
FrameFormat::GRAY,
|
FrameFormat::GRAY,
|
||||||
@@ -183,7 +183,7 @@ impl CallbackCamera {
|
|||||||
*self
|
*self
|
||||||
.last_frame_captured
|
.last_frame_captured
|
||||||
.lock()
|
.lock()
|
||||||
.map_err(|why| NokhwaError::GeneralError(why.to_string()))? = Buffer::new(
|
.map_err(|why| NokhwaError::GeneralError(why.to_string()))? = FrameBuffer::new(
|
||||||
new_fmt.resolution(),
|
new_fmt.resolution(),
|
||||||
&Vec::default(),
|
&Vec::default(),
|
||||||
self.camera_format()?.format(),
|
self.camera_format()?.format(),
|
||||||
@@ -266,7 +266,7 @@ impl CallbackCamera {
|
|||||||
.last_frame_captured
|
.last_frame_captured
|
||||||
.lock()
|
.lock()
|
||||||
.map_err(|why| NokhwaError::GeneralError(why.to_string()))? =
|
.map_err(|why| NokhwaError::GeneralError(why.to_string()))? =
|
||||||
Buffer::new(new_res, &Vec::default(), self.camera_format()?.format());
|
FrameBuffer::new(new_res, &Vec::default(), self.camera_format()?.format());
|
||||||
self.camera
|
self.camera
|
||||||
.lock()
|
.lock()
|
||||||
.map_err(|why| NokhwaError::SetPropertyError {
|
.map_err(|why| NokhwaError::SetPropertyError {
|
||||||
@@ -479,7 +479,7 @@ impl CallbackCamera {
|
|||||||
/// Sets the frame callback to the new specified function. This function will be called instead of the previous one(s).
|
/// Sets the frame callback to the new specified function. This function will be called instead of the previous one(s).
|
||||||
pub fn set_callback(
|
pub fn set_callback(
|
||||||
&mut self,
|
&mut self,
|
||||||
callback: impl FnMut(Buffer) + Send + 'static,
|
callback: impl FnMut(FrameBuffer) + Send + 'static,
|
||||||
) -> Result<(), NokhwaError> {
|
) -> Result<(), NokhwaError> {
|
||||||
*self
|
*self
|
||||||
.frame_callback
|
.frame_callback
|
||||||
@@ -494,7 +494,7 @@ impl CallbackCamera {
|
|||||||
/// Polls the camera for a frame, analogous to [`Camera::frame`](crate::Camera::frame)
|
/// Polls the camera for a frame, analogous to [`Camera::frame`](crate::Camera::frame)
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// This will error if the camera fails to capture a frame.
|
/// This will error if the camera fails to capture a frame.
|
||||||
pub fn poll_frame(&mut self) -> Result<Buffer, NokhwaError> {
|
pub fn poll_frame(&mut self) -> Result<FrameBuffer, NokhwaError> {
|
||||||
let frame = self
|
let frame = self
|
||||||
.camera
|
.camera
|
||||||
.lock()
|
.lock()
|
||||||
@@ -508,7 +508,7 @@ impl CallbackCamera {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the last frame captured by the camera.
|
/// Gets the last frame captured by the camera.
|
||||||
pub fn last_frame(&self) -> Result<Buffer, NokhwaError> {
|
pub fn last_frame(&self) -> Result<FrameBuffer, NokhwaError> {
|
||||||
Ok(self
|
Ok(self
|
||||||
.last_frame_captured
|
.last_frame_captured
|
||||||
.lock()
|
.lock()
|
||||||
@@ -549,7 +549,7 @@ impl Drop for CallbackCamera {
|
|||||||
fn camera_frame_thread_loop(
|
fn camera_frame_thread_loop(
|
||||||
camera: AtomicLock<Camera>,
|
camera: AtomicLock<Camera>,
|
||||||
frame_callback: HeldCallbackType,
|
frame_callback: HeldCallbackType,
|
||||||
last_frame_captured: AtomicLock<Buffer>,
|
last_frame_captured: AtomicLock<FrameBuffer>,
|
||||||
die_bool: Arc<AtomicBool>,
|
die_bool: Arc<AtomicBool>,
|
||||||
) {
|
) {
|
||||||
loop {
|
loop {
|
||||||
|
|||||||
Reference in New Issue
Block a user