From 52f70cded9b3bea6729190efb13cb611486a484d Mon Sep 17 00:00:00 2001 From: Alexandre Marcireau Date: Tue, 14 Oct 2025 15:49:18 +0100 Subject: [PATCH] Add a skeleton for the rosbag decoder --- Cargo.lock | 41 ++++++++++++++++++ Cargo.toml | 1 + src/lib.rs | 6 +++ src/rosbag/decoder.rs | 44 +++++++++++++++++++ src/rosbag/mod.rs | 98 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 190 insertions(+) create mode 100644 src/rosbag/decoder.rs create mode 100644 src/rosbag/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 7cade28..5000237 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -451,6 +451,12 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base64" version = "0.22.1" @@ -608,6 +614,26 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9" +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.13+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14" +dependencies = [ + "cc", + "pkg-config", +] + [[package]] name = "calloop" version = "0.13.0" @@ -3426,6 +3452,7 @@ dependencies = [ "numpy", "pyo3", "resvg", + "rosbag", "roxmltree", "serde", "serde_json", @@ -3637,6 +3664,20 @@ dependencies = [ "bytemuck", ] +[[package]] +name = "rosbag" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef77688c2fe3d1a94991e3d7256face190d6b6ea1a1ac60a6e2bad8e2aeabde7" +dependencies = [ + "base16ct", + "byteorder", + "bzip2", + "log 0.4.25", + "lz4", + "memmap2", +] + [[package]] name = "rowan" version = "0.16.1" diff --git a/Cargo.toml b/Cargo.toml index 20adf3e..50c10b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ neuromorphic-types = "0.6.0" numpy = {version = "0.23.0"} pyo3 = {version = "0.23.4", features = ["extension-module"]} resvg = "0.44.0" +rosbag = "0.6.3" roxmltree = "0.20.0" serde = {version = "1.0", features = ["derive"]} serde_json = "1.0" diff --git a/src/lib.rs b/src/lib.rs index 49cf3e5..0bd953b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,6 +13,7 @@ mod mp4; mod mustache; mod raster; mod render; +mod rosbag; //mod event_spectrogram; mod types; mod utilities; @@ -107,5 +108,10 @@ fn faery(python: Python<'_>, module: &pyo3::Bound<'_, pyo3::types::PyModule>) -> submodule.add_class::()?; module.add_submodule(&submodule)?; } + { + let submodule = PyModule::new(python, "rosbag")?; + submodule.add_class::()?; + module.add_submodule(&submodule)?; + } Ok(()) } diff --git a/src/rosbag/decoder.rs b/src/rosbag/decoder.rs new file mode 100644 index 0000000..3b4939b --- /dev/null +++ b/src/rosbag/decoder.rs @@ -0,0 +1,44 @@ +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("io error: {0}")] + Io(#[from] std::io::Error), + + #[error("rosbag error: {0}")] + Rosbag(String), +} + +pub struct Decoder { + inner: rosbag::RosBag, + event_buffer: Vec>, + dimensions: (u16, u16), + t: u64, +} + +impl Decoder { + pub fn new>(path: P) -> Result { + let inner = rosbag::RosBag::new(path)?; + for record in inner.chunk_records() { + match record.map_err(|error| Error::Rosbag(format!("{error:?}")))? { + rosbag::ChunkRecord::Chunk(chunk) => { + for message in chunk.messages() { + if message.is_ok() { + todo!("decode the message"); + } + } + } + rosbag::ChunkRecord::IndexData(_) => {} + } + } + + Ok(Decoder { + inner, + event_buffer: Vec::new(), + dimensions: (0, 0), + t: 0, + }) + } + + pub fn dimensions(&self) -> (u16, u16) { + self.dimensions + } +} diff --git a/src/rosbag/mod.rs b/src/rosbag/mod.rs new file mode 100644 index 0000000..fc5198f --- /dev/null +++ b/src/rosbag/mod.rs @@ -0,0 +1,98 @@ +mod decoder; + +use crate::types; + +use pyo3::prelude::*; + +impl From for PyErr { + fn from(error: decoder::Error) -> Self { + PyErr::new::(error.to_string()) + } +} + +#[pyclass] +pub struct Decoder { + inner: Option, +} + +#[pymethods] +impl Decoder { + #[new] + #[pyo3(signature = (path))] + fn new(path: &pyo3::Bound<'_, pyo3::types::PyAny>) -> PyResult { + Ok(Decoder { + inner: Some(decoder::Decoder::new(types::python_path_to_string(path)?)?), + }) + } + + #[getter] + fn dimensions(&self) -> PyResult<(u16, u16)> { + match self.inner { + Some(ref decoder) => Ok(decoder.dimensions()), + None => Err(pyo3::exceptions::PyException::new_err( + "called dimensions after __exit__", + )), + } + } + + /* + fn __enter__(slf: Py) -> Py { + slf + } + + #[pyo3(signature = (_exception_type, _value, _traceback))] + fn __exit__( + &mut self, + _exception_type: Option, + _value: Option, + _traceback: Option, + ) -> PyResult { + if self.inner.is_none() { + return Err(pyo3::exceptions::PyException::new_err( + "multiple calls to __exit__", + )); + } + let _ = self.inner.take(); + Ok(false) + } + + fn __iter__(shell: PyRefMut) -> PyResult> { + Ok(shell.into()) + } + + fn __next__(mut shell: PyRefMut) -> PyResult> { + let packet = match shell.inner { + Some(ref mut decoder) => match decoder.next() { + Ok(result) => match result { + Some(result) => result, + None => return Ok(None), + }, + Err(result) => return Err(result.into()), + }, + None => { + return Err(pyo3::exceptions::PyException::new_err( + "called __next__ after __exit__", + )) + } + }; + Python::with_gil(|python| -> PyResult> { + let length = packet.len() as numpy::npyffi::npy_intp; + let array = types::ArrayType::Dat.new_array(python, length); + unsafe { + for index in 0..length { + let event_cell = types::array_at(python, array, index); + std::ptr::copy( + &packet[index as usize] as *const common::Event as *const u8, + event_cell, + std::mem::size_of::(), + ); + } + Ok(Some(PyObject::from_owned_ptr( + python, + array as *mut pyo3::ffi::PyObject, + ))) + } + }) + } + */ +}