From 138bc71051588c9666577a9b6cb3f017d8695f21 Mon Sep 17 00:00:00 2001 From: Vivia Nikolaidou Date: Wed, 22 Jun 2022 20:10:23 +0300 Subject: [PATCH] gstreamer-audio: Add AudioCapsBuilder --- gstreamer-audio/src/caps.rs | 140 ++++++++++++++++++++++++++++++++++++ gstreamer-audio/src/lib.rs | 3 + 2 files changed, 143 insertions(+) create mode 100644 gstreamer-audio/src/caps.rs diff --git a/gstreamer-audio/src/caps.rs b/gstreamer-audio/src/caps.rs new file mode 100644 index 000000000..605146a62 --- /dev/null +++ b/gstreamer-audio/src/caps.rs @@ -0,0 +1,140 @@ +use crate::{AudioFormat, AudioLayout}; +use gst::prelude::*; +use gst::Caps; +use std::ops::Bound::*; +use std::ops::RangeBounds; + +pub struct AudioCapsBuilder { + builder: gst::caps::Builder, +} + +impl AudioCapsBuilder { + pub fn new() -> Self { + let builder = Caps::builder("audio/x-raw"); + AudioCapsBuilder { builder } + } + + pub fn any_features(self) -> AudioCapsBuilder { + AudioCapsBuilder { + builder: self.builder.any_features(), + } + } + + pub fn features(self, features: &[&str]) -> AudioCapsBuilder { + AudioCapsBuilder { + builder: self.builder.features(features), + } + } +} + +impl Default for AudioCapsBuilder { + fn default() -> Self { + Self::new() + } +} + +impl AudioCapsBuilder { + pub fn format(self, format: AudioFormat) -> Self { + Self { + builder: self.builder.field("format", format.to_str()), + } + } + + pub fn format_list(self, formats: impl IntoIterator) -> Self { + Self { + builder: self.builder.field( + "format", + gst::List::new(formats.into_iter().map(|f| f.to_str())), + ), + } + } + + pub fn rate(self, rate: i32) -> Self { + Self { + builder: self.builder.field("rate", rate), + } + } + + pub fn rate_range(self, rates: impl RangeBounds) -> Self { + let (start, end) = range_bounds_i32_start_end(rates); + let gst_rates = gst::IntRange::::new(start, end); + Self { + builder: self.builder.field("rate", gst_rates), + } + } + + pub fn rate_list(self, rates: impl IntoIterator) -> Self { + Self { + builder: self.builder.field("rate", gst::List::new(rates)), + } + } + + pub fn channels(self, channels: i32) -> Self { + Self { + builder: self.builder.field("channels", channels), + } + } + + pub fn channels_range(self, channels: impl RangeBounds) -> Self { + let (start, end) = range_bounds_i32_start_end(channels); + let gst_channels: gst::IntRange = gst::IntRange::new(start, end); + Self { + builder: self.builder.field("channels", gst_channels), + } + } + + pub fn channels_list(self, channels: impl IntoIterator) -> Self { + Self { + builder: self.builder.field("channels", gst::List::new(channels)), + } + } + + pub fn layout(self, layout: AudioLayout) -> Self { + Self { + builder: self.builder.field("layout", layout_str(layout)), + } + } + + pub fn layout_list(self, layouts: impl IntoIterator) -> Self { + Self { + builder: self.builder.field( + "layout", + gst::List::new(layouts.into_iter().map(layout_str)), + ), + } + } + + pub fn field(self, name: &str, value: V) -> Self { + Self { + builder: self.builder.field(name, value), + } + } + + pub fn build(self) -> gst::Caps { + self.builder.build() + } +} + +fn range_bounds_i32_start_end(range: impl RangeBounds) -> (i32, i32) { + skip_assert_initialized!(); + let start = match range.start_bound() { + Unbounded => 1, + Excluded(n) => n + 1, + Included(n) => *n, + }; + let end = match range.end_bound() { + Unbounded => i32::MAX, + Excluded(n) => n - 1, + Included(n) => *n, + }; + (start, end) +} + +fn layout_str(layout: AudioLayout) -> &'static str { + skip_assert_initialized!(); + match layout { + crate::AudioLayout::Interleaved => "interleaved", + crate::AudioLayout::NonInterleaved => "non-interleaved", + crate::AudioLayout::__Unknown(_) => "unknown", + } +} diff --git a/gstreamer-audio/src/lib.rs b/gstreamer-audio/src/lib.rs index 13389f11a..152d698a9 100644 --- a/gstreamer-audio/src/lib.rs +++ b/gstreamer-audio/src/lib.rs @@ -36,6 +36,9 @@ macro_rules! skip_assert_initialized { mod auto; pub use crate::auto::*; +mod caps; +pub use crate::caps::AudioCapsBuilder; + #[cfg(feature = "ser_de")] mod flag_serde;