Skip to main content

capture/
capture.rs

1use std::sync::Arc;
2use std::sync::atomic::{AtomicU64, Ordering};
3use std::time::Duration;
4
5use camera_stream::device::{CameraDevice, CameraManager};
6use camera_stream::frame::{Frame, Timestamp};
7use camera_stream::stream::CameraStream;
8
9fn main() {
10    #[cfg(target_os = "macos")]
11    {
12        use camera_stream::platform::macos::device::MacosCameraManager;
13
14        let manager = MacosCameraManager::default();
15
16        // Discover devices
17        let devices: Vec<_> = manager
18            .discover_devices()
19            .expect("failed to discover devices")
20            .collect();
21        println!("Found {} camera(s):", devices.len());
22        for (i, dev) in devices.iter().enumerate() {
23            println!("  [{}] {} (id: {})", i, dev.name(), dev.id());
24        }
25
26        if devices.is_empty() {
27            println!("No cameras found.");
28            return;
29        }
30
31        // Use default device
32        let device = manager
33            .default_device()
34            .expect("failed to get default device")
35            .expect("no default camera");
36
37        println!("\nUsing: {} ({})", device.name(), device.id());
38
39        // Print supported formats
40        let formats: Vec<_> = device.supported_formats().expect("failed to get formats").collect();
41        println!("\nSupported formats ({} total):", formats.len());
42        for (i, f) in formats.iter().take(10).enumerate() {
43            println!(
44                "  [{}] {:?} {}x{} ({} frame rate range(s))",
45                i,
46                f.pixel_format,
47                f.size.width,
48                f.size.height,
49                f.frame_rate_ranges().len(),
50            );
51            for rr in f.frame_rate_ranges() {
52                println!("       {:.1}-{:.1} fps", rr.min.as_f64(), rr.max.as_f64(),);
53            }
54        }
55        if formats.len() > 10 {
56            println!("  ... and {} more", formats.len() - 10);
57        }
58
59        // Pick first format or a reasonable default
60        let config =
61            if let Some(f) = formats.first() {
62                let rate = f.frame_rate_ranges().first().map(|r| r.max).unwrap_or(
63                    camera_stream::FrameRate {
64                        numerator: 30000,
65                        denominator: 1000,
66                    },
67                );
68                camera_stream::StreamConfig {
69                    pixel_format: f.pixel_format,
70                    size: f.size,
71                    frame_rate: rate,
72                }
73            } else {
74                println!("No supported formats found.");
75                return;
76            };
77
78        println!(
79            "\nOpening with {:?} {}x{} @ {:.1} fps",
80            config.pixel_format,
81            config.size.width,
82            config.size.height,
83            config.frame_rate.as_f64(),
84        );
85
86        let mut stream = device.open(&config).expect("failed to open stream");
87
88        let frame_count = Arc::new(AtomicU64::new(0));
89        let count_clone = frame_count.clone();
90        let target_frames: u64 = 60;
91
92        stream
93            .start(move |frame| {
94                let n = count_clone.fetch_add(1, Ordering::Relaxed) + 1;
95                let planes = frame.planes();
96                let total_bytes: usize = planes.iter().map(|p| p.data.len()).sum();
97                println!(
98                    "Frame {}: {:?} {}x{} ts={:.3}s planes={} bytes={}",
99                    n,
100                    frame.pixel_format(),
101                    frame.size().width,
102                    frame.size().height,
103                    frame.timestamp().as_secs_f64(),
104                    planes.len(),
105                    total_bytes,
106                );
107            })
108            .expect("failed to start stream");
109
110        // Wait until we've captured enough frames
111        loop {
112            std::thread::sleep(Duration::from_millis(100));
113            if frame_count.load(Ordering::Relaxed) >= target_frames {
114                break;
115            }
116        }
117
118        stream.stop().expect("failed to stop stream");
119        println!(
120            "\nDone. Captured {} frames.",
121            frame_count.load(Ordering::Relaxed)
122        );
123    }
124
125    #[cfg(not(target_os = "macos"))]
126    {
127        println!("This example only works on macOS.");
128    }
129}