153 lines
4.3 KiB
Rust
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,
|
|
}
|
|
}
|