Skip to content

Commit e97dd8b

Browse files
committed
io: Consolidate Arena types
Less maintenance burden, more visibility due to the implementations residing in a single file again. Signed-off-by: Christopher N. Hesse <[email protected]>
1 parent fdd93d8 commit e97dd8b

File tree

8 files changed

+180
-274
lines changed

8 files changed

+180
-274
lines changed

src/io/mmap/arena.rs

Lines changed: 0 additions & 137 deletions
This file was deleted.

src/io/mmap/mod.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,2 @@
1-
pub(crate) mod arena;
2-
31
pub mod stream;
42
pub use stream::Stream;

src/io/mmap/stream.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,17 @@ use v4l2_sys::v4l2_buffer;
66

77
use crate::buffer::{Metadata, Type};
88
use crate::device::{Device, Handle};
9-
use crate::io::mmap::arena::Arena;
109
use crate::io::traits::{CaptureStream, OutputStream, Stream as StreamTrait};
11-
use crate::memory::Memory;
10+
use crate::io::Arena;
11+
use crate::memory::{Memory, Mmap};
1212
use crate::v4l2;
1313

1414
/// Stream of mapped buffers
1515
///
1616
/// An arena instance is used internally for buffer handling.
1717
pub struct Stream<'a> {
1818
handle: Arc<Handle>,
19-
arena: Arena<'a>,
19+
arena: Arena<Mmap<'a>>,
2020
arena_index: usize,
2121
buf_type: Type,
2222
buf_meta: Vec<Metadata>,
@@ -50,7 +50,7 @@ impl<'a> Stream<'a> {
5050
}
5151

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

src/io/mod.rs

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,174 @@ pub mod traits;
22

