chalkydri/
cameras.rs

1use libcamera::{
2    camera::{ActiveCamera, CameraConfiguration},
3    camera_manager::CameraManager,
4    framebuffer_allocator::{FrameBuffer, FrameBufferAllocator},
5    framebuffer_map::MemoryMappedFrameBuffer,
6    properties,
7    request::{Request, ReuseFlag},
8    stream::StreamRole,
9};
10
11#[cfg(feature = "rerun")]
12use re_types::archetypes::EncodedImage;
13use std::{error::Error, sync::Arc, time::Duration};
14use tokio::sync::watch;
15use yuvutils_rs::{yuv420_to_rgb, YuvPlanarImage, YuvRange, YuvStandardMatrix};
16
17#[cfg(feature = "rerun")]
18use crate::Rerun;
19pub fn load_cameras(frame_tx: watch::Sender<Arc<Vec<u8>>>) -> Result<(), Box<dyn Error>> {
20    let man = CameraManager::new()?;
21    let cameras = man.cameras();
22    // TODO: this must not crash the software
23    assert!(cameras.len() > 0, "connect a camera");
24    let cam = cameras.get(0).unwrap();
25    info!("using camera '{}'", cam.id());
26    let cfgg = cam
27        .generate_configuration(&[StreamRole::VideoRecording])
28        .unwrap();
29    dbg!(&cfgg);
30
31    let active_cam = cam.acquire().unwrap();
32    let mut cw = CamWrapper::new(active_cam, cfgg, frame_tx);
33    cw.setup();
34    cw.run();
35
36    Ok(())
37}
38
39pub struct CamWrapper<'cam> {
40    cam: ActiveCamera<'cam>,
41    alloc: FrameBufferAllocator,
42    frame_tx: watch::Sender<Arc<Vec<u8>>>,
43    cam_tx: std::sync::mpsc::Sender<Request>,
44    cam_rx: std::sync::mpsc::Receiver<Request>,
45    configs: CameraConfiguration,
46}
47impl<'cam> CamWrapper<'cam> {
48    /// Wrap an [ActiveCamera]
49    pub fn new(
50        mut cam: ActiveCamera<'cam>,
51        mut cfgg: CameraConfiguration,
52        frame_tx: watch::Sender<Arc<Vec<u8>>>,
53    ) -> Self {
54        let alloc = FrameBufferAllocator::new(&cam);
55        cam.configure(&mut cfgg).unwrap();
56        let (cam_tx, cam_rx) = std::sync::mpsc::channel();
57        Self {
58            cam,
59            alloc,
60            cam_tx,
61            cam_rx,
62            frame_tx,
63            configs: cfgg,
64        }
65    }
66
67    /// Set up the camera and request the first frame
68    pub fn setup(&mut self) {
69        use libcamera::controls::*;
70        let stream = self.configs.get(0).unwrap();
71        let stream = stream.stream().unwrap();
72        // Allocate some buffers
73        let buffers = self
74            .alloc
75            .alloc(&stream)
76            .unwrap()
77            .into_iter()
78            .map(|buf| MemoryMappedFrameBuffer::new(buf).unwrap())
79            .collect::<Vec<_>>();
80        let reqs = buffers
81            .into_iter()
82            .enumerate()
83            .map(|(i, buf)| -> Result<Request, Box<dyn Error>> {
84                // Create the initial request
85                let mut req = self.cam.create_request(Some(i as u64)).unwrap();
86                // Set control values for the camera
87                {
88                    let ctrl = &mut req.controls_mut();
89                    // Autofocus
90                    (*ctrl).set(AfMode::Auto)?;
91                    (*ctrl).set(AfSpeed::Fast)?;
92                    //(*ctrl).set(AfRange::Full)?;
93                    // Autoexposure
94                    //(*ctrl).set(AeEnable(true))?;
95                    // TODO: make autoexposure constraint an option in the config UI
96                    // Maybe some logic to automatically set it based on lighting conditions?
97                    //(*ctrl).set(AeConstraintMode::ConstraintShadows)?;
98                    //(*ctrl).set(AeMeteringMode::MeteringCentreWeighted)?;
99                    //(*ctrl).set(FrameDuration(1000i64 / 60i64))?;
100                }
101                // Add buffer to the request
102                req.add_buffer(&stream, buf)?;
103                Ok(req)
104            })
105            .map(|x| x.unwrap())
106            .collect::<Vec<_>>();
107        let tx = self.cam_tx.clone();
108        self.cam.on_request_completed(move |req| {
109            tx.send(req).unwrap();
110        });
111        self.cam.start(None).unwrap();
112        for req in reqs {
113            self.cam.queue_request(req).unwrap();
114        }
115        //let properties::Model(_model) = self.cam.properties().get::<properties::Model>().unwrap();
116    }
117
118    /// Get a frame and request another
119    pub fn get_frame(&mut self) {
120        let stream = self.configs.get(0).unwrap().stream().unwrap();
121        let mut req = self
122            .cam_rx
123            .recv_timeout(Duration::from_millis(2000))
124            .expect("camera request failed");
125        let framebuffer: &MemoryMappedFrameBuffer<FrameBuffer> = req.buffer(&stream).unwrap();
126        let planes = framebuffer.data();
127        let y_plane = planes.get(0).unwrap();
128        let u_plane = planes.get(1).unwrap();
129        let v_plane = planes.get(2).unwrap();
130        let image = YuvPlanarImage {
131            width: 1920,
132            height: 1080,
133            y_plane,
134            u_plane,
135            v_plane,
136            y_stride: 1920,
137            u_stride: 960,
138            v_stride: 960,
139        };
140        let mut buff = vec![0u8; 6_220__800];
141        yuv420_to_rgb(
142            &image,
143            &mut buff,
144            5760,
145            YuvRange::Limited,
146            YuvStandardMatrix::Bt601,
147        )
148        .unwrap();
149        debug!("color converted. sending...");
150        self.frame_tx.send(Arc::new(buff.clone())).unwrap();
151        drop(buff);
152        req.reuse(ReuseFlag::REUSE_BUFFERS);
153        debug!("queueing another request");
154        self.cam.queue_request(req).unwrap();
155    }
156
157    /// Continously request frames until the end of time
158    pub fn run(mut self) {
159        loop {
160            self.get_frame();
161        }
162    }
163}