diff --git a/Cargo.toml b/Cargo.toml index f8685b5..1e969a4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,6 +32,7 @@ async-compat = "0.2.3" futures = "0.3.30" openh264 = "0.5.0" retina = "0.4.7" +tokio = "1.36.0" url = "2.5.0" diff --git a/README.md b/README.md index 681c0fd..b425425 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ rust bevy light field camera array tooling + ## run the viewer `cargo run -- --help` @@ -26,8 +27,19 @@ the viewer opens a window and displays the light field camera array, with post-p - [ ] real-time 3d reconstruction viewer +## light field camera array + +view the [onshape model](https://cad.onshape.com/documents/20d4b522e97cda88fb785536/w/9939c2cecd85477ae7e753f6/e/69f97c604cdee8494e4e46bc?renderMode=0&uiState=65ea51d493f7bd0c772084fa) + +![Alt text](docs/light_field_camera_onshape_transparent.webp) + +- [ ] parts list + + ## setup rtsp streaming server +it is useful to test the light field viewer with emulated camera streams + ### obs studio - install https://obsproject.com/ diff --git a/docs/light_field_camera_onshape_transparent.webp b/docs/light_field_camera_onshape_transparent.webp new file mode 100644 index 0000000..62d277d Binary files /dev/null and b/docs/light_field_camera_onshape_transparent.webp differ diff --git a/src/lib.rs b/src/lib.rs index e69de29..baf29e0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -0,0 +1 @@ +pub mod stream; diff --git a/src/stream.rs b/src/stream.rs new file mode 100644 index 0000000..ad32a4b --- /dev/null +++ b/src/stream.rs @@ -0,0 +1,135 @@ +use std::num::NonZeroU32; +use std::sync::{Arc, Mutex}; +use std::thread::Thread; + +use anyhow::{bail, Error}; +use async_compat::Compat; +use bevy::{ + prelude::*, + app::AppExit, + ecs::system::CommandQueue, + tasks::{ + block_on, + futures_lite::future, + AsyncComputeTaskPool, + Task, + }, +}; +use futures::TryStreamExt; +use openh264::{ + decoder::Decoder, + nal_units, +}; +use retina::{ + client::{ + Credentials, + Demuxed, + Playing, + Session, + SessionOptions, + SetupOptions, + TcpTransportOptions, + Transport, + }, + codec::VideoFrame, +}; +use tokio::runtime::Runtime; +use url::Url; + + +pub struct RtspStreamPlugin; +impl Plugin for RtspStreamPlugin { + fn build(&self, app: &mut App) { + app + .add_systems(Update, create_streams_from_descriptors); + } +} + + +#[derive(Debug, Clone, Copy)] +pub struct StreamId(pub usize); + +#[derive(Component)] +pub struct RtspStreamDescriptor { + pub uri: String, + pub id: StreamId, +} + +#[derive(Component)] +struct RtspStreamCreated; + + +#[derive(Resource)] +pub struct RtspStreamManager { + runtime: Runtime, + root: Thread, +} + +impl RtspStreamManager { + pub fn contains(&self, id: StreamId) -> bool { + false + } + + pub fn get_latest_frame(&self, id: StreamId) -> Option { + None + } +} + + +fn create_streams_from_descriptors( + mut commands: Commands, + stream_manager: Res, + descriptors: Query< + ( + Entity, + &RtspStreamDescriptor, + ), + Without, + >, +) { + for (entity, descriptor) in descriptors.iter() { + assert!(stream_manager.contains(descriptor.id), "Stream already exists"); + + + commands.entity(entity).insert(RtspStreamCreated); + + + } +} + + + + +pub struct RtspStream { + pub uri: String, + pub id: StreamId, + demuxed: Option, + decoder: Option, +} + +impl RtspStream { + pub fn new(uri: &str, id: StreamId) -> Self { + Self { + uri: uri.to_string(), + id, + demuxed: None, + decoder: None, + } + } +} + + +#[derive(Default)] +pub struct RtspStreams(pub Vec); + +impl RtspStreams { + pub fn new(urls: &[&str]) -> Self { + Self( + urls.iter() + .enumerate() + .map(|(i, &uri)| RtspStream::new(uri, StreamId(i))) + .collect() + ) + } +} +