gstreamer_pbutils/
discoverer.rs1use std::{boxed::Box as Box_, fmt, mem::transmute};
4
5use glib::{
6 prelude::*,
7 signal::{SignalHandlerId, connect_raw},
8 translate::*,
9};
10
11use crate::{Discoverer, DiscovererInfo, ffi};
12
13#[cfg(feature = "v1_30")]
14use crate::{DiscovererResult, DiscovererStreamInfo};
15
16impl Discoverer {
17 pub fn set_timeout(&self, timeout: gst::ClockTime) {
18 self.set_property("timeout", timeout);
19 }
20
21 pub fn timeout(&self) -> gst::ClockTime {
22 self.property("timeout")
23 }
24
25 #[doc(alias = "timeout")]
26 pub fn connect_timeout_notify<F: Fn(&Self) + Send + Sync + 'static>(
27 &self,
28 f: F,
29 ) -> SignalHandlerId {
30 unsafe {
31 let f: Box_<F> = Box_::new(f);
32 connect_raw(
33 self.as_ptr() as *mut _,
34 b"notify::timeout\0".as_ptr() as *const _,
35 Some(transmute::<*const (), unsafe extern "C" fn()>(
36 notify_timeout_trampoline::<Self, F> as *const (),
37 )),
38 Box_::into_raw(f),
39 )
40 }
41 }
42}
43
44unsafe extern "C" fn notify_timeout_trampoline<P, F: Fn(&P) + Send + Sync + 'static>(
45 this: *mut ffi::GstDiscoverer,
46 _param_spec: glib::ffi::gpointer,
47 f: glib::ffi::gpointer,
48) where
49 P: IsA<Discoverer>,
50{
51 unsafe {
52 let f: &F = &*(f as *const F);
53 f(Discoverer::from_glib_borrow(this).unsafe_cast_ref())
54 }
55}
56
57pub struct DebugInfo<'a>(&'a DiscovererInfo);
58
59impl fmt::Debug for DebugInfo<'_> {
60 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
61 let stream_info = self.0.stream_info();
62 let stream_list = self.0.stream_list();
63 let container_streams = self.0.container_streams();
64 let audio_streams = self.0.audio_streams();
65 let video_streams = self.0.video_streams();
66 let subtitle_streams = self.0.subtitle_streams();
67
68 f.debug_struct("DiscovererInfo")
69 .field("uri", &self.0.uri())
70 .field("result", &self.0.result())
71 .field("duration", &self.0.duration())
72 .field("is-live", &self.0.is_live())
73 .field("is-seekable", &self.0.is_seekable())
74 .field(
75 "stream-info",
76 &stream_info.as_ref().map(|info| info.debug()),
77 )
78 .field(
79 "stream-list",
80 &stream_list
81 .iter()
82 .map(|info| info.debug())
83 .collect::<Vec<_>>(),
84 )
85 .field(
86 "container-streams",
87 &container_streams
88 .iter()
89 .map(|info| info.debug())
90 .collect::<Vec<_>>(),
91 )
92 .field(
93 "audio-streams",
94 &audio_streams
95 .iter()
96 .map(|info| info.debug())
97 .collect::<Vec<_>>(),
98 )
99 .field(
100 "video-streams",
101 &video_streams
102 .iter()
103 .map(|info| info.debug())
104 .collect::<Vec<_>>(),
105 )
106 .field(
107 "subtitle-streams",
108 &subtitle_streams
109 .iter()
110 .map(|info| info.debug())
111 .collect::<Vec<_>>(),
112 )
113 .field("toc", &self.0.toc())
114 .field("misc", &self.0.misc())
115 .field(
116 "missing-elements-installer-details",
117 &self.0.missing_elements_installer_details(),
118 )
119 .finish()
120 }
121}
122
123impl DiscovererInfo {
124 pub fn debug(&self) -> DebugInfo<'_> {
125 DebugInfo(self)
126 }
127
128 #[cfg(feature = "v1_30")]
129 #[cfg_attr(docsrs, doc(cfg(feature = "v1_30")))]
130 #[doc(alias = "gst_discoverer_info_builder_new")]
131 pub fn builder(
132 uri: &str,
133 stream_info: impl IsA<DiscovererStreamInfo>,
134 ) -> DiscovererInfoBuilder {
135 skip_assert_initialized!();
136
137 DiscovererInfoBuilder::new(uri, stream_info)
138 }
139}
140
141#[cfg(feature = "v1_30")]
143#[cfg_attr(docsrs, doc(cfg(feature = "v1_30")))]
144#[derive(Debug)]
145#[doc(alias = "GstDiscovererInfoBuilder")]
146#[repr(transparent)]
147pub struct DiscovererInfoBuilder(std::ptr::NonNull<ffi::GstDiscovererInfoBuilder>);
148
149#[cfg(feature = "v1_30")]
150#[cfg_attr(docsrs, doc(cfg(feature = "v1_30")))]
151impl DiscovererInfoBuilder {
152 #[doc(alias = "gst_discoverer_info_builder_new")]
166 pub fn new(uri: &str, stream_info: impl IsA<DiscovererStreamInfo>) -> Self {
167 skip_assert_initialized!();
168
169 unsafe {
170 let ptr = ffi::gst_discoverer_info_builder_new(
171 uri.to_glib_none().0,
172 stream_info.upcast().into_glib_ptr(),
173 );
174 DiscovererInfoBuilder(std::ptr::NonNull::new_unchecked(ptr))
175 }
176 }
177
178 #[doc(alias = "gst_discoverer_info_builder_set_duration")]
179 pub fn duration(self, duration: gst::ClockTime) -> Self {
180 unsafe {
181 ffi::gst_discoverer_info_builder_set_duration(self.0.as_ptr(), duration.into_glib());
182 }
183 self
184 }
185
186 #[doc(alias = "gst_discoverer_info_builder_set_live")]
187 pub fn live(self, live: bool) -> Self {
188 unsafe {
189 ffi::gst_discoverer_info_builder_set_live(self.0.as_ptr(), live.into_glib());
190 }
191 self
192 }
193
194 #[doc(alias = "gst_discoverer_info_builder_set_result")]
195 pub fn result(self, result: DiscovererResult) -> Self {
196 unsafe {
197 ffi::gst_discoverer_info_builder_set_result(self.0.as_ptr(), result.into_glib());
198 }
199 self
200 }
201
202 #[doc(alias = "gst_discoverer_info_builder_set_seekable")]
203 pub fn seekable(self, seekable: bool) -> Self {
204 unsafe {
205 ffi::gst_discoverer_info_builder_set_seekable(self.0.as_ptr(), seekable.into_glib());
206 }
207 self
208 }
209
210 #[doc(alias = "gst_discoverer_info_builder_set_tags")]
211 pub fn tags(self, tags: &gst::TagList) -> Self {
212 unsafe {
213 ffi::gst_discoverer_info_builder_set_tags(self.0.as_ptr(), tags.to_glib_none().0);
214 }
215 self
216 }
217
218 #[doc(alias = "gst_discoverer_info_builder_build")]
224 pub fn build(self) -> DiscovererInfo {
225 unsafe {
226 let s = std::mem::ManuallyDrop::new(self);
229
230 from_glib_full(ffi::gst_discoverer_info_builder_build(s.0.as_ptr()))
231 }
232 }
233}
234
235#[cfg(feature = "v1_30")]
236#[cfg_attr(docsrs, doc(cfg(feature = "v1_30")))]
237impl Drop for DiscovererInfoBuilder {
238 #[inline]
239 #[doc(alias = "gst_discoverer_info_builder_free")]
240 fn drop(&mut self) {
241 unsafe {
242 ffi::gst_discoverer_info_builder_free(self.0.as_ptr());
243 }
244 }
245}
246
247#[cfg(test)]
248mod tests {
249 #[test]
250 #[cfg(feature = "v1_30")]
251 fn discoverer_info_builder_basic() {
252 use super::*;
253
254 gst::init().unwrap();
255
256 let audio_caps = gst::Caps::builder("audio/x-raw")
257 .field("format", "S16LE")
258 .build();
259 let audio_info =
260 crate::DiscovererAudioInfoBuilder::new("audio_stream", &audio_caps).build();
261
262 let mut tags = gst::TagList::new();
263 tags.get_mut()
264 .unwrap()
265 .add::<gst::tags::Title>(&"some title", gst::TagMergeMode::Append);
266
267 let info = DiscovererInfoBuilder::new("file:///tmp/test.wav", audio_info)
268 .duration(gst::ClockTime::from_seconds(5))
269 .live(false)
270 .seekable(true)
271 .result(DiscovererResult::Ok)
272 .tags(&tags)
273 .build();
274
275 assert_eq!(info.duration(), Some(gst::ClockTime::from_seconds(5)));
276 assert!(!info.is_live());
277 assert!(info.is_seekable());
278 assert_eq!(info.result(), DiscovererResult::Ok);
279 assert_eq!(info.uri(), glib::GString::from("file:///tmp/test.wav"));
280 }
281}