Skip to content

Commit

Permalink
use camera idea and dummy frames
Browse files Browse the repository at this point in the history
  • Loading branch information
payload committed Aug 22, 2023
1 parent 319ca12 commit 2eb8728
Show file tree
Hide file tree
Showing 3 changed files with 217 additions and 12 deletions.
98 changes: 98 additions & 0 deletions examples/iced2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
use std::iter::repeat;
use std::time::Instant;

use iced::widget::{column, container, image, text};
use iced::{
executor, subscription, window, Application, Command, Element, Event, Length, Settings,
Subscription, Theme,
};
use kamera::camera_idea::*;

pub fn main() -> iced::Result {
Example::run(Settings::default())
}

struct Example {
camera: Camera,
current_frame: image::Handle,
}

#[derive(Debug, Clone)]
#[allow(clippy::enum_variant_names)]
enum Message {
Tick(Instant),
Event(Event),
}

impl Application for Example {
type Message = Message;
type Executor = executor::Default;
type Theme = Theme;
type Flags = ();

fn new(_flags: Self::Flags) -> (Self, Command<Message>) {
let camera = Camera::new();
camera.play();

let app = Self {
camera,
current_frame: image::Handle::from_pixels(
16,
16,
Vec::from_iter(repeat([0, 0, 0, 0]).take(16 * 16).flatten()),
),
};

(app, Command::none())
}

fn title(&self) -> String {
String::from("Custom widget - Iced")
}

fn subscription(&self) -> Subscription<Message> {
Subscription::batch(
[subscription::events().map(Message::Event), window::frames().map(Message::Tick)]
.into_iter(),
)
}

fn update(&mut self, message: Message) -> Command<Message> {
match message {
Message::Tick(_instant) => {
for event in self.camera.events() {
match event {
CameraEvent::Frame => {
let frame = self.camera.current_frame();
self.current_frame = image::Handle::from_pixels(
frame.width(),
frame.height(),
frame.pixels().to_vec(),
);
}
CameraEvent::StateChange => {}
}
}
}
Message::Event(iced::event::Event::Mouse(mouse_event)) => {
if let iced::mouse::Event::ButtonPressed(_) = mouse_event {
self.camera.change_camera(CameraChange::Next);
}
}
_ => {}
}

Command::none()
}

fn view(&self) -> Element<Message> {
let camera_frame = image(self.current_frame.clone());
let camera_label = text(&self.camera.info().label);
container(column!(camera_frame, camera_label))
.width(Length::Fill)
.height(Length::Fill)
.center_x()
.center_y()
.into()
}
}
112 changes: 107 additions & 5 deletions src/camera_idea.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
use std::sync::mpsc::{channel, Receiver, Sender};
use crate::backend;

Check warning on line 1 in src/camera_idea.rs

View workflow job for this annotation

GitHub Actions / macos (stable)

unused import: `crate::backend`

Check failure on line 1 in src/camera_idea.rs

View workflow job for this annotation

GitHub Actions / macos (stable)

unused import: `crate::backend`

Check warning on line 1 in src/camera_idea.rs

View workflow job for this annotation

GitHub Actions / macos (stable)

unused import: `crate::backend`

Check failure on line 1 in src/camera_idea.rs

View workflow job for this annotation

GitHub Actions / linux (stable)

unused import: `crate::backend`

Check warning on line 1 in src/camera_idea.rs

View workflow job for this annotation

GitHub Actions / linux (stable)

unused import: `crate::backend`

Check warning on line 1 in src/camera_idea.rs

View workflow job for this annotation

GitHub Actions / linux (stable)

unused import: `crate::backend`

Check warning on line 1 in src/camera_idea.rs

View workflow job for this annotation

GitHub Actions / windows (stable)

unused import: `crate::backend`

Check failure on line 1 in src/camera_idea.rs

View workflow job for this annotation

GitHub Actions / windows (stable)

unused import: `crate::backend`

Check warning on line 1 in src/camera_idea.rs

View workflow job for this annotation

GitHub Actions / windows (stable)

unused import: `crate::backend`
use std::sync::{Arc, RwLock};
use std::thread::JoinHandle;

#[derive(Debug)]
pub struct Camera {
current_frame: RwLock<Arc<CameraFrame>>,
state: RwLock<Arc<CameraState>>,
event: Option<Receiver<CameraEvent>>,
// event: Receiver<CameraEvent>,
// backend_camera: RwLock<backend::Camera>,
}

