I am ingesting a video feed from a camera and I want to periodically check if the capabilities of the stream have changed (resolution/audio/encoding(h264/265).
For this I added connect_pad_added signal to the rtspsrc and when a pad is available I use the pad to check for capabilities.
I use the same pad again in future to get the current caps. However the capabilities are not updating when the resolution changes.
Will the get_current_caps for the source pad not get the latest caps?
What is the right way to achieve this?
Here is a simplified version of my code in Rust
use glib::{Cast, ObjectExt};
use gst::MessageView;
use gst::prelude::{ElementExt, GstBinExt, GstObjectExt};
use gst::Pad;
use gst::prelude::PadExt;
use std::sync::{Arc, Mutex};
#[cfg(not(target_os = "macos"))]
pub fn run<T, F: FnOnce() -> T + Send + 'static>(main: F) -> T
where
T: Send + 'static,
{
main()
}
#[derive(Debug, Clone)]
struct SourcePads {
video_pad: Option<Pad>,
audio_pad: Option<Pad>,
}
impl SourcePads {
fn update_audio(&mut self, x: Option<&Pad>) {
match x {
Some(y) => self.audio_pad = Some(y.clone()),
None => self.audio_pad = None,
}
}
fn update_video(&mut self, x: Option<&Pad>) {
match x {
Some(y) => self.video_pad = Some(y.clone()),
None => self.video_pad = None,
}
}
}
fn typefinder_main() {
gst::init().unwrap();
let pipe_str = format!("rtspsrc location={} name=rtspsrc0 rtspsrc0. ! rtph265depay ! tee name=t t.! queue ! hlssink2 name=ingest1 target-duration=2 playlist-location=stream.m3u8 location=%d.ts ", "rtsp://admin:pass@10.0.0.12:554/");
let pipeline = gst::parse_launch(pipe_str.as_str()).unwrap();
let pipeline = pipeline.dynamic_cast::<gst::Pipeline>().unwrap();
let mut source_pads = SourcePads{video_pad: None, audio_pad: None};
let source_pads = Mutex::new(source_pads);
let source_pads = Arc::new(source_pads);
pipeline.set_state(gst::State::Playing);
let bus = pipeline.bus().expect("unable to get bus");
let rtspsrc = pipeline.by_name("rtspsrc0").unwrap();
let mut src_pad_clone = source_pads.clone();
rtspsrc.connect_pad_added(move |src, src_pad | {
let new_pad_caps = src_pad.current_caps().expect("failed to get caps of new pad");
let new_pad_struct = new_pad_caps.structure(0).expect("Failed to get first structure of caps");
for x in 0..new_pad_struct.n_fields() {
let field_name = new_pad_struct.nth_field_name(x).unwrap();
new_pad_struct.value(new_pad_struct.nth_field_name(x).unwrap()).unwrap());
if field_name.starts_with("media") {
let media_type = new_pad_struct.value(field_name).unwrap();
let field_value = media_type.get::<&str>().unwrap();
if field_value.starts_with("audio") {
if let Ok(mut x) = src_pad_clone.lock() {
x.update_audio(Some(src_pad));
}
} else if field_value.starts_with("video") {
if let Ok(mut x) = src_pad_clone.lock() {
x.update_video(Some(src_pad));
}
}
}
}
});
let pipeline_weak = pipeline.downgrade();
//////// use depay to get the current caps ////
let depay = pipeline.by_name("rtph265depay0").unwrap();
let pad = depay.static_pad("src").unwrap();
pad.connect_notify(Some("caps"), |pad, _pspec| {
let current_caps = pad.current_caps().expect("failed to get caps from depay");
let new_pad_struct = current_caps.structure(0).expect("failed to get first structure");
println!("DEPAY CAPS={:#?}", new_pad_struct);
});
//////// use depay to get the current caps ////
for msg in bus.iter_timed(gst::ClockTime::NONE) {
match msg.view() {
MessageView::Eos(..) => {println!("end of stream");
match pipeline_weak.upgrade() {
Some(pipeline) => {
if let Ok(mut x) = source_pads.lock() {
x.update_audio(None);
x.update_video(None);
}
pipeline.set_state(gst::State::Ready);
pipeline.set_state(gst::State::Playing);
},
None => {println!("Could not get the pipeline")},
};
}
MessageView::Error(err) => println!("received an error e: {:#?}", err),
MessageView::StateChanged(s) => {
println!(
"State changed from {:?}: {:?} -> {:?} ({:?})",
s.src().map(|s| s.path_string()),
s.old(),
s.current(),
s.pending()
);
if let Ok(x) = source_pads.lock() {
match &x.video_pad {
Some(video_pad) => {
let new_pad_caps = video_pad.current_caps().expect("failed to get caps for video pad");
let new_pad_struct = new_pad_caps.structure(0).expect("failed to get first structure of caps");
println!("CAPS FROM BUS={:#?}", new_pad_struct);
}
None => println!("video pad not found"),
}
}
}
_ => (),
}
}
pipeline.set_state(gst::State::Null).unwrap();
}
fn main() {
typefinder_main();
}
Thanks a lot for your help!