1use std::sync::Arc;
2
3use kinect_v2_sys::{
4 ColorImageFormat, DEFAULT_FRAME_WAIT_TIMEOUT_MS, KINECT_DEFAULT_CAPTURE_FPS, WAITABLE_HANDLE,
5 color::{ColorFrame, ColorFrameReader},
6 kinect::{self, KinectSensor},
7};
8use windows::Win32::Foundation::{E_FAIL, E_INVALIDARG, WAIT_OBJECT_0, WAIT_TIMEOUT};
9use windows::Win32::System::Threading::WaitForSingleObject;
10use windows::{Win32::Foundation::WAIT_EVENT, core::Error};
11
12pub struct ColorFrameCapture {
17 kinect: KinectSensor, format: Option<ColorImageFormat>, }
20
21impl ColorFrameCapture {
22 pub fn new() -> Result<Self, Error> {
32 let kinect = kinect::get_default_kinect_sensor()?;
33 kinect.open()?;
34
35 Ok(ColorFrameCapture {
36 kinect,
37 format: None,
38 })
39 }
40
41 pub fn new_with_format(color_image_format: ColorImageFormat) -> Result<Self, Error> {
43 let mut capture = Self::new()?;
44 capture.format = Some(color_image_format);
45 Ok(capture)
46 }
47
48 pub fn iter(&self) -> Result<ColorFrameCaptureIter, Error> {
59 let source = self.kinect.color_frame_source()?;
60 let reader = source.open_reader()?;
62 if !source.get_is_active()? {
65 log::warn!(
66 "Color frame source is not active, cannot subscribe to frame arrived event."
67 );
68 return Err(Error::from_hresult(E_FAIL));
69 }
70 let mut waitable_handle = WAITABLE_HANDLE::default();
71
72 reader.subscribe_frame_arrived(&mut waitable_handle)?;
73 Ok(ColorFrameCaptureIter {
74 reader,
75 waitable_handle,
76 timeout_ms: DEFAULT_FRAME_WAIT_TIMEOUT_MS,
77 format: self.format.clone(),
78 })
79 }
80}
81
82pub struct ColorFrameCaptureIter {
87 reader: ColorFrameReader,
88 waitable_handle: WAITABLE_HANDLE,
89 timeout_ms: u32,
90 format: Option<ColorImageFormat>,
91}
92
93impl Drop for ColorFrameCaptureIter {
94 fn drop(&mut self) {
95 if let Err(e) = self.reader.unsubscribe_frame_arrived(self.waitable_handle) {
98 log::warn!("Failed to unsubscribe color frame arrived event: {e:?}");
99 }
100 }
101}
102
103impl Iterator for ColorFrameCaptureIter {
104 type Item = Result<ColorFrameData, Error>;
105
106 fn next(&mut self) -> Option<Self::Item> {
107 loop {
108 let wait_status: WAIT_EVENT =
109 unsafe { WaitForSingleObject(self.waitable_handle, self.timeout_ms) };
110
111 if wait_status == WAIT_OBJECT_0 {
112 let result = (|| {
115 let event_args = self
116 .reader
117 .get_frame_arrived_event_data(self.waitable_handle)?;
118 let frame_reference = event_args.get_frame_reference()?;
119 let color_frame = frame_reference.acquire_frame()?;
120 ColorFrameData::new(&color_frame, self.format.clone())
121 })(); return Some(result);
123 } else if wait_status == WAIT_TIMEOUT {
124 continue;
127 } else {
128 return Some(Err(Error::from_hresult(E_FAIL)));
129 }
130 }
131 }
132}
133
134#[derive(Debug, Clone)]
135pub struct ColorFrameData {
136 pub width: u32,
137 pub height: u32,
138 pub fps: u32,
139 pub bytes_per_pixel: u32,
140 pub timestamp: u64,
141 pub image_format: ColorImageFormat,
142 pub data: Arc<[u8]>, }
144
145fn get_bytes_per_pixel_for_format(format: ColorImageFormat) -> u32 {
146 match format {
147 ColorImageFormat::Rgba | ColorImageFormat::Bgra | ColorImageFormat::Bayer => 4,
148 ColorImageFormat::Yuy2 | ColorImageFormat::Yuv => 2,
149 ColorImageFormat::None => 0,
150 }
151}
152
153impl ColorFrameData {
154 pub fn new(
155 color_frame: &ColorFrame,
156 format_opt: Option<ColorImageFormat>,
157 ) -> Result<Self, Error> {
158 let frame_description = color_frame.get_frame_description()?;
159 let width = frame_description.get_width()? as u32;
160 let height = frame_description.get_height()? as u32;
161 let bytes_per_pixel = frame_description.get_bytes_per_pixel()?;
162 let buffer_size = width * height * bytes_per_pixel;
163 let timestamp = color_frame.get_relative_time()? as u64;
164 let image_format = color_frame.get_raw_color_image_format()?;
165 if let Some(desired_format) = format_opt {
166 if image_format != desired_format {
167 let desired_bpp = get_bytes_per_pixel_for_format(desired_format.clone());
169 if desired_bpp == 0 {
170 return Err(Error::from_hresult(E_INVALIDARG));
171 }
172 let converted_buffer_size = width * height * desired_bpp;
173 let mut converted_data = vec![0u8; converted_buffer_size as usize];
174 color_frame.copy_converted_frame_data_to_array(
175 &mut converted_data,
176 desired_format.clone(),
177 )?;
178 return Ok(Self {
179 width,
180 height,
181 fps: KINECT_DEFAULT_CAPTURE_FPS,
182 bytes_per_pixel: desired_bpp,
183 timestamp,
184 image_format: desired_format,
185 data: Arc::from(converted_data), });
187 }
188 }
189
190 let mut data = Vec::with_capacity(buffer_size as usize);
191 let raw_buffer = color_frame.access_raw_underlying_buffer()?;
192 assert!(
193 raw_buffer.len() as u32 == buffer_size,
194 "Raw buffer size does not match expected size"
195 );
196 data.extend_from_slice(raw_buffer);
197
198 Ok(Self {
199 width,
200 height,
201 fps: KINECT_DEFAULT_CAPTURE_FPS,
202 bytes_per_pixel,
203 timestamp,
204 image_format,
205 data: Arc::from(data), })
207 }
208}
209
210impl Default for ColorFrameData {
211 fn default() -> Self {
212 Self {
213 width: 0,
214 height: 0,
215 fps: KINECT_DEFAULT_CAPTURE_FPS,
216 bytes_per_pixel: 0,
217 timestamp: 0,
218 image_format: ColorImageFormat::None,
219 data: Arc::new([]), }
221 }
222}
223
224#[cfg(test)]
225mod tests {
226 use std::sync::mpsc;
227
228 use anyhow::anyhow;
229
230 use super::*;
231
232 #[test]
233 fn color_capture_test() -> anyhow::Result<()> {
234 let (color_tx, color_rx) = mpsc::channel::<ColorFrameData>();
235 let max_frames_to_capture = 10;
236 let color_capture_thread = std::thread::spawn(move || -> anyhow::Result<()> {
237 let color_capture = ColorFrameCapture::new()?;
238 for (frame_count, frame) in color_capture.iter()?.enumerate() {
239 if frame_count >= max_frames_to_capture {
240 break;
241 }
242 let data = frame.map_err(|e| anyhow!("Error capturing color frame: {}", e))?;
243 if color_tx.send(data).is_err() {
244 break;
246 }
247 }
248 Ok(())
249 });
250
251 let processing_thread = std::thread::spawn(move || -> anyhow::Result<()> {
252 for _ in 0..max_frames_to_capture {
253 let frame_data = match color_rx.recv() {
254 Ok(data) => data,
255 Err(_) => break,
256 };
257 println!(
258 "Received color frame: {}x{}, {} bytes, timestamp: {}, format: {:?}, bytes_per_pixel: {}",
259 frame_data.width,
260 frame_data.height,
261 frame_data.data.len(),
262 frame_data.timestamp,
263 frame_data.image_format,
264 frame_data.bytes_per_pixel
265 );
266
267 anyhow::ensure!(
268 frame_data.width == 1920,
269 "Unexpected width: {}",
270 frame_data.width
271 );
272 anyhow::ensure!(
273 frame_data.height == 1080,
274 "Unexpected height: {}",
275 frame_data.height
276 );
277 anyhow::ensure!(
278 [2, 4].contains(&frame_data.bytes_per_pixel),
279 "Unexpected bytes_per_pixel: {}",
280 frame_data.bytes_per_pixel
281 );
282 anyhow::ensure!(!frame_data.data.is_empty(), "Frame data is empty");
283 anyhow::ensure!(frame_data.timestamp > 0, "Timestamp is not positive");
284 anyhow::ensure!(
285 frame_data.fps == KINECT_DEFAULT_CAPTURE_FPS,
286 "Unexpected FPS: {}",
287 frame_data.fps
288 );
289 }
290 Ok(())
291 });
292
293 color_capture_thread
294 .join()
295 .map_err(|e| anyhow!("Color capture thread join error: {:?}", e))??;
296 processing_thread
297 .join()
298 .map_err(|e| anyhow!("Processing thread join error: {:?}", e))??;
299
300 Ok(())
301 }
302}