2025-06-28 00:05:13 -05:00

85 lines
2.9 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use gstreamer as gst;
use gstreamer_app as gst_app;
use gst::prelude::*;
use lesavka_common::lesavka::VideoPacket;
use winit::{
event_loop::EventLoop,
window::{Window, WindowAttributes},
};
const DESC: &str = concat!(
"appsrc name=src is-live=true format=time do-timestamp=true block=false ! ",
"queue max-size-buffers=0 max-size-bytes=0 max-size-time=0 leaky=downstream ! ",
"capsfilter caps=video/x-h264,stream-format=byte-stream,alignment=au ! ",
"h264parse disable-passthrough=true ! decodebin ! ",
"queue ! videoconvert ! autovideosink sync=false"
);
pub struct MonitorWindow {
id: u32,
_window: Window,
src: gst_app::AppSrc,
}
impl MonitorWindow {
pub fn new(id: u32, el: &EventLoop<()>) -> anyhow::Result<Self> {
gst::init()?; // idempotent
/* ---------- Wayland / X11 window ------------- */
let window = el
.create_window(
WindowAttributes::default()
.with_title(format!("Lesavka-eye-{id}"))
.with_decorations(true),
)?;
/* ---------- GStreamer pipeline --------------- */
let caps = gst::Caps::builder("video/x-h264")
.field("stream-format", &"byte-stream")
.field("alignment", &"au")
.build();
// let pipeline = gst::parse::launch(DESC)?
// .downcast::<gst::Pipeline>()
// .expect("pipeline downcast");
let pipeline: gst::Pipeline = gst::parse::launch(DESC)?
.downcast()
.expect("pipeline");
// let src = pipeline
// .by_name("src")
// .expect("appsrc element not found")
// .downcast::<gst_app::AppSrc>()
// .expect("appsrc downcast");
let src: gst_app::AppSrc = pipeline.by_name("src")
.expect("appsrc")
.downcast()
.expect("appsrc");
src.set_caps(Some(&caps));
src.set_format(gst::Format::Time); // downstream clock
src.set_property("blocksize", &0u32); // one AU per buffer
// NOTE: set_property() and friends return (), so no `?`
src.set_property("do-timestamp", &true);
src.set_latency(gst::ClockTime::NONE, gst::ClockTime::NONE);
pipeline.set_state(gst::State::Playing)?;
Ok(Self { id, _window: window, src })
}
/// Feed one H.264 accessunit into the pipeline.
pub fn push_packet(&self, pkt: VideoPacket) {
// Mutable so we can set the PTS:
let mut buf = gst::Buffer::from_slice(pkt.data);
// if let Some(ref mut b) = buf.get_mut() {
// b.set_pts(Some(gst::ClockTime::from_useconds(pkt.pts)));
// }
{
let b = buf.get_mut().unwrap();
b.set_pts(Some(gst::ClockTime::from_useconds(pkt.pts)));
}
let _ = self.src.push_buffer(buf); // ignore Eos / flushing
}
}