use crate::{
error::NokhwaError,
utils::{CameraFormat, CameraInfo, FrameFormat, Resolution},
};
use image::{buffer::ConvertBuffer, ImageBuffer, Rgb, RgbaImage};
use std::collections::HashMap;
#[cfg(feature = "output-wgpu")]
use wgpu::{
Device as WgpuDevice, Extent3d, ImageCopyTexture, ImageDataLayout, Queue as WgpuQueue,
Texture as WgpuTexture, TextureDescriptor, TextureDimension, TextureFormat, TextureUsage,
};
pub trait CaptureBackendTrait {
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(
&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 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<Vec<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 frame = self.frame()?;
let mut frame_data = frame.to_vec();
if convert_rgba {
let rgba_image: RgbaImage = frame.convert();
frame_data = rgba_image.to_vec();
}
let bytes = frame_data.len();
buffer.copy_from_slice(&frame_data);
Ok(bytes)
}
#[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: TextureUsage::SAMPLED | TextureUsage::COPY_DST,
});
let width_nonzero = match NonZeroU32::try_from(4 * rgba_frame.width()) {
Ok(w) => Some(w),
Err(why) => return Err(NokhwaError::CouldntCaptureFrame(why.to_string())),
};
let height_nonzero = match NonZeroU32::try_from(rgba_frame.height()) {
Ok(h) => Some(h),
Err(why) => return Err(NokhwaError::CouldntCaptureFrame(why.to_string())),
};
queue.write_texture(
ImageCopyTexture {
texture: &texture,
mip_level: 0,
origin: wgpu::Origin3d::ZERO,
},
&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 {}