use crate::{
all_known_camera_controls, mjpeg_to_rgb888, yuyv422_to_rgb888, CameraControl, CameraFormat,
CameraInfo, CaptureAPIBackend, CaptureBackendTrait, FrameFormat, KnownCameraControlFlag,
KnownCameraControls, NokhwaError, Resolution,
};
use image::{ImageBuffer, Rgb};
use nokhwa_bindings_windows::{wmf::MediaFoundationDevice, MFControl, MediaFoundationControls};
use std::{any::Any, borrow::Cow, collections::HashMap};
#[cfg_attr(feature = "docs-features", doc(cfg(feature = "input-msmf")))]
pub struct MediaFoundationCaptureDevice<'a> {
inner: MediaFoundationDevice<'a>,
info: CameraInfo,
}
impl<'a> MediaFoundationCaptureDevice<'a> {
pub fn new(index: usize, camera_fmt: Option<CameraFormat>) -> Result<Self, NokhwaError> {
let mut mf_device = MediaFoundationDevice::new(index)?;
if let Some(fmt) = camera_fmt {
mf_device.set_format(fmt.into())?;
}
let info = CameraInfo::new(
mf_device.name(),
"MediaFoundation Camera Device".to_string(),
mf_device.symlink(),
mf_device.index(),
);
Ok(MediaFoundationCaptureDevice {
inner: mf_device,
info,
})
}
pub fn new_with(
index: usize,
width: u32,
height: u32,
fps: u32,
fourcc: FrameFormat,
) -> Result<Self, NokhwaError> {
let camera_format = Some(CameraFormat::new_from(width, height, fourcc, fps));
MediaFoundationCaptureDevice::new(index, camera_format)
}
}
impl<'a> CaptureBackendTrait for MediaFoundationCaptureDevice<'a> {
fn backend(&self) -> CaptureAPIBackend {
CaptureAPIBackend::MediaFoundation
}
fn camera_info(&self) -> &CameraInfo {
&self.info
}
fn camera_format(&self) -> CameraFormat {
self.inner.format().into()
}
fn set_camera_format(&mut self, new_fmt: CameraFormat) -> Result<(), NokhwaError> {
if let Err(why) = self.inner.set_format(new_fmt.into()) {
return Err(why.into());
}
Ok(())
}
fn compatible_list_by_resolution(
&mut self,
fourcc: FrameFormat,
) -> Result<HashMap<Resolution, Vec<u32>>, NokhwaError> {
let mf_camera_format_list = self.inner.compatible_format_list()?;
let mut resolution_map: HashMap<Resolution, Vec<u32>> = HashMap::new();
for mf_camera_format in mf_camera_format_list {
let camera_format: CameraFormat = mf_camera_format.into();
if camera_format.format() != fourcc {
continue;
}
match resolution_map.get_mut(&camera_format.resolution()) {
Some(fps_list) => {
fps_list.push(camera_format.frame_rate());
}
None => {
if let Some(mut wtf_why_we_here_list) = resolution_map
.insert(camera_format.resolution(), vec![camera_format.frame_rate()])
{
wtf_why_we_here_list.push(camera_format.frame_rate());
resolution_map.insert(camera_format.resolution(), wtf_why_we_here_list);
}
}
}
}
Ok(resolution_map)
}
fn compatible_fourcc(&mut self) -> Result<Vec<FrameFormat>, NokhwaError> {
let mf_camera_format_list = self.inner.compatible_format_list()?;
let mut frame_format_list = vec![];
for mf_camera_format in mf_camera_format_list {
let camera_format: CameraFormat = mf_camera_format.into();
if !frame_format_list.contains(&camera_format.format()) {
frame_format_list.push(camera_format.format());
}
if frame_format_list.len() == 2 {
break;
}
}
Ok(frame_format_list)
}
fn resolution(&self) -> Resolution {
self.camera_format().resolution()
}
fn set_resolution(&mut self, new_res: Resolution) -> Result<(), NokhwaError> {
let mut new_format = self.camera_format();
new_format.set_resolution(new_res);
self.set_camera_format(new_format)
}
fn frame_rate(&self) -> u32 {
self.camera_format().frame_rate()
}
fn set_frame_rate(&mut self, new_fps: u32) -> Result<(), NokhwaError> {
let mut new_format = self.camera_format();
new_format.set_frame_rate(new_fps);
self.set_camera_format(new_format)
}
fn frame_format(&self) -> FrameFormat {
self.camera_format().format()
}
fn set_frame_format(&mut self, fourcc: FrameFormat) -> Result<(), NokhwaError> {
let mut new_format = self.camera_format();
new_format.set_format(fourcc);
self.set_camera_format(new_format)
}
fn supported_camera_controls(&self) -> Result<Vec<KnownCameraControls>, NokhwaError> {
let mut supported_camera_controls: Vec<KnownCameraControls> = vec![];
for camera_control in all_known_camera_controls() {
let msmf_camera_control: MediaFoundationControls = match camera_control {
KnownCameraControls::Brightness => MediaFoundationControls::Brightness,
KnownCameraControls::Contrast => MediaFoundationControls::Contrast,
KnownCameraControls::Hue => MediaFoundationControls::Hue,
KnownCameraControls::Saturation => MediaFoundationControls::Saturation,
KnownCameraControls::Sharpness => MediaFoundationControls::Sharpness,
KnownCameraControls::Gamma => MediaFoundationControls::Gamma,
KnownCameraControls::ColorEnable => MediaFoundationControls::ColorEnable,
KnownCameraControls::WhiteBalance => MediaFoundationControls::WhiteBalance,
KnownCameraControls::BacklightComp => MediaFoundationControls::BacklightComp,
KnownCameraControls::Gain => MediaFoundationControls::Gain,
KnownCameraControls::Pan => MediaFoundationControls::Pan,
KnownCameraControls::Tilt => MediaFoundationControls::Tilt,
KnownCameraControls::Roll => MediaFoundationControls::Roll,
KnownCameraControls::Zoom => MediaFoundationControls::Zoom,
KnownCameraControls::Exposure => MediaFoundationControls::Exposure,
KnownCameraControls::Iris => MediaFoundationControls::Iris,
KnownCameraControls::Focus => MediaFoundationControls::Focus,
};
if let Ok(supported) = self.inner.control(msmf_camera_control) {
supported_camera_controls.push(supported.control().into());
}
}
Ok(supported_camera_controls)
}
fn camera_control(&self, control: KnownCameraControls) -> Result<CameraControl, NokhwaError> {
let msmf_camera_control: MediaFoundationControls = match control {
KnownCameraControls::Brightness => MediaFoundationControls::Brightness,
KnownCameraControls::Contrast => MediaFoundationControls::Contrast,
KnownCameraControls::Hue => MediaFoundationControls::Hue,
KnownCameraControls::Saturation => MediaFoundationControls::Saturation,
KnownCameraControls::Sharpness => MediaFoundationControls::Sharpness,
KnownCameraControls::Gamma => MediaFoundationControls::Gamma,
KnownCameraControls::ColorEnable => MediaFoundationControls::ColorEnable,
KnownCameraControls::WhiteBalance => MediaFoundationControls::WhiteBalance,
KnownCameraControls::BacklightComp => MediaFoundationControls::BacklightComp,
KnownCameraControls::Gain => MediaFoundationControls::Gain,
KnownCameraControls::Pan => MediaFoundationControls::Pan,
KnownCameraControls::Tilt => MediaFoundationControls::Tilt,
KnownCameraControls::Roll => MediaFoundationControls::Roll,
KnownCameraControls::Zoom => MediaFoundationControls::Zoom,
KnownCameraControls::Exposure => MediaFoundationControls::Exposure,
KnownCameraControls::Iris => MediaFoundationControls::Iris,
KnownCameraControls::Focus => MediaFoundationControls::Focus,
};
let ctrl = match self.inner.control(msmf_camera_control) {
Ok(ctrl) => ctrl,
Err(why) => return Err(why.into()),
};
let flag = if ctrl.manual() {
KnownCameraControlFlag::Manual
} else {
KnownCameraControlFlag::Automatic
};
let min = MFControl::min(&ctrl);
let max = MFControl::max(&ctrl);
CameraControl::new(
control,
min,
max,
ctrl.current(),
ctrl.step(),
ctrl.default(),
flag,
ctrl.active(),
)
}
fn set_camera_control(&mut self, control: CameraControl) -> Result<(), NokhwaError> {
let ctrl = match control.control() {
KnownCameraControls::Brightness => MediaFoundationControls::Brightness,
KnownCameraControls::Contrast => MediaFoundationControls::Contrast,
KnownCameraControls::Hue => MediaFoundationControls::Hue,
KnownCameraControls::Saturation => MediaFoundationControls::Saturation,
KnownCameraControls::Sharpness => MediaFoundationControls::Sharpness,
KnownCameraControls::Gamma => MediaFoundationControls::Gamma,
KnownCameraControls::ColorEnable => MediaFoundationControls::ColorEnable,
KnownCameraControls::WhiteBalance => MediaFoundationControls::WhiteBalance,
KnownCameraControls::BacklightComp => MediaFoundationControls::BacklightComp,
KnownCameraControls::Gain => MediaFoundationControls::Gain,
KnownCameraControls::Pan => MediaFoundationControls::Pan,
KnownCameraControls::Tilt => MediaFoundationControls::Tilt,
KnownCameraControls::Roll => MediaFoundationControls::Roll,
KnownCameraControls::Zoom => MediaFoundationControls::Zoom,
KnownCameraControls::Exposure => MediaFoundationControls::Exposure,
KnownCameraControls::Iris => MediaFoundationControls::Iris,
KnownCameraControls::Focus => MediaFoundationControls::Focus,
};
let flag = match control.flag() {
KnownCameraControlFlag::Automatic => false,
KnownCameraControlFlag::Manual => true,
};
let msmf_camera_control = MFControl::new(
ctrl,
control.minimum_value(),
control.maximum_value(),
control.step(),
control.value(),
control.default(),
flag,
control.active(),
);
if let Err(why) = self.inner.set_control(msmf_camera_control) {
return Err(why.into());
}
Ok(())
}
fn raw_supported_camera_controls(&self) -> Result<Vec<Box<dyn Any>>, NokhwaError> {
Err(NokhwaError::UnsupportedOperationError(
CaptureAPIBackend::MediaFoundation,
))
}
fn raw_camera_control(&self, _control: &dyn Any) -> Result<Box<dyn Any>, NokhwaError> {
Err(NokhwaError::UnsupportedOperationError(
CaptureAPIBackend::MediaFoundation,
))
}
fn set_raw_camera_control(
&mut self,
_control: &dyn Any,
_value: &dyn Any,
) -> Result<(), NokhwaError> {
Err(NokhwaError::UnsupportedOperationError(
CaptureAPIBackend::MediaFoundation,
))
}
fn open_stream(&mut self) -> Result<(), NokhwaError> {
if let Err(why) = self.inner.start_stream() {
return Err(why.into());
}
Ok(())
}
fn is_stream_open(&self) -> bool {
self.inner.is_stream_open()
}
fn frame(&mut self) -> Result<ImageBuffer<Rgb<u8>, Vec<u8>>, NokhwaError> {
let camera_format = self.camera_format();
let raw_data = self.frame_raw()?;
let conv = match camera_format.format() {
FrameFormat::MJPEG => mjpeg_to_rgb888(raw_data.as_ref())?,
FrameFormat::YUYV => yuyv422_to_rgb888(raw_data.as_ref())?,
};
let imagebuf =
match ImageBuffer::from_vec(camera_format.width(), camera_format.height(), conv) {
Some(buf) => {
let rgbbuf: ImageBuffer<Rgb<u8>, Vec<u8>> = buf;
rgbbuf
}
None => return Err(NokhwaError::ReadFrameError(
"Imagebuffer is not large enough! This is probably a bug, please report it!"
.to_string(),
)),
};
Ok(imagebuf)
}
fn frame_raw(&mut self) -> Result<Cow<[u8]>, NokhwaError> {
match self.inner.raw_bytes() {
Ok(data) => Ok(data),
Err(why) => Err(why.into()),
}
}
fn stop_stream(&mut self) -> Result<(), NokhwaError> {
self.inner.stop_stream();
Ok(())
}
}