examples, audio, pbutils, video: Use AudioCapsBuilder and VideoCapsBuilder

Simplify caps creation code
This commit is contained in:
Vivia Nikolaidou 2022-10-14 13:19:49 +03:00
parent 734afa998b
commit 6d4ad712c7
18 changed files with 67 additions and 93 deletions

View file

@ -16,7 +16,6 @@ use gst::prelude::*;
use byte_slice_cast::*; use byte_slice_cast::*;
use std::i16; use std::i16;
use std::i32;
use anyhow::Error; use anyhow::Error;
use derive_more::{Display, Error}; use derive_more::{Display, Error};
@ -57,11 +56,9 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
// This can be set after linking the two objects, because format negotiation between // This can be set after linking the two objects, because format negotiation between
// both elements will happen during pre-rolling of the pipeline. // both elements will happen during pre-rolling of the pipeline.
appsink.set_caps(Some( appsink.set_caps(Some(
&gst::Caps::builder("audio/x-raw") &gst_audio::AudioCapsBuilder::new_interleaved()
.field("format", gst_audio::AUDIO_FORMAT_S16.to_str()) .format(gst_audio::AUDIO_FORMAT_S16)
.field("layout", "interleaved") .channels(1)
.field("channels", 1i32)
.field("rate", gst::IntRange::<i32>::new(1, i32::MAX))
.build(), .build(),
)); ));

View file

