Skip to main content

pinray_core/
frame.rs

1use crate::audio::AudioFrame;
2
3/// An axis-aligned rectangle in pixels, used for crop regions and damage.
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub struct Rect {
6    pub x: i32,
7    pub y: i32,
8    pub width: u32,
9    pub height: u32,
10}
11
12/// Pixel layout of [`VideoFrame::data`].
13///
14/// All backends deliver `Bgra8888` natively and can swizzle to `Rgba8888`;
15/// the remaining formats exist for future zero-copy paths.
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum PixelFormat {
18    /// 8-bit B, G, R, A byte order — the native format everywhere.
19    Bgra8888,
20    /// 8-bit R, G, B, A byte order (CPU swizzle from BGRA).
21    Rgba8888,
22    /// 24-bit packed RGB, no alpha.
23    Rgb888,
24    /// Biplanar 4:2:0 YCbCr (Y plane + interleaved CbCr).
25    Nv12,
26    /// Planar 4:2:0 YCbCr.
27    I420,
28}
29
30/// Color space hint for interpreting pixel values.
31#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32pub enum ColorSpace {
33    Srgb,
34    DisplayP3,
35    Bt709,
36    Bt2020,
37}
38
39/// A Linux DMA-BUF plane handle (zero-copy path, not yet produced).
40#[derive(Debug, Clone, PartialEq, Eq)]
41pub struct DmabufFrame {
42    pub fd: i32,
43    pub offset: u32,
44    pub size: u32,
45    pub stride: u32,
46    pub modifier: u64,
47}
48
49/// A macOS `CVPixelBuffer` pointer (zero-copy path, not yet produced).
50#[derive(Debug, Clone, Copy, PartialEq, Eq)]
51pub struct CvPixelBufferHandle {
52    pub ptr: usize,
53}
54
55/// A Windows `ID3D11Texture2D` pointer (zero-copy path, not yet produced).
56#[derive(Debug, Clone, Copy, PartialEq, Eq)]
57pub struct D3D11TextureHandle {
58    pub ptr: usize,
59}
60
61/// Where a frame's pixels live.
62///
63/// Every backend currently produces `Host` (a plain CPU byte buffer); the
64/// native-handle variants are reserved for opt-in zero-copy support.
65#[derive(Debug, Clone, PartialEq)]
66pub enum FrameData {
67    /// CPU memory, rows packed at [`VideoFrame::stride`] bytes.
68    Host(Vec<u8>),
69    Dmabuf(DmabufFrame),
70    CvPixelBuffer(CvPixelBufferHandle),
71    D3D11Texture(D3D11TextureHandle),
72}
73
74/// One captured video frame with complete layout and timing metadata.
75#[derive(Debug, Clone, PartialEq)]
76pub struct VideoFrame {
77    /// Capture timestamp in nanoseconds, monotonic within a session and
78    /// comparable with [`AudioFrame::stream_time_ns`] of the same session.
79    /// The epoch is platform-dependent (boot time on macOS/Windows,
80    /// process-relative on Linux).
81    pub stream_time_ns: i64,
82    /// Per-stream counter advanced once per delivered frame; a jump means
83    /// frames were dropped.
84    pub sequence: u64,
85    pub width: u32,
86    pub height: u32,
87    /// Bytes from the start of one row to the next in [`FrameData::Host`].
88    pub stride: u32,
89    pub pixel_format: PixelFormat,
90    pub color_space: Option<ColorSpace>,
91    pub data: FrameData,
92    /// Changed regions since the previous frame, when the backend knows.
93    pub damage: Option<Vec<Rect>>,
94}
95
96/// Why a [`GapEvent`] was emitted.
97#[derive(Debug, Clone, Copy, PartialEq, Eq)]
98pub enum GapReason {
99    /// Frames were dropped because the consumer fell behind.
100    Dropped,
101    /// The stream format changed mid-session.
102    FormatChanged,
103    /// The backend recovered from losing its capture source (e.g. a display
104    /// mode switch invalidating DXGI duplication).
105    BackendRestarted,
106    Unknown,
107}
108
109/// A discontinuity notice: frames were lost or the stream restarted.
110#[derive(Debug, Clone, PartialEq, Eq)]
111pub struct GapEvent {
112    pub stream_time_ns: i64,
113    pub reason: GapReason,
114    pub dropped_frames: Option<u32>,
115}
116
117/// What [`CaptureSession::next_event`](crate::CaptureSession::next_event)
118/// yields.
119#[derive(Debug, Clone, PartialEq)]
120pub enum CaptureEvent {
121    Video(VideoFrame),
122    Audio(AudioFrame),
123    Gap(GapEvent),
124    /// The stream ended and no further events will arrive.
125    End,
126}