gstreamer_editing_services/subclass/
formatter.rs1use 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> {
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 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}