use crate::gl::GpuReadback;
use crate::wl::{CapturedImage, DmabufFrame, Frame};
use anyhow::Result;
use std::time::Duration;
pub trait FrameSink {
fn push(&mut self, img: &CapturedImage, ts: Duration) -> Result<()>;
fn push_audio(&mut self, _pcm: &[f32]) {}
fn push_dmabuf(
&mut self,
rb: &mut GpuReadback,
frame: DmabufFrame,
ts: Duration,
) -> Result<()> {
let img = rb.readback(frame)?;
self.push(&img, ts)
}
fn finish(&mut self) -> Result<()> {
Ok(())
}
}
pub fn pump(
sink: &mut dyn FrameSink,
rb: &mut Option<GpuReadback>,
frame: Frame,
ts: Duration,
) -> Result<()> {
match frame {
Frame::Shm(img) => sink.push(&img, ts),
Frame::Dmabuf(d) => {
let rb = match rb {
Some(rb) => rb,
None => rb.insert(GpuReadback::new()?),
};
sink.push_dmabuf(rb, d, ts)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Default)]
struct Collect {
frames: Vec<(u32, u32, Duration)>,
finished: bool,
}
impl FrameSink for Collect {
fn push(&mut self, img: &CapturedImage, ts: Duration) -> Result<()> {
self.frames.push((img.width, img.height, ts));
Ok(())
}
fn finish(&mut self) -> Result<()> {
self.finished = true;
Ok(())
}
}
#[test]
fn pump_routes_shm_frames() {
let mut sink = Collect::default();
let mut rb = None; let img = CapturedImage {
width: 4,
height: 2,
rgba: vec![0; 4 * 2 * 4],
};
pump(
&mut sink,
&mut rb,
Frame::Shm(img),
Duration::from_millis(40),
)
.unwrap();
sink.finish().unwrap();
assert!(rb.is_none());
assert_eq!(sink.frames, vec![(4, 2, Duration::from_millis(40))]);
assert!(sink.finished);
}
}