1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/* Copyright (C) 2023 Purism SPC
 * Copyright (C) 2024 DorotaC
 * SPDX-License-Identifier: LGPL-2.1-or-later
 */

/*! UVC (USB) cameras. */

use crate::actors::camera_list::CreationKit;
use crate::actors::watcher_udev::Device;
use crate::pipelines;
use crate::util::flock::Locked;
use crate::util::media;
use std::error::Error;
use std::io;
use std::sync::Arc;
use super::{CameraInfo, Config};
use v4l;
use v4l::video::Capture;

fn apply_config(config: &Config, mut format: v4l::Format) -> v4l::Format {
    format.fourcc = config.fourcc;
    format.width = config.width;
    format.height = config.height;
    format
}

struct CameraDevice {
    // TODO: the media device is not a video capture device.
    device: media::Device,
}

impl super::UnacquiredCameraImpl for CameraDevice {
    fn acquire(self: Box<Self>) -> Result<Arc<dyn super::CameraImpl>, Box<dyn Error>> {
        if let Ok(device) = self.device.try_lock() {
            let video_capture_device = v4l::Device::with_path(device.get_video_capture_path()?)?;
            Ok(Arc::new(Camera {device, video_capture_device}))
        } else {
            Err(Box::new(super::AcquireError::AlreadyAcquired))
        }
    }
}
    
struct Camera {
    device: Locked<media::Device>,
    video_capture_device: v4l::Device,
}

impl super::CameraImpl for Camera {
    fn configure(&self, config: Config) -> Result<(), io::Error> {
        let format = self.video_capture_device.format()?;
        let format = apply_config(&config, format);
        self.video_capture_device.set_format(&format)?;
        Ok(())
    }

    fn video_capture_device(&self) -> &v4l::Device {
        &self.video_capture_device
    }
}

pub struct Checker {
}

impl Checker {
    pub fn check_match(device: &Device)
        -> Option<CreationKit>
    {
        device.device_node.as_ref()
            .and_then(|p| {
                media::Device::new(p).unwrap()
                .get_device_info().ok()
            })
            .and_then(|d| {
                if d.get_driver() == "uvcvideo" {
                    Some(CreationKit {
                        info: CameraInfo {
                            device: device.clone(),
                            id: format!("uvc:{}:{:0x}", d.get_device(), device.stable_id()),
                        },
                        builder: build as super::Builder,
                    })
                } else {
                    None
                }
            })
    }
}

pub fn build(camera: CameraInfo)
    -> Result<pipelines::UnacquiredCamera, Box<dyn Error>>
{
    let device = media::Device::new(
        camera.device
            .device_node.as_ref()
            .unwrap() // FIXME: why unwrap? The library should *never* crash
    )?;
    
    Ok(pipelines::UnacquiredCamera {
        device: Box::new(CameraDevice {
            device,
        }),
        id: camera.id,
    })
}