Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Windows Hello IR sensors #107

Open
wants to merge 1 commit into
base: 0.10
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 39 additions & 3 deletions nokhwa-bindings-windows/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ pub mod wmf {
ControlValueSetter, FrameFormat, KnownCameraControl, KnownCameraControlFlag, Resolution,
};
use once_cell::sync::Lazy;
use windows::Win32::Media::KernelStreaming::KSCATEGORY_SENSOR_CAMERA;
use std::ffi::c_void;
use std::{
borrow::Cow,
Expand All @@ -48,7 +49,7 @@ pub mod wmf {
};
use windows::Win32::Media::DirectShow::{CameraControl_Flags_Auto, CameraControl_Flags_Manual};
use windows::Win32::Media::MediaFoundation::{
IMFMediaType, MFCreateSample, MF_SOURCE_READER_FIRST_VIDEO_STREAM,
IMFMediaType, MFCreateSample, MF_SOURCE_READER_FIRST_VIDEO_STREAM, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_CATEGORY,
};
use windows::{
core::{Interface, GUID, PWSTR},
Expand Down Expand Up @@ -117,6 +118,12 @@ pub mod wmf {
0x0010,
[0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71],
);
const MF_VIDEO_FORMAT_L8: GUID = GUID::from_values(
0x0000_0032,
0x0000,
0x0010,
[0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71],
);

const MEDIA_FOUNDATION_FIRST_VIDEO_STREAM: u32 = 0xFFFF_FFFC;
const MF_SOURCE_READER_MEDIASOURCE: u32 = 0xFFFF_FFFF;
Expand Down Expand Up @@ -169,6 +176,7 @@ pub mod wmf {
MF_VIDEO_FORMAT_GRAY => Some(FrameFormat::GRAY),
MF_VIDEO_FORMAT_YUY2 => Some(FrameFormat::YUYV),
MF_VIDEO_FORMAT_MJPEG => Some(FrameFormat::MJPEG),
MF_VIDEO_FORMAT_L8 => Some(FrameFormat::L8),
_ => None,
}
}
Expand All @@ -180,6 +188,7 @@ pub mod wmf {
FrameFormat::NV12 => MF_VIDEO_FORMAT_NV12,
FrameFormat::GRAY => MF_VIDEO_FORMAT_GRAY,
FrameFormat::RAWRGB => MF_VIDEO_FORMAT_RGB24,
FrameFormat::L8 => MF_VIDEO_FORMAT_L8,
}
}

Expand Down Expand Up @@ -227,6 +236,16 @@ pub mod wmf {
fn query_activate_pointers() -> Result<Vec<IMFActivate>, NokhwaError> {
initialize_mf()?;

let mut devices = query_activate_pointers_internal(false)?;
let mut sensors = query_activate_pointers_internal(true)?;

devices.append(&mut sensors);
Ok(devices)
}

fn query_activate_pointers_internal(
include_sensors: bool,
) -> Result<Vec<IMFActivate>, NokhwaError> {
let mut attributes: Option<IMFAttributes> = None;
if let Err(why) = unsafe { MFCreateAttributes(&mut attributes, 1) } {
return Err(NokhwaError::GetPropertyError {
Expand All @@ -249,6 +268,23 @@ pub mod wmf {
error: why.to_string(),
});
}

if include_sensors {
if let Err(why) = unsafe {
attr.SetGUID(
&MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_CATEGORY,
&KSCATEGORY_SENSOR_CAMERA,
)
} {
return Err(NokhwaError::SetPropertyError {
property: "GUID MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_CATEGORY"
.to_string(),
value: "KSCATEGORY_SENSOR_CAMERA".to_string(),
error: why.to_string(),
});
}
}

attr
}
None => {
Expand Down Expand Up @@ -569,6 +605,8 @@ pub mod wmf {
self.source_reader
.GetNativeMediaType(MEDIA_FOUNDATION_FIRST_VIDEO_STREAM, index)
} {
index += 1;

let fourcc = match unsafe { media_type.GetGUID(&MF_MT_SUBTYPE) } {
Ok(fcc) => fcc,
Err(why) => {
Expand Down Expand Up @@ -651,8 +689,6 @@ pub mod wmf {
));
}
}

index += 1;
}
Ok(camera_format_list)
}
Expand Down
11 changes: 8 additions & 3 deletions nokhwa-core/src/pixel_format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ impl FormatDecoder for RgbFormat {
.collect()),
FrameFormat::RAWRGB => Ok(data.to_vec()),
FrameFormat::NV12 => nv12_to_rgb(resolution, data, false),
FrameFormat::L8 => panic!("Unsupported conversion from L8 to RGB"),
}
}

