kinect_v2_sys/
infrared.rs

1use crate::bindings::{
2    BOOLEAN, IFrameCapturedEventArgs, IFrameDescription, IInfraredFrame,
3    IInfraredFrameArrivedEventArgs, IInfraredFrameReader, IInfraredFrameReference,
4    IInfraredFrameSource, IKinectSensor, TIMESPAN, UINT, UINT16, WAITABLE_HANDLE,
5};
6use crate::frame::{FrameCapturedEventArgs, FrameDescription};
7use crate::kinect::KinectSensor;
8use std::ptr;
9use windows::Win32::Foundation::{E_FAIL, E_POINTER};
10use windows::core::Error;
11
12/// InfraredFrame represents a single frame of infrared data.
13pub struct InfraredFrame {
14    ptr: *mut IInfraredFrame,
15}
16
17impl InfraredFrame {
18    pub(crate) fn new(ptr: *mut IInfraredFrame) -> Self {
19        assert!(!ptr.is_null());
20        Self { ptr }
21    }
22    pub fn copy_frame_data_to_array(&self, frame_data: &mut [u16]) -> Result<(), Error> {
23        if self.ptr.is_null() {
24            return Err(Error::from(E_POINTER));
25        }
26        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
27        let copy_data_fn = vtbl
28            .CopyFrameDataToArray
29            .ok_or_else(|| Error::from(E_FAIL))?;
30        let capacity = frame_data.len() as UINT;
31        let hr = unsafe { copy_data_fn(self.ptr, capacity, frame_data.as_mut_ptr()) };
32        if hr.is_err() {
33            Err(Error::from_hresult(hr))
34        } else {
35            Ok(())
36        }
37    }
38    pub fn access_underlying_buffer(&self) -> Result<&[u16], Error> {
39        if self.ptr.is_null() {
40            return Err(Error::from(E_POINTER));
41        }
42        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
43        let access_buffer_fn = vtbl
44            .AccessUnderlyingBuffer
45            .ok_or_else(|| Error::from(E_FAIL))?;
46        let mut capacity: UINT = 0;
47        let mut buffer: *mut UINT16 = ptr::null_mut();
48        let hr = unsafe { access_buffer_fn(self.ptr, &mut capacity, &mut buffer) };
49        if hr.is_err() {
50            Err(Error::from_hresult(hr))
51        } else if buffer.is_null() || capacity == 0 {
52            Err(Error::from(E_POINTER))
53        } else {
54            // Create a safe slice from the raw pointer
55            let slice =
56                unsafe { std::slice::from_raw_parts(buffer as *const u16, capacity as usize) };
57            Ok(slice)
58        }
59    }
60
61    pub fn get_frame_description(&self) -> Result<FrameDescription, Error> {
62        if self.ptr.is_null() {
63            return Err(Error::from(E_POINTER));
64        }
65        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
66        let get_description_fn = vtbl
67            .get_FrameDescription
68            .ok_or_else(|| Error::from(E_FAIL))?;
69        let mut frame_description_ptr: *mut IFrameDescription = ptr::null_mut();
70        let hr = unsafe { get_description_fn(self.ptr, &mut frame_description_ptr) };
71        if hr.is_err() {
72            Err(Error::from_hresult(hr))
73        } else {
74            Ok(FrameDescription::new(frame_description_ptr))
75        }
76    }
77
78    pub fn get_relative_time(&self) -> Result<TIMESPAN, Error> {
79        if self.ptr.is_null() {
80            return Err(Error::from(E_POINTER));
81        }
82        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
83        let get_time_fn = vtbl.get_RelativeTime.ok_or_else(|| Error::from(E_FAIL))?;
84        let mut relative_time: TIMESPAN = 0;
85        let hr = unsafe { get_time_fn(self.ptr, &mut relative_time) };
86        if hr.is_err() {
87            Err(Error::from_hresult(hr))
88        } else {
89            Ok(relative_time)
90        }
91    }
92
93    pub fn get_infrared_frame_source(&self) -> Result<InfraredFrameSource, Error> {
94        if self.ptr.is_null() {
95            return Err(Error::from(E_POINTER));
96        }
97        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
98        let get_source_fn = vtbl
99            .get_InfraredFrameSource
100            .ok_or_else(|| Error::from(E_FAIL))?;
101        let mut infrared_frame_source_ptr: *mut IInfraredFrameSource = ptr::null_mut();
102        let hr = unsafe { get_source_fn(self.ptr, &mut infrared_frame_source_ptr) };
103        if hr.is_err() {
104            Err(Error::from_hresult(hr))
105        } else if infrared_frame_source_ptr.is_null() {
106            Err(Error::from(E_POINTER))
107        } else {
108            Ok(InfraredFrameSource::new(infrared_frame_source_ptr))
109        }
110    }
111}
112
113impl Drop for InfraredFrame {
114    fn drop(&mut self) {
115        if !self.ptr.is_null() {
116            unsafe {
117                if let Some(vtbl) = (*self.ptr).lpVtbl.as_ref()
118                    && let Some(release_fn) = vtbl.Release
119                {
120                    release_fn(self.ptr);
121                }
122            }
123            self.ptr = ptr::null_mut();
124        }
125    }
126}
127
128pub struct InfraredFrameSource {
129    ptr: *mut IInfraredFrameSource,
130}
131impl InfraredFrameSource {
132    pub(crate) fn new(ptr: *mut IInfraredFrameSource) -> Self {
133        assert!(!ptr.is_null());
134        Self { ptr }
135    }
136
137    pub fn subscribe_frame_captured(&self) -> Result<WAITABLE_HANDLE, Error> {
138        if self.ptr.is_null() {
139            return Err(Error::from(E_POINTER));
140        }
141        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
142        let subscribe_fn = vtbl
143            .SubscribeFrameCaptured
144            .ok_or_else(|| Error::from(E_FAIL))?;
145        let mut waitable_handle: WAITABLE_HANDLE = windows::Win32::Foundation::HANDLE::default();
146        let hr = unsafe { subscribe_fn(self.ptr, &mut waitable_handle) };
147        if hr.is_err() {
148            Err(Error::from_hresult(hr))
149        } else {
150            Ok(waitable_handle)
151        }
152    }
153
154    pub fn unsubscribe_frame_captured(
155        &self,
156        waitable_handle: WAITABLE_HANDLE,
157    ) -> Result<(), Error> {
158        if self.ptr.is_null() {
159            return Err(Error::from(E_POINTER));
160        }
161        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
162        let unsubscribe_fn = vtbl
163            .UnsubscribeFrameCaptured
164            .ok_or_else(|| Error::from(E_FAIL))?;
165        let hr = unsafe { unsubscribe_fn(self.ptr, waitable_handle) };
166        if hr.is_err() {
167            Err(Error::from_hresult(hr))
168        } else {
169            Ok(())
170        }
171    }
172
173    pub fn get_frame_captured_event_data(
174        &self,
175        waitable_handle: WAITABLE_HANDLE,
176    ) -> Result<FrameCapturedEventArgs, Error> {
177        if self.ptr.is_null() {
178            return Err(Error::from(E_POINTER));
179        }
180        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
181        let get_data_fn = vtbl
182            .GetFrameCapturedEventData
183            .ok_or_else(|| Error::from(E_FAIL))?;
184        let mut event_args_ptr: *mut IFrameCapturedEventArgs = ptr::null_mut();
185        let hr = unsafe { get_data_fn(self.ptr, waitable_handle, &mut event_args_ptr) };
186        if hr.is_err() {
187            Err(Error::from_hresult(hr))
188        } else {
189            Ok(FrameCapturedEventArgs::new(event_args_ptr))
190        }
191    }
192
193    pub fn get_is_active(&self) -> Result<bool, Error> {
194        if self.ptr.is_null() {
195            return Err(Error::from(E_POINTER));
196        }
197        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
198        let get_active_fn = vtbl.get_IsActive.ok_or_else(|| Error::from(E_FAIL))?;
199        let mut is_active: BOOLEAN = 0;
200        let hr = unsafe { get_active_fn(self.ptr, &mut is_active) };
201        if hr.is_err() {
202            Err(Error::from_hresult(hr))
203        } else {
204            Ok(is_active != 0)
205        }
206    }
207
208    pub fn open_reader(&self) -> Result<InfraredFrameReader, Error> {
209        if self.ptr.is_null() {
210            return Err(Error::from(E_POINTER));
211        }
212        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
213        let open_reader_fn = vtbl.OpenReader.ok_or_else(|| Error::from(E_FAIL))?;
214        let mut reader_ptr: *mut IInfraredFrameReader = ptr::null_mut();
215        let hr = unsafe { open_reader_fn(self.ptr, &mut reader_ptr) };
216        if hr.is_err() {
217            Err(Error::from_hresult(hr))
218        } else if reader_ptr.is_null() {
219            Err(Error::from(E_POINTER))
220        } else {
221            Ok(InfraredFrameReader::new(reader_ptr))
222        }
223    }
224
225    pub fn get_frame_description(&self) -> Result<FrameDescription, Error> {
226        if self.ptr.is_null() {
227            return Err(Error::from(E_POINTER));
228        }
229        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
230        let get_description_fn = vtbl
231            .get_FrameDescription
232            .ok_or_else(|| Error::from(E_FAIL))?;
233        let mut frame_description_ptr: *mut IFrameDescription = ptr::null_mut();
234        let hr = unsafe { get_description_fn(self.ptr, &mut frame_description_ptr) };
235        if hr.is_err() {
236            Err(Error::from_hresult(hr))
237        } else {
238            Ok(FrameDescription::new(frame_description_ptr))
239        }
240    }
241
242    pub fn get_kinect_sensor(&self) -> Result<KinectSensor, Error> {
243        if self.ptr.is_null() {
244            return Err(Error::from(E_POINTER));
245        }
246        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
247        let get_sensor_fn = vtbl.get_KinectSensor.ok_or_else(|| Error::from(E_FAIL))?;
248        let mut sensor: *mut IKinectSensor = ptr::null_mut();
249        let hr = unsafe { get_sensor_fn(self.ptr, &mut sensor) };
250        if hr.is_err() {
251            Err(Error::from_hresult(hr))
252        } else {
253            Ok(KinectSensor::new(sensor))
254        }
255    }
256}
257
258impl Drop for InfraredFrameSource {
259    fn drop(&mut self) {
260        if !self.ptr.is_null() {
261            unsafe {
262                if let Some(vtbl) = (*self.ptr).lpVtbl.as_ref()
263                    && let Some(release_fn) = vtbl.Release
264                {
265                    release_fn(self.ptr);
266                }
267            }
268            self.ptr = ptr::null_mut();
269        }
270    }
271}
272
273pub struct InfraredFrameReader {
274    ptr: *mut IInfraredFrameReader,
275}
276
277impl InfraredFrameReader {
278    pub(crate) fn new(ptr: *mut IInfraredFrameReader) -> Self {
279        assert!(!ptr.is_null());
280        Self { ptr }
281    }
282
283    pub fn subscribe_frame_arrived(&self) -> Result<WAITABLE_HANDLE, Error> {
284        if self.ptr.is_null() {
285            return Err(Error::from(E_POINTER));
286        }
287        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
288        let subscribe_fn = vtbl
289            .SubscribeFrameArrived
290            .ok_or_else(|| Error::from(E_FAIL))?;
291        let mut waitable_handle: WAITABLE_HANDLE = windows::Win32::Foundation::HANDLE::default();
292        let hr = unsafe { subscribe_fn(self.ptr, &mut waitable_handle) };
293        if hr.is_err() {
294            Err(Error::from_hresult(hr))
295        } else {
296            Ok(waitable_handle)
297        }
298    }
299
300    pub fn unsubscribe_frame_arrived(&self, waitable_handle: WAITABLE_HANDLE) -> Result<(), Error> {
301        if self.ptr.is_null() {
302            return Err(Error::from(E_POINTER));
303        }
304        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
305        let unsubscribe_fn = vtbl
306            .UnsubscribeFrameArrived
307            .ok_or_else(|| Error::from(E_FAIL))?;
308        let hr = unsafe { unsubscribe_fn(self.ptr, waitable_handle) };
309        if hr.is_err() {
310            Err(Error::from_hresult(hr))
311        } else {
312            Ok(())
313        }
314    }
315    pub fn get_frame_arrived_event_data(
316        &self,
317        waitable_handle: WAITABLE_HANDLE,
318    ) -> Result<InfraredFrameArrivedEventArgs, Error> {
319        if self.ptr.is_null() {
320            return Err(Error::from(E_POINTER));
321        }
322        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
323        let get_data_fn = vtbl
324            .GetFrameArrivedEventData
325            .ok_or_else(|| Error::from(E_FAIL))?;
326        let mut event_data: *mut IInfraredFrameArrivedEventArgs = ptr::null_mut();
327        let hr = unsafe { get_data_fn(self.ptr, waitable_handle, &mut event_data) };
328        if hr.is_err() {
329            Err(Error::from_hresult(hr))
330        } else if event_data.is_null() {
331            Err(Error::from(E_POINTER))
332        } else {
333            Ok(InfraredFrameArrivedEventArgs::new(event_data))
334        }
335    }
336
337    pub fn acquire_latest_frame(&self) -> Result<InfraredFrame, Error> {
338        if self.ptr.is_null() {
339            return Err(Error::from(E_POINTER));
340        }
341        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
342        let acquire_fn = vtbl.AcquireLatestFrame.ok_or_else(|| Error::from(E_FAIL))?;
343        let mut frame_ptr: *mut IInfraredFrame = ptr::null_mut();
344        let hr = unsafe { acquire_fn(self.ptr, &mut frame_ptr) };
345        if hr.is_err() {
346            Err(Error::from_hresult(hr))
347        } else if frame_ptr.is_null() {
348            Err(Error::from(E_POINTER))
349        } else {
350            Ok(InfraredFrame::new(frame_ptr))
351        }
352    }
353
354    pub fn get_is_paused(&self) -> Result<bool, Error> {
355        if self.ptr.is_null() {
356            return Err(Error::from(E_POINTER));
357        }
358        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
359        let get_paused_fn = vtbl.get_IsPaused.ok_or_else(|| Error::from(E_FAIL))?;
360        let mut is_paused: BOOLEAN = 0;
361        let hr = unsafe { get_paused_fn(self.ptr, &mut is_paused) };
362        if hr.is_err() {
363            Err(Error::from_hresult(hr))
364        } else {
365            Ok(is_paused != 0)
366        }
367    }
368
369    pub fn put_is_paused(&self, is_paused: bool) -> Result<(), Error> {
370        if self.ptr.is_null() {
371            return Err(Error::from(E_POINTER));
372        }
373        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
374        let put_paused_fn = vtbl.put_IsPaused.ok_or_else(|| Error::from(E_FAIL))?;
375        let paused_value: BOOLEAN = if is_paused { 1 } else { 0 };
376        let hr = unsafe { put_paused_fn(self.ptr, paused_value) };
377        if hr.is_err() {
378            Err(Error::from_hresult(hr))
379        } else {
380            Ok(())
381        }
382    }
383
384    pub fn get_infrared_frame_source(&self) -> Result<InfraredFrameSource, Error> {
385        if self.ptr.is_null() {
386            return Err(Error::from(E_POINTER));
387        }
388        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
389        let get_source_fn = vtbl
390            .get_InfraredFrameSource
391            .ok_or_else(|| Error::from(E_FAIL))?;
392        let mut source_ptr: *mut IInfraredFrameSource = ptr::null_mut();
393        let hr = unsafe { get_source_fn(self.ptr, &mut source_ptr) };
394        if hr.is_err() {
395            Err(Error::from_hresult(hr))
396        } else if source_ptr.is_null() {
397            Err(Error::from(E_POINTER))
398        } else {
399            Ok(InfraredFrameSource::new(source_ptr))
400        }
401    }
402}
403
404impl Drop for InfraredFrameReader {
405    fn drop(&mut self) {
406        if !self.ptr.is_null() {
407            unsafe {
408                if let Some(vtbl) = (*self.ptr).lpVtbl.as_ref()
409                    && let Some(release_fn) = vtbl.Release
410                {
411                    release_fn(self.ptr);
412                }
413            }
414            self.ptr = ptr::null_mut();
415        }
416    }
417}
418
419pub struct InfraredFrameReference {
420    ptr: *mut IInfraredFrameReference,
421}
422
423impl InfraredFrameReference {
424    pub(crate) fn new(ptr: *mut IInfraredFrameReference) -> Self {
425        assert!(!ptr.is_null());
426        Self { ptr }
427    }
428
429    pub fn acquire_frame(&self) -> Result<InfraredFrame, Error> {
430        if self.ptr.is_null() {
431            return Err(Error::from(E_POINTER));
432        }
433        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
434        let acquire_frame_fn = vtbl.AcquireFrame.ok_or_else(|| Error::from(E_FAIL))?;
435        let mut frame_ptr: *mut IInfraredFrame = ptr::null_mut();
436        let hr = unsafe { acquire_frame_fn(self.ptr, &mut frame_ptr) };
437        if hr.is_err() {
438            Err(Error::from_hresult(hr))
439        } else if frame_ptr.is_null() {
440            Err(Error::from(E_POINTER))
441        } else {
442            Ok(InfraredFrame::new(frame_ptr))
443        }
444    }
445
446    pub fn get_relative_time(&self) -> Result<TIMESPAN, Error> {
447        if self.ptr.is_null() {
448            return Err(Error::from(E_POINTER));
449        }
450        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
451        let get_time_fn = vtbl.get_RelativeTime.ok_or_else(|| Error::from(E_FAIL))?;
452        let mut relative_time: TIMESPAN = 0;
453        let hr = unsafe { get_time_fn(self.ptr, &mut relative_time) };
454        if hr.is_err() {
455            Err(Error::from_hresult(hr))
456        } else {
457            Ok(relative_time)
458        }
459    }
460}
461
462impl Drop for InfraredFrameReference {
463    fn drop(&mut self) {
464        if !self.ptr.is_null() {
465            unsafe {
466                if let Some(vtbl) = (*self.ptr).lpVtbl.as_ref()
467                    && let Some(release_fn) = vtbl.Release
468                {
469                    release_fn(self.ptr);
470                }
471            }
472            self.ptr = ptr::null_mut();
473        }
474    }
475}
476
477pub struct InfraredFrameArrivedEventArgs {
478    ptr: *mut IInfraredFrameArrivedEventArgs,
479}
480
481impl InfraredFrameArrivedEventArgs {
482    pub(crate) fn new(ptr: *mut IInfraredFrameArrivedEventArgs) -> Self {
483        assert!(!ptr.is_null());
484        Self { ptr }
485    }
486
487    pub fn get_frame_reference(&self) -> Result<InfraredFrameReference, Error> {
488        if self.ptr.is_null() {
489            return Err(Error::from(E_POINTER));
490        }
491        let vtbl = unsafe { (*self.ptr).lpVtbl.as_ref() }.ok_or_else(|| Error::from(E_POINTER))?;
492        let get_frame_reference_fn = vtbl.get_FrameReference.ok_or_else(|| Error::from(E_FAIL))?;
493        let mut frame_reference_ptr: *mut IInfraredFrameReference = ptr::null_mut();
494        let hr = unsafe { get_frame_reference_fn(self.ptr, &mut frame_reference_ptr) };
495        if hr.is_err() {
496            Err(Error::from_hresult(hr))
497        } else if frame_reference_ptr.is_null() {
498            Err(Error::from(E_POINTER))
499        } else {
500            Ok(InfraredFrameReference::new(frame_reference_ptr))
501        }
502    }
503}
504
505impl Drop for InfraredFrameArrivedEventArgs {
506    fn drop(&mut self) {
507        if !self.ptr.is_null() {
508            unsafe {
509                if let Some(vtbl) = (*self.ptr).lpVtbl.as_ref()
510                    && let Some(release_fn) = vtbl.Release
511                {
512                    release_fn(self.ptr);
513                }
514            }
515            self.ptr = ptr::null_mut();
516        }
517    }
518}
519
520// tests
521#[cfg(test)]
522mod tests {
523    use crate::kinect;
524    use std::{thread, time::Duration};
525    use windows::Win32::{
526        Foundation::{WAIT_OBJECT_0, WAIT_TIMEOUT},
527        System::{Com::Urlmon::E_PENDING, Threading::WaitForSingleObject},
528    };
529
530    #[test]
531    fn get_latest_infrared_frame() -> anyhow::Result<()> {
532        let kinect = kinect::get_default_kinect_sensor()?;
533        kinect.open()?;
534        let infrared_frame_source = kinect.infrared_frame_source()?;
535        let infrared_frame_reader = infrared_frame_source.open_reader()?;
536
537        let mut frame_count = 0;
538        loop {
539            match infrared_frame_reader.acquire_latest_frame() {
540                Ok(infrared_frame) => {
541                    let frame_description = infrared_frame.get_frame_description()?;
542                    let width = frame_description.get_width()?;
543                    let height = frame_description.get_height()?;
544                    let relative_time = infrared_frame.get_relative_time()?;
545                    assert_eq!(width, 512);
546                    assert_eq!(height, 424);
547                    assert!(relative_time > 0);
548                    frame_count += 1;
549                    if frame_count > 10 {
550                        break; // Exit after processing 10 frames
551                    }
552                }
553                Err(e) => {
554                    if e.code() == E_PENDING {
555                        // If the frame is not ready yet, wait and try again
556                        thread::sleep(Duration::from_millis(100));
557                    } else {
558                        // If it's a different error, return it
559                        return Err(anyhow::Error::new(e));
560                    }
561                }
562            }
563        }
564
565        Ok(())
566    }
567
568    #[test]
569    fn subscribe_infrared_frame_arrived_event() -> anyhow::Result<()> {
570        let kinect = kinect::get_default_kinect_sensor()?;
571        kinect.open()?;
572        let infrared_frame_source = kinect.infrared_frame_source()?;
573        let infrared_frame_reader = infrared_frame_source.open_reader()?;
574        let waitable_handle = infrared_frame_reader.subscribe_frame_arrived()?;
575        let mut frame_count = 0;
576        let is_active = infrared_frame_source.get_is_active()?;
577        assert!(is_active, "Color frame source should be active");
578        loop {
579            let result = unsafe { WaitForSingleObject(waitable_handle, 100) };
580            if result == WAIT_OBJECT_0 {
581                let event_args =
582                    infrared_frame_reader.get_frame_arrived_event_data(waitable_handle)?;
583
584                let frame_reference = event_args.get_frame_reference()?;
585                let infrared_frame = frame_reference.acquire_frame()?;
586                let frame_description = infrared_frame.get_frame_description()?;
587                let width = frame_description.get_width()?;
588                let height = frame_description.get_height()?;
589                let relative_time = frame_reference.get_relative_time()?;
590                let bytes_per_pixel = frame_description.get_bytes_per_pixel()?;
591                assert_eq!(width, 512);
592                assert_eq!(height, 424);
593                assert!(relative_time > 0);
594                assert_eq!(bytes_per_pixel, 2);
595                let capacity = (width * height) as u32;
596                let mut frame_data: Vec<u16> = vec![0; capacity as usize];
597                infrared_frame.copy_frame_data_to_array(&mut frame_data)?;
598                println!(
599                    "Infrared frame dimensions: {}x{}, time: {}, data length: {}",
600                    width,
601                    height,
602                    relative_time,
603                    frame_data.len()
604                );
605
606                frame_count += 1;
607                if frame_count > 10 {
608                    break; // Exit after processing 10 frames
609                }
610            } else if result == WAIT_TIMEOUT {
611                println!("No new infrared frame available, waiting...");
612            } else {
613                return Err(anyhow::anyhow!(
614                    "WaitForSingleObject failed with result: {:?}",
615                    result
616                ));
617            }
618        }
619
620        Ok(())
621    }
622}