screencapturekit/stream/configuration/colors.rs
1//! Color and pixel format configuration
2//!
3//! Methods for configuring color space, pixel format, and background color.
4
5use crate::utils::{
6 ffi_string::{ffi_string_from_buffer, SMALL_BUFFER_SIZE},
7 four_char_code::FourCharCode,
8};
9
10const DEFAULT_ALPHA: f32 = 1.0;
11type BackgroundColor = (f32, f32, f32, f32);
12
13use super::{internal::SCStreamConfiguration, pixel_format::PixelFormat};
14
15impl SCStreamConfiguration {
16 /// Set the pixel format for captured frames
17 ///
18 /// Streams created via [`Self::new`] / [`Self::default`] are pinned to
19 /// [`PixelFormat::BGRA`] at construction time, so calling this method is
20 /// only required when you want a non-BGRA format (e.g. YUV `420v` for
21 /// video encoding, or `l10r` for HDR). Apple's runtime default for
22 /// `SCStreamConfiguration()` varies by macOS release — see
23 /// [`PixelFormat::BGRA`] for context.
24 ///
25 /// # Examples
26 ///
27 /// ```
28 /// use screencapturekit::stream::configuration::{SCStreamConfiguration, PixelFormat};
29 ///
30 /// let mut config = SCStreamConfiguration::default();
31 /// config.set_pixel_format(PixelFormat::BGRA);
32 /// ```
33 pub fn set_pixel_format(&mut self, pixel_format: PixelFormat) -> &mut Self {
34 let four_char_code: FourCharCode = pixel_format.into();
35 unsafe {
36 crate::ffi::sc_stream_configuration_set_pixel_format(
37 self.as_ptr(),
38 four_char_code.as_u32(),
39 );
40 }
41 self
42 }
43
44 /// Set the pixel format (builder pattern)
45 #[must_use]
46 pub fn with_pixel_format(mut self, pixel_format: PixelFormat) -> Self {
47 self.set_pixel_format(pixel_format);
48 self
49 }
50
51 /// Get the current pixel format
52 pub fn pixel_format(&self) -> PixelFormat {
53 unsafe {
54 let value = crate::ffi::sc_stream_configuration_get_pixel_format(self.as_ptr());
55 PixelFormat::from(value)
56 }
57 }
58
59 /// Set the background color for captured content with an explicit alpha value.
60 ///
61 /// Available on macOS 13.0+
62 pub fn set_background_color_rgba(&mut self, r: f32, g: f32, b: f32, a: f32) -> &mut Self {
63 unsafe {
64 crate::ffi::sc_stream_configuration_set_background_color(self.as_ptr(), r, g, b, a);
65 }
66 self
67 }
68
69 /// Set the background color for captured content.
70 ///
71 /// This convenience overload uses an opaque alpha channel (`1.0`).
72 pub fn set_background_color(&mut self, r: f32, g: f32, b: f32) -> &mut Self {
73 self.set_background_color_rgba(r, g, b, DEFAULT_ALPHA)
74 }
75
76 /// Set the background color with an explicit alpha value (builder pattern).
77 #[must_use]
78 pub fn with_background_color_rgba(mut self, r: f32, g: f32, b: f32, a: f32) -> Self {
79 self.set_background_color_rgba(r, g, b, a);
80 self
81 }
82
83 /// Set the background color (builder pattern).
84 ///
85 /// This convenience overload uses an opaque alpha channel (`1.0`).
86 #[must_use]
87 pub fn with_background_color(mut self, r: f32, g: f32, b: f32) -> Self {
88 self.set_background_color(r, g, b);
89 self
90 }
91
92 /// Get the current background color, if it was set through this wrapper.
93 pub fn background_color(&self) -> Option<BackgroundColor> {
94 let mut r = 0.0f32;
95 let mut g = 0.0f32;
96 let mut b = 0.0f32;
97 let mut a = 0.0f32;
98 // The value is read back from the Swift bridge's per-configuration
99 // state (keyed by object identity and released with the configuration),
100 // so there is no Rust-side cache to leak or to go stale on pointer reuse.
101 let was_set = unsafe {
102 crate::ffi::sc_stream_configuration_get_background_color(
103 self.as_ptr(),
104 &mut r,
105 &mut g,
106 &mut b,
107 &mut a,
108 )
109 };
110 was_set.then_some((r, g, b, a))
111 }
112
113 /// Set the color space name for captured content.
114 ///
115 /// Available on macOS 13.0+
116 ///
117 /// If `name` contains an interior NUL byte it cannot be converted to a C
118 /// string and the call is silently ignored (the configuration is left
119 /// unchanged). Valid color-space names never contain NUL bytes.
120 pub fn set_color_space_name(&mut self, name: &str) -> &mut Self {
121 if let Ok(c_name) = std::ffi::CString::new(name) {
122 unsafe {
123 crate::ffi::sc_stream_configuration_set_color_space_name(
124 self.as_ptr(),
125 c_name.as_ptr(),
126 );
127 }
128 }
129 self
130 }
131
132 /// Set the color space name (builder pattern).
133 #[must_use]
134 pub fn with_color_space_name(mut self, name: &str) -> Self {
135 self.set_color_space_name(name);
136 self
137 }
138
139 /// Get the color space name for captured content.
140 pub fn color_space_name(&self) -> Option<String> {
141 unsafe {
142 ffi_string_from_buffer(SMALL_BUFFER_SIZE, |buf, len| {
143 crate::ffi::sc_stream_configuration_get_color_space_name(self.as_ptr(), buf, len)
144 })
145 }
146 }
147
148 /// Set the color matrix for captured content
149 ///
150 /// Available on macOS 13.0+. The matrix should be a 3x3 array in row-major order.
151 ///
152 /// If `matrix` contains an interior NUL byte it cannot be converted to a C
153 /// string and the call is silently ignored (the configuration is left
154 /// unchanged). Valid matrix-name strings never contain NUL bytes.
155 pub fn set_color_matrix(&mut self, matrix: &str) -> &mut Self {
156 if let Ok(c_matrix) = std::ffi::CString::new(matrix) {
157 unsafe {
158 crate::ffi::sc_stream_configuration_set_color_matrix(
159 self.as_ptr(),
160 c_matrix.as_ptr(),
161 );
162 }
163 }
164 self
165 }
166
167 /// Get the color matrix for captured content.
168 ///
169 /// Returns the color matrix as a string, or `None` if not set.
170 pub fn color_matrix(&self) -> Option<String> {
171 unsafe {
172 ffi_string_from_buffer(SMALL_BUFFER_SIZE, |buf, len| {
173 crate::ffi::sc_stream_configuration_get_color_matrix(self.as_ptr(), buf, len)
174 })
175 }
176 }
177
178 /// Set the color matrix (builder pattern)
179 #[must_use]
180 pub fn with_color_matrix(mut self, matrix: &str) -> Self {
181 self.set_color_matrix(matrix);
182 self
183 }
184}