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

            
18
use 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)]
24
pub 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)]
31
pub 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)]
43
pub 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)]
60
pub 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)]
76
pub 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)]
93
pub 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

            
108
impl 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

            
120
impl 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)]
134
pub 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

            
143
impl 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
}