Skip to main content

azul_core/
camera.rs

1//! POD types for the camera-capture surface
2//! (SUPER_PLAN_2 §4 Priority 6 + research/01).
3//!
4//! Camera frames are GPU textures, not scalar samples, so the stateful side
5//! is heavier than the sensors': `azul_layout::managers::camera` owns a
6//! `CameraStream` per capture, each holding a shared `ImageRef` texture the
7//! capture thread writes into (zero-copy - clones see new bytes via the
8//! `ImageRef` `Arc`). A `CameraPreview` node renders that texture and, by
9//! appearing in the DOM, declares "I need the camera" to the permission
10//! layer (research/01 §"permission-as-DOM").
11//!
12//! Defined here in `azul-core` so the config / id / status types cross the
13//! FFI without `azul-layout` (or AVFoundation / Camera2) as a dependency -
14//! these are what an app passes to `start_camera` and reads back from a
15//! stream. The `Nv12` zero-copy output format is a `RawImageFormat` addition
16//! deferred to the backend tick; configs default to `BGRA8`.
17
18use crate::resources::RawImageFormat;
19
20/// Identifies one camera capture stream - assigned by `start_camera`, used
21/// to read the stream back (`get_camera_frame`) and to stop / pause / flip it.
22#[repr(C)]
23#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
24pub struct CaptureStreamId {
25    pub id: u64,
26}
27
28/// Which physical camera to open.
29#[repr(C)]
30#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
31pub enum CameraFacing {
32    /// User-facing (selfie) camera.
33    Front,
34    /// World-facing (rear) camera.
35    Back,
36    /// An external / USB camera (desktop webcams report here).
37    External,
38}
39
40/// Lifecycle of a capture stream.
41#[repr(C)]
42#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
43pub enum StreamState {
44    /// Opening the device / negotiating the format.
45    Starting,
46    /// Delivering frames.
47    Running,
48    /// Temporarily suspended (app backgrounded, `pause_camera`).
49    Paused,
50    /// Stopped by the app (`stop_camera`) or torn down.
51    Stopped,
52    /// Failed - see the stream's [`CaptureErrorCode`].
53    Error,
54}
55
56/// Rotation / mirroring the capture needs relative to the display (the
57/// sensor's native orientation rarely matches the UI's).
58#[repr(C)]
59#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
60pub enum CaptureOrientation {
61    /// Upright (0°).
62    Up,
63    /// Upside down (180°).
64    Down,
65    /// Rotated 90° counter-clockwise.
66    Left,
67    /// Rotated 90° clockwise.
68    Right,
69    /// Horizontally mirrored (typical for the front camera).
70    Mirror,
71}
72
73/// Why a capture stream failed ([`StreamState::Error`]).
74#[repr(C)]
75#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
76pub enum CaptureErrorCode {
77    /// The user denied (or hasn't granted) camera permission.
78    PermissionDenied,
79    /// No camera matched the requested [`CameraFacing`].
80    DeviceUnavailable,
81    /// The device disappeared mid-capture (unplugged / claimed).
82    DeviceLost,
83    /// The requested format / resolution isn't supported.
84    Unsupported,
85    /// A platform error not covered above.
86    Internal,
87}
88
89/// Requested capture configuration - the input to `start_camera`. Zero
90/// `width`/`height`/`fps` mean "let the backend pick its default".
91#[repr(C)]
92#[derive(Debug, Clone, Copy, PartialEq)]
93pub struct CameraConfig {
94    /// Which camera to open.
95    pub facing: CameraFacing,
96    /// Preferred frame width in px (0 = backend default).
97    pub width: u32,
98    /// Preferred frame height in px (0 = backend default).
99    pub height: u32,
100    /// Preferred frame rate (0 = backend default).
101    pub fps: u32,
102    /// Texture format the backend should deliver. `BGRA8` is the portable
103    /// default; `Nv12` (a later `RawImageFormat` addition) is the zero-copy
104    /// path on platforms that produce it natively.
105    pub output_format: RawImageFormat,
106}
107
108impl Default for CameraConfig {
109    fn default() -> Self {
110        Self {
111            facing: CameraFacing::Back,
112            width: 0,
113            height: 0,
114            fps: 0,
115            output_format: RawImageFormat::BGRA8,
116        }
117    }
118}
119
120impl CameraConfig {
121    /// A default config for the given `facing` (backend-chosen size/fps,
122    /// `BGRA8`).
123    pub fn new(facing: CameraFacing) -> Self {
124        Self {
125            facing,
126            ..Self::default()
127        }
128    }
129}
130
131/// Runtime stats for a capture stream - surfaced for HUD / debugging.
132#[repr(C)]
133#[derive(Debug, Clone, Copy, PartialEq)]
134pub struct CaptureStats {
135    /// Measured delivery rate (frames/s), smoothed by the backend.
136    pub measured_fps: f32,
137    /// Frames delivered to the texture since the stream started.
138    pub frames_delivered: u64,
139    /// Frames the backend dropped (couldn't keep up / late).
140    pub frames_dropped: u64,
141}
142
143impl Default for CaptureStats {
144    fn default() -> Self {
145        Self {
146            measured_fps: 0.0,
147            frames_delivered: 0,
148            frames_dropped: 0,
149        }
150    }
151}