diff --git a/CHANGELOG.md b/CHANGELOG.md index 1645ff6..f2ec853 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ Currently, the focus is on implementing the high-level V4L2 single-planar API. Multi-planar capture will not be targeted in the near future unless someone else starts working on it. +## [0.13.1] - 2023-05-26 +### Added +- Basic multi-planar streaming support ## [0.13.1] - 2022-12-08 ### Fixed diff --git a/Cargo.toml b/Cargo.toml index a4ae1bf..381e95b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "v4l" description = "Safe video4linux (v4l) bindings" -version = "0.13.1" +version = "0.14.0" authors = ["Christopher N. Hesse "] edition = "2018" license = "MIT" @@ -11,8 +11,8 @@ repository= "https://github.com/raymanfx/libv4l-rs" [dependencies] bitflags = "1.2.1" libc = "0.2" -v4l-sys = { path = "v4l-sys", version = "0.2.0", optional = true } -v4l2-sys = { path = "v4l2-sys", version = "0.2.0", package="v4l2-sys-mit", optional = true } +v4l-sys = { path = "v4l-sys", version = "0.2.1", optional = true } +v4l2-sys = { path = "v4l2-sys", version = "0.2.1", package="v4l2-sys-mit", optional = true } [dev-dependencies] glium = "0.27.0" diff --git a/src/buffer.rs b/src/buffer.rs index 7bdb2a3..4c30dcd 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -30,6 +30,15 @@ pub enum Type { Private = 0x80, } +impl Type { + pub fn planar(&self) -> bool { + match self { + Type::VideoCaptureMplane | Type::VideoOutputMplane => true, + _ => false, + } + } +} + bitflags! { #[allow(clippy::unreadable_literal)] pub struct Flags: u32 { diff --git a/src/device.rs b/src/device.rs index 3a2010a..c67e8c5 100644 --- a/src/device.rs +++ b/src/device.rs @@ -11,13 +11,19 @@ use crate::v4l2::videodev::v4l2_ext_controls; use crate::v4l_sys::*; use crate::{capability::Capabilities, control::Control}; +pub const PLANES_ONE: bool = false; +pub const PLANES_MANY: bool = true; + +pub type Device = PlanarDevice; +pub type MultiPlaneDevice = PlanarDevice; + /// Linux capture device abstraction -pub struct Device { +pub struct PlanarDevice { /// Raw handle handle: Arc, } -impl Device { +impl PlanarDevice { /// Returns a capture device by index /// /// Devices are usually enumerated by the system. @@ -41,7 +47,7 @@ impl Device { return Err(io::Error::last_os_error()); } - Ok(Device { + Ok(Self { handle: Arc::new(Handle::new(fd)), }) } @@ -67,7 +73,7 @@ impl Device { return Err(io::Error::last_os_error()); } - Ok(Device { + Ok(Self { handle: Arc::new(Handle::new(fd)), }) } @@ -76,7 +82,9 @@ impl Device { pub fn handle(&self) -> Arc { self.handle.clone() } +} +impl Device { /// Returns video4linux framework defined information such as card, driver, etc. pub fn query_caps(&self) -> io::Result { unsafe { diff --git a/src/format/mod.rs b/src/format/mod.rs index 04cb966..d44bf2e 100644 --- a/src/format/mod.rs +++ b/src/format/mod.rs @@ -46,9 +46,9 @@ impl fmt::Display for Flags { } } -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Clone)] /// Streaming format (single-planar) -pub struct Format { +pub struct PlanarFormat

