GSTREAMER定期从流中获取当前功能
我正在从相机中摄入视频供稿,我想定期检查流的功能是否已更改(分辨率/音频/编码(H264/265)。
为此,我添加了connect_pad_pad_added
信号信号RTSPRC
,当有PAD时,我会
在将来再次使用相同的垫子来获得当前的
帽子 cops 无法获得最新的上限
?
/
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:[email protected]: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();
}
get_current_caps <
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:[email protected]: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!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
pad :: get_current_caps()
将随时为您提供最新的帽如果分辨率基于静态SDP,则会更改。您可能想在下游的垫子上检查帽子,例如视频解码器(或Depayloader或Parser)的源垫。
每当盖帽更换时,要通知您可以使用
Pad::get_current_caps()
will get you the latest caps at any time but in case ofrtspsrc
's source pads these caps generally don't contain the resolution and especially won't change if the resolution changes as they're based on the static SDP.You probably want to check the caps on a pad further downstream, e.g. the source pad of the video decoder (or the depayloader or parser).
To get notified whenever the caps are changing you could use