Skip to main content

gstreamer_pbutils/
missing_plugins.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use glib::{translate::*, value::ToSendValue};
4use gst::{Element, Message, Seqnum, ffi as gst_ffi, prelude::*};
5
6use crate::ffi;
7
8macro_rules! message_builder_generic_impl {
9    ($new_fn:expr) => {
10        #[allow(clippy::needless_update)]
11        pub fn src<O: IsA<Element> + Cast + Clone>(self, src: &O) -> Self {
12            Self {
13                builder: self.builder.src(src),
14                ..self
15            }
16        }
17
18        #[allow(clippy::needless_update)]
19        pub fn src_if<O: IsA<Element> + Cast + Clone>(self, src: &O, predicate: bool) -> Self {
20            if predicate { self.src(src) } else { self }
21        }
22
23        #[allow(clippy::needless_update)]
24        pub fn src_if_some<O: IsA<Element> + Cast + Clone>(self, src: Option<&O>) -> Self {
25            if let Some(src) = src {
26                self.src(src)
27            } else {
28                self
29            }
30        }
31
32        #[doc(alias = "gst_message_set_seqnum")]
33        #[allow(clippy::needless_update)]
34        pub fn seqnum(self, seqnum: Seqnum) -> Self {
35            Self {
36                builder: self.builder.seqnum(seqnum),
37                ..self
38            }
39        }
40
41        #[doc(alias = "gst_message_set_seqnum")]
42        #[allow(clippy::needless_update)]
43        pub fn seqnum_if(self, seqnum: Seqnum, predicate: bool) -> Self {
44            if predicate { self.seqnum(seqnum) } else { self }
45        }
46
47        #[doc(alias = "gst_message_set_seqnum")]
48        #[allow(clippy::needless_update)]
49        pub fn seqnum_if_some(self, seqnum: Option<Seqnum>) -> Self {
50            if let Some(seqnum) = seqnum {
51                self.seqnum(seqnum)
52            } else {
53                self
54            }
55        }
56
57        #[cfg(feature = "v1_26")]
58        #[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
59        #[doc(alias = "gst_message_set_details")]
60        pub fn details(self, details: gst::Structure) -> Self {
61            Self {
62                builder: self.builder.details(details),
63                ..self
64            }
65        }
66
67        #[cfg(feature = "v1_26")]
68        #[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
69        #[doc(alias = "gst_message_set_details")]
70        pub fn details_if(self, details: gst::Structure, predicate: bool) -> Self {
71            if predicate {
72                self.details(details)
73            } else {
74                self
75            }
76        }
77
78        #[cfg(feature = "v1_26")]
79        #[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
80        #[doc(alias = "gst_message_set_details")]
81        pub fn details_if_some(self, details: Option<gst::Structure>) -> Self {
82            if let Some(details) = details {
83                self.details(details)
84            } else {
85                self
86            }
87        }
88
89        #[cfg(feature = "v1_26")]
90        #[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
91        #[doc(alias = "gst_missing_plugin_message_set_stream_id")]
92        pub fn stream_id(self, stream_id: &'a str) -> Self {
93            Self {
94                stream_id: Some(stream_id),
95                ..self
96            }
97        }
98
99        #[cfg(feature = "v1_26")]
100        #[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
101        #[doc(alias = "gst_missing_plugin_message_set_stream_id")]
102        pub fn stream_id_if(self, stream_id: &'a str, predicate: bool) -> Self {
103            if predicate {
104                self.stream_id(stream_id)
105            } else {
106                self
107            }
108        }
109
110        #[cfg(feature = "v1_26")]
111        #[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
112        #[doc(alias = "gst_missing_plugin_message_set_stream_id")]
113        pub fn stream_id_if_some(self, stream_id: Option<&'a str>) -> Self {
114            if let Some(stream_id) = stream_id {
115                self.stream_id(stream_id)
116            } else {
117                self
118            }
119        }
120
121        // rustdoc-stripper-ignore-next
122        /// Sets field `name` to the given value `value`.
123        ///
124        /// Overrides any default or previously defined value for `name`.
125        pub fn other_field(self, name: &'a str, value: impl ToSendValue) -> Self {
126            Self {
127                builder: self.builder.other_field(name, value),
128                ..self
129            }
130        }
131
132        gst::impl_builder_gvalue_extra_setters!(other_field);
133
134        #[must_use = "Building the message without using it has no effect"]
135        #[allow(clippy::redundant_closure_call)]
136        pub fn build(mut self) -> Message {
137            skip_assert_initialized!();
138            unsafe {
139                let src = self.builder.src.to_glib_none().0;
140                let msg = $new_fn(&mut self, src);
141                if let Some(seqnum) = self.builder.seqnum {
142                    gst_ffi::gst_message_set_seqnum(msg, seqnum.into_glib());
143                }
144
145                #[cfg(feature = "v1_26")]
146                if let Some(details) = self.builder.details {
147                    gst_ffi::gst_message_set_details(msg, details.into_glib_ptr());
148                }
149
150                if !self.builder.other_fields.is_empty() {
151                    let structure = gst_ffi::gst_message_writable_structure(msg);
152
153                    if !structure.is_null() {
154                        let structure =
155                            gst::StructureRef::from_glib_borrow_mut(structure as *mut _);
156
157                        for (k, v) in self.builder.other_fields {
158                            structure.set_value(k, v);
159                        }
160                    }
161                }
162
163                from_glib_full(msg)
164            }
165        }
166    };
167}
168
169struct MessageBuilder<'a> {
170    src: Option<Element>,
171    seqnum: Option<Seqnum>,
172    #[cfg(feature = "v1_26")]
173    details: Option<gst::Structure>,
174    other_fields: Vec<(&'a str, glib::SendValue)>,
175}
176
177impl<'a> MessageBuilder<'a> {
178    fn new() -> Self {
179        skip_assert_initialized!();
180        Self {
181            src: None,
182            seqnum: None,
183            #[cfg(feature = "v1_26")]
184            details: None,
185            other_fields: Vec::new(),
186        }
187    }
188
189    fn src<O: IsA<Element> + Cast + Clone>(self, src: &O) -> Self {
190        Self {
191            src: Some(src.clone().upcast::<Element>()),
192            ..self
193        }
194    }
195
196    fn seqnum(self, seqnum: Seqnum) -> Self {
197        Self {
198            seqnum: Some(seqnum),
199            ..self
200        }
201    }
202
203    #[cfg(feature = "v1_26")]
204    #[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
205    #[doc(alias = "gst_message_set_details")]
206    fn details(self, details: gst::Structure) -> Self {
207        Self {
208            details: Some(details),
209            ..self
210        }
211    }
212
213    fn other_field(self, name: &'a str, value: impl ToSendValue) -> Self {
214        let mut other_fields = self.other_fields;
215        other_fields.push((name, value.to_send_value()));
216
217        Self {
218            other_fields,
219            ..self
220        }
221    }
222}
223
224enum MessageBuilderDetail<'a> {
225    Decoder(&'a gst::Caps),
226    Encoder(&'a gst::Caps),
227    Element(&'a str),
228    Sink(&'a str),
229    Src(&'a str),
230}
231
232#[must_use = "The builder must be built to be used"]
233pub struct MissingPluginMessageBuilder<'a> {
234    builder: MessageBuilder<'a>,
235    detail: MessageBuilderDetail<'a>,
236    #[cfg(feature = "v1_26")]
237    stream_id: Option<&'a str>,
238}
239
240impl<'a> MissingPluginMessageBuilder<'a> {
241    fn new(detail: MessageBuilderDetail<'a>) -> Self {
242        skip_assert_initialized!();
243        Self {
244            builder: MessageBuilder::new(),
245            detail,
246            #[cfg(feature = "v1_26")]
247            stream_id: None,
248        }
249    }
250
251    message_builder_generic_impl!(|s: &Self, src| {
252        let msg = match s.detail {
253            MessageBuilderDetail::Decoder(caps) => {
254                ffi::gst_missing_decoder_message_new(src, caps.to_glib_none().0)
255            }
256            MessageBuilderDetail::Encoder(caps) => {
257                ffi::gst_missing_encoder_message_new(src, caps.to_glib_none().0)
258            }
259            MessageBuilderDetail::Element(name) => {
260                ffi::gst_missing_element_message_new(src, name.to_glib_none().0)
261            }
262            MessageBuilderDetail::Sink(protocol) => {
263                ffi::gst_missing_uri_sink_message_new(src, protocol.to_glib_none().0)
264            }
265            MessageBuilderDetail::Src(protocol) => {
266                ffi::gst_missing_uri_source_message_new(src, protocol.to_glib_none().0)
267            }
268        };
269
270        #[cfg(feature = "v1_26")]
271        if let Some(stream_id) = s.stream_id {
272            ffi::gst_missing_plugin_message_set_stream_id(msg, stream_id.to_glib_none().0);
273        }
274
275        msg
276    });
277}
278
279#[derive(Clone, Debug)]
280pub struct MissingPluginMessage<'a> {
281    pub msg: &'a gst::MessageRef,
282}
283
284impl<'a> MissingPluginMessage<'a> {
285    #[doc(alias = "gst_missing_decoder_message_new")]
286    #[allow(clippy::new_ret_no_self)]
287    pub fn for_decoder(caps: &'a gst::Caps) -> gst::Message {
288        skip_assert_initialized!();
289        MissingPluginMessageBuilder::new(MessageBuilderDetail::Decoder(caps)).build()
290    }
291
292    #[doc(alias = "gst_missing_decoder_message_new")]
293    pub fn builder_for_decoder(caps: &'a gst::Caps) -> MissingPluginMessageBuilder<'a> {
294        skip_assert_initialized!();
295        MissingPluginMessageBuilder::new(MessageBuilderDetail::Decoder(caps))
296    }
297
298    #[doc(alias = "gst_missing_encoder_message_new")]
299    #[allow(clippy::new_ret_no_self)]
300    pub fn for_encoder(caps: &'a gst::Caps) -> gst::Message {
301        skip_assert_initialized!();
302        MissingPluginMessageBuilder::new(MessageBuilderDetail::Encoder(caps)).build()
303    }
304
305    #[doc(alias = "gst_missing_encoder_message_new")]
306    pub fn builder_for_encoder(caps: &'a gst::Caps) -> MissingPluginMessageBuilder<'a> {
307        skip_assert_initialized!();
308        MissingPluginMessageBuilder::new(MessageBuilderDetail::Encoder(caps))
309    }
310
311    #[doc(alias = "gst_missing_element_message_new")]
312    #[allow(clippy::new_ret_no_self)]
313    pub fn for_element(name: &'a str) -> gst::Message {
314        skip_assert_initialized!();
315        MissingPluginMessageBuilder::new(MessageBuilderDetail::Element(name)).build()
316    }
317
318    #[doc(alias = "gst_missing_element_message_new")]
319    pub fn builder_for_element(name: &'a str) -> MissingPluginMessageBuilder<'a> {
320        skip_assert_initialized!();
321        MissingPluginMessageBuilder::new(MessageBuilderDetail::Element(name))
322    }
323
324    #[doc(alias = "gst_missing_uri_source_message_new")]
325    #[allow(clippy::new_ret_no_self)]
326    pub fn for_uri_source(protocol: &'a str) -> gst::Message {
327        skip_assert_initialized!();
328        MissingPluginMessageBuilder::new(MessageBuilderDetail::Src(protocol)).build()
329    }
330
331    #[doc(alias = "gst_missing_uri_source_message_new")]
332    pub fn builder_for_uri_source(protocol: &'a str) -> MissingPluginMessageBuilder<'a> {
333        skip_assert_initialized!();
334        MissingPluginMessageBuilder::new(MessageBuilderDetail::Src(protocol))
335    }
336
337    #[doc(alias = "gst_missing_uri_sink_message_new")]
338    #[allow(clippy::new_ret_no_self)]
339    pub fn for_uri_sink(protocol: &'a str) -> gst::Message {
340        skip_assert_initialized!();
341        MissingPluginMessageBuilder::new(MessageBuilderDetail::Sink(protocol)).build()
342    }
343
344    #[doc(alias = "gst_missing_uri_sink_message_new")]
345    pub fn builder_for_uri_sink(protocol: &'a str) -> MissingPluginMessageBuilder<'a> {
346        skip_assert_initialized!();
347        MissingPluginMessageBuilder::new(MessageBuilderDetail::Sink(protocol))
348    }
349
350    #[doc(alias = "gst_is_missing_plugin_message")]
351    pub fn is(msg: &gst::MessageRef) -> bool {
352        skip_assert_initialized!();
353        unsafe {
354            from_glib(ffi::gst_is_missing_plugin_message(mut_override(
355                msg.as_ptr(),
356            )))
357        }
358    }
359
360    pub fn parse(msg: &'a gst::MessageRef) -> Result<Self, glib::error::BoolError> {
361        skip_assert_initialized!();
362        if Self::is(msg) {
363            Ok(MissingPluginMessage { msg })
364        } else {
365            Err(glib::bool_error!("Invalid missing plugin message"))
366        }
367    }
368
369    #[doc(alias = "gst_missing_plugin_message_get_description")]
370    pub fn description(&self) -> glib::GString {
371        unsafe {
372            from_glib_full(ffi::gst_missing_plugin_message_get_description(
373                mut_override(self.msg.as_ptr()),
374            ))
375        }
376    }
377
378    #[doc(alias = "gst_missing_plugin_message_get_installer_detail")]
379    pub fn installer_detail(&self) -> glib::GString {
380        unsafe {
381            from_glib_full(ffi::gst_missing_plugin_message_get_installer_detail(
382                mut_override(self.msg.as_ptr()),
383            ))
384        }
385    }
386
387    #[cfg(feature = "v1_26")]
388    #[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
389    #[doc(alias = "gst_missing_plugin_message_get_stream_id")]
390    pub fn stream_id(&self) -> Option<&glib::GStr> {
391        unsafe {
392            let stream_id =
393                ffi::gst_missing_plugin_message_get_stream_id(mut_override(self.msg.as_ptr()));
394            if stream_id.is_null() {
395                None
396            } else {
397                Some(glib::GStr::from_ptr(stream_id))
398            }
399        }
400    }
401}
402
403#[doc(alias = "gst_missing_decoder_installer_detail_new")]
404pub fn missing_decoder_installer_detail_new(caps: &gst::Caps) -> glib::GString {
405    skip_assert_initialized!();
406    unsafe {
407        from_glib_full(ffi::gst_missing_decoder_installer_detail_new(mut_override(
408            caps.as_ptr(),
409        )))
410    }
411}
412
413#[doc(alias = "gst_missing_encoder_installer_detail_new")]
414pub fn missing_encoder_installer_detail_new(caps: &gst::Caps) -> glib::GString {
415    skip_assert_initialized!();
416    unsafe {
417        from_glib_full(ffi::gst_missing_encoder_installer_detail_new(mut_override(
418            caps.as_ptr(),
419        )))
420    }
421}
422
423#[doc(alias = "gst_missing_element_installer_detail_new")]
424pub fn missing_element_installer_detail_new(name: &str) -> glib::GString {
425    skip_assert_initialized!();
426    unsafe {
427        from_glib_full(ffi::gst_missing_element_installer_detail_new(mut_override(
428            name.to_glib_none().0,
429        )))
430    }
431}
432
433#[doc(alias = "gst_missing_uri_source_installer_detail_new")]
434pub fn missing_uri_source_installer_detail_new(protocol: &str) -> glib::GString {
435    skip_assert_initialized!();
436    unsafe {
437        from_glib_full(ffi::gst_missing_uri_source_installer_detail_new(
438            mut_override(protocol.to_glib_none().0),
439        ))
440    }
441}
442
443#[doc(alias = "gst_missing_uri_sink_installer_detail_new")]
444pub fn missing_uri_sink_installer_detail_new(protocol: &str) -> glib::GString {
445    skip_assert_initialized!();
446    unsafe {
447        from_glib_full(ffi::gst_missing_uri_sink_installer_detail_new(
448            mut_override(protocol.to_glib_none().0),
449        ))
450    }
451}
452
453#[doc(alias = "gst_install_plugins_supported")]
454pub fn install_plugins_supported() -> bool {
455    skip_assert_initialized!();
456    unsafe { from_glib(ffi::gst_install_plugins_supported()) }
457}
458
459#[doc(alias = "gst_install_plugins_installation_in_progress")]
460pub fn install_plugins_installation_in_progress() -> bool {
461    skip_assert_initialized!();
462    unsafe { from_glib(ffi::gst_install_plugins_installation_in_progress()) }
463}
464
465#[doc(alias = "gst_install_plugins_sync")]
466pub fn install_plugins_sync(
467    details: &[&str],
468    ctx: Option<&crate::InstallPluginsContext>,
469) -> crate::InstallPluginsReturn {
470    skip_assert_initialized!();
471    unsafe {
472        from_glib(ffi::gst_install_plugins_sync(
473            ToGlibPtr::<*const *mut _>::to_glib_none(&glib::StrV::from(details)).0
474                as *const *const _,
475            ctx.to_glib_none().0,
476        ))
477    }
478}
479
480#[doc(alias = "gst_install_plugins_async")]
481pub fn install_plugins_async<F: FnOnce(crate::InstallPluginsReturn) + Send + 'static>(
482    details: &[&str],
483    ctx: Option<&crate::InstallPluginsContext>,
484    func: F,
485) -> crate::InstallPluginsReturn {
486    skip_assert_initialized!();
487
488    let user_data: Box<Option<F>> = Box::new(Some(func));
489
490    unsafe extern "C" fn trampoline<F: FnOnce(crate::InstallPluginsReturn) + Send + 'static>(
491        ret: ffi::GstInstallPluginsReturn,
492        user_data: glib::ffi::gpointer,
493    ) {
494        unsafe {
495            let callback = Box::from_raw(user_data as *mut F);
496            callback(from_glib(ret));
497        }
498    }
499
500    unsafe {
501        from_glib(ffi::gst_install_plugins_async(
502            ToGlibPtr::<*const *mut _>::to_glib_none(&glib::StrV::from(details)).0
503                as *const *const _,
504            ctx.to_glib_none().0,
505            Some(trampoline::<F>),
506            Box::into_raw(user_data) as *mut _,
507        ))
508    }
509}