gstreamer_video/
video_message.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::ptr;
4
5use glib::{
6    translate::{from_glib, from_glib_full, IntoGlib, ToGlibPtr},
7    value::ToSendValue,
8};
9use gst::{ffi as gst_ffi, prelude::*, Message, Object, Seqnum};
10
11use crate::{ffi, NavigationMessageType};
12
13macro_rules! message_builder_generic_impl {
14    ($new_fn:expr) => {
15        #[allow(clippy::needless_update)]
16        pub fn src<O: IsA<Object> + Cast + Clone>(self, src: &O) -> Self {
17            Self {
18                builder: self.builder.src(src),
19                ..self
20            }
21        }
22
23        #[allow(clippy::needless_update)]
24        pub fn src_if<O: IsA<Object> + Cast + Clone>(self, src: &O, predicate: bool) -> Self {
25            if predicate {
26                self.src(src)
27            } else {
28                self
29            }
30        }
31
32        #[allow(clippy::needless_update)]
33        pub fn src_if_some<O: IsA<Object> + Cast + Clone>(self, src: Option<&O>) -> Self {
34            if let Some(src) = src {
35                self.src(src)
36            } else {
37                self
38            }
39        }
40
41        #[doc(alias = "gst_message_set_seqnum")]
42        #[allow(clippy::needless_update)]
43        pub fn seqnum(self, seqnum: Seqnum) -> Self {
44            Self {
45                builder: self.builder.seqnum(seqnum),
46                ..self
47            }
48        }
49
50        #[doc(alias = "gst_message_set_seqnum")]
51        #[allow(clippy::needless_update)]
52        pub fn seqnum_if(self, seqnum: Seqnum, predicate: bool) -> Self {
53            if predicate {
54                self.seqnum(seqnum)
55            } else {
56                self
57            }
58        }
59
60        #[doc(alias = "gst_message_set_seqnum")]
61        #[allow(clippy::needless_update)]
62        pub fn seqnum_if_some(self, seqnum: Option<Seqnum>) -> Self {
63            if let Some(seqnum) = seqnum {
64                self.seqnum(seqnum)
65            } else {
66                self
67            }
68        }
69
70        pub fn other_field(self, name: &'a str, value: impl ToSendValue) -> Self {
71            Self {
72                builder: self.builder.other_field(name, value),
73                ..self
74            }
75        }
76
77        gst::impl_builder_gvalue_extra_setters!(other_field);
78
79        #[deprecated = "use builder.other_field() instead"]
80        #[allow(clippy::needless_update)]
81        pub fn other_fields(
82            self,
83            other_fields: &[(&'a str, &'a (dyn ToSendValue + Sync))],
84        ) -> Self {
85            Self {
86                builder: self.builder.other_fields(other_fields),
87                ..self
88            }
89        }
90
91        #[must_use = "Building the message without using it has no effect"]
92        #[allow(clippy::redundant_closure_call)]
93        pub fn build(mut self) -> Message {
94            skip_assert_initialized!();
95            unsafe {
96                let src = self.builder.src.to_glib_none().0;
97                let msg = $new_fn(&mut self, src);
98                if let Some(seqnum) = self.builder.seqnum {
99                    gst_ffi::gst_message_set_seqnum(msg, seqnum.into_glib());
100                }
101
102                if !self.builder.other_fields.is_empty() {
103                    let structure = gst_ffi::gst_message_writable_structure(msg);
104
105                    if !structure.is_null() {
106                        let structure =
107                            gst::StructureRef::from_glib_borrow_mut(structure as *mut _);
108
109                        for (k, v) in self.builder.other_fields {
110                            structure.set_value(k, v);
111                        }
112                    }
113                }
114
115                from_glib_full(msg)
116            }
117        }
118    };
119}
120
121struct MessageBuilder<'a> {
122    src: Option<Object>,
123    seqnum: Option<Seqnum>,
124    other_fields: Vec<(&'a str, glib::SendValue)>,
125}
126
127impl<'a> MessageBuilder<'a> {
128    pub(crate) fn new() -> Self {
129        skip_assert_initialized!();
130        Self {
131            src: None,
132            seqnum: None,
133            other_fields: Vec::new(),
134        }
135    }
136
137    pub fn src<O: IsA<Object> + Cast + Clone>(self, src: &O) -> Self {
138        Self {
139            src: Some(src.clone().upcast::<Object>()),
140            ..self
141        }
142    }
143
144    pub fn seqnum(self, seqnum: Seqnum) -> Self {
145        Self {
146            seqnum: Some(seqnum),
147            ..self
148        }
149    }
150
151    fn other_field(self, name: &'a str, value: impl ToSendValue) -> Self {
152        let mut other_fields = self.other_fields;
153        other_fields.push((name, value.to_send_value()));
154
155        Self {
156            other_fields,
157            ..self
158        }
159    }
160
161    fn other_fields(self, other_fields: &[(&'a str, &'a (dyn ToSendValue + Sync))]) -> Self {
162        let mut s = self;
163
164        for (name, value) in other_fields {
165            s = s.other_field(name, value.to_send_value());
166        }
167
168        s
169    }
170}
171
172#[must_use = "The builder must be built to be used"]
173pub struct NavigationEventMessageBuilder<'a> {
174    builder: MessageBuilder<'a>,
175    event: gst::Event,
176}
177
178impl<'a> NavigationEventMessageBuilder<'a> {
179    fn new(event: gst::Event) -> Self {
180        skip_assert_initialized!();
181        Self {
182            builder: MessageBuilder::new(),
183            event,
184        }
185    }
186
187    message_builder_generic_impl!(|s: &Self, src| ffi::gst_navigation_message_new_event(
188        src,
189        s.event.to_glib_none().0
190    ));
191}
192
193#[derive(Clone, Debug)]
194pub struct NavigationEventMessage {
195    pub event: gst::Event,
196}
197
198impl PartialEq for NavigationEventMessage {
199    fn eq(&self, other: &Self) -> bool {
200        self.event.as_ptr() == other.event.as_ptr()
201    }
202}
203
204impl Eq for NavigationEventMessage {}
205
206impl NavigationEventMessage {
207    #[doc(alias = "gst_navigation_message_new_event")]
208    #[allow(clippy::new_ret_no_self)]
209    pub fn new(event: gst::Event) -> gst::Message {
210        skip_assert_initialized!();
211        NavigationEventMessageBuilder::new(event).build()
212    }
213
214    pub fn builder<'a>(event: gst::Event) -> NavigationEventMessageBuilder<'a> {
215        skip_assert_initialized!();
216        NavigationEventMessageBuilder::new(event)
217    }
218
219    #[doc(alias = "gst_navigation_message_parse_event")]
220    pub fn parse(msg: &gst::MessageRef) -> Result<Self, glib::error::BoolError> {
221        skip_assert_initialized!();
222        unsafe {
223            let mut event = ptr::null_mut();
224            let ret = from_glib(ffi::gst_navigation_message_parse_event(
225                msg.as_mut_ptr(),
226                &mut event,
227            ));
228            if ret {
229                Ok(Self {
230                    event: from_glib_full(event),
231                })
232            } else {
233                Err(glib::bool_error!("Invalid navigation event msg"))
234            }
235        }
236    }
237}
238
239#[derive(Clone, PartialEq, Eq, Debug)]
240pub enum NavigationMessage {
241    Event(NavigationEventMessage),
242}
243
244impl NavigationMessage {
245    #[doc(alias = "gst_navigation_message_get_type")]
246    pub fn type_(msg: &gst::MessageRef) -> NavigationMessageType {
247        skip_assert_initialized!();
248        unsafe { from_glib(ffi::gst_navigation_message_get_type(msg.as_mut_ptr())) }
249    }
250
251    #[doc(alias = "gst_navigation_message_parse_event")]
252    pub fn parse(msg: &gst::MessageRef) -> Result<Self, glib::error::BoolError> {
253        skip_assert_initialized!();
254
255        let event_type: NavigationMessageType = Self::type_(msg);
256
257        match event_type {
258            NavigationMessageType::Event => NavigationEventMessage::parse(msg).map(Self::Event),
259            _ => Err(glib::bool_error!(
260                "Unsupported navigation msg {:?}",
261                event_type
262            )),
263        }
264    }
265}