1
Fork 0
cabinet/encoder/src/main.rs
Andy Killorin f5bc322862
switched to jpeg from h264 compression
10x larger over the wire but no dependency on libstdc++
2025-01-02 19:42:05 -05:00

88 lines
2.9 KiB
Rust

use std::{array::from_ref, net::SocketAddr, result, sync::Arc, thread::{self, sleep}, time::Duration};
use image::{codecs::jpeg::JpegEncoder, ImageBuffer, Rgb};
use nokhwa::{pixel_format::RgbFormat, utils::{ApiBackend, RequestedFormat, RequestedFormatType, Resolution}, Camera};
use anyhow::{Context, Ok, Result};
use tokio::{io::AsyncWriteExt, net::{TcpListener, TcpStream}, runtime::Runtime, sync::{Notify, RwLock}, task::LocalSet};
fn main() -> Result<()>{
let await_frame = Arc::new(Notify::new());
let latest_frame = Arc::new(RwLock::new(Vec::new()));
{
let runtime = Runtime::new()?;
let await_frame = await_frame.clone();
let latest_frame = latest_frame.clone();
thread::spawn(move || {
let local = LocalSet::new();
local.block_on(&runtime, camera_manager(await_frame, latest_frame)).unwrap();
});
}
{
let runtime = Runtime::new()?;
let await_frame = await_frame.clone();
let latest_frame = latest_frame.clone();
thread::spawn(move || {
let local = LocalSet::new();
local.block_on(&runtime, server(await_frame, latest_frame)).unwrap();
});
}
loop {}
}
async fn camera_manager(await_frame: Arc<Notify>, latest_frame: Arc<RwLock<Vec<u8>>>) -> Result<()>{
let cameras = nokhwa::query(ApiBackend::Auto)?;
let camera = cameras.get(0).context("no cameras")?;
println!("using: {}",camera.human_name());
let requested = RequestedFormat::new::<RgbFormat>(RequestedFormatType::HighestResolution(Resolution::new(320, 240)));
let mut camera = Camera::new(camera.index().clone(), requested)?;
camera.open_stream()?;
loop {
let frame = camera.frame()?;
let frame: ImageBuffer<Rgb<u8>, Vec<u8>> = frame.decode_image::<RgbFormat>()?;
let mut output = Vec::new();
let mut encoder = JpegEncoder::new_with_quality(&mut output, 30);
encoder.encode_image(&frame).unwrap();
*latest_frame.write().await = output;
await_frame.notify_waiters();
}
}
async fn stream_video(await_frame: Arc<Notify>, latest_frame: Arc<RwLock<Vec<u8>>>, mut client: TcpStream) -> Result<()>{
loop {
await_frame.notified().await;
let data = latest_frame.read().await;
println!("len: {}", data.len());
let len = data.len();
// holding data across await, likely nonissue
client.write_u32(len as u32).await?;
client.write(&data).await?;
}
}
async fn server(await_frame: Arc<Notify>, latest_frame: Arc<RwLock<Vec<u8>>>) -> Result<()> {
let port = 2993;
let listener = TcpListener::bind(format!("0.0.0.0:{port}")).await?;
println!("listening on {port}");
while let result::Result::Ok((client, addr)) = listener.accept().await {
println!("connected to {:?}", addr);
tokio::task::spawn_local(stream_video(await_frame.clone(), latest_frame.clone(), client));
}
Ok(())
}