Skip to main content

gstreamer_pbutils/
discoverer_container_info.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2use std::fmt;
3
4use crate::{DiscovererContainerInfo, prelude::*};
5
6#[cfg(feature = "v1_30")]
7use glib::translate::*;
8
9#[cfg(feature = "v1_30")]
10use crate::{DiscovererStreamInfo, ffi};
11
12pub struct Debug<'a>(&'a DiscovererContainerInfo);
13
14impl fmt::Debug for Debug<'_> {
15    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
16        let streams = self.0.streams();
17
18        let mut d = f.debug_struct("DiscovererContainerInfo");
19
20        d.field("tags", &self.0.tags()).field(
21            "streams",
22            &streams.iter().map(|info| info.debug()).collect::<Vec<_>>(),
23        );
24
25        #[cfg(feature = "v1_20")]
26        d.field("stream-number", &self.0.stream_number());
27        #[cfg(feature = "v1_20")]
28        d.field("tags", &self.0.tags());
29
30        d.finish()
31    }
32}
33
34impl DiscovererContainerInfo {
35    pub fn debug(&self) -> Debug<'_> {
36        Debug(self)
37    }
38
39    #[cfg(feature = "v1_30")]
40    #[cfg_attr(docsrs, doc(cfg(feature = "v1_30")))]
41    #[doc(alias = "gst_discoverer_container_info_builder_new")]
42    pub fn builder(caps: &gst::Caps) -> DiscovererContainerInfoBuilder {
43        skip_assert_initialized!();
44
45        DiscovererContainerInfoBuilder::new(caps)
46    }
47}
48
49/// Opaque structure for building [`DiscovererContainerInfo`][crate::DiscovererContainerInfo] objects programmatically.
50#[cfg(feature = "v1_30")]
51#[cfg_attr(docsrs, doc(cfg(feature = "v1_30")))]
52#[derive(Debug)]
53#[doc(alias = "GstDiscovererContainerInfoBuilder")]
54#[repr(transparent)]
55pub struct DiscovererContainerInfoBuilder(
56    std::ptr::NonNull<ffi::GstDiscovererContainerInfoBuilder>,
57);
58
59#[cfg(feature = "v1_30")]
60#[cfg_attr(docsrs, doc(cfg(feature = "v1_30")))]
61impl DiscovererContainerInfoBuilder {
62    /// Creates a new [`DiscovererContainerInfoBuilder`][crate::DiscovererContainerInfoBuilder] for building a
63    /// [`DiscovererContainerInfo`][crate::DiscovererContainerInfo] with multiple streams.
64    /// ## `caps`
65    /// the container caps
66    ///
67    /// # Returns
68    ///
69    /// a new [`DiscovererContainerInfoBuilder`][crate::DiscovererContainerInfoBuilder],
70    ///  or [`None`] if `caps` is [`None`]
71    #[doc(alias = "gst_discoverer_container_info_builder_new")]
72    pub fn new(caps: &gst::Caps) -> Self {
73        skip_assert_initialized!();
74
75        unsafe {
76            let ptr = ffi::gst_discoverer_container_info_builder_new(caps.to_glib_none().0);
77            DiscovererContainerInfoBuilder(std::ptr::NonNull::new_unchecked(ptr))
78        }
79    }
80
81    /// Adds a stream to the container. Takes ownership of `stream_info`.
82    /// ## `stream_info`
83    /// the stream info to add
84    ///
85    /// # Returns
86    ///
87    /// the same builder for chaining
88    #[doc(alias = "gst_discoverer_container_info_builder_add_stream")]
89    pub fn add_stream(self, stream_info: impl IsA<DiscovererStreamInfo>) -> Self {
90        unsafe {
91            ffi::gst_discoverer_container_info_builder_add_stream(
92                self.0.as_ptr(),
93                stream_info.upcast().into_glib_ptr(),
94            );
95        }
96        self
97    }
98
99    #[doc(alias = "gst_discoverer_container_info_builder_set_tags")]
100    pub fn tags(self, tags: &gst::TagList) -> Self {
101        unsafe {
102            ffi::gst_discoverer_container_info_builder_set_tags(
103                self.0.as_ptr(),
104                tags.to_glib_none().0,
105            );
106        }
107        self
108    }
109
110    /// Builds and returns a new [`DiscovererContainerInfo`][crate::DiscovererContainerInfo]. This frees the builder.
111    ///
112    /// # Returns
113    ///
114    /// a new [`DiscovererContainerInfo`][crate::DiscovererContainerInfo]
115    #[doc(alias = "gst_discoverer_container_info_builder_build")]
116    pub fn build(self) -> DiscovererContainerInfo {
117        unsafe {
118            // gst_discoverer_container_info_builder_build frees the builder,
119            // so prevent it from being dropped at the end of this scope/function
120            let s = std::mem::ManuallyDrop::new(self);
121
122            from_glib_full(ffi::gst_discoverer_container_info_builder_build(
123                s.0.as_ptr(),
124            ))
125        }
126    }
127}
128
129#[cfg(feature = "v1_30")]
130#[cfg_attr(docsrs, doc(cfg(feature = "v1_30")))]
131impl Drop for DiscovererContainerInfoBuilder {
132    #[inline]
133    #[doc(alias = "gst_discoverer_container_info_builder_free")]
134    fn drop(&mut self) {
135        unsafe {
136            ffi::gst_discoverer_container_info_builder_free(self.0.as_ptr());
137        }
138    }
139}
140
141#[cfg(test)]
142mod tests {
143    #[test]
144    #[cfg(feature = "v1_30")]
145    fn discoverer_container_info_builder_basic() {
146        use std::str::FromStr;
147
148        use super::*;
149
150        gst::init().unwrap();
151
152        let container_caps = gst::Caps::from_str("video/quicktime").unwrap();
153        let audio_caps = gst::Caps::from_str("audio/x-raw, format=S16LE").unwrap();
154
155        let audio_info =
156            crate::DiscovererAudioInfoBuilder::new("audio_stream", &audio_caps).build();
157
158        let mut tags = gst::TagList::new();
159        tags.get_mut()
160            .unwrap()
161            .add::<gst::tags::Title>(&"some title", gst::TagMergeMode::Append);
162
163        let info = DiscovererContainerInfoBuilder::new(&container_caps)
164            .add_stream(audio_info)
165            .tags(&tags)
166            .build();
167
168        assert_eq!(info.streams().len(), 1);
169        assert_eq!(
170            info.tags()
171                .unwrap()
172                .get::<gst::tags::Title>()
173                .unwrap()
174                .get(),
175            "some title"
176        );
177    }
178}