Update MediaFoundation to latest methods, fix errors in CI

This commit is contained in:
l1npengtul
2021-11-30 00:54:42 +09:00
parent 5eddbc8520
commit 69c6c9c887
14 changed files with 195 additions and 144 deletions
+9 -3
View File
@@ -14,7 +14,8 @@ repository = "https://github.com/l1npengtul/nokhwa"
crate-type = ["cdylib", "rlib"]
[features]
default = ["flume"]
default = ["flume", "decoding"]
decoding = ["mozjpeg"]
input-v4l = ["v4l", "v4l2-sys-mit"]
input-msmf = ["nokhwa-bindings-windows"]
input-avfoundation = ["nokhwa-bindings-macos"]
@@ -35,7 +36,6 @@ test-fail-warning = []
[dependencies]
thiserror = "1.0.26"
paste = "1.0.5"
mozjpeg = "0.8.24"
[dependencies.flume]
version = "0.10.8"
@@ -45,6 +45,10 @@ optional = true
version = "^0.23"
default-features = false
[target.'cfg(not(target_arch = "wasm"))'.dependencies.mozjpeg]
version = "0.8.24"
optional = true
[target.'cfg(target_os = "linux")'.dependencies.v4l]
version = "0.12.1"
optional = true
@@ -75,11 +79,13 @@ features = ["clang-runtime"]
optional = true
[dependencies.nokhwa-bindings-windows]
version = "0.3.2"
version = "0.3.3"
path = "nokhwa-bindings-windows"
optional = true
[dependencies.nokhwa-bindings-macos]
version = "0.1.1"
path = "nokhwa-bindings-macos"
optional = true
[dependencies.gstreamer]
+12 -3
View File
@@ -22,7 +22,9 @@ use glium::{
IndexBuffer, Surface, Texture2d, VertexBuffer,
};
use glutin::{event_loop::EventLoop, window::WindowBuilder, ContextBuilder};
use nokhwa::{nokhwa_initialize, query_devices, Camera, CaptureAPIBackend, FrameFormat};
use nokhwa::{
nokhwa_initialize, query_devices, Camera, CameraIndex, CaptureAPIBackend, FrameFormat,
};
use std::time::Instant;
#[derive(Copy, Clone)]
@@ -191,8 +193,15 @@ fn main() {
.trim()
.parse::<usize>()
{
let mut camera =
Camera::new_with(index, width, height, fps, format, backend_value).unwrap();
let mut camera = Camera::new_with(
CameraIndex::Index(index as u32),
width,
height,
fps,
format,
backend_value,
)
.unwrap();
if matches_clone.is_present("query-device") {
match camera.compatible_fourcc() {
+2 -2
View File
@@ -1,7 +1,7 @@
[package]
name = "nokhwa-bindings-macos"
version = "0.1.1"
edition = "2018"
version = "0.1.2"
edition = "2021"
authors = ["l1npengtul"]
license = "Apache-2.0"
repository = "https://github.com/l1npengtul/nokhwa"
+5 -4
View File
@@ -1,8 +1,8 @@
[package]
name = "nokhwa-bindings-windows"
version = "0.3.2"
version = "0.3.3"
authors = ["l1npengtul"]
edition = "2018"
edition = "2021"
license = "Apache-2.0"
repository = "https://github.com/l1npengtul/nokhwa"
description = "The Windows Media Foundation bindings crate for `nokhwa`"
@@ -14,8 +14,9 @@ keywords = ["media-foundation", "windows", "capture", "webcam"]
thiserror = "^1.0"
[target.'cfg(all(target_os = "windows", windows))'.dependencies]
windows = "^0.28"
lazy_static = "1.4.0"
[target.'cfg(all(target_os = "windows", windows))'.build-dependencies.windows]
[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"]
-28
View File
@@ -1,28 +0,0 @@
/*
* Copyright 2021 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.
*/
#[cfg(all(windows, not(feature = "docs-only")))]
fn main() {
windows::build!(
Windows::Win32::Media::MediaFoundation::*,
Windows::Win32::System::Com::{CoInitializeEx, COINIT, CoUninitialize},
Windows::Win32::Foundation::{S_OK},
Windows::Win32::Graphics::DirectShow::*,
)
}
#[cfg(any(not(windows), feature = "docs-only"))]
fn main() {}
+133 -81
View File
@@ -16,7 +16,9 @@
#![deny(clippy::pedantic)]
#![warn(clippy::all)]
#![allow(clippy::must_use_candidate)]
#![allow(clippy::missing_errors_doc)]
#![allow(clippy::cast_possible_truncation)]
#![allow(clippy::too_many_lines)]
//! # nokhwa-bindings-windows
//! This crate is the `MediaFoundation` bindings for the `nokhwa` crate.
@@ -52,7 +54,7 @@ pub enum BindingError {
#[error("Failed to enumerate: {0}")]
EnumerateError(String),
#[error("Failed to open device {0}: {1}")]
DeviceOpenFailError(usize, String),
DeviceOpenFailError(String, String),
#[error("Failed to read frame: {0}")]
ReadFrameError(String),
#[error("Not Implemented!")]
@@ -92,6 +94,7 @@ impl Default for MFCameraFormat {
}
impl MFCameraFormat {
#[must_use]
pub fn new(resolution: MFResolution, format: MFFrameFormat, frame_rate: u32) -> Self {
MFCameraFormat {
resolution,
@@ -100,6 +103,7 @@ impl MFCameraFormat {
}
}
#[must_use]
pub fn new_from(res_x: u32, res_y: u32, format: MFFrameFormat, fps: u32) -> Self {
MFCameraFormat {
resolution: MFResolution {
@@ -111,14 +115,17 @@ impl MFCameraFormat {
}
}
#[must_use]
pub fn resolution(&self) -> MFResolution {
self.resolution
}
#[must_use]
pub fn width(&self) -> u32 {
self.resolution.width_x
}
#[must_use]
pub fn height(&self) -> u32 {
self.resolution.height_y
}
@@ -127,6 +134,7 @@ impl MFCameraFormat {
self.resolution = resolution;
}
#[must_use]
pub fn frame_rate(&self) -> u32 {
self.frame_rate
}
@@ -135,6 +143,7 @@ impl MFCameraFormat {
self.frame_rate = frame_rate;
}
#[must_use]
pub fn format(&self) -> MFFrameFormat {
self.format
}
@@ -182,22 +191,27 @@ impl<'a> MediaFoundationDeviceDescriptor<'a> {
})
}
#[must_use]
pub fn index(&self) -> usize {
self.index
}
#[must_use]
pub fn name(&self) -> &Cow<[u16]> {
&self.name
}
#[must_use]
pub fn symlink(&self) -> &Cow<[u16]> {
&self.symlink
}
#[must_use]
pub fn name_as_string(&self) -> String {
String::from_utf16_lossy(self.name.borrow())
}
#[must_use]
pub fn link_as_string(&self) -> String {
String::from_utf16_lossy(self.symlink.borrow())
}
@@ -250,6 +264,7 @@ pub struct MFControl {
impl MFControl {
#[allow(clippy::too_many_arguments)]
#[must_use]
pub fn new(
control: MediaFoundationControls,
min: i32,
@@ -272,6 +287,7 @@ impl MFControl {
}
}
#[must_use]
pub fn control(&self) -> MediaFoundationControls {
self.control
}
@@ -280,6 +296,7 @@ impl MFControl {
self.control = control;
}
#[must_use]
pub fn min(&self) -> i32 {
self.min
}
@@ -288,6 +305,7 @@ impl MFControl {
self.min = min;
}
#[must_use]
pub fn max(&self) -> i32 {
self.max
}
@@ -296,6 +314,7 @@ impl MFControl {
self.max = max;
}
#[must_use]
pub fn step(&self) -> i32 {
self.step
}
@@ -304,6 +323,7 @@ impl MFControl {
self.step = step;
}
#[must_use]
pub fn current(&self) -> i32 {
self.current
}
@@ -311,6 +331,7 @@ impl MFControl {
pub fn set_current(&mut self, current: i32) {
self.current = current;
}
#[must_use]
pub fn default(&self) -> i32 {
self.default
}
@@ -319,6 +340,7 @@ impl MFControl {
self.default = default;
}
#[must_use]
pub fn manual(&self) -> bool {
self.manual
}
@@ -327,6 +349,7 @@ impl MFControl {
self.manual = manual;
}
#[must_use]
pub fn active(&self) -> bool {
self.active
}
@@ -336,44 +359,16 @@ impl MFControl {
}
}
mod bindings {
#[cfg(all(windows, not(feature = "docs-only")))]
::windows::include_bindings!();
}
#[cfg(all(windows, not(feature = "docs-only")))]
pub mod wmf {
#![windows_subsystem = "windows"]
use crate::{
bindings::Windows::Win32::{
Foundation::PWSTR,
Graphics::DirectShow::{
CameraControl_Exposure, CameraControl_Focus, CameraControl_Iris, CameraControl_Pan,
CameraControl_Roll, CameraControl_Tilt, CameraControl_Zoom, IAMCameraControl,
IAMVideoProcAmp, VideoProcAmp_BacklightCompensation, VideoProcAmp_Brightness,
VideoProcAmp_ColorEnable, VideoProcAmp_Contrast, VideoProcAmp_Gain,
VideoProcAmp_Gamma, VideoProcAmp_Hue, VideoProcAmp_Saturation,
VideoProcAmp_Sharpness, VideoProcAmp_WhiteBalance,
},
Media::MediaFoundation::{
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, MF_MT_FRAME_RATE_RANGE_MIN,
MF_MT_FRAME_SIZE, MF_MT_MAJOR_TYPE, MF_MT_SUBTYPE, MF_READWRITE_DISABLE_CONVERTERS,
},
System::Com::{CoInitializeEx, CoUninitialize, COINIT},
},
BindingError, MFCameraFormat, MFControl, MFFrameFormat, MFResolution,
MediaFoundationControls, MediaFoundationDeviceDescriptor,
};
use std::{
borrow::Cow,
cell::Cell,
ffi::c_void,
mem::MaybeUninit,
slice::from_raw_parts,
sync::{
@@ -381,7 +376,35 @@ pub mod wmf {
Arc,
},
};
use windows::{Guid, Interface};
use windows::{
core::{Interface, GUID},
Win32::{
Foundation::PWSTR,
Media::{
DirectShow::{
CameraControl_Exposure, CameraControl_Focus, CameraControl_Iris,
CameraControl_Pan, CameraControl_Roll, CameraControl_Tilt, CameraControl_Zoom,
IAMCameraControl, IAMVideoProcAmp, VideoProcAmp_BacklightCompensation,
VideoProcAmp_Brightness, VideoProcAmp_ColorEnable, VideoProcAmp_Contrast,
VideoProcAmp_Gain, VideoProcAmp_Gamma, VideoProcAmp_Hue,
VideoProcAmp_Saturation, VideoProcAmp_Sharpness, VideoProcAmp_WhiteBalance,
},
MediaFoundation::{
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,
MF_MT_FRAME_RATE_RANGE_MIN, MF_MT_FRAME_SIZE, MF_MT_MAJOR_TYPE, MF_MT_SUBTYPE,
MF_READWRITE_DISABLE_CONVERTERS,
},
},
System::Com::{CoInitializeEx, CoUninitialize, COINIT},
},
};
lazy_static! {
static ref INITIALIZED: Arc<AtomicBool> = Arc::new(AtomicBool::new(false));
@@ -393,13 +416,13 @@ pub mod wmf {
const CO_INIT_DISABLE_OLE1DDE: COINIT = COINIT(0x4);
// See: https://gix.github.io/media-types/#major-types
const MF_VIDEO_FORMAT_YUY2: Guid = Guid::from_values(
const MF_VIDEO_FORMAT_YUY2: GUID = GUID::from_values(
0x3259_5559,
0x0000,
0x0010,
[0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71],
);
const MF_VIDEO_FORMAT_MJPEG: Guid = Guid::from_values(
const MF_VIDEO_FORMAT_MJPEG: GUID = GUID::from_values(
0x4750_4A4D,
0x0000,
0x0010,
@@ -483,10 +506,10 @@ pub mod wmf {
let mut device_list = vec![];
unsafe { from_raw_parts(unused_mf_activate.assume_init(), count as usize) }
.into_iter()
.iter()
.for_each(|pointer| {
if let Some(imf_activate) = pointer {
device_list.push(imf_activate.clone())
device_list.push(imf_activate.clone());
}
});
@@ -495,7 +518,7 @@ pub mod wmf {
fn activate_to_descriptors(
index: usize,
imf_activate: IMFActivate,
imf_activate: &IMFActivate,
) -> Result<MediaFoundationDeviceDescriptor<'static>, BindingError> {
let mut name: PWSTR = PWSTR(&mut 0_u16);
let mut len_name = 0;
@@ -528,9 +551,9 @@ pub mod wmf {
));
}
Ok(unsafe {
unsafe {
MediaFoundationDeviceDescriptor::new(index, name.0, symlink.0, len_name, len_symlink)
}?)
}
}
pub fn query_media_foundation_descriptors(
@@ -538,7 +561,7 @@ pub mod wmf {
let mut device_list = vec![];
for (index, activate_ptr) in query_activate_pointers()?.into_iter().enumerate() {
device_list.push(activate_to_descriptors(index, activate_ptr.clone())?);
device_list.push(activate_to_descriptors(index, &activate_ptr)?);
}
Ok(device_list)
}
@@ -557,18 +580,18 @@ pub mod wmf {
.nth(index)
{
Some(activate) => match unsafe { activate.ActivateObject::<IMFMediaSource>() } {
Ok(media_source) => (
media_source,
activate_to_descriptors(index, activate.clone())?,
),
Ok(media_source) => (media_source, activate_to_descriptors(index, &activate)?),
Err(why) => {
return Err(BindingError::DeviceOpenFailError(index, why.to_string()))
return Err(BindingError::DeviceOpenFailError(
index.to_string(),
why.to_string(),
))
}
},
None => {
return Err(BindingError::DeviceOpenFailError(
index,
"No Device".to_string(),
index.to_string(),
"Not Found".to_string(),
))
}
};
@@ -604,7 +627,12 @@ pub mod wmf {
MFCreateSourceReaderFromMediaSource(&media_source, source_reader_attr)
} {
Ok(sr) => sr,
Err(why) => return Err(BindingError::DeviceOpenFailError(index, why.to_string())),
Err(why) => {
return Err(BindingError::DeviceOpenFailError(
index.to_string(),
why.to_string(),
))
}
};
// increment refcnt
@@ -618,6 +646,32 @@ pub mod wmf {
})
}
pub fn with_string(unique_id: &[u16]) -> Result<Self, BindingError> {
let devicelist = query_media_foundation_descriptors()?;
let mut id_eq = None;
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),
None => {
return Err(BindingError::DeviceOpenFailError(
std::str::from_utf8(
&unique_id.iter().map(|x| *x as u8).collect::<Vec<u8>>(),
)
.unwrap_or("")
.to_string(),
"Not Found".to_string(),
))
}
}
}
pub fn index(&self) -> usize {
self.device_specifier.index
}
@@ -634,17 +688,10 @@ pub mod wmf {
let mut camera_format_list = vec![];
let mut index = 0;
loop {
let media_type = match unsafe {
self.source_reader
.GetNativeMediaType(MEDIA_FOUNDATION_FIRST_VIDEO_STREAM, index)
} {
Ok(mt) => mt,
Err(_) => {
break;
}
};
while let Ok(media_type) = unsafe {
self.source_reader
.GetNativeMediaType(MEDIA_FOUNDATION_FIRST_VIDEO_STREAM, index)
} {
let fourcc = match unsafe { media_type.GetGUID(&MF_MT_SUBTYPE) } {
Ok(fcc) => fcc,
Err(why) => {
@@ -791,7 +838,7 @@ pub mod wmf {
}
}
index = index + 1;
index += 1;
}
Ok(camera_format_list)
}
@@ -804,7 +851,7 @@ pub mod wmf {
MEDIA_FOUNDATION_FIRST_VIDEO_STREAM,
&MF_MEDIASOURCE_SERVICE,
&IMFMediaSource::IID,
&mut ptr_receiver as *mut *mut IMFMediaSource as *mut *mut c_void,
(&mut ptr_receiver as *mut *mut IMFMediaSource).cast::<*mut std::ffi::c_void>(),
) {
return Err(BindingError::GUIDSetError(
"MEDIA_FOUNDATION_FIRST_VIDEO_STREAM".to_string(),
@@ -1291,10 +1338,7 @@ pub mod wmf {
}
}
let is_manual = match flag {
CAM_CTRL_MANUAL => true,
_ => false,
};
let is_manual = matches!(flag, CAM_CTRL_MANUAL);
Ok(MFControl::new(
control, min, max, step, value, default, is_manual, true,
@@ -1309,7 +1353,7 @@ pub mod wmf {
MEDIA_FOUNDATION_FIRST_VIDEO_STREAM,
&MF_MEDIASOURCE_SERVICE,
&IMFMediaSource::IID,
&mut ptr_receiver as *mut *mut IMFMediaSource as *mut *mut c_void,
(&mut ptr_receiver as *mut *mut IMFMediaSource).cast::<*mut std::ffi::c_void>(),
) {
return Err(BindingError::GUIDSetError(
"MEDIA_FOUNDATION_FIRST_VIDEO_STREAM".to_string(),
@@ -1341,13 +1385,15 @@ pub mod wmf {
};
let value = control.current;
let flags = match control.manual {
true => CAM_CTRL_MANUAL,
false => CAM_CTRL_AUTO,
let flags = if control.manual {
CAM_CTRL_MANUAL
} else {
CAM_CTRL_AUTO
};
let flag_str = match control.manual {
true => "CAM_CTRL_MANUAL",
false => "CAM_CTRL_AUTO",
let flag_str = if control.manual {
"CAM_CTRL_MANUAL"
} else {
"CAM_CTRL_AUTO"
};
match control.control {
@@ -1555,8 +1601,8 @@ pub mod wmf {
};
// set relevant things
let resolution = ((format.resolution.width_x as u64) << 32_u64)
+ (format.resolution.height_y as u64);
let resolution = (u64::from(format.resolution.width_x) << 32_u64)
+ u64::from(format.resolution.height_y);
let fps = {
let frame_rate_u64 = 0_u64;
let mut bytes: [u8; 8] = frame_rate_u64.to_le_bytes();
@@ -1718,11 +1764,14 @@ pub mod wmf {
buffer_valid_length as usize,
) as &[u8]);
// swallow errors
let _ = buffer.Lock(
&mut buffer_start_ptr,
std::ptr::null_mut(),
&mut buffer_valid_length,
);
if buffer
.Lock(
&mut buffer_start_ptr,
std::ptr::null_mut(),
&mut buffer_valid_length,
)
.is_ok()
{}
}
Ok(Cow::from(data_slice))
@@ -1737,15 +1786,18 @@ pub mod wmf {
fn drop(&mut self) {
// swallow errors
unsafe {
let _ = self
if self
.source_reader
.Flush(MEDIA_FOUNDATION_FIRST_VIDEO_STREAM);
.Flush(MEDIA_FOUNDATION_FIRST_VIDEO_STREAM)
.is_ok()
{}
// decrement refcnt
if CAMERA_REFCNT.load(Ordering::SeqCst) > 0 {
CAMERA_REFCNT.store(CAMERA_REFCNT.load(Ordering::SeqCst) - 1, Ordering::SeqCst)
CAMERA_REFCNT.store(CAMERA_REFCNT.load(Ordering::SeqCst) - 1, Ordering::SeqCst);
}
if CAMERA_REFCNT.load(Ordering::SeqCst) == 0 {
#[allow(clippy::let_underscore_drop)]
let _ = de_initialize_mf();
}
}
+10 -3
View File
@@ -51,8 +51,15 @@ impl<'a> MediaFoundationCaptureDevice<'a> {
index: CameraIndex<'a>,
camera_fmt: Option<CameraFormat>,
) -> Result<Self, NokhwaError> {
let index = index.index_num()?;
let mut mf_device = MediaFoundationDevice::new(index as usize)?;
let mut mf_device = match &index {
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::<Vec<u16>>(),
),
}?;
if let Some(fmt) = camera_fmt {
mf_device.set_format(fmt.into())?;
}
@@ -61,7 +68,7 @@ impl<'a> MediaFoundationCaptureDevice<'a> {
mf_device.name(),
"MediaFoundation Camera Device".to_string(),
mf_device.symlink(),
CameraIndex::Index(index),
index,
);
Ok(MediaFoundationCaptureDevice {
+1 -2
View File
@@ -26,8 +26,7 @@ use opencv::{
CAP_MSMF, CAP_PROP_FPS, CAP_PROP_FRAME_HEIGHT, CAP_PROP_FRAME_WIDTH, CAP_V4L2,
},
};
use std::ops::Deref;
use std::{any::Any, borrow::Cow, collections::HashMap};
use std::{any::Any, borrow::Cow, collections::HashMap, ops::Deref};
/// Converts $from into $to
/// Example usage:
+1 -1
View File
@@ -56,7 +56,7 @@ use uvc::{
#[cfg_attr(feature = "docs-features", doc(cfg(feature = "input-uvc")))]
pub struct UVCCaptureDevice<'a> {
camera_format: CameraFormat,
camera_info: CameraInfo,
camera_info: CameraInfo<'a>,
frame_receiver: Receiver<Vec<u8>>,
frame_sender: Sender<Vec<u8>>,
stream_handle_init: Cell<bool>,
+1 -1
View File
@@ -209,7 +209,7 @@ pub trait CaptureBackendTrait {
queue: &WgpuQueue,
label: Option<&'a str>,
) -> Result<WgpuTexture, NokhwaError> {
use std::{convert::TryFrom, num::NonZeroU32};
use std::num::NonZeroU32;
let frame = self.frame()?;
let rgba_frame: RgbaImage = frame.convert();
-4
View File
@@ -28,10 +28,6 @@
//!
//! Please read the README for more.
#[cfg(feature = "small-wasm")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
/// Raw access to each of Nokhwa's backends.
pub mod backends;
mod camera;
+1 -1
View File
@@ -102,7 +102,7 @@ impl<'a> NetworkCamera<'a> {
/// Directly copies a frame to a Wgpu texture. This will automatically convert the frame into a RGBA frame.
/// # Errors
/// If the frame cannot be captured or the resolution is 0 on any axis, this will error.
pub fn frame_texture<'a>(
pub fn frame_texture(
&mut self,
device: &WgpuDevice,
queue: &WgpuQueue,
+1 -1
View File
@@ -14,7 +14,7 @@
* limitations under the License.
*/
use crate::{CameraIndex, CameraInfo, CaptureAPIBackend, NokhwaError};
use crate::{CameraInfo, CaptureAPIBackend, NokhwaError};
/// Query the system for a list of available devices.
/// Usually the order goes Native -> UVC -> Gstreamer.
+19 -10
View File
@@ -592,13 +592,13 @@ impl<'a> Display for CameraInfo<'a> {
all(feature = "input-msmf", target_os = "windows"),
all(feature = "docs-only", feature = "docs-nolink", feature = "input-msmf")
))]
impl From<MediaFoundationDeviceDescriptor<'_>> for CameraInfo {
impl From<MediaFoundationDeviceDescriptor<'_>> for CameraInfo<'_> {
fn from(dev_desc: MediaFoundationDeviceDescriptor<'_>) -> Self {
CameraInfo {
human_name: dev_desc.name_as_string(),
description: "Media Foundation Device".to_string(),
misc: dev_desc.link_as_string(),
index: dev_desc.index(),
human_name: Cow::from(dev_desc.name_as_string()),
description: Cow::from("Media Foundation Device"),
misc: Cow::from(dev_desc.link_as_string()),
index: CameraIndex::Index(dev_desc.index() as u32),
}
}
}
@@ -615,13 +615,13 @@ impl From<MediaFoundationDeviceDescriptor<'_>> for CameraInfo {
)
))]
#[allow(clippy::cast_possible_truncation)]
impl From<AVCaptureDeviceDescriptor> for CameraInfo {
impl From<AVCaptureDeviceDescriptor> for CameraInfo<'_> {
fn from(descriptor: AVCaptureDeviceDescriptor) -> Self {
CameraInfo {
human_name: descriptor.name,
description: descriptor.description,
misc: descriptor.misc,
index: descriptor.index as usize,
human_name: Cow::from(descriptor.name),
description: Cow::from(descriptor.description),
misc: Cow::from(descriptor.misc),
index: CameraIndex::Index(descriptor.index as u32),
}
}
}
@@ -1088,6 +1088,8 @@ where
/// # Safety
/// This function uses `unsafe`. The caller must ensure that:
/// - The input data is of the right size, does not exceed bounds, and/or the final size matches with the initial size.
#[cfg(all(feature = "decoding", not(target_arch = "wasm")))]
#[cfg_attr(feature = "docs-features", doc(cfg(feature = "decoding")))]
pub fn mjpeg_to_rgb888(data: &[u8]) -> Result<Vec<u8>, NokhwaError> {
use mozjpeg::Decompress;
@@ -1127,6 +1129,13 @@ pub fn mjpeg_to_rgb888(data: &[u8]) -> Result<Vec<u8>, NokhwaError> {
)
}
#[cfg(not(all(feature = "decoding", not(target_arch = "wasm"))))]
pub fn mjpeg_to_rgb888(data: &[u8]) -> Result<Vec<u8>, NokhwaError> {
Err(NokhwaError::NotImplementedError(
"Not available on WASM".to_string(),
))
}
// For those maintaining this, I recommend you read: https://docs.microsoft.com/en-us/windows/win32/medfound/recommended-8-bit-yuv-formats-for-video-rendering#yuy2
// https://en.wikipedia.org/wiki/YUV#Converting_between_Y%E2%80%B2UV_and_RGB
// and this too: https://stackoverflow.com/questions/16107165/convert-from-yuv-420-to-imagebgr-byte