Skip to content

Commit

Permalink
buffer: Merge metadata and memory into single Buffer struct
Browse files Browse the repository at this point in the history
v4l2 users coming from other languages will be used to all the data being
in one place, which is what the C API mandates anyways. Let's stick to the
original data layout for simplicity.

Signed-off-by: Christopher N. Hesse <[email protected]>
  • Loading branch information
raymanfx committed May 6, 2024
1 parent 62fc9e4 commit a55ac7c
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 72 deletions.
5 changes: 3 additions & 2 deletions examples/glium.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,13 @@ fn main() -> io::Result<()> {
Stream::<Mmap>::with_buffers(&dev, Type::VideoCapture, buffer_count).unwrap();

loop {
let (buf, _) = stream.next().unwrap();
let buf = stream.next().unwrap();
let data = match &format.fourcc.repr {
b"RGB3" => buf.to_vec(),
b"MJPG" => {
// Decode the JPEG frame to RGB
let mut decoder = jpeg::Decoder::new(buf);
let slice: &[u8] = buf;
let mut decoder = jpeg::Decoder::new(slice);
decoder.decode().expect("failed to decode JPEG")
}
_ => panic!("invalid buffer pixelformat"),
Expand Down
8 changes: 4 additions & 4 deletions examples/stream_capture_mmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ fn main() -> io::Result<()> {
let mut megabytes_ps: f64 = 0.0;
for i in 0..count {
let t0 = Instant::now();
let (buf, meta) = stream.next()?;
let buf = stream.next()?;
let duration_us = t0.elapsed().as_micros();

let cur = buf.len() as f64 / 1_048_576.0 * 1_000_000.0 / duration_us as f64;
Expand All @@ -47,9 +47,9 @@ fn main() -> io::Result<()> {
}

println!("Buffer");
println!(" sequence : {}", meta.sequence);
println!(" timestamp : {}", meta.timestamp);
println!(" flags : {}", meta.flags);
println!(" sequence : {}", buf.sequence);
println!(" timestamp : {}", buf.timestamp);
println!(" flags : {}", buf.flags);
println!(" length : {}", buf.len());
}

Expand Down
8 changes: 4 additions & 4 deletions examples/stream_capture_userptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ fn main() -> io::Result<()> {
let mut megabytes_ps: f64 = 0.0;
for i in 0..count {
let t0 = Instant::now();
let (buf, meta) = stream.next()?;
let buf = stream.next()?;
let duration_us = t0.elapsed().as_micros();

let cur = buf.len() as f64 / 1_048_576.0 * 1_000_000.0 / duration_us as f64;
Expand All @@ -47,9 +47,9 @@ fn main() -> io::Result<()> {
}

println!("Buffer");
println!(" sequence : {}", meta.sequence);
println!(" timestamp : {}", meta.timestamp);
println!(" flags : {}", meta.flags);
println!(" sequence : {}", buf.sequence);
println!(" timestamp : {}", buf.timestamp);
println!(" flags : {}", buf.flags);
println!(" length : {}", buf.len());
}

Expand Down
24 changes: 12 additions & 12 deletions examples/stream_forward_mmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,18 +59,18 @@ fn main() -> io::Result<()> {
let mut megabytes_ps: f64 = 0.0;
for i in 0..count {
let t0 = Instant::now();
let (buf_in, buf_in_meta) = CaptureStream::next(&mut cap_stream)?;
let (buf_out, buf_out_meta) = OutputStream::next(&mut out_stream)?;
let buf_in = CaptureStream::next(&mut cap_stream)?;
let buf_out = OutputStream::next(&mut out_stream)?;

// Output devices generally cannot know the exact size of the output buffers for
// compressed formats (e.g. MJPG). They will however allocate a size that is always
// large enough to hold images of the format in question. We know how big a buffer we need
// since we control the input buffer - so just enforce that size on the output buffer.
let buf_out = &mut buf_out[0..buf_in.len()];
let slice_out = &mut buf_out[0..buf_in.len()];

buf_out.copy_from_slice(buf_in);
buf_out_meta.field = 0;
buf_out_meta.bytesused = buf_in_meta.bytesused;
slice_out.copy_from_slice(buf_in);
buf_out.field = 0;
buf_out.bytesused = buf_in.bytesused;
let duration_us = t0.elapsed().as_micros();

let cur = buf_in.len() as f64 / 1_048_576.0 * 1_000_000.0 / duration_us as f64;
Expand All @@ -84,12 +84,12 @@ fn main() -> io::Result<()> {
}

println!("Buffer");
println!(" sequence [in] : {}", buf_in_meta.sequence);
println!(" sequence [out] : {}", buf_out_meta.sequence);
println!(" timestamp [in] : {}", buf_in_meta.timestamp);
println!(" timestamp [out] : {}", buf_out_meta.timestamp);
println!(" flags [in] : {}", buf_in_meta.flags);
println!(" flags [out] : {}", buf_out_meta.flags);
println!(" sequence [in] : {}", buf_in.sequence);
println!(" sequence [out] : {}", buf_out.sequence);
println!(" timestamp [in] : {}", buf_in.timestamp);
println!(" timestamp [out] : {}", buf_out.timestamp);
println!(" flags [in] : {}", buf_in.flags);
println!(" flags [out] : {}", buf_out.flags);
println!(" length [in] : {}", buf_in.len());
println!(" length [out] : {}", buf_out.len());
}
Expand Down
38 changes: 35 additions & 3 deletions src/buffer.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use std::fmt;
use std::{
fmt,
ops::{Deref, DerefMut},
};

use crate::timestamp::Timestamp;

Expand Down Expand Up @@ -98,8 +101,10 @@ impl fmt::Display for Flags {
}

/// Buffer metadata, mostly used not to convolute the main buffer structs
#[derive(Copy, Clone, Default)]
pub struct Metadata {
#[derive(Debug)]
pub struct Buffer<T> {
/// Backing memory
pub memory: T,
/// Number of bytes occupied by the data in the buffer
pub bytesused: u32,
/// Buffer flags
Expand All @@ -111,3 +116,30 @@ pub struct Metadata {
/// Sequence number, counting the frames
pub sequence: u32,
}

impl<T> Buffer<T> {
pub(crate) fn new(memory: T) -> Self {
Buffer {
memory,
bytesused: 0,
flags: Flags::from(0),
field: 0,
timestamp: Timestamp::default(),
sequence: 0,
}
}
}

impl<T> Deref for Buffer<T> {
type Target = T;

fn deref(&self) -> &Self::Target {
&self.memory
}
}

impl<T> DerefMut for Buffer<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.memory
}
}
66 changes: 27 additions & 39 deletions src/io/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::{

use v4l2_sys::{v4l2_buffer, v4l2_format, v4l2_requestbuffers};

use crate::buffer::{Metadata, Type};
use crate::buffer::{Buffer, Type};
use crate::device::{Device, Handle};
use crate::io::traits::{CaptureStream, OutputStream, Stream as StreamTrait};
use crate::memory::{Memory, Mmap, UserPtr};
Expand All @@ -23,7 +23,7 @@ use crate::v4l2;
/// In case of errors during unmapping, we panic because there is memory corruption going on.
pub(crate) struct Arena<T> {
handle: Arc<Handle>,
pub bufs: Vec<T>,
pub bufs: Vec<Buffer<T>>,
pub buf_mem: Memory,
pub buf_type: Type,
}
Expand Down Expand Up @@ -119,7 +119,8 @@ impl<'a> Arena<Mmap<'a>> {

let slice =
slice::from_raw_parts_mut::<u8>(ptr as *mut u8, v4l2_buf.length as usize);
self.bufs.push(Mmap(slice));
let buf = Buffer::new(Mmap(slice));
self.bufs.push(buf);
}
}

Expand Down Expand Up @@ -171,8 +172,8 @@ You may want to use this crate with the raw v4l2 FFI bindings instead!\n"
let count = self.request(count)?;
for _ in 0..count {
let size = unsafe { v4l2_fmt.fmt.pix.sizeimage };
let buf = vec![0u8; size as usize];
self.bufs.push(UserPtr(buf));
let buf = Buffer::new(UserPtr(vec![0u8; size as usize]));
self.bufs.push(buf);
}

Ok(count)
Expand All @@ -187,7 +188,6 @@ pub struct Stream<T> {
arena: Arena<T>,
arena_index: usize,
buf_type: Type,
buf_meta: Vec<Metadata>,
timeout: Option<i32>,

active: bool,
Expand Down Expand Up @@ -220,16 +220,13 @@ impl<'a> Stream<Mmap<'a>> {

pub fn with_buffers(dev: &Device, buf_type: Type, buf_count: u32) -> io::Result<Self> {
let mut arena = Arena::<Mmap<'a>>::new(dev.handle(), buf_type);
let count = arena.allocate(buf_count)?;
let mut buf_meta = Vec::new();
buf_meta.resize(count as usize, Metadata::default());
let _count = arena.allocate(buf_count)?;

Ok(Stream {
handle: dev.handle(),
arena,
arena_index: 0,
buf_type,
buf_meta,
active: false,
timeout: None,
})
Expand Down Expand Up @@ -263,16 +260,13 @@ impl Stream<UserPtr> {

pub fn with_buffers(dev: &Device, buf_type: Type, buf_count: u32) -> io::Result<Self> {
let mut arena = Arena::<UserPtr>::new(dev.handle(), buf_type);
let count = arena.allocate(buf_count)?;
let mut buf_meta = Vec::new();
buf_meta.resize(count as usize, Metadata::default());
let _count = arena.allocate(buf_count)?;

Ok(Stream {
handle: dev.handle(),
arena,
arena_index: 0,
buf_type,
buf_meta,
active: false,
timeout: None,
})
Expand Down Expand Up @@ -323,7 +317,7 @@ impl<T> Drop for Stream<T> {
}

impl<T> StreamTrait for Stream<T> {
type Item = [u8];
type Item = Buffer<T>;

fn start(&mut self) -> io::Result<()> {
unsafe {
Expand Down Expand Up @@ -394,18 +388,17 @@ where
}
self.arena_index = v4l2_buf.index as usize;

self.buf_meta[self.arena_index] = Metadata {
bytesused: v4l2_buf.bytesused,
flags: v4l2_buf.flags.into(),
field: v4l2_buf.field,
timestamp: v4l2_buf.timestamp.into(),
sequence: v4l2_buf.sequence,
};
let buf = &mut self.arena.bufs[self.arena_index];
buf.bytesused = v4l2_buf.bytesused;
buf.flags = v4l2_buf.flags.into();
buf.field = v4l2_buf.field;
buf.timestamp = v4l2_buf.timestamp.into();
buf.sequence = v4l2_buf.sequence;

Ok(self.arena_index)
}

fn next(&'a mut self) -> io::Result<(&Self::Item, &Metadata)> {
fn next(&'a mut self) -> io::Result<&Self::Item> {
if !self.active {
// Enqueue all buffers once on stream start
for index in 0..self.arena.bufs.len() {
Expand All @@ -421,9 +414,7 @@ where

// The index used to access the buffer elements is given to us by v4l2, so we assume it
// will always be valid.
let bytes = &self.arena.bufs[self.arena_index];
let meta = &self.buf_meta[self.arena_index];
Ok((bytes, meta))
Ok(&self.arena.bufs[self.arena_index])
}
}

Expand All @@ -442,8 +433,8 @@ where
// MetaData.bytesused is initialized to 0. For an output device, when bytesused is
// set to 0 v4l2 will set it to the size of the plane:
// https://www.kernel.org/doc/html/v4.15/media/uapi/v4l/buffer.html#struct-v4l2-plane
v4l2_buf.bytesused = self.buf_meta[index].bytesused;
v4l2_buf.field = self.buf_meta[index].field;
v4l2_buf.bytesused = self.arena.bufs[index].bytesused;
v4l2_buf.field = self.arena.bufs[index].field;

if self
.handle
Expand Down Expand Up @@ -476,18 +467,17 @@ where
}
self.arena_index = v4l2_buf.index as usize;

self.buf_meta[self.arena_index] = Metadata {
bytesused: v4l2_buf.bytesused,
flags: v4l2_buf.flags.into(),
field: v4l2_buf.field,
timestamp: v4l2_buf.timestamp.into(),
sequence: v4l2_buf.sequence,
};
let buf = &mut self.arena.bufs[self.arena_index];
buf.bytesused = v4l2_buf.bytesused;
buf.flags = v4l2_buf.flags.into();
buf.field = v4l2_buf.field;
buf.timestamp = v4l2_buf.timestamp.into();
buf.sequence = v4l2_buf.sequence;

Ok(self.arena_index)
}

fn next(&'a mut self) -> io::Result<(&mut Self::Item, &mut Metadata)> {
fn next(&'a mut self) -> io::Result<&mut Self::Item> {
let init = !self.active;
if !self.active {
self.start()?;
Expand All @@ -503,8 +493,6 @@ where

// The index used to access the buffer elements is given to us by v4l2, so we assume it
// will always be valid.
let bytes = &mut self.arena.bufs[self.arena_index];
let meta = &mut self.buf_meta[self.arena_index];
Ok((bytes, meta))
Ok(&mut self.arena.bufs[self.arena_index])
}
}
6 changes: 2 additions & 4 deletions src/io/traits.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use std::io;

use crate::buffer::Metadata;

/// Streaming I/O
pub trait Stream {
type Item: ?Sized;
Expand All @@ -22,7 +20,7 @@ pub trait CaptureStream<'a>: Stream {

/// Fetch a new frame by first queueing and then dequeueing.
/// First time initialization is performed if necessary.
fn next(&'a mut self) -> io::Result<(&Self::Item, &Metadata)>;
fn next(&'a mut self) -> io::Result<&Self::Item>;
}

pub trait OutputStream<'a>: Stream {
Expand All @@ -34,5 +32,5 @@ pub trait OutputStream<'a>: Stream {

/// Dump a new frame by first queueing and then dequeueing.
/// First time initialization is performed if necessary.
fn next(&'a mut self) -> io::Result<(&mut Self::Item, &mut Metadata)>;
fn next(&'a mut self) -> io::Result<&mut Self::Item>;
}
8 changes: 4 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@
//! Stream::<Mmap>::with_buffers(&mut dev, Type::VideoCapture, 4).expect("Failed to create buffer stream");
//!
//! loop {
//! let (buf, meta) = stream.next().unwrap();
//! let buf = stream.next().unwrap();
//! println!(
//! "Buffer size: {}, seq: {}, timestamp: {}",
//! buf.len(),
//! meta.sequence,
//! meta.timestamp
//! buf.memory.len(),
//! buf.sequence,
//! buf.timestamp
//! );
//!}
//!```
Expand Down

0 comments on commit a55ac7c

Please sign in to comment.