Skip to main content

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