From 6ecbf0d55695335f52d6fcf2b6a22ed45f5e4d99 Mon Sep 17 00:00:00 2001 From: dyknon Date: Mon, 24 Feb 2025 18:58:32 +0900 Subject: Remote camera capability. --- src/v4l2abst.rs | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 src/v4l2abst.rs (limited to 'src/v4l2abst.rs') diff --git a/src/v4l2abst.rs b/src/v4l2abst.rs new file mode 100644 index 0000000..baefea0 --- /dev/null +++ b/src/v4l2abst.rs @@ -0,0 +1,103 @@ +use anyhow::{anyhow, Result}; +use crate::v4l2; +use chrono::{DateTime, Local}; +use std::io::{Read, Write}; +use std::mem::size_of; + +pub struct Frame<'a>{ + pub format: v4l2::ImageFormat, + pub width: usize, + pub height: usize, + pub stride: usize, + pub buf: &'a [u8], + pub timestamp: DateTime, +} +impl<'a> Frame<'a>{ + pub fn serialize(&self, dst: &mut impl Write) -> Result<()>{ + dst.write_all(&u32::to_be_bytes(self.format.into()))?; + dst.write_all(&self.timestamp.timestamp_subsec_nanos().to_be_bytes())?; + dst.write_all(&self.timestamp.timestamp().to_be_bytes())?; + dst.write_all(&self.width.to_be_bytes())?; + dst.write_all(&self.height.to_be_bytes())?; + dst.write_all(&self.stride.to_be_bytes())?; + dst.write_all(&self.buf.len().to_be_bytes())?; + dst.write_all(self.buf)?; + Ok(()) + } + pub fn deserialize<'b>(src: &'b mut impl Read, buf: &'a mut Vec) + -> Result{ + struct Rh<'c>(&'c mut dyn Read); + impl<'c> Rh<'c>{ + fn u32(&mut self) -> Result{ + let mut tmp: [u8; 4] = Default::default(); + self.0.read_exact(&mut tmp)?; + Ok(u32::from_be_bytes(tmp)) + } + fn i64(&mut self) -> Result{ + let mut tmp: [u8; 8] = Default::default(); + self.0.read_exact(&mut tmp)?; + Ok(i64::from_be_bytes(tmp)) + } + fn usize(&mut self) -> Result{ + let mut tmp: [u8; size_of::()] = Default::default(); + self.0.read_exact(&mut tmp)?; + Ok(usize::from_be_bytes(tmp)) + } + } + let mut src = Rh(src); + let format = src.u32()?.into(); + let (ns, s) = (src.u32()?, src.i64()?); + let timestamp = DateTime::from_timestamp(s, ns) + .ok_or(anyhow!("Invalid DateTime"))?.into(); + let width = src.usize()?; + let height = src.usize()?; + let stride = src.usize()?; + let len = src.usize()?; + buf.resize(len, 0); + src.0.read_exact(buf)?; + Ok(Frame{ format, width, height, stride, buf, timestamp }) + } +} + +pub trait CaptStream{ + fn next(&mut self, cb: impl FnOnce(Frame) -> R) -> Result; +} + +impl CaptStream for v4l2::CaptStream{ + fn next(&mut self, cb: impl FnOnce(Frame) -> R) -> Result{ + let (width, height) = (self.width(), self.height()); + let stride = self.bytesperline(); + let format = self.pixelformat(); + let mut cb = Some(cb); + loop{ + if let Some(ret) = v4l2::CaptStream::next(self, |buf, attr|{ + if attr.flags.error{ + return None; + } + let timestamp = attr.get_datetime().unwrap(); + Some(cb.take().unwrap()(Frame{ + format, width, height, stride, buf, timestamp + })) + })?{ + return Ok(ret); + } + } + } +} + +pub struct RemoteCam(I); +impl RemoteCam{ + pub fn new(inner: I) -> Self{ + Self(inner) + } +} +impl CaptStream for RemoteCam{ + fn next(&mut self, cb: impl FnOnce(Frame) -> R) -> Result{ + let ack: [u8; 1] = [0x2e]; + let mut buf = Vec::new(); + let frame = Frame::deserialize(&mut self.0, &mut buf)?; + self.0.write_all(&ack)?; + self.0.flush()?; + Ok(cb(frame)) + } +} -- cgit v1.2.3