Expand Down Expand Up @@ -112,6 +113,7 @@ impl FormatDecoder for RgbFormat {
Ok(())
}
FrameFormat::NV12 => buf_nv12_to_rgb(resolution, data, dest, false),
FrameFormat::L8 => panic!("Unsupported conversion from L8 to RGB"),
}
}
}
Expand Down Expand Up @@ -151,6 +153,7 @@ impl FormatDecoder for RgbAFormat {
.flat_map(|x| [x[0], x[1], x[2], 255])
.collect()),
FrameFormat::NV12 => nv12_to_rgb(resolution, data, true),
FrameFormat::L8 => panic!("Unsupported conversion from L8 to RGBA"),
}
}

Expand Down Expand Up @@ -194,6 +197,7 @@ impl FormatDecoder for RgbAFormat {
Ok(())
}
FrameFormat::NV12 => buf_nv12_to_rgb(resolution, data, dest, true),
FrameFormat::L8 => panic!("Unsupported conversion from L8 to RGB"),
}
}
}
Expand Down Expand Up @@ -253,6 +257,7 @@ impl FormatDecoder for LumaFormat {
.chunks(3)
.map(|px| ((i32::from(px[0]) + i32::from(px[1]) + i32::from(px[2])) / 3) as u8)
.collect()),
FrameFormat::L8 => Ok(data.to_vec()),
}
}

Expand All @@ -273,7 +278,7 @@ impl FormatDecoder for LumaFormat {
})
}

FrameFormat::GRAY => {
FrameFormat::GRAY | FrameFormat::L8 => {
data.iter().zip(dest.iter_mut()).for_each(|(pxv, d)| {
*d = *pxv;
});
Expand Down Expand Up @@ -337,7 +342,7 @@ impl FormatDecoder for LumaAFormat {
[(avg / 3) as u8, 255]
})
.collect()),
FrameFormat::GRAY => Ok(data.iter().flat_map(|x| [*x, 255]).collect()),
FrameFormat::GRAY | FrameFormat::L8 => Ok(data.iter().flat_map(|x| [*x, 255]).collect()),
FrameFormat::RAWRGB => Err(NokhwaError::ProcessFrameError {
src: fcc,
destination: "RGB => RGB".to_string(),
Expand Down Expand Up @@ -372,7 +377,7 @@ impl FormatDecoder for LumaAFormat {
destination: "NV12 => LumaA".to_string(),
error: "Conversion Error".to_string(),
}),
FrameFormat::GRAY => {
FrameFormat::GRAY | FrameFormat::L8 => {
if dest.len() != data.len() * 2 {
return Err(NokhwaError::ProcessFrameError {
src: fcc,
Expand Down
2 changes: 1 addition & 1 deletion nokhwa-core/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ pub trait CaptureBackendTrait {
let resolution = cfmt.resolution();
let pxwidth = match cfmt.format() {
FrameFormat::MJPEG | FrameFormat::YUYV | FrameFormat::RAWRGB | FrameFormat::NV12 => 3,
FrameFormat::GRAY => 1,
FrameFormat::GRAY | FrameFormat::L8 => 1,
};
if alpha {
return (resolution.width() * resolution.height() * (pxwidth + 1)) as usize;
Expand Down
4 changes: 4 additions & 0 deletions nokhwa-core/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ pub enum FrameFormat {
NV12,
GRAY,
RAWRGB,
L8,
}

impl Display for FrameFormat {
Expand All @@ -319,6 +320,7 @@ impl Display for FrameFormat {
FrameFormat::NV12 => {
write!(f, "NV12")
}
FrameFormat::L8 => write!(f, "L8"),
}
}
}
Expand All @@ -332,6 +334,7 @@ impl FromStr for FrameFormat {
"GRAY" => Ok(FrameFormat::GRAY),
"RAWRGB" => Ok(FrameFormat::RAWRGB),
"NV12" => Ok(FrameFormat::NV12),
"L8" => Ok(FrameFormat::L8),
_ => Err(NokhwaError::StructureError {
structure: "FrameFormat".to_string(),
error: format!("No match for {s}"),
Expand All @@ -349,6 +352,7 @@ pub const fn frame_formats() -> &'static [FrameFormat] {
FrameFormat::NV12,
FrameFormat::GRAY,
FrameFormat::RAWRGB,
FrameFormat::L8,
]
}

Expand Down
4 changes: 2 additions & 2 deletions src/backends/capture/msmf_backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,10 @@ impl MediaFoundationCaptureDevice {
index.clone(),
);

let availible = mf_device.compatible_format_list()?;
let available = mf_device.compatible_format_list()?;

let desired = camera_fmt
.fulfill(&availible)
.fulfill(&available)
.ok_or(NokhwaError::InitializeError {
backend: ApiBackend::MediaFoundation,
error: "Failed to fulfill requested format".to_string(),
Expand Down