vcs-camera-satellite/src/gst.rs
2024-09-22 01:12:47 +00:00

153 lines
4.3 KiB
Rust

use gstreamer::{
self as gst,
prelude::{
Cast, ElementExt, ElementExtManual, GObjectExtManualGst, GstBinExt, GstBinExtManual, PadExt,
},
ElementFactory,
};
use gstreamer_app as gst_app;
use crate::config::AppConfig;
pub struct Pipeline {
pub pipeline: gst::Pipeline,
pub sink: gst_app::AppSink,
}
const HEIGHT: usize = 480;
const SOCKET_PATH: &str = "/tmp/VCS-streamer-shm";
pub fn new_pipeline(config: &AppConfig) -> Pipeline {
let pipeline = gst::Pipeline::builder()
.name("camera_to_rtp_pipeine")
.build();
let source = {
#[cfg(target_os = "windows")]
{
ElementFactory::make("mfvideosrc")
.build()
.expect("Could not make mfvideosrc element!")
}
#[cfg(not(target_os = "windows"))]
{
ElementFactory::make("v4l2src")
.build()
.expect("Could not make mfvideosrc element!")
}
};
let video_convert = ElementFactory::make("videoconvert")
.build()
.expect("Could not make videoconvert gst element!");
let video_rate = ElementFactory::make("videorate")
.build()
.expect("Could not make videoscale gst element!");
let tee = ElementFactory::make("tee")
.build()
.expect("Could not make Tee gst element!");
let video_scale = ElementFactory::make("videoscale")
.property("add-borders", true)
.build()
.unwrap();
let video_scale_caps = gstreamer::Caps::builder("video/x-raw")
.field("height", HEIGHT as i32)
.field("width", (HEIGHT as f64 * config.aspect_ratio) as i32)
// .field("framerate", gstreamer::Fraction::new(30, 1))
.build();
// We are using VP8 because VP9 resulted in much worse video quality
// when testing -NY 8/25/2024
let vp8enc = ElementFactory::make("vp8enc")
.build()
.expect("Could not make vp8enc gst element!");
let rtp = ElementFactory::make("rtpvp8pay")
.build()
.expect("Could not make rtpvp8pay gst element!");
let app_sink = gst_app::AppSink::builder().build();
pipeline
.add_many([
&source,
&video_convert,
&video_rate,
&tee,
&video_scale,
&vp8enc,
&rtp,
app_sink.upcast_ref(),
])
.expect("Could not add all the stuff to the pipeline");
source
.link(&video_convert)
.expect("Could not link source to video convert");
let tee_caps = gstreamer::Caps::builder("video/x-raw").build();
video_convert
.link_filtered(&tee, &tee_caps)
.expect("Could not link video convert and tee!");
let tee_src_1 = tee
.request_pad_simple("src_%u")
.expect("Could not get src pad 1 from tee");
tee_src_1
.link(
&video_rate
.static_pad("sink")
.expect("Could not get static sink pad from video_rate"),
)
.expect("Could not link tee pad and video rate");
video_rate
.link(&video_scale)
.expect("Could not link video rate to video scale");
video_scale
.link_filtered(&vp8enc, &video_scale_caps)
.expect("Could not link videoscale to vp8enc with caps!");
gst::Element::link_many(&[&vp8enc, &rtp, app_sink.upcast_ref()])
.expect("Could not gst link vp8enc through appsink!");
#[cfg(not(target_os = "windows"))]
{
let hailo_sink = ElementFactory::make("shmsink")
.build()
.expect("Could not create the shared memory sink!");
hailo_sink.set_property_from_str("socket-path", SOCKET_PATH);
hailo_sink.set_property_from_str("sync", "true");
hailo_sink.set_property_from_str("wait-for-connection", "false");
pipeline
.add(&hailo_sink)
.expect("Could not add hailo shm to pipeline bin!");
let tee_src_2 = tee
.request_pad_simple("src_%u")
.expect("Could not create hailo tee src pad");
tee_src_2
.link(
&hailo_sink
.static_pad("sink")
.expect("Could not get hailo static sink pad"),
)
.expect("Could not link tee src pad to hailo sink pad");
}
Pipeline {
pipeline,
sink: app_sink,
}
}