mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2024-12-18 16:16:28 +00:00
0135aea9e4
extend the example to support both audio and video conversions Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/1938>
172 lines
5 KiB
Rust
172 lines
5 KiB
Rust
use std::process::exit;
|
|
|
|
use anyhow::Error;
|
|
use clap::Parser;
|
|
use gst::prelude::*;
|
|
|
|
#[derive(Parser, Debug)]
|
|
struct Args {
|
|
host_addr: String,
|
|
}
|
|
|
|
fn link_video(pad: &gst::Pad, pipeline: &gst::Pipeline) {
|
|
let q = gst::ElementFactory::make("queue")
|
|
.name(format!("queue_{}", pad.name()))
|
|
.build()
|
|
.unwrap();
|
|
|
|
let vc = gst::ElementFactory::make("videoconvert")
|
|
.name(format!("videoconvert_{}", pad.name()))
|
|
.build()
|
|
.unwrap();
|
|
|
|
let vsink = gst::ElementFactory::make("autovideosink")
|
|
.name(format!("vsink_{}", pad.name()))
|
|
.build()
|
|
.unwrap();
|
|
|
|
pipeline.add_many([&q, &vc, &vsink]).unwrap();
|
|
gst::Element::link_many([&q, &vc, &vsink]).unwrap();
|
|
let qsinkpad = q.static_pad("sink").unwrap();
|
|
pad.link(&qsinkpad).expect("linking should work");
|
|
|
|
q.sync_state_with_parent().unwrap();
|
|
vc.sync_state_with_parent().unwrap();
|
|
vsink.sync_state_with_parent().unwrap();
|
|
}
|
|
|
|
fn unlink_video(pad: &gst::Pad, pipeline: &gst::Pipeline) {
|
|
let q = pipeline
|
|
.by_name(format!("queue_{}", pad.name()).as_str())
|
|
.unwrap();
|
|
let vc = pipeline
|
|
.by_name(format!("videoconvert_{}", pad.name()).as_str())
|
|
.unwrap();
|
|
let vsink = pipeline
|
|
.by_name(format!("vsink_{}", pad.name()).as_str())
|
|
.unwrap();
|
|
|
|
q.set_state(gst::State::Null).unwrap();
|
|
vc.set_state(gst::State::Null).unwrap();
|
|
vsink.set_state(gst::State::Null).unwrap();
|
|
|
|
pipeline.remove_many([&q, &vsink]).unwrap();
|
|
}
|
|
|
|
fn link_audio(pad: &gst::Pad, pipeline: &gst::Pipeline) {
|
|
let aq = gst::ElementFactory::make("queue")
|
|
.name(format!("aqueue_{}", pad.name()))
|
|
.build()
|
|
.unwrap();
|
|
|
|
let ac = gst::ElementFactory::make("audioconvert")
|
|
.name(format!("audioconvert_{}", pad.name()))
|
|
.build()
|
|
.unwrap();
|
|
|
|
let asink = gst::ElementFactory::make("autoaudiosink")
|
|
.name(format!("asink_{}", pad.name()))
|
|
.build()
|
|
.unwrap();
|
|
|
|
pipeline.add_many([&aq, &ac, &asink]).unwrap();
|
|
gst::Element::link_many([&aq, &ac, &asink]).unwrap();
|
|
let qsinkpad = aq.static_pad("sink").unwrap();
|
|
pad.link(&qsinkpad).expect("linking should work");
|
|
|
|
aq.sync_state_with_parent().unwrap();
|
|
ac.sync_state_with_parent().unwrap();
|
|
asink.sync_state_with_parent().unwrap();
|
|
}
|
|
|
|
fn unlink_audio(pad: &gst::Pad, pipeline: &gst::Pipeline) {
|
|
let aq = pipeline
|
|
.by_name(format!("aqueue_{}", pad.name()).as_str())
|
|
.unwrap();
|
|
let ac = pipeline
|
|
.by_name(format!("audioconvert_{}", pad.name()).as_str())
|
|
.unwrap();
|
|
let asink = pipeline
|
|
.by_name(format!("asink_{}", pad.name()).as_str())
|
|
.unwrap();
|
|
|
|
aq.set_state(gst::State::Null).unwrap();
|
|
ac.set_state(gst::State::Null).unwrap();
|
|
asink.set_state(gst::State::Null).unwrap();
|
|
|
|
pipeline.remove_many([&aq, &asink]).unwrap();
|
|
}
|
|
|
|
fn main() -> Result<(), Error> {
|
|
gst::init()?;
|
|
|
|
let args = Args::parse();
|
|
|
|
let pipeline = gst::Pipeline::builder().build();
|
|
let ws = gst::ElementFactory::make("whipserversrc").build()?;
|
|
ws.dynamic_cast_ref::<gst::ChildProxy>()
|
|
.unwrap()
|
|
.set_child_property("signaller::host-addr", args.host_addr);
|
|
|
|
ws.set_property("enable-data-channel-navigation", true);
|
|
|
|
let pipe = pipeline.clone();
|
|
ws.connect_pad_added(move |_ws, pad| {
|
|
if pad.name().contains("video_") {
|
|
link_video(pad, &pipe);
|
|
} else if pad.name().contains("audio_") {
|
|
link_audio(pad, &pipe);
|
|
} else {
|
|
println!("unknown pad type {}", pad.name());
|
|
}
|
|
});
|
|
|
|
let pipe = pipeline.clone();
|
|
ws.connect_pad_removed(move |_ws, pad| {
|
|
if pad.name().contains("video_") {
|
|
unlink_video(pad, &pipe);
|
|
} else if pad.name().contains("audio_") {
|
|
unlink_audio(pad, &pipe);
|
|
} else {
|
|
println!("unknown pad type {}", pad.name());
|
|
}
|
|
});
|
|
pipeline.add(&ws)?;
|
|
pipeline.set_state(gst::State::Playing)?;
|
|
|
|
let p = pipeline.clone();
|
|
ctrlc::set_handler(move || {
|
|
p.set_state(gst::State::Null).unwrap();
|
|
exit(0);
|
|
})
|
|
.expect("Error setting Ctrl-C handler");
|
|
|
|
let bus = pipeline.bus().expect("Pipeline should have a bus");
|
|
for msg in bus.iter_timed(gst::ClockTime::NONE) {
|
|
use gst::MessageView;
|
|
|
|
match msg.view() {
|
|
MessageView::Eos(..) => {
|
|
println!("EOS");
|
|
break;
|
|
}
|
|
MessageView::Error(err) => {
|
|
pipeline.set_state(gst::State::Null)?;
|
|
eprintln!(
|
|
"Got error from {}: {} ({})",
|
|
msg.src()
|
|
.map(|s| String::from(s.path_string()))
|
|
.unwrap_or_else(|| "None".into()),
|
|
err.error(),
|
|
err.debug().unwrap_or_else(|| "".into()),
|
|
);
|
|
break;
|
|
}
|
|
_ => (),
|
|
}
|
|
}
|
|
|
|
pipeline.set_state(gst::State::Null)?;
|
|
|
|
Ok(())
|
|
}
|