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