use super::prelude::{CouldNotGetFrameSensorError, FrameCategory, FrameConstructionError, FrameEx};
use crate::{
check_rs2_error,
kind::{Rs2Extension, Rs2FrameMetadata, Rs2StreamKind, Rs2TimestampDomain},
sensor::Sensor,
stream_profile::StreamProfile,
};
use anyhow::Result;
use num_traits::FromPrimitive;
use realsense_sys as sys;
use std::{
convert::{TryFrom, TryInto},
ptr::{self, NonNull},
slice,
};
#[derive(Debug)]
pub struct PointsFrame {
frame_ptr: NonNull<sys::rs2_frame>,
timestamp: f64,
timestamp_domain: Rs2TimestampDomain,
frame_stream_profile: StreamProfile,
num_points: usize,
vertices_data_ptr: NonNull<sys::rs2_vertex>,
texture_data_ptr: NonNull<sys::rs2_pixel>,
should_drop: bool,
}
impl FrameCategory for PointsFrame {
fn extension() -> Rs2Extension {
Rs2Extension::Points
}
fn kind() -> Rs2StreamKind {
Rs2StreamKind::Any
}
fn has_correct_kind(&self) -> bool {
self.frame_stream_profile.kind() == Self::kind()
}
}
impl FrameEx for PointsFrame {
fn stream_profile(&self) -> &StreamProfile {
&self.frame_stream_profile
}
fn sensor(&self) -> Result<Sensor> {
unsafe {
let mut err = std::ptr::null_mut::<sys::rs2_error>();
let sensor_ptr = sys::rs2_get_frame_sensor(self.frame_ptr.as_ptr(), &mut err);
check_rs2_error!(err, CouldNotGetFrameSensorError)?;
Ok(Sensor::try_from(NonNull::new(sensor_ptr).unwrap())?)
}
}
fn timestamp(&self) -> f64 {
self.timestamp
}
fn timestamp_domain(&self) -> Rs2TimestampDomain {
self.timestamp_domain
}
fn metadata(&self, metadata_kind: Rs2FrameMetadata) -> Option<std::os::raw::c_longlong> {
if !self.supports_metadata(metadata_kind) {
return None;
}
unsafe {
let mut err = std::ptr::null_mut::<sys::rs2_error>();
let val = sys::rs2_get_frame_metadata(
self.frame_ptr.as_ptr(),
#[allow(clippy::useless_conversion)]
(metadata_kind as i32).try_into().unwrap(),
&mut err,
);
if err.as_ref().is_none() {
Some(val)
} else {
sys::rs2_free_error(err);
None
}
}
}
fn supports_metadata(&self, metadata_kind: Rs2FrameMetadata) -> bool {
unsafe {
let mut err = std::ptr::null_mut::<sys::rs2_error>();
let supports_metadata = sys::rs2_supports_frame_metadata(
self.frame_ptr.as_ptr(),
#[allow(clippy::useless_conversion)]
(metadata_kind as i32).try_into().unwrap(),
&mut err,
);
if err.as_ref().is_none() {
supports_metadata != 0
} else {
sys::rs2_free_error(err);
false
}
}
}
unsafe fn get_owned_raw(mut self) -> NonNull<sys::rs2_frame> {
self.should_drop = false;
self.frame_ptr
}
}
impl Drop for PointsFrame {
fn drop(&mut self) {
unsafe {
if self.should_drop {
sys::rs2_release_frame(self.frame_ptr.as_ptr());
}
}
}
}
unsafe impl Send for PointsFrame {}
impl std::convert::TryFrom<NonNull<sys::rs2_frame>> for PointsFrame {
type Error = anyhow::Error;
fn try_from(frame_ptr: NonNull<sys::rs2_frame>) -> Result<Self, Self::Error> {
unsafe {
let mut err = ptr::null_mut::<sys::rs2_error>();
let timestamp = sys::rs2_get_frame_timestamp(frame_ptr.as_ptr(), &mut err);
check_rs2_error!(err, FrameConstructionError::CouldNotGetTimestamp)?;
let timestamp_domain =
sys::rs2_get_frame_timestamp_domain(frame_ptr.as_ptr(), &mut err);
check_rs2_error!(err, FrameConstructionError::CouldNotGetTimestampDomain)?;
let profile_ptr = sys::rs2_get_frame_stream_profile(frame_ptr.as_ptr(), &mut err);
check_rs2_error!(err, FrameConstructionError::CouldNotGetFrameStreamProfile)?;
let nonnull_profile_ptr =
NonNull::new(profile_ptr as *mut sys::rs2_stream_profile).unwrap();
let profile = StreamProfile::try_from(nonnull_profile_ptr)?;
let num_points = sys::rs2_get_frame_points_count(frame_ptr.as_ptr(), &mut err);
check_rs2_error!(err, FrameConstructionError::CouldNotGetPointCount)?;
let vertices_ptr = sys::rs2_get_frame_vertices(frame_ptr.as_ptr(), &mut err);
check_rs2_error!(err, FrameConstructionError::CouldNotGetData)?;
let texture_ptr = sys::rs2_get_frame_texture_coordinates(frame_ptr.as_ptr(), &mut err);
check_rs2_error!(err, FrameConstructionError::CouldNotGetData)?;
Ok(PointsFrame {
frame_ptr,
timestamp,
timestamp_domain: Rs2TimestampDomain::from_i32(timestamp_domain as i32).unwrap(),
frame_stream_profile: profile,
num_points: num_points as usize,
vertices_data_ptr: NonNull::new(vertices_ptr).unwrap(),
texture_data_ptr: NonNull::new(texture_ptr).unwrap(),
should_drop: true,
})
}
}
}
impl PointsFrame {
pub fn vertices(&self) -> &[sys::rs2_vertex] {
unsafe {
slice::from_raw_parts::<sys::rs2_vertex>(
self.vertices_data_ptr.as_ptr(),
self.num_points,
)
}
}
pub fn texture_coordinates(&self) -> &[[f32; 2]] {
unsafe {
slice::from_raw_parts::<[f32; 2]>(
self.texture_data_ptr.as_ptr().cast::<[f32; 2]>(),
self.num_points,
)
}
}
pub fn points_count(&self) -> usize {
self.num_points
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn frame_has_correct_kind() {
assert_eq!(PointsFrame::kind(), Rs2StreamKind::Any);
}
}