gstreamer_editing_services/subclass/
formatter.rs
1use crate::{ffi, prelude::*, Formatter};
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> {
9 self.parent_can_load_uri(uri)
10 }
11
12 fn load_from_uri(&self, timeline: &crate::Timeline, uri: &str) -> Result<(), glib::Error> {
27 self.parent_load_from_uri(timeline, uri)
28 }
29
30 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 let instance = &*(ptr as *mut T::Instance);
195 let imp = instance.imp();
196
197 match imp.can_load_uri(glib::GString::from_glib_borrow(uri).as_str()) {
198 Err(err) => {
199 if !error.is_null() {
200 *error = err.into_glib_ptr();
201 }
202
203 glib::ffi::GFALSE
204 }
205 Ok(_) => glib::ffi::GTRUE,
206 }
207}
208
209unsafe extern "C" fn formatter_load_from_uri<T: FormatterImpl>(
210 ptr: *mut ffi::GESFormatter,
211 timeline: *mut ffi::GESTimeline,
212 uri: *const libc::c_char,
213 error: *mut *mut glib::ffi::GError,
214) -> glib::ffi::gboolean {
215 let instance = &*(ptr as *mut T::Instance);
216 let imp = instance.imp();
217 let timeline = from_glib_borrow(timeline);
218
219 match imp.load_from_uri(&timeline, glib::GString::from_glib_borrow(uri).as_str()) {
220 Err(err) => {
221 if !error.is_null() {
222 *error = err.into_glib_ptr();
223 }
224
225 glib::ffi::GFALSE
226 }
227 Ok(_) => glib::ffi::GTRUE,
228 }
229}
230
231unsafe extern "C" fn formatter_save_to_uri<T: FormatterImpl>(
232 ptr: *mut ffi::GESFormatter,
233 timeline: *mut ffi::GESTimeline,
234 uri: *const libc::c_char,
235 overwrite: glib::ffi::gboolean,
236 error: *mut *mut glib::ffi::GError,
237) -> glib::ffi::gboolean {
238 let instance = &*(ptr as *mut T::Instance);
239 let imp = instance.imp();
240 let timeline = from_glib_borrow(timeline);
241
242 match imp.save_to_uri(
243 &timeline,
244 glib::GString::from_glib_borrow(uri).as_str(),
245 from_glib(overwrite),
246 ) {
247 Err(err) => {
248 if !error.is_null() {
249 *error = err.into_glib_ptr();
250 }
251
252 glib::ffi::GFALSE
253 }
254 Ok(_) => glib::ffi::GTRUE,
255 }
256}
257
258#[cfg(test)]
259mod tests {
260 use super::*;
261 use crate::Formatter;
262
263 pub mod imp {
264 use super::*;
265
266 #[derive(Default)]
267 pub struct SimpleFormatter;
268
269 #[glib::object_subclass]
270 impl ObjectSubclass for SimpleFormatter {
271 const NAME: &'static str = "SimpleFormatter";
272 type Type = super::SimpleFormatter;
273 type ParentType = Formatter;
274 }
275 impl ObjectImpl for SimpleFormatter {}
276 impl FormatterImpl for SimpleFormatter {
277 fn can_load_uri(&self, uri: &str) -> Result<(), glib::Error> {
278 if uri.starts_with("ges:test") {
279 Ok(())
280 } else {
281 self.parent_can_load_uri(uri)
282 }
283 }
284
285 fn load_from_uri(
286 &self,
287 timeline: &crate::Timeline,
288 _uri: &str,
289 ) -> Result<(), glib::Error> {
290 timeline.append_layer();
291
292 Ok(())
293 }
294
295 fn save_to_uri(
296 &self,
297 timeline: &crate::Timeline,
298 uri: &str,
299 _overwrite: bool,
300 ) -> Result<(), glib::Error> {
301 unsafe { timeline.set_data("saved", uri.to_string()) };
302
303 Ok(())
304 }
305 }
306 }
307
308 glib::wrapper! {
309 pub struct SimpleFormatter(ObjectSubclass<imp::SimpleFormatter>) @extends Formatter, gst::Object;
310 }
311
312 impl SimpleFormatter {
313 pub fn new() -> Self {
314 glib::Object::builder().build()
315 }
316 }
317
318 impl Default for SimpleFormatter {
319 fn default() -> Self {
320 Self::new()
321 }
322 }
323
324 #[test]
325 fn test_formatter_subclass() {
326 crate::init().unwrap();
327
328 let formatter = SimpleFormatter::new();
329 formatter
330 .can_load_uri("ges:test:")
331 .expect("We can load anything...");
332
333 assert!(formatter.can_load_uri("nottest").is_err());
334
335 let timeline = crate::Timeline::new();
336 assert_eq!(timeline.layers().len(), 0);
337 #[allow(deprecated)]
338 formatter
339 .load_from_uri(&timeline, "test")
340 .expect("We can load anything...");
341 assert_eq!(timeline.layers().len(), 1);
342
343 unsafe {
344 assert_eq!(timeline.data::<Option<String>>("saved"), None);
345 }
346 #[allow(deprecated)]
347 formatter
348 .save_to_uri(&timeline, "test", false)
349 .expect("We can save anything...");
350 unsafe {
351 assert_eq!(
352 timeline.data::<String>("saved").unwrap().as_ref(),
353 &"test".to_string()
354 );
355 }
356
357 Formatter::register(
358 SimpleFormatter::static_type(),
359 "SimpleFormatter",
360 None,
361 None,
362 None,
363 1.0,
364 gst::Rank::PRIMARY,
365 );
366
367 let proj = crate::Project::new(Some("ges:test:"));
368 let timeline = proj
369 .extract()
370 .unwrap()
371 .downcast::<crate::Timeline>()
372 .unwrap();
373 assert_eq!(timeline.layers().len(), 1);
374
375 let proj = crate::Project::new(Some("ges:notest:"));
376 assert!(proj.extract().is_err());
377 }
378}