compositor: freezes when new pad pushes buffer
Demo app:
// src/main.rs
use gstreamer::init;
use gstreamer::prelude::*;
use gstreamer::Caps;
use gstreamer::Element;
use gstreamer::ElementFactory;
use gstreamer::MessageView;
use gstreamer::Pipeline;
use gstreamer::State;
use gstreamer::CLOCK_TIME_NONE;
use std::thread;
use std::time::Duration;
fn main() {
init().unwrap();
let pipeline = Pipeline::new(None);
let videotestsrc = ElementFactory::make("videotestsrc", None).unwrap();
let capsfilter = ElementFactory::make("capsfilter", None).unwrap();
let compositor = ElementFactory::make("compositor", None).unwrap();
let capsfilter_out = ElementFactory::make("capsfilter", None).unwrap();
let autovideosink = ElementFactory::make("autovideosink", None).unwrap();
videotestsrc.set_property_from_str("pattern", "ball");
{
let caps = Caps::new_simple("video/x-raw", &[("width", &1280_i32), ("height", &720_i32)]);
capsfilter.set_property("caps", &caps).unwrap();
}
{
let caps = Caps::new_simple("video/x-raw", &[("width", &1280_i32), ("height", &720_i32)]);
capsfilter_out.set_property("caps", &caps).unwrap();
}
pipeline
.add_many(&[
&videotestsrc,
&capsfilter,
&compositor,
&capsfilter_out,
&autovideosink,
])
.unwrap();
Element::link_many(&[
&videotestsrc,
&capsfilter,
&compositor,
&capsfilter_out,
&autovideosink,
])
.unwrap();
pipeline.set_state(State::Playing).unwrap();
thread::spawn({
let pipeline = pipeline.clone();
move || {
for i in 0.. {
thread::sleep(Duration::from_secs(1));
println!("Adding extra source {}", i);
let videotestsrc = ElementFactory::make("videotestsrc", None).unwrap();
let capsfilter = ElementFactory::make("capsfilter", None).unwrap();
{
let caps = Caps::new_simple(
"video/x-raw",
&[("width", &1280_i32), ("height", &720_i32)],
);
capsfilter.set_property("caps", &caps).unwrap();
}
pipeline.add_many(&[&videotestsrc, &capsfilter]).unwrap();
videotestsrc.link(&capsfilter).unwrap();
let pad = compositor.get_request_pad("sink_%u").unwrap();
// Make it invisible, just to avoid covering ball from initial source
pad.set_property("alpha", &0.0_f64).unwrap();
capsfilter
.get_static_pad("src")
.unwrap()
.link(&pad)
.unwrap();
videotestsrc.sync_state_with_parent().unwrap();
capsfilter.sync_state_with_parent().unwrap();
}
}
});
let bus = pipeline.get_bus().unwrap();
for msg in bus.iter_timed(CLOCK_TIME_NONE) {
match msg.view() {
MessageView::Eos(..) => break,
MessageView::Error(err) => {
println!(
"Error from {:?}: {} ({:?})",
err.get_src().map(|s| s.get_path_string()),
err.get_error(),
err.get_debug()
);
break;
}
_ => (),
}
}
pipeline.set_state(State::Null).unwrap();
}
# Cargo.toml
[package]
authors = ["Nazar Mokrynskyi <nazar@mokrynskyi.com>"]
edition = "2018"
name = "test"
version = "0.0.0"
[dependencies.gstreamer]
features = ["v1_18"]
version = "0.16.2"
Basically there is a test video source with a ball moving and every second we add a new test video source, and with each new source we can see that ball freezes. The bigger resolution and number of sources is the longer is the freeze observed. While expected behavior is to not have freezes.
Another observation is that adding a pad is not enough, this seems to happen with the first buffer being sent via newly added pad.
I'm on 1.17, CPU is Core i9-9900K @4.8GHz all core, definitely enough to render a ball moving with a few extra sources without freezes.