Skip to main content

v4l/io/userptr/
stream.rs

1use std::convert::TryInto;
2use std::time::Duration;
3use std::{io, mem, sync::Arc};
4
5use crate::buffer::{Metadata, Type};
6use crate::device::{Device, Handle};
7use crate::io::traits::{CaptureStream, Stream as StreamTrait};
8use crate::io::userptr::arena::Arena;
9use crate::memory::Memory;
10use crate::v4l2;
11use crate::v4l_sys::*;
12
13/// Stream of user buffers
14///
15/// An arena instance is used internally for buffer handling.
16pub struct Stream {
17    handle: Arc<Handle>,
18    arena: Arena,
19    arena_index: usize,
20    buf_type: Type,
21    buf_meta: Vec<Metadata>,
22    timeout: Option<i32>,
23
24    active: bool,
25}
26
27impl Stream {
28    /// Returns a stream for frame capturing
29    ///
30    /// # Arguments
31    ///
32    /// * `dev` - Device ref to get its file descriptor
33    /// * `buf_type` - Type of the buffers
34    ///
35    /// # Example
36    ///
37    /// ```
38    /// use v4l::buffer::Type;
39    /// use v4l::device::Device;
40    /// use v4l::io::userptr::Stream;
41    ///
42    /// let dev = Device::new(0);
43    /// if let Ok(dev) = dev {
44    ///     let stream = Stream::new(&dev, Type::VideoCapture);
45    /// }
46    /// ```
47    pub fn new(dev: &Device, buf_type: Type) -> io::Result<Self> {
48        Stream::with_buffers(dev, buf_type, 4)
49    }
50
51    pub fn with_buffers(dev: &Device, buf_type: Type, buf_count: u32) -> io::Result<Self> {
52        let mut arena = Arena::new(dev.handle(), buf_type);
53        let count = arena.allocate(buf_count)?;
54        let mut buf_meta = Vec::new();
55        buf_meta.resize(count as usize, Metadata::default());
56
57        Ok(Stream {
58            handle: dev.handle(),
59            arena,
60            arena_index: 0,
61            buf_type,
62            buf_meta,
63            active: false,
64            timeout: None,
65        })
66    }
67
68    /// Returns the raw device handle
69    pub fn handle(&self) -> Arc<Handle> {
70        self.handle.clone()
71    }
72
73    /// Sets a timeout of the v4l file handle.
74    pub fn set_timeout(&mut self, duration: Duration) {
75        self.timeout = Some(duration.as_millis().try_into().unwrap());
76    }
77
78    /// Clears the timeout of the v4l file handle.
79    pub fn clear_timeout(&mut self) {
80        self.timeout = None;
81    }
82
83    fn buffer_desc(&self) -> v4l2_buffer {
84        v4l2_buffer {
85            type_: self.buf_type as u32,
86            memory: Memory::UserPtr as u32,
87            ..unsafe { mem::zeroed() }
88        }
89    }
90}
91
92impl Drop for Stream {
93    fn drop(&mut self) {
94        if let Err(e) = self.stop() {
95            if let Some(code) = e.raw_os_error() {
96                // ENODEV means the file descriptor wrapped in the handle became invalid, most
97                // likely because the device was unplugged or the connection (USB, PCI, ..)
98                // broke down. Handle this case gracefully by ignoring it.
99                if code == 19 {
100                    /* ignore */
101                    return;
102                }
103            }
104
105            panic!("{:?}", e)
106        }
107    }
108}
109
110impl StreamTrait for Stream {
111    type Item = [u8];
112
113    fn start(&mut self) -> io::Result<()> {
114        unsafe {
115            let mut typ = self.buf_type as u32;
116            v4l2::ioctl(
117                self.handle.fd(),
118                v4l2::vidioc::VIDIOC_STREAMON,
119                &mut typ as *mut _ as *mut std::os::raw::c_void,
120            )?;
121        }
122
123        self.active = true;
124        Ok(())
125    }
126
127    fn stop(&mut self) -> io::Result<()> {
128        unsafe {
129            let mut typ = self.buf_type as u32;
130            v4l2::ioctl(
131                self.handle.fd(),
132                v4l2::vidioc::VIDIOC_STREAMOFF,
133                &mut typ as *mut _ as *mut std::os::raw::c_void,
134            )?;
135        }
136
137        self.active = false;
138        Ok(())
139    }
140}
141
142impl<'a> CaptureStream<'a> for Stream {
143    fn queue(&mut self, index: usize) -> io::Result<()> {
144        let buf = &mut self.arena.bufs[index];
145        let mut v4l2_buf = v4l2_buffer {
146            index: index as u32,
147            m: v4l2_buffer__bindgen_ty_1 {
148                userptr: buf.as_ptr() as std::os::raw::c_ulong,
149            },
150            length: buf.len() as u32,
151            ..self.buffer_desc()
152        };
153        unsafe {
154            v4l2::ioctl(
155                self.handle.fd(),
156                v4l2::vidioc::VIDIOC_QBUF,
157                &mut v4l2_buf as *mut _ as *mut std::os::raw::c_void,
158            )?;
159        }
160
161        Ok(())
162    }
163
164    fn dequeue(&mut self) -> io::Result<usize> {
165        let mut v4l2_buf = self.buffer_desc();
166
167        if self.handle.poll(libc::POLLIN, self.timeout.unwrap_or(-1))? == 0 {
168            // This condition can only happen if there was a timeout.
169            // A timeout is only possible if the `timeout` value is non-zero, meaning we should
170            // propagate it to the caller.
171            return Err(io::Error::new(io::ErrorKind::TimedOut, "VIDIOC_DQBUF"));
172        }
173
174        unsafe {
175            v4l2::ioctl(
176                self.handle.fd(),
177                v4l2::vidioc::VIDIOC_DQBUF,
178                &mut v4l2_buf as *mut _ as *mut std::os::raw::c_void,
179            )?;
180        }
181        self.arena_index = v4l2_buf.index as usize;
182
183        self.buf_meta[self.arena_index] = Metadata {
184            bytesused: v4l2_buf.bytesused,
185            flags: v4l2_buf.flags.into(),
186            field: v4l2_buf.field,
187            timestamp: v4l2_buf.timestamp.into(),
188            sequence: v4l2_buf.sequence,
189        };
190
191        Ok(self.arena_index)
192    }
193
194    fn next(&'a mut self) -> io::Result<(&Self::Item, &Metadata)> {
195        if !self.active {
196            // Enqueue all buffers once on stream start
197            for index in 0..self.arena.bufs.len() {
198                self.queue(index)?;
199            }
200
201            self.start()?;
202        } else {
203            self.queue(self.arena_index)?;
204        }
205
206        self.arena_index = self.dequeue()?;
207
208        // The index used to access the buffer elements is given to us by v4l2, so we assume it
209        // will always be valid.
210        let bytes = &mut self.arena.bufs[self.arena_index];
211        let meta = &self.buf_meta[self.arena_index];
212        Ok((bytes, meta))
213    }
214}