33
pub mod mmap;
44
pub mod userptr;
5+
6+
use std::{io, mem, ptr, slice, sync::Arc};
7+
8+
use v4l2_sys::{v4l2_buffer, v4l2_format, v4l2_requestbuffers};
9+
10+
use crate::buffer;
11+
use crate::device::Handle;
12+
use crate::memory::{Memory, Mmap, UserPtr};
13+
use crate::v4l2;
14+
15+
/// Manage mapped buffers
16+
///
17+
/// All buffers are unmapped in the Drop impl.
18+
/// In case of errors during unmapping, we panic because there is memory corruption going on.
19+
pub(crate) struct Arena<T> {
20+
handle: Arc<Handle>,
21+
pub bufs: Vec<T>,
22+
pub buf_mem: Memory,
23+
pub buf_type: buffer::Type,
24+
}
25+
26+
impl<T> Arena<T> {
27+
fn request(&mut self, count: u32) -> io::Result<u32> {
28+
// free all buffers by requesting 0
29+
let mut v4l2_reqbufs = v4l2_requestbuffers {
30+
count,
31+
type_: self.buf_type as u32,
32+
memory: self.buf_mem as u32,
33+
..unsafe { mem::zeroed() }
34+
};
35+
unsafe {
36+
v4l2::ioctl(
37+
self.handle.fd(),
38+
v4l2::vidioc::VIDIOC_REQBUFS,
39+
&mut v4l2_reqbufs as *mut _ as *mut std::os::raw::c_void,
40+
)?;
41+
}
42+
43+
Ok(v4l2_reqbufs.count)
44+
}
45+
}
46+
47+
impl<T> Drop for Arena<T> {
48+
fn drop(&mut self) {
49+
if self.bufs.is_empty() {
50+
// nothing to do
51+
return;
52+
}
53+
54+
// free all buffers by requesting 0
55+
if let Err(e) = self.request(0) {
56+
if let Some(code) = e.raw_os_error() {
57+
// ENODEV means the file descriptor wrapped in the handle became invalid, most
58+
// likely because the device was unplugged or the connection (USB, PCI, ..)
59+
// broke down. Handle this case gracefully by ignoring it.
60+
if code == 19 {
61+
/* ignore */
62+
return;
63+
}
64+
}
65+
66+
panic!("{:?}", e)
67+
}
68+
}
69+
}
70+
71+
impl<'a> Arena<Mmap<'a>> {
72+
/// Returns a new buffer manager instance
73+
///
74+
/// You usually do not need to use this directly.
75+
/// A MappedBufferStream creates its own manager instance by default.
76+
///
77+
/// # Arguments
78+
///
79+
/// * `handle` - Device handle to get its file descriptor
80+
/// * `buf_type` - Type of the buffers
81+
pub fn new(handle: Arc<Handle>, buf_type: buffer::Type) -> Self {
82+
Arena {
83+
handle,
84+
bufs: Vec::new(),
85+
buf_mem: Memory::Mmap,
86+
buf_type,
87+
}
88+
}
89+
90+
pub fn allocate(&mut self, count: u32) -> io::Result<u32> {
91+
let count = self.request(count)?;
92+
for index in 0..count {
93+
let mut v4l2_buf = v4l2_buffer {
94+
index,
95+
type_: self.buf_type as u32,
96+
memory: self.buf_mem as u32,
97+
..unsafe { mem::zeroed() }
98+
};
99+
unsafe {
100+
v4l2::ioctl(
101+
self.handle.fd(),
102+
v4l2::vidioc::VIDIOC_QUERYBUF,
103+
&mut v4l2_buf as *mut _ as *mut std::os::raw::c_void,
104+
)?;
105+
106+
let ptr = v4l2::mmap(
107+
ptr::null_mut(),
108+
v4l2_buf.length as usize,
109+
libc::PROT_READ | libc::PROT_WRITE,
110+
libc::MAP_SHARED,
111+
self.handle.fd(),
112+
v4l2_buf.m.offset as libc::off_t,
113+
)?;
114+
115+
let slice =
116+
slice::from_raw_parts_mut::<u8>(ptr as *mut u8, v4l2_buf.length as usize);
117+
self.bufs.push(Mmap(slice));
118+
}
119+
}
120+
121+
Ok(count)
122+
}
123+
}
124+
125+
impl Arena<UserPtr> {
126+
/// Returns a new buffer manager instance
127+
///
128+
/// You usually do not need to use this directly.
129+
/// A MappedBufferStream creates its own manager instance by default.
130+
///
131+
/// # Arguments
132+
///
133+
/// * `handle` - Device handle to get its file descriptor
134+
/// * `buf_type` - Type of the buffers
135+
pub fn new(handle: Arc<Handle>, buf_type: buffer::Type) -> Self {
136+
Arena {
137+
handle,
138+
bufs: Vec::new(),
139+
buf_mem: Memory::UserPtr,
140+
buf_type,
141+
}
142+
}
143+
144+
pub fn allocate(&mut self, count: u32) -> io::Result<u32> {
145+
// we need to get the maximum buffer size from the format first
146+
let mut v4l2_fmt = v4l2_format {
147+
type_: self.buf_type as u32,
148+
..unsafe { mem::zeroed() }
149+
};
150+
unsafe {
151+
v4l2::ioctl(
152+
self.handle.fd(),
153+
v4l2::vidioc::VIDIOC_G_FMT,
154+
&mut v4l2_fmt as *mut _ as *mut std::os::raw::c_void,
155+
)?;
156+
}
157+
158+
#[cfg(feature = "v4l-sys")]
159+
eprintln!(
160+
"\n### WARNING ###\n\
161+
As of early 2020, libv4l2 still does not support USERPTR buffers!\n\
162+
You may want to use this crate with the raw v4l2 FFI bindings instead!\n"
163+
);
164+
165+
// allocate the new user buffers
166+
let count = self.request(count)?;
167+
for _ in 0..count {
168+
let size = unsafe { v4l2_fmt.fmt.pix.sizeimage };
169+
let buf = vec![0u8; size as usize];
170+
self.bufs.push(UserPtr(buf));
171+
}
172+
173+
Ok(count)
174+
}
175+
}

0 commit comments

Comments
 (0)