// client/src/output/video.rs use gstreamer as gst; use gstreamer_app as gst_app; use gst::prelude::*; use navka_common::navka::VideoPacket; use winit::{ event_loop::EventLoop, window::{Window, WindowBuilder}, }; pub struct MonitorWindow { id: u32, _window: Window, src: gst_app::AppSrc, } impl MonitorWindow { pub fn new(id: u32, el: &EventLoop<()>) -> anyhow::Result { gst::init()?; let window = WindowBuilder::new() .with_title(format!("Lesavka‑monitor‑{id}")) .with_decorations(false) .build(el)?; // appsrc -> decode -> convert -> waylandsink let pipeline = gst::parse_launch( "appsrc name=src is-live=true format=time do-timestamp=true ! \ queue ! h264parse ! avdec_h264 ! videoconvert ! \ waylandsink name=sink sync=false", )? .downcast::()?; let src = pipeline.by_name("src").unwrap().downcast::()?; src.set_latency(gst::ClockTime::NONE); src.set_property_format(gst::Format::Time); pipeline.set_state(gst::State::Playing)?; Ok(Self { id, _window: window, src }) } pub fn push_packet(&self, pkt: VideoPacket) { if let Ok(mut buf) = gst::Buffer::from_mut_slice(pkt.data) { buf.set_pts(gst::ClockTime::from_microseconds(pkt.pts)); let _ = self.src.push_buffer(buf); } } }