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 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 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 let formats: Vec<_> = device
41 .supported_formats()
42 .expect("failed to get formats")
43 .collect();
44 println!("\nSupported formats ({} total):", formats.len());
45 for (i, f) in formats.iter().take(10).enumerate() {
46 println!(
47 " [{}] {:?} {}x{} ({} frame rate range(s))",
48 i,
49 f.pixel_format,
50 f.size.width,
51 f.size.height,
52 f.frame_rate_ranges().len(),
53 );
54 for rr in f.frame_rate_ranges() {
55 println!(" {:.1}-{:.1} fps", rr.min.as_f64(), rr.max.as_f64(),);
56 }
57 }
58 if formats.len() > 10 {
59 println!(" ... and {} more", formats.len() - 10);
60 }
61
62 let config = if let Some(f) = formats.first() {
64 let rate =
65 f.frame_rate_ranges()
66 .first()
67 .map(|r| r.max)
68 .unwrap_or(camera_stream::Ratio {
69 numerator: 30000,
70 denominator: 1000,
71 });
72 camera_stream::StreamConfig {
73 pixel_format: f.pixel_format,
74 size: f.size,
75 frame_rate: rate,
76 }
77 } else {
78 println!("No supported formats found.");
79 return;
80 };
81
82 println!(
83 "\nOpening with {:?} {}x{} @ {:.1} fps",
84 config.pixel_format,
85 config.size.width,
86 config.size.height,
87 config.frame_rate.as_f64(),
88 );
89
90 let mut stream = device.open(&config).expect("failed to open stream");
91
92 let frame_count = Arc::new(AtomicU64::new(0));
93 let count_clone = frame_count.clone();
94 let target_frames: u64 = 60;
95
96 stream
97 .start(move |frame| {
98 let n = count_clone.fetch_add(1, Ordering::Relaxed) + 1;
99 let planes = frame.planes();
100 let total_bytes: usize = planes.iter().map(|p| p.data.len()).sum();
101 println!(
102 "Frame {}: {:?} {}x{} ts={:.3}s planes={} bytes={}",
103 n,
104 frame.pixel_format(),
105 frame.size().width,
106 frame.size().height,
107 frame.timestamp().as_secs_f64(),
108 planes.len(),
109 total_bytes,
110 );
111 })
112 .expect("failed to start stream");
113
114 loop {
116 std::thread::sleep(Duration::from_millis(100));
117 if frame_count.load(Ordering::Relaxed) >= target_frames {
118 break;
119 }
120 }
121
122 stream.stop().expect("failed to stop stream");
123 println!(
124 "\nDone. Captured {} frames.",
125 frame_count.load(Ordering::Relaxed)
126 );
127 }
128
129 #[cfg(not(target_os = "macos"))]
130 {
131 println!("This example only works on macOS.");
132 }
133}