1use super::pixel::{get_pixel, PixelKind};
13use super::prelude::{
14 CouldNotGetFrameSensorError, DepthError, DisparityError, FrameCategory, FrameConstructionError,
15 FrameEx, BITS_PER_BYTE,
16};
17use crate::{
18 check_rs2_error,
19 kind::{Rs2Extension, Rs2FrameMetadata, Rs2Option, Rs2StreamKind, Rs2TimestampDomain},
20 sensor::Sensor,
21 stream_profile::StreamProfile,
22};
23use anyhow::Result;
24use num_traits::FromPrimitive;
25use realsense_sys as sys;
26use std::{
27 convert::{TryFrom, TryInto},
28 marker::PhantomData,
29 os::raw::c_int,
30 ptr::{self, NonNull},
31};
32
33#[derive(Debug)]
35pub struct Depth;
36#[derive(Debug)]
38pub struct Disparity;
39#[derive(Debug)]
41pub struct Color;
42#[derive(Debug)]
44pub struct Infrared;
45#[derive(Debug)]
47pub struct Fisheye;
48#[derive(Debug)]
50pub struct Confidence;
51
52#[derive(Debug)]
57pub struct ImageFrame<Kind> {
58 frame_ptr: NonNull<sys::rs2_frame>,
60 width: usize,
62 height: usize,
64 stride: usize,
66 bits_per_pixel: usize,
68 timestamp: f64,
70 timestamp_domain: Rs2TimestampDomain,
72 frame_number: u64,
74 frame_stream_profile: StreamProfile,
76 data_size_in_bytes: usize,
78 data: NonNull<std::os::raw::c_void>,
80 should_drop: bool,
83 _phantom: PhantomData<Kind>,
85}
86
87pub struct Iter<'a, K> {
89 pub(crate) frame: &'a ImageFrame<K>,
91
92 pub(crate) column: usize,
94
95 pub(crate) row: usize,
97}
98
99impl<'a, K> Iterator for Iter<'a, K> {
100 type Item = PixelKind<'a>;
101
102 fn next(&mut self) -> Option<Self::Item> {
104 if self.column >= self.frame.width() || self.row >= self.frame.height() {
105 return None;
106 }
107
108 let next = self.frame.get_unchecked(self.column, self.row);
109
110 self.column += 1;
111
112 if self.column >= self.frame.width() {
113 self.column = 0;
114 self.row += 1;
115 }
116 Some(next)
117 }
118}
119
120pub type DepthFrame = ImageFrame<Depth>;
126pub type DisparityFrame = ImageFrame<Disparity>;
132pub type ColorFrame = ImageFrame<Color>;
138pub type InfraredFrame = ImageFrame<Infrared>;
144pub type FisheyeFrame = ImageFrame<Fisheye>;
150pub type ConfidenceFrame = ImageFrame<Confidence>;
156
157impl<K> Drop for ImageFrame<K> {
158 fn drop(&mut self) {
159 unsafe {
160 if self.should_drop {
161 sys::rs2_release_frame(self.frame_ptr.as_ptr());
162 }
163 }
164 }
165}
166
167impl<'a, K> IntoIterator for &'a ImageFrame<K> {
168 type Item = <Iter<'a, K> as Iterator>::Item;
169 type IntoIter = Iter<'a, K>;
170
171 fn into_iter(self) -> Self::IntoIter {
172 self.iter()
173 }
174}
175
176unsafe impl<K> Send for ImageFrame<K> {}
177
178impl<K> TryFrom<NonNull<sys::rs2_frame>> for ImageFrame<K> {
179 type Error = anyhow::Error;
180
181 fn try_from(frame_ptr: NonNull<sys::rs2_frame>) -> Result<Self, Self::Error> {
202 unsafe {
203 let mut err = ptr::null_mut::<sys::rs2_error>();
204 let width = sys::rs2_get_frame_width(frame_ptr.as_ptr(), &mut err);
205 check_rs2_error!(err, FrameConstructionError::CouldNotGetWidth)?;
206
207 let height = sys::rs2_get_frame_height(frame_ptr.as_ptr(), &mut err);
208 check_rs2_error!(err, FrameConstructionError::CouldNotGetHeight)?;
209
210 let bits_per_pixel = sys::rs2_get_frame_bits_per_pixel(frame_ptr.as_ptr(), &mut err);
211 check_rs2_error!(err, FrameConstructionError::CouldNotGetBitsPerPixel)?;
212
213 let stride = sys::rs2_get_frame_stride_in_bytes(frame_ptr.as_ptr(), &mut err);
214 check_rs2_error!(err, FrameConstructionError::CouldNotGetStride)?;
215
216 let timestamp = sys::rs2_get_frame_timestamp(frame_ptr.as_ptr(), &mut err);
217 check_rs2_error!(err, FrameConstructionError::CouldNotGetTimestamp)?;
218
219 let timestamp_domain =
220 sys::rs2_get_frame_timestamp_domain(frame_ptr.as_ptr(), &mut err);
221 check_rs2_error!(err, FrameConstructionError::CouldNotGetTimestampDomain)?;
222
223 let frame_number = sys::rs2_get_frame_number(frame_ptr.as_ptr(), &mut err);
224 check_rs2_error!(err, FrameConstructionError::CouldNotGetFrameNumber)?;
225
226 let profile_ptr = sys::rs2_get_frame_stream_profile(frame_ptr.as_ptr(), &mut err);
227 check_rs2_error!(err, FrameConstructionError::CouldNotGetFrameStreamProfile)?;
228
229 let nonnull_profile_ptr =
230 NonNull::new(profile_ptr as *mut sys::rs2_stream_profile).unwrap();
231 let profile = StreamProfile::try_from(nonnull_profile_ptr)?;
232
233 let size = sys::rs2_get_frame_data_size(frame_ptr.as_ptr(), &mut err);
234 check_rs2_error!(err, FrameConstructionError::CouldNotGetDataSize)?;
235
236 debug_assert_eq!(size, width * height * bits_per_pixel / BITS_PER_BYTE);
237
238 let data_ptr = sys::rs2_get_frame_data(frame_ptr.as_ptr(), &mut err);
239 check_rs2_error!(err, FrameConstructionError::CouldNotGetData)?;
240
241 let nonnull_data_ptr = NonNull::new(data_ptr as *mut std::os::raw::c_void).unwrap();
242
243 Ok(ImageFrame {
244 frame_ptr,
245 width: width as usize,
246 height: height as usize,
247 stride: stride as usize,
248 bits_per_pixel: bits_per_pixel as usize,
249 timestamp,
250 timestamp_domain: Rs2TimestampDomain::from_i32(timestamp_domain as i32).unwrap(),
251 frame_number,
252 frame_stream_profile: profile,
253 data_size_in_bytes: size as usize,
254 data: nonnull_data_ptr,
255 should_drop: true,
256 _phantom: PhantomData::<K> {},
257 })
258 }
259 }
260}
261
262impl FrameCategory for DepthFrame {
263 fn extension() -> Rs2Extension {
264 Rs2Extension::DepthFrame
265 }
266
267 fn kind() -> Rs2StreamKind {
268 Rs2StreamKind::Depth
269 }
270
271 fn has_correct_kind(&self) -> bool {
272 self.frame_stream_profile.kind() == Self::kind()
273 }
274}
275
276impl FrameCategory for DisparityFrame {
277 fn extension() -> Rs2Extension {
278 Rs2Extension::DisparityFrame
279 }
280
281 fn kind() -> Rs2StreamKind {
282 Rs2StreamKind::Any
283 }
284
285 fn has_correct_kind(&self) -> bool {
286 self.frame_stream_profile.kind() == Self::kind()
287 }
288}
289
290impl FrameCategory for ColorFrame {
291 fn extension() -> Rs2Extension {
292 Rs2Extension::VideoFrame
293 }
294
295 fn kind() -> Rs2StreamKind {
296 Rs2StreamKind::Color
297 }
298
299 fn has_correct_kind(&self) -> bool {
300 self.frame_stream_profile.kind() == Self::kind()
301 }
302}
303
304impl FrameCategory for InfraredFrame {
305 fn extension() -> Rs2Extension {
306 Rs2Extension::VideoFrame
307 }
308
309 fn kind() -> Rs2StreamKind {
310 Rs2StreamKind::Infrared
311 }
312
313 fn has_correct_kind(&self) -> bool {
314 self.frame_stream_profile.kind() == Self::kind()
315 }
316}
317
318impl FrameCategory for FisheyeFrame {
319 fn extension() -> Rs2Extension {
320 Rs2Extension::VideoFrame
321 }
322
323 fn kind() -> Rs2StreamKind {
324 Rs2StreamKind::Fisheye
325 }
326
327 fn has_correct_kind(&self) -> bool {
328 self.frame_stream_profile.kind() == Self::kind()
329 }
330}
331
332impl FrameCategory for ConfidenceFrame {
333 fn extension() -> Rs2Extension {
334 Rs2Extension::VideoFrame
335 }
336
337 fn kind() -> Rs2StreamKind {
338 Rs2StreamKind::Confidence
339 }
340
341 fn has_correct_kind(&self) -> bool {
342 self.frame_stream_profile.kind() == Self::kind()
343 }
344}
345
346impl<T> FrameEx for ImageFrame<T> {
347 fn stream_profile(&self) -> &StreamProfile {
348 &self.frame_stream_profile
349 }
350
351 fn sensor(&self) -> Result<Sensor> {
352 unsafe {
353 let mut err = std::ptr::null_mut::<sys::rs2_error>();
354 let sensor_ptr = sys::rs2_get_frame_sensor(self.frame_ptr.as_ptr(), &mut err);
355 check_rs2_error!(err, CouldNotGetFrameSensorError)?;
356
357 Ok(Sensor::from(NonNull::new(sensor_ptr).unwrap()))
358 }
359 }
360
361 fn timestamp(&self) -> f64 {
362 self.timestamp
363 }
364
365 fn timestamp_domain(&self) -> Rs2TimestampDomain {
366 self.timestamp_domain
367 }
368
369 fn frame_number(&self) -> u64 {
370 self.frame_number
371 }
372
373 fn metadata(&self, metadata_kind: Rs2FrameMetadata) -> Option<std::os::raw::c_longlong> {
374 if !self.supports_metadata(metadata_kind) {
375 return None;
376 }
377
378 unsafe {
379 let mut err = std::ptr::null_mut::<sys::rs2_error>();
380
381 let val = sys::rs2_get_frame_metadata(
382 self.frame_ptr.as_ptr(),
383 #[allow(clippy::useless_conversion)]
384 (metadata_kind as i32).try_into().unwrap(),
385 &mut err,
386 );
387
388 if err.as_ref().is_none() {
389 Some(val)
390 } else {
391 sys::rs2_free_error(err);
392 None
393 }
394 }
395 }
396
397 fn supports_metadata(&self, metadata_kind: Rs2FrameMetadata) -> bool {
398 unsafe {
399 let mut err = std::ptr::null_mut::<sys::rs2_error>();
400
401 let supports_metadata = sys::rs2_supports_frame_metadata(
402 self.frame_ptr.as_ptr(),
403 #[allow(clippy::useless_conversion)]
404 (metadata_kind as i32).try_into().unwrap(),
405 &mut err,
406 );
407
408 if err.as_ref().is_none() {
409 supports_metadata != 0
410 } else {
411 sys::rs2_free_error(err);
412 false
413 }
414 }
415 }
416
417 unsafe fn get_owned_raw(mut self) -> NonNull<sys::rs2_frame> {
418 self.should_drop = false;
419
420 self.frame_ptr
421 }
422}
423
424impl DepthFrame {
425 pub fn distance(&self, col: usize, row: usize) -> Result<f32, DepthError> {
434 unsafe {
435 let mut err = ptr::null_mut::<sys::rs2_error>();
436 let distance = sys::rs2_depth_frame_get_distance(
437 self.frame_ptr.as_ptr(),
438 col as c_int,
439 row as c_int,
440 &mut err,
441 );
442 check_rs2_error!(err, DepthError::CouldNotGetDistance)?;
443 Ok(distance)
444 }
445 }
446
447 pub fn depth_units(&self) -> Result<f32> {
449 let sensor = self.sensor()?;
450 let depth_units = sensor.get_option(Rs2Option::DepthUnits).ok_or_else(|| {
451 anyhow::anyhow!("Option is not supported on the sensor for this frame type.")
452 })?;
453 Ok(depth_units)
454 }
455}
456
457impl DisparityFrame {
458 pub fn distance(&self, col: usize, row: usize) -> Result<f32, DepthError> {
470 unsafe {
471 let mut err = ptr::null_mut::<sys::rs2_error>();
472 let distance = sys::rs2_depth_frame_get_distance(
473 self.frame_ptr.as_ptr(),
474 col as c_int,
475 row as c_int,
476 &mut err,
477 );
478 check_rs2_error!(err, DepthError::CouldNotGetDistance)?;
479 Ok(distance)
480 }
481 }
482
483 pub fn depth_units(&self) -> Result<f32> {
485 let sensor = self.sensor()?;
486 let depth_units = sensor.get_option(Rs2Option::DepthUnits).ok_or_else(|| {
487 anyhow::anyhow!("Option is not supported on the sensor for this frame type.")
488 })?;
489 Ok(depth_units)
490 }
491
492 pub fn baseline(&self) -> Result<f32, DisparityError> {
494 unsafe {
495 let mut err = ptr::null_mut::<sys::rs2_error>();
496 let baseline =
497 sys::rs2_depth_stereo_frame_get_baseline(self.frame_ptr.as_ptr(), &mut err);
498 check_rs2_error!(err, DisparityError)?;
499 Ok(baseline)
500 }
501 }
502}
503
504impl<K> ImageFrame<K> {
505 pub fn iter(&self) -> Iter<'_, K> {
507 Iter {
508 frame: self,
509 column: 0,
510 row: 0,
511 }
512 }
513
514 #[inline(always)]
521 pub fn get_unchecked(&self, col: usize, row: usize) -> PixelKind<'_> {
522 unsafe {
523 get_pixel(
524 self.frame_stream_profile.format(),
525 self.data_size_in_bytes,
526 self.data.as_ptr(),
527 self.stride,
528 col,
529 row,
530 )
531 }
532 }
533
534 pub fn stride(&self) -> usize {
536 self.stride
537 }
538
539 pub fn bits_per_pixel(&self) -> usize {
541 self.bits_per_pixel
542 }
543
544 pub fn get_data_size(&self) -> usize {
546 self.data_size_in_bytes
547 }
548
549 pub unsafe fn get_data(&self) -> &std::os::raw::c_void {
558 self.data.as_ref()
559 }
560
561 pub fn width(&self) -> usize {
563 self.width
564 }
565
566 pub fn height(&self) -> usize {
568 self.height
569 }
570
571 pub fn get(&self, col: usize, row: usize) -> Option<PixelKind<'_>> {
573 if col >= self.width || row >= self.height {
574 None
575 } else {
576 Some(self.get_unchecked(col, row))
577 }
578 }
579}
580
581#[cfg(test)]
582mod tests {
583 use super::*;
584
585 #[test]
586 fn frame_has_correct_kind() {
587 assert_eq!(ColorFrame::kind(), Rs2StreamKind::Color);
588 assert_eq!(DepthFrame::kind(), Rs2StreamKind::Depth);
589 assert_eq!(DisparityFrame::kind(), Rs2StreamKind::Any);
590 assert_eq!(InfraredFrame::kind(), Rs2StreamKind::Infrared);
591 assert_eq!(FisheyeFrame::kind(), Rs2StreamKind::Fisheye);
592 assert_eq!(ConfidenceFrame::kind(), Rs2StreamKind::Confidence);
593 }
594}