1use std::convert::TryFrom;
2use std::path::Path;
3use std::sync::Arc;
4use std::{io, mem};
5
6use libc;
7
8use crate::control;
9use crate::v4l2;
10use crate::v4l2::videodev::v4l2_ext_controls;
11use crate::v4l_sys::*;
12use crate::{capability::Capabilities, control::Control};
13
14pub struct Device {
16 handle: Arc<Handle>,
18}
19
20impl Device {
21 pub fn new(index: usize) -> io::Result<Self> {
37 let path = format!("{}{}", "/dev/video", index);
38 let fd = v4l2::open(path, libc::O_RDWR | libc::O_NONBLOCK)?;
39
40 if fd == -1 {
41 return Err(io::Error::last_os_error());
42 }
43
44 Ok(Device {
45 handle: Arc::new(Handle::new(fd)),
46 })
47 }
48
49 pub fn with_path<P: AsRef<Path>>(path: P) -> io::Result<Self> {
64 let fd = v4l2::open(&path, libc::O_RDWR | libc::O_NONBLOCK)?;
65
66 if fd == -1 {
67 return Err(io::Error::last_os_error());
68 }
69
70 Ok(Device {
71 handle: Arc::new(Handle::new(fd)),
72 })
73 }
74
75 pub fn handle(&self) -> Arc<Handle> {
77 self.handle.clone()
78 }
79
80 pub fn query_caps(&self) -> io::Result<Capabilities> {
82 unsafe {
83 let mut v4l2_caps: v4l2_capability = mem::zeroed();
84 v4l2::ioctl(
85 self.handle().fd(),
86 v4l2::vidioc::VIDIOC_QUERYCAP,
87 &mut v4l2_caps as *mut _ as *mut std::os::raw::c_void,
88 )?;
89
90 Ok(Capabilities::from(v4l2_caps))
91 }
92 }
93
94 pub fn query_controls(&self) -> io::Result<Vec<control::Description>> {
96 let mut controls = Vec::new();
97 unsafe {
98 let mut v4l2_ctrl: v4l2_query_ext_ctrl = mem::zeroed();
99
100 loop {
101 v4l2_ctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
102 v4l2_ctrl.id |= V4L2_CTRL_FLAG_NEXT_COMPOUND;
103 match v4l2::ioctl(
104 self.handle().fd(),
105 v4l2::vidioc::VIDIOC_QUERY_EXT_CTRL,
106 &mut v4l2_ctrl as *mut _ as *mut std::os::raw::c_void,
107 ) {
108 Ok(_) => {
109 let mut control = control::Description::from(v4l2_ctrl);
111
112 if control.typ == control::Type::Menu
114 || control.typ == control::Type::IntegerMenu
115 {
116 let mut items = Vec::new();
117
118 for i in (v4l2_ctrl.minimum..=v4l2_ctrl.maximum)
119 .step_by(v4l2_ctrl.step as usize)
120 {
121 let mut v4l2_menu = v4l2_querymenu {
122 id: v4l2_ctrl.id,
123 index: i as u32,
124 ..mem::zeroed()
125 };
126 let res = v4l2::ioctl(
127 self.handle().fd(),
128 v4l2::vidioc::VIDIOC_QUERYMENU,
129 &mut v4l2_menu as *mut _ as *mut std::os::raw::c_void,
130 );
131
132 if res.is_err() {
143 continue;
144 }
145
146 let item =
147 control::MenuItem::try_from((control.typ, v4l2_menu)).unwrap();
148 items.push((v4l2_menu.index, item));
149 }
150
151 control.items = Some(items);
152 }
153
154 controls.push(control);
155 }
156 Err(e) => {
157 if controls.is_empty() || e.kind() != io::ErrorKind::InvalidInput {
158 return Err(e);
159 } else {
160 break;
161 }
162 }
163 }
164 }
165 }
166
167 Ok(controls)
168 }
169
170 pub fn control(&self, id: u32) -> io::Result<Control> {
176 unsafe {
177 let mut queryctrl = v4l2_query_ext_ctrl {
178 id,
179 ..mem::zeroed()
180 };
181 v4l2::ioctl(
182 self.handle().fd(),
183 v4l2::vidioc::VIDIOC_QUERY_EXT_CTRL,
184 &mut queryctrl as *mut _ as *mut std::os::raw::c_void,
185 )?;
186
187 let description = control::Description::from(queryctrl);
189
190 let mut v4l2_ctrl = v4l2_ext_control {
192 id,
193 ..mem::zeroed()
194 };
195 let mut v4l2_ctrls = v4l2_ext_controls {
196 count: 1,
197 controls: &mut v4l2_ctrl,
198 ..mem::zeroed()
199 };
200 v4l2::ioctl(
201 self.handle().fd(),
202 v4l2::vidioc::VIDIOC_G_EXT_CTRLS,
203 &mut v4l2_ctrls as *mut _ as *mut std::os::raw::c_void,
204 )?;
205
206 let value = match description.typ {
207 control::Type::Integer64 => {
208 control::Value::Integer(v4l2_ctrl.__bindgen_anon_1.value64)
209 }
210 control::Type::Integer | control::Type::Menu => {
211 control::Value::Integer(v4l2_ctrl.__bindgen_anon_1.value as i64)
212 }
213 control::Type::Boolean => {
214 control::Value::Boolean(v4l2_ctrl.__bindgen_anon_1.value == 1)
215 }
216 _ => {
217 return Err(io::Error::new(
218 io::ErrorKind::Other,
219 "cannot handle control type",
220 ))
221 }
222 };
223
224 Ok(Control { id, value })
225 }
226 }
227
228 pub fn set_control(&self, ctrl: Control) -> io::Result<()> {
234 self.set_controls(vec![ctrl])
235 }
236
237 pub fn set_controls(&self, ctrls: Vec<Control>) -> io::Result<()> {
243 unsafe {
244 let mut control_list: Vec<v4l2_ext_control> = vec![];
245 let mut class: Option<u32> = None;
246
247 if ctrls.is_empty() {
248 return Err(io::Error::new(
249 io::ErrorKind::InvalidInput,
250 "ctrls cannot be empty",
251 ));
252 }
253
254 for ref ctrl in ctrls {
255 let mut control = v4l2_ext_control {
256 id: ctrl.id,
257 ..mem::zeroed()
258 };
259 class = match class {
260 Some(c) => {
261 if c != (control.id & 0xFFFF0000) {
262 return Err(io::Error::new(
263 io::ErrorKind::InvalidInput,
264 "All controls must be in the same class",
265 ));
266 } else {
267 Some(c)
268 }
269 }
270 None => Some(control.id & 0xFFFF0000),
271 };
272
273 match ctrl.value {
274 control::Value::None => {}
275 control::Value::Integer(val) => {
276 control.__bindgen_anon_1.value64 = val;
277 control.size = std::mem::size_of::<i64>() as u32;
278 }
279 control::Value::Boolean(val) => {
280 control.__bindgen_anon_1.value64 = val as i64;
281 control.size = std::mem::size_of::<i64>() as u32;
282 }
283 control::Value::String(ref val) => {
284 control.__bindgen_anon_1.string = val.as_ptr() as *mut std::os::raw::c_char;
285 control.size = val.len() as u32;
286 }
287 control::Value::CompoundU8(ref val) => {
288 control.__bindgen_anon_1.p_u8 = val.as_ptr() as *mut u8;
289 control.size = (val.len() * std::mem::size_of::<u8>()) as u32;
290 }
291 control::Value::CompoundU16(ref val) => {
292 control.__bindgen_anon_1.p_u16 = val.as_ptr() as *mut u16;
293 control.size = (val.len() * std::mem::size_of::<u16>()) as u32;
294 }
295 control::Value::CompoundU32(ref val) => {
296 control.__bindgen_anon_1.p_u32 = val.as_ptr() as *mut u32;
297 control.size = (val.len() * std::mem::size_of::<u32>()) as u32;
298 }
299 control::Value::CompoundPtr(ref val) => {
300 control.__bindgen_anon_1.ptr = val.as_ptr() as *mut std::os::raw::c_void;
301 control.size = (val.len() * std::mem::size_of::<u8>()) as u32;
302 }
303 };
304
305 control_list.push(control);
306 }
307
308 let class = class.ok_or_else(|| {
309 io::Error::new(
310 io::ErrorKind::InvalidInput,
311 "failed to determine control class",
312 )
313 })?;
314
315 let mut controls = v4l2_ext_controls {
316 count: control_list.len() as u32,
317 controls: control_list.as_mut_ptr(),
318
319 which: class,
320 ..mem::zeroed()
321 };
322
323 v4l2::ioctl(
324 self.handle().fd(),
325 v4l2::vidioc::VIDIOC_S_EXT_CTRLS,
326 &mut controls as *mut _ as *mut std::os::raw::c_void,
327 )
328 }
329 }
330}
331
332impl io::Read for Device {
333 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
334 unsafe {
335 let ret = libc::read(
336 self.handle().fd(),
337 buf.as_mut_ptr() as *mut std::os::raw::c_void,
338 buf.len(),
339 );
340 match ret {
341 -1 => Err(io::Error::last_os_error()),
342 ret => Ok(ret as usize),
343 }
344 }
345 }
346}
347
348impl io::Write for Device {
349 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
350 unsafe {
351 let ret = libc::write(
352 self.handle().fd(),
353 buf.as_ptr() as *const std::os::raw::c_void,
354 buf.len(),
355 );
356
357 match ret {
358 -1 => Err(io::Error::last_os_error()),
359 ret => Ok(ret as usize),
360 }
361 }
362 }
363
364 fn flush(&mut self) -> io::Result<()> {
365 Ok(())
368 }
369}
370
371pub struct Handle {
375 fd: std::os::raw::c_int,
376}
377
378impl Handle {
379 fn new(fd: std::os::raw::c_int) -> Self {
380 Self { fd }
381 }
382
383 pub fn fd(&self) -> std::os::raw::c_int {
385 self.fd
386 }
387
388 pub fn poll(&self, events: i16, timeout: i32) -> io::Result<i32> {
398 match unsafe {
399 libc::poll(
400 [libc::pollfd {
401 fd: self.fd,
402 events,
403 revents: 0,
404 }]
405 .as_mut_ptr(),
406 1,
407 timeout,
408 )
409 } {
410 -1 => Err(io::Error::last_os_error()),
411 ret => {
412 assert!(ret == 0 || ret == 1);
415 Ok(ret)
416 }
417 }
418 }
419}
420
421impl Drop for Handle {
422 fn drop(&mut self) {
423 v4l2::close(self.fd).unwrap();
424 }
425}