@ -123,18 +123,9 @@ mod cairo_compositor {
// GStreamer about all possible pads that could exist for this type. // GStreamer about all possible pads that could exist for this type.
// On all pads we can only handle BGRx. // On all pads we can only handle BGRx.
let caps = gst::Caps::builder("video/x-raw") let caps = gst_video::VideoCapsBuilder::new()
.field("format", gst_video::VideoFormat::Bgrx.to_str()) .format(gst_video::VideoFormat::Bgrx)
.field("width", gst::IntRange::<i32>::new(1, i32::MAX))
.field("height", gst::IntRange::<i32>::new(1, i32::MAX))
.field("pixel-aspect-ratio", gst::Fraction::new(1, 1)) .field("pixel-aspect-ratio", gst::Fraction::new(1, 1))
.field(
"framerate",
gst::FractionRange::new(
gst::Fraction::new(0, 1),
gst::Fraction::new(i32::MAX, 1),
),
)
.build(); .build();
vec![ vec![

View file

@ -459,8 +459,8 @@ mod video_filter {
impl ElementImpl for FdMemoryFadeInVideoFilter { impl ElementImpl for FdMemoryFadeInVideoFilter {
fn pad_templates() -> &'static [PadTemplate] { fn pad_templates() -> &'static [PadTemplate] {
static PAD_TEMPLATES: Lazy<Vec<PadTemplate>> = Lazy::new(|| { static PAD_TEMPLATES: Lazy<Vec<PadTemplate>> = Lazy::new(|| {
let caps = gst::Caps::builder("video/x-raw") let caps = gst_video::VideoCapsBuilder::new()
.field("format", "BGRA") .format(gst_video::VideoFormat::Bgra)
.build(); .build();
vec![ vec![
PadTemplate::new("sink", PadDirection::Sink, PadPresence::Always, &caps) PadTemplate::new("sink", PadDirection::Sink, PadPresence::Always, &caps)

View file

@ -75,10 +75,10 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
// Plug in a capsfilter element that will force the videotestsrc and the overlay to work // Plug in a capsfilter element that will force the videotestsrc and the overlay to work
// with images of the size 800x800, and framerate of 15 fps, since my laptop struggles // with images of the size 800x800, and framerate of 15 fps, since my laptop struggles
// rendering it at the default 30 fps // rendering it at the default 30 fps
let caps = gst::Caps::builder("video/x-raw") let caps = gst_video::VideoCapsBuilder::new()
.field("width", 800i32) .width(800)
.field("height", 800i32) .height(800)
.field("framerate", gst::Fraction::new(15, 1)) .framerate(gst::Fraction::new(15, 1))
.build(); .build();
capsfilter.set_property("caps", &caps); capsfilter.set_property("caps", &caps);

View file

@ -77,9 +77,9 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
// Plug in a capsfilter element that will force the videotestsrc and the cairooverlay to work // Plug in a capsfilter element that will force the videotestsrc and the cairooverlay to work
// with images of the size 800x800. // with images of the size 800x800.
let caps = gst::Caps::builder("video/x-raw") let caps = gst_video::VideoCapsBuilder::new()
.field("width", 800i32) .width(800)
.field("height", 800i32) .height(800)
.build(); .build();
capsfilter.set_property("caps", &caps); capsfilter.set_property("caps", &caps);

View file

@ -222,9 +222,9 @@ fn example_main() -> Result<(), Error> {
.field("clock-rate", 90000i32) .field("clock-rate", 90000i32)
.build(); .build();
let video_caps = gst::Caps::builder("video/x-raw") let video_caps = gst_video::VideoCapsBuilder::new()
.field("width", 1920i32) .width(1920)
.field("height", 1080i32) .height(1080)
.build(); .build();
src.set_property("address", "127.0.0.1"); src.set_property("address", "127.0.0.1");

View file

@ -36,7 +36,6 @@ mod fir_filter {
mod imp { mod imp {
use super::*; use super::*;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::i32;
use std::sync::Mutex; use std::sync::Mutex;
// This is the private data of our filter // This is the private data of our filter
@ -86,11 +85,9 @@ mod fir_filter {
// GStreamer about all possible pads that could exist for this type. // GStreamer about all possible pads that could exist for this type.
// On both of pads we can only handle F32 mono at any sample rate. // On both of pads we can only handle F32 mono at any sample rate.
let caps = gst::Caps::builder("audio/x-raw") let caps = gst_audio::AudioCapsBuilder::new_interleaved()
.field("format", gst_audio::AUDIO_FORMAT_F32.to_str()) .format(gst_audio::AUDIO_FORMAT_F32)
.field("rate", gst::IntRange::<i32>::new(1, i32::MAX)) .channels(1)
.field("channels", 1i32)
.field("layout", "interleaved")
.build(); .build();
vec![ vec![

View file

@ -54,8 +54,8 @@ fn create_pipeline(uri: String, out_path: std::path::PathBuf) -> Result<gst::Pip
// This can be set after linking the two objects, because format negotiation between // This can be set after linking the two objects, because format negotiation between
// both elements will happen during pre-rolling of the pipeline. // both elements will happen during pre-rolling of the pipeline.
appsink.set_caps(Some( appsink.set_caps(Some(
&gst::Caps::builder("video/x-raw") &gst_video::VideoCapsBuilder::new()
.field("format", gst_video::VideoFormat::Rgbx.to_str()) .format(gst_video::VideoFormat::Rgbx)
.build(), .build(),
)); ));

View file

@ -547,9 +547,9 @@ impl App {
appsink.set_property("emit-signals", false); appsink.set_property("emit-signals", false);
appsink.set_property("max-buffers", 1u32); appsink.set_property("max-buffers", 1u32);
let caps = gst::Caps::builder("video/x-raw") let caps = gst_video::VideoCapsBuilder::new()
.features(&[&gst_gl::CAPS_FEATURE_MEMORY_GL_MEMORY]) .features(&[&gst_gl::CAPS_FEATURE_MEMORY_GL_MEMORY])
.field("format", gst_video::VideoFormat::Rgba.to_str()) .format(gst_video::VideoFormat::Rgba)
.field("texture-target", "2D") .field("texture-target", "2D")
.build(); .build();
appsink.set_caps(Some(&caps)); appsink.set_caps(Some(&caps));

View file

@ -315,7 +315,7 @@ pub trait AudioFormatIteratorExt {
fn into_audio_caps( fn into_audio_caps(
self, self,
layout: crate::AudioLayout, layout: crate::AudioLayout,
) -> Option<gst::caps::Builder<gst::caps::NoFeature>>; ) -> Option<crate::AudioCapsBuilder<gst::caps::NoFeature>>;
} }
impl<T> AudioFormatIteratorExt for T impl<T> AudioFormatIteratorExt for T
@ -325,7 +325,7 @@ where
fn into_audio_caps( fn into_audio_caps(
self, self,
layout: crate::AudioLayout, layout: crate::AudioLayout,
) -> Option<gst::caps::Builder<gst::caps::NoFeature>> { ) -> Option<crate::AudioCapsBuilder<gst::caps::NoFeature>> {
let formats: Vec<crate::AudioFormat> = self.collect(); let formats: Vec<crate::AudioFormat> = self.collect();
if !formats.is_empty() { if !formats.is_empty() {
Some(crate::functions::audio_make_raw_caps(&formats, layout)) Some(crate::functions::audio_make_raw_caps(&formats, layout))
@ -339,7 +339,7 @@ pub trait AudioFormatIteratorExtRef {
fn into_audio_caps( fn into_audio_caps(
self, self,
layout: crate::AudioLayout, layout: crate::AudioLayout,
) -> Option<gst::caps::Builder<gst::caps::NoFeature>>; ) -> Option<crate::AudioCapsBuilder<gst::caps::NoFeature>>;
} }
impl<'a, T> AudioFormatIteratorExtRef for T impl<'a, T> AudioFormatIteratorExtRef for T
@ -349,7 +349,7 @@ where
fn into_audio_caps( fn into_audio_caps(
self, self,
layout: crate::AudioLayout, layout: crate::AudioLayout,
) -> Option<gst::caps::Builder<gst::caps::NoFeature>> { ) -> Option<crate::AudioCapsBuilder<gst::caps::NoFeature>> {
let formats: Vec<crate::AudioFormat> = self.copied().collect(); let formats: Vec<crate::AudioFormat> = self.copied().collect();
if !formats.is_empty() { if !formats.is_empty() {
Some(crate::functions::audio_make_raw_caps(&formats, layout)) Some(crate::functions::audio_make_raw_caps(&formats, layout))
@ -416,7 +416,7 @@ mod tests {
.into_audio_caps(crate::AudioLayout::Interleaved) .into_audio_caps(crate::AudioLayout::Interleaved)
.unwrap() .unwrap()
.build(); .build();
assert_eq!(caps.to_string(), "audio/x-raw, format=(string){ S16LE, S16BE }, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string)interleaved"); assert_eq!(caps.to_string(), "audio/x-raw, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string)interleaved, format=(string){ S16LE, S16BE }");
} }
#[test] #[test]

View file

@ -468,11 +468,10 @@ mod tests {
fn test_from_to_caps() { fn test_from_to_caps() {
gst::init().unwrap(); gst::init().unwrap();
let caps = gst::Caps::builder("audio/x-raw") let caps = crate::AudioCapsBuilder::new_interleaved()
.field("format", "S16LE") .format(crate::AudioFormat::S16le)
.field("rate", 48000) .rate(48000)
.field("channels", 2) .channels(2)
.field("layout", "interleaved")
.field("channel-mask", gst::Bitmask::new(0x3)) .field("channel-mask", gst::Bitmask::new(0x3))
.build(); .build();
let info = AudioInfo::from_caps(&caps).unwrap(); let info = AudioInfo::from_caps(&caps).unwrap();

View file

@ -119,6 +119,7 @@ impl<T> AudioCapsBuilder<T> {
} }
} }
#[must_use]
pub fn build(self) -> gst::Caps { pub fn build(self) -> gst::Caps {
self.builder.build() self.builder.build()
} }

View file

@ -1,7 +1,6 @@
// Take a look at the license at the top of the repository in the LICENSE file. // Take a look at the license at the top of the repository in the LICENSE file.
use glib::translate::{from_glib_full, IntoGlibPtr, ToGlibPtr}; use glib::translate::{from_glib_full, IntoGlibPtr, ToGlibPtr};
use glib::ToSendValue;
use std::i32; use std::i32;
@ -48,19 +47,16 @@ pub fn audio_buffer_truncate(
pub fn audio_make_raw_caps( pub fn audio_make_raw_caps(
formats: &[crate::AudioFormat], formats: &[crate::AudioFormat],
layout: crate::AudioLayout, layout: crate::AudioLayout,
) -> gst::caps::Builder<gst::caps::NoFeature> { ) -> crate::AudioCapsBuilder<gst::caps::NoFeature> {
assert_initialized_main_thread!(); assert_initialized_main_thread!();
let formats = formats.iter().map(|f| match f { let formats = formats.iter().copied().map(|f| match f {
crate::AudioFormat::Encoded => panic!("Invalid encoded format"), crate::AudioFormat::Encoded => panic!("Invalid encoded format"),
crate::AudioFormat::Unknown => panic!("Invalid unknown format"), crate::AudioFormat::Unknown => panic!("Invalid unknown format"),
_ => f.to_string().to_send_value(), _ => f,
}); });
let builder = gst::caps::Caps::builder("audio/x-raw") let builder = crate::AudioCapsBuilder::new().format_list(formats);
.field("format", gst::List::from_values(formats))
.field("rate", gst::IntRange::new(1, i32::MAX))
.field("channels", gst::IntRange::new(1, i32::MAX));
match layout { match layout {
crate::AudioLayout::Interleaved => builder.field("layout", "interleaved"), crate::AudioLayout::Interleaved => builder.field("layout", "interleaved"),
@ -82,7 +78,7 @@ mod tests {
crate::AudioLayout::Interleaved, crate::AudioLayout::Interleaved,
) )
.build(); .build();
assert_eq!(caps.to_string(), "audio/x-raw, format=(string){ S16BE, S16LE }, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string)interleaved"); assert_eq!(caps.to_string(), "audio/x-raw, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string)interleaved, format=(string){ S16BE, S16LE }");
#[cfg(feature = "v1_18")] #[cfg(feature = "v1_18")]
{ {
@ -109,12 +105,12 @@ mod tests {
&[crate::AudioFormat::S16be, crate::AudioFormat::S16le], &[crate::AudioFormat::S16be, crate::AudioFormat::S16le],
crate::AudioLayout::NonInterleaved, crate::AudioLayout::NonInterleaved,
) )
.field("rate", 16000) .rate(16000)
.field("channels", 2) .channels(2)
.build(); .build();
assert_eq!( assert_eq!(
caps.to_string(), caps.to_string(),
"audio/x-raw, format=(string){ S16BE, S16LE }, rate=(int)16000, channels=(int)2, layout=(string)non-interleaved" "audio/x-raw, rate=(int)16000, channels=(int)2, layout=(string)non-interleaved, format=(string){ S16BE, S16LE }",
); );
} }

View file

@ -637,8 +637,8 @@ mod tests {
let caps = gst::Caps::builder("audio/x-raw").build(); let caps = gst::Caps::builder("audio/x-raw").build();
let restriction = gst::Caps::builder("audio/x-raw") let restriction = gst_audio::AudioCapsBuilder::new()
.field("format", "S32LE") .format(gst_audio::AudioFormat::S32le)
.build(); .build();
let audio_profile = EncodingAudioProfile::builder(&caps) let audio_profile = EncodingAudioProfile::builder(&caps)
@ -665,8 +665,8 @@ mod tests {
assert_eq!(audio_profile.allows_dynamic_output(), ALLOW_DYNAMIC_OUTPUT); assert_eq!(audio_profile.allows_dynamic_output(), ALLOW_DYNAMIC_OUTPUT);
assert_eq!(audio_profile.is_enabled(), ENABLED); assert_eq!(audio_profile.is_enabled(), ENABLED);
let restriction = gst::Caps::builder("audio/x-raw") let restriction = gst_audio::AudioCapsBuilder::new()
.field("format", "S32BE") .format(gst_audio::AudioFormat::S32be)
.build(); .build();
audio_profile.set_restriction(Some(&restriction)); audio_profile.set_restriction(Some(&restriction));
assert_eq!(audio_profile.restriction().unwrap(), restriction); assert_eq!(audio_profile.restriction().unwrap(), restriction);
@ -678,8 +678,8 @@ mod tests {
let caps = gst::Caps::builder("video/x-raw").build(); let caps = gst::Caps::builder("video/x-raw").build();
let restriction = gst::Caps::builder("video/x-raw") let restriction = gst_video::VideoCapsBuilder::new()
.field("format", "RGBA") .format(gst_video::VideoFormat::Rgba)
.build(); .build();
let video_profile = EncodingVideoProfile::builder(&caps) let video_profile = EncodingVideoProfile::builder(&caps)
@ -713,8 +713,8 @@ mod tests {
assert_eq!(video_profile.is_variableframerate(), VARIABLE_FRAMERATE); assert_eq!(video_profile.is_variableframerate(), VARIABLE_FRAMERATE);
assert_eq!(video_profile.pass(), PASS); assert_eq!(video_profile.pass(), PASS);
let restriction = gst::Caps::builder("video/x-raw") let restriction = gst_video::VideoCapsBuilder::new()
.field("format", "NV12") .format(gst_video::VideoFormat::Nv12)
.build(); .build();
video_profile.set_restriction(Some(&restriction)); video_profile.set_restriction(Some(&restriction));
assert_eq!(video_profile.restriction().unwrap(), restriction); assert_eq!(video_profile.restriction().unwrap(), restriction);

View file

@ -182,6 +182,7 @@ impl<T> VideoCapsBuilder<T> {
} }
} }
#[must_use]
pub fn build(self) -> gst::Caps { pub fn build(self) -> gst::Caps {
self.builder.build() self.builder.build()
} }

View file

@ -1,7 +1,6 @@
// Take a look at the license at the top of the repository in the LICENSE file. // Take a look at the license at the top of the repository in the LICENSE file.
use glib::translate::{from_glib, from_glib_full, IntoGlib, ToGlibPtr}; use glib::translate::{from_glib, from_glib_full, IntoGlib, ToGlibPtr};
use glib::ToSendValue;
use std::i32; use std::i32;
use std::mem; use std::mem;
@ -214,23 +213,16 @@ pub fn is_common_aspect_ratio(width: u32, height: u32, par: gst::Fraction) -> bo
pub fn video_make_raw_caps( pub fn video_make_raw_caps(
formats: &[crate::VideoFormat], formats: &[crate::VideoFormat],
) -> gst::caps::Builder<gst::caps::NoFeature> { ) -> crate::VideoCapsBuilder<gst::caps::NoFeature> {
assert_initialized_main_thread!(); assert_initialized_main_thread!();
let formats = formats.iter().map(|f| match f { let formats = formats.iter().copied().map(|f| match f {
crate::VideoFormat::Encoded => panic!("Invalid encoded format"), crate::VideoFormat::Encoded => panic!("Invalid encoded format"),
crate::VideoFormat::Unknown => panic!("Invalid unknown format"), crate::VideoFormat::Unknown => panic!("Invalid unknown format"),
_ => f.to_string().to_send_value(), _ => f,
}); });
gst::caps::Caps::builder("video/x-raw") crate::VideoCapsBuilder::new().format_list(formats)
.field("format", gst::List::from_values(formats))
.field("width", gst::IntRange::new(1, i32::MAX))
.field("height", gst::IntRange::new(1, i32::MAX))
.field(
"framerate",
gst::FractionRange::new(gst::Fraction::new(0, 1), gst::Fraction::new(i32::MAX, 1)),
)
} }
#[cfg(test)] #[cfg(test)]
@ -321,9 +313,9 @@ mod tests {
} }
let caps = video_make_raw_caps(&[crate::VideoFormat::Nv12, crate::VideoFormat::Nv16]) let caps = video_make_raw_caps(&[crate::VideoFormat::Nv12, crate::VideoFormat::Nv16])
.field("width", 800) .width(800)
.field("height", 600) .height(600)
.field("framerate", gst::Fraction::new(30, 1)) .framerate(gst::Fraction::new(30, 1))
.build(); .build();
assert_eq!(caps.to_string(), "video/x-raw, format=(string){ NV12, NV16 }, width=(int)800, height=(int)600, framerate=(fraction)30/1"); assert_eq!(caps.to_string(), "video/x-raw, format=(string){ NV12, NV16 }, width=(int)800, height=(int)600, framerate=(fraction)30/1");
} }

View file

@ -407,14 +407,14 @@ impl DoubleEndedIterator for VideoFormatIterator {
} }
} }
pub trait VideoFormatIteratorExt { pub trait VideoFormatIteratorExt {
fn into_video_caps(self) -> Option<gst::caps::Builder<gst::caps::NoFeature>>; fn into_video_caps(self) -> Option<crate::VideoCapsBuilder<gst::caps::NoFeature>>;
} }
impl<T> VideoFormatIteratorExt for T impl<T> VideoFormatIteratorExt for T
where where
T: Iterator<Item = crate::VideoFormat>, T: Iterator<Item = crate::VideoFormat>,
{ {
fn into_video_caps(self) -> Option<gst::caps::Builder<gst::caps::NoFeature>> { fn into_video_caps(self) -> Option<crate::VideoCapsBuilder<gst::caps::NoFeature>> {
let formats: Vec<crate::VideoFormat> = self.collect(); let formats: Vec<crate::VideoFormat> = self.collect();
if !formats.is_empty() { if !formats.is_empty() {
Some(crate::functions::video_make_raw_caps(&formats)) Some(crate::functions::video_make_raw_caps(&formats))
@ -425,14 +425,14 @@ where
} }
pub trait VideoFormatIteratorExtRef { pub trait VideoFormatIteratorExtRef {
fn into_video_caps(self) -> Option<gst::caps::Builder<gst::caps::NoFeature>>; fn into_video_caps(self) -> Option<crate::VideoCapsBuilder<gst::caps::NoFeature>>;
} }
impl<'a, T> VideoFormatIteratorExtRef for T impl<'a, T> VideoFormatIteratorExtRef for T
where where
T: Iterator<Item = &'a crate::VideoFormat>, T: Iterator<Item = &'a crate::VideoFormat>,
{ {
fn into_video_caps(self) -> Option<gst::caps::Builder<gst::caps::NoFeature>> { fn into_video_caps(self) -> Option<crate::VideoCapsBuilder<gst::caps::NoFeature>> {
let formats: Vec<crate::VideoFormat> = self.copied().collect(); let formats: Vec<crate::VideoFormat> = self.copied().collect();
if !formats.is_empty() { if !formats.is_empty() {
Some(crate::functions::video_make_raw_caps(&formats)) Some(crate::functions::video_make_raw_caps(&formats))

View file

@ -1038,11 +1038,11 @@ mod tests {
fn test_from_to_caps() { fn test_from_to_caps() {
gst::init().unwrap(); gst::init().unwrap();
let caps = gst::Caps::builder("video/x-raw") let caps = crate::VideoCapsBuilder::new()
.field("format", "I420") .format(crate::VideoFormat::I420)
.field("width", 320) .width(320)
.field("height", 240) .height(240)
.field("framerate", gst::Fraction::new(30, 1)) .framerate(gst::Fraction::new(30, 1))
.field("pixel-aspect-ratio", gst::Fraction::new(1, 1)) .field("pixel-aspect-ratio", gst::Fraction::new(1, 1))
.field("interlace-mode", "progressive") .field("interlace-mode", "progressive")
.field("chroma-site", "mpeg2") .field("chroma-site", "mpeg2")