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> {
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}