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