diff --git a/Cargo.toml b/Cargo.toml index 53d0a76..579b382 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -79,7 +79,7 @@ features = ["clang-runtime"] optional = true [dependencies.nokhwa-bindings-windows] -version = "0.3.4" +version = "0.3.3" path = "nokhwa-bindings-windows" optional = true diff --git a/examples/capture/src/main.rs b/examples/capture/src/main.rs index bdfda62..695320e 100644 --- a/examples/capture/src/main.rs +++ b/examples/capture/src/main.rs @@ -23,8 +23,7 @@ use glium::{ }; use glutin::{event_loop::EventLoop, window::WindowBuilder, ContextBuilder}; use nokhwa::{ - nokhwa_initialize, query_devices, Camera, CameraFormat, CameraIndex, CaptureAPIBackend, - FrameFormat, Resolution, + nokhwa_initialize, query_devices, Camera, CameraIndex, CaptureAPIBackend, FrameFormat, }; use std::time::Instant; @@ -195,7 +194,7 @@ fn main() { .parse::() { let mut camera = Camera::new_with( - &CameraIndex::Index(index as u32), + CameraIndex::Index(index as u32), width, height, fps, diff --git a/nokhwa-bindings-windows/Cargo.toml b/nokhwa-bindings-windows/Cargo.toml index c265e0c..4e6d1f1 100644 --- a/nokhwa-bindings-windows/Cargo.toml +++ b/nokhwa-bindings-windows/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nokhwa-bindings-windows" -version = "0.3.4" +version = "0.3.3" authors = ["l1npengtul"] edition = "2021" license = "Apache-2.0" @@ -19,3 +19,4 @@ lazy_static = "1.4.0" [target.'cfg(all(target_os = "windows", windows))'.dependencies.windows] version = "^0.28" features = ["alloc", "Win32_Media_MediaFoundation", "Win32_System_Com", "Win32_Foundation", "Win32_Media_DirectShow"] + diff --git a/nokhwa-bindings-windows/src/lib.rs b/nokhwa-bindings-windows/src/lib.rs index a35fcbd..81d4c14 100644 --- a/nokhwa-bindings-windows/src/lib.rs +++ b/nokhwa-bindings-windows/src/lib.rs @@ -61,7 +61,7 @@ pub enum BindingError { NotImplementedError, } -#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub struct MFResolution { pub width_x: u32, pub height_y: u32, @@ -73,7 +73,7 @@ pub enum MFFrameFormat { YUYV, } -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, Ord, PartialOrd)] +#[derive(Copy, Clone, Debug, Hash, PartialEq)] pub struct MFCameraFormat { resolution: MFResolution, format: MFFrameFormat, @@ -369,9 +369,7 @@ pub mod wmf { use std::{ borrow::Cow, cell::Cell, - collections::HashMap, mem::MaybeUninit, - ptr::null_mut, slice::from_raw_parts, sync::{ atomic::{AtomicBool, AtomicUsize, Ordering}, @@ -392,11 +390,11 @@ pub mod wmf { VideoProcAmp_Saturation, VideoProcAmp_Sharpness, VideoProcAmp_WhiteBalance, }, MediaFoundation::{ - IMFActivate, IMFAttributes, IMFMediaSource, IMFMediaType, IMFSample, - IMFSourceReader, MFCreateAttributes, MFCreateMediaType, - MFCreateSourceReaderFromMediaSource, MFEnumDeviceSources, MFMediaType_Video, - MFShutdown, MFStartup, MFSTARTUP_NOSOCKET, MF_API_VERSION, - MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, + IMFActivate, IMFAttributes, IMFMediaSource, IMFSample, IMFSourceReader, + MFCreateAttributes, MFCreateMediaType, MFCreateSourceReaderFromMediaSource, + MFEnumDeviceSources, MFMediaType_Video, MFShutdown, MFStartup, + MFSTARTUP_NOSOCKET, MF_API_VERSION, MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, + MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, MF_MEDIASOURCE_SERVICE, MF_MT_FRAME_RATE, MF_MT_FRAME_RATE_RANGE_MAX, @@ -576,7 +574,7 @@ pub mod wmf { } impl<'a> MediaFoundationDevice<'a> { - fn internal(index: usize) -> Result { + pub fn new(index: usize) -> Result { let (media_source, device_descriptor) = match query_activate_pointers()? .into_iter() .nth(index) @@ -648,28 +646,19 @@ pub mod wmf { }) } - pub fn new(index: usize, format: MFCameraFormat) -> Result { - let mut camera = MediaFoundationDevice::internal(index)?; - camera.set_format(format)?; - Ok(camera) - } - - pub fn with_string( - unique_id: &[u16], - format: MFCameraFormat, - ) -> Result { - let device_list = query_media_foundation_descriptors()?; + pub fn with_string(unique_id: &[u16]) -> Result { + let devicelist = query_media_foundation_descriptors()?; let mut id_eq = None; - for media_foundation_device in device_list { - if (media_foundation_device.symlink() as &[u16]) == unique_id { - id_eq = Some(media_foundation_device.index); + for mfdev in devicelist { + if (mfdev.symlink() as &[u16]) == unique_id { + id_eq = Some(mfdev.index); break; } } match id_eq { - Some(index) => Self::new(index, format), + Some(index) => Self::new(index), None => { return Err(BindingError::DeviceOpenFailError( std::str::from_utf8( @@ -695,24 +684,16 @@ pub mod wmf { self.device_specifier.link_as_string() } - fn internal_format_list( - &mut self, - ) -> Result, BindingError> { - let mut camera_format_map = HashMap::new(); + pub fn compatible_format_list(&mut self) -> Result, BindingError> { + let mut camera_format_list = vec![]; let mut index = 0; while let Ok(media_type) = unsafe { self.source_reader .GetNativeMediaType(MEDIA_FOUNDATION_FIRST_VIDEO_STREAM, index) } { - index += 1; - let fourcc = match unsafe { media_type.GetGUID(&MF_MT_SUBTYPE) } { - Ok(fcc) => match fcc { - MF_VIDEO_FORMAT_YUY2 => MFFrameFormat::YUYV, - MF_VIDEO_FORMAT_MJPEG => MFFrameFormat::MJPEG, - _ => continue, - }, + Ok(fcc) => fcc, Err(why) => { return Err(BindingError::GUIDReadError( "MF_MT_SUBTYPE".to_string(), @@ -789,60 +770,77 @@ pub mod wmf { } }; - if frame_rate_min != 0 { - camera_format_map.insert( - MFCameraFormat { + if fourcc == MF_VIDEO_FORMAT_MJPEG { + if frame_rate_min != 0 { + camera_format_list.push(MFCameraFormat { resolution: MFResolution { width_x: width, height_y: height, }, - format: fourcc, + format: MFFrameFormat::MJPEG, frame_rate: frame_rate_min, - }, - media_type.clone(), - ); - } + }); + } - if frame_rate != frame_rate_min && frame_rate != 0 { - camera_format_map.insert( - MFCameraFormat { + if frame_rate != 0 && frame_rate_min != frame_rate { + camera_format_list.push(MFCameraFormat { resolution: MFResolution { width_x: width, height_y: height, }, - format: fourcc, + format: MFFrameFormat::MJPEG, frame_rate, - }, - media_type.clone(), - ); - } + }); + } - if frame_rate_max != frame_rate - && frame_rate_max != frame_rate_min - && frame_rate_max != 0 - { - camera_format_map.insert( - MFCameraFormat { + if frame_rate_max != 0 && frame_rate != frame_rate_max { + camera_format_list.push(MFCameraFormat { resolution: MFResolution { width_x: width, height_y: height, }, - format: fourcc, + format: MFFrameFormat::MJPEG, frame_rate: frame_rate_max, - }, - media_type.clone(), - ); - } - } - Ok(camera_format_map) - } + }); + } + } else if fourcc == MF_VIDEO_FORMAT_YUY2 { + if frame_rate_min != 0 { + camera_format_list.push(MFCameraFormat { + resolution: MFResolution { + width_x: width, + height_y: height, + }, + format: MFFrameFormat::YUYV, + frame_rate: frame_rate_min, + }); + } - pub fn compatible_format_list(&mut self) -> Result, BindingError> { - Ok(self - .internal_format_list()? - .into_keys() - .into_iter() - .collect()) + if frame_rate != 0 && frame_rate_min != frame_rate { + camera_format_list.push(MFCameraFormat { + resolution: MFResolution { + width_x: width, + height_y: height, + }, + format: MFFrameFormat::YUYV, + frame_rate, + }); + } + + if frame_rate_max != 0 && frame_rate != frame_rate_max { + camera_format_list.push(MFCameraFormat { + resolution: MFResolution { + width_x: width, + height_y: height, + }, + format: MFFrameFormat::YUYV, + frame_rate: frame_rate_max, + }); + } + } + + index += 1; + } + Ok(camera_format_list) } pub fn control(&self, control: MediaFoundationControls) -> Result { @@ -1596,7 +1594,6 @@ pub mod wmf { } pub fn set_format(&mut self, format: MFCameraFormat) -> Result<(), BindingError> { - let mut index = 0; // convert to media_type let media_type = match unsafe { MFCreateMediaType() } { Ok(mt) => mt, @@ -1662,115 +1659,22 @@ pub mod wmf { )); } - while let Ok(media_type) = unsafe { - self.source_reader - .GetNativeMediaType(MEDIA_FOUNDATION_FIRST_VIDEO_STREAM, index) + let reserved = std::ptr::null_mut(); + if let Err(why) = unsafe { + self.source_reader.SetCurrentMediaType( + MEDIA_FOUNDATION_FIRST_VIDEO_STREAM, + reserved, + media_type.clone(), + ) } { - index += 1; - - let fourcc = match unsafe { media_type.GetGUID(&MF_MT_SUBTYPE) } { - Ok(fcc) => match fcc { - MF_VIDEO_FORMAT_YUY2 => MFFrameFormat::YUYV, - MF_VIDEO_FORMAT_MJPEG => MFFrameFormat::MJPEG, - _ => continue, - }, - Err(why) => { - return Err(BindingError::GUIDReadError( - "MF_MT_SUBTYPE".to_string(), - why.to_string(), - )) - } - }; - - let (width, height) = match unsafe { media_type.GetUINT64(&MF_MT_FRAME_SIZE) } { - Ok(res_u64) => { - let width = (res_u64 >> 32) as u32; - let height = res_u64 as u32; // the cast will truncate the upper bits - (width, height) - } - Err(why) => { - return Err(BindingError::GUIDReadError( - "MF_MT_FRAME_SIZE".to_string(), - why.to_string(), - )) - } - }; - - // MFRatio is represented as 2 u32s in memory. This means we cann convert it to 2 - let frame_rate_max = - match unsafe { media_type.GetUINT64(&MF_MT_FRAME_RATE_RANGE_MAX) } { - Ok(fraction_u64) => { - let mut numerator = (fraction_u64 >> 32) as u32; - let denominator = fraction_u64 as u32; - if denominator != 1 { - numerator = 0; - } - numerator - } - Err(why) => { - return Err(BindingError::GUIDReadError( - "MF_MT_FRAME_RATE_RANGE_MAX".to_string(), - why.to_string(), - )) - } - }; - - let frame_rate = match unsafe { media_type.GetUINT64(&MF_MT_FRAME_RATE) } { - Ok(fraction_u64) => { - let mut numerator = (fraction_u64 >> 32) as u32; - let denominator = fraction_u64 as u32; - if denominator != 1 { - numerator = 0; - } - numerator - } - Err(why) => { - return Err(BindingError::GUIDReadError( - "MF_MT_FRAME_RATE".to_string(), - why.to_string(), - )) - } - }; - - let frame_rate_min = - match unsafe { media_type.GetUINT64(&MF_MT_FRAME_RATE_RANGE_MIN) } { - Ok(fraction_u64) => { - let mut numerator = (fraction_u64 >> 32) as u32; - let denominator = fraction_u64 as u32; - if denominator != 1 { - numerator = 0; - } - numerator - } - Err(why) => { - return Err(BindingError::GUIDReadError( - "MF_MT_FRAME_RATE_RANGE_MIN".to_string(), - why.to_string(), - )) - } - }; - - if format.width() == width - && format.height() == height - && [frame_rate_max, frame_rate, frame_rate_min].contains(&format.frame_rate) - && format.format == fourcc - { - return match unsafe { - self.source_reader.SetCurrentMediaType( - MEDIA_FOUNDATION_FIRST_VIDEO_STREAM, - null_mut(), - media_type, - ) - } { - Ok(_) => { - self.device_format = format; - Ok(()) - } - Err(why) => Err(BindingError::AttributeError(why.to_string())), - }; - } + return Err(BindingError::GUIDSetError( + "MF_SOURCE_READER_FIRST_VIDEO_STREAM".to_string(), + format!("{:?}", media_type), + why.to_string(), + )); } - Err(BindingError::EnumerateError("Not Found".to_string())) + self.device_format = format; + Ok(()) } pub fn is_stream_open(&self) -> bool { @@ -1782,6 +1686,7 @@ pub mod wmf { self.source_reader .SetStreamSelection(MEDIA_FOUNDATION_FIRST_VIDEO_STREAM, true) } { + println!("a"); return Err(BindingError::ReadFrameError(why.to_string())); } diff --git a/src/backends/capture/msmf_backend.rs b/src/backends/capture/msmf_backend.rs index c5e522a..559dd76 100644 --- a/src/backends/capture/msmf_backend.rs +++ b/src/backends/capture/msmf_backend.rs @@ -47,18 +47,22 @@ impl<'a> MediaFoundationCaptureDevice<'a> { /// If `camera_format` is `None`, it will be spawned with with 640x480@15 FPS, MJPEG [`CameraFormat`] default. /// # Errors /// This function will error if Media Foundation fails to get the device. This will also error if the index is a [`CameraIndex::String`] that cannot be parsed into a `usize`. - pub fn new(index: &CameraIndex, camera_fmt: Option) -> Result { - let format = camera_fmt.unwrap_or_default(); + pub fn new( + index: &CameraIndex<'a>, + camera_fmt: Option, + ) -> Result { let mut mf_device = match &index { - CameraIndex::Index(idx) => MediaFoundationDevice::new(*idx as usize, format.into()), + CameraIndex::Index(idx) => MediaFoundationDevice::new(*idx as usize), CameraIndex::String(lnk) => MediaFoundationDevice::with_string( &lnk.as_bytes() .into_iter() .map(|x| *x as u16) .collect::>(), - format.into(), ), }?; + if let Some(fmt) = camera_fmt { + mf_device.set_format(fmt.into())?; + } let info = CameraInfo::new( mf_device.name(), @@ -77,7 +81,7 @@ impl<'a> MediaFoundationCaptureDevice<'a> { /// # Errors /// This function will error if Media Foundation fails to get the device. This will also error if the index is a [`CameraIndex::String`] that cannot be parsed into a `usize`. pub fn new_with( - index: &CameraIndex, + index: &CameraIndex<'a>, width: u32, height: u32, fps: u32,