Skip to main content

gstreamer_editing_services/subclass/
formatter.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use crate::{Formatter, ffi, prelude::*};
4use glib::{subclass::prelude::*, translate::*};
5
6pub trait FormatterImpl: ObjectImpl + ObjectSubclass<Type: IsA<Formatter>> + Send + Sync {
7    fn can_load_uri(&self, uri: &str) -> Result<(), glib::Error> {
8        self.parent_can_load_uri(uri)
9    }
10
11    fn load_from_uri(&self, timeline: &crate::Timeline, uri: &str) -> Result<(), glib::Error> {
12        self.parent_load_from_uri(timeline, uri)
13    }
14
15    fn save_to_uri(
16        &self,
17        timeline: &crate::Timeline,
18        uri: &str,
19        overwrite: bool,
20    ) -> Result<(), glib::Error> {
21        self.parent_save_to_uri(timeline, uri, overwrite)
22    }
23}
24
25pub trait FormatterImplExt: FormatterImpl {
26    fn parent_can_load_uri(&self, uri: &str) -> Result<(), glib::Error> {
27        unsafe {
28            let data = Self::type_data();
29            let parent_class = data.as_ref().parent_class() as *mut ffi::GESFormatterClass;
30
31            let f = (*parent_class)
32                .can_load_uri
33                .expect("Missing parent function `can_load_uri`");
34
35            let mut error = std::ptr::null_mut();
36            let res = f(
37                self.obj()
38                    .unsafe_cast_ref::<crate::Formatter>()
39                    .to_glib_none()
40                    .0,
41                uri.to_glib_none().0,
42                &mut error,
43            );
44
45            if res == glib::ffi::GFALSE {
46                if error.is_null() {
47                    Err(glib::Error::new(
48                        gst::CoreError::Failed,
49                        "Can load uri failed",
50                    ))
51                } else {
52                    Err(from_glib_full(error))
53                }
54            } else {
55                Ok(())
56            }
57        }
58    }
59
60    fn parent_load_from_uri(
61        &self,
62        timeline: &crate::Timeline,
63        uri: &str,
64    ) -> Result<(), glib::Error> {
65        unsafe {
66            let data = Self::type_data();
67            let parent_class = data.as_ref().parent_class() as *mut ffi::GESFormatterClass;
68
69            let f = (*parent_class)
70                .load_from_uri
71                .expect("Missing parent function `load_from_uri`");
72
73            let mut error = std::ptr::null_mut();
74            let res = f(
75                self.obj()
76                    .unsafe_cast_ref::<crate::Formatter>()
77                    .to_glib_none()
78                    .0,
79                timeline
80                    .unsafe_cast_ref::<crate::Timeline>()
81                    .to_glib_none()
82                    .0,
83                uri.to_glib_none().0,
84                &mut error,
85            );
86
87            if res == glib::ffi::GFALSE {
88                if error.is_null() {
89                    Err(glib::Error::new(
90                        gst::CoreError::Failed,
91                        "Load from uri failed",
92                    ))
93                } else {
94                    Err(from_glib_full(error))
95                }
96            } else {
97                Ok(())
98            }
99        }
100    }
101    fn parent_save_to_uri(
102        &self,
103        timeline: &crate::Timeline,
104        uri: &str,
105        overwrite: bool,
106    ) -> Result<(), glib::Error> {
107        unsafe {
108            let data = Self::type_data();
109            let parent_class = data.as_ref().parent_class() as *mut ffi::GESFormatterClass;
110
111            let f = (*parent_class)
112                .save_to_uri
113                .expect("Missing parent function `save_to_uri`");
114
115            let mut error = std::ptr::null_mut();
116            let res = f(
117                self.obj()
118                    .unsafe_cast_ref::<crate::Formatter>()
119                    .to_glib_none()
120                    .0,
121                timeline
122                    .unsafe_cast_ref::<crate::Timeline>()
123                    .to_glib_none()
124                    .0,
125                uri.to_glib_none().0,
126                overwrite.into_glib(),
127                &mut error,
128            );
129
130            if res == glib::ffi::GFALSE {
131                if error.is_null() {
132                    Err(glib::Error::new(
133                        gst::CoreError::Failed,
134                        "Save to uri failed",
135                    ))
136                } else {
137                    Err(from_glib_full(error))
138                }
139            } else {
140                Ok(())
141            }
142        }
143    }
144}
145
146impl<T: FormatterImpl> FormatterImplExt for T {}
147
148unsafe impl<T: FormatterImpl> IsSubclassable<T> for Formatter {
149    fn class_init(klass: &mut glib::Class<Self>) {
150        Self::parent_class_init::<T>(klass);
151        let klass = klass.as_mut();
152        klass.can_load_uri = Some(formatter_can_load_uri::<T>);
153        klass.load_from_uri = Some(formatter_load_from_uri::<T>);
154        klass.save_to_uri = Some(formatter_save_to_uri::<T>);
155    }
156}
157
158unsafe extern "C" fn formatter_can_load_uri<T: FormatterImpl>(
159    ptr: *mut ffi::GESFormatter,
160    uri: *const libc::c_char,
161    error: *mut *mut glib::ffi::GError,
162) -> glib::ffi::gboolean {
163    unsafe {
164        let instance = &*(ptr as *mut T::Instance);
165        let imp = instance.imp();
166
167        match imp.can_load_uri(glib::GString::from_glib_borrow(uri).as_str()) {
168            Err(err) => {
169                if !error.is_null() {
170                    *error = err.into_glib_ptr();
171                }
172
173                glib::ffi::GFALSE
174            }
175            Ok(_) => glib::ffi::GTRUE,
176        }
177    }
178}
179
180unsafe extern "C" fn formatter_load_from_uri<T: FormatterImpl>(
181    ptr: *mut ffi::GESFormatter,
182    timeline: *mut ffi::GESTimeline,
183    uri: *const libc::c_char,
184    error: *mut *mut glib::ffi::GError,
185) -> glib::ffi::gboolean {
186    unsafe {
187        let instance = &*(ptr as *mut T::Instance);
188        let imp = instance.imp();
189        let timeline = from_glib_borrow(timeline);
190
191        match imp.load_from_uri(&timeline, glib::GString::from_glib_borrow(uri).as_str()) {
192            Err(err) => {
193                if !error.is_null() {
194                    *error = err.into_glib_ptr();
195                }
196
197                glib::ffi::GFALSE
198            }
199            Ok(_) => glib::ffi::GTRUE,
200        }
201    }
202}
203
204unsafe extern "C" fn formatter_save_to_uri<T: FormatterImpl>(
205    ptr: *mut ffi::GESFormatter,
206    timeline: *mut ffi::GESTimeline,
207    uri: *const libc::c_char,
208    overwrite: glib::ffi::gboolean,
209    error: *mut *mut glib::ffi::GError,
210) -> glib::ffi::gboolean {
211    unsafe {
212        let instance = &*(ptr as *mut T::Instance);
213        let imp = instance.imp();
214        let timeline = from_glib_borrow(timeline);
215
216        match imp.save_to_uri(
217            &timeline,
218            glib::GString::from_glib_borrow(uri).as_str(),
219            from_glib(overwrite),
220        ) {
221            Err(err) => {
222                if !error.is_null() {
223                    *error = err.into_glib_ptr();
224                }
225
226                glib::ffi::GFALSE
227            }
228            Ok(_) => glib::ffi::GTRUE,
229        }
230    }
231}
232
233#[cfg(test)]
234mod tests {
235    use super::*;
236    use crate::Formatter;
237
238    pub mod imp {
239        use super::*;
240
241        #[derive(Default)]
242        pub struct SimpleFormatter;
243
244        #[glib::object_subclass]
245        impl ObjectSubclass for SimpleFormatter {
246            const NAME: &'static str = "SimpleFormatter";
247            type Type = super::SimpleFormatter;
248            type ParentType = Formatter;
249        }
250        impl ObjectImpl for SimpleFormatter {}
251        impl FormatterImpl for SimpleFormatter {
252            fn can_load_uri(&self, uri: &str) -> Result<(), glib::Error> {
253                if uri.starts_with("ges:test") {
254                    Ok(())
255                } else {
256                    self.parent_can_load_uri(uri)
257                }
258            }
259
260            fn load_from_uri(
261                &self,
262                timeline: &crate::Timeline,
263                _uri: &str,
264            ) -> Result<(), glib::Error> {
265                timeline.append_layer();
266
267                Ok(())
268            }
269
270            fn save_to_uri(
271                &self,
272                timeline: &crate::Timeline,
273                uri: &str,
274                _overwrite: bool,
275            ) -> Result<(), glib::Error> {
276                unsafe { timeline.set_data("saved", uri.to_string()) };
277
278                Ok(())
279            }
280        }
281    }
282
283    glib::wrapper! {
284        pub struct SimpleFormatter(ObjectSubclass<imp::SimpleFormatter>) @extends Formatter, gst::Object;
285    }
286
287    impl SimpleFormatter {
288        pub fn new() -> Self {
289            glib::Object::builder().build()
290        }
291    }
292
293    impl Default for SimpleFormatter {
294        fn default() -> Self {
295            Self::new()
296        }
297    }
298
299    #[test]
300    fn test_formatter_subclass() {
301        crate::init().unwrap();
302
303        let formatter = SimpleFormatter::new();
304        formatter
305            .can_load_uri("ges:test:")
306            .expect("We can load anything...");
307
308        assert!(formatter.can_load_uri("nottest").is_err());
309
310        let timeline = crate::Timeline::new();
311        assert_eq!(timeline.layers().len(), 0);
312        #[allow(deprecated)]
313        formatter
314            .load_from_uri(&timeline, "test")
315            .expect("We can load anything...");
316        assert_eq!(timeline.layers().len(), 1);
317
318        unsafe {
319            assert_eq!(timeline.data::<Option<String>>("saved"), None);
320        }
321        #[allow(deprecated)]
322        formatter
323            .save_to_uri(&timeline, "test", false)
324            .expect("We can save anything...");
325        unsafe {
326            assert_eq!(
327                timeline.data::<String>("saved").unwrap().as_ref(),
328                &"test".to_string()
329            );
330        }
331
332        Formatter::register(
333            SimpleFormatter::static_type(),
334            "SimpleFormatter",
335            None,
336            None,
337            None,
338            1.0,
339            gst::Rank::PRIMARY,
340        );
341
342        let proj = crate::Project::new(Some("ges:test:"));
343        let timeline = proj
344            .extract()
345            .unwrap()
346            .downcast::<crate::Timeline>()
347            .unwrap();
348        assert_eq!(timeline.layers().len(), 1);
349
350        let proj = crate::Project::new(Some("ges:notest:"));
351        assert!(proj.extract().is_err());
352    }
353}