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        #[deprecated = "use builder.other_field() instead"]
143        #[allow(clippy::needless_update)]
144        pub fn other_fields(
145            self,
146            other_fields: &[(&'a str, &'a (dyn ToSendValue + Sync))],
147        ) -> Self {
148            Self {
149                builder: self.builder.other_fields(other_fields),
150                ..self
151            }
152        }
153
154        #[must_use = "Building the message without using it has no effect"]
155        #[allow(clippy::redundant_closure_call)]
156        pub fn build(mut self) -> Message {
157            skip_assert_initialized!();
158            unsafe {
159                let src = self.builder.src.to_glib_none().0;
160                let msg = $new_fn(&mut self, src);
161                if let Some(seqnum) = self.builder.seqnum {
162                    gst_ffi::gst_message_set_seqnum(msg, seqnum.into_glib());
163                }
164
165                #[cfg(feature = "v1_26")]
166                if let Some(details) = self.builder.details {
167                    gst_ffi::gst_message_set_details(msg, details.into_glib_ptr());
168                }
169
170                if !self.builder.other_fields.is_empty() {
171                    let structure = gst_ffi::gst_message_writable_structure(msg);
172
173                    if !structure.is_null() {
174                        let structure =
175                            gst::StructureRef::from_glib_borrow_mut(structure as *mut _);
176
177                        for (k, v) in self.builder.other_fields {
178                            structure.set_value(k, v);
179                        }
180                    }
181                }
182
183                from_glib_full(msg)
184            }
185        }
186    };
187}
188
189struct MessageBuilder<'a> {
190    src: Option<Element>,
191    seqnum: Option<Seqnum>,
192    #[cfg(feature = "v1_26")]
193    details: Option<gst::Structure>,
194    other_fields: Vec<(&'a str, glib::SendValue)>,
195}
196
197impl<'a> MessageBuilder<'a> {
198    fn new() -> Self {
199        skip_assert_initialized!();
200        Self {
201            src: None,
202            seqnum: None,
203            #[cfg(feature = "v1_26")]
204            details: None,
205            other_fields: Vec::new(),
206        }
207    }
208
209    fn src<O: IsA<Element> + Cast + Clone>(self, src: &O) -> Self {
210        Self {
211            src: Some(src.clone().upcast::<Element>()),
212            ..self
213        }
214    }
215
216    fn seqnum(self, seqnum: Seqnum) -> Self {
217        Self {
218            seqnum: Some(seqnum),
219            ..self
220        }
221    }
222
223    #[cfg(feature = "v1_26")]
224    #[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
225    #[doc(alias = "gst_message_set_details")]
226    fn details(self, details: gst::Structure) -> Self {
227        Self {
228            details: Some(details),
229            ..self
230        }
231    }
232
233    fn other_field(self, name: &'a str, value: impl ToSendValue) -> Self {
234        let mut other_fields = self.other_fields;
235        other_fields.push((name, value.to_send_value()));
236
237        Self {
238            other_fields,
239            ..self
240        }
241    }
242
243    fn other_fields(self, other_fields: &[(&'a str, &'a (dyn ToSendValue + Sync))]) -> Self {
244        let mut s = self;
245
246        for (name, value) in other_fields {
247            s = s.other_field(name, value.to_send_value());
248        }
249
250        s
251    }
252}
253
254enum MessageBuilderDetail<'a> {
255    Decoder(&'a gst::Caps),
256    Encoder(&'a gst::Caps),
257    Element(&'a str),
258    Sink(&'a str),
259    Src(&'a str),
260}
261
262#[must_use = "The builder must be built to be used"]
263pub struct MissingPluginMessageBuilder<'a> {
264    builder: MessageBuilder<'a>,
265    detail: MessageBuilderDetail<'a>,
266    #[cfg(feature = "v1_26")]
267    stream_id: Option<&'a str>,
268}
269
270impl<'a> MissingPluginMessageBuilder<'a> {
271    fn new(detail: MessageBuilderDetail<'a>) -> Self {
272        skip_assert_initialized!();
273        Self {
274            builder: MessageBuilder::new(),
275            detail,
276            #[cfg(feature = "v1_26")]
277            stream_id: None,
278        }
279    }
280
281    message_builder_generic_impl!(|s: &Self, src| {
282        let msg = match s.detail {
283            MessageBuilderDetail::Decoder(caps) => {
284                ffi::gst_missing_decoder_message_new(src, caps.to_glib_none().0)
285            }
286            MessageBuilderDetail::Encoder(caps) => {
287                ffi::gst_missing_encoder_message_new(src, caps.to_glib_none().0)
288            }
289            MessageBuilderDetail::Element(name) => {
290                ffi::gst_missing_element_message_new(src, name.to_glib_none().0)
291            }
292            MessageBuilderDetail::Sink(protocol) => {
293                ffi::gst_missing_uri_sink_message_new(src, protocol.to_glib_none().0)
294            }
295            MessageBuilderDetail::Src(protocol) => {
296                ffi::gst_missing_uri_source_message_new(src, protocol.to_glib_none().0)
297            }
298        };
299
300        #[cfg(feature = "v1_26")]
301        if let Some(stream_id) = s.stream_id {
302            ffi::gst_missing_plugin_message_set_stream_id(msg, stream_id.to_glib_none().0);
303        }
304
305        msg
306    });
307}
308
309#[derive(Clone, Debug)]
310pub struct MissingPluginMessage<'a> {
311    pub msg: &'a gst::MessageRef,
312}
313
314impl<'a> MissingPluginMessage<'a> {
315    #[doc(alias = "gst_missing_decoder_message_new")]
316    #[allow(clippy::new_ret_no_self)]
317    pub fn for_decoder(caps: &'a gst::Caps) -> gst::Message {
318        skip_assert_initialized!();
319        MissingPluginMessageBuilder::new(MessageBuilderDetail::Decoder(caps)).build()
320    }
321
322    #[doc(alias = "gst_missing_decoder_message_new")]
323    pub fn builder_for_decoder(caps: &'a gst::Caps) -> MissingPluginMessageBuilder<'a> {
324        skip_assert_initialized!();
325        MissingPluginMessageBuilder::new(MessageBuilderDetail::Decoder(caps))
326    }
327
328    #[doc(alias = "gst_missing_encoder_message_new")]
329    #[allow(clippy::new_ret_no_self)]
330    pub fn for_encoder(caps: &'a gst::Caps) -> gst::Message {
331        skip_assert_initialized!();
332        MissingPluginMessageBuilder::new(MessageBuilderDetail::Encoder(caps)).build()
333    }
334
335    #[doc(alias = "gst_missing_encoder_message_new")]
336    pub fn builder_for_encoder(caps: &'a gst::Caps) -> MissingPluginMessageBuilder<'a> {
337        skip_assert_initialized!();
338        MissingPluginMessageBuilder::new(MessageBuilderDetail::Encoder(caps))
339    }
340
341    #[doc(alias = "gst_missing_element_message_new")]
342    #[allow(clippy::new_ret_no_self)]
343    pub fn for_element(name: &'a str) -> gst::Message {
344        skip_assert_initialized!();
345        MissingPluginMessageBuilder::new(MessageBuilderDetail::Element(name)).build()
346    }
347
348    #[doc(alias = "gst_missing_element_message_new")]
349    pub fn builder_for_element(name: &'a str) -> MissingPluginMessageBuilder<'a> {
350        skip_assert_initialized!();
351        MissingPluginMessageBuilder::new(MessageBuilderDetail::Element(name))
352    }
353
354    #[doc(alias = "gst_missing_uri_source_message_new")]
355    #[allow(clippy::new_ret_no_self)]
356    pub fn for_uri_source(protocol: &'a str) -> gst::Message {
357        skip_assert_initialized!();
358        MissingPluginMessageBuilder::new(MessageBuilderDetail::Src(protocol)).build()
359    }
360
361    #[doc(alias = "gst_missing_uri_source_message_new")]
362    pub fn builder_for_uri_source(protocol: &'a str) -> MissingPluginMessageBuilder<'a> {
363        skip_assert_initialized!();
364        MissingPluginMessageBuilder::new(MessageBuilderDetail::Src(protocol))
365    }
366
367    #[doc(alias = "gst_missing_uri_sink_message_new")]
368    #[allow(clippy::new_ret_no_self)]
369    pub fn for_uri_sink(protocol: &'a str) -> gst::Message {
370        skip_assert_initialized!();
371        MissingPluginMessageBuilder::new(MessageBuilderDetail::Sink(protocol)).build()
372    }
373
374    #[doc(alias = "gst_missing_uri_sink_message_new")]
375    pub fn builder_for_uri_sink(protocol: &'a str) -> MissingPluginMessageBuilder<'a> {
376        skip_assert_initialized!();
377        MissingPluginMessageBuilder::new(MessageBuilderDetail::Sink(protocol))
378    }
379
380    #[doc(alias = "gst_is_missing_plugin_message")]
381    pub fn is(msg: &gst::MessageRef) -> bool {
382        skip_assert_initialized!();
383        unsafe {
384            from_glib(ffi::gst_is_missing_plugin_message(mut_override(
385                msg.as_ptr(),
386            )))
387        }
388    }
389
390    pub fn parse(msg: &'a gst::MessageRef) -> Result<Self, glib::error::BoolError> {
391        skip_assert_initialized!();
392        if Self::is(msg) {
393            Ok(MissingPluginMessage { msg })
394        } else {
395            Err(glib::bool_error!("Invalid missing plugin message"))
396        }
397    }
398
399    #[doc(alias = "gst_missing_plugin_message_get_description")]
400    pub fn description(&self) -> glib::GString {
401        unsafe {
402            from_glib_full(ffi::gst_missing_plugin_message_get_description(
403                mut_override(self.msg.as_ptr()),
404            ))
405        }
406    }
407
408    #[doc(alias = "gst_missing_plugin_message_get_installer_detail")]
409    pub fn installer_detail(&self) -> glib::GString {
410        unsafe {
411            from_glib_full(ffi::gst_missing_plugin_message_get_installer_detail(
412                mut_override(self.msg.as_ptr()),
413            ))
414        }
415    }
416
417    #[cfg(feature = "v1_26")]
418    #[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
419    #[doc(alias = "gst_missing_plugin_message_get_stream_id")]
420    pub fn stream_id(&self) -> Option<&glib::GStr> {
421        unsafe {
422            let stream_id =
423                ffi::gst_missing_plugin_message_get_stream_id(mut_override(self.msg.as_ptr()));
424            if stream_id.is_null() {
425                None
426            } else {
427                Some(glib::GStr::from_ptr(stream_id))
428            }
429        }
430    }
431}
432
433#[doc(alias = "gst_missing_decoder_installer_detail_new")]
434pub fn missing_decoder_installer_detail_new(caps: &gst::Caps) -> glib::GString {
435    skip_assert_initialized!();
436    unsafe {
437        from_glib_full(ffi::gst_missing_decoder_installer_detail_new(mut_override(
438            caps.as_ptr(),
439        )))
440    }
441}
442
443#[doc(alias = "gst_missing_encoder_installer_detail_new")]
444pub fn missing_encoder_installer_detail_new(caps: &gst::Caps) -> glib::GString {
445    skip_assert_initialized!();
446    unsafe {
447        from_glib_full(ffi::gst_missing_encoder_installer_detail_new(mut_override(
448            caps.as_ptr(),
449        )))
450    }
451}
452
453#[doc(alias = "gst_missing_element_installer_detail_new")]
454pub fn missing_element_installer_detail_new(name: &str) -> glib::GString {
455    skip_assert_initialized!();
456    unsafe {
457        from_glib_full(ffi::gst_missing_element_installer_detail_new(mut_override(
458            name.to_glib_none().0,
459        )))
460    }
461}
462
463#[doc(alias = "gst_missing_uri_source_installer_detail_new")]
464pub fn missing_uri_source_installer_detail_new(protocol: &str) -> glib::GString {
465    skip_assert_initialized!();
466    unsafe {
467        from_glib_full(ffi::gst_missing_uri_source_installer_detail_new(
468            mut_override(protocol.to_glib_none().0),
469        ))
470    }
471}
472
473#[doc(alias = "gst_missing_uri_sink_installer_detail_new")]
474pub fn missing_uri_sink_installer_detail_new(protocol: &str) -> glib::GString {
475    skip_assert_initialized!();
476    unsafe {
477        from_glib_full(ffi::gst_missing_uri_sink_installer_detail_new(
478            mut_override(protocol.to_glib_none().0),
479        ))
480    }
481}
482
483#[doc(alias = "gst_install_plugins_supported")]
484pub fn install_plugins_supported() -> bool {
485    skip_assert_initialized!();
486    unsafe { from_glib(ffi::gst_install_plugins_supported()) }
487}
488
489#[doc(alias = "gst_install_plugins_installation_in_progress")]
490pub fn install_plugins_installation_in_progress() -> bool {
491    skip_assert_initialized!();
492    unsafe { from_glib(ffi::gst_install_plugins_installation_in_progress()) }
493}
494
495#[doc(alias = "gst_install_plugins_sync")]
496pub fn install_plugins_sync(
497    details: &[&str],
498    ctx: Option<&crate::InstallPluginsContext>,
499) -> crate::InstallPluginsReturn {
500    skip_assert_initialized!();
501    unsafe {
502        from_glib(ffi::gst_install_plugins_sync(
503            ToGlibPtr::<*const *mut _>::to_glib_none(&glib::StrV::from(details)).0
504                as *const *const _,
505            ctx.to_glib_none().0,
506        ))
507    }
508}
509
510#[doc(alias = "gst_install_plugins_async")]
511pub fn install_plugins_async<F: FnOnce(crate::InstallPluginsReturn) + Send + 'static>(
512    details: &[&str],
513    ctx: Option<&crate::InstallPluginsContext>,
514    func: F,
515) -> crate::InstallPluginsReturn {
516    skip_assert_initialized!();
517
518    let user_data: Box<Option<F>> = Box::new(Some(func));
519
520    unsafe extern "C" fn trampoline<F: FnOnce(crate::InstallPluginsReturn) + Send + 'static>(
521        ret: ffi::GstInstallPluginsReturn,
522        user_data: glib::ffi::gpointer,
523    ) {
524        let callback = Box::from_raw(user_data as *mut F);
525        callback(from_glib(ret));
526    }
527
528    unsafe {
529        from_glib(ffi::gst_install_plugins_async(
530            ToGlibPtr::<*const *mut _>::to_glib_none(&glib::StrV::from(details)).0
531                as *const *const _,
532            ctx.to_glib_none().0,
533            Some(trampoline::<F>),
534            Box::into_raw(user_data) as *mut _,
535        ))
536    }
537}