From 1a433614c6b04eccac2f33fe2df8bc4adc2b3d15 Mon Sep 17 00:00:00 2001 From: Michael Mikovsky <77305074+Astatin3@users.noreply.github.com> Date: Sun, 31 Aug 2025 12:31:40 -0600 Subject: [PATCH] Get streaming to work --- .gitignore | 3 + new-game-project/node_3d.gd | 34 +- new-game-project/node_3d.tscn | 1 - new-game-project/pointcloud.gd | 8 +- new-game-project/stream.gd | 105 ++ new-game-project/stream.gd.uid | 1 + raspi-proxy/.cargo/config.toml | 3 + raspi-proxy/Cargo.lock | 1584 +++++++++++++++++++++++++ raspi-proxy/Cargo.toml | 13 + raspi-proxy/run.sh | 20 + raspi-proxy/src/camera/camera.rs | 251 ++++ raspi-proxy/src/camera/fetch_frame.rs | 335 ++++++ raspi-proxy/src/camera/intrinsics.rs | 128 ++ raspi-proxy/src/camera/mod.rs | 8 + raspi-proxy/src/main.rs | 99 ++ 15 files changed, 2578 insertions(+), 15 deletions(-) create mode 100644 new-game-project/stream.gd create mode 100644 new-game-project/stream.gd.uid create mode 100644 raspi-proxy/.cargo/config.toml create mode 100644 raspi-proxy/Cargo.lock create mode 100644 raspi-proxy/Cargo.toml create mode 100755 raspi-proxy/run.sh create mode 100644 raspi-proxy/src/camera/camera.rs create mode 100644 raspi-proxy/src/camera/fetch_frame.rs create mode 100644 raspi-proxy/src/camera/intrinsics.rs create mode 100644 raspi-proxy/src/camera/mod.rs create mode 100644 raspi-proxy/src/main.rs diff --git a/.gitignore b/.gitignore index d9aac21..b4e7003 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# Rust +target/ + # Godot 4+ specific ignores .godot/ diff --git a/new-game-project/node_3d.gd b/new-game-project/node_3d.gd index 13e8dd1..8ea90c2 100644 --- a/new-game-project/node_3d.gd +++ b/new-game-project/node_3d.gd @@ -1,19 +1,23 @@ extends Node3D const num_points: int = 50 -const scale_pos: float = 0.01 -const scale_color: float = 255. / num_points +const scale_pos: float = -0.001 +const scale_color: float = 1 / num_points @onready var right_hand: XRController3D = get_node("XROrigin3D/RightHand") @onready var world_cloud: Pointcloud = get_node("World_Pointcloud") @onready var hand_cloud: Pointcloud = get_node("XROrigin3D/RightHand/Hand_Pointcloud") +var stream: Stream + var points: Array[Vector3] = [] -var colors: Array[Vector3] = [] +var colors: Array[Color] = [] var xr_interface: XRInterface +var thread: Thread + func _ready(): xr_interface = XRServer.find_interface("OpenXR") if xr_interface and xr_interface.is_initialized(): @@ -26,30 +30,40 @@ func _ready(): get_viewport().use_xr = true xr_interface.environment_blend_mode = XRInterface.XR_ENV_BLEND_MODE_ALPHA_BLEND get_viewport().transparent_bg = true + hand_cloud.global_scale(Vector3(scale_pos, scale_pos, scale_pos)) + #world_cloud.global_scale(Vector3(scale_pos, scale_pos, scale_pos)) else: print("OpenXR not initialized, please check if your headset is connected") - for x in 50: for y in 50: - points.append(Vector3(x * scale_pos, y * scale_pos, 0)) - colors.append(Vector3(x * scale_color, y * scale_color, 0)) + points.append(Vector3(x * 0.01, y * 0.01, 0)) + colors.append(Color(x * 0.01, y * 0.01, 0)) hand_cloud.set_points(points, colors) + + stream = Stream.new() + stream.start("10.42.0.1", 1234) + var last_pressed = false func _process(delta): + if(stream.new_points()): + hand_cloud.set_points(stream.current_points, stream.current_colors) + var pressed = right_hand.get_float("trigger") > 0. if(pressed && !last_pressed): var points_clone: Array[Vector3] = [] print(right_hand.global_position) - for point in points: - - points_clone.append(right_hand.to_global(point)) - world_cloud.add_points(points_clone, colors.duplicate()) + for point in stream.current_points: + points_clone.append(right_hand.to_global(point * scale_pos)) + + world_cloud.add_points(points_clone, stream.current_colors) last_pressed = true print("points! ", len(points_clone)) elif (!pressed): last_pressed = false + + diff --git a/new-game-project/node_3d.tscn b/new-game-project/node_3d.tscn index ceb9c59..84e0443 100644 --- a/new-game-project/node_3d.tscn +++ b/new-game-project/node_3d.tscn @@ -26,7 +26,6 @@ pose = &"aim" script = ExtResource("2_a0tk4") [node name="CSGBox3D2" type="CSGBox3D" parent="XROrigin3D/RightHand"] -visible = false size = Vector3(0.05, 0.05, 0.05) [node name="Hand_Pointcloud" type="MultiMeshInstance3D" parent="XROrigin3D/RightHand"] diff --git a/new-game-project/pointcloud.gd b/new-game-project/pointcloud.gd index 9535b69..2400112 100644 --- a/new-game-project/pointcloud.gd +++ b/new-game-project/pointcloud.gd @@ -4,7 +4,7 @@ class_name Pointcloud extends MultiMeshInstance3D var points: Array[Vector3] = [] -var colors: Array[Vector3] = [] +var colors: Array[Color] = [] func _ready(): multimesh = MultiMesh.new() @@ -21,14 +21,14 @@ func _ready(): multimesh.mesh=pmesh -func add_points(new_points:Array[Vector3],new_colors:Array[Vector3]): +func add_points(new_points:Array[Vector3],new_colors:Array[Color]): points.append_array(new_points) colors.append_array(new_colors) set_points(points, colors) -func set_points(points:Array[Vector3],colors:Array[Vector3]): +func set_points(points:Array[Vector3],colors:Array[Color]): multimesh.instance_count = len(points) for i in multimesh.instance_count: multimesh.set_instance_transform(i, Transform3D(Basis(), points[i])) - multimesh.set_instance_color(i,Color(colors[i].x/256.0,colors[i].y/256.0,colors[i].z/256.0)) + multimesh.set_instance_color(i,colors[i]) diff --git a/new-game-project/stream.gd b/new-game-project/stream.gd new file mode 100644 index 0000000..aafc7ac --- /dev/null +++ b/new-game-project/stream.gd @@ -0,0 +1,105 @@ +class_name Stream +extends Node + +var thread: Thread +var _status: int = 0 +var _stream: StreamPeerTCP = StreamPeerTCP.new() + +func start(host: String, port: int): + thread = Thread.new() + thread.start(tcp_server.bind(host, port)) + +func tcp_server(host: String, port: int): + while true: + connect_to_host(host, port) + + while process(): + pass + + OS.delay_msec(1000) + +func connect_to_host(host: String, port: int) -> bool: + print("Connecting to %s:%d" % [host, port]) + # Reset status so we can tell if it changes to error again. + _status = _stream.STATUS_NONE + if _stream.connect_to_host(host, port) != OK: + print("Error connecting to host.") + return false + return true + #emit_signal("error") + +func process() -> bool: + _stream.poll() + var new_status: int = _stream.get_status() + if new_status != _status: + _status = new_status + match _status: + _stream.STATUS_NONE: + print("Disconnected from host.") + return false + #emit_signal("disconnected") + _stream.STATUS_CONNECTING: + print("Connecting to host.") + return true + _stream.STATUS_CONNECTED: + print("Connected to host.") + #emit_signal("connected") + _stream.STATUS_ERROR: + print("Error with socket stream.") + return false + #emit_signal("error") + + if _status == _stream.STATUS_CONNECTED: + parse_bytes() + return true + + return false + + +var current_packet_length: int = -1 +var current_index: int = 0 + +var current_points: Array[Vector3] = [] +var current_colors: Array[Color] = [] +var has_new_points = false + +var overflow_bytes: Array = [] + + +func parse_bytes(): + _stream.put_u8(2); + + var type = _stream.get_32() + + match type: + 1: + var len = _stream.get_32() + + print("Got type %d with len %d" % [type, len]) + + var points: Array[Vector3] = [] + var colors: Array[Color] = [] + # + for i in len: + points.append(Vector3( + _stream.get_32(), + _stream.get_32(), + _stream.get_32() + )) + # + colors.append(Color( + _stream.get_u8() / 256., + _stream.get_u8() / 256., + _stream.get_u8() / 256. + )) + + current_points = points + current_colors = colors + has_new_points = true + + +func new_points() -> bool: + if(has_new_points): + has_new_points = false + return true + return false diff --git a/new-game-project/stream.gd.uid b/new-game-project/stream.gd.uid new file mode 100644 index 0000000..c14dbe4 --- /dev/null +++ b/new-game-project/stream.gd.uid @@ -0,0 +1 @@ +uid://bxmxpyrxv8wfr diff --git a/raspi-proxy/.cargo/config.toml b/raspi-proxy/.cargo/config.toml new file mode 100644 index 0000000..214b932 --- /dev/null +++ b/raspi-proxy/.cargo/config.toml @@ -0,0 +1,3 @@ +[target.aarch64-unknown-linux-gnu] +linker = "/usr/bin/aarch64-linux-gnu-g++" + diff --git a/raspi-proxy/Cargo.lock b/raspi-proxy/Cargo.lock new file mode 100644 index 0000000..b3e13bb --- /dev/null +++ b/raspi-proxy/Cargo.lock @@ -0,0 +1,1584 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "aligned-vec" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b" +dependencies = [ + "equator", +] + +[[package]] +name = "anyhow" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" + +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" + +[[package]] +name = "arg_enum_proc_macro" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "av1-grain" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f3efb2ca85bc610acfa917b5aaa36f3fcbebed5b3182d7f877b02531c4b80c8" +dependencies = [ + "anyhow", + "arrayvec", + "log 0.4.27", + "nom", + "num-rational", + "v_frame", +] + +[[package]] +name = "avif-serialize" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47c8fbc0f831f4519fe8b810b6a7a91410ec83031b8233f730a0480029f6a23f" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bit_field" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitstream-io" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2" + +[[package]] +name = "built" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ed6191a7e78c36abdb16ab65341eefd73d64d303fffccdbb00d51e4205967b" + +[[package]] +name = "bumpalo" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + +[[package]] +name = "bytemuck" +version = "1.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + +[[package]] +name = "cc" +version = "1.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42bc4aea80032b7bf409b0bc7ccad88853858911b7713a8062fdc0623867bedc" +dependencies = [ + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-expr" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +dependencies = [ + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cfg-if" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "env_logger" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" +dependencies = [ + "humantime", + "is-terminal", + "log 0.4.27", + "regex", + "termcolor", +] + +[[package]] +name = "equator" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc" +dependencies = [ + "equator-macro", +] + +[[package]] +name = "equator-macro" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "exr" +version = "1.73.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83197f59927b46c04a183a619b7c29df34e63e63c7869320862268c0ef687e0" +dependencies = [ + "bit_field", + "half", + "lebe", + "miniz_oxide", + "rayon-core", + "smallvec", + "zune-inflate", +] + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "flate2" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.3+wasi-0.2.4", +] + +[[package]] +name = "gif" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae047235e33e2829703574b54fdec96bfbad892062d97fed2f76022287de61b" +dependencies = [ + "color_quant", + "weezl", +] + +[[package]] +name = "half" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" +dependencies = [ + "cfg-if", + "crunchy", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "http" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "humantime" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f" + +[[package]] +name = "image" +version = "0.25.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a" +dependencies = [ + "bytemuck", + "byteorder-lite", + "color_quant", + "exr", + "gif", + "image-webp", + "num-traits", + "png", + "qoi", + "ravif", + "rayon", + "rgb", + "tiff", + "zune-core", + "zune-jpeg", +] + +[[package]] +name = "image-webp" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3" +dependencies = [ + "byteorder-lite", + "quick-error", +] + +[[package]] +name = "imgref" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408" + +[[package]] +name = "indexmap" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "interpolate_name" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "is-terminal" +version = "0.4.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.3", + "libc", +] + +[[package]] +name = "jpeg-decoder" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00810f1d8b74be64b13dbf3db89ac67740615d6c891f0e7b6179326533011a07" + +[[package]] +name = "lebe" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" + +[[package]] +name = "libc" +version = "0.2.175" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" + +[[package]] +name = "libfuzzer-sys" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5037190e1f70cbeef565bd267599242926f724d3b8a9f510fd7e0b540cfa4404" +dependencies = [ + "arbitrary", + "cc", +] + +[[package]] +name = "log" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" +dependencies = [ + "log 0.4.27", +] + +[[package]] +name = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + +[[package]] +name = "loop9" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" +dependencies = [ + "imgref", +] + +[[package]] +name = "matrixmultiply" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08" +dependencies = [ + "autocfg", + "rawpointer", +] + +[[package]] +name = "maybe-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +dependencies = [ + "cfg-if", + "rayon", +] + +[[package]] +name = "memchr" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "ndarray" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841" +dependencies = [ + "matrixmultiply", + "num-complex", + "num-integer", + "num-traits", + "portable-atomic", + "portable-atomic-util", + "rawpointer", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "noop_proc_macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" + +[[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]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "png" +version = "0.17.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" +dependencies = [ + "bitflags", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "portable-atomic" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" + +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "pretty_env_logger" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "865724d4dbe39d9f3dd3b52b88d859d66bcb2d6a0acfd5ea68a65fb66d4bdc1c" +dependencies = [ + "env_logger", + "log 0.4.27", +] + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "profiling" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773" +dependencies = [ + "profiling-procmacros", +] + +[[package]] +name = "profiling-procmacros" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "qoi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.16", +] + +[[package]] +name = "raspi-proxy" +version = "0.1.0" +dependencies = [ + "byteorder", + "image", + "log 0.4.27", + "ndarray", + "pretty_env_logger", + "ureq", + "warn", +] + +[[package]] +name = "rav1e" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9" +dependencies = [ + "arbitrary", + "arg_enum_proc_macro", + "arrayvec", + "av1-grain", + "bitstream-io", + "built", + "cfg-if", + "interpolate_name", + "itertools", + "libc", + "libfuzzer-sys", + "log 0.4.27", + "maybe-rayon", + "new_debug_unreachable", + "noop_proc_macro", + "num-derive", + "num-traits", + "once_cell", + "paste", + "profiling", + "rand", + "rand_chacha", + "simd_helpers", + "system-deps", + "thiserror", + "v_frame", + "wasm-bindgen", +] + +[[package]] +name = "ravif" +version = "0.11.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5825c26fddd16ab9f515930d49028a630efec172e903483c94796cfe31893e6b" +dependencies = [ + "avif-serialize", + "imgref", + "loop9", + "quick-error", + "rav1e", + "rayon", + "rgb", +] + +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + +[[package]] +name = "rayon" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "regex" +version = "1.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" + +[[package]] +name = "rgb" +version = "0.8.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c6a884d2998352bb4daf0183589aec883f16a6da1f4dde84d8e2e9a5409a1ce" + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.16", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.23.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" +dependencies = [ + "log 0.4.27", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[package]] +name = "simd_helpers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" +dependencies = [ + "quote", +] + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "system-deps" +version = "6.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" +dependencies = [ + "cfg-expr", + "heck", + "pkg-config", + "toml", + "version-compare", +] + +[[package]] +name = "target-lexicon" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tiff" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" +dependencies = [ + "flate2", + "jpeg-decoder", + "weezl", +] + +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "ureq" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00432f493971db5d8e47a65aeb3b02f8226b9b11f1450ff86bb772776ebadd70" +dependencies = [ + "base64", + "flate2", + "log 0.4.27", + "percent-encoding", + "rustls", + "rustls-pemfile", + "rustls-pki-types", + "ureq-proto", + "utf-8", + "webpki-roots", +] + +[[package]] +name = "ureq-proto" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe120bb823a0061680e66e9075942fcdba06d46551548c2c259766b9558bc9a" +dependencies = [ + "base64", + "http", + "httparse", + "log 0.4.27", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "v_frame" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "666b7727c8875d6ab5db9533418d7c764233ac9c0cff1d469aec8fa127597be2" +dependencies = [ + "aligned-vec", + "num-traits", + "wasm-bindgen", +] + +[[package]] +name = "version-compare" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" + +[[package]] +name = "warn" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f2638072850e7fde2e4e96d78204024000382e5666876bd8a3e7e9db6ed22cb" +dependencies = [ + "log 0.3.9", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasi" +version = "0.14.3+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a51ae83037bdd272a9e28ce236db8c07016dd0d50c27038b3f407533c030c95" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log 0.4.27", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "webpki-roots" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8983c3ab33d6fb807cfcdad2491c4ea8cbc8ed839181c7dfd9c67c83e261b2" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "weezl" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3" + +[[package]] +name = "winapi-util" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0978bf7171b3d90bac376700cb56d606feb40f251a475a5d6634613564460b22" +dependencies = [ + "windows-sys 0.60.2", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.3", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + +[[package]] +name = "winnow" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "052283831dbae3d879dc7f51f3d92703a316ca49f91540417d38591826127814" + +[[package]] +name = "zerocopy" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[package]] +name = "zune-core" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" + +[[package]] +name = "zune-inflate" +version = "0.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "zune-jpeg" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1f7e205ce79eb2da3cd71c5f55f3589785cb7c79f6a03d1c8d1491bda5d089" +dependencies = [ + "zune-core", +] diff --git a/raspi-proxy/Cargo.toml b/raspi-proxy/Cargo.toml new file mode 100644 index 0000000..8d24477 --- /dev/null +++ b/raspi-proxy/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "raspi-proxy" +version = "0.1.0" +edition = "2024" + +[dependencies] +byteorder = "1.5.0" +image = "0.25.6" +log = "0.4.27" +ndarray = "0.16.1" +pretty_env_logger = "0.5.0" +ureq = "3.1.0" +warn = "0.2.2" diff --git a/raspi-proxy/run.sh b/raspi-proxy/run.sh new file mode 100755 index 0000000..00bb0a5 --- /dev/null +++ b/raspi-proxy/run.sh @@ -0,0 +1,20 @@ +set -o errexit +set -o nounset +set -o pipefail +set -o xtrace + +# SSH Config +REMOTE_LOCATION="10.42.0.1" +REMOTE_USERNAME="user" +REMOTE_PASSWORD="pass" + +# Other constants +BINARY_NAME="raspi-proxy" +TARGET_HOST=${REMOTE_USERNAME}@${REMOTE_LOCATION} +TARGET_ARCH=aarch64-unknown-linux-gnu +SOURCE_PATH="./target/${TARGET_ARCH}/release/${BINARY_NAME}" +TARGET_PATH="/home/${REMOTE_USERNAME}/${BINARY_NAME}" + +cargo build --release --target=$TARGET_ARCH $@ # Build +sshpass -p ${REMOTE_PASSWORD} scp ${SOURCE_PATH} ${TARGET_HOST}:${TARGET_PATH} # Upload +sshpass -p ${REMOTE_PASSWORD} ssh -t ${TARGET_HOST} "RUST_BACKTRACE=full RUST_LOG=info ${TARGET_PATH}" # Run \ No newline at end of file diff --git a/raspi-proxy/src/camera/camera.rs b/raspi-proxy/src/camera/camera.rs new file mode 100644 index 0000000..d4368c3 --- /dev/null +++ b/raspi-proxy/src/camera/camera.rs @@ -0,0 +1,251 @@ +use std::{ + sync::{ + Arc, Mutex + }, + thread, +}; + +use std::io::Cursor; + +use byteorder::{LittleEndian, ReadBytesExt}; +use ndarray::Array2; + +use crate::camera::{fetch_frame::{decode_frame, frame_config_encode, normalize, ProcessedFrames}, intrinsics::{depth_to_point_cloud, DEFAULT_INTRINSICS}, PointArr}; + + +// Constants (replace with your actual values) +const HOST: &str = "192.168.233.1"; +const PORT: u16 = 80; + +pub struct PrevFrames { + pub depth: Array2, + pub status: Array2, +} + +impl Default for PrevFrames { + fn default() -> Self { + Self { + depth: Array2::from_elem((240, 320), 0), + status: Array2::from_elem((240, 320), 0), + } + } +} + +pub struct SipeedCamera { + frames: Arc>, + prev_frames: PrevFrames, + thread_handle: Option>, + // point_cloud: LivePointView, +} + +impl Default for SipeedCamera { + fn default() -> Self { + // Shared state for the latest processed frames + let frames = Arc::new(Mutex::new(ProcessedFrames::default())); + + let frames_clone = Arc::clone(&frames); + let decoder_handle = thread::spawn(move || { + loop { + match fetch_frame() { + Ok(frame_data) => match decode_frame(&frame_data) { + Ok(processed) => { + *frames_clone.lock().unwrap() = processed; + } + Err(e) => warn!("Error decoding frame: {}", e), + }, + Err(e) => warn!("Error fetching frame: {}", e), + } + } + }); + + Self { + frames, + thread_handle: Some(decoder_handle), + prev_frames: PrevFrames::default(), + // point_cloud: LivePointView::default(), + } + } +} + +impl SipeedCamera { + pub fn get_points(&mut self) -> Option { + let frames_lock = self.frames.lock().unwrap(); + let ref frames = *frames_lock; + + // let prev_status_lock = self.prev_status.lock(); + // let ref prev_status = *prev_status_lock; + + let mut processed = false; + + // Display depth image + if let Some(ref depth) = frames.depth { + self.prev_frames.depth = (&self.prev_frames.depth + depth) / 2; + + let depth_viz = normalize(&self.prev_frames.depth); + processed = true; + } + + // // Display IR image + // if let Some(ref ir) = frames.ir { + // let ir_viz = normalize(ir); + // ui.heading("IR"); + // image_widget(ui, "ir_img", &ir_viz, [320.0, 240.0]); + // processed = true; + // } + + // Display status image if available + if let Some(ref status) = frames.status { + self.prev_frames.status = (&self.prev_frames.status + (2 - status)) / 2; + let status_viz = normalize(&self.prev_frames.status); + processed = true; + } + + // Display RGB image if available + if let Some(ref rgb) = frames.rgb { + let rgb_viz = rgb.as_slice().unwrap(); + let size = match rgb.dim().1 { + 640 => [640.0, 480.0], + 800 => [800.0, 600.0], + _ => [640.0, 480.0], // Default + }; + processed = true; + } + + if let Some(ref status) = frames.status { + if let Some(ref rgb) = frames.rgb { + let mut points: PointArr = Vec::new(); + + for i in 0..(320 * 240) { + let x = i / 240; + let y = i % 320; + + // println!("{:?}", status.get((x, y))); + + let status = status.get((x, y)); + + if status.is_none() || *status.unwrap() != 0 { + continue; + } + + // let prev_status = prev_status.get((x, y)); + + // if prev_status.is_none() || *prev_status.unwrap() != 0 { + // continue; + // } + + // if *status.get((x, y)).unwrap() != 0u16 { + // continue; + // } + // + + let (r, g, b) = if let Some((rgbx, rgby)) = scale_shift_rgb_xy(x, y) { + ( + *rgb.get((rgbx, rgby, 0)).unwrap() as u8, + *rgb.get((rgbx, rgby, 1)).unwrap() as u8, + *rgb.get((rgbx, rgby, 2)).unwrap() as u8, + ) + } else { + (255, 255, 255) + }; + + let d = self.prev_frames.depth.get((x, y)).unwrap(); + + let (x, y, z) = depth_to_point_cloud( + x as i32, + y as i32, + d + 50, + &DEFAULT_INTRINSICS, + ); + + points.push((x, y, z, r, g, b)) + } + + return Some(points) + } + } + + None + + // self.point_cloud.render(ui); + } +} + +fn scale_shift_rgb_xy(x: usize, y: usize) -> Option<(usize, usize)> { + static X_OFFSET: f32 = 30.; + static Y_OFFSET: f32 = 22.; + static SCAME: f32 = 1.75; + + let x = ((x as f32 + X_OFFSET) * SCAME) as usize; + let y = ((y as f32 + Y_OFFSET) * SCAME) as usize; + + if y >= 640 { + return None; + } + if x >= 480 { + return None; + } + + // println!("{}, {}", x, y); + + Some((x as usize, y as usize)) +} + +fn fetch_frame() -> Result, Box> { + is_success(&frame_config_encode(1, 0, 255, 0, 2, 7, 1, 0, 0))?; + + + let url = format!("http://{}:{}/getdeep", HOST, PORT); + + trace!("Fetching images from: {}", url); + + let response = ureq::get(url).call()?; + + if response.status() != 200 { + return Err(format!("Failed to get frame: HTTP {}", response.status()).into()); + } + + trace!("Got deep image"); + let deep_img = response.into_body().read_to_vec()?; + trace!("Length={}", deep_img.len()); + + // Parse frame ID and timestamp + if deep_img.len() >= 16 { + let mut cursor = Cursor::new(&deep_img[0..16]); + let frame_id = cursor.read_u64::()?; + let stamp_msec = cursor.read_u64::()?; + trace!( + "Frame ID: {}, Timestamp: {:.3}s", + frame_id, + stamp_msec as f64 / 1000.0 + ); + } + + return Ok(deep_img); +} + +fn is_success(data: &[u8]) -> Result<(), Box> { + let url = format!("http://{}:{}/set_cfg", HOST, PORT); + + trace!("Sending request to: {}", url); + + let response = ureq::post(url).send(data.to_vec())?; + if response.status() == 200 { + return Ok(()); + } else { + return Err(format!("Status code: {}", response.status().to_string()).into()); + } +} + +// Helper to display images in egui +// fn image_widget(ui: &mut egui::Ui, id: &str, rgb_data: &[u8], size: [f32; 2]) { +// let color_image = egui::ColorImage::from_rgb([size[0] as usize, size[1] as usize], rgb_data); + +// let handle = ui +// .ctx() +// .load_texture(id, color_image, egui::TextureOptions::LINEAR); + +// let sized_image = +// egui::load::SizedTexture::new(handle.id(), egui::vec2(size[0] as f32, size[1] as f32)); + +// ui.image(sized_image); +// } diff --git a/raspi-proxy/src/camera/fetch_frame.rs b/raspi-proxy/src/camera/fetch_frame.rs new file mode 100644 index 0000000..9ae6680 --- /dev/null +++ b/raspi-proxy/src/camera/fetch_frame.rs @@ -0,0 +1,335 @@ +use byteorder::{LittleEndian, ReadBytesExt}; +use ndarray::{Array2, Array3}; +use std::io::Cursor; + +pub struct ProcessedFrames { + pub depth: Option>, + pub ir: Option>, + pub status: Option>, + pub rgb: Option>, +} + +impl Default for ProcessedFrames { + fn default() -> Self { + Self { + depth: None, + ir: None, + status: None, + rgb: None, + } + } +} + +// Messages between threads +pub enum FrameMessage { + RawFrame(Vec), + DecodedFrame(ProcessedFrames), + Shutdown, +} + +// Frame data structures +#[allow(dead_code)] +pub struct FrameConfig { + trigger_mode: u8, + deep_mode: u8, + deep_shift: u8, + ir_mode: u8, + status_mode: u8, + status_mask: u8, + rgb_mode: u8, + rgb_res: u8, + expose_time: i32, +} + +pub struct FramePayload { + depth_img: Option>, + ir_img: Option>, + status_img: Option>, + rgb_img: Option>, +} + +// Helper functions +fn frame_config_decode(frame_config: &[u8]) -> Result> { + if frame_config.len() < 12 { + return Err("Frame config data too short".into()); + } + + let mut cursor = Cursor::new(frame_config); + + Ok(FrameConfig { + trigger_mode: cursor.read_u8()?, + deep_mode: cursor.read_u8()?, + deep_shift: cursor.read_u8()?, + ir_mode: cursor.read_u8()?, + status_mode: cursor.read_u8()?, + status_mask: cursor.read_u8()?, + rgb_mode: cursor.read_u8()?, + rgb_res: cursor.read_u8()?, + expose_time: cursor.read_i32::()?, + }) +} + +pub fn frame_config_encode( + trigger_mode: u8, + deep_mode: u8, + deep_shift: u8, + ir_mode: u8, + status_mode: u8, + status_mask: u8, + rgb_mode: u8, + rgb_res: u8, + expose_time: i32, +) -> Vec { + let mut result = Vec::with_capacity(12); + result.push(trigger_mode); + result.push(deep_mode); + result.push(deep_shift); + result.push(ir_mode); + result.push(status_mode); + result.push(status_mask); + result.push(rgb_mode); + result.push(rgb_res); + + // Add expose_time as little endian + result.extend_from_slice(&expose_time.to_le_bytes()); + + result +} + +fn frame_payload_decode( + frame_data: &[u8], + config: &FrameConfig, +) -> Result> { + if frame_data.len() < 8 { + return Err("Frame data too short".into()); + } + + let mut cursor = Cursor::new(&frame_data[0..8]); + let deep_data_size = cursor.read_i32::()?; + let rgb_data_size = cursor.read_i32::()?; + + let mut payload = &frame_data[8..]; + + // Depth image + let depth_size = (320 * 240 * 2) >> config.deep_mode; + let depth_img = if depth_size > 0 && payload.len() >= depth_size { + let result = payload[..depth_size].to_vec(); + payload = &payload[depth_size..]; + Some(result) + } else { + None + }; + + // IR image + let ir_size = (320 * 240 * 2) >> config.ir_mode; + let ir_img = if ir_size > 0 && payload.len() >= ir_size { + let result = payload[..ir_size].to_vec(); + payload = &payload[ir_size..]; + Some(result) + } else { + None + }; + + // Status image + let status_size = (320 * 240 / 8) + * match config.status_mode { + 0 => 16, + 1 => 2, + 2 => 8, + _ => 1, + }; + + let status_img = if status_size > 0 && payload.len() >= status_size { + let result = payload[..status_size].to_vec(); + payload = &payload[status_size..]; + Some(result) + } else { + None + }; + + // Verify deep data size + let calculated_deep_size = depth_size + ir_size + status_size; + if calculated_deep_size != deep_data_size as usize { + warn!( + "Warning: Deep data size mismatch: {} vs {}", + calculated_deep_size, deep_data_size + ); + } + + // RGB image + let rgb_size = payload.len(); + if rgb_size != rgb_data_size as usize { + warn!( + "Warning: RGB data size mismatch: {} vs {}", + rgb_size, rgb_data_size + ); + } + + let rgb_img = if rgb_size > 0 { + // Process RGB image based on config + if config.rgb_mode == 1 { + // JPEG decode using OpenCV + let rgb_data = payload.to_vec(); + let decoded = decode_jpeg(&rgb_data); + decoded + } else { + Some(payload.to_vec()) + } + } else { + None + }; + + Ok(FramePayload { + depth_img, + ir_img, + status_img, + rgb_img, + }) +} + +fn decode_jpeg(jpeg_data: &[u8]) -> Option> { + // Use the image crate to decode JPEG and convert to RGB + let img = image::load_from_memory(jpeg_data).ok()?; + let rgb_img = img.to_rgb8(); + + // Convert to raw bytes + Some(rgb_img.into_raw()) +} + +pub fn decode_frame(frame_data: &[u8]) -> Result> { + if frame_data.len() < 28 { + // 16 (header) + 12 (config) + return Err("Frame data too short".into()); + } + + // Extract config + let config = frame_config_decode(&frame_data[16..28])?; + + // Decode payload + let payload = frame_payload_decode(&frame_data[28..], &config)?; + + // Process depth image + let depth = if let Some(depth_data) = payload.depth_img { + if config.deep_mode == 0 { + let data = depth_data.as_slice(); + let depth_array = Array2::from_shape_fn((240, 320), |(y, x)| { + let idx = (y * 320 + x) * 2; + if idx + 1 < data.len() { + u16::from_le_bytes([data[idx], data[idx + 1]]) + } else { + 0 + } + }); + Some(depth_array) + } else { + let data = depth_data.as_slice(); + let depth_array = Array2::from_shape_fn((240, 320), |(y, x)| { + let idx = y * 320 + x; + if idx < data.len() { + u16::from(data[idx]) + } else { + 0 + } + }); + Some(depth_array) + } + } else { + None + }; + + // Process IR image + let ir = if let Some(ir_data) = payload.ir_img { + if config.ir_mode == 0 { + let data = ir_data.as_slice(); + let ir_array = Array2::from_shape_fn((240, 320), |(y, x)| { + let idx = (y * 320 + x) * 2; + if idx + 1 < data.len() { + u16::from_le_bytes([data[idx], data[idx + 1]]) + } else { + 0 + } + }); + Some(ir_array) + } else { + let data = ir_data.as_slice(); + let ir_array = Array2::from_shape_fn((240, 320), |(y, x)| { + let idx = y * 320 + x; + if idx < data.len() { + u16::from(data[idx]) + } else { + 0 + } + }); + Some(ir_array) + } + } else { + None + }; + + // Process status image + let status = if let Some(status_data) = payload.status_img { + // Process according to status_mode + let data = status_data.as_slice(); + let status_array = Array2::from_shape_fn((240, 320), |(y, x)| { + // This is a simplified approach - actual processing depends on status_mode + let idx = y * 320 + x; + if idx < data.len() { + u16::from(data[idx]) + } else { + 0 + } + }); + Some(status_array) + } else { + None + }; + + // Process RGB image + let rgb = if let Some(rgb_data) = payload.rgb_img { + let shape = if config.rgb_mode == 1 { + match config.rgb_res { + 0 => (480, 640, 3), // Default resolution + _ => (600, 800, 3), // Alternative resolution + } + } else { + (480, 640, 3) // Default for non-JPEG + }; + + if rgb_data.len() >= shape.0 * shape.1 * shape.2 { + let rgb_array = Array3::from_shape_vec((shape.0, shape.1, shape.2), rgb_data)?; + Some(rgb_array) + } else { + trace!( + "RGB data size ({}) doesn't match expected size ({})", + rgb_data.len(), + shape.0 * shape.1 * shape.2 + ); + None + } + } else { + None + }; + + Ok(ProcessedFrames { + depth, + ir, + status, + rgb, + }) +} + +pub fn normalize(data: &Array2) -> Vec { + let mut result = Vec::with_capacity(data.dim().0 * data.dim().1 * 3); + + let max = 255. / (*data.iter().max().unwrap_or(&255u16) as f32); + + for &value in data.iter() { + let num = (value as f32 * max) as u8; + + result.push(num); + result.push(num); + result.push(num); + } + + result +} diff --git a/raspi-proxy/src/camera/intrinsics.rs b/raspi-proxy/src/camera/intrinsics.rs new file mode 100644 index 0000000..544690e --- /dev/null +++ b/raspi-proxy/src/camera/intrinsics.rs @@ -0,0 +1,128 @@ +use std::f64; + +pub static DEFAULT_INTRINSICS: CameraIntrinsics = CameraIntrinsics { + fx: 2.318290e+02, + fy: 2.327785e+02, + u0: 1.669372e+02, + v0: 1.235151e+02, + k1: 5.857900e-02, + k2: 2.431399e-02, + k3: -2.737180e-01, + p1: 2.299994e-05, + p2: 1.658998e-03, +}; + +/// Camera intrinsic parameters +#[derive(Debug, Clone, Copy)] +pub struct CameraIntrinsics { + pub fx: f64, // focal length x + pub fy: f64, // focal length y + pub u0: f64, // principal point x + pub v0: f64, // principal point y + pub k1: f64, // radial distortion coefficient 1 + pub k2: f64, // radial distortion coefficient 2 + pub k3: f64, // radial distortion coefficient 3 + pub p1: f64, // tangential distortion coefficient 1 + pub p2: f64, // tangential distortion coefficient 2 +} + +impl CameraIntrinsics { + pub fn new( + fx: f64, + fy: f64, + u0: f64, + v0: f64, + k1: f64, + k2: f64, + k3: f64, + p1: f64, + p2: f64, + ) -> Self { + Self { + fx, + fy, + u0, + v0, + k1, + k2, + k3, + p1, + p2, + } + } +} + +/// Convert a pixel with depth information to a 3D point +/// +/// # Arguments +/// * `x` - x-coordinate in the image (columns) +/// * `y` - y-coordinate in the image (rows) +/// * `depth` - depth value at the pixel (typically in millimeters) +/// * `intrinsics` - camera intrinsic parameters +/// +/// # Returns +/// A 3D point in the camera coordinate system +pub fn depth_to_point_cloud( + x: i32, + y: i32, + depth: u16, + intrinsics: &CameraIntrinsics, +) -> (i32, i32, i32) { + // Convert pixel coordinates to normalized image coordinates + let x_f = x as f64; + let y_f = y as f64; + + // Apply distortion correction if needed + let (x_corrected, y_corrected) = correct_distortion(x_f, y_f, intrinsics); + + // Convert normalized image coordinates to camera coordinates + let z = depth as f64; // depth in camera z-direction + + // Back-project using the pinhole camera model + // (x - u0) / fx = X / Z + // (y - v0) / fy = Y / Z + let x_3d = (x_corrected - intrinsics.u0) * z / intrinsics.fx; + let y_3d = (y_corrected - intrinsics.v0) * z / intrinsics.fy; + + // Return the 3D point, converting to integer values if needed + (x_3d.round() as i32, y_3d.round() as i32, z.round() as i32) +} + +/// Corrects for lens distortion based on the Brown-Conrady model +/// +/// # Arguments +/// * `x` - uncorrected x coordinate in pixel space +/// * `y` - uncorrected y coordinate in pixel space +/// * `intrinsics` - camera intrinsic parameters with distortion coefficients +/// +/// # Returns +/// Corrected (x, y) coordinates +fn correct_distortion(x: f64, y: f64, intrinsics: &CameraIntrinsics) -> (f64, f64) { + // Convert to normalized image coordinates (centered at principal point) + let x_norm = (x - intrinsics.u0) / intrinsics.fx; + let y_norm = (y - intrinsics.v0) / intrinsics.fy; + + // Calculate squared radius for radial distortion + let r2 = x_norm * x_norm + y_norm * y_norm; + let r4 = r2 * r2; + let r6 = r4 * r2; + + // Calculate radial distortion factor + let radial_factor = 1.0 + intrinsics.k1 * r2 + intrinsics.k2 * r4 + intrinsics.k3 * r6; + + // Calculate tangential distortion + let tangential_x = + 2.0 * intrinsics.p1 * x_norm * y_norm + intrinsics.p2 * (r2 + 2.0 * x_norm * x_norm); + let tangential_y = + intrinsics.p1 * (r2 + 2.0 * y_norm * y_norm) + 2.0 * intrinsics.p2 * x_norm * y_norm; + + // Apply distortion correction + let x_corrected = x_norm * radial_factor + tangential_x; + let y_corrected = y_norm * radial_factor + tangential_y; + + // Convert back to pixel coordinates + let x_pixel = x_corrected * intrinsics.fx + intrinsics.u0; + let y_pixel = y_corrected * intrinsics.fy + intrinsics.v0; + + (x_pixel, y_pixel) +} diff --git a/raspi-proxy/src/camera/mod.rs b/raspi-proxy/src/camera/mod.rs new file mode 100644 index 0000000..16242e4 --- /dev/null +++ b/raspi-proxy/src/camera/mod.rs @@ -0,0 +1,8 @@ +mod fetch_frame; +mod intrinsics; +mod camera; + +pub use camera::SipeedCamera; + +pub type Point = (i32, i32, i32, u8, u8, u8); +pub type PointArr = Vec; \ No newline at end of file diff --git a/raspi-proxy/src/main.rs b/raspi-proxy/src/main.rs new file mode 100644 index 0000000..e683969 --- /dev/null +++ b/raspi-proxy/src/main.rs @@ -0,0 +1,99 @@ +#[macro_use] +extern crate log; +mod camera; + +use std::{io::{Read, Write}, net::{TcpListener, TcpStream}}; + +use camera::SipeedCamera; + +const SOCKET: &'static str = "0.0.0.0:1234"; + +enum DataBlocks { + Error = 0, + PointCloudData = 1, + ReadyData = 2 +} + +pub fn main() { + pretty_env_logger::init(); + + let mut camera = SipeedCamera::default(); + + info!("Connection established with camera"); + + // loop { + // let points = camera.get_points(); + // info!("{:?}", points); + // } + + + let mut listener = TcpListener::bind(SOCKET).expect("Failed to bind"); + + info!("Server listening on {}", SOCKET); + + loop { + match run_server(&mut camera, &mut listener) { + Err(e) => { + error!("{}", e); + } + _ => {} + } + } + + // println!("Test!"); +} + +fn run_server(camera: &mut SipeedCamera, listener: &mut TcpListener) -> Result<(), std::io::Error> { + for stream in listener.incoming() { + let mut stream = stream?; + + info!("New connection: {}", stream.peer_addr().unwrap()); + run_stream(camera, &mut stream)?; + + } + + Ok(()) +} + +fn run_stream(camera: &mut SipeedCamera,stream: &mut TcpStream) -> Result<(), std::io::Error> { + loop { + let mut recv_buf = [0u8; 1]; + stream.read_exact(&mut recv_buf)?; + assert!(recv_buf[0] == DataBlocks::ReadyData as u8); + + + let mut bytes = Vec::new(); + + let points = camera.get_points(); + + if let Some(points) = points { + + + // bytes.append(&mut ("A").as_bytes().to_vec()); + // bytes.append(&mut "B".as_bytes().to_vec()); + + bytes.append(&mut (DataBlocks::PointCloudData as i32).to_le_bytes().to_vec()); + bytes.append(&mut (points.len() as i32).to_le_bytes().to_vec()); + // bytes.append(&mut points.len().to_le_bytes().to_vec()); + + for point in points { + bytes.append(&mut point.0.to_le_bytes().to_vec()); + bytes.append(&mut point.1.to_le_bytes().to_vec()); + bytes.append(&mut point.2.to_le_bytes().to_vec()); + bytes.append(&mut point.3.to_le_bytes().to_vec()); + bytes.append(&mut point.4.to_le_bytes().to_vec()); + bytes.append(&mut point.5.to_le_bytes().to_vec()); + } + + } else { + bytes.append(&mut (DataBlocks::Error as i32).to_le_bytes().to_vec()); + } + + + + stream.write_all(&bytes)?; + stream.flush()?; + + info!("Sent {} bytes", bytes.len()); + } +} \ No newline at end of file