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        #[must_use = "Building the message without using it has no effect"]
80        #[allow(clippy::redundant_closure_call)]
81        pub fn build(mut self) -> Message {
82            skip_assert_initialized!();
83            unsafe {
84                let src = self.builder.src.to_glib_none().0;
85                let msg = $new_fn(&mut self, src);
86                if let Some(seqnum) = self.builder.seqnum {
87                    gst_ffi::gst_message_set_seqnum(msg, seqnum.into_glib());
88                }
89
90                if !self.builder.other_fields.is_empty() {
91                    let structure = gst_ffi::gst_message_writable_structure(msg);
92
93                    if !structure.is_null() {
94                        let structure =
95                            gst::StructureRef::from_glib_borrow_mut(structure as *mut _);
96
97                        for (k, v) in self.builder.other_fields {
98                            structure.set_value(k, v);
99                        }
100                    }
101                }
102
103                from_glib_full(msg)
104            }
105        }
106    };
107}
108
109struct MessageBuilder<'a> {
110    src: Option<Object>,
111    seqnum: Option<Seqnum>,
112    other_fields: Vec<(&'a str, glib::SendValue)>,
113}
114
115impl<'a> MessageBuilder<'a> {
116    pub(crate) fn new() -> Self {
117        skip_assert_initialized!();
118        Self {
119            src: None,
120            seqnum: None,
121            other_fields: Vec::new(),
122        }
123    }
124
125    pub fn src<O: IsA<Object> + Cast + Clone>(self, src: &O) -> Self {
126        Self {
127            src: Some(src.clone().upcast::<Object>()),
128            ..self
129        }
130    }
131
132    pub fn seqnum(self, seqnum: Seqnum) -> Self {
133        Self {
134            seqnum: Some(seqnum),
135            ..self
136        }
137    }
138
139    fn other_field(self, name: &'a str, value: impl ToSendValue) -> Self {
140        let mut other_fields = self.other_fields;
141        other_fields.push((name, value.to_send_value()));
142
143        Self {
144            other_fields,
145            ..self
146        }
147    }
148}
149
150#[must_use = "The builder must be built to be used"]
151pub struct NavigationEventMessageBuilder<'a> {
152    builder: MessageBuilder<'a>,
153    event: gst::Event,
154}
155
156impl<'a> NavigationEventMessageBuilder<'a> {
157    fn new(event: gst::Event) -> Self {
158        skip_assert_initialized!();
159        Self {
160            builder: MessageBuilder::new(),
161            event,
162        }
163    }
164
165    message_builder_generic_impl!(|s: &Self, src| ffi::gst_navigation_message_new_event(
166        src,
167        s.event.to_glib_none().0
168    ));
169}
170
171#[derive(Clone, Debug)]
172pub struct NavigationEventMessage {
173    pub event: gst::Event,
174}
175
176impl PartialEq for NavigationEventMessage {
177    fn eq(&self, other: &Self) -> bool {
178        self.event.as_ptr() == other.event.as_ptr()
179    }
180}
181
182impl Eq for NavigationEventMessage {}
183
184impl NavigationEventMessage {
185    #[doc(alias = "gst_navigation_message_new_event")]
186    #[allow(clippy::new_ret_no_self)]
187    pub fn new(event: gst::Event) -> gst::Message {
188        skip_assert_initialized!();
189        NavigationEventMessageBuilder::new(event).build()
190    }
191
192    pub fn builder<'a>(event: gst::Event) -> NavigationEventMessageBuilder<'a> {
193        skip_assert_initialized!();
194        NavigationEventMessageBuilder::new(event)
195    }
196
197    #[doc(alias = "gst_navigation_message_parse_event")]
198    pub fn parse(msg: &gst::MessageRef) -> Result<Self, glib::error::BoolError> {
199        skip_assert_initialized!();
200        unsafe {
201            let mut event = ptr::null_mut();
202            let ret = from_glib(ffi::gst_navigation_message_parse_event(
203                msg.as_mut_ptr(),
204                &mut event,
205            ));
206            if ret {
207                Ok(Self {
208                    event: from_glib_full(event),
209                })
210            } else {
211                Err(glib::bool_error!("Invalid navigation event msg"))
212            }
213        }
214    }
215}
216
217#[derive(Clone, PartialEq, Eq, Debug)]
218pub enum NavigationMessage {
219    Event(NavigationEventMessage),
220}
221
222impl NavigationMessage {
223    #[doc(alias = "gst_navigation_message_get_type")]
224    pub fn type_(msg: &gst::MessageRef) -> NavigationMessageType {
225        skip_assert_initialized!();
226        unsafe { from_glib(ffi::gst_navigation_message_get_type(msg.as_mut_ptr())) }
227    }
228
229    #[doc(alias = "gst_navigation_message_parse_event")]
230    pub fn parse(msg: &gst::MessageRef) -> Result<Self, glib::error::BoolError> {
231        skip_assert_initialized!();
232
233        let event_type: NavigationMessageType = Self::type_(msg);
234
235        match event_type {
236            NavigationMessageType::Event => NavigationEventMessage::parse(msg).map(Self::Event),
237            _ => Err(glib::bool_error!(
238                "Unsupported navigation msg {:?}",
239                event_type
240            )),
241        }
242    }
243}