use crate::{
error::NokhwaError,
utils::{CameraFormat, CameraInfo, FrameFormat, Resolution},
CameraControl, CaptureAPIBackend, KnownCameraControls,
};
use image::{buffer::ConvertBuffer, ImageBuffer, Rgb, RgbaImage};
use std::{any::Any, borrow::Cow, collections::HashMap};
#[cfg(feature = "output-wgpu")]
use wgpu::{
Device as WgpuDevice, Extent3d, ImageCopyTexture, ImageDataLayout, Queue as WgpuQueue,
Texture as WgpuTexture, TextureAspect, TextureDescriptor, TextureDimension, TextureFormat,
TextureUsages,
};
pub trait CaptureBackendTrait {
fn backend(&self) -> CaptureAPIBackend;
fn camera_info(&self) -> &CameraInfo;
fn camera_format(&self) -> CameraFormat;
fn set_camera_format(&mut self, new_fmt: CameraFormat) -> Result<(), NokhwaError>;
fn compatible_list_by_resolution(
&mut self,
fourcc: FrameFormat,
) -> Result<HashMap<Resolution, Vec<u32>>, NokhwaError>;
fn compatible_fourcc(&mut self) -> Result<Vec<FrameFormat>, NokhwaError>;
fn resolution(&self) -> Resolution;
fn set_resolution(&mut self, new_res: Resolution) -> Result<(), NokhwaError>;
fn frame_rate(&self) -> u32;
fn set_frame_rate(&mut self, new_fps: u32) -> Result<(), NokhwaError>;
fn frame_format(&self) -> FrameFormat;
fn set_frame_format(&mut self, fourcc: FrameFormat) -> Result<(), NokhwaError>;
fn supported_camera_controls(&self) -> Result<Vec<KnownCameraControls>, NokhwaError>;
fn camera_control(&self, control: KnownCameraControls) -> Result<CameraControl, NokhwaError>;
fn set_camera_control(&mut self, control: CameraControl) -> Result<(), NokhwaError>;
fn raw_supported_camera_controls(&self) -> Result<Vec<Box<dyn Any>>, NokhwaError>;
fn raw_camera_control(&self, control: &dyn Any) -> Result<Box<dyn Any>, NokhwaError>;
fn set_raw_camera_control(
&mut self,
control: &dyn Any,
value: &dyn Any,
) -> Result<(), NokhwaError>;
fn open_stream(&mut self) -> Result<(), NokhwaError>;
fn is_stream_open(&self) -> bool;
fn frame(&mut self) -> Result<ImageBuffer<Rgb<u8>, Vec<u8>>, NokhwaError>;
fn frame_raw(&mut self) -> Result<Cow<[u8]>, NokhwaError>;
fn min_buffer_size(&self, rgba: bool) -> usize {
let resolution = self.resolution();
if rgba {
return (resolution.width() * resolution.height() * 4) as usize;
}
(resolution.width() * resolution.height() * 3) as usize
}
fn write_frame_to_buffer(
&mut self,
buffer: &mut [u8],
convert_rgba: bool,
) -> Result<usize, NokhwaError> {
let resolution = self.resolution();
let frame = self.frame_raw()?;
if convert_rgba {
let image_data =
match ImageBuffer::from_raw(resolution.width(), resolution.height(), frame) {
Some(image) => {
let image: ImageBuffer<Rgb<u8>, Cow<[u8]>> = image;
image
}
None => {
return Err(NokhwaError::ReadFrameError(
"Frame Cow Too Small".to_string(),
))
}
};
let rgba_image: RgbaImage = image_data.convert();
buffer.copy_from_slice(rgba_image.as_raw());
return Ok(rgba_image.len());
}
buffer.copy_from_slice(frame.as_ref());
Ok(frame.len())
}
#[cfg(feature = "output-wgpu")]
#[cfg_attr(feature = "docs-features", doc(cfg(feature = "output-wgpu")))]
fn frame_texture<'a>(
&mut self,
device: &WgpuDevice,
queue: &WgpuQueue,
label: Option<&'a str>,
) -> Result<WgpuTexture, NokhwaError> {
use std::{convert::TryFrom, num::NonZeroU32};
let frame = self.frame()?;
let rgba_frame: RgbaImage = frame.convert();
let texture_size = Extent3d {
width: frame.width(),
height: frame.height(),
depth_or_array_layers: 1,
};
let texture = device.create_texture(&TextureDescriptor {
label,
size: texture_size,
mip_level_count: 1,
sample_count: 1,
dimension: TextureDimension::D2,
format: TextureFormat::Rgba8UnormSrgb,
usage: TextureUsages::TEXTURE_BINDING | TextureUsages::COPY_DST,
});
let width_nonzero = match NonZeroU32::try_from(4 * rgba_frame.width()) {
Ok(w) => Some(w),
Err(why) => return Err(NokhwaError::ReadFrameError(why.to_string())),
};
let height_nonzero = match NonZeroU32::try_from(rgba_frame.height()) {
Ok(h) => Some(h),
Err(why) => return Err(NokhwaError::ReadFrameError(why.to_string())),
};
queue.write_texture(
ImageCopyTexture {
texture: &texture,
mip_level: 0,
origin: wgpu::Origin3d::ZERO,
aspect: TextureAspect::All,
},
&rgba_frame.to_vec(),
ImageDataLayout {
offset: 0,
bytes_per_row: width_nonzero,
rows_per_image: height_nonzero,
},
texture_size,
);
Ok(texture)
}
fn stop_stream(&mut self) -> Result<(), NokhwaError>;
}
pub trait VirtualBackendTrait {}