2025-06-26 16:17:31 -05:00

76 lines
2.8 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.

// client/src/output/video.rs
use gstreamer as gst;
use gstreamer_app as gst_app;
use gst::prelude::*;
use gst_app::prelude::*;
use lesavka_common::lesavka::VideoPacket;
use winit::window::{Window, WindowAttributes};
use winit::event_loop::EventLoop;
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()?;
let window = el.create_window(
WindowAttributes::default()
.with_title(format!("Lesavkamonitor{id}"))
.with_decorations(false)
)?;
let caps = gst::Caps::builder("video/x-h264")
.field("stream-format", &"byte-stream")
.field("alignment", &"au")
.build();
let desc = if std::env::var_os("LESAVKA_HW_DEC").is_some() {
"appsrc name=src is-live=true format=time do-timestamp=true block=false ! \
capsfilter caps=video/x-h264,stream-format=byte-stream,alignment=au ! \
queue max-size-buffers=0 max-size-bytes=0 max-size-time=0 leaky=downstream ! \
h264parse ! vaapih264dec low-latency=true ! videoconvert ! \
autovideosink sync=false max-lateness=-1"
} else {
"appsrc name=src is-live=true format=time do-timestamp=true block=false ! \
capsfilter caps=video/x-h264,stream-format=byte-stream,alignment=au ! \
queue max-size-buffers=0 max-size-bytes=0 max-size-time=0 leaky=downstream ! \
h264parse ! decodebin ! videoconvert ! autovideosink sync=false max-lateness=-1"
};
let pipeline = gst::parse::launch(desc)?
.downcast::<gst::Pipeline>()
.unwrap();
let src = pipeline.by_name("src").unwrap()
.downcast::<gst_app::AppSrc>().unwrap();
src.set_caps(Some(&caps));
// use the dedicated helpers from `AppSrcExt` instead of the generic
// `set_property`, which returns `()` (hence the earlier E0277).
src.set_format(gst::Format::Time); // timestamps are in running-time
// “blocksize=0” → deliver whole access-units (no chunking). The generic
// `set_property()` API returns a `Result<(), glib::BoolError>` so we just
// unwrap: this property always exists on AppSrc.
src.set_property("blocksize", &0u32);
src.set_latency(gst::ClockTime::NONE, gst::ClockTime::NONE);
pipeline.set_state(gst::State::Playing)?;
Ok(Self { id, _window: window, src })
}
pub fn push_packet(&self, pkt: VideoPacket) {
let mut buf = gst::Buffer::from_slice(pkt.data);
buf.get_mut().unwrap()
.set_pts(Some(gst::ClockTime::from_useconds(pkt.pts)));
let _ = self.src.push_buffer(buf);
}
}