#[derive(Debug)]
pub struct CameraState {
state: State,

Check warning on line 14 in src/camera_idea.rs

View workflow job for this annotation

GitHub Actions / macos (stable)

fields `state`, `raw_format`, `constraints`, `capabilities`, `setting`, and `available_cameras` are never read

Check failure on line 14 in src/camera_idea.rs

View workflow job for this annotation

GitHub Actions / macos (stable)

fields `state`, `raw_format`, `constraints`, `capabilities`, `setting`, and `available_cameras` are never read

Check warning on line 14 in src/camera_idea.rs

View workflow job for this annotation

GitHub Actions / macos (stable)

fields `state`, `raw_format`, `constraints`, `capabilities`, `setting`, and `available_cameras` are never read

Check failure on line 14 in src/camera_idea.rs

View workflow job for this annotation

GitHub Actions / linux (stable)

fields `state`, `raw_format`, `constraints`, `capabilities`, `setting`, and `available_cameras` are never read

Check warning on line 14 in src/camera_idea.rs

View workflow job for this annotation

GitHub Actions / linux (stable)

fields `state`, `raw_format`, `constraints`, `capabilities`, `setting`, and `available_cameras` are never read

Check warning on line 14 in src/camera_idea.rs

View workflow job for this annotation

GitHub Actions / linux (stable)

fields `state`, `raw_format`, `constraints`, `capabilities`, `setting`, and `available_cameras` are never read

Check warning on line 14 in src/camera_idea.rs

View workflow job for this annotation

GitHub Actions / windows (stable)

fields `state`, `raw_format`, `constraints`, `capabilities`, `setting`, and `available_cameras` are never read

Check failure on line 14 in src/camera_idea.rs

View workflow job for this annotation

GitHub Actions / windows (stable)

fields `state`, `raw_format`, `constraints`, `capabilities`, `setting`, and `available_cameras` are never read

Check warning on line 14 in src/camera_idea.rs

View workflow job for this annotation

GitHub Actions / windows (stable)

fields `state`, `raw_format`, `constraints`, `capabilities`, `setting`, and `available_cameras` are never read
raw_format: RawFormat,
Expand All @@ -18,6 +20,7 @@ pub struct CameraState {
available_cameras: Vec<CameraInfo>,
}

#[derive(Debug)]
pub struct CameraFrame {
frame_counter: usize,
width: u32,
Expand All @@ -27,11 +30,14 @@ pub struct CameraFrame {
camera_info: Arc<CameraInfo>,
}

#[derive(Debug)]
pub enum RawFormat {
ARGB,
BGRA,
RGBA,
}

#[derive(Debug)]
pub enum State {
NoCamera,
Playing,
Expand All @@ -40,43 +46,55 @@ pub enum State {
Error,
}

#[derive(Debug)]
pub enum CameraEvent {
Frame,
StateChange,
}

#[derive(Debug)]
pub enum CameraChange {
Next,
}

#[derive(Default, Debug)]
pub struct CameraInfo {
pub id: String,
pub label: String,
}

#[derive(Default, Debug)]
pub struct CameraConstraints {
pub width: Constraint<u32>,
pub height: Constraint<u32>,
pub frame_rate: Constraint<u32>,
}

#[derive(Default, Debug)]
pub struct CameraCapabilities {
pub width: Capability<u32>,
pub height: Capability<u32>,
pub frame_rate: Capability<u32>,
}

#[derive(Default, Debug)]
pub struct CameraSettings {
pub width: u32,
pub height: u32,
pub frame_rate: u32,
}

#[derive(Default, Debug)]
pub enum Constraint<T> {
#[default]
Any,
Pref(T),
}

#[derive(Default, Debug)]
pub enum Capability<T> {
#[default]
Any, // TODO maybe not wanted
Range(T, T),
}

Expand All @@ -98,7 +116,91 @@ impl Camera {
self.state.read().unwrap().clone()
}

pub fn events(&mut self) -> Option<Receiver<CameraEvent>> {
self.event.take()
pub fn events(&self) -> impl Iterator<Item = CameraEvent> {
if let Ok(mut frame) = self.current_frame.write() {
let frame_counter = frame.frame_counter + 1;
*frame = Arc::new(CameraFrame {
frame_counter,
..CameraFrame::new_random_color(frame_counter)
});
}

vec![CameraEvent::Frame, CameraEvent::StateChange].into_iter()
}

////////////////////////////////////////////////

pub fn new() -> Self {

Check failure on line 133 in src/camera_idea.rs

View workflow job for this annotation

GitHub Actions / macos (stable)

you should consider adding a `Default` implementation for `Camera`

Check failure on line 133 in src/camera_idea.rs

View workflow job for this annotation

GitHub Actions / linux (stable)

you should consider adding a `Default` implementation for `Camera`

Check failure on line 133 in src/camera_idea.rs

View workflow job for this annotation

GitHub Actions / windows (stable)

you should consider adding a `Default` implementation for `Camera`
Self {
current_frame: RwLock::new(Arc::new(CameraFrame::new())),
state: RwLock::new(Arc::new(CameraState::new())),
}
}

////////////////////////////////////////////////

pub fn info(&self) -> Arc<CameraInfo> {
self.state.read().unwrap().camera_info.clone()
}
}

impl CameraFrame {
fn new() -> Self {
Self {
frame_counter: 0,
width: 0,
height: 0,
raw_format: RawFormat::ARGB,
raw_data: Vec::new(),
camera_info: Arc::new(CameraInfo::default()),
}
}

fn new_random_color(seed: usize) -> Self {
let w = 160 * 2;
let h = 90 * 2;

// this should cycle through red, green, blue
let f = (seed as f32) * 3.14 / 255.0;

Check failure on line 164 in src/camera_idea.rs

View workflow job for this annotation

GitHub Actions / macos (stable)

approximate value of `f{32, 64}::consts::PI` found

Check failure on line 164 in src/camera_idea.rs

View workflow job for this annotation

GitHub Actions / linux (stable)

approximate value of `f{32, 64}::consts::PI` found

Check failure on line 164 in src/camera_idea.rs

View workflow job for this annotation

GitHub Actions / windows (stable)

approximate value of `f{32, 64}::consts::PI` found
let r = (f * 5.0).sin().powi(2) * 255.0;
let g = ((f + 0.8) * 5.0).sin().clamp(0.0, 1.0) * 255.0;
let b = ((f + 1.6) * 5.0).sin().clamp(0.0, 1.0) * 255.0;
Self {
frame_counter: 0,
width: w,
height: h,
raw_format: RawFormat::RGBA,
camera_info: Arc::new(CameraInfo::default()),
raw_data: std::iter::repeat([r as _, g as _, b as _, 255])
.take((w * h) as _)
.flatten()
.collect(),
}
}

pub fn width(&self) -> u32 {
self.width
}

pub fn height(&self) -> u32 {
self.height
}

pub fn pixels(&self) -> &[u8] {
&self.raw_data
}
}

impl CameraState {
fn new() -> Self {
Self {
state: State::NoCamera,
raw_format: RawFormat::ARGB,
constraints: CameraConstraints::default(),
capabilities: CameraCapabilities::default(),
setting: CameraSettings::default(),
camera_info: Arc::new(CameraInfo::default()),
available_cameras: Vec::new(),
}
}
}
19 changes: 12 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,18 @@ mod camera_on_thread;
pub use camera_on_thread::*;

pub mod camera_idea;
mod camera_idea_impl;

#[cfg(target_os = "macos")] mod mac_avf;
#[cfg(target_os = "macos")] pub(crate) use mac_avf as backend;
#[cfg(target_os = "macos")]
mod mac_avf;
#[cfg(target_os = "macos")]
pub(crate) use mac_avf as backend;

#[cfg(target_os = "windows")] mod win_mf;
#[cfg(target_os = "windows")] pub(crate) use win_mf as backend;
#[cfg(target_os = "windows")]
mod win_mf;
#[cfg(target_os = "windows")]
pub(crate) use win_mf as backend;

#[cfg(target_os = "linux")] mod linux_v4l2;
#[cfg(target_os = "linux")] pub(crate) use linux_v4l2 as backend;
#[cfg(target_os = "linux")]
mod linux_v4l2;
#[cfg(target_os = "linux")]
pub(crate) use linux_v4l2 as backend;

0 comments on commit 2eb8728

Please sign in to comment.