GSTREAMER定期从流中获取当前功能

发布于 2025-02-04 00:00:55 字数 5527 浏览 3 评论 0原文

我正在从相机中摄入视频供稿,我想定期检查流的功能是否已更改(分辨率/音频/编码(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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

风蛊 2025-02-11 00:00:55

pad :: get_current_caps()将随时为您提供最新的帽如果分辨率基于静态SDP,则会更改。

您可能想在下游的垫子上检查帽子,例如视频解码器(或Depayloader或Parser)的源垫。

每当盖帽更换时,要通知您可以使用

let pad = video_decoder.static_pad("src").unwrap();
pad.connect_notify(Some("caps"), |pad, _pspec| {
  let current_caps = pad.current_caps();
  [...]
});

Pad::get_current_caps() will get you the latest caps at any time but in case of rtspsrc'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

let pad = video_decoder.static_pad("src").unwrap();
pad.connect_notify(Some("caps"), |pad, _pspec| {
  let current_caps = pad.current_caps();
  [...]
});
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文