gstreamer: move parse_* functions to their own module

Better namespacing so the API is more Rust-y.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1355>
This commit is contained in:
Guillaume Desmottes 2023-12-01 16:53:44 +01:00
parent f255b82b55
commit a649e7dead
24 changed files with 177 additions and 158 deletions

View file

@ -48,7 +48,7 @@ fn example_main() {
let main_loop = glib::MainLoop::new(None, false); let main_loop = glib::MainLoop::new(None, false);
// This creates a pipeline by parsing the gst-launch pipeline syntax. // This creates a pipeline by parsing the gst-launch pipeline syntax.
let pipeline = gst::parse_launch( let pipeline = gst::parse::launch(
"audiotestsrc name=src ! queue max-size-time=2000000000 ! fakesink name=sink sync=true", "audiotestsrc name=src ! queue max-size-time=2000000000 ! fakesink name=sink sync=true",
) )
.unwrap(); .unwrap();

View file

@ -27,7 +27,7 @@ fn example_main() {
let mut context = gst::ParseContext::new(); let mut context = gst::ParseContext::new();
let pipeline = let pipeline =
match gst::parse_launch_full(pipeline_str, Some(&mut context), gst::ParseFlags::empty()) { match gst::parse::launch_full(pipeline_str, Some(&mut context), gst::ParseFlags::empty()) {
Ok(pipeline) => pipeline, Ok(pipeline) => pipeline,
Err(err) => { Err(err) => {
if let Some(gst::ParseError::NoSuchElement) = err.kind::<gst::ParseError>() { if let Some(gst::ParseError::NoSuchElement) = err.kind::<gst::ParseError>() {

View file

@ -30,7 +30,7 @@ fn example_main() {
let main_loop = glib::MainLoop::new(None, false); let main_loop = glib::MainLoop::new(None, false);
// This creates a pipeline by parsing the gst-launch pipeline syntax. // This creates a pipeline by parsing the gst-launch pipeline syntax.
let pipeline = gst::parse_launch("audiotestsrc ! fakesink").unwrap(); let pipeline = gst::parse::launch("audiotestsrc ! fakesink").unwrap();
let bus = pipeline.bus().unwrap(); let bus = pipeline.bus().unwrap();
pipeline pipeline

View file

@ -42,7 +42,7 @@ fn example_main() {
gst::init().unwrap(); gst::init().unwrap();
// Create a pipeline from the launch-syntax given on the cli. // Create a pipeline from the launch-syntax given on the cli.
let pipeline = gst::parse_launch(&pipeline_str).unwrap(); let pipeline = gst::parse::launch(&pipeline_str).unwrap();
let bus = pipeline.bus().unwrap(); let bus = pipeline.bus().unwrap();
pipeline pipeline

View file

@ -42,7 +42,7 @@ fn example_main() {
gst::init().unwrap(); gst::init().unwrap();
// Create a pipeline from the launch-syntax given on the cli. // Create a pipeline from the launch-syntax given on the cli.
let pipeline = gst::parse_launch(&pipeline_str).unwrap(); let pipeline = gst::parse::launch(&pipeline_str).unwrap();
let bus = pipeline.bus().unwrap(); let bus = pipeline.bus().unwrap();
pipeline pipeline

View file

@ -26,8 +26,11 @@ fn example_main() {
// Especially GUIs should probably handle this case, to tell users that they need to // Especially GUIs should probably handle this case, to tell users that they need to
// install the corresponding gstreamer plugins. // install the corresponding gstreamer plugins.
let mut context = gst::ParseContext::new(); let mut context = gst::ParseContext::new();
let pipeline = let pipeline = match gst::parse::launch_full(
match gst::parse_launch_full(&pipeline_str, Some(&mut context), gst::ParseFlags::empty()) { &pipeline_str,
Some(&mut context),
gst::ParseFlags::empty(),
) {
Ok(pipeline) => pipeline, Ok(pipeline) => pipeline,
Err(err) => { Err(err) => {
if let Some(gst::ParseError::NoSuchElement) = err.kind::<gst::ParseError>() { if let Some(gst::ParseError::NoSuchElement) = err.kind::<gst::ParseError>() {

View file

@ -24,7 +24,7 @@ fn example_main() {
let main_loop = glib::MainLoop::new(None, false); let main_loop = glib::MainLoop::new(None, false);
// Let GStreamer create a pipeline from the parsed launch syntax on the cli. // Let GStreamer create a pipeline from the parsed launch syntax on the cli.
let pipeline = gst::parse_launch(&pipeline_str).unwrap(); let pipeline = gst::parse::launch(&pipeline_str).unwrap();
let bus = pipeline.bus().unwrap(); let bus = pipeline.bus().unwrap();
pipeline pipeline

View file

@ -22,7 +22,7 @@ fn example_main() {
// Parse the pipeline we want to probe from a static in-line string. // Parse the pipeline we want to probe from a static in-line string.
// Here we give our audiotestsrc a name, so we can retrieve that element // Here we give our audiotestsrc a name, so we can retrieve that element
// from the resulting pipeline. // from the resulting pipeline.
let pipeline = gst::parse_launch(&format!( let pipeline = gst::parse::launch(&format!(
"audiotestsrc name=src ! audio/x-raw,format={},channels=1 ! fakesink", "audiotestsrc name=src ! audio/x-raw,format={},channels=1 ! fakesink",
gst_audio::AUDIO_FORMAT_S16 gst_audio::AUDIO_FORMAT_S16
)) ))

View file

@ -28,7 +28,7 @@ fn example_main() {
let main_loop = glib::MainLoop::new(None, false); let main_loop = glib::MainLoop::new(None, false);
// Let GStreamer create a pipeline from the parsed launch syntax on the cli. // Let GStreamer create a pipeline from the parsed launch syntax on the cli.
let pipeline = gst::parse_launch(&pipeline_str).unwrap(); let pipeline = gst::parse::launch(&pipeline_str).unwrap();
let bus = pipeline.bus().unwrap(); let bus = pipeline.bus().unwrap();
pipeline pipeline

View file

@ -42,7 +42,7 @@ fn example_main() -> Result<(), Error> {
// Parse the pipeline we want to probe from a static in-line string. // Parse the pipeline we want to probe from a static in-line string.
let mut context = gst::ParseContext::new(); let mut context = gst::ParseContext::new();
let pipeline = match gst::parse_launch_full( let pipeline = match gst::parse::launch_full(
"audiotestsrc wave=white-noise num-buffers=100 ! flacenc ! filesink location=test.flac", "audiotestsrc wave=white-noise num-buffers=100 ! flacenc ! filesink location=test.flac",
Some(&mut context), Some(&mut context),
gst::ParseFlags::empty(), gst::ParseFlags::empty(),

View file

@ -27,7 +27,7 @@ fn create_pipeline(uri: String, out_path: std::path::PathBuf) -> Result<gst::Pip
gst::init()?; gst::init()?;
// Create our pipeline from a pipeline description string. // Create our pipeline from a pipeline description string.
let pipeline = gst::parse_launch(&format!( let pipeline = gst::parse::launch(&format!(
"uridecodebin uri={uri} ! videoconvert ! appsink name=sink" "uridecodebin uri={uri} ! videoconvert ! appsink name=sink"
))? ))?
.downcast::<gst::Pipeline>() .downcast::<gst::Pipeline>()

View file

@ -11,7 +11,7 @@ fn example_main() {
gst::init().unwrap(); gst::init().unwrap();
// This creates a pipeline by parsing the gst-launch pipeline syntax. // This creates a pipeline by parsing the gst-launch pipeline syntax.
let pipeline = gst::parse_launch( let pipeline = gst::parse::launch(
"videotestsrc name=src ! video/x-raw,width=640,height=480 ! compositor0.sink_0 \ "videotestsrc name=src ! video/x-raw,width=640,height=480 ! compositor0.sink_0 \
compositor ! video/x-raw,width=1280,height=720 ! videoconvert ! autovideosink", compositor ! video/x-raw,width=1280,height=720 ! videoconvert ! autovideosink",
) )

View file

@ -83,7 +83,7 @@ fn example_main() {
gst::init().unwrap(); gst::init().unwrap();
let pipeline = gst::parse_launch(&format!( let pipeline = gst::parse::launch(&format!(
"compositor name=mix background=1 sink_0::xpos=0 sink_0::ypos=0 sink_0::zorder=0 sink_0::width={WIDTH} sink_0::height={HEIGHT} ! xvimagesink \ "compositor name=mix background=1 sink_0::xpos=0 sink_0::ypos=0 sink_0::zorder=0 sink_0::width={WIDTH} sink_0::height={HEIGHT} ! xvimagesink \
videotestsrc name=src ! video/x-raw,framerate=30/1,width={WIDTH},height={HEIGHT},pixel-aspect-ratio=1/1 ! queue ! mix.sink_0" videotestsrc name=src ! video/x-raw,framerate=30/1,width={WIDTH},height={HEIGHT},pixel-aspect-ratio=1/1 ! queue ! mix.sink_0"
)).unwrap().downcast::<gst::Pipeline>().unwrap(); )).unwrap().downcast::<gst::Pipeline>().unwrap();

View file

@ -646,7 +646,7 @@ mod tests {
StreamProducer, StreamProducer,
) { ) {
let producer_pipe = let producer_pipe =
gst::parse_launch("appsrc name=producer_src ! appsink name=producer_sink") gst::parse::launch("appsrc name=producer_src ! appsink name=producer_sink")
.unwrap() .unwrap()
.downcast::<gst::Pipeline>() .downcast::<gst::Pipeline>()
.unwrap(); .unwrap();
@ -678,7 +678,7 @@ mod tests {
impl Consumer { impl Consumer {
fn new(id: &str) -> Self { fn new(id: &str) -> Self {
let pipeline = gst::parse_launch(&format!("appsrc name={id} ! appsink name=sink")) let pipeline = gst::parse::launch(&format!("appsrc name={id} ! appsink name=sink"))
.unwrap() .unwrap()
.downcast::<gst::Pipeline>() .downcast::<gst::Pipeline>()
.unwrap(); .unwrap();

View file

@ -2,125 +2,17 @@
use std::ptr; use std::ptr;
use glib::{prelude::*, translate::*}; use glib::translate::*;
#[cfg(feature = "v1_18")] #[cfg(feature = "v1_18")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
use crate::Tracer; use crate::Tracer;
use crate::{Bin, Element, Object, ParseContext, ParseFlags};
// import only functions which do not have their own module as namespace // import only functions which do not have their own module as namespace
pub use crate::auto::functions::{ pub use crate::auto::functions::{
main_executable_path, parse_bin_from_description, parse_launch, parse_launchv, update_registry, main_executable_path, update_registry, util_get_timestamp, version, version_string,
util_get_timestamp, version, version_string,
}; };
pub fn parse_bin_from_description_with_name(
bin_description: &str,
ghost_unlinked_pads: bool,
bin_name: &str,
) -> Result<Bin, glib::Error> {
skip_assert_initialized!();
let bin = parse_bin_from_description(bin_description, ghost_unlinked_pads)?;
if !bin_name.is_empty() {
let obj = bin.clone().upcast::<Object>();
unsafe {
ffi::gst_object_set_name(obj.to_glib_none().0, bin_name.to_glib_none().0);
}
}
Ok(bin)
}
#[doc(alias = "gst_parse_bin_from_description_full")]
pub fn parse_bin_from_description_full(
bin_description: &str,
ghost_unlinked_pads: bool,
mut context: Option<&mut ParseContext>,
flags: ParseFlags,
) -> Result<Element, glib::Error> {
skip_assert_initialized!();
unsafe {
let mut error = ptr::null_mut();
let ret = ffi::gst_parse_bin_from_description_full(
bin_description.to_glib_none().0,
ghost_unlinked_pads.into_glib(),
context.to_glib_none_mut().0,
flags.into_glib(),
&mut error,
);
if error.is_null() {
Ok(from_glib_none(ret))
} else {
Err(from_glib_full(error))
}
}
}
pub fn parse_bin_from_description_with_name_full(
bin_description: &str,
ghost_unlinked_pads: bool,
bin_name: &str,
context: Option<&mut ParseContext>,
flags: ParseFlags,
) -> Result<Element, glib::Error> {
skip_assert_initialized!();
let bin =
parse_bin_from_description_full(bin_description, ghost_unlinked_pads, context, flags)?;
if !bin_name.is_empty() {
let obj = bin.clone().upcast::<Object>();
unsafe {
ffi::gst_object_set_name(obj.to_glib_none().0, bin_name.to_glib_none().0);
}
}
Ok(bin)
}
#[doc(alias = "gst_parse_launch_full")]
pub fn parse_launch_full(
pipeline_description: &str,
mut context: Option<&mut ParseContext>,
flags: ParseFlags,
) -> Result<Element, glib::Error> {
assert_initialized_main_thread!();
unsafe {
let mut error = ptr::null_mut();
let ret = ffi::gst_parse_launch_full(
pipeline_description.to_glib_none().0,
context.to_glib_none_mut().0,
flags.into_glib(),
&mut error,
);
if error.is_null() {
Ok(from_glib_none(ret))
} else {
Err(from_glib_full(error))
}
}
}
#[doc(alias = "gst_parse_launchv_full")]
pub fn parse_launchv_full(
argv: &[&str],
mut context: Option<&mut ParseContext>,
flags: ParseFlags,
) -> Result<Element, glib::Error> {
assert_initialized_main_thread!();
unsafe {
let mut error = ptr::null_mut();
let ret = ffi::gst_parse_launchv_full(
argv.to_glib_none().0,
context.to_glib_none_mut().0,
flags.into_glib(),
&mut error,
);
if error.is_null() {
Ok(from_glib_none(ret))
} else {
Err(from_glib_full(error))
}
}
}
#[doc(alias = "gst_calculate_linear_regression")] #[doc(alias = "gst_calculate_linear_regression")]
pub fn calculate_linear_regression( pub fn calculate_linear_regression(
xy: &[(u64, u64)], xy: &[(u64, u64)],
@ -181,7 +73,6 @@ pub fn active_tracers() -> glib::List<Tracer> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::prelude::*;
#[test] #[test]
fn test_calculate_linear_regression() { fn test_calculate_linear_regression() {
@ -197,18 +88,4 @@ mod tests {
calculate_linear_regression(&values, Some(&mut temp)).unwrap(); calculate_linear_regression(&values, Some(&mut temp)).unwrap();
assert_eq!((m_num, m_denom, b, xbase), (10, 10, 3, 3)); assert_eq!((m_num, m_denom, b, xbase), (10, 10, 3, 3));
} }
#[test]
fn test_parse_bin_from_description_with_name() {
crate::init().unwrap();
let bin =
parse_bin_from_description_with_name("fakesrc ! fakesink", false, "all_fake").unwrap();
let name = bin.name();
assert_eq!(name, "all_fake");
let bin = parse_bin_from_description_with_name("fakesrc ! fakesink", false, "").unwrap();
let name = bin.name();
assert_ne!(name, "");
}
} }

View file

@ -259,6 +259,8 @@ pub use crate::functions::*;
mod utils; mod utils;
pub use crate::utils::ObjectLockGuard; pub use crate::utils::ObjectLockGuard;
pub mod parse;
#[cfg(feature = "v1_18")] #[cfg(feature = "v1_18")]
mod gtype; mod gtype;

137
gstreamer/src/parse.rs Normal file
View file

@ -0,0 +1,137 @@
// Take a look at the license at the top of the repository in the LICENSE file.
use std::ptr;
use glib::{prelude::*, translate::*};
use crate::{Bin, Element, Object, ParseContext, ParseFlags};
pub use crate::auto::functions::parse_bin_from_description as bin_from_description;
pub use crate::auto::functions::parse_launch as launch;
pub use crate::auto::functions::parse_launchv as launchv;
#[doc(alias = "gst_parse_bin_from_description_full")]
pub fn bin_from_description_with_name(
bin_description: &str,
ghost_unlinked_pads: bool,
bin_name: &str,
) -> Result<Bin, glib::Error> {
skip_assert_initialized!();
let bin = bin_from_description(bin_description, ghost_unlinked_pads)?;
if !bin_name.is_empty() {
let obj = bin.clone().upcast::<Object>();
unsafe {
ffi::gst_object_set_name(obj.to_glib_none().0, bin_name.to_glib_none().0);
}
}
Ok(bin)
}
#[doc(alias = "gst_parse_bin_from_description_full")]
pub fn bin_from_description_full(
bin_description: &str,
ghost_unlinked_pads: bool,
mut context: Option<&mut ParseContext>,
flags: ParseFlags,
) -> Result<Element, glib::Error> {
skip_assert_initialized!();
unsafe {
let mut error = ptr::null_mut();
let ret = ffi::gst_parse_bin_from_description_full(
bin_description.to_glib_none().0,
ghost_unlinked_pads.into_glib(),
context.to_glib_none_mut().0,
flags.into_glib(),
&mut error,
);
if error.is_null() {
Ok(from_glib_none(ret))
} else {
Err(from_glib_full(error))
}
}
}
#[doc(alias = "gst_parse_bin_from_description_full")]
pub fn bin_from_description_with_name_full(
bin_description: &str,
ghost_unlinked_pads: bool,
bin_name: &str,
context: Option<&mut ParseContext>,
flags: ParseFlags,
) -> Result<Element, glib::Error> {
skip_assert_initialized!();
let bin = bin_from_description_full(bin_description, ghost_unlinked_pads, context, flags)?;
if !bin_name.is_empty() {
let obj = bin.clone().upcast::<Object>();
unsafe {
ffi::gst_object_set_name(obj.to_glib_none().0, bin_name.to_glib_none().0);
}
}
Ok(bin)
}
#[doc(alias = "gst_parse_launch_full")]
pub fn launch_full(
pipeline_description: &str,
mut context: Option<&mut ParseContext>,
flags: ParseFlags,
) -> Result<Element, glib::Error> {
assert_initialized_main_thread!();
unsafe {
let mut error = ptr::null_mut();
let ret = ffi::gst_parse_launch_full(
pipeline_description.to_glib_none().0,
context.to_glib_none_mut().0,
flags.into_glib(),
&mut error,
);
if error.is_null() {
Ok(from_glib_none(ret))
} else {
Err(from_glib_full(error))
}
}
}
#[doc(alias = "gst_parse_launchv_full")]
pub fn launchv_full(
argv: &[&str],
mut context: Option<&mut ParseContext>,
flags: ParseFlags,
) -> Result<Element, glib::Error> {
assert_initialized_main_thread!();
unsafe {
let mut error = ptr::null_mut();
let ret = ffi::gst_parse_launchv_full(
argv.to_glib_none().0,
context.to_glib_none_mut().0,
flags.into_glib(),
&mut error,
);
if error.is_null() {
Ok(from_glib_none(ret))
} else {
Err(from_glib_full(error))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::prelude::*;
#[test]
fn test_parse_bin_from_description_with_name() {
crate::init().unwrap();
let bin = bin_from_description_with_name("fakesrc ! fakesink", false, "all_fake").unwrap();
let name = bin.name();
assert_eq!(name, "all_fake");
let bin = bin_from_description_with_name("fakesrc ! fakesink", false, "").unwrap();
let name = bin.name();
assert_ne!(name, "");
}
}

View file

@ -9,7 +9,7 @@ fn tutorial_main() {
// Build the pipeline // Build the pipeline
let uri = "https://gstreamer.freedesktop.org/data/media/sintel_trailer-480p.webm"; let uri = "https://gstreamer.freedesktop.org/data/media/sintel_trailer-480p.webm";
let pipeline = gst::parse_launch(&format!("playbin uri={uri}")).unwrap(); let pipeline = gst::parse::launch(&format!("playbin uri={uri}")).unwrap();
// Start playing // Start playing
pipeline pipeline

View file

@ -12,7 +12,7 @@ fn tutorial_main() -> Result<(), Error> {
// Build the pipeline // Build the pipeline
let uri = "https://gstreamer.freedesktop.org/data/media/sintel_trailer-480p.webm"; let uri = "https://gstreamer.freedesktop.org/data/media/sintel_trailer-480p.webm";
let pipeline = gst::parse_launch(&format!("playbin uri={uri}"))?; let pipeline = gst::parse::launch(&format!("playbin uri={uri}"))?;
// Start playing // Start playing
let res = pipeline.set_state(gst::State::Playing)?; let res = pipeline.set_state(gst::State::Playing)?;

View file

@ -122,7 +122,7 @@ USAGE: Choose one of the following options, then press enter:
// Build the pipeline. // Build the pipeline.
let uri = "https://gstreamer.freedesktop.org/data/media/sintel_trailer-480p.webm"; let uri = "https://gstreamer.freedesktop.org/data/media/sintel_trailer-480p.webm";
let pipeline = gst::parse_launch(&format!("playbin uri={uri}"))?; let pipeline = gst::parse::launch(&format!("playbin uri={uri}"))?;
// Start playing. // Start playing.
let _ = pipeline.set_state(State::Playing)?; let _ = pipeline.set_state(State::Playing)?;

View file

@ -46,7 +46,7 @@ fn tutorial_main() -> Result<(), Error> {
gst::init().unwrap(); gst::init().unwrap();
// Create the playbin element // Create the playbin element
let pipeline = gst::parse_launch("playbin uri=appsrc://").unwrap(); let pipeline = gst::parse::launch("playbin uri=appsrc://").unwrap();
// This part is called when playbin has created the appsrc element, // This part is called when playbin has created the appsrc element,
// so we have a chance to configure it. // so we have a chance to configure it.

View file

@ -110,7 +110,7 @@ fn tutorial_main() -> Result<(), Error> {
thread::spawn(move || handle_keyboard(ready_tx)); thread::spawn(move || handle_keyboard(ready_tx));
// Build the pipeline // Build the pipeline
let pipeline = gst::parse_launch( let pipeline = gst::parse::launch(
"playbin uri=https://gstreamer.freedesktop.org/data/media/sintel_trailer-480p.webm", "playbin uri=https://gstreamer.freedesktop.org/data/media/sintel_trailer-480p.webm",
)?; )?;

View file

@ -45,7 +45,7 @@ fn tutorial_main() -> Result<(), Error> {
let vis_plugin = vis_factory.create().build().unwrap(); let vis_plugin = vis_factory.create().build().unwrap();
// Build the pipeline // Build the pipeline
let pipeline = gst::parse_launch("playbin uri=http://radio.hbr1.com:19800/ambient.ogg")?; let pipeline = gst::parse::launch("playbin uri=http://radio.hbr1.com:19800/ambient.ogg")?;
// Set the visualization flag // Set the visualization flag
let flags = pipeline.property_value("flags"); let flags = pipeline.property_value("flags");

View file

@ -9,7 +9,7 @@ fn tutorial_main() -> Result<(), Error> {
gst::init()?; gst::init()?;
// Build the pipeline // Build the pipeline
let pipeline = gst::parse_launch( let pipeline = gst::parse::launch(
"playbin uri=https://gstreamer.freedesktop.org/data/media/sintel_trailer-480p.webm", "playbin uri=https://gstreamer.freedesktop.org/data/media/sintel_trailer-480p.webm",
)?; )?;