1use crate::{error::CcapError, sys, types::*};
2use std::ffi::CStr;
3
4#[derive(Debug, Clone)]
6pub struct DeviceInfo {
7 pub name: String,
9 pub supported_pixel_formats: Vec<PixelFormat>,
11 pub supported_resolutions: Vec<Resolution>,
13}
14
15impl DeviceInfo {
16 pub fn from_c_struct(info: &sys::CcapDeviceInfo) -> Result<Self, CcapError> {
18 let name_cstr = unsafe { CStr::from_ptr(info.deviceName.as_ptr()) };
19 let name = name_cstr
20 .to_str()
21 .map_err(|e| CcapError::StringConversionError(e.to_string()))?
22 .to_string();
23
24 let format_count = (info.pixelFormatCount).min(info.supportedPixelFormats.len());
26 let supported_pixel_formats = info.supportedPixelFormats[..format_count]
27 .iter()
28 .map(|&format| PixelFormat::from_c_enum(format))
29 .collect();
30
31 let resolution_count = (info.resolutionCount).min(info.supportedResolutions.len());
32 let supported_resolutions = info.supportedResolutions[..resolution_count]
33 .iter()
34 .map(|&res| Resolution::from(res))
35 .collect();
36
37 Ok(DeviceInfo {
38 name,
39 supported_pixel_formats,
40 supported_resolutions,
41 })
42 }
43}
44
45pub struct VideoFrame {
47 frame: *mut sys::CcapVideoFrame,
48 owns_frame: bool, }
50
51impl VideoFrame {
52 pub(crate) fn from_c_ptr(frame: *mut sys::CcapVideoFrame) -> Self {
53 VideoFrame {
54 frame,
55 owns_frame: true,
56 }
57 }
58
59 pub(crate) fn from_c_ptr_ref(frame: *mut sys::CcapVideoFrame) -> Self {
61 VideoFrame {
62 frame,
63 owns_frame: false,
64 }
65 }
66
67 #[allow(dead_code)]
69 pub(crate) fn as_c_ptr(&self) -> *const sys::CcapVideoFrame {
70 self.frame as *const sys::CcapVideoFrame
71 }
72
73 #[allow(dead_code)]
75 pub(crate) fn from_raw(frame: *mut sys::CcapVideoFrame) -> Option<Self> {
76 if frame.is_null() {
77 None
78 } else {
79 Some(VideoFrame {
80 frame,
81 owns_frame: true,
82 })
83 }
84 }
85
86 pub fn info<'a>(&'a self) -> crate::error::Result<VideoFrameInfo<'a>> {
88 let mut info = sys::CcapVideoFrameInfo::default();
89
90 let success = unsafe { sys::ccap_video_frame_get_info(self.frame, &mut info) };
91
92 if success {
93 let plane0_size = (info.stride[0] as usize) * (info.height as usize);
97 let plane1_size = if info.stride[1] > 0 {
98 (info.stride[1] as usize) * ((info.height as usize + 1) / 2)
99 } else {
100 0
101 };
102 let plane2_size = if info.stride[2] > 0 {
103 (info.stride[2] as usize) * ((info.height as usize + 1) / 2)
104 } else {
105 0
106 };
107
108 Ok(VideoFrameInfo {
109 width: info.width,
110 height: info.height,
111 pixel_format: PixelFormat::from(info.pixelFormat),
112 size_in_bytes: info.sizeInBytes,
113 timestamp: info.timestamp,
114 frame_index: info.frameIndex,
115 orientation: FrameOrientation::from(info.orientation),
116 data_planes: [
117 if info.data[0].is_null() {
118 None
119 } else {
120 Some(unsafe { std::slice::from_raw_parts(info.data[0], plane0_size) })
121 },
122 if info.data[1].is_null() {
123 None
124 } else {
125 Some(unsafe { std::slice::from_raw_parts(info.data[1], plane1_size) })
126 },
127 if info.data[2].is_null() {
128 None
129 } else {
130 Some(unsafe { std::slice::from_raw_parts(info.data[2], plane2_size) })
131 },
132 ],
133 strides: [info.stride[0], info.stride[1], info.stride[2]],
134 })
135 } else {
136 Err(CcapError::FrameGrabFailed)
137 }
138 }
139
140 pub fn data(&self) -> crate::error::Result<&[u8]> {
142 let mut info = sys::CcapVideoFrameInfo::default();
143
144 let success = unsafe { sys::ccap_video_frame_get_info(self.frame, &mut info) };
145
146 if success && !info.data[0].is_null() {
147 Ok(unsafe { std::slice::from_raw_parts(info.data[0], info.sizeInBytes as usize) })
148 } else {
149 Err(CcapError::FrameGrabFailed)
150 }
151 }
152
153 pub fn width(&self) -> u32 {
155 self.info().map(|info| info.width).unwrap_or(0)
156 }
157
158 pub fn height(&self) -> u32 {
160 self.info().map(|info| info.height).unwrap_or(0)
161 }
162
163 pub fn pixel_format(&self) -> PixelFormat {
165 self.info()
166 .map(|info| info.pixel_format)
167 .unwrap_or(PixelFormat::Unknown)
168 }
169
170 pub fn data_size(&self) -> u32 {
172 self.info().map(|info| info.size_in_bytes).unwrap_or(0)
173 }
174
175 pub fn index(&self) -> u64 {
177 self.info().map(|info| info.frame_index).unwrap_or(0)
178 }
179}
180
181impl Drop for VideoFrame {
182 fn drop(&mut self) {
183 if self.owns_frame {
184 unsafe {
185 sys::ccap_video_frame_release(self.frame);
186 }
187 }
188 }
189}
190
191unsafe impl Send for VideoFrame {}
223
224#[derive(Debug)]
226pub struct VideoFrameInfo<'a> {
227 pub width: u32,
229 pub height: u32,
231 pub pixel_format: PixelFormat,
233 pub size_in_bytes: u32,
235 pub timestamp: u64,
237 pub frame_index: u64,
239 pub orientation: FrameOrientation,
241 pub data_planes: [Option<&'a [u8]>; 3],
243 pub strides: [u32; 3],
245}