Skip to main content

gstreamer_pbutils/
discoverer_video_info.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::fmt;
4
5use glib::{prelude::*, translate::*};
6
7use crate::{DiscovererStreamInfo, DiscovererVideoInfo, ffi};
8
9impl DiscovererVideoInfo {
10    #[doc(alias = "get_framerate")]
11    #[doc(alias = "gst_discoverer_video_info_get_framerate_num")]
12    #[doc(alias = "gst_discoverer_video_info_get_framerate_denom")]
13    pub fn framerate(&self) -> gst::Fraction {
14        unsafe {
15            gst::Fraction::new(
16                ffi::gst_discoverer_video_info_get_framerate_num(self.to_glib_none().0) as i32,
17                ffi::gst_discoverer_video_info_get_framerate_denom(self.to_glib_none().0) as i32,
18            )
19        }
20    }
21
22    #[doc(alias = "get_par")]
23    #[doc(alias = "gst_discoverer_video_info_get_par_num")]
24    #[doc(alias = "gst_discoverer_video_info_get_par_denom")]
25    pub fn par(&self) -> gst::Fraction {
26        unsafe {
27            gst::Fraction::new(
28                ffi::gst_discoverer_video_info_get_par_num(self.to_glib_none().0) as i32,
29                ffi::gst_discoverer_video_info_get_par_denom(self.to_glib_none().0) as i32,
30            )
31        }
32    }
33
34    pub fn debug(&self) -> Debug<'_> {
35        Debug(self)
36    }
37
38    #[cfg(feature = "v1_30")]
39    #[cfg_attr(docsrs, doc(cfg(feature = "v1_30")))]
40    #[doc(alias = "gst_discoverer_video_info_builder_new")]
41    pub fn builder(stream_id: &str, caps: &gst::Caps) -> DiscovererVideoInfoBuilder {
42        skip_assert_initialized!();
43
44        DiscovererVideoInfoBuilder::new(stream_id, caps)
45    }
46}
47
48pub struct Debug<'a>(&'a DiscovererVideoInfo);
49
50impl fmt::Debug for Debug<'_> {
51    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
52        let info = self.0.upcast_ref::<DiscovererStreamInfo>();
53
54        f.debug_struct("DiscovererVideoInfo")
55            .field("width", &self.0.width())
56            .field("height", &self.0.height())
57            .field("depth", &self.0.depth())
58            .field("bitrate", &self.0.bitrate())
59            .field("max-bitrate", &self.0.max_bitrate())
60            .field("is-image", &self.0.is_image())
61            .field("is-interlaced", &self.0.is_interlaced())
62            .field("stream", &info.debug())
63            .finish()
64    }
65}
66
67/// Opaque structure for building [`DiscovererVideoInfo`][crate::DiscovererVideoInfo] objects programmatically.
68#[cfg(feature = "v1_30")]
69#[cfg_attr(docsrs, doc(cfg(feature = "v1_30")))]
70#[derive(Debug)]
71#[doc(alias = "GstDiscovererVideoInfoBuilder")]
72#[repr(transparent)]
73pub struct DiscovererVideoInfoBuilder(std::ptr::NonNull<ffi::GstDiscovererVideoInfoBuilder>);
74
75#[cfg(feature = "v1_30")]
76#[cfg_attr(docsrs, doc(cfg(feature = "v1_30")))]
77impl DiscovererVideoInfoBuilder {
78    /// Creates a new [`DiscovererVideoInfoBuilder`][crate::DiscovererVideoInfoBuilder].
79    /// Video properties (width, height, framerate, PAR) will be extracted from caps.
80    /// ## `stream_id`
81    /// the stream ID
82    /// ## `caps`
83    /// the video caps
84    ///
85    /// # Returns
86    ///
87    /// a new [`DiscovererVideoInfoBuilder`][crate::DiscovererVideoInfoBuilder]
88    #[doc(alias = "gst_discoverer_video_info_builder_new")]
89    pub fn new(stream_id: &str, caps: &gst::Caps) -> Self {
90        skip_assert_initialized!();
91
92        unsafe {
93            let ptr = ffi::gst_discoverer_video_info_builder_new(
94                stream_id.to_glib_none().0,
95                caps.to_glib_none().0,
96            );
97            DiscovererVideoInfoBuilder(std::ptr::NonNull::new_unchecked(ptr))
98        }
99    }
100
101    #[doc(alias = "gst_discoverer_video_info_builder_set_bitrate")]
102    pub fn bitrate(self, bitrate: u32) -> Self {
103        unsafe {
104            ffi::gst_discoverer_video_info_builder_set_bitrate(self.0.as_ptr(), bitrate);
105        }
106        self
107    }
108
109    #[doc(alias = "gst_discoverer_video_info_builder_set_interlaced")]
110    pub fn interlaced(self, interlaced: bool) -> Self {
111        unsafe {
112            ffi::gst_discoverer_video_info_builder_set_interlaced(
113                self.0.as_ptr(),
114                interlaced.into_glib(),
115            );
116        }
117        self
118    }
119
120    #[doc(alias = "gst_discoverer_video_info_builder_set_max_bitrate")]
121    pub fn max_bitrate(self, max_bitrate: u32) -> Self {
122        unsafe {
123            ffi::gst_discoverer_video_info_builder_set_max_bitrate(self.0.as_ptr(), max_bitrate);
124        }
125        self
126    }
127
128    #[doc(alias = "gst_discoverer_video_info_builder_set_is_image")]
129    pub fn is_image(self, is_image: bool) -> Self {
130        unsafe {
131            ffi::gst_discoverer_video_info_builder_set_is_image(
132                self.0.as_ptr(),
133                is_image.into_glib(),
134            );
135        }
136        self
137    }
138
139    #[doc(alias = "gst_discoverer_video_info_builder_set_tags")]
140    pub fn tags(self, tags: &gst::TagList) -> Self {
141        unsafe {
142            ffi::gst_discoverer_video_info_builder_set_tags(self.0.as_ptr(), tags.to_glib_none().0);
143        }
144        self
145    }
146
147    /// Builds and returns a new [`DiscovererVideoInfo`][crate::DiscovererVideoInfo]. This frees the builder.
148    ///
149    /// # Returns
150    ///
151    /// a new [`DiscovererVideoInfo`][crate::DiscovererVideoInfo]
152    #[doc(alias = "gst_discoverer_video_info_builder_build")]
153    pub fn build(self) -> DiscovererVideoInfo {
154        unsafe {
155            // the gst_discoverer_video_info_builder_build frees the builder before creating new
156            // so prevent it from being dropped at the end of this scope/function
157            let s = std::mem::ManuallyDrop::new(self);
158
159            from_glib_full(ffi::gst_discoverer_video_info_builder_build(s.0.as_ptr()))
160        }
161    }
162}
163
164#[cfg(feature = "v1_30")]
165#[cfg_attr(docsrs, doc(cfg(feature = "v1_30")))]
166impl Drop for DiscovererVideoInfoBuilder {
167    #[inline]
168    #[doc(alias = "gst_discoverer_video_info_builder_free")]
169    fn drop(&mut self) {
170        unsafe {
171            ffi::gst_discoverer_video_info_builder_free(self.0.as_ptr());
172        }
173    }
174}
175
176#[cfg(test)]
177mod tests {
178    #[test]
179    #[cfg(feature = "v1_30")]
180    fn discoverer_video_info_builder_basic() {
181        use super::*;
182        use std::str::FromStr;
183
184        use crate::traits::DiscovererStreamInfoExt;
185
186        gst::init().unwrap();
187
188        let caps = gst::Caps::from_str(
189            "video/x-raw, width=3840, height=2160, framerate=60/1, pixel-aspect-ratio=1/1",
190        )
191        .unwrap();
192
193        let mut tags = gst::TagList::new();
194        tags.get_mut()
195            .unwrap()
196            .add::<gst::tags::Title>(&"some title", gst::TagMergeMode::Append);
197
198        let info = DiscovererVideoInfoBuilder::new("video_builder_test", &caps)
199            .bitrate(20000000)
200            .interlaced(true)
201            .max_bitrate(30000000)
202            .is_image(false)
203            .tags(&tags)
204            .build();
205
206        assert_eq!(info.height(), 2160);
207        assert_eq!(info.width(), 3840);
208        assert_eq!(info.par(), gst::Fraction::new(1, 1));
209        assert_eq!(info.framerate(), gst::Fraction::new(60, 1));
210        assert_eq!(
211            info.stream_id(),
212            Some(glib::GString::from("video_builder_test"))
213        );
214        assert_eq!(info.bitrate(), 20000000);
215        assert!(!info.is_image());
216        assert!(info.is_interlaced());
217        assert_eq!(info.max_bitrate(), 30000000);
218        assert_eq!(
219            info.tags()
220                .unwrap()
221                .get::<gst::tags::Title>()
222                .unwrap()
223                .get(),
224            "some title"
225        );
226    }
227}