1use kinect_v2_sys::{
2 DEFAULT_FRAME_WAIT_TIMEOUT_MS, WAITABLE_HANDLE,
3 bindings::{
4 CameraSpacePoint, DetectionResult, FrameEdges, HandState, Joint, JointOrientation,
5 JointType, PointF, TrackingConfidence, TrackingState, Vector4,
6 },
7 body::{Body, BodyFrame, BodyFrameReader},
8 kinect::{self, KinectSensor},
9};
10use windows::Win32::Foundation::{E_FAIL, WAIT_OBJECT_0, WAIT_TIMEOUT};
11use windows::Win32::System::Threading::WaitForSingleObject;
12use windows::{Win32::Foundation::WAIT_EVENT, core::Error};
13
14pub struct BodyFrameCapture {
19 kinect: KinectSensor, }
21
22impl BodyFrameCapture {
23 pub fn new() -> Result<Self, Error> {
33 let kinect = kinect::get_default_kinect_sensor()?;
34 kinect.open()?;
35
36 Ok(BodyFrameCapture { kinect })
37 }
38
39 pub fn iter(&self) -> Result<BodyFrameCaptureIter, Error> {
50 let source = self.kinect.body_frame_source()?;
51 let reader = source.open_reader()?;
53 if !source.get_is_active()? {
56 log::warn!("Body frame source is not active, cannot subscribe to frame arrived event.");
57 return Err(Error::from_hresult(E_FAIL));
58 }
59
60 let mut waitable_handle = WAITABLE_HANDLE::default();
61 reader.subscribe_frame_arrived(&mut waitable_handle)?;
62 Ok(BodyFrameCaptureIter {
63 reader,
64 waitable_handle,
65 timeout_ms: DEFAULT_FRAME_WAIT_TIMEOUT_MS,
66 })
67 }
68}
69
70pub struct BodyFrameCaptureIter {
75 reader: BodyFrameReader,
76 waitable_handle: WAITABLE_HANDLE,
77 timeout_ms: u32,
78}
79
80impl Drop for BodyFrameCaptureIter {
81 fn drop(&mut self) {
82 if let Err(e) = self.reader.unsubscribe_frame_arrived(self.waitable_handle) {
85 log::warn!("Failed to unsubscribe body frame arrived event: {e:?}");
86 }
87 }
88}
89
90impl Iterator for BodyFrameCaptureIter {
91 type Item = Result<BodyFrameData, Error>;
92
93 fn next(&mut self) -> Option<Self::Item> {
94 loop {
95 let wait_status: WAIT_EVENT =
96 unsafe { WaitForSingleObject(self.waitable_handle, self.timeout_ms) };
97
98 if wait_status == WAIT_OBJECT_0 {
99 let result = (|| {
102 let event_args = self
103 .reader
104 .get_frame_arrived_event_data(self.waitable_handle)?;
105 let frame_reference = event_args.get_frame_reference()?;
106 let body_frame = frame_reference.acquire_frame()?;
107 BodyFrameData::new(&body_frame)
108 })(); return Some(result);
110 } else if wait_status == WAIT_TIMEOUT {
111 continue;
114 } else {
115 return Some(Err(Error::from_hresult(E_FAIL)));
116 }
117 }
118 }
119}
120
121#[derive(Debug, Clone)]
122pub struct BodyData {
123 pub tracking_id: u64,
124 pub is_tracked: bool,
125 pub is_restricted: bool,
126 pub hand_left_state: HandState,
127 pub hand_right_state: HandState,
128 pub hand_left_confidence: TrackingConfidence,
129 pub hand_right_confidence: TrackingConfidence,
130 pub clipped_edges: FrameEdges,
131 pub lean: PointF,
132 pub lean_tracking_state: TrackingState,
133 pub is_engaged: bool,
134 pub joints: Vec<Joint>,
135 pub joint_orientations: Vec<JointOrientation>,
136}
137
138impl BodyData {
139 pub fn new(body: Body) -> Result<Self, Error> {
140 use kinect_v2_sys::bindings::{Joint, JointOrientation};
141
142 let tracking_id = body.get_tracking_id()?;
144
145 let is_tracked = body.get_is_tracked()?;
146
147 let is_restricted = body.get_is_restricted()?;
148
149 let hand_left_state = body.get_hand_left_state()?;
150
151 let hand_right_state = body.get_hand_right_state()?;
152
153 let hand_left_confidence = body.get_hand_left_confidence()?;
154
155 let hand_right_confidence = body.get_hand_right_confidence()?;
156
157 let clipped_edges = body.get_clipped_edges()?;
158
159 let is_engaged = body.get_engaged()? == DetectionResult::Yes;
160
161 let lean = body.get_lean()?;
163 let lean_tracking_state = body.get_lean_tracking_state()?;
164
165 const JOINT_COUNT: usize = 25;
167 let mut joints: [Joint; JOINT_COUNT] = unsafe { std::mem::zeroed() };
168 body.get_joints(joints.as_mut())?;
169 let joints: Vec<Joint> = joints.to_vec();
170
171 let mut joint_orientations: [JointOrientation; JOINT_COUNT] = unsafe { std::mem::zeroed() };
173 body.get_joint_orientations(joint_orientations.as_mut())?;
174 let joint_orientations: Vec<JointOrientation> = joint_orientations.to_vec();
175
176 Ok(Self {
177 tracking_id,
178 is_tracked,
179 is_restricted,
180 hand_left_state,
181 hand_right_state,
182 hand_left_confidence,
183 hand_right_confidence,
184 clipped_edges,
185 lean,
186 lean_tracking_state,
187 is_engaged,
188 joints,
189 joint_orientations,
190 })
191 }
192
193 pub fn get_joint_position(&self, joint_type: JointType) -> Option<CameraSpacePoint> {
195 self.joints
196 .iter()
197 .find(|joint| joint.JointType == joint_type)
198 .map(|joint| joint.Position.clone())
199 }
200
201 pub fn get_joint_orientation(&self, joint_type: JointType) -> Option<Vector4> {
203 self.joint_orientations
204 .iter()
205 .find(|joint_orientation| joint_orientation.JointType == joint_type)
206 .map(|joint_orientation| joint_orientation.Orientation.clone())
207 }
208
209 pub fn is_actively_tracked(&self) -> bool {
211 self.is_tracked && !self.is_restricted
212 }
213}
214
215#[derive(Debug, Clone, Default)]
216pub struct BodyFrameData {
217 pub timestamp: u64,
218 pub floor_clip_plane: Vector4,
219 pub body_count: u32,
220 pub bodies: Vec<BodyData>,
221}
222
223impl BodyFrameData {
224 pub fn new(body_frame: &BodyFrame) -> Result<Self, Error> {
225 let timestamp = body_frame.get_relative_time()? as u64;
226 let floor_clip_plane = body_frame.get_floor_clip_plane()?;
228 let body_frame_source = body_frame.get_body_frame_source()?;
230 let body_count = body_frame_source.get_body_count()? as u32;
231
232 let bodies = body_frame.get_and_refresh_body_data()?;
234 let bodies = bodies
235 .into_iter()
236 .map(BodyData::new)
237 .collect::<Result<Vec<BodyData>, Error>>()?;
238
239 Ok(Self {
240 timestamp,
241 floor_clip_plane,
242 body_count,
243 bodies,
244 })
245 }
246}
247
248#[cfg(test)]
249mod tests {
250 use super::*;
251 use anyhow::anyhow;
252 use std::sync::mpsc;
253
254 #[test]
255 fn body_capture_test() -> anyhow::Result<()> {
256 let (body_tx, body_rx) = mpsc::channel::<BodyFrameData>();
257 let max_frames_to_capture = 10;
258 let body_capture_thread = std::thread::spawn(move || -> anyhow::Result<()> {
259 let body_capture = BodyFrameCapture::new()?;
260 for (frame_count, frame) in body_capture.iter()?.enumerate() {
261 if frame_count >= max_frames_to_capture {
262 break;
263 }
264 let data = frame.map_err(|e| anyhow!("Error capturing body frame: {}", e))?;
265 if body_tx.send(data).is_err() {
266 break;
267 }
268 }
269 Ok(())
270 });
271
272 let processing_thread = std::thread::spawn(move || -> anyhow::Result<()> {
273 for _ in 0..max_frames_to_capture {
274 let frame_data = match body_rx.recv() {
275 Ok(data) => data,
276 Err(_) => break,
277 };
278 println!(
279 "Received body frame: timestamp: {}, body_count: {}",
280 frame_data.timestamp, frame_data.body_count
281 );
282 anyhow::ensure!(frame_data.body_count > 0, "No bodies detected");
283 anyhow::ensure!(frame_data.timestamp > 0, "Timestamp is not positive");
284 }
285 Ok(())
286 });
287
288 body_capture_thread
289 .join()
290 .map_err(|e| anyhow!("Body capture thread join error: {:?}", e))??;
291 processing_thread
292 .join()
293 .map_err(|e| anyhow!("Processing thread join error: {:?}", e))??;
294 Ok(())
295 }
296}