{ /// width in pixels pub width: u32, /// height in pixels @@ -59,9 +59,9 @@ pub struct Format { pub field_order: FieldOrder, /// bytes per line - pub stride: u32, + pub stride: P, /// maximum number of bytes required to store an image - pub size: u32, + pub size: P, /// flags set by the application or driver pub flags: Flags, @@ -74,6 +74,9 @@ pub struct Format { pub transfer: TransferFunction, } +pub type Format = PlanarFormat; +impl Copy for Format {} + impl Format { /// Returns a capture format /// @@ -154,3 +157,86 @@ impl From for v4l2_pix_format { } } } + +pub type MultiPlaneFormat = PlanarFormat>; + +impl MultiPlaneFormat { + pub fn single_plane(width: u32, height: u32, fourcc: FourCC) -> Self { + Self { + width, + height, + fourcc, + field_order: FieldOrder::Any, + stride: vec![0], + size: vec![0], + flags: Flags::empty(), + colorspace: Colorspace::Default, + quantization: Quantization::Default, + transfer: TransferFunction::Default, + } + } +} + +impl From for MultiPlaneFormat { + fn from(fmt: v4l2_pix_format_mplane) -> Self { + let planes = &fmt.plane_fmt[0..fmt.num_planes as usize]; + Self { + width: fmt.width, + height: fmt.height, + fourcc: FourCC::from(fmt.pixelformat), + field_order: FieldOrder::try_from(fmt.field).expect("Invalid field order"), + stride: planes.iter().map(|p| p.bytesperline).collect(), + size: planes.iter().map(|p| p.sizeimage).collect(), + flags: Flags::from(fmt.flags as u32), + colorspace: Colorspace::try_from(fmt.colorspace).expect("Invalid colorspace"), + quantization: Quantization::try_from(fmt.quantization as u32) + .expect("Invalid quantization"), + transfer: TransferFunction::try_from(fmt.xfer_func as u32) + .expect("Invalid transfer function"), + } + } +} + +impl fmt::Display for MultiPlaneFormat { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + writeln!(f, "width : {}", self.width)?; + writeln!(f, "height : {}", self.height)?; + writeln!(f, "fourcc : {}", self.fourcc)?; + writeln!(f, "field : {}", self.field_order)?; + writeln!(f, "stride : {:?}", self.stride)?; + writeln!(f, "size : {:?}", self.size)?; + writeln!(f, "colorspace : {}", self.colorspace)?; + writeln!(f, "quantization : {}", self.quantization)?; + writeln!(f, "transfer : {}", self.transfer)?; + Ok(()) + } +} + +impl From for v4l2_pix_format_mplane { + fn from(format: MultiPlaneFormat) -> Self { + let mut fmt = Self { + width: format.width, + height: format.height, + pixelformat: format.fourcc.into(), + field: format.field_order as u32, + plane_fmt: [ + v4l2_plane_pix_format { + ..unsafe { mem::zeroed() } + } + ; 8 + ], + num_planes: format.size.len() as u8, + colorspace: format.colorspace as u32, + flags: Into::::into(format.flags) as u8, + quantization: format.quantization as u8, + xfer_func: format.transfer as u8, + ..unsafe { mem::zeroed() } + }; + for i in 0..format.size.len() { + fmt.plane_fmt[i].sizeimage = format.size[i]; + fmt.plane_fmt[i].bytesperline = format.stride[i]; + } + fmt + } +} + diff --git a/src/io/mmap/arena.rs b/src/io/mmap/arena.rs index 9fae806..2d6dd97 100644 --- a/src/io/mmap/arena.rs +++ b/src/io/mmap/arena.rs @@ -12,8 +12,9 @@ use crate::v4l_sys::*; /// In case of errors during unmapping, we panic because there is memory corruption going on. pub struct Arena<'a> { handle: Arc, - pub bufs: Vec<&'a mut [u8]>, + pub bufs: Vec>, pub buf_type: buffer::Type, + pub planes: Vec>, } impl<'a> Arena<'a> { @@ -31,6 +32,7 @@ impl<'a> Arena<'a> { handle, bufs: Vec::new(), buf_type, + planes: Vec::new(), } } @@ -51,6 +53,24 @@ impl<'a> Arena<'a> { } pub fn allocate(&mut self, count: u32) -> io::Result { + let num_planes = if !self.buf_type.planar() { + 1 + } else { + // we need to get the number of image planes from the format + let mut v4l2_fmt: v4l2_format; + unsafe { + v4l2_fmt = mem::zeroed(); + v4l2_fmt.type_ = self.buf_type as u32; + v4l2::ioctl( + self.handle.fd(), + v4l2::vidioc::VIDIOC_G_FMT, + &mut v4l2_fmt as *mut _ as *mut std::os::raw::c_void, + )?; + + v4l2_fmt.fmt.pix_mp.num_planes as usize + } + }; + let mut v4l2_reqbufs = v4l2_requestbuffers { count, ..self.requestbuffers_desc() @@ -64,10 +84,18 @@ impl<'a> Arena<'a> { } for index in 0..v4l2_reqbufs.count { + let mut v4l2_planes: Vec = Vec::new(); + unsafe { + v4l2_planes.resize(num_planes as usize, mem::zeroed()); + } let mut v4l2_buf = v4l2_buffer { index, ..self.buffer_desc() }; + if self.buf_type.planar() { + v4l2_buf.length = num_planes as u32; + v4l2_buf.m.planes = v4l2_planes.as_mut_ptr(); + } unsafe { v4l2::ioctl( self.handle.fd(), @@ -75,18 +103,26 @@ impl<'a> Arena<'a> { &mut v4l2_buf as *mut _ as *mut std::os::raw::c_void, )?; - let ptr = v4l2::mmap( - ptr::null_mut(), - v4l2_buf.length as usize, - libc::PROT_READ | libc::PROT_WRITE, - libc::MAP_SHARED, - self.handle.fd(), - v4l2_buf.m.offset as libc::off_t, - )?; + // each plane has to be mapped separately + let mut planes = Vec::new(); + for plane in &v4l2_planes { + let ptr = v4l2::mmap( + ptr::null_mut(), + plane.length as usize, + libc::PROT_READ | libc::PROT_WRITE, + libc::MAP_SHARED, + self.handle.fd(), + plane.m.mem_offset as libc::off_t, + )?; + + planes.push(slice::from_raw_parts_mut::( + ptr as *mut u8, plane.length as usize + )); + } - let slice = - slice::from_raw_parts_mut::(ptr as *mut u8, v4l2_buf.length as usize); - self.bufs.push(slice); + // finally, add the buffer (with all its planes) to the set + self.bufs.push(planes); + self.planes.push(v4l2_planes); } } @@ -95,8 +131,10 @@ impl<'a> Arena<'a> { pub fn release(&mut self) -> io::Result<()> { for buf in &self.bufs { - unsafe { - v4l2::munmap(buf.as_ptr() as *mut core::ffi::c_void, buf.len())?; + for plane in buf { + unsafe { + v4l2::munmap(plane.as_ptr() as *mut core::ffi::c_void, buf.len())?; + } } } diff --git a/src/io/mmap/stream.rs b/src/io/mmap/stream.rs index cd666bd..3205db6 100644 --- a/src/io/mmap/stream.rs +++ b/src/io/mmap/stream.rs @@ -3,7 +3,7 @@ use std::time::Duration; use std::{io, mem, sync::Arc}; use crate::buffer::{Metadata, Type}; -use crate::device::{Device, Handle}; +use crate::device::{PlanarDevice, Handle}; use crate::io::mmap::arena::Arena; use crate::io::traits::{CaptureStream, OutputStream, Stream as StreamTrait}; use crate::memory::Memory; @@ -44,11 +44,15 @@ impl<'a> Stream<'a> { /// let stream = Stream::new(&dev, Type::VideoCapture); /// } /// ``` - pub fn new(dev: &Device, buf_type: Type) -> io::Result { + pub fn new( + dev: &PlanarDevice, buf_type: Type + ) -> io::Result { Stream::with_buffers(dev, buf_type, 4) } - pub fn with_buffers(dev: &Device, buf_type: Type, buf_count: u32) -> io::Result { + pub fn with_buffers( + dev: &PlanarDevice, buf_type: Type, buf_count: u32 + ) -> io::Result { let mut arena = Arena::new(dev.handle(), buf_type); let count = arena.allocate(buf_count)?; let mut buf_meta = Vec::new(); @@ -80,12 +84,18 @@ impl<'a> Stream<'a> { self.timeout = None; } - fn buffer_desc(&self) -> v4l2_buffer { - v4l2_buffer { + fn buffer_desc(&mut self, index: usize) -> v4l2_buffer { + let mut v4l2_buf = v4l2_buffer { + index: index as u32, type_: self.buf_type as u32, memory: Memory::Mmap as u32, ..unsafe { mem::zeroed() } + }; + if self.buf_type.planar() { + v4l2_buf.length = self.arena.planes[index].len() as u32; + v4l2_buf.m.planes = self.arena.planes[index].as_mut_ptr(); } + v4l2_buf } } @@ -108,7 +118,7 @@ impl<'a> Drop for Stream<'a> { } impl<'a> StreamTrait for Stream<'a> { - type Item = [u8]; + type Item = Vec<&'a mut [u8]>; fn start(&mut self) -> io::Result<()> { unsafe { @@ -142,8 +152,7 @@ impl<'a> StreamTrait for Stream<'a> { impl<'a, 'b> CaptureStream<'b> for Stream<'a> { fn queue(&mut self, index: usize) -> io::Result<()> { let mut v4l2_buf = v4l2_buffer { - index: index as u32, - ..self.buffer_desc() + ..self.buffer_desc(index) }; unsafe { @@ -158,7 +167,7 @@ impl<'a, 'b> CaptureStream<'b> for Stream<'a> { } fn dequeue(&mut self) -> io::Result { - let mut v4l2_buf = self.buffer_desc(); + let mut v4l2_buf = self.buffer_desc(0); if self.handle.poll(libc::POLLIN, self.timeout.unwrap_or(-1))? == 0 { // This condition can only happen if there was a timeout. @@ -187,6 +196,10 @@ impl<'a, 'b> CaptureStream<'b> for Stream<'a> { Ok(self.arena_index) } + fn get(&self, index: usize) -> io::Result<(&Self::Item, &Metadata)> { + Ok((&self.arena.bufs[index], &self.buf_meta[index])) + } + fn next(&'b mut self) -> io::Result<(&Self::Item, &Metadata)> { if !self.active { // Enqueue all buffers once on stream start @@ -199,21 +212,15 @@ impl<'a, 'b> CaptureStream<'b> for Stream<'a> { CaptureStream::queue(self, self.arena_index)?; } - self.arena_index = CaptureStream::dequeue(self)?; - - // 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)) + let index = CaptureStream::dequeue(self)?; + CaptureStream::get(self, index) } } impl<'a, 'b> OutputStream<'b> for Stream<'a> { fn queue(&mut self, index: usize) -> io::Result<()> { let mut v4l2_buf = v4l2_buffer { - index: index as u32, - ..self.buffer_desc() + ..self.buffer_desc(index) }; unsafe { // output settings @@ -244,7 +251,7 @@ impl<'a, 'b> OutputStream<'b> for Stream<'a> { } fn dequeue(&mut self) -> io::Result { - let mut v4l2_buf = self.buffer_desc(); + let mut v4l2_buf = self.buffer_desc(0); unsafe { v4l2::ioctl( diff --git a/src/io/traits.rs b/src/io/traits.rs index 8234016..37d0fb8 100644 --- a/src/io/traits.rs +++ b/src/io/traits.rs @@ -20,6 +20,9 @@ pub trait CaptureStream<'a>: Stream { /// Remove a buffer from the drivers' outgoing queue fn dequeue(&mut self) -> io::Result; + /// Access the buffer at the specified index. + fn get(&self, index: usize) -> io::Result<(&Self::Item, &Metadata)>; + /// 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)>; diff --git a/src/io/userptr/stream.rs b/src/io/userptr/stream.rs index 5261806..272aaad 100644 --- a/src/io/userptr/stream.rs +++ b/src/io/userptr/stream.rs @@ -191,6 +191,10 @@ impl<'a> CaptureStream<'a> for Stream { Ok(self.arena_index) } + fn get(&self, index: usize) -> io::Result<(&Self::Item, &Metadata)> { + Ok((&self.arena.bufs[index], &self.buf_meta[index])) + } + fn next(&'a mut self) -> io::Result<(&Self::Item, &Metadata)> { if !self.active { // Enqueue all buffers once on stream start @@ -203,12 +207,7 @@ impl<'a> CaptureStream<'a> for Stream { self.queue(self.arena_index)?; } - self.arena_index = self.dequeue()?; - - // 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 = &self.buf_meta[self.arena_index]; - Ok((bytes, meta)) + let index = self.dequeue()?; + self.get(index) } } diff --git a/src/video/capture/mod.rs b/src/video/capture/mod.rs index 949502c..277833b 100644 --- a/src/video/capture/mod.rs +++ b/src/video/capture/mod.rs @@ -1,10 +1,11 @@ pub mod parameters; pub use parameters::Parameters; +pub mod mplane; use std::convert::TryFrom; use std::{io, mem}; -use crate::buffer::Type; +use crate::buffer::Type::VideoCapture; use crate::device::Device; use crate::format::FourCC; use crate::format::{Description as FormatDescription, Format}; @@ -17,14 +18,16 @@ use crate::video::traits::Capture; impl Capture for Device { impl_enum_frameintervals!(); impl_enum_framesizes!(); - impl_enum_formats!(Type::VideoCapture); - impl_format!(Type::VideoCapture); - impl_set_format!(Type::VideoCapture); + impl_enum_formats!(VideoCapture); + impl_format!(VideoCapture); + impl_set_format!(VideoCapture); + + type Format = Format; fn params(&self) -> io::Result { unsafe { let mut v4l2_params = v4l2_streamparm { - type_: Type::VideoCapture as u32, + type_: VideoCapture as u32, ..mem::zeroed() }; v4l2::ioctl( @@ -40,7 +43,7 @@ impl Capture for Device { fn set_params(&self, params: &Parameters) -> io::Result { unsafe { let mut v4l2_params = v4l2_streamparm { - type_: Type::VideoCapture as u32, + type_: VideoCapture as u32, parm: v4l2_streamparm__bindgen_ty_1 { capture: (*params).into(), }, diff --git a/src/video/capture/mplane.rs b/src/video/capture/mplane.rs new file mode 100644 index 0000000..fd89020 --- /dev/null +++ b/src/video/capture/mplane.rs @@ -0,0 +1,31 @@ +use std::convert::TryFrom; +use std::{io, mem}; + +use super::Parameters; +use crate::buffer::Type::VideoCaptureMplane; +use crate::device::MultiPlaneDevice; +use crate::format::FourCC; +use crate::format::{Description as FormatDescription, MultiPlaneFormat}; +use crate::frameinterval::FrameInterval; +use crate::framesize::FrameSize; +use crate::v4l2; +use crate::v4l_sys::*; +use crate::video::traits::Capture; + +impl Capture for MultiPlaneDevice { + impl_enum_frameintervals!(); + impl_enum_framesizes!(); + impl_format!(VideoCaptureMplane); + impl_set_format!(VideoCaptureMplane); + impl_enum_formats!(VideoCaptureMplane); + + type Format = MultiPlaneFormat; + + fn params(&self) -> io::Result { + unimplemented!() + } + + fn set_params(&self, _params: &Parameters) -> io::Result { + unimplemented!() + } +} diff --git a/src/video/macros.rs b/src/video/macros.rs index 3f35829..12ea3bc 100644 --- a/src/video/macros.rs +++ b/src/video/macros.rs @@ -127,9 +127,15 @@ macro_rules! impl_enum_formats { }; } +macro_rules! get_pix { + (VideoCapture) => { |v4l2_fmt: v4l2_format| v4l2_fmt.fmt.pix }; + (VideoOutput) => { |v4l2_fmt: v4l2_format| v4l2_fmt.fmt.pix }; + (VideoCaptureMplane) => { |v4l2_fmt: v4l2_format| v4l2_fmt.fmt.pix_mp }; +} + macro_rules! impl_format { - ($typ:expr) => { - fn format(&self) -> io::Result { + ($typ:ident) => { + fn format(&self) -> io::Result { unsafe { let mut v4l2_fmt = v4l2_format { type_: $typ as u32, @@ -141,19 +147,25 @@ macro_rules! impl_format { &mut v4l2_fmt as *mut _ as *mut std::os::raw::c_void, )?; - Ok(Format::from(v4l2_fmt.fmt.pix)) + Ok(Self::Format::from(get_pix!($typ)(v4l2_fmt))) } } }; } +macro_rules! set_pix { + (VideoCapture, $pix:expr) => { v4l2_format__bindgen_ty_1 { pix: $pix, } }; + (VideoOutput, $pix:expr) => { v4l2_format__bindgen_ty_1 { pix: $pix, } }; + (VideoCaptureMplane, $pix:expr) => { v4l2_format__bindgen_ty_1 { pix_mp: $pix, } }; +} + macro_rules! impl_set_format { - ($typ:expr) => { - fn set_format(&self, fmt: &Format) -> io::Result { + ($typ:ident) => { + fn set_format(&self, fmt: &Self::Format) -> io::Result { unsafe { let mut v4l2_fmt = v4l2_format { type_: $typ as u32, - fmt: v4l2_format__bindgen_ty_1 { pix: (*fmt).into() }, + fmt: set_pix!($typ, fmt.clone().into()), }; v4l2::ioctl( self.handle().fd(), diff --git a/src/video/output/mod.rs b/src/video/output/mod.rs index f7f82c3..cadbfc0 100644 --- a/src/video/output/mod.rs +++ b/src/video/output/mod.rs @@ -4,7 +4,7 @@ pub use parameters::Parameters; use std::convert::TryFrom; use std::{io, mem}; -use crate::buffer::Type; +use crate::buffer::Type::VideoOutput; use crate::device::Device; use crate::format::FourCC; use crate::format::{Description as FormatDescription, Format}; @@ -17,14 +17,16 @@ use crate::video::traits::Output; impl Output for Device { impl_enum_frameintervals!(); impl_enum_framesizes!(); - impl_enum_formats!(Type::VideoOutput); - impl_format!(Type::VideoOutput); - impl_set_format!(Type::VideoOutput); + impl_enum_formats!(VideoOutput); + impl_format!(VideoOutput); + impl_set_format!(VideoOutput); + + type Format = Format; fn params(&self) -> io::Result { unsafe { let mut v4l2_params = v4l2_streamparm { - type_: Type::VideoOutput as u32, + type_: VideoOutput as u32, ..mem::zeroed() }; v4l2::ioctl( @@ -40,7 +42,7 @@ impl Output for Device { fn set_params(&self, params: &Parameters) -> io::Result { unsafe { let mut v4l2_params = v4l2_streamparm { - type_: Type::VideoOutput as u32, + type_: VideoOutput as u32, parm: v4l2_streamparm__bindgen_ty_1 { output: (*params).into(), }, diff --git a/src/video/traits.rs b/src/video/traits.rs index e7444e1..f701db7 100644 --- a/src/video/traits.rs +++ b/src/video/traits.rs @@ -3,12 +3,13 @@ use std::io; use crate::video::capture::Parameters as CaptureParameters; use crate::video::output::Parameters as OutputParameters; use crate::{ - format::Description as FormatDescription, format::Format, format::FourCC, + format::Description as FormatDescription, format::FourCC, frameinterval::FrameInterval, framesize::FrameSize, }; /// Capture device protocol pub trait Capture { + type Format; /// Returns a vector of all frame intervals that the device supports for the given pixel format /// and frame size fn enum_frameintervals( @@ -28,7 +29,7 @@ pub trait Capture { fn enum_formats(&self) -> io::Result>; /// Returns the format currently in use - fn format(&self) -> io::Result; + fn format(&self) -> io::Result; /// Modifies the capture format and returns the actual format /// @@ -40,7 +41,7 @@ pub trait Capture { /// # Arguments /// /// * `fmt` - Desired format - fn set_format(&self, fmt: &Format) -> io::Result; + fn set_format(&self, fmt: &Self::Format) -> io::Result; /// Returns the parameters currently in use fn params(&self) -> io::Result; @@ -55,6 +56,7 @@ pub trait Capture { /// Output device protocol pub trait Output { + type Format; /// Returns a vector of all frame intervals that the device supports for the given pixel format /// and frame size fn enum_frameintervals( @@ -74,7 +76,7 @@ pub trait Output { fn enum_formats(&self) -> io::Result>; /// Returns the format currently in use - fn format(&self) -> io::Result; + fn format(&self) -> io::Result; /// Modifies the capture format and returns the actual format /// @@ -85,7 +87,7 @@ pub trait Output { /// # Arguments /// /// * `fmt` - Desired format - fn set_format(&self, fmt: &Format) -> io::Result; + fn set_format(&self, fmt: &Self::Format) -> io::Result; /// Returns the parameters currently in use fn params(&self) -> io::Result; diff --git a/v4l-sys/Cargo.toml b/v4l-sys/Cargo.toml index 2372adf..4382ae1 100644 --- a/v4l-sys/Cargo.toml +++ b/v4l-sys/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "v4l-sys" description = "Raw video4linux (v4l) bindings" -version = "0.2.0" +version = "0.2.1" authors = ["Christopher N. Hesse "] edition = "2018" license = "MIT" diff --git a/v4l2-sys/Cargo.toml b/v4l2-sys/Cargo.toml index b499730..eb6442e 100644 --- a/v4l2-sys/Cargo.toml +++ b/v4l2-sys/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "v4l2-sys-mit" description = "Raw v4l2 bindings (MIT licensed)" -version = "0.2.0" +version = "0.2.1" authors = ["Christopher N. Hesse "] edition = "2018" license = "MIT"