intermidate

This commit is contained in:
l1npengtul
2025-02-08 20:32:11 +09:00
parent 4d44710261
commit bca9b4a65a
5 changed files with 166 additions and 43 deletions
Generated
+7 -6
View File
@@ -1241,7 +1241,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "887d93f60543e9a9362ef8a21beedd0a833c5d9610e18c67abe15a5963dcb1a4"
dependencies = [
"bit_field",
"flume 0.11.0",
"flume 0.11.1",
"half",
"lebe",
"miniz_oxide",
@@ -1306,9 +1306,9 @@ dependencies = [
[[package]]
name = "flume"
version = "0.11.0"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181"
checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095"
dependencies = [
"futures-core",
"futures-sink",
@@ -2491,7 +2491,7 @@ name = "nokhwa"
version = "0.11.0"
dependencies = [
"async-trait",
"flume 0.11.0",
"flume 0.11.1",
"image 0.25.0",
"js-sys",
"mozjpeg",
@@ -2516,6 +2516,7 @@ dependencies = [
name = "nokhwa-bindings-linux"
version = "0.2.0"
dependencies = [
"flume 0.11.1",
"nokhwa-core",
"pipewire",
"v4l",
@@ -2531,7 +2532,7 @@ dependencies = [
"cocoa-foundation",
"core-media-sys",
"core-video-sys",
"flume 0.11.0",
"flume 0.11.1",
"nokhwa-core",
"objc",
"once_cell",
@@ -2553,7 +2554,7 @@ dependencies = [
"async-trait",
"bytes",
"derive_builder",
"flume 0.11.0",
"flume 0.11.1",
"futures",
"image 0.25.0",
"num-rational 0.4.2",
+2
View File
@@ -11,10 +11,12 @@ keywords = ["v4l", "v4l2", "linux", "nokhwa", "webcam"]
[features]
v4l2 = ["v4l", "v4l2-sys-mit"]
pw = ["pipewire"]
async = ["flume/async", "nokhwa-core/async"]
[dependencies]
v4l = { version = "0.14", features = ["v4l2"], optional = true }
v4l2-sys-mit = { version = "0.3", optional = true }
flume = "0.11.1"
[dependencies.pipewire]
version = "0.8"
+1
View File
@@ -16,3 +16,4 @@
#[cfg(feature = "v4l2")]
pub mod v4l2;
pub mod pipewire;
mod v4l2r;
+155 -37
View File
@@ -1,23 +1,27 @@
use std::collections::{HashMap, HashSet};
use std::mem;
use std::num::NonZeroI32;
use v4l::context::enum_devices;
use v4l::{Capabilities, Device, Format, FourCC, Fraction, FrameInterval};
use v4l::control::{Description, Flags, MenuItem, Type, Value};
use v4l::frameinterval::FrameIntervalEnum;
use v4l::video::Output;
use v4l::video::output::Parameters;
use nokhwa_core::camera::{Camera, Capture, Setting};
use nokhwa_core::control::{ControlDescription, ControlFlags, ControlId, ControlValue, ControlValueDescriptor, Controls};
use nokhwa_core::error::{NokhwaError, NokhwaResult};
use nokhwa_core::frame_format::FrameFormat;
use nokhwa_core::platform::{Backends, PlatformTrait};
use nokhwa_core::control::{ControlBody, ControlFlags, ControlId, ControlValue, ControlValueDescriptor, Controls};
use nokhwa_core::ranges::Range;
use nokhwa_core::stream::Stream;
use nokhwa_core::types::{CameraFormat, CameraIndex, CameraInformation, FrameRate, Resolution};
use v4l2_sys_mit::{V4L2_CID_FOCUS_ABSOLUTE, V4L2_CID_FOCUS_RELATIVE, V4L2_CID_AUTO_FOCUS_RANGE, V4L2_CID_FOCUS_AUTO, V4L2_CID_AUTO_FOCUS_STATUS, V4L2_CID_ISO_SENSITIVITY, V4L2_CID_EXPOSURE_AUTO, V4L2_CID_AUTO_EXPOSURE_BIAS, V4L2_CID_EXPOSURE_METERING, V4L2_CID_EXPOSURE_ABSOLUTE, V4L2_CID_ISO_SENSITIVITY_AUTO, V4L2_CID_IRIS_ABSOLUTE, V4L2_CID_IRIS_RELATIVE, V4L2_CID_AUTO_WHITE_BALANCE, V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE, V4L2_CID_ZOOM_CONTINUOUS, V4L2_CID_ZOOM_RELATIVE, V4L2_CID_ZOOM_ABSOLUTE, V4L2_CID_FLASH_LED_MODE, V4L2_CID_FLASH_STROBE, V4L2_CID_FLASH_STROBE_STATUS, V4L2_CID_CAMERA_ORIENTATION, V4L2_CTRL_FLAG_DISABLED, V4L2_CID_FLASH_STROBE_STOP, v4l2_querymenu};
use v4l::device::Handle;
use v4l::v4l2::ioctl;
use nokhwa_core::ranges::Range;
use std::collections::hash_map::{Keys, Values};
use std::collections::{HashMap, HashSet};
use std::num::NonZeroI32;
use std::sync::Arc;
use std::thread::JoinHandle;
use flume::{Sender, Receiver, unbounded, bounded};
use v4l::context::enum_devices;
use v4l::control::{Description, Flags, MenuItem, Type, Value};
use v4l::frameinterval::FrameIntervalEnum;
use v4l::video::output::Parameters;
use v4l::video::Output;
use v4l::{Capabilities, Device, Format, FourCC, Fraction, FrameInterval};
use v4l2_sys_mit::{V4L2_CID_AUTO_EXPOSURE_BIAS, V4L2_CID_AUTO_FOCUS_RANGE, V4L2_CID_AUTO_FOCUS_STATUS, V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE, V4L2_CID_AUTO_WHITE_BALANCE, V4L2_CID_CAMERA_ORIENTATION, V4L2_CID_EXPOSURE_ABSOLUTE, V4L2_CID_EXPOSURE_AUTO, V4L2_CID_EXPOSURE_METERING, V4L2_CID_FLASH_LED_MODE, V4L2_CID_FLASH_STROBE, V4L2_CID_FLASH_STROBE_STATUS, V4L2_CID_FLASH_STROBE_STOP, V4L2_CID_FOCUS_ABSOLUTE, V4L2_CID_FOCUS_AUTO, V4L2_CID_FOCUS_RELATIVE, V4L2_CID_IRIS_ABSOLUTE, V4L2_CID_IRIS_RELATIVE, V4L2_CID_ISO_SENSITIVITY, V4L2_CID_ISO_SENSITIVITY_AUTO, V4L2_CID_ZOOM_ABSOLUTE, V4L2_CID_ZOOM_CONTINUOUS, V4L2_CID_ZOOM_RELATIVE};
use v4l::io::traits::OutputStream;
use v4l::prelude::MmapStream;
use nokhwa_core::frame_buffer::FrameBuffer;
fn index_capabilities_to_camera_info(index: u32, capabilities: Capabilities) -> CameraInformation {
let name = capabilities.card;
@@ -107,7 +111,22 @@ macro_rules! define_control_id_conv {
})
}
_ => Err(NokhwaError::ConversionError("Could not match ID".to_string())
)
)
}
}
fn control_id_to_cid_ref(control_id: &ControlId) -> Result<u32, NokhwaError> {
match control_id {
$(
$control_id => Ok($v4l_cid)
)+
ControlId::PlatformSpecific(specific_id) => {
u32::try_from(specific_id).map_err(|why| {
NokhwaError::ConversionError("ID must be a u32".to_string())
})
}
_ => Err(NokhwaError::ConversionError("Could not match ID".to_string())
)
}
}
@@ -186,7 +205,7 @@ fn flags(flags: Flags) -> HashSet<ControlFlags> {
output_flags
}
fn convert_description_to_ctrl_body(description: Description) -> Option<ControlBody> {
fn convert_description_to_ctrl_body(description: Description) -> Option<ControlDescription> {
let flags = flags(description.flags);
let (descriptor, default) = match description.typ {
@@ -233,9 +252,6 @@ fn convert_description_to_ctrl_body(description: Description) -> Option<ControlB
)
}
Type::IntegerMenu | Type::Menu => {
// We just initialize the values to Null for now.
// We fill it out later.
// our keys
let descriptor = match description.items {
Some(items) => {
@@ -270,12 +286,10 @@ fn convert_description_to_ctrl_body(description: Description) -> Option<ControlB
_ => return None,
};
Some(
ControlBody::new(
flags,
descriptor,
default
)
ControlDescription::new(
flags,
descriptor,
default
)
}
@@ -307,8 +321,25 @@ impl PlatformTrait for V4L2Platform {
}).flatten().collect::<Vec<_>>())
}
fn open(&mut self, index: &CameraIndex) -> NokhwaResult<Self::Camera> {
todo!()
fn open(&mut self, index: CameraIndex) -> NokhwaResult<Self::Camera> {
let device = match &index {
CameraIndex::Index(i) => Device::new(*i as usize),
CameraIndex::String(path) => Device::with_path(path)
}.map_err(|why| {
NokhwaError::OpenDeviceError(index.to_string(), why.to_string())
})?;
let mut v4l2_camera = V4L2Camera {
device,
camera_format: None,
camera_index: index,
controls: Default::default(),
stream: None,
};
v4l2_camera.refresh_controls()?;
Ok(v4l2_camera)
}
}
@@ -316,7 +347,8 @@ pub struct V4L2Camera {
device: Device,
camera_format: Option<CameraFormat>,
camera_index: CameraIndex,
controls: Option<Controls>,
controls: Controls,
stream: Option<Stream>,
}
impl Setting for V4L2Camera {
@@ -405,13 +437,32 @@ impl Setting for V4L2Camera {
Ok(())
}
fn controls(&self) -> &Controls {
fn control_ids(&self) -> Keys<ControlId, ControlDescription> {
self.controls.ids()
}
match self.controls {
fn control_descriptions(&self) -> Values<ControlId, ControlDescription> {
self.controls.descriptions()
}
}
fn control_values(&self) -> Values<ControlId, ControlValue> {
self.controls.values()
}
let properties = self.device.query_controls().map_err(|why| {
fn control_value(&self, id: &ControlId) -> Option<&ControlValue> {
self.controls.value(id)
}
fn control_description(&self, id: &ControlId) -> Option<&ControlDescription> {
self.controls.description(id)
}
fn set_control(&mut self, property: &ControlId, value: ControlValue) -> Result<(), NokhwaError> {
self.controls.set_control_value(property, value)
}
fn refresh_controls(&mut self) -> Result<(), NokhwaError> {
let descriptions = self.device.query_controls().map_err(|why| {
NokhwaError::GetPropertyError { property: "query_controls".to_string(), error: why.to_string() }
})?.into_iter().map(|description| {
let id = cid_to_control_id(description.id);
@@ -419,17 +470,84 @@ impl Setting for V4L2Camera {
convert_description_to_ctrl_body(description).map(|body| {
(id, body)
})
}).flatten().collect::<HashMap<ControlId, ControlBody>>();
}
}).flatten().collect::<HashMap<ControlId, ControlDescription>>();
fn set_control(&mut self, property: &ControlId, value: ControlValue) -> Result<(), NokhwaError> {
todo!()
let values = descriptions.keys().into_iter().copied().flat_map(|k| control_id_to_cid(k).map(|cid| (k, cid))).flat_map(|(id, cid)| {
self.device.control(cid).map(|v| (id, v))
}).map(|(id, value)| {
(id, match value.value {
Value::None => ControlValue::Null,
Value::Integer(i) => ControlValue::Integer(i),
Value::Boolean(b) => ControlValue::Boolean(b),
Value::String(s) => ControlValue::String(s),
Value::CompoundU8(bin) | Value::CompoundPtr(bin) => ControlValue::Binary(bin),
Value::CompoundU16(u) | Value::CompoundU32(u) => ControlValue::Array(
u.into_iter().map(|u| ControlValue::Integer(u as i64)).collect()
),
})
}).collect::<HashMap<ControlId, ControlValue>>();
match Controls::new(descriptions, values) {
Some(c) => { self.controls = c; }
None => return Err(NokhwaError::SetPropertyError {
property: "control".to_string(),
value: format!("{:?} {:?}", descriptions, values),
error: "Failed to convert to control".to_string(),
})
}
Ok(())
}
}
struct V4L2Stream {
thread: JoinHandle<()>,
control: Sender<()>,
receiver: Arc<Receiver<FrameBuffer>>,
}
impl Drop for V4L2Stream {
fn drop(&mut self) {
let _ = self.control.send(());
}
}
impl Capture for V4L2Camera {
fn open_stream(&mut self) -> Result<Stream, NokhwaError> {
todo!()
let format = match self.camera_format {
Some(fmt) => fmt,
None => return Err(NokhwaError::OpenStreamError("No Format".to_string()))
};
let (control, ctrl_recv) = bounded(1);
let (sender, receiver) = unbounded();
let receiver = Arc::new(receiver);
self.set_format(format)?;
let mut mmap_stream = MmapStream::new(&self.device, v4l::buffer::Type::VideoCapture).map_err(|why| {
return NokhwaError::OpenStreamError(why.to_string())
})?;
let thread = std::thread::spawn(move || {
loop {
if ctrl_recv.is_disconnected() || sender.is_disconnected() {
return;
}
if let Ok(_) = ctrl_recv.try_recv() {
return;
}
match mmap_stream.next() {
Ok((data, meta)) => {
FrameBuffer::new()
}
Err(_) => {}
}
}
()
})
}
fn close_stream(&mut self) -> Result<(), NokhwaError> {
+1
View File
@@ -0,0 +1 @@
// TODO