styx_capture/
virtual_backend.rs

1//! Virtual capture backend that emits patterned frames from a buffer pool.
2use std::sync::atomic::{AtomicU64, Ordering};
3
4use styx_core::prelude::*;
5
6use crate::{CaptureConfig, CaptureDescriptor, CaptureSource, Mode};
7
8/// Simple virtual capture backend that emits patterned frames from a buffer pool.
9///
10/// # Example
11/// ```rust
12/// use styx_capture::prelude::*;
13///
14/// let pool = BufferPool::with_capacity(1, 128);
15/// let res = Resolution::new(4, 4).unwrap();
16/// let format = MediaFormat::new(FourCc::new(*b"RG24"), res, ColorSpace::Srgb);
17/// let mode = Mode {
18///     id: ModeId { format, interval: None },
19///     format,
20///     intervals: smallvec::smallvec![],
21///     interval_stepwise: None,
22/// };
23/// let source = VirtualCapture::new(mode, pool, 3);
24/// let frame = source.next_frame().unwrap();
25/// assert_eq!(frame.meta().format.code.to_string(), "RG24");
26/// ```
27pub struct VirtualCapture {
28    descriptor: CaptureDescriptor,
29    pool: BufferPool,
30    mode: Mode,
31    bytes_per_pixel: usize,
32    counter: AtomicU64,
33}
34
35impl VirtualCapture {
36    /// Create a virtual source using the provided mode and pool.
37    pub fn new(mode: Mode, pool: BufferPool, bytes_per_pixel: usize) -> Self {
38        let descriptor = CaptureDescriptor {
39            modes: vec![mode.clone()],
40            controls: Vec::new(),
41        };
42        Self {
43            descriptor,
44            pool,
45            mode,
46            bytes_per_pixel,
47            counter: AtomicU64::new(0),
48        }
49    }
50
51    fn next_payload(&self, timestamp: u64) -> FrameLease {
52        crate::build_frame_from_pool(
53            self.mode.format,
54            &self.pool,
55            timestamp,
56            self.bytes_per_pixel,
57        )
58    }
59
60    /// Emit a single frame and return whether it was accepted by the downstream queue.
61    pub fn tick(&self, _config: &CaptureConfig, sink: &BoundedTx<FrameLease>) -> SendOutcome {
62        let ts = self.counter.fetch_add(1, Ordering::Relaxed);
63        let mut frame = self.next_payload(ts);
64        for mut plane in frame.planes_mut() {
65            for byte in plane.data().iter_mut() {
66                *byte = (ts % 256) as u8;
67            }
68        }
69        sink.send(frame)
70    }
71}
72
73impl CaptureSource for VirtualCapture {
74    fn descriptor(&self) -> &CaptureDescriptor {
75        &self.descriptor
76    }
77
78    fn next_frame(&self) -> Option<FrameLease> {
79        let ts = self.counter.fetch_add(1, Ordering::Relaxed);
80        Some(self.next_payload(ts))
81    }
82}