rustgstreamergstreamer-rs

Chaining pad_added callback for multiple dynamic pad elements


I am working with a rtsp stream where the one of the channels is video and other could be either audio or onvif data.

I need to detect if the second rtspsrc pad(channel) is audio and then setup the pipeline to decode the audio stream.

First I detect if the newly added pad in rtspsrc is audio by adding a connect_pad_added. When it is audio then I create a decodebin and then attached to the src_pad and add another connect_pad_added to the decodebin this time to receive the src_pad and then create the rest of the pipeline.

Somehow the first connect_pad_added to the rtspsrc gets called but not the one I connect to the decode bin.

Is it not okay to chain the pad_added connections like that? What is a better way to do it in such a scenario?

Here is a code snippet of what I am doing.

From the pipeline launched through parse_launch I get the rtspsrc element let rtspsrc=pipeline.by_name("basesrc").

rtspsrc.connect_pad_added(|src, src_pad| {
    // get the pad struct and detect media type
    let media_type = src_pad.current_caps().and_then(|caps| {
        let new_pad_struct = caps
            .structure(0)
            .expect("Failed to get first structure of caps for audio");
        for i in 0..new_pad_struct.n_fields() {
            match new_pad_struct.nth_field_name(i).unwrap() {
                "media" => {
                    // check if field value starts with audio
                    audio = true
                }
                _ => {}
            }
        }
        Some(audio)
    });

    match media_type {
        Some(is_audio) => {
            if is_audio {
                let audio_decode = gst::ElementFactory::make("decodebin", None)
                    .expect("unable to create decodebin");
                pipeline
                    .add_many(&[&audio_decode])
                    .expect("unable to add audio decoder to pipeline bin");
                let sink_pad = audio_decode.static_pad("sink").ok_or(/*...*/);
                src_pad
                    .link(&sink_pad)
                    .expect("unable to link src_pad to audio_decode sinkpad");
                audio_decode.connect_pad_added(move |dbin, audio_src_pad| {
                    // setup the rest of pipeline audiodecoder ! encoder ! tee name=t t.! hlssink2.. t. ! hlssink2
                    //.....
                });
            }
        }
        None => {
            log::warn!("failed to get media_type from pad after pad added");
        }
    }
});

Solution

  • The issue was that once the pipeline is in running state, the newly added decodebin is not in same state as the rest of the pipeline.

    calling decodebin.sync_state_with_parent() after linking the rtspsrc.src->decodebin.sink fixed the problem.