source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
dependencies = [
- "cfg-if",
+ "cfg-if 1.0.0",
"once_cell",
"version_check",
"zerocopy",
dependencies = [
"alsa-sys",
"bitflags 2.6.0",
- "cfg-if",
+ "cfg-if 1.0.0",
"libc",
]
checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
dependencies = [
"addr2line",
- "cfg-if",
+ "cfg-if 1.0.0",
"libc",
"miniz_oxide 0.8.0",
"object",
"windows-targets 0.52.6",
]
+[[package]]
+name = "bindgen"
+version = "0.65.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5"
+dependencies = [
+ "bitflags 1.3.2",
+ "cexpr",
+ "clang-sys",
+ "lazy_static",
+ "lazycell",
+ "log",
+ "peeking_take_while",
+ "prettyplease",
+ "proc-macro2",
+ "quote",
+ "regex",
+ "rustc-hash",
+ "shlex",
+ "syn 2.0.87",
+ "which",
+]
+
[[package]]
name = "bindgen"
version = "0.70.1"
[[package]]
name = "bytemuck"
-version = "1.18.0"
+version = "1.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94bbb0ad554ad961ddc5da507a12a29b14e4ae5bda06b19f575a3e6079d2e2ae"
+checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4"
[[package]]
name = "byteorder"
"target-lexicon",
]
+[[package]]
+name = "cfg-if"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
+
[[package]]
name = "cfg-if"
version = "1.0.0"
"libloading 0.8.5",
]
+[[package]]
+name = "cocoa"
+version = "0.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c49e86fc36d5704151f5996b7b3795385f50ce09e3be0f47a0cfde869681cf8"
+dependencies = [
+ "bitflags 1.3.2",
+ "block",
+ "core-foundation 0.7.0",
+ "core-graphics 0.19.2",
+ "foreign-types 0.3.2",
+ "libc",
+ "objc",
+]
+
+[[package]]
+name = "cocoa-foundation"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81411967c50ee9a1fc11365f8c585f863a22a9697c89239c452292c40ba79b0d"
+dependencies = [
+ "bitflags 2.6.0",
+ "block",
+ "core-foundation 0.10.1",
+ "core-graphics-types 0.2.0",
+ "objc",
+]
+
[[package]]
name = "codespan-reporting"
version = "0.11.1"
"memchr",
]
+[[package]]
+name = "core-foundation"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171"
+dependencies = [
+ "core-foundation-sys 0.7.0",
+ "libc",
+]
+
[[package]]
name = "core-foundation"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
dependencies = [
- "core-foundation-sys",
+ "core-foundation-sys 0.8.7",
+ "libc",
+]
+
+[[package]]
+name = "core-foundation"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6"
+dependencies = [
+ "core-foundation-sys 0.8.7",
"libc",
]
+[[package]]
+name = "core-foundation-sys"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac"
+
[[package]]
name = "core-foundation-sys"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
+[[package]]
+name = "core-graphics"
+version = "0.19.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b3889374e6ea6ab25dba90bb5d96202f61108058361f6dc72e8b03e6f8bbe923"
+dependencies = [
+ "bitflags 1.3.2",
+ "core-foundation 0.7.0",
+ "foreign-types 0.3.2",
+ "libc",
+]
+
[[package]]
name = "core-graphics"
version = "0.22.3"
checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb"
dependencies = [
"bitflags 1.3.2",
- "core-foundation",
- "core-graphics-types",
+ "core-foundation 0.9.4",
+ "core-graphics-types 0.1.3",
"foreign-types 0.3.2",
"libc",
]
checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf"
dependencies = [
"bitflags 1.3.2",
- "core-foundation",
+ "core-foundation 0.9.4",
+ "libc",
+]
+
+[[package]]
+name = "core-graphics-types"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb"
+dependencies = [
+ "bitflags 2.6.0",
+ "core-foundation 0.10.1",
+ "libc",
+]
+
+[[package]]
+name = "core-media-sys"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "273bf3fc5bf51fd06a7766a84788c1540b6527130a0bce39e00567d6ab9f31f1"
+dependencies = [
+ "cfg-if 0.1.10",
+ "core-foundation-sys 0.7.0",
+ "libc",
+]
+
+[[package]]
+name = "core-video-sys"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34ecad23610ad9757664d644e369246edde1803fcb43ed72876565098a5d3828"
+dependencies = [
+ "cfg-if 0.1.10",
+ "core-foundation-sys 0.7.0",
+ "core-graphics 0.19.2",
"libc",
+ "metal 0.18.0",
+ "objc",
]
[[package]]
checksum = "321077172d79c662f64f5071a03120748d5bb652f5231570141be24cfcd2bace"
dependencies = [
"bitflags 1.3.2",
- "core-foundation-sys",
+ "core-foundation-sys 0.8.7",
"coreaudio-sys",
]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ce857aa0b77d77287acc1ac3e37a05a8c95a2af3647d23b15f263bdaeb7562b"
dependencies = [
- "bindgen",
+ "bindgen 0.70.1",
]
[[package]]
checksum = "873dab07c8f743075e57f524c583985fbaf745602acbe916a01539364369a779"
dependencies = [
"alsa",
- "core-foundation-sys",
+ "core-foundation-sys 0.8.7",
"coreaudio-rs",
"dasp_sample",
"jni",
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
dependencies = [
- "cfg-if",
+ "cfg-if 1.0.0",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
+[[package]]
+name = "dunce"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
+
[[package]]
name = "either"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+[[package]]
+name = "errno"
+version = "0.3.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
+dependencies = [
+ "libc",
+ "windows-sys 0.61.2",
+]
+
[[package]]
name = "exr"
version = "1.73.0"
"miniz_oxide 0.8.0",
]
+[[package]]
+name = "flume"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+ "nanorand",
+ "spin",
+]
+
[[package]]
name = "foreign-types"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [
- "cfg-if",
+ "cfg-if 1.0.0",
+ "js-sys",
"libc",
"wasi 0.11.0+wasi-snapshot-preview1",
+ "wasm-bindgen",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
dependencies = [
- "cfg-if",
+ "cfg-if 1.0.0",
"libc",
"r-efi",
"wasi 0.14.7+wasi-0.2.4",
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888"
dependencies = [
- "cfg-if",
+ "cfg-if 1.0.0",
"crunchy",
]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
+[[package]]
+name = "home"
+version = "0.5.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d"
+dependencies = [
+ "windows-sys 0.61.2",
+]
+
[[package]]
name = "hound"
version = "3.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
dependencies = [
- "cfg-if",
+ "cfg-if 1.0.0",
"js-sys",
"wasm-bindgen",
"web-sys",
checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97"
dependencies = [
"cesu8",
- "cfg-if",
+ "cfg-if 1.0.0",
"combine",
"jni-sys",
"log",
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+[[package]]
+name = "lazycell"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
+
[[package]]
name = "lebe"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
dependencies = [
- "cfg-if",
+ "cfg-if 1.0.0",
"winapi",
]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
dependencies = [
- "cfg-if",
+ "cfg-if 1.0.0",
"windows-targets 0.52.6",
]
"redox_syscall 0.4.1",
]
+[[package]]
+name = "linux-raw-sys"
+version = "0.4.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
+
[[package]]
name = "lock_api"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519"
dependencies = [
- "cfg-if",
+ "cfg-if 1.0.0",
]
[[package]]
"autocfg",
]
+[[package]]
+name = "metal"
+version = "0.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e198a0ee42bdbe9ef2c09d0b9426f3b2b47d90d93a4a9b0395c4cea605e92dc0"
+dependencies = [
+ "bitflags 1.3.2",
+ "block",
+ "cocoa",
+ "core-graphics 0.19.2",
+ "foreign-types 0.3.2",
+ "log",
+ "objc",
+]
+
[[package]]
name = "metal"
version = "0.26.0"
dependencies = [
"bitflags 2.6.0",
"block",
- "core-graphics-types",
+ "core-graphics-types 0.1.3",
"foreign-types 0.5.0",
"log",
"objc",
"windows-sys 0.48.0",
]
+[[package]]
+name = "mozjpeg"
+version = "0.10.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7891b80aaa86097d38d276eb98b3805d6280708c4e0a1e6f6aed9380c51fec9"
+dependencies = [
+ "arrayvec",
+ "bytemuck",
+ "libc",
+ "mozjpeg-sys",
+ "rgb",
+]
+
+[[package]]
+name = "mozjpeg-sys"
+version = "2.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f0dc668bf9bf888c88e2fb1ab16a406d2c380f1d082b20d51dd540ab2aa70c1"
+dependencies = [
+ "cc",
+ "dunce",
+ "libc",
+ "nasm-rs",
+]
+
[[package]]
name = "naga"
version = "0.13.0"
"unicode-xid",
]
+[[package]]
+name = "nanorand"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3"
+dependencies = [
+ "getrandom 0.2.15",
+]
+
+[[package]]
+name = "nasm-rs"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34f676553b60ccbb76f41f9ae8f2428dac3f259ff8f1c2468a174778d06a1af9"
+dependencies = [
+ "jobserver",
+ "log",
+]
+
[[package]]
name = "ndk"
version = "0.7.0"
checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069"
dependencies = [
"bitflags 1.3.2",
- "cfg-if",
+ "cfg-if 1.0.0",
"libc",
"memoffset",
]
dependencies = [
"autocfg",
"bitflags 1.3.2",
- "cfg-if",
+ "cfg-if 1.0.0",
"libc",
"memoffset",
]
+[[package]]
+name = "nokhwa"
+version = "0.10.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4cae50786bfa1214ed441f98addbea51ca1b9aaa9e4bf5369cda36654b3efaa"
+dependencies = [
+ "flume",
+ "image",
+ "nokhwa-bindings-linux",
+ "nokhwa-bindings-macos",
+ "nokhwa-bindings-windows",
+ "nokhwa-core",
+ "paste",
+ "thiserror 2.0.16",
+]
+
+[[package]]
+name = "nokhwa-bindings-linux"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4bd666aaa41d14357817bd9a981773a73c4d00b34d344cfc244e47ebd397b1ec"
+dependencies = [
+ "nokhwa-core",
+ "v4l",
+]
+
+[[package]]
+name = "nokhwa-bindings-macos"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de78eb4a2d47a68f490899aa0516070d7a972f853ec2bb374ab53be0bd39b60f"
+dependencies = [
+ "block",
+ "cocoa-foundation",
+ "core-foundation 0.10.1",
+ "core-media-sys",
+ "core-video-sys",
+ "flume",
+ "nokhwa-core",
+ "objc",
+ "once_cell",
+]
+
+[[package]]
+name = "nokhwa-bindings-windows"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "899799275c93ef69bbe8cb888cf6f8249abe751cbc50be5299105022aec14a1c"
+dependencies = [
+ "nokhwa-core",
+ "once_cell",
+ "windows 0.62.2",
+]
+
+[[package]]
+name = "nokhwa-core"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "109975552bbd690894f613bce3d408222911e317197c72b2e8b9a1912dc261ae"
+dependencies = [
+ "bytes",
+ "image",
+ "mozjpeg",
+ "thiserror 2.0.16",
+]
+
[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
dependencies = [
- "cfg-if",
+ "cfg-if 1.0.0",
"libc",
"redox_syscall 0.5.3",
"smallvec",
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
+[[package]]
+name = "peeking_take_while"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
+
[[package]]
name = "percent-encoding"
version = "2.3.1"
"zerocopy",
]
+[[package]]
+name = "prettyplease"
+version = "0.2.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033"
+dependencies = [
+ "proc-macro2",
+ "syn 2.0.87",
+]
+
[[package]]
name = "primal-check"
version = "0.3.4"
"av1-grain",
"bitstream-io",
"built",
- "cfg-if",
+ "cfg-if 1.0.0",
"interpolate_name",
"itertools 0.12.1",
"libc",
[[package]]
name = "rayon"
-version = "1.10.0"
+version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
+checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f"
dependencies = [
"either",
"rayon-core",
[[package]]
name = "rayon-core"
-version = "1.12.1"
+version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
+checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
dependencies = [
"crossbeam-deque",
"crossbeam-utils",
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
+[[package]]
+name = "relative-path"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bca40a312222d8ba74837cb474edef44b37f561da5f773981007a10bbaa992b0"
+dependencies = [
+ "serde",
+]
+
[[package]]
name = "renderdoc-sys"
version = "1.1.0"
checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832"
[[package]]
-name = "rgb"
-version = "0.8.50"
+name = "resampler"
+version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a"
+checksum = "80f5ab61459422b1a350caae1aadef48ebae234b12e80248e9ba9557018ef060"
[[package]]
-name = "rscam"
-version = "0.5.5"
+name = "rgb"
+version = "0.8.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89056084211cd54924fedf2e2199b906409d1f795cfd8e7e3271061742457018"
+checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a"
dependencies = [
- "libc",
+ "bytemuck",
]
[[package]]
"hound",
"image",
"libc",
+ "nokhwa",
"npyz",
"rand 0.9.2",
- "rscam",
+ "rayon",
+ "relative-path",
+ "resampler",
"rustfft",
"show-image",
+ "vcpkg",
]
[[package]]
[[package]]
name = "rustfft"
-version = "6.2.0"
+version = "6.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43806561bc506d0c5d160643ad742e3161049ac01027b5e6d7524091fd401d86"
+checksum = "21db5f9893e91f41798c88680037dba611ca6674703c1a18601b01a72c8adb89"
dependencies = [
"num-complex",
"num-integer",
"primal-check",
"strength_reduce",
"transpose",
- "version_check",
+]
+
+[[package]]
+name = "rustix"
+version = "0.38.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
+dependencies = [
+ "bitflags 2.6.0",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys 0.59.0",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
dependencies = [
- "cfg-if",
+ "cfg-if 1.0.0",
"cpufeatures",
"digest",
]
"wayland-protocols",
]
+[[package]]
+name = "spin"
+version = "0.9.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
+dependencies = [
+ "lock_api",
+]
+
[[package]]
name = "spirv"
version = "0.2.0+1.5.4"
"arrayref",
"arrayvec",
"bytemuck",
- "cfg-if",
+ "cfg-if 1.0.0",
"png",
"tiny-skia-path",
]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a"
+[[package]]
+name = "v4l"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8fbfea44a46799d62c55323f3c55d06df722fbe577851d848d328a1041c3403"
+dependencies = [
+ "bitflags 1.3.2",
+ "libc",
+ "v4l2-sys-mit",
+]
+
+[[package]]
+name = "v4l2-sys-mit"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6779878362b9bacadc7893eac76abe69612e8837ef746573c4a5239daf11990b"
+dependencies = [
+ "bindgen 0.65.1",
+]
+
[[package]]
name = "v_frame"
version = "0.3.8"
"wasm-bindgen",
]
+[[package]]
+name = "vcpkg"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
+
[[package]]
name = "vec_map"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
dependencies = [
- "cfg-if",
+ "cfg-if 1.0.0",
"once_cell",
"wasm-bindgen-macro",
]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed"
dependencies = [
- "cfg-if",
+ "cfg-if 1.0.0",
"js-sys",
"wasm-bindgen",
"web-sys",
checksum = "752e44d3998ef35f71830dd1ad3da513e628e2e4d4aedb0ab580f850827a0b41"
dependencies = [
"arrayvec",
- "cfg-if",
+ "cfg-if 1.0.0",
"js-sys",
"log",
"naga",
"bit-set",
"bitflags 2.6.0",
"block",
- "core-graphics-types",
+ "core-graphics-types 0.1.3",
"d3d12",
"glow",
"gpu-alloc",
"libc",
"libloading 0.8.5",
"log",
- "metal",
+ "metal 0.26.0",
"naga",
"objc",
"parking_lot",
"web-sys",
]
+[[package]]
+name = "which"
+version = "4.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
+dependencies = [
+ "either",
+ "home",
+ "once_cell",
+ "rustix",
+]
+
[[package]]
name = "widestring"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9252e5725dbed82865af151df558e754e4a3c2c30818359eb17465f1346a1b49"
dependencies = [
- "windows-core",
+ "windows-core 0.54.0",
"windows-targets 0.52.6",
]
+[[package]]
+name = "windows"
+version = "0.62.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580"
+dependencies = [
+ "windows-collections",
+ "windows-core 0.62.2",
+ "windows-future",
+ "windows-numerics",
+]
+
+[[package]]
+name = "windows-collections"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610"
+dependencies = [
+ "windows-core 0.62.2",
+]
+
[[package]]
name = "windows-core"
version = "0.54.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12661b9c89351d684a50a8a643ce5f608e20243b9fb84687800163429f161d65"
dependencies = [
- "windows-result",
+ "windows-result 0.1.2",
"windows-targets 0.52.6",
]
+[[package]]
+name = "windows-core"
+version = "0.62.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
+dependencies = [
+ "windows-implement",
+ "windows-interface",
+ "windows-link",
+ "windows-result 0.4.1",
+ "windows-strings",
+]
+
+[[package]]
+name = "windows-future"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb"
+dependencies = [
+ "windows-core 0.62.2",
+ "windows-link",
+ "windows-threading",
+]
+
+[[package]]
+name = "windows-implement"
+version = "0.60.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.87",
+]
+
+[[package]]
+name = "windows-interface"
+version = "0.59.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.87",
+]
+
+[[package]]
+name = "windows-link"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
+
+[[package]]
+name = "windows-numerics"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26"
+dependencies = [
+ "windows-core 0.62.2",
+ "windows-link",
+]
+
[[package]]
name = "windows-result"
version = "0.1.2"
"windows-targets 0.52.6",
]
+[[package]]
+name = "windows-result"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-strings"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
+dependencies = [
+ "windows-link",
+]
+
[[package]]
name = "windows-sys"
version = "0.45.0"
"windows-targets 0.52.6",
]
+[[package]]
+name = "windows-sys"
+version = "0.61.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
+dependencies = [
+ "windows-link",
+]
+
[[package]]
name = "windows-targets"
version = "0.42.2"
"windows_x86_64_msvc 0.52.6",
]
+[[package]]
+name = "windows-threading"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37"
+dependencies = [
+ "windows-link",
+]
+
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.2"
"android-activity",
"bitflags 1.3.2",
"cfg_aliases",
- "core-foundation",
- "core-graphics",
+ "core-foundation 0.9.4",
+ "core-graphics 0.22.3",
"dispatch",
"instant",
"libc",
version = "0.1.0"
edition = "2021"
build = "build.rs"
-include = ["src/perspective.cpp"]
+include = ["src/process.cpp", "src/barrel.cpp", "src/color.cpp", "src/homography.cpp"]
[dependencies]
libc = "0.2.161"
show-image = {version = "0.14.0", features = ["image"]}
hound = "3.5.1"
cpal = "0.15.3"
-rscam = "0.5.5"
npyz = "0.8.4"
rand = "0.9.2"
nokhwa = {version = "0.10.10", features = ["input-native"]}
relative-path = "2.0.1"
-yuv = "0.8.9"
-lowpass-filter = "0.3.2"
+rayon = "1.11.0"
+resampler = "0.4.1"
[build-dependencies]
+vcpkg = "0.2"
cc = "1.0"
-
-[env]
-CXXFLAGS = "-Wunused-parameter -lopencv_core -lopencv_highgui -lopencv_xfeatures2d -lopencv_calib3d -lopencv_videoio -lopencv_imgcodecs -lopencv_features2d -lopencv_imgproc -lstdc++"
println!("cargo::rerun-if-changed=src/process.cpp");
println!("cargo::rerun-if-changed=src/homography.cpp");
println!("cargo::rerun-if-changed=src/color.cpp");
- println!("cargo::rustc-env=CXXFLAGS=-Wunused-parameter -lopencv_core -lopencv_highgui -lopencv_xfeatures2d -lopencv_calib3d -lopencv_videoio -lopencv_imgcodecs -lopencv_imgproc -lopencv_features2d");
+ println!("cargo::rerun-if-changed=src/barrel.cpp");
+
+ println!("cargo:rustc-link-search=native=D:\\vcpkg\\installed\\x64-windows-static-md\\lib");
+
+ println!("cargo:rustc-link-lib=static=opencv_core4");
+ println!("cargo:rustc-link-lib=static=opencv_imgproc4");
+ println!("cargo:rustc-link-lib=static=opencv_imgcodecs4");
+ println!("cargo:rustc-link-lib=static=opencv_highgui4");
+
+ let mut config = vcpkg::Config::new();
+ config.vcpkg_root([r"D:\", "vcpkg"].iter().collect::<std::path::PathBuf>());
+ let lib = config.find_package("opencv4").unwrap();
+ let mut path = lib.include_paths[0].clone();
+ path.push("opencv4");
+
+ println!("{:?}", lib);
cc::Build::new()
.file("src/process.cpp")
.cpp(true)
- .include("/usr/include/opencv4/")
+ .include(&path)
// definitions cross language
- .define("WINDOW_SIZE", "128")
- .define("CHUNK_SIZE", "72")
- .define("IMAGE_WIDTH", "1920")
- .define("IMAGE_HEIGHT", "1080")
+ .define("WINDOW_SIZE", "64")
+ .define("CHUNK_SIZE", "128")
+ .define("CANVAS_WIDTH", "500")
+ .define("CANVAS_HEIGHT", "1000")
+ .define("IMAGE_WIDTH", "1080")
+ .define("IMAGE_HEIGHT", "1920")
.define("LUT_SIZE", "12")
//.define("USE_LUT", None)
+ //.define("PASSTHROUGH", None)
.compile("process.a");
- println!("cargo::rustc-flags=-lopencv_core -lopencv_highgui -lopencv_xfeatures2d -lopencv_calib3d -lopencv_videoio -lopencv_imgcodecs -lopencv_imgproc -lopencv_features2d");
-
- println!("cargo:rustc-env=WGPU_BACKEND=gl"); // fix show_image bug(?)
+ println!("cargo:rustc-env=WGPU_BACKEND=primary"); // fix show_image bug(?)
println!("cargo:rustc-env=WGPU_POWER_PREF=high"); // can switch to low if performance issues
+
}
-#include "opencv4/opencv2/imgproc.hpp"
+#include "opencv2/imgproc.hpp"
+#include <opencv2/highgui.hpp>
+#include <opencv2/core.hpp>
+#include <opencv2/imgcodecs.hpp>
+using namespace std;
using namespace cv;
void ApplyUndistort(uint8_t *camera_ptr, float *xmat_ptr, float *ymat_ptr)
{
- Mat xmat (IMAGE_HEIGHT, IMAGE_WIDTH, CV_32F, xmat_ptr);
- Mat ymat (IMAGE_HEIGHT, IMAGE_WIDTH, CV_32F, ymat_ptr);
+ Mat xmat (IMAGE_HEIGHT, IMAGE_WIDTH, CV_16SC2, xmat_ptr);
+ Mat ymat (IMAGE_HEIGHT, IMAGE_WIDTH, CV_16UC1, ymat_ptr);
Mat capture(IMAGE_HEIGHT, IMAGE_WIDTH, CV_8UC3, camera_ptr);
Mat buffer = capture.clone();
*/
remap(buffer, capture, xmat, ymat, INTER_NEAREST);
+
+ cv::imshow("Testing", capture);
+ int k = waitKey(0); // Wait for a keystroke in the window
}
--- /dev/null
+#include "DeckLink X.Y\Win\Include\DeckLinkAPI.idl";
\ No newline at end of file
#include <cmath>
-#include "opencv4/opencv2/core.hpp"
-
-#ifndef LUT_SIZE
-const int IMAGE_WIDTH = 1920;
-const int IMAGE_HEIGHT = 1080;
-const int LUT_SIZE = 12;
-#endif
+#include "opencv2/core.hpp"
using namespace std;
using namespace cv;
// is this damn well right?!?!
-const float SCALER = ((float)LUT_SIZE - 1.) / 255.;
+const float SCALER = ((float) LUT_SIZE - 1.) / 255.;
void ApplyCorrection(uint8_t *buffer_ptr, uint8_t *lut_ptr)
{
try
{
- Mat capture(IMAGE_HEIGHT, IMAGE_WIDTH, CV_8UC3, buffer_ptr);
+ Mat buffer(CHUNK_SIZE, WINDOW_SIZE, CV_8UC3, buffer_ptr);
- MatIterator_<Point3_<uint8_t>> it = capture.begin<Point3_<uint8_t>>();
- MatIterator_<Point3_<uint8_t>> it_end = capture.end<Point3_<uint8_t>>();
+ MatIterator_<Point3_<uint8_t>> it = buffer.begin<Point3_<uint8_t>>();
+ MatIterator_<Point3_<uint8_t>> it_end = buffer.end<Point3_<uint8_t>>();
/*
* Pretty sure that because we're not actually using opencv for anything
Point3_<float> scaled (pixel);
scaled *= SCALER;
- int r = floor(scaled.z);
- int g = floor(scaled.y);
- int b = floor(scaled.x);
+ int r = (int) floor(scaled.z);
+ int g = (int) floor(scaled.y);
+ int b = (int) floor(scaled.x);
int idx = (((LUT_SIZE * LUT_SIZE) * r) + (LUT_SIZE * g)+ b) * 3;
}
catch (const std::exception &e) // handle exceptions for rust
{
- std::cout << "Exception " << e.what() << std::endl;
+ std::cout << "Exception BANG! " << e.what() << std::endl;
}
}
--- /dev/null
+use crate::{HUE_MIN, HUE_REL};\r
+\r
+\r
+pub fn _hsv_to_rgb (h: f32, s: f32, v:f32) -> (f32, f32, f32) {\r
+ let mut _h = h * (HUE_REL / 255f32); // [0, HUE_REL) <- should this be ... * (360 / 256) ?????????\r
+ let _s = s / 255f32; // [0, 1]\r
+ let _v = v / 255f32; // [0, 1]\r
+ \r
+ _h += HUE_MIN; // [HUE_MIN, HUE_MAX)\r
+ _h /= 60f32;\r
+\r
+ let c = _s * _v;\r
+ let m = _v - c;\r
+ let x = c * (1f32 - (_h.rem_euclid(2f32) - 1f32).abs());\r
+\r
+ let (mut r, mut g, mut b) = match _h.floor() {\r
+ 0.0 => (c, x, 0f32),\r
+ 1.0 => (x, c, 0f32),\r
+ 2.0 => (0f32, c, x),\r
+ 3.0 => (0f32, x, c),\r
+ 4.0 => (x, 0f32, c),\r
+ _ => (c, 0f32, x)\r
+ };\r
+\r
+ r = (r + m) * 255f32;\r
+ g = (g + m) * 255f32;\r
+ b = (b + m) * 255f32;\r
+\r
+ (r, g, b)\r
+}\r
+\r
+pub fn _rgb_to_hsv (r: f32, g: f32, b:f32) -> (f32, f32, f32) {\r
+ let v = r.max(g).max(b);\r
+ let c = (v - r.min(g).min(b)) * 255f32;\r
+ let s = if v == 0f32 { 0f32 } else { c / v };\r
+\r
+ let mut h = if c == 0f32 {\r
+ // case 1:\r
+ 0f32\r
+ } else if v == r {\r
+ // case 2:\r
+ 60f32 * ((g - b) / c).rem_euclid(6f32)\r
+ } else if v == g {\r
+ // case 3:\r
+ 60f32 * (((b - r) / c) + 2f32)\r
+ } else {\r
+ // case 4:\r
+ 60f32 * (((r - g) / c) + 4f32)\r
+ };\r
+ h *= 255f32 / 360f32;\r
+\r
+ (h, s, v)\r
+}\r
+\r
+pub fn _rgb_to_sv (r: f32, g: f32, b:f32) -> (f32, f32) {\r
+ let v = r.max(g).max(b);\r
+ let s = if v == 0f32 { 0f32 } else { ((v - r.min(g).min(b)) * 255f32) / v }; // only do "c" if we need to\r
+\r
+ (s, v)\r
+}
\ No newline at end of file
# undistort
mapx, mapy = cv.initUndistortRectifyMap(mtx, dist, None, newcameramtx, (w,h), 5)
+
+mapx, mapy = cv.convertMaps(mapx, mapy, cv.CV_16SC2)
+
dst = cv.remap(img, mapx, mapy, cv.INTER_LINEAR)
np.save("./data/mapx.npy", mapx)
dst = dst[y:y+h, x:x+w]
img = cv.resize(img, (w, h))
-dst = np.concat((dst, img), axis=1)
+dst = np.concat((img, dst), axis=1)
cv.namedWindow("Result", cv.WINDOW_GUI_NORMAL)
cv.imshow('Result', dst)
if PASSTHROUGH and CAST_TEST:
validate(lut)
- save("./data/cube.npy", lut.lut)
+ save("cube.npy", lut.lut)
-#include "opencv4/opencv2/xfeatures2d.hpp"
-#include "opencv4/opencv2/calib3d.hpp"
-#include "opencv4/opencv2/imgproc.hpp"
-#include "opencv4/opencv2/imgcodecs.hpp"
+#include "opencv2/calib3d.hpp"
+#include "opencv2/xfeatures2d.hpp"
+#include "opencv2/imgproc.hpp"
+#include "opencv2/imgcodecs.hpp"
+#include <opencv2/highgui.hpp>
+#include <opencv2/core.hpp>
using namespace cv;
using namespace cv::xfeatures2d;
{
try
{
- Mat img1 = imread( samples::findFile("./test/calibration.jpg")/*, IMREAD_GRAYSCALE */);
+ Mat img1 = imread( samples::findFile("./test/towers.jpg")/*, IMREAD_GRAYSCALE */);
Mat img2(IMAGE_HEIGHT, IMAGE_WIDTH, CV_8UC3, camera_ptr);
+ cvtColor(img2, img2, COLOR_RGB2BGR);
// detect keypoints and compute descriptors
int minHessian = 400;
Ptr<SURF> detector = SURF::create( minHessian );
+ (*detector).setExtended(true);
std::vector<KeyPoint> keypoints1, keypoints2;
Mat descriptors1, descriptors2;
// copy the result to the homography location
const double* result_ptr = homography.ptr<double>(0);
std::memcpy(homography_ptr, result_ptr, 72); // size of [f64; 9]
+
+ Mat output;
+ drawMatches(img1, keypoints1, img2, keypoints2, good_matches, output);
+
+ namedWindow("testing", WINDOW_NORMAL);
+ imshow("testing", output);
+ int k = waitKey(0); // Wait for a keystroke in the window
}
catch (const std::exception &e) // handle exceptions for rust
{
}
}
-void ApplyHomography(uint8_t *camera_ptr, uint8_t *buffer_ptr, double *homography_ptr)
+#ifndef CUDA
+
+void ApplyHomography(uint8_t *camera_ptr, uint8_t *buffer_ptr, double *homography_ptr) // validated!
{
Mat capture(IMAGE_HEIGHT, IMAGE_WIDTH, CV_8UC3, camera_ptr);
+ Mat result(CANVAS_HEIGHT, CANVAS_WIDTH, CV_8UC3);
+ Mat homography(3, 3, CV_64F, homography_ptr);
+
+#ifdef PASSTHROUGH
+ Mat buffer(CHUNK_SIZE, WINDOW_SIZE, CV_8UC3);
+#else
Mat buffer(CHUNK_SIZE, WINDOW_SIZE, CV_8UC3, buffer_ptr);
+#endif // PASSTHROUGH
+
+ warpPerspective(capture, result, homography, Size(CANVAS_WIDTH, CANVAS_HEIGHT)); // try INTER_LINEAR
+ resize(result, buffer, Size(WINDOW_SIZE, CHUNK_SIZE), 0, 0, INTER_NEAREST); // make sure this is right it would probably be a nebulous one to figure out
+}
+
+#else
+
+#include "opencv2/gpu/gpu.hpp"
+
+void ApplyHomography(uint8_t* camera_ptr, uint8_t* buffer_ptr, double* homography_ptr) // validated!
+{
+ Mat capture(IMAGE_HEIGHT, IMAGE_WIDTH, CV_8UC3, camera_ptr);
Mat homography(3, 3, CV_64F, homography_ptr);
- warpPerspective(capture, capture, homography, capture.size());
- resize(capture, buffer, buffer.size());
+#ifdef PASSTHROUGH
+ Mat buffer(CHUNK_SIZE, WINDOW_SIZE, CV_8UC3);
+#else
+ Mat buffer(CHUNK_SIZE, WINDOW_SIZE, CV_8UC3, buffer_ptr);
+#endif // PASSTHROUGH
+
+ GpuMat capture_gpu(IMAGE_HEIGHT, IMAGE_WIDTH, CV_8UC3);
+ GpuMat result_gpu(CANVAS_HEIGHT, CANVAS_WIDTH, CV_8UC3);
+ GpuMat homography_gpu(3, 3, CV_64F);
+ GpuMat buffer_gpu(CHUNK_SIZE, WINDOW_SIZE, CV_8UC3);
+
+ capture_gpu.upload(capture);
+ homography_gpu.upload(homography);
+
+ gpu::warpPerspective(capture_gpu, result_gpu, homography_gpu, Size(CANVAS_WIDTH, CANVAS_HEIGHT)); // vvv try INTER_LINEAR
+ gpu::resize(result_gpu, buffer_gpu, Size(WINDOW_SIZE, CHUNK_SIZE), 0, 0, INTER_NEAREST); // make sure this is right it would probably be a nebulous one to figure out
+
+ buffer.download(buffer_gpu);
}
+#endif // CUDA
-use image::ImageFormat;
-use nokhwa::{Camera, FormatDecoder};
+use nokhwa::{Camera, query};
use nokhwa::utils::{
RequestedFormat,
CameraIndex,
CameraFormat,
Resolution,
- FrameFormat,
- RequestedFormatType
+ RequestedFormatType,
+ ApiBackend
};
+use nokhwa::utils::KnownCameraControl::*;
+use nokhwa::utils::ControlValueSetter::*;
use nokhwa::pixel_format::{RgbFormat, YuyvFormat};
use rustfft::num_complex::Complex;
use npyz::NpyFile;
-use yuv::{yuyv422_to_rgb, YuvPackedImage, YuvRange, YuvStandardMatrix};
-
use std::io::BufReader;
use std::fs::File;
+use relative_path::RelativePath;
+
+use rayon::prelude::*;
use crate::{
GetHomography,
ProcessCapture,
LUT_LENGTH,
+ LUT_PATH,
+ MAPX_PATH,
+ MAPY_PATH,
SPECTOGRAM_AREA,
IMAGE_AREA,
- IMAGE_WIDTH,
- IMAGE_HEIGHT,
VOLUME_MIN,
VOLUME_REL,
AMPLITUDE_REL,
AMPLITUDE_MIN,
ANGLE_REL,
ANGLE_MIN,
- FPS
+ FPS,
+ PASSTHROUGH,
+ IMAGE_WIDTH,
+ IMAGE_HEIGHT,
+ IMAGE_FORMAT,
+ DEBUG
+};
+
+use crate::color_functions::{
+ _hsv_to_rgb,
+ _rgb_to_sv
};
pub struct ImageArray {
pub data: Vec<u8>,
homography: [f64; 9],
lut: [u8; LUT_LENGTH],
+ mapx_ptr: usize,
+ mapy_ptr: usize,
camera_buffer: Vec<u8>,
- camera: Camera,
- chunks: usize
+ camera: Camera
}
impl ImageArray {
- pub fn new (homography: [f64; 9]) -> Self {
-
+ pub fn new (homography: [f64; 9], index: u32, mapx_ptr: usize, mapy_ptr: usize, focus: i64) -> Self {
+
// digest the numpy array and setup lut
- let file = BufReader::new(File::open("./data/cube.npy").unwrap());
+ let lut_path = RelativePath::new(LUT_PATH).as_str();
+ let file = BufReader::new(File::open(lut_path).unwrap());
let npy = NpyFile::new(file).unwrap();
-
- // this is a little silly i should handle these things
let lut: [u8; LUT_LENGTH] = npy.into_vec().unwrap().try_into().unwrap();
-
- // setup the camera
- let index = CameraIndex::Index(2);
- let format = CameraFormat::new(
- Resolution { width_x: 1920, height_y: 1080 },
- FrameFormat::YUYV,
- FPS as u32
- );
- let requested = RequestedFormat::new::<YuyvFormat>(
- RequestedFormatType::Closest(format)
+
+ // setup the camera formats
+ let index = CameraIndex::Index(index);
+ let format = RequestedFormat::new::<YuyvFormat>(
+ RequestedFormatType::Closest(
+ CameraFormat::new(
+ Resolution { width_x: IMAGE_WIDTH as u32, height_y: IMAGE_HEIGHT as u32},
+ IMAGE_FORMAT,
+ FPS as u32
+ )
+ )
);
-
- let mut camera = Camera::new(index, requested).unwrap();
+
+ if DEBUG {
+ // open the camera with its default to get the list of all its formats & print the backend info
+ println!("{:#?}", query(ApiBackend::MediaFoundation));
+ let mut camera = Camera::new(index.clone(), RequestedFormat::new::<YuyvFormat>(RequestedFormatType::None)).unwrap();
+ println!("{:?}", camera.compatible_list_by_resolution(IMAGE_FORMAT));
+ println!("{:?}", camera.supported_camera_controls().unwrap());
+ };
+
+ let mut camera = Camera::new(index, format).unwrap();
camera.open_stream().unwrap();
- // self
+ camera.set_camera_control(Brightness, Integer(255)).unwrap();
+ camera.set_camera_control(Contrast, Integer(128)).unwrap();
+ camera.set_camera_control(Saturation, Integer(128)).unwrap();
+ camera.set_camera_control(Sharpness, Integer(0)).unwrap();
+ camera.set_camera_control(WhiteBalance, Integer(5000)).unwrap();
+ camera.set_camera_control(BacklightComp, Integer(0)).unwrap();
+ camera.set_camera_control(Gain, Integer(0)).unwrap();
+ camera.set_camera_control(Exposure, Integer(-2)).unwrap();
+ camera.set_camera_control(Zoom, Integer(100)).unwrap();
+ camera.set_camera_control(Focus, Integer(focus)).unwrap();
+
Self {
data: vec![0u8; SPECTOGRAM_AREA * 3],
homography,
lut,
+ mapx_ptr,
+ mapy_ptr,
camera_buffer: vec![0u8; IMAGE_AREA],
- camera,
- chunks: SPECTOGRAM_AREA
+ camera
}
}
pub fn read_camera (&mut self) {
- let frame = self.camera.frame().unwrap();
-
- // some code to turn the yuyv into rgb if we need it!
- // let stride = (IMAGE_WIDTH * 3) as u32;
- // let vuvy = YuvPackedImage{
- // yuy: frame.buffer(),
- // yuy_stride: stride,
- // width: IMAGE_WIDTH as u32,
- // height: IMAGE_HEIGHT as u32
- // };
- // let mut rgb = [0u8; IMAGE_AREA];
- // yuyv422_to_rgb(
- // &vuvy,
- // &mut rgb,
- // stride,
- // YuvRange::Full,
- // YuvStandardMatrix::Bt601
- // ).unwrap();
-
+ let frame = self.camera.frame().expect(&format!("Oh no! Camera {} failed", self.camera.info()));
let decoder = frame.decode_image::<RgbFormat>().unwrap();
- decoder.save_with_format("./image.png", ImageFormat::Png).unwrap();
-
- self.camera_buffer = decoder.into_vec()[..].into(); // something is wrong here
-
-
+ self.camera_buffer = decoder.into_raw()[..].into();
+
unsafe {
ProcessCapture (
self.camera_buffer.as_ptr() as usize,
- self.data.as_ptr() as usize,
- self.homography.as_ptr() as usize,
- self.lut.as_ptr() as usize
+ self.data.as_ptr() as usize,
+ self.homography.as_ptr() as usize,
+ self.lut.as_ptr() as usize,
+ self.mapx_ptr,
+ self.mapy_ptr
);
- }
+ };
}
pub fn calibrate (&mut self) {
- // hopefully dont need this !
- // for _i in 0..10 {
- // self.camera_buffer = self.camera.capture().unwrap()[..].try_into().expect("Image is wrong size"); //delete assignment
- // }
+ // read straight from the camera so as to not make "read_camera" too convoluted
+ for _ in 0..100 {
+ self.camera.frame().unwrap();
+ }
+ let frame = self.camera.frame().unwrap();
+ let decoder = frame.decode_image::<RgbFormat>().unwrap();
+ self.camera_buffer = decoder.into_raw()[..].into();
// enter unsafe and get the homography array
- unsafe {
- GetHomography(self.camera_buffer.as_ptr() as usize, self.homography.as_ptr() as usize);
+ if !PASSTHROUGH {
+ unsafe {
+ GetHomography(
+ self.camera_buffer.as_ptr() as usize,
+ self.homography.as_ptr() as usize,
+ self.mapx_ptr,
+ self.mapy_ptr
+ );
+ }
}
+ if DEBUG { println!("{:#?}", self.homography); }
}
pub fn read_buffer (&mut self, buffer: &[Complex<f32>]) {
- let mut r: f32;
- let mut theta: f32;
- let mut amplitude: f32;
-
- let mut hue: f32;
- let mut angle: f32;
-
- let mut d:f32;
- let mut s:f32;
- let mut v:f32;
- let mut c:f32;
- let mut m:f32;
- let mut x:f32;
- let mut g:f32;
- let mut b:f32;
-
- for i in 0..self.chunks {
- (r, theta) = buffer[i].to_polar();
-
- // make linear and normalize
- amplitude = 20f32 * r.log10();
+ /*
+ hsv -> amplitude, angle, extra
+ extra and spectrogram become seperated
+
+ hsv -> angle, amplitude, extra
+ extra and spectrogram become seperated
+
+ hsv -> angle, extra, amplitude
+ good but color split down middle in strange way
+ hue mapped to phase is also poor
+
+ hsv -> amplitude, extra, angle
+ Looks more integrated but not that much
+ good noise
+
+ hsv -> extra, angle, amplitude
+ enjoy the colors -> laurens fave looks cohesive
+ visually more interesting. makes the spectrograms minimal & sounds clear
+
+ hsv -> extra, amplitude, angle
+ similar to last but slightly worse could be workable but
+
+ rgb -> all
+ just different combinations of colors
+ fairly seperated
+
+ hsplit -> angle, amplitude
+
+ hsplit -> amplitude, angle
+
+ */
+ (0..SPECTOGRAM_AREA).into_par_iter().zip(self.data.par_chunks_mut(3)).for_each(|(i, rgb)| {
+ let (norm, theta) = buffer[i].to_polar();
+
+ // scale amplitude
+ let mut amplitude = 20f32 * norm.log10();
amplitude = ((amplitude - VOLUME_MIN) / (VOLUME_REL / AMPLITUDE_REL)) + AMPLITUDE_MIN;
-
- hue = (180f32 / 255f32) * amplitude;
-
- angle = (theta.to_degrees() + 180f32) * (ANGLE_REL / 360f32) + ANGLE_MIN;
-
- d = hue * (1f32 / 30f32);
- s = angle / 255f32;
- v = amplitude / 255f32;
-
- c = s * v;
- m = v - c;
- x = c * (1f32 - (d.rem_euclid(2f32) - 1f32).abs());
-
- (r, g, b) = match d.floor() {
- 0.0 => (c, x, 0f32),
- 1.0 => (x, c, 0f32),
- 2.0 => (0f32, c, x),
- 3.0 => (0f32, x, c),
- 4.0 => (x, 0f32, c),
- _ => (c, 0f32, x)
- };
-
- self.data[i*3] = ((r + m) * 255f32) as u8;
- self.data[i*3+1] = ((g + m) * 255f32) as u8;
- self.data[i*3+2] = ((b + m) * 255f32) as u8;
- }
+
+ // scale angle
+ let angle = (theta.to_degrees() + 180f32) * (ANGLE_REL / 360f32) + ANGLE_MIN;
+
+ // ==============================================
+ let (r, g, b) = _hsv_to_rgb(amplitude, angle, amplitude);
+ // ==============================================
+
+ rgb[0] = r as u8;
+ rgb[1] = g as u8;
+ rgb[2] = b as u8;
+ });
}
pub fn write_buffer (&mut self, buffer: &mut [Complex<f32>]) {
- let mut r: f32;
- let mut amplitude: f32;
-
- let mut angle: f32;
-
- let mut s:f32;
- let mut v:f32;
- let mut c:f32;
- let mut g:f32;
- let mut b:f32;
+ (0..SPECTOGRAM_AREA).into_par_iter().zip(buffer.par_iter_mut()).for_each(|(i, buffer_point)| {
+ let r = self.data[i*3] as f32;
+ let g = self.data[i*3+1] as f32;
+ let b = self.data[i*3+2] as f32;
- for i in 0..self.chunks {
- r = self.data[i*3] as f32;
- g = self.data[i*3+1] as f32;
- b = self.data[i*3+2] as f32;
-
- v = r.max(g).max(b);
- c = (v - r.min(g).min(b)) * 255f32;
- s = if v == 0f32 { 0f32 } else { c / v };
-
- amplitude = (v - AMPLITUDE_MIN) * (VOLUME_REL / AMPLITUDE_REL) + VOLUME_MIN;
+ // ==========================================
+ let (mut angle, mut amplitude) = _rgb_to_sv(r, g, b);
+ // ==========================================
+ // scale amplitude
+ amplitude = (amplitude - AMPLITUDE_MIN) * (VOLUME_REL / AMPLITUDE_REL) + VOLUME_MIN;
amplitude = 10f32.powf(amplitude / 20f32);
-
- angle = (s - ANGLE_MIN) / (ANGLE_REL / 360f32) - 180f32;
+
+ // scale angle
+ angle = (angle - ANGLE_MIN) / (ANGLE_REL / 360f32) - 180f32;
angle = angle.to_radians();
- buffer[i] = Complex::from_polar(amplitude, angle);
- }
+ *buffer_point = Complex::from_polar(amplitude, angle);
+ });
}
}
# get image from camera and fix perspective
def get(self, image):
- small = cv.resize(image, (640,360))
- cv.imshow("LUT Calibration", small)
+ cv.imshow("LUT Calibration", image)
cv.waitKey(CAP_WAIT)
if PASSTHROUGH:
"""
LUT_SIZE = 12
-IMAGE_WIDTH = 1920 #1920
-IMAGE_HEIGHT = 1080 #1080
+IMAGE_WIDTH = 500 #1920
+IMAGE_HEIGHT = 1000 #1080
# size of the qr codes and the space around them (px)
-QR_SIZE = 300
-QR_PADDING = 10
+QR_SIZE = 200
+QR_PADDING = 5
# the wait time between each camera check after we stop generating
WAIT_TIME = 0.1 #s
use rustfft::algorithm::Radix4;
use rustfft::{Fft, FftDirection};
use rustfft::num_complex::Complex;
-use show_image::{ImageView, ImageInfo, create_window, event};
+
+use show_image::{
+ ImageView,
+ ImageInfo,
+ ArcImage,
+ create_window,
+ event,
+ Color,
+ WindowOptions
+};
+
use cpal::{StreamConfig, BufferSize, SampleRate};
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
+
use std::sync::{Arc, Mutex};
use std::sync::mpsc;
-use image::ImageReader;
+use std::time::SystemTime;
+
+use image::{ImageReader, ImageBuffer, Rgb};
+
use relative_path::RelativePath;
+
+use nokhwa::utils::FrameFormat;
+
+use rayon::prelude::*;
+
+use npyz::NpyFile;
+
+use resampler::{Attenuation, Latency, ResamplerFir, SampleRate as ResamplerSampleRate};
+
+use std::io::{BufReader, Write};
+use std::fs::File;
mod image_array;
mod sample_buffer;
+mod style_utils;
+mod color_functions;
+mod utils;
use image_array::ImageArray;
use sample_buffer::SampleBuffer;
-use lowpass_filter::LowpassFilter;
+/*
+NOTES:
+ - to calibrate you have to press enter on the images in the order of A-B-C.
+ - the sample rate is based only off file A and the others are assumed to be the same
+ - could paralelize the fft calls to speed them up?
+ - need to look at how images are displayed to the screen, very inneffective
+*/
-const WINDOW_SIZE: usize = 128;
-const CHUNK_SIZE: usize = 72;
+const WINDOW_SIZE: usize = 64; // 32
+const CHUNK_SIZE: usize = 128; // 64
const SPECTOGRAM_AREA: usize = WINDOW_SIZE * CHUNK_SIZE;
+// config of the display windows
+// note: this is only used for the show_image config
+const CANVAS_WIDTH: usize = 500;
+const CANVAS_HEIGHT: usize = 1000;
+
// configuration of the camera used
-const IMAGE_WIDTH: usize = 1920;
-const IMAGE_HEIGHT: usize = 1080;
+const IMAGE_WIDTH: usize = 1080;
+const IMAGE_HEIGHT: usize = 1920;
const IMAGE_AREA: usize = IMAGE_WIDTH * IMAGE_HEIGHT * 3;
-const FPS: usize = 5;
+const IMAGE_FORMAT: FrameFormat = FrameFormat::NV12;
+const FPS: usize = 30;
+
+const CAM_A_IDX: u32 = 1;
+const CAM_B_IDX: u32 = 2;
+const CAM_C_IDX: u32 = 0;
+
+const DEV_C12_IDX: usize = 4;
+const DEV_C34_IDX: usize = 2;
+const DEV_C56_IDX: usize = 7;
+const DEV_C78_IDX: usize = 6;
+/*
+const DEV_C12_IDX: usize = 0;
+const DEV_C34_IDX: usize = 0;
+const DEV_C56_IDX: usize = 0;
+const DEV_C78_IDX: usize = 0;
+*/
// maximum and minimum pixel values of angle and amplitude. could be confined to
// improve performance for quiet sounds.
-const AMPLITUDE_MAX: f32 = 255.0;
-const AMPLITUDE_MIN: f32 = 0.0;
+const AMPLITUDE_MAX: f32 = 245.0;
+const AMPLITUDE_MIN: f32 = 10.0;
const AMPLITUDE_REL: f32 = AMPLITUDE_MAX - AMPLITUDE_MIN;
-const ANGLE_MAX: f32 = 255.0;
-const ANGLE_MIN: f32 = 0.0;
+const ANGLE_MAX: f32 = 245.0;
+const ANGLE_MIN: f32 = 10.0;
const ANGLE_REL: f32 = ANGLE_MAX - ANGLE_MIN;
+// this is a scaling specific to hue that applies idependant of which thing is mapped to it
+const HUE_MAX: f32 = 0.0; // in range of [0,360)
+const HUE_MIN: f32 = 360.0;
+const HUE_REL: f32 = HUE_MAX - HUE_MIN;
+
// because of the opposingly logarithmic properties of both noise error and volume
// this maximum value is important. -40 to 100 may not work under real conditions,
// and -40 to 65 or even lower may produce better results.
-const VOLUME_MAX: f32 = 65.0; // 60 - 65
+const VOLUME_MAX: f32 = 60.0; // 60 - 65
const VOLUME_MIN: f32 = -40.0;
const VOLUME_REL: f32 = VOLUME_MAX - VOLUME_MIN;
const LUT_SIZE: usize = 12;
const LUT_LENGTH: usize = LUT_SIZE * LUT_SIZE * LUT_SIZE * 3;
+const LUT_PATH: &str = "./data/cube.npy";
-const DEBUG_MODE: bool = true;
+const MAPX_PATH: &str = "./data/mapx.npy";
+const MAPY_PATH: &str = "./data/mapy.npy";
-const CALIBRATION_PATH: &str = "./test/calibration.jpg";
-const AUDIO_PATH: &str = "./test/example.wav";
+const PASSTHROUGH: bool = false;
+const DEBUG: bool = true;
+const CALIBRATE: bool = true;
+
+const CALIBRATION_PATH: &str = "./test/towers.jpg";
+ const AUDIO_PATH_A: &str = "./test/example_hq.wav";
+ const AUDIO_PATH_B: &str = "./test/example_hq.wav";
+ const AUDIO_PATH_C: &str = "./test/example_hq.wav";
+//const AUDIO_PATH_A: &str = "test/threshold-A_03.wav";
+//const AUDIO_PATH_B: &str = "test/threshold-B_03.wav";
+//const AUDIO_PATH_C: &str = "test/threshold-C_03.wav";
+
+const AUDIO_A_C1: f32 = 1.0; const AUDIO_A_C2: f32 = 0.0;
+const AUDIO_A_C3: f32 = 0.0; const AUDIO_A_C4: f32 = 0.0;
+const AUDIO_A_C5: f32 = 0.0; const AUDIO_A_C6: f32 = 0.0;
+const AUDIO_A_C7: f32 = 0.0; const AUDIO_A_C8: f32 = 0.0;
+
+const AUDIO_B_C1: f32 = 0.0; const AUDIO_B_C2: f32 = 0.0;
+const AUDIO_B_C3: f32 = 0.0; const AUDIO_B_C4: f32 = 0.0;
+const AUDIO_B_C5: f32 = 0.0; const AUDIO_B_C6: f32 = 1.0;
+const AUDIO_B_C7: f32 = 0.0; const AUDIO_B_C8: f32 = 0.0;
+
+const AUDIO_C_C1: f32 = 0.0; const AUDIO_C_C2: f32 = 0.0;
+const AUDIO_C_C3: f32 = 0.0; const AUDIO_C_C4: f32 = 0.0;
+const AUDIO_C_C5: f32 = 1.0; const AUDIO_C_C6: f32 = 0.0;
+const AUDIO_C_C7: f32 = 0.0; const AUDIO_C_C8: f32 = 0.0;
+
+const OUTPUT_RATE: usize = 48000;//Hz
// feedback config
-const WET: f32 = 0.0;
+const WET: f32 = 0.9;
const DRY: f32 = 1.0;
-// audio effects and filtering
-const MAIN_LOWPASS: f32 = 20000.0;
-const FEEDBACK_LOWPASS: f32 = 20000.0;
-const FILTER_SCALING: f32 = 1. / 65535.; // to bring any signal down to +-1
-
extern "C" {
- fn GetHomography(camera_ptr: usize, homography_ptr: usize);
- fn ProcessCapture(camera_ptr: usize, buffer_ptr: usize, homography_ptr: usize, lut_ptr: usize);
+ fn GetHomography(camera_ptr: usize, homography_ptr: usize, xmap_ptr: usize, ymap_ptr: usize);
+ fn ProcessCapture(camera_ptr: usize, buffer_ptr: usize, homography_ptr: usize, lut_ptr: usize, xmap_ptr: usize, ymap_ptr: usize);
}
#[show_image::main]
fn main () -> Result<(), Box<dyn std::error::Error>> {
+ println!(" * Info: max delay is {}ms", 44100000 / SPECTOGRAM_AREA);
+
+ println!(" * Reserving memory");
+
// pregenerate the fft transformers
let forward_transform = Radix4::<f32>::new(WINDOW_SIZE, FftDirection::Forward);
let inverse_transform = Radix4::<f32>::new(WINDOW_SIZE, FftDirection::Inverse);
let scratch_size = forward_transform.get_inplace_scratch_len();
// preallocate complex space for the ffts
- let mut buffer = vec![Complex{re: 0f32, im: 0f32}; SPECTOGRAM_AREA];
+ let mut buffer_a = vec![Complex{re: 0f32, im: 0f32}; SPECTOGRAM_AREA];
+ let mut buffer_b = vec![Complex{re: 0f32, im: 0f32}; SPECTOGRAM_AREA];
+ let mut buffer_c = vec![Complex{re: 0f32, im: 0f32}; SPECTOGRAM_AREA];
let mut scratch = vec![Complex{re: 0f32, im: 0f32}; scratch_size];
// setup communication between the main thread and the audio thread
- let (tx, rx) = mpsc::channel();
- let sample_buffer = Arc::new(Mutex::new([0i16; 2*SPECTOGRAM_AREA]));
- let mut samples = SampleBuffer::new(sample_buffer.clone(), tx);
+ let (tx_c12, rx_c12) = mpsc::channel();
+ let (tx_c34, rx_c34) = mpsc::channel();
+ let (tx_c56, rx_c56) = mpsc::channel();
+ let (tx_c78, rx_c78) = mpsc::channel();
+
+ let sample_buffer_c1 = Arc::new(Mutex::new([0i16; 2*SPECTOGRAM_AREA]));
+ let sample_buffer_c2 = Arc::new(Mutex::new([0i16; 2*SPECTOGRAM_AREA]));
+ let sample_buffer_c3 = Arc::new(Mutex::new([0i16; 2*SPECTOGRAM_AREA]));
+ let sample_buffer_c4 = Arc::new(Mutex::new([0i16; 2*SPECTOGRAM_AREA]));
+ let sample_buffer_c5 = Arc::new(Mutex::new([0i16; 2*SPECTOGRAM_AREA]));
+ let sample_buffer_c6 = Arc::new(Mutex::new([0i16; 2*SPECTOGRAM_AREA]));
+ let sample_buffer_c7 = Arc::new(Mutex::new([0i16; 2*SPECTOGRAM_AREA]));
+ let sample_buffer_c8 = Arc::new(Mutex::new([0i16; 2*SPECTOGRAM_AREA]));
+
+ let mut samples_c12 = SampleBuffer::new(sample_buffer_c1.clone(), sample_buffer_c2.clone(), tx_c12);
+ let mut samples_c34 = SampleBuffer::new(sample_buffer_c3.clone(), sample_buffer_c4.clone(), tx_c34);
+ let mut samples_c56 = SampleBuffer::new(sample_buffer_c5.clone(), sample_buffer_c6.clone(), tx_c56);
+ let mut samples_c78 = SampleBuffer::new(sample_buffer_c7.clone(), sample_buffer_c8.clone(), tx_c78);
+
+ // resampler
+ let mut resampler = ResamplerFir::new(
+ 1,
+ ResamplerSampleRate::Hz22050,
+ ResamplerSampleRate::Hz48000,
+ Latency::Sample64, // could change to Sample8
+ Attenuation::Db90,
+ );
+
+ // get the map to share it between the image arrays
+ let mapx_path = RelativePath::new(MAPX_PATH).as_str();
+ let mapx_file = BufReader::new(File::open(mapx_path).unwrap());
+ let mapx_npy = NpyFile::new(mapx_file).unwrap();
+ let mapx: Vec<i16> = mapx_npy.into_vec().unwrap();
+
+ let mapy_path = RelativePath::new(MAPY_PATH).as_str();
+ let mapy_file = BufReader::new(File::open(mapy_path).unwrap());
+ let mapy_npy = NpyFile::new(mapy_file).unwrap();
+ let mapy: Vec<u16> = mapy_npy.into_vec().unwrap();
// setup homography space and get ready for the calibration
- let homography = [0f64; 9]; // homography is a 3x3 matrix of 64-bit floats
- let mut image_array = ImageArray::new(homography);
+ let homography_a = [0f64; 9]; // homography is a 3x3 matrix of 64-bit floats
+ let homography_b = [0f64; 9]; // homography is a 3x3 matrix of 64-bit floats
+ let homography_c = [0f64; 9]; // homography is a 3x3 matrix of 64-bit floats
+ println!(" * Starting camera A");
+ let mut image_array_a = ImageArray::new(homography_a, CAM_A_IDX, mapx.as_ptr() as usize, mapy.as_ptr() as usize, 190);
+ println!(" * Starting camera B");
+ let mut image_array_b = ImageArray::new(homography_b, CAM_B_IDX, mapx.as_ptr() as usize, mapy.as_ptr() as usize, 172);
+ println!(" * Starting camera C");
+ let mut image_array_c = ImageArray::new(homography_c, CAM_C_IDX, mapx.as_ptr() as usize, mapy.as_ptr() as usize, 236);
// create the debug window
- let debug_window = create_window("Debug", Default::default())?;
+ let window_options = WindowOptions{
+ preserve_aspect_ratio: false,
+ background_color: Color::black(),
+ start_hidden: false,
+ size: Some([(WINDOW_SIZE * 3) as u32, CHUNK_SIZE as u32]),
+ resizable: true,
+ borderless: false,
+ fullscreen: false,
+ overlays_visible: false,
+ default_controls: false
+ };
+ let debug_window = create_window("Debug", window_options)?;
// get calibration image path
let calibration_path = RelativePath::new(CALIBRATION_PATH).as_str();
// create window for displaying images and display calibration image
- let display_window = create_window("Display", Default::default())?;
+ let window_options = WindowOptions{
+ preserve_aspect_ratio: false,
+ background_color: Color::black(),
+ start_hidden: false,
+ size: Some([CANVAS_WIDTH as u32, CANVAS_HEIGHT as u32]),
+ resizable: true,
+ borderless: false,
+ fullscreen: false,
+ overlays_visible: false,
+ default_controls: false
+ };
+ let display_window_a = create_window("Display A", window_options.clone())?;
+ let display_window_b = create_window("Display B", window_options.clone())?;
+ let display_window_c = create_window("Display C", window_options)?;
+
let calibration_image = ImageReader::open(calibration_path)?.decode()?;
- display_window.set_image("Display", calibration_image)?;
+ display_window_a.set_image("Display A", calibration_image.clone())?;
+ display_window_b.set_image("Display B", calibration_image.clone())?;
+ display_window_c.set_image("Display C", calibration_image)?;
- // wait for the user to press a key before continuing
- for event in display_window.event_channel()? {
- if let event::WindowEvent::KeyboardInput(event) = event {
- if event.input.key_code == Some(event::VirtualKeyCode::Return) && event.input.state.is_pressed() {
- break;
+ let mut arc_data_a: [u8; SPECTOGRAM_AREA * 3];
+ let mut arc_image_a: ArcImage;
+ let mut arc_data_b: [u8; SPECTOGRAM_AREA * 3];
+ let mut arc_image_b: ArcImage;
+ let mut arc_data_c: [u8; SPECTOGRAM_AREA * 3];
+ let mut arc_image_c: ArcImage;
+
+ // calibrate camera
+ if CALIBRATE {
+ println!(" * Calibrating Display A");
+ // wait for the user to press a key before continuing
+ for event in display_window_a.event_channel()? {
+ if let event::WindowEvent::KeyboardInput(event) = event {
+ if event.input.key_code == Some(event::VirtualKeyCode::Return) && event.input.state.is_pressed() {
+ image_array_a.calibrate();
+ break;
+ }
+ }
+ }
+
+ println!(" * Calibrating Display B");
+ for event in display_window_b.event_channel()? {
+ if let event::WindowEvent::KeyboardInput(event) = event {
+ if event.input.key_code == Some(event::VirtualKeyCode::Return) && event.input.state.is_pressed() {
+ image_array_b.calibrate();
+ break;
+ }
+ }
+ }
+
+ println!(" * Calibrating Display C");
+ for event in display_window_c.event_channel()? {
+ if let event::WindowEvent::KeyboardInput(event) = event {
+ if event.input.key_code == Some(event::VirtualKeyCode::Return) && event.input.state.is_pressed() {
+ image_array_c.calibrate();
+ break;
+ }
}
}
}
- // calibrate camera
- image_array.calibrate();
-
- // get audio path
- let audio_path = RelativePath::new(AUDIO_PATH).as_str();
-
- // open audio file
- let mut reader = hound::WavReader::open(audio_path).unwrap();
- let file_rate = reader.spec().sample_rate;
-
- // setup the lowpass filters
- let main_lowpass = LowpassFilter::new(file_rate, MAIN_LOWPASS);
- let feedback_lowpass = LowpassFilter::new(file_rate, FEEDBACK_LOWPASS);
-
+ // get audio path and open audio file
+ let audio_path_a = RelativePath::new(AUDIO_PATH_A).as_str();
+ let audio_path_b = RelativePath::new(AUDIO_PATH_B).as_str();
+ let audio_path_c = RelativePath::new(AUDIO_PATH_C).as_str();
+
+ println!(" * Opening audio files");
+
+ let mut reader_a = hound::WavReader::open(audio_path_a).unwrap();
+ let mut reader_b = hound::WavReader::open(audio_path_b).unwrap();
+ let mut reader_c = hound::WavReader::open(audio_path_c).unwrap();
+
+ let file_rate = reader_a.spec().sample_rate;
+
+ // get inf iter of the samples in the wav file
+ let samples_a: Vec<i16> = reader_a.samples::<i16>().filter_map(Result::ok).collect::<Vec<i16>>();
+ let mut infinite_a = samples_a.iter().copied().cycle();
+
+ let samples_b: Vec<i16> = reader_b.samples::<i16>().filter_map(Result::ok).collect::<Vec<i16>>();
+ let mut infinite_b = samples_b.iter().copied().cycle();
+
+ let samples_c: Vec<i16> = reader_c.samples::<i16>().filter_map(Result::ok).collect::<Vec<i16>>();
+ let mut infinite_c = samples_c.iter().copied().cycle();
+
+ println!(" * Itterators constructed");
+
+ let mut out_samples_a = [0f32; 11025]; // this is an arbitrary number sorry
+ let mut out_samples_b = [0f32; 11025];
+ let mut out_samples_c = [0f32; 11025];
+
// setup audio output and build output stream
+ println!(" * Output stream setup");
let host = cpal::default_host();
- let device = host.default_output_device().expect("No output device available");
+
+ if DEBUG {
+ for device in host.output_devices().unwrap() {
+ println!("{:?}", device.name().unwrap());
+ }
+ //println!("{:?}", device.default_output_config());
+ //let configs = device.supported_output_configs().unwrap();
+ //for supported_config in configs {
+ // println!("{:?}", supported_config);
+ //}
+ }
- let stream = device.build_output_stream(
+ let device_c12 = host.output_devices().unwrap().nth(DEV_C12_IDX).unwrap();
+ let device_c34 = host.output_devices().unwrap().nth(DEV_C34_IDX).unwrap();
+ let device_c56 = host.output_devices().unwrap().nth(DEV_C56_IDX).unwrap();
+ let device_c78 = host.output_devices().unwrap().nth(DEV_C78_IDX).unwrap();
+
+ // CHANNELS 1-2
+ let stream_c12 = device_c12.build_output_stream(
+ &StreamConfig{
+ channels: 2,
+ sample_rate: SampleRate(OUTPUT_RATE as u32),
+ buffer_size: BufferSize::Fixed(WINDOW_SIZE as u32)
+ },
+ move |data: &mut [i16], _: &cpal::OutputCallbackInfo| {
+ samples_c12.get_data(data);
+ },
+ move |err| {
+ eprintln!("An error occurred on the output audio stream: {}", err);
+ },
+ None
+ ).unwrap();
+ println!(" * Starting stream");
+ stream_c12.play().expect("Stream 1-2 play failed");
+
+ // CHANNELS 3-4
+ let stream_c34 = device_c34.build_output_stream(
+ &StreamConfig{
+ channels: 2,
+ sample_rate: SampleRate(OUTPUT_RATE as u32),
+ buffer_size: BufferSize::Fixed(WINDOW_SIZE as u32)
+ },
+ move |data: &mut [i16], _: &cpal::OutputCallbackInfo| {
+ samples_c34.get_data(data);
+ },
+ move |err| {
+ eprintln!("An error occurred on the output audio stream: {}", err);
+ },
+ None
+ ).unwrap();
+ println!(" * Starting stream");
+ stream_c34.play().expect("Stream 3-4 play failed");
+
+ // CHANNELS 5-6
+ let stream_c56 = device_c56.build_output_stream(
+ &StreamConfig{
+ channels: 2,
+ sample_rate: SampleRate(OUTPUT_RATE as u32),
+ buffer_size: BufferSize::Fixed(WINDOW_SIZE as u32)
+ },
+ move |data: &mut [i16], _: &cpal::OutputCallbackInfo| {
+ samples_c56.get_data(data);
+ },
+ move |err| {
+ eprintln!("An error occurred on the output audio stream: {}", err);
+ },
+ None
+ ).unwrap();
+ println!(" * Starting stream");
+ stream_c56.play().expect("Stream 5-6 play failed");
+
+ // CHANNELS 7-8
+ let stream_c78 = device_c78.build_output_stream(
&StreamConfig{
channels: 2,
- sample_rate: SampleRate(file_rate),
+ sample_rate: SampleRate(OUTPUT_RATE as u32),
buffer_size: BufferSize::Fixed(WINDOW_SIZE as u32)
},
move |data: &mut [i16], _: &cpal::OutputCallbackInfo| {
- samples.get_data(data);
+ samples_c78.get_data(data);
},
move |err| {
- eprintln!("an error occurred on the output audio stream: {}", err);
+ eprintln!("An error occurred on the output audio stream: {}", err);
},
None
).unwrap();
- stream.play().expect("Stream play failed");
+ println!(" * Starting stream");
+ stream_c78.play().expect("Stream 7-8 play failed");
// begin looping though the samples until the buffer is full of complex audio with an imag element of 0
let mut i = 0;
- for sample in reader.samples::<i16>() {
+
+ let mut value_a: f32;
+ let mut value_b: f32;
+ let mut value_c: f32;
+ let mut now = SystemTime::now();
+
+ println!(" * Efficiency begins");
+ println!(" * See you soon");
+
+ // EFFICIENCY BEGINS
+
+ let mut imagenum = 0;
+
+ loop {
if i == SPECTOGRAM_AREA {
// transform and do power scaling
- forward_transform.process_with_scratch(&mut buffer, &mut scratch);
- for x in buffer.iter_mut() {
- *x *= 1f32 / WINDOW_SIZE as f32;
- }
- image_array.read_buffer(&buffer);
+ forward_transform.process_with_scratch(&mut buffer_a, &mut scratch);
+ buffer_a = buffer_a.par_iter_mut()
+ .map(|x| *x * (1f32 / WINDOW_SIZE as f32))
+ .collect();
+ image_array_a.read_buffer(&buffer_a);
+
+ forward_transform.process_with_scratch(&mut buffer_b, &mut scratch);
+ buffer_b = buffer_b.par_iter_mut()
+ .map(|x| *x * (1f32 / WINDOW_SIZE as f32))
+ .collect();
+ image_array_b.read_buffer(&buffer_b);
+
+ forward_transform.process_with_scratch(&mut buffer_c, &mut scratch);
+ buffer_c = buffer_c.par_iter_mut()
+ .map(|x| *x * (1f32 / WINDOW_SIZE as f32))
+ .collect();
+ image_array_c.read_buffer(&buffer_c);
// show the image on screen
- let image = ImageView::new(ImageInfo::rgb8(WINDOW_SIZE as u32, CHUNK_SIZE as u32), &image_array.data);
- display_window.set_image ("image", image)?;
+
+ arc_data_a = image_array_a.data.clone().try_into().unwrap();
+ arc_image_a = ArcImage::new(
+ ImageInfo::rgb8(WINDOW_SIZE as u32, CHUNK_SIZE as u32),
+ Arc::new(arc_data_a)
+ );
+ display_window_a.set_image("Display A", arc_image_a)?;
+
+ arc_data_b = image_array_b.data.clone().try_into().unwrap();
+ arc_image_b = ArcImage::new(
+ ImageInfo::rgb8(WINDOW_SIZE as u32, CHUNK_SIZE as u32),
+ Arc::new(arc_data_b)
+ );
+ display_window_b.set_image("Display B", arc_image_b)?;
+
+ arc_data_c = image_array_c.data.clone().try_into().unwrap();
+ arc_image_c = ArcImage::new(
+ ImageInfo::rgb8(WINDOW_SIZE as u32, CHUNK_SIZE as u32),
+ Arc::new(arc_data_c)
+ );
+ display_window_c.set_image("Display C", arc_image_c)?;
// capture and transform camera view to image
- image_array.read_camera();
+ image_array_a.read_camera();
+ image_array_b.read_camera();
+ image_array_c.read_camera();
// make and display debug image
- if DEBUG_MODE {
- let debug_image = ImageView::new(ImageInfo::rgb8(WINDOW_SIZE as u32, CHUNK_SIZE as u32), &image_array.data);
+ if DEBUG {
+ let mut a_image = image_array_a.data.clone();
+ let mut b_image = image_array_b.data.clone();
+ let mut c_image = image_array_c.data.clone();
+
+ let a_slice: &mut [u8] = a_image.as_mut_slice();
+ let b_slice: &mut [u8] = b_image.as_mut_slice();
+ let c_slice: &mut [u8] = c_image.as_mut_slice();
+
+ let mut a_chunks = a_slice.chunks_mut(WINDOW_SIZE * 3);
+ let mut b_chunks = b_slice.chunks_mut(WINDOW_SIZE * 3);
+ let mut c_chunks = c_slice.chunks_mut(WINDOW_SIZE * 3);
+
+ let mut image_data = vec![0u8;0];
+ for _ in 0..CHUNK_SIZE {
+ let mut line = vec![0u8;0];
+
+ let a_line = a_chunks.next().unwrap();
+ let b_line = b_chunks.next().unwrap();
+ let c_line = c_chunks.next().unwrap();
+
+ line.extend_from_slice(a_line);
+ line.extend_from_slice(b_line);
+ line.extend_from_slice(c_line);
+
+
+ image_data.extend_from_slice(line.as_slice());
+ }
+
+ if false {
+ let save_image: ImageBuffer<Rgb<u8>, Vec<u8>> = ImageBuffer::from_raw((WINDOW_SIZE * 4) as u32, CHUNK_SIZE as u32, image_data.clone()).unwrap();
+ imagenum += 1;
+ save_image.save(format!("frames/frame-{:0>3}.png", imagenum)).unwrap();
+ }
+
+ let debug_image = ImageView::new(ImageInfo::rgb8((WINDOW_SIZE * 3) as u32, CHUNK_SIZE as u32), image_data.as_slice());
debug_window.set_image("Debug", debug_image)?;
}
// convert image to audio
- image_array.write_buffer(&mut buffer);
- inverse_transform.process_with_scratch(&mut buffer, &mut scratch);
+ image_array_a.write_buffer(&mut buffer_a);
+ image_array_b.write_buffer(&mut buffer_b);
+ image_array_c.write_buffer(&mut buffer_c);
+ inverse_transform.process_with_scratch(&mut buffer_a, &mut scratch);
+ inverse_transform.process_with_scratch(&mut buffer_b, &mut scratch);
+ inverse_transform.process_with_scratch(&mut buffer_c, &mut scratch);
// when a "true" is receved by rx, get lock for sample buffer and fill the last half with the audio
- if rx.recv().unwrap() {
- let mut write_buffer = sample_buffer.lock().unwrap();
- for (i, x) in write_buffer[SPECTOGRAM_AREA..].iter_mut().enumerate() {
- let value = main_lowpass.run(buffer[i].re / i16::MAX as f32);
- *x = (value * i16::MAX) as i16;
- }
+ if DEBUG { now = SystemTime::now(); }
+
+ let _ = resampler.resample(&buffer_a.iter().rev().map(|x| x.re).collect::<Vec<f32>>(), &mut out_samples_a).unwrap();
+ let _ = resampler.resample(&buffer_b.iter().rev().map(|x| x.re).collect::<Vec<f32>>(), &mut out_samples_b).unwrap();
+ let _ = resampler.resample(&buffer_c.iter().rev().map(|x| x.re).collect::<Vec<f32>>(), &mut out_samples_c).unwrap();
+
+
+ // CHANNELS 1-2
+ if rx_c12.recv().unwrap() {
+ if DEBUG { println!("{:?}", now.elapsed().unwrap()); }
+ sample_buffer_c1.lock().unwrap()[SPECTOGRAM_AREA..]
+ .par_iter_mut()
+ .enumerate()
+ .for_each(|(i, x)| {
+ *x = ((out_samples_a[i] * AUDIO_A_C1) + (out_samples_b[i] * AUDIO_B_C1) + (out_samples_b[i] * AUDIO_C_C1)) as i16;
+ });
+ sample_buffer_c2.lock().unwrap()[SPECTOGRAM_AREA..]
+ .par_iter_mut()
+ .enumerate()
+ .for_each(|(i, x)| {
+ *x = ((out_samples_a[i] * AUDIO_A_C2) + (out_samples_b[i] * AUDIO_B_C2) + (out_samples_b[i] * AUDIO_C_C2)) as i16;
+ });
+ }
+
+ // CHANNELS 3-4
+ if rx_c34.recv().unwrap() {
+ sample_buffer_c3.lock().unwrap()[SPECTOGRAM_AREA..]
+ .par_iter_mut()
+ .enumerate()
+ .for_each(|(i, x)| {
+ *x = ((out_samples_a[i] * AUDIO_A_C3) + (out_samples_b[i] * AUDIO_B_C3) + (out_samples_b[i] * AUDIO_C_C3)) as i16;
+ });
+ sample_buffer_c4.lock().unwrap()[SPECTOGRAM_AREA..]
+ .par_iter_mut()
+ .enumerate()
+ .for_each(|(i, x)| {
+ *x = ((out_samples_a[i] * AUDIO_A_C4) + (out_samples_b[i] * AUDIO_B_C4) + (out_samples_b[i] * AUDIO_C_C4)) as i16;
+ });
+ }
+
+ // CHANNELS 5-6
+ if rx_c56.recv().unwrap() {
+ sample_buffer_c5.lock().unwrap()[SPECTOGRAM_AREA..]
+ .par_iter_mut()
+ .enumerate()
+ .for_each(|(i, x)| {
+ *x = ((out_samples_a[i] * AUDIO_A_C5) + (out_samples_b[i] * AUDIO_B_C5) + (out_samples_b[i] * AUDIO_C_C5)) as i16;
+ });
+ sample_buffer_c6.lock().unwrap()[SPECTOGRAM_AREA..]
+ .par_iter_mut()
+ .enumerate()
+ .for_each(|(i, x)| {
+ *x = ((out_samples_a[i] * AUDIO_A_C6) + (out_samples_b[i] * AUDIO_B_C6) + (out_samples_b[i] * AUDIO_C_C6)) as i16;
+ });
+ }
+
+ // CHANNELS 7-8
+ if rx_c78.recv().unwrap() {
+ sample_buffer_c7.lock().unwrap()[SPECTOGRAM_AREA..]
+ .par_iter_mut()
+ .enumerate()
+ .for_each(|(i, x)| {
+ *x = ((out_samples_a[i] * AUDIO_A_C7) + (out_samples_b[i] * AUDIO_B_C7) + (out_samples_b[i] * AUDIO_C_C7)) as i16;
+ });
+ sample_buffer_c8.lock().unwrap()[SPECTOGRAM_AREA..]
+ .par_iter_mut()
+ .enumerate()
+ .for_each(|(i, x)| {
+ *x = ((out_samples_a[i] * AUDIO_A_C8) + (out_samples_b[i] * AUDIO_B_C8) + (out_samples_b[i] * AUDIO_C_C8)) as i16;
+ });
}
i = 0;
}
+
// if buffer is not full convert value and add to buffer
- let mut value = sample.unwrap_or_default() as f32;
- let feedback_value = feedback_lowpass.run(buffer[i].re / i16::MAX as f32);
- value = (value * DRY) + (feedback_value * i16::MAX * WET);
+ value_a = (infinite_a.next().unwrap() as f32 * DRY) + (buffer_a[i].re * WET);
+ value_b = (infinite_b.next().unwrap() as f32 * DRY) + (buffer_b[i].re * WET);
+ value_c = (infinite_c.next().unwrap() as f32 * DRY) + (buffer_c[i].re * WET);
+
+ buffer_a[i] = Complex{re: value_a, im: 0f32};
+ buffer_b[i] = Complex{re: value_b, im: 0f32};
+ buffer_c[i] = Complex{re: value_c, im: 0f32};
- buffer[i] = Complex{re: value, im: 0f32};
i += 1;
}
-
- Ok(())
-
}
-#include "barrel.cpp"
#include "homography.cpp"
+#include "barrel.cpp"
+
+#ifdef USE_LUT
#include "color.cpp"
+#endif
extern "C"
{
- void ProcessCapture(uint8_t *camera_ptr, uint8_t *buffer_ptr, double *homography_ptr, uint8_t *lut_ptr)
+ void ProcessCapture(uint8_t *camera_ptr, uint8_t *buffer_ptr, double *homography_ptr, uint8_t *lut_ptr, float* xmat_ptr, float* ymat_ptr)
{
/*
* Heres the plan:
* even thinking about it in the rust.
*/
+ //ApplyUndistort(camera_ptr, xmat_ptr, ymat_ptr);
ApplyHomography(camera_ptr, buffer_ptr, homography_ptr);
#ifdef USE_LUT
ApplyCorrection(buffer_ptr, lut_ptr);
}
// get homography function (see "homography.cpp")
- void GetHomography(uint8_t *camera_ptr, double *homography_ptr)
+ void GetHomography(uint8_t *camera_ptr, double *homography_ptr, float* xmat_ptr, float* ymat_ptr)
{
+ //ApplyUndistort(camera_ptr, xmat_ptr, ymat_ptr);
FuncGetHomography(camera_ptr, homography_ptr);
}
}
use crate::SPECTOGRAM_AREA;
pub struct SampleBuffer {
- buffer: Arc<Mutex<[i16; 2 * SPECTOGRAM_AREA]>>,
+ right_buffer: Arc<Mutex<[i16; 2 * SPECTOGRAM_AREA]>>,
+ left_buffer: Arc<Mutex<[i16; 2 * SPECTOGRAM_AREA]>>,
index: usize,
tx: Sender<bool>
}
impl SampleBuffer {
- pub fn new(buffer: Arc<Mutex<[i16; 2 * SPECTOGRAM_AREA]>>, tx: Sender<bool>) -> Self {
+ pub fn new(right_buffer: Arc<Mutex<[i16; 2 * SPECTOGRAM_AREA]>>, left_buffer: Arc<Mutex<[i16; 2 * SPECTOGRAM_AREA]>>, tx: Sender<bool>) -> Self {
+
Self {
- buffer,
+ right_buffer,
+ left_buffer,
index: 0,
tx
}
}
pub fn get_data(&mut self, data: &mut [i16]) {
- let mut buffer = self.buffer.lock().unwrap();
+ let mut right_buffer = self.right_buffer.lock().unwrap();
+ let mut left_buffer = self.left_buffer.lock().unwrap();
let length = data.len()/2;
for i in 0..length {
- data[i*2] = buffer[i + self.index];
+ data[i*2] = right_buffer[i + self.index];
+ data[i*2+1] = left_buffer[i + self.index];
}
self.index += length;
if self.index > SPECTOGRAM_AREA {
for i in 0..SPECTOGRAM_AREA {
- buffer[i] = buffer[i + SPECTOGRAM_AREA];
+ right_buffer[i] = right_buffer[i + SPECTOGRAM_AREA];
+ left_buffer[i] = left_buffer[i + SPECTOGRAM_AREA];
}
self.index -= SPECTOGRAM_AREA;
todo:
- test the lut system in-situ, graph for optimal
-- possibly see if a version can be made that takes mic input
-- implement recording for testing
- implement image display in unused channel
-
+- get temp guest list together
+- ask R about headcounts and other event things
- write cpp code for using cuFFT (not supported by rust-cuda)
-- potentially write rust-cuda kernel for the color conversion
+- add 3 to 2 reverse functions
+- implement the video frame reader
+- speed the whole thing up
QUICKLY:
-- make functional with windows
- - some things that might not be windows compatible:
- - show-image (YES but might need to mess with the backend)
- - hound for reading the wav files (YES)
- - cpal for the audio out (YES look into asio extra feature for lower latency)
- - rscam for the camera (NO drop in for nokhwa) (IMPLEMENTED)
- - the file paths (IMPLEMENTED)
- evaluate if cuda is neccicary
LIBRARIES:
- FFTW (https://www.fftw.org/fftw3_doc/) for the c++
-- nokhwa (IMPLEMENTED)
+- vid2img (https://github.com/rafaelcaricio/vid2img)
- fon
- rayon
- reinstate the read loop
AUDIO ISSUES:
-- disable the feedback mix code
-- disable the filtering code
+- implement filtering
+
+CLICKING:
+- check if messing with the itterators is possibly causing some kind of jump
+
+WARP ISSUES:
+- surf.setExtended(True) // set surf to 128 keypoints if its only 64 right now
+
+
+
+
+
+ // some code to turn the yuyv into rgb if we need it!
+ // let stride = (IMAGE_WIDTH * 3) as u32;
+ // let vuvy = YuvPackedImage{
+ // yuy: frame.buffer(),
+ // yuy_stride: stride,
+ // width: IMAGE_WIDTH as u32,
+ // height: IMAGE_HEIGHT as u32
+ // };
+ // let mut rgb = [0u8; IMAGE_AREA];
+ // yuyv422_to_rgb(
+ // &vuvy,
+ // &mut rgb,
+ // stride,
+ // YuvRange::Full,
+ // YuvStandardMatrix::Bt601
+ // ).unwrap();W
\ No newline at end of file