-
Notifications
You must be signed in to change notification settings - Fork 66
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
432 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
use std::io; | ||
use std::time::Instant; | ||
|
||
use v4l::buffer::Type; | ||
use v4l::io::traits::CaptureStream; | ||
use v4l::prelude::*; | ||
use v4l::video::Capture; | ||
|
||
fn main() -> io::Result<()> { | ||
let path = "/dev/video0"; | ||
println!("Using device: {}\n", path); | ||
|
||
// Capture 4 frames by default | ||
let count = 4; | ||
|
||
// Allocate 4 buffers by default | ||
let buffer_count = 4; | ||
|
||
let dev = Device::with_path(path)?; | ||
let format = dev.format()?; | ||
let params = dev.params()?; | ||
println!("Active format:\n{}", format); | ||
println!("Active parameters:\n{}", params); | ||
|
||
// Setup a buffer stream and grab a frame, then print its data | ||
let mut stream = DmabufStream::with_buffers(&dev, Type::VideoCapture, buffer_count)?; | ||
|
||
// warmup | ||
stream.next()?; | ||
|
||
let start = Instant::now(); | ||
let mut megabytes_ps: f64 = 0.0; | ||
for i in 0..count { | ||
let t0 = Instant::now(); | ||
let (buf, meta) = stream.next()?; | ||
let duration_us = t0.elapsed().as_micros(); | ||
|
||
println!("Buffer"); | ||
println!(" sequence : {}", meta.sequence); | ||
println!(" timestamp : {}", meta.timestamp); | ||
println!(" flags : {}", meta.flags); | ||
use std::fs::File; | ||
use std::os::fd::{FromRawFd, AsRawFd, IntoRawFd}; | ||
use memmap2; | ||
let outf = unsafe { File::from_raw_fd(buf.as_raw_fd()) }; | ||
let outfmap = unsafe { memmap2::Mmap::map(&outf) }?; | ||
println!(" length : {}", outfmap.len()); | ||
|
||
let cur = outfmap.len() as f64 / 1_048_576.0 * 1_000_000.0 / duration_us as f64; | ||
if i == 0 { | ||
megabytes_ps = cur; | ||
} else { | ||
// ignore the first measurement | ||
let prev = megabytes_ps * (i as f64 / (i + 1) as f64); | ||
let now = cur * (1.0 / (i + 1) as f64); | ||
megabytes_ps = prev + now; | ||
} | ||
// Prevent File from dropping and closing the fd, because fd is borrowed from texture and not ours to close. | ||
let _ = File::into_raw_fd(outf); | ||
} | ||
|
||
println!(); | ||
println!("FPS: {}", count as f64 / start.elapsed().as_secs_f64()); | ||
println!("MB/s: {}", megabytes_ps); | ||
|
||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
use std::{io, mem, sync::Arc}; | ||
use std::os::fd::{FromRawFd, OwnedFd}; | ||
|
||
use crate::buffer; | ||
use crate::device::Handle; | ||
use crate::memory::Memory; | ||
use crate::v4l2; | ||
use crate::v4l_sys::*; | ||
|
||
/// Manage dmabuf buffers | ||
/// | ||
/// All buffers are released in the Drop impl. | ||
pub struct Arena { | ||
handle: Arc<Handle>, | ||
pub bufs: Vec<OwnedFd>, | ||
pub buf_type: buffer::Type, | ||
} | ||
|
||
impl Arena { | ||
/// Returns a new buffer manager instance | ||
/// | ||
/// You usually do not need to use this directly. | ||
/// A UserBufferStream creates its own manager instance by default. | ||
/// | ||
/// # Arguments | ||
/// | ||
/// * `handle` - Device handle to get its file descriptor | ||
/// * `buf_type` - Type of the buffers | ||
pub fn new(handle: Arc<Handle>, buf_type: buffer::Type) -> Self { | ||
Arena { | ||
handle, | ||
bufs: Vec::new(), | ||
buf_type, | ||
} | ||
} | ||
|
||
fn requestbuffers_desc(&self) -> v4l2_requestbuffers { | ||
v4l2_requestbuffers { | ||
type_: self.buf_type as u32, | ||
..unsafe { mem::zeroed() } | ||
} | ||
} | ||
|
||
pub fn allocate(&mut self, count: u32) -> io::Result<u32> { | ||
// we need to get the maximum buffer size from the format first | ||
let mut v4l2_fmt = v4l2_format { | ||
type_: self.buf_type as u32, | ||
..unsafe { mem::zeroed() } | ||
}; | ||
unsafe { | ||
v4l2::ioctl( | ||
self.handle.fd(), | ||
v4l2::vidioc::VIDIOC_G_FMT, | ||
&mut v4l2_fmt as *mut _ as *mut std::os::raw::c_void, | ||
)?; | ||
} | ||
|
||
let mut v4l2_reqbufs = v4l2_requestbuffers { | ||
count, | ||
memory: Memory::Mmap as u32, | ||
..self.requestbuffers_desc() | ||
}; | ||
unsafe { | ||
v4l2::ioctl( | ||
self.handle.fd(), | ||
v4l2::vidioc::VIDIOC_REQBUFS, | ||
&mut v4l2_reqbufs as *mut _ as *mut std::os::raw::c_void, | ||
)?; | ||
} | ||
|
||
for index in 0..v4l2_reqbufs.count { | ||
let mut v4l2_exportbuf = v4l2_exportbuffer { | ||
index, | ||
type_: self.buf_type as u32, | ||
flags: libc::O_RDWR as _, | ||
..unsafe { mem::zeroed() } | ||
}; | ||
let fd = unsafe { | ||
v4l2::ioctl( | ||
self.handle.fd(), | ||
v4l2::vidioc::VIDIOC_EXPBUF, | ||
&mut v4l2_exportbuf as *mut _ as *mut std::os::raw::c_void, | ||
)?; | ||
OwnedFd::from_raw_fd(v4l2_exportbuf.fd) | ||
}; | ||
self.bufs.push(fd); | ||
} | ||
|
||
let mut v4l2_reqbufs = v4l2_requestbuffers { | ||
count, | ||
memory: Memory::DmaBuf as u32, | ||
..self.requestbuffers_desc() | ||
}; | ||
unsafe { | ||
v4l2::ioctl( | ||
self.handle.fd(), | ||
v4l2::vidioc::VIDIOC_REQBUFS, | ||
&mut v4l2_reqbufs as *mut _ as *mut std::os::raw::c_void, | ||
)?; | ||
} | ||
|
||
Ok(v4l2_reqbufs.count) | ||
} | ||
|
||
pub fn release(&mut self) -> io::Result<()> { | ||
// free all buffers by requesting 0 | ||
let mut v4l2_reqbufs = v4l2_requestbuffers { | ||
count: 0, | ||
memory: Memory::DmaBuf as u32, | ||
..self.requestbuffers_desc() | ||
}; | ||
unsafe { | ||
v4l2::ioctl( | ||
self.handle.fd(), | ||
v4l2::vidioc::VIDIOC_REQBUFS, | ||
&mut v4l2_reqbufs as *mut _ as *mut std::os::raw::c_void, | ||
) | ||
} | ||
} | ||
} | ||
|
||
impl Drop for Arena { | ||
fn drop(&mut self) { | ||
if self.bufs.is_empty() { | ||
// nothing to do | ||
return; | ||
} | ||
|
||
if let Err(e) = self.release() { | ||
if let Some(code) = e.raw_os_error() { | ||
// ENODEV means the file descriptor wrapped in the handle became invalid, most | ||
// likely because the device was unplugged or the connection (USB, PCI, ..) | ||
// broke down. Handle this case gracefully by ignoring it. | ||
if code == 19 { | ||
/* ignore */ | ||
return; | ||
} | ||
} | ||
|
||
panic!("{:?}", e) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
pub(crate) mod arena; | ||
|
||
pub mod stream; | ||
pub use stream::Stream; |
Oops, something went wrong.