use crate::{error::CcapError, sys, types::*};
use std::ffi::CStr;
#[derive(Debug, Clone)]
pub struct DeviceInfo {
pub name: String,
pub supported_pixel_formats: Vec<PixelFormat>,
pub supported_resolutions: Vec<Resolution>,
}
impl DeviceInfo {
pub fn from_c_struct(info: &sys::CcapDeviceInfo) -> Result<Self, CcapError> {
let name_cstr = unsafe { CStr::from_ptr(info.deviceName.as_ptr()) };
let name = name_cstr
.to_str()
.map_err(|e| CcapError::StringConversionError(e.to_string()))?
.to_string();
let format_count = (info.pixelFormatCount).min(info.supportedPixelFormats.len());
let supported_pixel_formats = info.supportedPixelFormats[..format_count]
.iter()
.map(|&format| PixelFormat::from_c_enum(format))
.collect();
let resolution_count = (info.resolutionCount).min(info.supportedResolutions.len());
let supported_resolutions = info.supportedResolutions[..resolution_count]
.iter()
.map(|&res| Resolution::from(res))
.collect();
Ok(DeviceInfo {
name,
supported_pixel_formats,
supported_resolutions,
})
}
}
pub struct VideoFrame {
frame: *mut sys::CcapVideoFrame,
owns_frame: bool, }
impl VideoFrame {
pub(crate) fn from_c_ptr(frame: *mut sys::CcapVideoFrame) -> Self {
VideoFrame {
frame,
owns_frame: true,
}
}
pub(crate) fn from_c_ptr_ref(frame: *mut sys::CcapVideoFrame) -> Self {
VideoFrame {
frame,
owns_frame: false,
}
}
#[allow(dead_code)]
pub(crate) fn as_c_ptr(&self) -> *const sys::CcapVideoFrame {
self.frame as *const sys::CcapVideoFrame
}
#[allow(dead_code)]
pub(crate) fn from_raw(frame: *mut sys::CcapVideoFrame) -> Option<Self> {
if frame.is_null() {
None
} else {
Some(VideoFrame {
frame,
owns_frame: true,
})
}
}
pub fn info<'a>(&'a self) -> crate::error::Result<VideoFrameInfo<'a>> {
let mut info = sys::CcapVideoFrameInfo::default();
let success = unsafe { sys::ccap_video_frame_get_info(self.frame, &mut info) };
if success {
let plane0_size = (info.stride[0] as usize) * (info.height as usize);
let plane1_size = if info.stride[1] > 0 {
(info.stride[1] as usize) * ((info.height as usize + 1) / 2)
} else {
0
};
let plane2_size = if info.stride[2] > 0 {
(info.stride[2] as usize) * ((info.height as usize + 1) / 2)
} else {
0
};
Ok(VideoFrameInfo {
width: info.width,
height: info.height,
pixel_format: PixelFormat::from(info.pixelFormat),
size_in_bytes: info.sizeInBytes,
timestamp: info.timestamp,
frame_index: info.frameIndex,
orientation: FrameOrientation::from(info.orientation),
data_planes: [
if info.data[0].is_null() {
None
} else {
Some(unsafe { std::slice::from_raw_parts(info.data[0], plane0_size) })
},
if info.data[1].is_null() {
None
} else {
Some(unsafe { std::slice::from_raw_parts(info.data[1], plane1_size) })
},
if info.data[2].is_null() {
None
} else {
Some(unsafe { std::slice::from_raw_parts(info.data[2], plane2_size) })
},
],
strides: [info.stride[0], info.stride[1], info.stride[2]],
})
} else {
Err(CcapError::FrameGrabFailed)
}
}
pub fn data(&self) -> crate::error::Result<&[u8]> {
let mut info = sys::CcapVideoFrameInfo::default();
let success = unsafe { sys::ccap_video_frame_get_info(self.frame, &mut info) };
if success && !info.data[0].is_null() {
Ok(unsafe { std::slice::from_raw_parts(info.data[0], info.sizeInBytes as usize) })
} else {
Err(CcapError::FrameGrabFailed)
}
}
pub fn width(&self) -> u32 {
self.info().map(|info| info.width).unwrap_or(0)
}
pub fn height(&self) -> u32 {
self.info().map(|info| info.height).unwrap_or(0)
}
pub fn pixel_format(&self) -> PixelFormat {
self.info()
.map(|info| info.pixel_format)
.unwrap_or(PixelFormat::Unknown)
}
pub fn data_size(&self) -> u32 {
self.info().map(|info| info.size_in_bytes).unwrap_or(0)
}
pub fn index(&self) -> u64 {
self.info().map(|info| info.frame_index).unwrap_or(0)
}
}
impl Drop for VideoFrame {
fn drop(&mut self) {
if self.owns_frame {
unsafe {
sys::ccap_video_frame_release(self.frame);
}
}
}
}
unsafe impl Send for VideoFrame {}
#[derive(Debug)]
pub struct VideoFrameInfo<'a> {
pub width: u32,
pub height: u32,
pub pixel_format: PixelFormat,
pub size_in_bytes: u32,
pub timestamp: u64,
pub frame_index: u64,
pub orientation: FrameOrientation,
pub data_planes: [Option<&'a [u8]>; 3],
pub strides: [u32; 3],
}