mirror of
https://github.com/l1npengtul/nokhwa.git
synced 2026-07-04 02:27:26 +00:00
264 lines
9.0 KiB
Rust
264 lines
9.0 KiB
Rust
/*
|
|
* Copyright 2022 l1npengtul <l1npengtul@protonmail.com> / The Nokhwa Contributors
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
use nokhwa_bindings_windows::wmf::MediaFoundationDevice;
|
|
use nokhwa_core::{
|
|
frame_buffer::FrameBuffer,
|
|
error::NokhwaError,
|
|
pixel_format::RgbFormat,
|
|
traits::CaptureTrait,
|
|
types::{
|
|
ApiBackend, CameraFormat, CameraIndex,
|
|
CameraInfo, FrameFormat, RequestedFormat,
|
|
RequestedFormatType, Resolution,
|
|
},
|
|
};
|
|
use std::{borrow::Cow, collections::HashMap};
|
|
use nokhwa_core::properties::{all_known_camera_controls, CameraControl, ControlValue, KnownCameraControl};
|
|
|
|
/// The backend that deals with Media Foundation on Windows.
|
|
/// To see what this does, please see [`CaptureTrait`].
|
|
///
|
|
/// Note: This requires Windows 7 or newer to work.
|
|
/// # Quirks
|
|
/// - This does build on non-windows platforms, however when you do the backend will be empty and will return an error for any given operation.
|
|
/// - Please check [`nokhwa-bindings-windows`](https://github.com/l1npengtul/nokhwa/tree/senpai/nokhwa-bindings-windows) source code to see the internal raw interface.
|
|
/// - The symbolic link for the device is listed in the `misc` attribute of the [`CameraInfo`].
|
|
/// - 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.
|
|
#[cfg_attr(feature = "docs-features", doc(cfg(feature = "input-msmf")))]
|
|
pub struct MediaFoundationCaptureDevice {
|
|
inner: MediaFoundationDevice,
|
|
info: CameraInfo,
|
|
}
|
|
|
|
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.
|
|
/// # Errors
|
|
/// This function will error if Media Foundation fails to get the device.
|
|
pub fn new(index: &CameraIndex, camera_fmt: RequestedFormat) -> Result<Self, NokhwaError> {
|
|
let mut mf_device = MediaFoundationDevice::new(index.clone())?;
|
|
|
|
let info = CameraInfo::new(
|
|
&mf_device.name(),
|
|
"MediaFoundation Camera Device",
|
|
&mf_device.symlink(),
|
|
index.clone(),
|
|
);
|
|
|
|
let availible = mf_device.compatible_format_list()?;
|
|
|
|
let desired = camera_fmt
|
|
.fulfill(&availible)
|
|
.ok_or(NokhwaError::InitializeError {
|
|
backend: ApiBackend::MediaFoundation,
|
|
error: "Failed to fulfill requested format".to_string(),
|
|
})?;
|
|
|
|
mf_device.set_format(desired)?;
|
|
|
|
let mut new_cam = MediaFoundationCaptureDevice {
|
|
inner: mf_device,
|
|
info,
|
|
};
|
|
new_cam.refresh_camera_format()?;
|
|
Ok(new_cam)
|
|
}
|
|
|
|
/// Create a new Media Foundation Device with desired settings.
|
|
/// # Errors
|
|
/// This function will error if Media Foundation fails to get the device.
|
|
#[deprecated(since = "0.10.0", note = "please use `new` instead.")]
|
|
pub fn new_with(
|
|
index: &CameraIndex,
|
|
width: u32,
|
|
height: u32,
|
|
fps: u32,
|
|
fourcc: FrameFormat,
|
|
) -> Result<Self, NokhwaError> {
|
|
let camera_format = RequestedFormat::new::<RgbFormat>(RequestedFormatType::Exact(
|
|
CameraFormat::new_from(width, height, fourcc, fps),
|
|
));
|
|
MediaFoundationCaptureDevice::new(index, camera_format)
|
|
}
|
|
|
|
/// Gets the list of supported [`KnownCameraControl`]s
|
|
/// # Errors
|
|
/// May error if there is an error from `MediaFoundation`.
|
|
pub fn supported_camera_controls(&self) -> Vec<KnownCameraControl> {
|
|
let mut supported_camera_controls: Vec<KnownCameraControl> = vec![];
|
|
|
|
for camera_control in all_known_camera_controls() {
|
|
if let Ok(supported) = self.inner.control(camera_control) {
|
|
supported_camera_controls.push(supported.control());
|
|
}
|
|
}
|
|
supported_camera_controls
|
|
}
|
|
}
|
|
|
|
impl CaptureTrait for MediaFoundationCaptureDevice {
|
|
fn backend(&self) -> ApiBackend {
|
|
ApiBackend::MediaFoundation
|
|
}
|
|
|
|
fn camera_info(&self) -> &CameraInfo {
|
|
&self.info
|
|
}
|
|
|
|
fn refresh_camera_format(&mut self) -> Result<(), NokhwaError> {
|
|
let _ = self.inner.format_refreshed()?;
|
|
Ok(())
|
|
}
|
|
|
|
fn camera_format(&self) -> CameraFormat {
|
|
self.inner.format()
|
|
}
|
|
|
|
fn set_camera_format(&mut self, new_fmt: CameraFormat) -> Result<(), NokhwaError> {
|
|
self.inner.set_format(new_fmt)
|
|
}
|
|
|
|
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 camera_format in mf_camera_format_list {
|
|
// check fcc
|
|
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 camera_format in mf_camera_format_list {
|
|
if !frame_format_list.contains(&camera_format.format()) {
|
|
frame_format_list.push(camera_format.format());
|
|
}
|
|
|
|
// TODO: Update as we get more frame formats!
|
|
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 camera_control(&self, control: KnownCameraControl) -> Result<CameraControl, NokhwaError> {
|
|
self.inner.control(control)
|
|
}
|
|
|
|
fn camera_controls(&self) -> Result<Vec<CameraControl>, NokhwaError> {
|
|
let mut camera_ctrls = Vec::with_capacity(15);
|
|
for ctrl_id in all_known_camera_controls() {
|
|
let ctrl = match self.camera_control(ctrl_id) {
|
|
Ok(v) => v,
|
|
Err(_) => continue,
|
|
};
|
|
|
|
camera_ctrls.push(ctrl);
|
|
}
|
|
camera_ctrls.shrink_to_fit();
|
|
Ok(camera_ctrls)
|
|
}
|
|
|
|
fn set_camera_control(
|
|
&mut self,
|
|
id: KnownCameraControl,
|
|
value: ControlValue,
|
|
) -> Result<(), NokhwaError> {
|
|
self.inner.set_control(id, value)
|
|
}
|
|
|
|
fn open_stream(&mut self) -> Result<(), NokhwaError> {
|
|
self.inner.start_stream()
|
|
}
|
|
|
|
fn is_stream_open(&self) -> bool {
|
|
self.inner.is_stream_open()
|
|
}
|
|
|
|
fn frame(&mut self) -> Result<FrameBuffer, NokhwaError> {
|
|
self.refresh_camera_format()?;
|
|
let self_ctrl = self.camera_format();
|
|
Ok(FrameBuffer::new(
|
|
self_ctrl.resolution(),
|
|
&self.inner.raw_bytes()?,
|
|
self_ctrl.format(),
|
|
))
|
|
}
|
|
|
|
fn frame_raw(&mut self) -> Result<Cow<[u8]>, NokhwaError> {
|
|
self.inner.raw_bytes()
|
|
}
|
|
|
|
fn stop_stream(&mut self) -> Result<(), NokhwaError> {
|
|
self.inner.stop_stream();
|
|
Ok(())
|
|
}
|
|
}
|