mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2024-12-28 21:10:34 +00:00
e905299eba
This new plugin exposes two elements, intersink and intersrc. These act as wormholes for data in the same process and can be used to forward data from one pipeline to another. The implementation makes use of gstreamer-utils' StreamProducer, and supports dynamically adding and removing consumers, before and after producers, and changing producer names while PLAYING, both on the sink and the src. This initial implementation comes with a small demo, and a few tests. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/1257>
138 lines
4 KiB
Rust
138 lines
4 KiB
Rust
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
use gst::prelude::*;
|
|
use serial_test::serial;
|
|
|
|
use pretty_assertions::assert_eq;
|
|
|
|
fn init() {
|
|
use std::sync::Once;
|
|
static INIT: Once = Once::new();
|
|
|
|
INIT.call_once(|| {
|
|
gst::init().unwrap();
|
|
gstrsinter::plugin_register_static().unwrap();
|
|
});
|
|
}
|
|
|
|
fn start_consumer(producer_name: &str) -> gst_check::Harness {
|
|
let mut hc = gst_check::Harness::new("intersrc");
|
|
|
|
hc.element()
|
|
.unwrap()
|
|
.set_property("producer-name", producer_name);
|
|
hc.play();
|
|
|
|
hc
|
|
}
|
|
|
|
fn start_producer(producer_name: &str) -> (gst::Pad, gst::Element) {
|
|
let element = gst::ElementFactory::make("intersink").build().unwrap();
|
|
|
|
element.set_property("producer-name", producer_name);
|
|
element.set_state(gst::State::Playing).unwrap();
|
|
|
|
let sinkpad = element.static_pad("sink").unwrap();
|
|
let srcpad = gst::Pad::new(gst::PadDirection::Src);
|
|
srcpad.set_active(true).unwrap();
|
|
srcpad.link(&sinkpad).unwrap();
|
|
|
|
srcpad.push_event(gst::event::StreamStart::builder("foo").build());
|
|
srcpad
|
|
.push_event(gst::event::Caps::builder(&gst::Caps::builder("video/x-raw").build()).build());
|
|
srcpad.push_event(
|
|
gst::event::Segment::builder(&gst::FormattedSegment::<gst::format::Time>::new()).build(),
|
|
);
|
|
|
|
(srcpad, element)
|
|
}
|
|
|
|
fn push_one(srcpad: &gst::Pad, pts: gst::ClockTime) {
|
|
let mut inbuf = gst::Buffer::with_size(1).unwrap();
|
|
|
|
{
|
|
let buf = inbuf.get_mut().unwrap();
|
|
buf.set_pts(pts);
|
|
}
|
|
|
|
srcpad.push(inbuf).unwrap();
|
|
}
|
|
|
|
#[test]
|
|
#[serial]
|
|
fn test_forward_one_buffer() {
|
|
init();
|
|
|
|
let mut hc = start_consumer("p1");
|
|
let (srcpad, element) = start_producer("p1");
|
|
|
|
push_one(&srcpad, gst::ClockTime::from_nseconds(1));
|
|
|
|
let outbuf = hc.pull().unwrap();
|
|
|
|
assert_eq!(outbuf.pts(), Some(gst::ClockTime::from_nseconds(1)));
|
|
|
|
element.set_state(gst::State::Null).unwrap();
|
|
}
|
|
|
|
#[test]
|
|
#[serial]
|
|
fn test_change_name_of_producer() {
|
|
init();
|
|
|
|
let mut hc1 = start_consumer("p1");
|
|
let mut hc2 = start_consumer("p2");
|
|
let (srcpad, element) = start_producer("p1");
|
|
|
|
/* Once this returns, the buffer should have been dispatched only to hc1 */
|
|
push_one(&srcpad, gst::ClockTime::from_nseconds(1));
|
|
let outbuf = hc1.pull().unwrap();
|
|
assert_eq!(outbuf.pts(), Some(gst::ClockTime::from_nseconds(1)));
|
|
|
|
element.set_property("producer-name", "p2");
|
|
|
|
/* This should only get dispatched to hc2, and it should be its first buffer */
|
|
push_one(&srcpad, gst::ClockTime::from_nseconds(2));
|
|
let outbuf = hc2.pull().unwrap();
|
|
assert_eq!(outbuf.pts(), Some(gst::ClockTime::from_nseconds(2)));
|
|
|
|
element.set_property("producer-name", "p1");
|
|
|
|
/* Back to hc1, which should not see the buffer we pushed in the previous step */
|
|
push_one(&srcpad, gst::ClockTime::from_nseconds(3));
|
|
let outbuf = hc1.pull().unwrap();
|
|
assert_eq!(outbuf.pts(), Some(gst::ClockTime::from_nseconds(3)));
|
|
|
|
element.set_state(gst::State::Null).unwrap();
|
|
}
|
|
|
|
#[test]
|
|
#[serial]
|
|
fn test_change_producer_name() {
|
|
init();
|
|
|
|
let mut hc = start_consumer("p1");
|
|
let (srcpad1, element1) = start_producer("p1");
|
|
let (srcpad2, element2) = start_producer("p2");
|
|
|
|
/* This buffer should be dispatched to no consumer */
|
|
push_one(&srcpad2, gst::ClockTime::from_nseconds(1));
|
|
|
|
/* This one should be dispatched to hc, and it should be its first buffer */
|
|
push_one(&srcpad1, gst::ClockTime::from_nseconds(2));
|
|
let outbuf = hc.pull().unwrap();
|
|
assert_eq!(outbuf.pts(), Some(gst::ClockTime::from_nseconds(2)));
|
|
|
|
hc.element().unwrap().set_property("producer-name", "p2");
|
|
|
|
/* This buffer should be dispatched to no consumer */
|
|
push_one(&srcpad1, gst::ClockTime::from_nseconds(3));
|
|
|
|
/* This one should be dispatched to hc, and it should be its next buffer */
|
|
push_one(&srcpad2, gst::ClockTime::from_nseconds(4));
|
|
let outbuf = hc.pull().unwrap();
|
|
assert_eq!(outbuf.pts(), Some(gst::ClockTime::from_nseconds(4)));
|
|
|
|
element1.set_state(gst::State::Null).unwrap();
|
|
element2.set_state(gst::State::Null).unwrap();
|
|
}
|