summaryrefslogtreecommitdiff
path: root/src/v4l2abst.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/v4l2abst.rs')
-rw-r--r--src/v4l2abst.rs103
1 files changed, 103 insertions, 0 deletions
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<Local>,
+}
+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<u8>)
+ -> Result<Self>{
+ struct Rh<'c>(&'c mut dyn Read);
+ impl<'c> Rh<'c>{
+ fn u32(&mut self) -> Result<u32>{
+ let mut tmp: [u8; 4] = Default::default();
+ self.0.read_exact(&mut tmp)?;
+ Ok(u32::from_be_bytes(tmp))
+ }
+ fn i64(&mut self) -> Result<i64>{
+ let mut tmp: [u8; 8] = Default::default();
+ self.0.read_exact(&mut tmp)?;
+ Ok(i64::from_be_bytes(tmp))
+ }
+ fn usize(&mut self) -> Result<usize>{
+ let mut tmp: [u8; size_of::<usize>()] = 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<R>(&mut self, cb: impl FnOnce(Frame) -> R) -> Result<R>;
+}
+
+impl CaptStream for v4l2::CaptStream{
+ fn next<R>(&mut self, cb: impl FnOnce(Frame) -> R) -> Result<R>{
+ 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: Read + Write>(I);
+impl<I: Read + Write> RemoteCam<I>{
+ pub fn new(inner: I) -> Self{
+ Self(inner)
+ }
+}
+impl<I: Read + Write> CaptStream for RemoteCam<I>{
+ fn next<R>(&mut self, cb: impl FnOnce(Frame) -> R) -> Result<R>{
+ 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))
+ }
+}