Skip to content

Commit 197d2b9

Browse files
committed
work on instant mode
1 parent f863d76 commit 197d2b9

File tree

9 files changed

+790
-686
lines changed

9 files changed

+790
-686
lines changed
Lines changed: 169 additions & 163 deletions
Original file line numberDiff line numberDiff line change
@@ -1,194 +1,200 @@
1-
#![cfg(target_os = "macos")]
2-
3-
use cap_camera_avfoundation::{
4-
CallbackOutputDelegate, CallbackOutputDelegateInner, YCbCrMatrix, list_video_devices,
5-
};
6-
use cidre::*;
7-
use clap::{Parser, Subcommand};
8-
use inquire::Select;
9-
use std::{fmt::Display, ops::Deref};
10-
11-
#[derive(Parser)]
12-
struct Cli {
13-
#[command(subcommand)]
14-
command: Commands,
1+
fn main() {
2+
#[cfg(target_os = "macos")]
3+
macos::main();
154
}
165

17-
#[derive(Subcommand)]
18-
enum Commands {
19-
/// Print details of a device
20-
Device,
21-
}
6+
#[cfg(target_os = "macos")]
7+
mod macos {
8+
use cap_camera_avfoundation::{
9+
CallbackOutputDelegate, CallbackOutputDelegateInner, YCbCrMatrix, list_video_devices,
10+
};
11+
use cidre::*;
12+
use clap::{Parser, Subcommand};
13+
use inquire::Select;
14+
use std::{fmt::Display, ops::Deref};
15+
16+
#[derive(Parser)]
17+
struct Cli {
18+
#[command(subcommand)]
19+
command: Commands,
20+
}
2221

23-
pub fn main() {
24-
let _devices = list_video_devices();
25-
let devices = _devices
26-
.iter()
27-
.enumerate()
28-
.map(|(i, v)| CaptureDeviceSelectOption(v, i))
29-
.collect::<Vec<_>>();
30-
31-
let selected = Select::new("Select a device", devices).prompt().unwrap();
32-
let mut selected_device = _devices.get(selected.1).unwrap();
33-
34-
println!("Info for device '{}'", selected_device.localized_name());
35-
36-
let formats = selected_device.formats();
37-
38-
let mut _formats = vec![];
39-
40-
for (i, format) in formats.iter().enumerate() {
41-
let desc = format.format_desc();
42-
43-
let color_space = desc
44-
.ext(cm::FormatDescExtKey::ycbcr_matrix())
45-
.map(|v| {
46-
v.try_as_string()
47-
.and_then(|v| YCbCrMatrix::try_from(v).ok())
48-
})
49-
.unwrap_or(Some(YCbCrMatrix::Rec601));
50-
51-
let fr_ranges = format.video_supported_frame_rate_ranges();
52-
53-
for fr_range in fr_ranges.iter() {
54-
_formats.push(Format {
55-
index: i,
56-
width: desc.dims().width,
57-
height: desc.dims().height,
58-
fourcc: desc.media_sub_type(),
59-
color_space,
60-
max_frame_rate: (
61-
fr_range.min_frame_duration().value,
62-
fr_range.min_frame_duration().scale,
63-
),
64-
});
65-
}
22+
#[derive(Subcommand)]
23+
enum Commands {
24+
/// Print details of a device
25+
Device,
6626
}
6727

68-
let selected_format = if _formats.len() > 1 {
69-
inquire::Select::new("Select a format", _formats)
70-
.prompt()
71-
.unwrap()
72-
} else {
73-
_formats.remove(0)
74-
};
28+
pub fn main() {
29+
let _devices = list_video_devices();
30+
let devices = _devices
31+
.iter()
32+
.enumerate()
33+
.map(|(i, v)| CaptureDeviceSelectOption(v, i))
34+
.collect::<Vec<_>>();
35+
36+
let selected = Select::new("Select a device", devices).prompt().unwrap();
37+
let mut selected_device = _devices.get(selected.1).unwrap();
38+
39+
println!("Info for device '{}'", selected_device.localized_name());
40+
41+
let formats = selected_device.formats();
42+
43+
let mut _formats = vec![];
44+
45+
for (i, format) in formats.iter().enumerate() {
46+
let desc = format.format_desc();
47+
48+
let color_space = desc
49+
.ext(cm::FormatDescExtKey::ycbcr_matrix())
50+
.map(|v| {
51+
v.try_as_string()
52+
.and_then(|v| YCbCrMatrix::try_from(v).ok())
53+
})
54+
.unwrap_or(Some(YCbCrMatrix::Rec601));
55+
56+
let fr_ranges = format.video_supported_frame_rate_ranges();
57+
58+
for fr_range in fr_ranges.iter() {
59+
_formats.push(Format {
60+
index: i,
61+
width: desc.dims().width,
62+
height: desc.dims().height,
63+
fourcc: desc.media_sub_type(),
64+
color_space,
65+
max_frame_rate: (
66+
fr_range.min_frame_duration().value,
67+
fr_range.min_frame_duration().scale,
68+
),
69+
});
70+
}
71+
}
7572

76-
let input = av::capture::DeviceInput::with_device(&selected_device).unwrap();
77-
let queue = dispatch::Queue::new();
78-
let delegate =
79-
CallbackOutputDelegate::with(CallbackOutputDelegateInner::new(Box::new(|data| {
80-
let Some(image_buf) = data.sample_buf.image_buf() else {
81-
return;
82-
};
83-
84-
let total_bytes = if image_buf.plane_count() > 0 {
85-
(0..image_buf.plane_count())
86-
.map(|i| image_buf.plane_bytes_per_row(i) * image_buf.plane_height(i))
87-
.sum::<usize>()
73+
let selected_format = if _formats.len() > 1 {
74+
inquire::Select::new("Select a format", _formats)
75+
.prompt()
76+
.unwrap()
77+
} else {
78+
_formats.remove(0)
79+
};
80+
81+
let input = av::capture::DeviceInput::with_device(&selected_device).unwrap();
82+
let queue = dispatch::Queue::new();
83+
let delegate =
84+
CallbackOutputDelegate::with(CallbackOutputDelegateInner::new(Box::new(|data| {
85+
let Some(image_buf) = data.sample_buf.image_buf() else {
86+
return;
87+
};
88+
89+
let total_bytes = if image_buf.plane_count() > 0 {
90+
(0..image_buf.plane_count())
91+
.map(|i| image_buf.plane_bytes_per_row(i) * image_buf.plane_height(i))
92+
.sum::<usize>()
93+
} else {
94+
image_buf.plane_bytes_per_row(0) * image_buf.plane_height(0)
95+
};
96+
97+
let mut format = image_buf.pixel_format().0.to_be_bytes();
98+
let format_fourcc = four_cc_to_str(&mut format);
99+
100+
println!(
101+
"New frame: {}x{}, {:.2}pts, {total_bytes} bytes, format={format_fourcc}",
102+
image_buf.width(),
103+
image_buf.height(),
104+
data.sample_buf.pts().value as f64 / data.sample_buf.pts().scale as f64,
105+
)
106+
})));
107+
108+
let mut output = av::capture::VideoDataOutput::new();
109+
110+
let mut session = av::capture::Session::new();
111+
112+
session.configure(|s| {
113+
if s.can_add_input(&input) {
114+
s.add_input(&input);
88115
} else {
89-
image_buf.plane_bytes_per_row(0) * image_buf.plane_height(0)
90-
};
116+
panic!("can't add input");
117+
}
91118

92-
let mut format = image_buf.pixel_format().0.to_be_bytes();
93-
let format_fourcc = four_cc_to_str(&mut format);
119+
s.add_output(&output);
94120

95-
println!(
96-
"New frame: {}x{}, {:.2}pts, {total_bytes} bytes, format={format_fourcc}",
97-
image_buf.width(),
98-
image_buf.height(),
99-
data.sample_buf.pts().value as f64 / data.sample_buf.pts().scale as f64,
100-
)
101-
})));
102-
103-
let mut output = av::capture::VideoDataOutput::new();
121+
let mut _lock = selected_device.config_lock().unwrap();
104122

105-
let mut session = av::capture::Session::new();
123+
_lock.set_active_format(&formats[selected_format.index]);
124+
});
106125

107-
session.configure(|s| {
108-
if s.can_add_input(&input) {
109-
s.add_input(&input);
110-
} else {
111-
panic!("can't add input");
112-
}
126+
output.set_sample_buf_delegate(Some(delegate.as_ref()), Some(&queue));
113127

114-
s.add_output(&output);
128+
let video_settings = ns::Dictionary::with_keys_values(
129+
&[cv::pixel_buffer_keys::pixel_format().as_ns()],
130+
&[ns::Number::with_u32(selected_format.fourcc).as_id_ref()],
131+
);
132+
output
133+
.set_video_settings(Some(video_settings.as_ref()))
134+
.unwrap();
115135

116-
let mut _lock = selected_device.config_lock().unwrap();
136+
// The device config must stay locked while running starts,
137+
// otherwise start_running can overwrite the active format on macOS
138+
// https://stackoverflow.com/questions/36689578/avfoundation-capturing-video-with-custom-resolution
139+
{
140+
let mut _lock = selected_device.config_lock().unwrap();
117141

118-
_lock.set_active_format(&formats[selected_format.index]);
119-
});
142+
_lock.set_active_format(&formats[selected_format.index]);
120143

121-
output.set_sample_buf_delegate(Some(delegate.as_ref()), Some(&queue));
122-
123-
let video_settings = ns::Dictionary::with_keys_values(
124-
&[cv::pixel_buffer_keys::pixel_format().as_ns()],
125-
&[ns::Number::with_u32(selected_format.fourcc).as_id_ref()],
126-
);
127-
output
128-
.set_video_settings(Some(video_settings.as_ref()))
129-
.unwrap();
144+
session.start_running();
145+
}
130146

131-
// The device config must stay locked while running starts,
132-
// otherwise start_running can overwrite the active format on macOS
133-
// https://stackoverflow.com/questions/36689578/avfoundation-capturing-video-with-custom-resolution
134-
{
135-
let mut _lock = selected_device.config_lock().unwrap();
147+
std::thread::sleep(std::time::Duration::from_secs(10));
136148

137-
_lock.set_active_format(&formats[selected_format.index]);
149+
session.stop_running();
138150

139-
session.start_running();
151+
std::thread::sleep(std::time::Duration::from_secs(10));
140152
}
141153

142-
std::thread::sleep(std::time::Duration::from_secs(10));
143-
144-
session.stop_running();
145-
146-
std::thread::sleep(std::time::Duration::from_secs(10));
147-
}
148-
149-
struct Format {
150-
index: usize,
151-
width: i32,
152-
height: i32,
153-
fourcc: FourCharCode,
154-
#[allow(unused)]
155-
color_space: Option<YCbCrMatrix>,
156-
max_frame_rate: (i64, i32),
157-
}
154+
struct Format {
155+
index: usize,
156+
width: i32,
157+
height: i32,
158+
fourcc: FourCharCode,
159+
#[allow(unused)]
160+
color_space: Option<YCbCrMatrix>,
161+
max_frame_rate: (i64, i32),
162+
}
158163

159-
impl Display for Format {
160-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
161-
write!(
162-
f,
163-
"{}x{}, {} max fps ({}/{}) {}",
164-
self.width,
165-
self.height,
166-
self.max_frame_rate.1 as f32 / self.max_frame_rate.0 as f32,
167-
self.max_frame_rate.0,
168-
self.max_frame_rate.1,
169-
four_cc_to_string(self.fourcc.to_be_bytes())
170-
)
164+
impl Display for Format {
165+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
166+
write!(
167+
f,
168+
"{}x{}, {} max fps ({}/{}) {}",
169+
self.width,
170+
self.height,
171+
self.max_frame_rate.1 as f32 / self.max_frame_rate.0 as f32,
172+
self.max_frame_rate.0,
173+
self.max_frame_rate.1,
174+
four_cc_to_string(self.fourcc.to_be_bytes())
175+
)
176+
}
171177
}
172-
}
173178

174-
struct CaptureDeviceSelectOption<'a>(&'a av::CaptureDevice, usize);
179+
struct CaptureDeviceSelectOption<'a>(&'a av::CaptureDevice, usize);
175180

176-
impl<'a> Display for CaptureDeviceSelectOption<'a> {
177-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
178-
write!(f, "{} ({})", self.0.localized_name(), self.0.unique_id())
181+
impl<'a> Display for CaptureDeviceSelectOption<'a> {
182+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
183+
write!(f, "{} ({})", self.0.localized_name(), self.0.unique_id())
184+
}
179185
}
180-
}
181186

182-
impl AsRef<av::CaptureDevice> for CaptureDeviceSelectOption<'_> {
183-
fn as_ref(&self) -> &av::CaptureDevice {
184-
self.0
187+
impl AsRef<av::CaptureDevice> for CaptureDeviceSelectOption<'_> {
188+
fn as_ref(&self) -> &av::CaptureDevice {
189+
self.0
190+
}
185191
}
186-
}
187192

188-
impl Deref for CaptureDeviceSelectOption<'_> {
189-
type Target = av::CaptureDevice;
193+
impl Deref for CaptureDeviceSelectOption<'_> {
194+
type Target = av::CaptureDevice;
190195

191-
fn deref(&self) -> &Self::Target {
192-
self.0
196+
fn deref(&self) -> &Self::Target {
197+
self.0
198+
}
193199
}
194200
}

0 commit comments

Comments
 (0)