fix windows media foundation

This commit is contained in:
l1npengtul
2022-10-29 03:10:21 -07:00
parent 75d10fc9ef
commit 0dc85c908f
4 changed files with 172 additions and 214 deletions
+19
View File
@@ -0,0 +1,19 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Clippy Main Windows" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
<option name="command" value="clippy --features &quot;output-wgpu, input-msmf&quot;" />
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
<option name="channel" value="DEFAULT" />
<option name="requiredFeatures" value="true" />
<option name="allFeatures" value="false" />
<option name="emulateTerminal" value="false" />
<option name="withSudo" value="false" />
<option name="buildTarget" value="REMOTE" />
<option name="backtrace" value="SHORT" />
<envs />
<option name="isRedirectInput" value="false" />
<option name="redirectInputPath" value="" />
<method v="2">
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
</method>
</configuration>
</component>
+125 -136
View File
@@ -31,13 +31,6 @@
#[macro_use] #[macro_use]
extern crate lazy_static; extern crate lazy_static;
#[cfg(all(target_os = "windows", windows))]
use std::{
borrow::{Borrow, Cow},
cmp::Ordering,
slice::from_raw_parts,
};
#[cfg(all(windows, not(feature = "docs-only")))] #[cfg(all(windows, not(feature = "docs-only")))]
pub mod wmf { pub mod wmf {
use nokhwa_core::error::NokhwaError; use nokhwa_core::error::NokhwaError;
@@ -45,6 +38,7 @@ pub mod wmf {
ApiBackend, CameraControl, CameraFormat, CameraIndex, CameraInfo, ControlValueDescription, ApiBackend, CameraControl, CameraFormat, CameraIndex, CameraInfo, ControlValueDescription,
ControlValueSetter, FrameFormat, KnownCameraControl, KnownCameraControlFlag, Resolution, ControlValueSetter, FrameFormat, KnownCameraControl, KnownCameraControlFlag, Resolution,
}; };
use std::ffi::c_void;
use std::{ use std::{
borrow::Cow, borrow::Cow,
cell::Cell, cell::Cell,
@@ -65,11 +59,11 @@ pub mod wmf {
Media::{ Media::{
DirectShow::{ DirectShow::{
CameraControl_Exposure, CameraControl_Focus, CameraControl_Iris, CameraControl_Exposure, CameraControl_Focus, CameraControl_Iris,
CameraControl_Pan, CameraControl_Roll, CameraControl_Tilt, CameraControl_Zoom, CameraControl_Pan, CameraControl_Tilt, CameraControl_Zoom, IAMCameraControl,
IAMCameraControl, IAMVideoProcAmp, VideoProcAmp_BacklightCompensation, IAMVideoProcAmp, VideoProcAmp_BacklightCompensation, VideoProcAmp_Brightness,
VideoProcAmp_Brightness, VideoProcAmp_ColorEnable, VideoProcAmp_Contrast, VideoProcAmp_ColorEnable, VideoProcAmp_Contrast, VideoProcAmp_Gain,
VideoProcAmp_Gain, VideoProcAmp_Gamma, VideoProcAmp_Hue, VideoProcAmp_Gamma, VideoProcAmp_Hue, VideoProcAmp_Saturation,
VideoProcAmp_Saturation, VideoProcAmp_Sharpness, VideoProcAmp_WhiteBalance, VideoProcAmp_Sharpness, VideoProcAmp_WhiteBalance,
}, },
KernelStreaming::GUID_NULL, KernelStreaming::GUID_NULL,
MediaFoundation::{ MediaFoundation::{
@@ -120,53 +114,52 @@ pub mod wmf {
const MEDIA_FOUNDATION_FIRST_VIDEO_STREAM: u32 = 0xFFFF_FFFC; const MEDIA_FOUNDATION_FIRST_VIDEO_STREAM: u32 = 0xFFFF_FFFC;
const MF_SOURCE_READER_MEDIASOURCE: u32 = 0xFFFF_FFFF; const MF_SOURCE_READER_MEDIASOURCE: u32 = 0xFFFF_FFFF;
const CAM_CTRL_AUTO: i32 = 0x0001; // const CAM_CTRL_AUTO: i32 = 0x0001;
const CAM_CTRL_MANUAL: i32 = 0x0002; // const CAM_CTRL_MANUAL: i32 = 0x0002;
macro_rules! define_controls { // macro_rules! define_controls {
( $( ($key:expr => ($property:ident, $min:ident, $max:ident, $step:ident, $default:ident, $flag:ident)) )* ) => { // ( $( ($key:expr => ($property:ident, $min:ident, $max:ident, $step:ident, $default:ident, $flag:ident)) )* ) => {
$( // $(
$key => { // $key => {
if let Err(why) = unsafe { // if let Err(why) = unsafe {
video_proc_amp.GetRange( // video_proc_amp.GetRange(
$property.0, // $property.0,
&mut $min, // &mut $min,
&mut $max, // &mut $max,
&mut $step, // &mut $step,
&mut $default, // &mut $default,
&mut $flag, // &mut $flag,
) // )
} { // } {
return Err(NokhwaError::GetPropertyError { // return Err(NokhwaError::GetPropertyError {
property: stringify!($key).to_string(), // property: stringify!($key).to_string(),
error: why.to_string() // error: why.to_string()
}); // });
} // }
} // }
)* // )*
}; // };
( $( ($key:expr : ($property:ident, $value:ident, $flag:ident)) )* ) => { // ( $( ($key:expr : ($property:ident, $value:ident, $flag:ident)) )* ) => {
$( // $(
$key => { // $key => {
if let Err(why) = unsafe { // if let Err(why) = unsafe {
video_proc_amp.Get($property.0, &mut $value, &mut $flag) // video_proc_amp.Get($property.0, &mut $value, &mut $flag)
} { // } {
return Err(NokhwaError::GetPropertyError { // return Err(NokhwaError::GetPropertyError {
property: stringify!($key).to_string(), // property: stringify!($key).to_string(),
error: why.to_string() // error: why.to_string()
}); // });
} // }
} // }
)* // )*
}; // };
} // }
pub fn initialize_mf() -> Result<(), NokhwaError> { pub fn initialize_mf() -> Result<(), NokhwaError> {
if !(INITIALIZED.load(Ordering::SeqCst)) { if !(INITIALIZED.load(Ordering::SeqCst)) {
let a = std::ptr::null_mut(); if let Err(why) = unsafe {
if let Err(why) = CoInitializeEx(None, CO_INIT_APARTMENT_THREADED | CO_INIT_DISABLE_OLE1DDE)
unsafe { CoInitializeEx(a, CO_INIT_APARTMENT_THREADED | CO_INIT_DISABLE_OLE1DDE) } } {
{
return Err(NokhwaError::InitializeError { return Err(NokhwaError::InitializeError {
backend: ApiBackend::MediaFoundation, backend: ApiBackend::MediaFoundation,
error: why.to_string(), error: why.to_string(),
@@ -270,15 +263,15 @@ pub mod wmf {
imf_activate: &IMFActivate, imf_activate: &IMFActivate,
) -> Result<CameraInfo, NokhwaError> { ) -> Result<CameraInfo, NokhwaError> {
let mut pwstr_name = PWSTR(&mut 0_u16); let mut pwstr_name = PWSTR(&mut 0_u16);
let mut _len_pwstrname = 0; let mut len_pwstrname = 0;
let mut pwstr_symlink = PWSTR(&mut 0_u16); let mut pwstr_symlink = PWSTR(&mut 0_u16);
let mut _len_pwstrsymlink = 0; let mut len_pwstrsymlink = 0;
if let Err(why) = unsafe { if let Err(why) = unsafe {
imf_activate.GetAllocatedString( imf_activate.GetAllocatedString(
&MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, &MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME,
&mut pwstr_name, &mut pwstr_name,
&mut _len_pwstrname, &mut len_pwstrname,
) )
} { } {
return Err(NokhwaError::GetPropertyError { return Err(NokhwaError::GetPropertyError {
@@ -291,7 +284,7 @@ pub mod wmf {
imf_activate.GetAllocatedString( imf_activate.GetAllocatedString(
&MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK,
&mut pwstr_symlink, &mut pwstr_symlink,
&mut _len_pwstrsymlink, &mut len_pwstrsymlink,
) )
} { } {
return Err(NokhwaError::GetPropertyError { return Err(NokhwaError::GetPropertyError {
@@ -358,7 +351,8 @@ pub mod wmf {
CCRange(i32), CCRange(i32),
} }
pub fn kcc_to_i32(kcc: KnownCameraControl) -> Option<MFControlId> { #[allow(clippy::cast_sign_loss)]
fn kcc_to_i32(kcc: KnownCameraControl) -> Option<MFControlId> {
let control_id = match kcc { let control_id = match kcc {
KnownCameraControl::Brightness => MFControlId::ProcAmpRange(VideoProcAmp_Brightness.0), KnownCameraControl::Brightness => MFControlId::ProcAmpRange(VideoProcAmp_Brightness.0),
KnownCameraControl::Contrast => MFControlId::ProcAmpRange(VideoProcAmp_Contrast.0), KnownCameraControl::Contrast => MFControlId::ProcAmpRange(VideoProcAmp_Contrast.0),
@@ -380,7 +374,7 @@ pub mod wmf {
KnownCameraControl::Iris => MFControlId::CCValue(CameraControl_Iris.0), KnownCameraControl::Iris => MFControlId::CCValue(CameraControl_Iris.0),
KnownCameraControl::Focus => MFControlId::CCValue(CameraControl_Focus.0), KnownCameraControl::Focus => MFControlId::CCValue(CameraControl_Focus.0),
KnownCameraControl::Other(o) => { KnownCameraControl::Other(o) => {
if o == VideoProcAmp_ColorEnable as u128 { if o == VideoProcAmp_ColorEnable.0 as u128 {
MFControlId::ProcAmpRange(o as i32) MFControlId::ProcAmpRange(o as i32)
} else { } else {
return None; return None;
@@ -391,14 +385,14 @@ pub mod wmf {
Some(control_id) Some(control_id)
} }
pub struct MediaFoundationDevice<'a> { pub struct MediaFoundationDevice {
is_open: Cell<bool>, is_open: Cell<bool>,
device_specifier: CameraInfo, device_specifier: CameraInfo,
device_format: CameraFormat, device_format: CameraFormat,
source_reader: IMFSourceReader, source_reader: IMFSourceReader,
} }
impl<'a> MediaFoundationDevice<'a> { impl MediaFoundationDevice {
pub fn new(index: CameraIndex) -> Result<Self, NokhwaError> { pub fn new(index: CameraIndex) -> Result<Self, NokhwaError> {
match index { match index {
CameraIndex::Index(i) => { CameraIndex::Index(i) => {
@@ -477,7 +471,7 @@ pub mod wmf {
Ok(MediaFoundationDevice { Ok(MediaFoundationDevice {
is_open: Cell::new(false), is_open: Cell::new(false),
device_specifier: device_descriptor, device_specifier: device_descriptor,
device_format: MFCameraFormat::default(), device_format: CameraFormat::default(),
source_reader, source_reader,
}) })
} }
@@ -494,9 +488,7 @@ pub mod wmf {
match id_eq { match id_eq {
Some(index) => Self::new(CameraIndex::Index(index)), Some(index) => Self::new(CameraIndex::Index(index)),
None => { None => Err(NokhwaError::OpenDeviceError(s, "Not Found".to_string())),
return Err(NokhwaError::OpenDeviceError(s, "Not Found".to_string()))
}
} }
} }
} }
@@ -673,13 +665,15 @@ pub mod wmf {
MF_SOURCE_READER_MEDIASOURCE, MF_SOURCE_READER_MEDIASOURCE,
&GUID_NULL, &GUID_NULL,
&IAMCameraControl::IID, &IAMCameraControl::IID,
(ptr_receiver as *mut IAMCameraControl).cast::<*mut std::ffi::c_void>(), ptr_receiver
.cast::<IAMCameraControl>()
.cast::<*mut c_void>(),
) { ) {
return Err(BindingError::GUIDSetError( return Err(NokhwaError::SetPropertyError {
"MF_SOURCE_READER_MEDIASOURCE".to_string(), property: "MF_SOURCE_READER_MEDIASOURCE".to_string(),
"IAMCameraControl".to_string(), value: "IAMCameraControl".to_string(),
why.to_string(), error: why.to_string(),
)); });
} }
receiver.assume_init() receiver.assume_init()
}; };
@@ -690,13 +684,13 @@ pub mod wmf {
MF_SOURCE_READER_MEDIASOURCE, MF_SOURCE_READER_MEDIASOURCE,
&GUID_NULL, &GUID_NULL,
&IAMVideoProcAmp::IID, &IAMVideoProcAmp::IID,
(ptr_receiver as *mut IAMVideoProcAmp).cast::<*mut std::ffi::c_void>(), ptr_receiver.cast::<IAMVideoProcAmp>().cast::<*mut c_void>(),
) { ) {
return Err(BindingError::GUIDSetError( return Err(NokhwaError::SetPropertyError {
"MF_SOURCE_READER_MEDIASOURCE".to_string(), property: "MF_SOURCE_READER_MEDIASOURCE".to_string(),
"IAMVideoProcAmp".to_string(), value: "IAMVideoProcAmp".to_string(),
why.to_string(), error: why.to_string(),
)); });
} }
receiver.assume_init() receiver.assume_init()
}; };
@@ -764,11 +758,11 @@ pub mod wmf {
}); });
} }
ControlValueDescription::IntegerRange { ControlValueDescription::IntegerRange {
min: min as i64, min: i64::from(min),
max: max as i64, max: i64::from(max),
value: value as i64, value: i64::from(value),
step: step as i64, step: i64::from(step),
default: default as i64, default: i64::from(default),
} }
}, },
MFControlId::CCValue(id) => unsafe { MFControlId::CCValue(id) => unsafe {
@@ -793,9 +787,9 @@ pub mod wmf {
} }
ControlValueDescription::Integer { ControlValueDescription::Integer {
value: value as i64, value: i64::from(value),
default: default as i64, default: i64::from(default),
step: step as i64, step: i64::from(step),
} }
}, },
MFControlId::CCRange(id) => unsafe { MFControlId::CCRange(id) => unsafe {
@@ -819,16 +813,16 @@ pub mod wmf {
}); });
} }
ControlValueDescription::IntegerRange { ControlValueDescription::IntegerRange {
min: min as i64, min: i64::from(min),
max: max as i64, max: i64::from(max),
value: value as i64, value: i64::from(value),
step: step as i64, step: i64::from(step),
default: default as i64, default: i64::from(default),
} }
}, },
}; };
let is_manual = if matches!(flag, CameraControl_Flags_Manual) { let is_manual = if flag == CameraControl_Flags_Manual.0 {
KnownCameraControlFlag::Manual KnownCameraControlFlag::Manual
} else { } else {
KnownCameraControlFlag::Automatic KnownCameraControlFlag::Automatic
@@ -857,13 +851,15 @@ pub mod wmf {
MF_SOURCE_READER_MEDIASOURCE, MF_SOURCE_READER_MEDIASOURCE,
&GUID_NULL, &GUID_NULL,
&IAMCameraControl::IID, &IAMCameraControl::IID,
(ptr_receiver as *mut IAMCameraControl).cast::<*mut std::ffi::c_void>(), ptr_receiver
.cast::<IAMCameraControl>()
.cast::<*mut c_void>(),
) { ) {
return Err(BindingError::GUIDSetError( return Err(NokhwaError::SetPropertyError {
"MF_SOURCE_READER_MEDIASOURCE".to_string(), property: "MF_SOURCE_READER_MEDIASOURCE".to_string(),
"IAMCameraControl".to_string(), value: "IAMCameraControl".to_string(),
why.to_string(), error: why.to_string(),
)); });
} }
receiver.assume_init() receiver.assume_init()
}; };
@@ -874,13 +870,13 @@ pub mod wmf {
MF_SOURCE_READER_MEDIASOURCE, MF_SOURCE_READER_MEDIASOURCE,
&GUID_NULL, &GUID_NULL,
&IAMVideoProcAmp::IID, &IAMVideoProcAmp::IID,
(ptr_receiver as *mut IAMVideoProcAmp).cast::<*mut std::ffi::c_void>(), ptr_receiver.cast::<IAMVideoProcAmp>().cast::<*mut c_void>(),
) { ) {
return Err(BindingError::GUIDSetError( return Err(NokhwaError::SetPropertyError {
"MF_SOURCE_READER_MEDIASOURCE".to_string(), property: "MF_SOURCE_READER_MEDIASOURCE".to_string(),
"IAMVideoProcAmp".to_string(), value: "IAMVideoProcAmp".to_string(),
why.to_string(), error: why.to_string(),
)); });
} }
receiver.assume_init() receiver.assume_init()
}; };
@@ -893,7 +889,7 @@ pub mod wmf {
let ctrl_value = match value { let ctrl_value = match value {
ControlValueSetter::Integer(i) => i as i32, ControlValueSetter::Integer(i) => i as i32,
ControlValueSetter::Boolean(b) => b as i32, ControlValueSetter::Boolean(b) => i32::from(b),
v => { v => {
return Err(NokhwaError::StructureError { return Err(NokhwaError::StructureError {
structure: format!("ControlValueSetter {}", v), structure: format!("ControlValueSetter {}", v),
@@ -906,7 +902,7 @@ pub mod wmf {
.flag() .flag()
.get(0) .get(0)
.map(|x| { .map(|x| {
if x == KnownCameraControlFlag::Automatic { if *x == KnownCameraControlFlag::Automatic {
CameraControl_Flags_Auto CameraControl_Flags_Auto
} else { } else {
CameraControl_Flags_Manual CameraControl_Flags_Manual
@@ -941,6 +937,7 @@ pub mod wmf {
Ok(()) Ok(())
} }
#[allow(clippy::cast_sign_loss)]
pub fn format_refreshed(&mut self) -> Result<CameraFormat, NokhwaError> { pub fn format_refreshed(&mut self) -> Result<CameraFormat, NokhwaError> {
match unsafe { match unsafe {
self.source_reader self.source_reader
@@ -983,7 +980,7 @@ pub mod wmf {
_ => { _ => {
return Err(NokhwaError::GetPropertyError { return Err(NokhwaError::GetPropertyError {
property: "MF_MT_SUBTYPE".to_string(), property: "MF_MT_SUBTYPE".to_string(),
error: why.to_string(), error: "Unknown".to_string(),
}) })
} }
}, },
@@ -1038,6 +1035,11 @@ pub mod wmf {
FrameFormat::MJPEG => MF_VIDEO_FORMAT_MJPEG, FrameFormat::MJPEG => MF_VIDEO_FORMAT_MJPEG,
FrameFormat::YUYV => MF_VIDEO_FORMAT_YUY2, FrameFormat::YUYV => MF_VIDEO_FORMAT_YUY2,
FrameFormat::GRAY => MF_VIDEO_FORMAT_GRAY, FrameFormat::GRAY => MF_VIDEO_FORMAT_GRAY,
FrameFormat::RAWRGB => {
return Err(NokhwaError::NotImplementedError(
"RGB24 not implemented".to_string(),
))
} // TODO: Implement RGB24
}; };
// setting to the new media_type // setting to the new media_type
if let Err(why) = unsafe { media_type.SetGUID(&MF_MT_MAJOR_TYPE, &MFMediaType_Video) } { if let Err(why) = unsafe { media_type.SetGUID(&MF_MT_MAJOR_TYPE, &MFMediaType_Video) } {
@@ -1050,7 +1052,7 @@ pub mod wmf {
if let Err(why) = unsafe { media_type.SetGUID(&MF_MT_SUBTYPE, &fourcc) } { if let Err(why) = unsafe { media_type.SetGUID(&MF_MT_SUBTYPE, &fourcc) } {
return Err(NokhwaError::SetPropertyError { return Err(NokhwaError::SetPropertyError {
property: "MF_MT_SUBTYPE".to_string(), property: "MF_MT_SUBTYPE".to_string(),
value: fourcc.to_string(), value: format!("{:?}", fourcc),
error: why.to_string(), error: why.to_string(),
}); });
} }
@@ -1083,11 +1085,10 @@ pub mod wmf {
}); });
} }
let reserved = std::ptr::null_mut();
if let Err(why) = unsafe { if let Err(why) = unsafe {
self.source_reader.SetCurrentMediaType( self.source_reader.SetCurrentMediaType(
MEDIA_FOUNDATION_FIRST_VIDEO_STREAM, MEDIA_FOUNDATION_FIRST_VIDEO_STREAM,
reserved, None,
&media_type, &media_type,
) )
} { } {
@@ -1118,20 +1119,18 @@ pub mod wmf {
Ok(()) Ok(())
} }
pub fn raw_bytes(&mut self) -> Result<Cow<'a, [u8]>, NokhwaError> { pub fn raw_bytes(&mut self) -> Result<Cow<[u8]>, NokhwaError> {
let mut flags: u32 = 0;
let mut imf_sample: Option<IMFSample> = None; let mut imf_sample: Option<IMFSample> = None;
{ {
loop { loop {
if let Err(why) = unsafe { if let Err(why) = unsafe {
self.source_reader.ReadSample( self.source_reader.ReadSample(
MEDIA_FOUNDATION_FIRST_VIDEO_STREAM, MEDIA_FOUNDATION_FIRST_VIDEO_STREAM,
0, 0,
std::ptr::null_mut(), None,
&mut flags, None,
std::ptr::null_mut(), None,
&mut imf_sample, Some(&mut imf_sample),
) )
} { } {
return Err(NokhwaError::ReadFrameError(why.to_string())); return Err(NokhwaError::ReadFrameError(why.to_string()));
@@ -1147,7 +1146,7 @@ pub mod wmf {
Some(sample) => sample, Some(sample) => sample,
None => { None => {
// shouldn't happen // shouldn't happen
return Err(NokhwaError::ReadFrameError(why.to_string())); return Err(NokhwaError::ReadFrameError("No sample".to_string()));
} }
}; };
@@ -1159,13 +1158,9 @@ pub mod wmf {
let mut buffer_valid_length = 0; let mut buffer_valid_length = 0;
let mut buffer_start_ptr = std::ptr::null_mut::<u8>(); let mut buffer_start_ptr = std::ptr::null_mut::<u8>();
if let Err(why) = unsafe { if let Err(why) =
buffer.Lock( unsafe { buffer.Lock(&mut buffer_start_ptr, None, Some(&mut buffer_valid_length)) }
&mut buffer_start_ptr, {
std::ptr::null_mut(),
&mut buffer_valid_length,
)
} {
return Err(NokhwaError::ReadFrameError(why.to_string())); return Err(NokhwaError::ReadFrameError(why.to_string()));
} }
@@ -1189,11 +1184,7 @@ pub mod wmf {
) as &[u8]); ) as &[u8]);
// swallow errors // swallow errors
if buffer if buffer
.Lock( .Lock(&mut buffer_start_ptr, None, Some(&mut buffer_valid_length))
&mut buffer_start_ptr,
std::ptr::null_mut(),
&mut buffer_valid_length,
)
.is_ok() .is_ok()
{} {}
} }
@@ -1206,7 +1197,7 @@ pub mod wmf {
} }
} }
impl<'a> Drop for MediaFoundationDevice<'a> { impl Drop for MediaFoundationDevice {
fn drop(&mut self) { fn drop(&mut self) {
// swallow errors // swallow errors
unsafe { unsafe {
@@ -1262,15 +1253,13 @@ pub mod wmf {
struct Empty; struct Empty;
pub struct MediaFoundationDevice<'a> { pub struct MediaFoundationDevice {
_phantom: &'a Empty,
camera: CameraIndex, camera: CameraIndex,
} }
impl<'a> MediaFoundationDevice<'a> { impl MediaFoundationDevice {
pub fn new(_index: CameraIndex) -> Result<Self, NokhwaError> { pub fn new(_index: CameraIndex) -> Result<Self, NokhwaError> {
Ok(MediaFoundationDevice { Ok(MediaFoundationDevice {
_phantom: &Empty,
camera: CameraIndex::Index(0), camera: CameraIndex::Index(0),
}) })
} }
+23 -63
View File
@@ -17,11 +17,12 @@ use nokhwa_bindings_windows::wmf::MediaFoundationDevice;
use nokhwa_core::{ use nokhwa_core::{
buffer::Buffer, buffer::Buffer,
error::NokhwaError, error::NokhwaError,
pixel_format::RgbFormat,
traits::CaptureBackendTrait, traits::CaptureBackendTrait,
types::{ types::{
all_known_camera_controls, ApiBackend, CameraControl, CameraFormat, CameraIndex, all_known_camera_controls, ApiBackend, CameraControl, CameraFormat, CameraIndex,
CameraInfo, ControlValueSetter, FrameFormat, KnownCameraControl, RequestedFormat, CameraInfo, ControlValueSetter, FrameFormat, KnownCameraControl, RequestedFormat,
Resolution, RequestedFormatType, Resolution,
}, },
}; };
use std::{borrow::Cow, collections::HashMap}; use std::{borrow::Cow, collections::HashMap};
@@ -38,12 +39,12 @@ use std::{borrow::Cow, collections::HashMap};
/// - The names may contain invalid characters since they were converted from UTF16. /// - The names may contain invalid characters since they were converted from UTF16.
/// - When you call new or drop the struct, `initialize`/`de_initialize` will automatically be called. /// - When you call new or drop the struct, `initialize`/`de_initialize` will automatically be called.
#[cfg_attr(feature = "docs-features", doc(cfg(feature = "input-msmf")))] #[cfg_attr(feature = "docs-features", doc(cfg(feature = "input-msmf")))]
pub struct MediaFoundationCaptureDevice<'a> { pub struct MediaFoundationCaptureDevice {
inner: MediaFoundationDevice<'a>, inner: MediaFoundationDevice,
info: CameraInfo, info: CameraInfo,
} }
impl<'a> MediaFoundationCaptureDevice<'a> { impl MediaFoundationCaptureDevice {
/// Creates a new capture device using the Media Foundation backend. Indexes are gives to devices by the OS, and usually numbered by order of discovery. /// Creates a new capture device using the Media Foundation backend. Indexes are gives to devices by the OS, and usually numbered by order of discovery.
/// # Errors /// # Errors
/// This function will error if Media Foundation fails to get the device. /// This function will error if Media Foundation fails to get the device.
@@ -52,28 +53,21 @@ impl<'a> MediaFoundationCaptureDevice<'a> {
let info = CameraInfo::new( let info = CameraInfo::new(
&mf_device.name(), &mf_device.name(),
&"MediaFoundation Camera Device".to_string(), "MediaFoundation Camera Device",
&mf_device.symlink(), &mf_device.symlink(),
index.clone(), index.clone(),
); );
let availible = mf_device let availible = mf_device.compatible_format_list()?;
.compatible_format_list()?
.into_iter()
.map(|x| {
let cf: CameraFormat = x.into();
cf
})
.collect::<Vec<CameraFormat>>();
let desired = camera_fmt let desired = camera_fmt
.fufill(&availible) .fulfill(&availible)
.ok_or(NokhwaError::InitializeError { .ok_or(NokhwaError::InitializeError {
backend: ApiBackend::MediaFoundation, backend: ApiBackend::MediaFoundation,
error: "Failed to fulfill requested format".to_string(), error: "Failed to fulfill requested format".to_string(),
})?; })?;
mf_device.set_format(desired.into())?; mf_device.set_format(desired)?;
let mut new_cam = MediaFoundationCaptureDevice { let mut new_cam = MediaFoundationCaptureDevice {
inner: mf_device, inner: mf_device,
@@ -86,7 +80,7 @@ impl<'a> MediaFoundationCaptureDevice<'a> {
/// Create a new Media Foundation Device with desired settings. /// Create a new Media Foundation Device with desired settings.
/// # Errors /// # Errors
/// This function will error if Media Foundation fails to get the device. /// This function will error if Media Foundation fails to get the device.
#[deprecated(since = "0.10", note = "please use `new` instead.")] #[deprecated(since = "0.10.0", note = "please use `new` instead.")]
pub fn new_with( pub fn new_with(
index: &CameraIndex, index: &CameraIndex,
width: u32, width: u32,
@@ -94,51 +88,28 @@ impl<'a> MediaFoundationCaptureDevice<'a> {
fps: u32, fps: u32,
fourcc: FrameFormat, fourcc: FrameFormat,
) -> Result<Self, NokhwaError> { ) -> Result<Self, NokhwaError> {
let camera_format = let camera_format = RequestedFormat::new::<RgbFormat>(RequestedFormatType::Exact(
RequestedFormat::Exact(CameraFormat::new_from(width, height, fourcc, fps)); CameraFormat::new_from(width, height, fourcc, fps),
));
MediaFoundationCaptureDevice::new(index, camera_format) MediaFoundationCaptureDevice::new(index, camera_format)
} }
/// Gets the list of supported [`KnownCameraControl`]s /// Gets the list of supported [`KnownCameraControl`]s
/// # Errors /// # Errors
/// May error if there is an error from `MediaFoundation`. /// May error if there is an error from `MediaFoundation`.
fn supported_camera_controls(&self) -> Result<Vec<KnownCameraControl>, NokhwaError> { pub fn supported_camera_controls(&self) -> Vec<KnownCameraControl> {
let mut supported_camera_controls: Vec<KnownCameraControl> = vec![]; let mut supported_camera_controls: Vec<KnownCameraControl> = vec![];
for camera_control in all_known_camera_controls() { for camera_control in all_known_camera_controls() {
let msmf_camera_control: MediaFoundationControls = match camera_control { if let Ok(supported) = self.inner.control(camera_control) {
KnownCameraControl::Brightness => MediaFoundationControls::Brightness, supported_camera_controls.push(supported.control());
KnownCameraControl::Contrast => MediaFoundationControls::Contrast,
KnownCameraControl::Hue => MediaFoundationControls::Hue,
KnownCameraControl::Saturation => MediaFoundationControls::Saturation,
KnownCameraControl::Sharpness => MediaFoundationControls::Sharpness,
KnownCameraControl::Gamma => MediaFoundationControls::Gamma,
KnownCameraControl::WhiteBalance => MediaFoundationControls::WhiteBalance,
KnownCameraControl::BacklightComp => MediaFoundationControls::BacklightComp,
KnownCameraControl::Gain => MediaFoundationControls::Gain,
KnownCameraControl::Pan => MediaFoundationControls::Pan,
KnownCameraControl::Tilt => MediaFoundationControls::Tilt,
KnownCameraControl::Zoom => MediaFoundationControls::Zoom,
KnownCameraControl::Exposure => MediaFoundationControls::Exposure,
KnownCameraControl::Iris => MediaFoundationControls::Iris,
KnownCameraControl::Focus => MediaFoundationControls::Focus,
KnownCameraControl::Other(id) => match id {
0 => MediaFoundationControls::ColorEnable,
1 => MediaFoundationControls::Roll,
_ => continue,
},
};
if let Ok(supported) = self.inner.control(msmf_camera_control) {
supported_camera_controls.push(supported.control().into());
} }
} }
supported_camera_controls
Ok(supported_camera_controls)
} }
} }
impl<'a> CaptureBackendTrait for MediaFoundationCaptureDevice<'a> { impl CaptureBackendTrait for MediaFoundationCaptureDevice {
fn backend(&self) -> ApiBackend { fn backend(&self) -> ApiBackend {
ApiBackend::MediaFoundation ApiBackend::MediaFoundation
} }
@@ -153,14 +124,11 @@ impl<'a> CaptureBackendTrait for MediaFoundationCaptureDevice<'a> {
} }
fn camera_format(&self) -> CameraFormat { fn camera_format(&self) -> CameraFormat {
self.inner.format().into() self.inner.format()
} }
fn set_camera_format(&mut self, new_fmt: CameraFormat) -> Result<(), NokhwaError> { fn set_camera_format(&mut self, new_fmt: CameraFormat) -> Result<(), NokhwaError> {
if let Err(why) = self.inner.set_format(new_fmt.into()) { self.inner.set_format(new_fmt)
return Err(why.into());
}
Ok(())
} }
fn compatible_list_by_resolution( fn compatible_list_by_resolution(
@@ -170,9 +138,7 @@ impl<'a> CaptureBackendTrait for MediaFoundationCaptureDevice<'a> {
let mf_camera_format_list = self.inner.compatible_format_list()?; let mf_camera_format_list = self.inner.compatible_format_list()?;
let mut resolution_map: HashMap<Resolution, Vec<u32>> = HashMap::new(); let mut resolution_map: HashMap<Resolution, Vec<u32>> = HashMap::new();
for mf_camera_format in mf_camera_format_list { for camera_format in mf_camera_format_list {
let camera_format: CameraFormat = mf_camera_format.into();
// check fcc // check fcc
if camera_format.format() != fourcc { if camera_format.format() != fourcc {
continue; continue;
@@ -199,9 +165,7 @@ impl<'a> CaptureBackendTrait for MediaFoundationCaptureDevice<'a> {
let mf_camera_format_list = self.inner.compatible_format_list()?; let mf_camera_format_list = self.inner.compatible_format_list()?;
let mut frame_format_list = vec![]; let mut frame_format_list = vec![];
for mf_camera_format in mf_camera_format_list { for camera_format in mf_camera_format_list {
let camera_format: CameraFormat = mf_camera_format.into();
if !frame_format_list.contains(&camera_format.format()) { if !frame_format_list.contains(&camera_format.format()) {
frame_format_list.push(camera_format.format()); frame_format_list.push(camera_format.format());
} }
@@ -271,11 +235,7 @@ impl<'a> CaptureBackendTrait for MediaFoundationCaptureDevice<'a> {
} }
fn open_stream(&mut self) -> Result<(), NokhwaError> { fn open_stream(&mut self) -> Result<(), NokhwaError> {
if let Err(why) = self.inner.start_stream() { self.inner.start_stream()
return Err(why.into());
}
Ok(())
} }
fn is_stream_open(&self) -> bool { fn is_stream_open(&self) -> bool {
+5 -15
View File
@@ -16,7 +16,7 @@
use nokhwa_core::{ use nokhwa_core::{
error::NokhwaError, error::NokhwaError,
types::{ApiBackend, CameraIndex, CameraInfo}, types::{ApiBackend, CameraInfo},
}; };
// TODO: Update as this goes // TODO: Update as this goes
@@ -207,12 +207,13 @@ fn query_uvc() -> Result<Vec<CameraInfo>, NokhwaError> {
#[cfg(feature = "input-gst")] #[cfg(feature = "input-gst")]
fn query_gstreamer() -> Result<Vec<CameraInfo>, NokhwaError> { fn query_gstreamer() -> Result<Vec<CameraInfo>, NokhwaError> {
use crate::CameraIndex;
use gstreamer::{ use gstreamer::{
prelude::{DeviceExt, DeviceMonitorExt, DeviceMonitorExtManual}, prelude::{DeviceExt, DeviceMonitorExt, DeviceMonitorExtManual},
Caps, DeviceMonitor, Caps, DeviceMonitor,
}; };
use nokhwa_core::types::CameraIndex;
use std::str::FromStr; use std::str::FromStr;
if let Err(why) = gstreamer::init() { if let Err(why) = gstreamer::init() {
return Err(NokhwaError::GeneralError(format!( return Err(NokhwaError::GeneralError(format!(
"Failed to init gstreamer: {}", "Failed to init gstreamer: {}",
@@ -270,19 +271,8 @@ fn query_gstreamer() -> Result<Vec<CameraInfo>, NokhwaError> {
// please refer to https://docs.microsoft.com/en-us/windows/win32/medfound/enumerating-video-capture-devices // please refer to https://docs.microsoft.com/en-us/windows/win32/medfound/enumerating-video-capture-devices
#[cfg(all(feature = "input-msmf", target_os = "windows"))] #[cfg(all(feature = "input-msmf", target_os = "windows"))]
fn query_msmf<'a>() -> Result<Vec<CameraInfo<'a>>, NokhwaError> { fn query_msmf() -> Result<Vec<CameraInfo>, NokhwaError> {
let list: Vec<CameraInfo> = nokhwa_bindings_windows::wmf::query_media_foundation_descriptors()
match nokhwa_bindings_windows::wmf::query_media_foundation_descriptors() {
Ok(l) => l
.into_iter()
.map(|mf_desc| {
let camera_info: CameraInfo = mf_desc.into();
camera_info
})
.collect(),
Err(why) => return Err(why.into()),
};
Ok(list)
} }
#[cfg(any(not(feature = "input-msmf"), not(target_os = "windows")))] #[cfg(any(not(feature = "input-msmf"), not(target_os = "windows")))]