1 | // Take a look at the license at the top of the repository in the LICENSE file. |
2 | |
3 | use std::{mem, ptr}; |
4 | |
5 | use atomic_refcell::AtomicRefCell; |
6 | use glib::{prelude::*, translate::*}; |
7 | use gst::{prelude::*, subclass::prelude::*}; |
8 | |
9 | use crate::{ffi, prelude::*, BaseSrc}; |
10 | |
11 | #[derive (Default)] |
12 | pub(super) struct InstanceData { |
13 | pub(super) pending_buffer_list: AtomicRefCell<Option<gst::BufferList>>, |
14 | } |
15 | |
16 | #[derive (Debug)] |
17 | pub enum CreateSuccess { |
18 | FilledBuffer, |
19 | NewBuffer(gst::Buffer), |
20 | NewBufferList(gst::BufferList), |
21 | } |
22 | |
23 | pub trait BaseSrcImpl: BaseSrcImplExt + ElementImpl { |
24 | fn start(&self) -> Result<(), gst::ErrorMessage> { |
25 | self.parent_start() |
26 | } |
27 | |
28 | fn stop(&self) -> Result<(), gst::ErrorMessage> { |
29 | self.parent_stop() |
30 | } |
31 | |
32 | fn is_seekable(&self) -> bool { |
33 | self.parent_is_seekable() |
34 | } |
35 | |
36 | fn size(&self) -> Option<u64> { |
37 | self.parent_size() |
38 | } |
39 | |
40 | #[doc (alias = "get_times" )] |
41 | fn times(&self, buffer: &gst::BufferRef) -> (Option<gst::ClockTime>, Option<gst::ClockTime>) { |
42 | self.parent_times(buffer) |
43 | } |
44 | |
45 | fn fill( |
46 | &self, |
47 | offset: u64, |
48 | length: u32, |
49 | buffer: &mut gst::BufferRef, |
50 | ) -> Result<gst::FlowSuccess, gst::FlowError> { |
51 | self.parent_fill(offset, length, buffer) |
52 | } |
53 | |
54 | fn alloc(&self, offset: u64, length: u32) -> Result<gst::Buffer, gst::FlowError> { |
55 | self.parent_alloc(offset, length) |
56 | } |
57 | |
58 | fn create( |
59 | &self, |
60 | offset: u64, |
61 | buffer: Option<&mut gst::BufferRef>, |
62 | length: u32, |
63 | ) -> Result<CreateSuccess, gst::FlowError> { |
64 | self.parent_create(offset, buffer, length) |
65 | } |
66 | |
67 | fn do_seek(&self, segment: &mut gst::Segment) -> bool { |
68 | self.parent_do_seek(segment) |
69 | } |
70 | |
71 | fn query(&self, query: &mut gst::QueryRef) -> bool { |
72 | BaseSrcImplExt::parent_query(self, query) |
73 | } |
74 | |
75 | fn event(&self, event: &gst::Event) -> bool { |
76 | self.parent_event(event) |
77 | } |
78 | |
79 | fn caps(&self, filter: Option<&gst::Caps>) -> Option<gst::Caps> { |
80 | self.parent_caps(filter) |
81 | } |
82 | |
83 | fn negotiate(&self) -> Result<(), gst::LoggableError> { |
84 | self.parent_negotiate() |
85 | } |
86 | |
87 | fn set_caps(&self, caps: &gst::Caps) -> Result<(), gst::LoggableError> { |
88 | self.parent_set_caps(caps) |
89 | } |
90 | |
91 | fn fixate(&self, caps: gst::Caps) -> gst::Caps { |
92 | self.parent_fixate(caps) |
93 | } |
94 | |
95 | fn unlock(&self) -> Result<(), gst::ErrorMessage> { |
96 | self.parent_unlock() |
97 | } |
98 | |
99 | fn unlock_stop(&self) -> Result<(), gst::ErrorMessage> { |
100 | self.parent_unlock_stop() |
101 | } |
102 | |
103 | fn decide_allocation( |
104 | &self, |
105 | query: &mut gst::query::Allocation, |
106 | ) -> Result<(), gst::LoggableError> { |
107 | self.parent_decide_allocation(query) |
108 | } |
109 | } |
110 | |
111 | mod sealed { |
112 | pub trait Sealed {} |
113 | impl<T: super::BaseSrcImplExt> Sealed for T {} |
114 | } |
115 | |
116 | pub trait BaseSrcImplExt: sealed::Sealed + ObjectSubclass { |
117 | fn parent_start(&self) -> Result<(), gst::ErrorMessage> { |
118 | unsafe { |
119 | let data = Self::type_data(); |
120 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
121 | (*parent_class) |
122 | .start |
123 | .map(|f| { |
124 | if from_glib(f(self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0)) { |
125 | Ok(()) |
126 | } else { |
127 | Err(gst::error_msg!( |
128 | gst::CoreError::StateChange, |
129 | ["Parent function `start` failed" ] |
130 | )) |
131 | } |
132 | }) |
133 | .unwrap_or(Ok(())) |
134 | } |
135 | } |
136 | |
137 | fn parent_stop(&self) -> Result<(), gst::ErrorMessage> { |
138 | unsafe { |
139 | let data = Self::type_data(); |
140 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
141 | (*parent_class) |
142 | .stop |
143 | .map(|f| { |
144 | if from_glib(f(self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0)) { |
145 | Ok(()) |
146 | } else { |
147 | Err(gst::error_msg!( |
148 | gst::CoreError::StateChange, |
149 | ["Parent function `stop` failed" ] |
150 | )) |
151 | } |
152 | }) |
153 | .unwrap_or(Ok(())) |
154 | } |
155 | } |
156 | |
157 | fn parent_is_seekable(&self) -> bool { |
158 | unsafe { |
159 | let data = Self::type_data(); |
160 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
161 | (*parent_class) |
162 | .is_seekable |
163 | .map(|f| from_glib(f(self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0))) |
164 | .unwrap_or(false) |
165 | } |
166 | } |
167 | |
168 | fn parent_size(&self) -> Option<u64> { |
169 | unsafe { |
170 | let data = Self::type_data(); |
171 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
172 | (*parent_class) |
173 | .get_size |
174 | .map(|f| { |
175 | let mut size = mem::MaybeUninit::uninit(); |
176 | if from_glib(f( |
177 | self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0, |
178 | size.as_mut_ptr(), |
179 | )) { |
180 | Some(size.assume_init()) |
181 | } else { |
182 | None |
183 | } |
184 | }) |
185 | .unwrap_or(None) |
186 | } |
187 | } |
188 | |
189 | fn parent_times( |
190 | &self, |
191 | buffer: &gst::BufferRef, |
192 | ) -> (Option<gst::ClockTime>, Option<gst::ClockTime>) { |
193 | unsafe { |
194 | let data = Self::type_data(); |
195 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
196 | (*parent_class) |
197 | .get_times |
198 | .map(|f| { |
199 | let mut start = mem::MaybeUninit::uninit(); |
200 | let mut stop = mem::MaybeUninit::uninit(); |
201 | f( |
202 | self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0, |
203 | buffer.as_mut_ptr(), |
204 | start.as_mut_ptr(), |
205 | stop.as_mut_ptr(), |
206 | ); |
207 | ( |
208 | from_glib(start.assume_init()), |
209 | from_glib(stop.assume_init()), |
210 | ) |
211 | }) |
212 | .unwrap_or((gst::ClockTime::NONE, gst::ClockTime::NONE)) |
213 | } |
214 | } |
215 | |
216 | fn parent_fill( |
217 | &self, |
218 | offset: u64, |
219 | length: u32, |
220 | buffer: &mut gst::BufferRef, |
221 | ) -> Result<gst::FlowSuccess, gst::FlowError> { |
222 | unsafe { |
223 | let data = Self::type_data(); |
224 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
225 | (*parent_class) |
226 | .fill |
227 | .map(|f| { |
228 | try_from_glib(f( |
229 | self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0, |
230 | offset, |
231 | length, |
232 | buffer.as_mut_ptr(), |
233 | )) |
234 | }) |
235 | .unwrap_or(Err(gst::FlowError::NotSupported)) |
236 | } |
237 | } |
238 | |
239 | fn parent_alloc(&self, offset: u64, length: u32) -> Result<gst::Buffer, gst::FlowError> { |
240 | unsafe { |
241 | let data = Self::type_data(); |
242 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
243 | (*parent_class) |
244 | .alloc |
245 | .map(|f| { |
246 | let mut buffer_ptr: *mut gst::ffi::GstBuffer = ptr::null_mut(); |
247 | |
248 | // FIXME: Wrong signature in -sys bindings |
249 | // https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys/issues/3 |
250 | let buffer_ref = &mut buffer_ptr as *mut _ as *mut gst::ffi::GstBuffer; |
251 | |
252 | gst::FlowSuccess::try_from_glib(f( |
253 | self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0, |
254 | offset, |
255 | length, |
256 | buffer_ref, |
257 | )) |
258 | .map(|_| from_glib_full(buffer_ptr)) |
259 | }) |
260 | .unwrap_or(Err(gst::FlowError::NotSupported)) |
261 | } |
262 | } |
263 | |
264 | fn parent_create( |
265 | &self, |
266 | offset: u64, |
267 | mut buffer: Option<&mut gst::BufferRef>, |
268 | length: u32, |
269 | ) -> Result<CreateSuccess, gst::FlowError> { |
270 | unsafe { |
271 | let data = Self::type_data(); |
272 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
273 | (*parent_class) |
274 | .create |
275 | .map(|f| { |
276 | let instance = self.obj(); |
277 | let instance = instance.unsafe_cast_ref::<BaseSrc>(); |
278 | let orig_buffer_ptr = buffer |
279 | .as_mut() |
280 | .map(|b| b.as_mut_ptr()) |
281 | .unwrap_or(ptr::null_mut()); |
282 | let mut buffer_ptr = orig_buffer_ptr; |
283 | |
284 | // FIXME: Wrong signature in -sys bindings |
285 | // https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys/issues/3 |
286 | let buffer_ref = &mut buffer_ptr as *mut _ as *mut gst::ffi::GstBuffer; |
287 | |
288 | let instance_data = self.instance_data::<InstanceData>(BaseSrc::static_type()).unwrap(); |
289 | |
290 | if let Err(err) = gst::FlowSuccess::try_from_glib( |
291 | f( |
292 | instance.to_glib_none().0, |
293 | offset, |
294 | length, |
295 | buffer_ref, |
296 | ) |
297 | ) { |
298 | *instance_data.pending_buffer_list.borrow_mut() = None; |
299 | return Err(err); |
300 | } |
301 | |
302 | let pending_buffer_list = instance_data.pending_buffer_list.borrow_mut().take(); |
303 | if pending_buffer_list.is_some() && |
304 | (buffer.is_some() || instance.src_pad().mode() == gst::PadMode::Pull) { |
305 | panic!("Buffer lists can only be returned in push mode" ); |
306 | } |
307 | |
308 | if buffer_ptr.is_null() && pending_buffer_list.is_none() { |
309 | gst::error!( |
310 | gst::CAT_RUST, |
311 | obj = instance, |
312 | "No buffer and no buffer list returned" |
313 | ); |
314 | return Err(gst::FlowError::Error); |
315 | } |
316 | |
317 | if !buffer_ptr.is_null() && pending_buffer_list.is_some() { |
318 | gst::error!( |
319 | gst::CAT_RUST, |
320 | obj = instance, |
321 | "Both buffer and buffer list returned" |
322 | ); |
323 | return Err(gst::FlowError::Error); |
324 | } |
325 | |
326 | if let Some(passed_buffer) = buffer { |
327 | if buffer_ptr != orig_buffer_ptr { |
328 | let new_buffer = gst::Buffer::from_glib_full(buffer_ptr); |
329 | |
330 | gst::debug!( |
331 | gst::CAT_PERFORMANCE, |
332 | obj = instance, |
333 | "Returned new buffer from parent create function, copying into passed buffer" |
334 | ); |
335 | |
336 | let mut map = match passed_buffer.map_writable() { |
337 | Ok(map) => map, |
338 | Err(_) => { |
339 | gst::error!( |
340 | gst::CAT_RUST, |
341 | obj = instance, |
342 | "Failed to map passed buffer writable" |
343 | ); |
344 | return Err(gst::FlowError::Error); |
345 | } |
346 | }; |
347 | |
348 | let copied_size = new_buffer.copy_to_slice(0, &mut map); |
349 | drop(map); |
350 | |
351 | if let Err(copied_size) = copied_size { |
352 | passed_buffer.set_size(copied_size); |
353 | } |
354 | |
355 | match new_buffer.copy_into(passed_buffer, gst::BUFFER_COPY_METADATA, ..) { |
356 | Ok(_) => Ok(CreateSuccess::FilledBuffer), |
357 | Err(_) => { |
358 | gst::error!( |
359 | gst::CAT_RUST, |
360 | obj = instance, |
361 | "Failed to copy buffer metadata" |
362 | ); |
363 | |
364 | Err(gst::FlowError::Error) |
365 | } |
366 | } |
367 | } else { |
368 | Ok(CreateSuccess::FilledBuffer) |
369 | } |
370 | } else if let Some(buffer_list) = pending_buffer_list { |
371 | Ok(CreateSuccess::NewBufferList(buffer_list)) |
372 | } else { |
373 | Ok(CreateSuccess::NewBuffer(from_glib_full(buffer_ptr))) |
374 | } |
375 | }) |
376 | .unwrap_or(Err(gst::FlowError::NotSupported)) |
377 | } |
378 | } |
379 | |
380 | fn parent_do_seek(&self, segment: &mut gst::Segment) -> bool { |
381 | unsafe { |
382 | let data = Self::type_data(); |
383 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
384 | (*parent_class) |
385 | .do_seek |
386 | .map(|f| { |
387 | from_glib(f( |
388 | self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0, |
389 | segment.to_glib_none_mut().0, |
390 | )) |
391 | }) |
392 | .unwrap_or(false) |
393 | } |
394 | } |
395 | |
396 | fn parent_query(&self, query: &mut gst::QueryRef) -> bool { |
397 | unsafe { |
398 | let data = Self::type_data(); |
399 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
400 | (*parent_class) |
401 | .query |
402 | .map(|f| { |
403 | from_glib(f( |
404 | self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0, |
405 | query.as_mut_ptr(), |
406 | )) |
407 | }) |
408 | .unwrap_or(false) |
409 | } |
410 | } |
411 | |
412 | fn parent_event(&self, event: &gst::Event) -> bool { |
413 | unsafe { |
414 | let data = Self::type_data(); |
415 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
416 | (*parent_class) |
417 | .event |
418 | .map(|f| { |
419 | from_glib(f( |
420 | self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0, |
421 | event.to_glib_none().0, |
422 | )) |
423 | }) |
424 | .unwrap_or(false) |
425 | } |
426 | } |
427 | |
428 | fn parent_caps(&self, filter: Option<&gst::Caps>) -> Option<gst::Caps> { |
429 | unsafe { |
430 | let data = Self::type_data(); |
431 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
432 | |
433 | (*parent_class) |
434 | .get_caps |
435 | .map(|f| { |
436 | from_glib_full(f( |
437 | self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0, |
438 | filter.to_glib_none().0, |
439 | )) |
440 | }) |
441 | .unwrap_or(None) |
442 | } |
443 | } |
444 | |
445 | fn parent_negotiate(&self) -> Result<(), gst::LoggableError> { |
446 | unsafe { |
447 | let data = Self::type_data(); |
448 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
449 | (*parent_class) |
450 | .negotiate |
451 | .map(|f| { |
452 | gst::result_from_gboolean!( |
453 | f(self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0), |
454 | gst::CAT_RUST, |
455 | "Parent function `negotiate` failed" |
456 | ) |
457 | }) |
458 | .unwrap_or(Ok(())) |
459 | } |
460 | } |
461 | |
462 | fn parent_set_caps(&self, caps: &gst::Caps) -> Result<(), gst::LoggableError> { |
463 | unsafe { |
464 | let data = Self::type_data(); |
465 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
466 | (*parent_class) |
467 | .set_caps |
468 | .map(|f| { |
469 | gst::result_from_gboolean!( |
470 | f( |
471 | self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0, |
472 | caps.to_glib_none().0 |
473 | ), |
474 | gst::CAT_RUST, |
475 | "Parent function `set_caps` failed" |
476 | ) |
477 | }) |
478 | .unwrap_or(Ok(())) |
479 | } |
480 | } |
481 | |
482 | fn parent_fixate(&self, caps: gst::Caps) -> gst::Caps { |
483 | unsafe { |
484 | let data = Self::type_data(); |
485 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
486 | |
487 | match (*parent_class).fixate { |
488 | Some(fixate) => from_glib_full(fixate( |
489 | self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0, |
490 | caps.into_glib_ptr(), |
491 | )), |
492 | None => caps, |
493 | } |
494 | } |
495 | } |
496 | |
497 | fn parent_unlock(&self) -> Result<(), gst::ErrorMessage> { |
498 | unsafe { |
499 | let data = Self::type_data(); |
500 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
501 | (*parent_class) |
502 | .unlock |
503 | .map(|f| { |
504 | if from_glib(f(self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0)) { |
505 | Ok(()) |
506 | } else { |
507 | Err(gst::error_msg!( |
508 | gst::CoreError::Failed, |
509 | ["Parent function `unlock` failed" ] |
510 | )) |
511 | } |
512 | }) |
513 | .unwrap_or(Ok(())) |
514 | } |
515 | } |
516 | |
517 | fn parent_unlock_stop(&self) -> Result<(), gst::ErrorMessage> { |
518 | unsafe { |
519 | let data = Self::type_data(); |
520 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
521 | (*parent_class) |
522 | .unlock_stop |
523 | .map(|f| { |
524 | if from_glib(f(self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0)) { |
525 | Ok(()) |
526 | } else { |
527 | Err(gst::error_msg!( |
528 | gst::CoreError::Failed, |
529 | ["Parent function `unlock_stop` failed" ] |
530 | )) |
531 | } |
532 | }) |
533 | .unwrap_or(Ok(())) |
534 | } |
535 | } |
536 | |
537 | fn parent_decide_allocation( |
538 | &self, |
539 | query: &mut gst::query::Allocation, |
540 | ) -> Result<(), gst::LoggableError> { |
541 | unsafe { |
542 | let data = Self::type_data(); |
543 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
544 | (*parent_class) |
545 | .decide_allocation |
546 | .map(|f| { |
547 | gst::result_from_gboolean!( |
548 | f( |
549 | self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0, |
550 | query.as_mut_ptr(), |
551 | ), |
552 | gst::CAT_RUST, |
553 | "Parent function `decide_allocation` failed" , |
554 | ) |
555 | }) |
556 | .unwrap_or(Ok(())) |
557 | } |
558 | } |
559 | } |
560 | |
561 | impl<T: BaseSrcImpl> BaseSrcImplExt for T {} |
562 | |
563 | unsafe impl<T: BaseSrcImpl> IsSubclassable<T> for BaseSrc { |
564 | fn class_init(klass: &mut glib::Class<Self>) { |
565 | Self::parent_class_init::<T>(klass); |
566 | let klass = klass.as_mut(); |
567 | klass.start = Some(base_src_start::<T>); |
568 | klass.stop = Some(base_src_stop::<T>); |
569 | klass.is_seekable = Some(base_src_is_seekable::<T>); |
570 | klass.get_size = Some(base_src_get_size::<T>); |
571 | klass.get_times = Some(base_src_get_times::<T>); |
572 | klass.fill = Some(base_src_fill::<T>); |
573 | klass.alloc = Some(base_src_alloc::<T>); |
574 | klass.create = Some(base_src_create::<T>); |
575 | klass.do_seek = Some(base_src_do_seek::<T>); |
576 | klass.query = Some(base_src_query::<T>); |
577 | klass.event = Some(base_src_event::<T>); |
578 | klass.get_caps = Some(base_src_get_caps::<T>); |
579 | klass.negotiate = Some(base_src_negotiate::<T>); |
580 | klass.set_caps = Some(base_src_set_caps::<T>); |
581 | klass.fixate = Some(base_src_fixate::<T>); |
582 | klass.unlock = Some(base_src_unlock::<T>); |
583 | klass.unlock_stop = Some(base_src_unlock_stop::<T>); |
584 | klass.decide_allocation = Some(base_src_decide_allocation::<T>); |
585 | } |
586 | |
587 | fn instance_init(instance: &mut glib::subclass::InitializingObject<T>) { |
588 | Self::parent_instance_init(instance); |
589 | |
590 | instance.set_instance_data(BaseSrc::static_type(), InstanceData::default()); |
591 | } |
592 | } |
593 | |
594 | unsafe extern "C" fn base_src_start<T: BaseSrcImpl>( |
595 | ptr: *mut ffi::GstBaseSrc, |
596 | ) -> glib::ffi::gboolean { |
597 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
598 | let imp: &T = instance.imp(); |
599 | |
600 | gstbool::panic_to_error!(imp, false, { |
601 | match imp.start() { |
602 | Ok(()) => true, |
603 | Err(err) => { |
604 | imp.post_error_message(err); |
605 | false |
606 | } |
607 | } |
608 | }) |
609 | .into_glib() |
610 | } |
611 | |
612 | unsafe extern "C" fn base_src_stop<T: BaseSrcImpl>( |
613 | ptr: *mut ffi::GstBaseSrc, |
614 | ) -> glib::ffi::gboolean { |
615 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
616 | let imp: &T = instance.imp(); |
617 | |
618 | gstbool::panic_to_error!(imp, false, { |
619 | match imp.stop() { |
620 | Ok(()) => true, |
621 | Err(err) => { |
622 | imp.post_error_message(err); |
623 | false |
624 | } |
625 | } |
626 | }) |
627 | .into_glib() |
628 | } |
629 | |
630 | unsafe extern "C" fn base_src_is_seekable<T: BaseSrcImpl>( |
631 | ptr: *mut ffi::GstBaseSrc, |
632 | ) -> glib::ffi::gboolean { |
633 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
634 | let imp: &T = instance.imp(); |
635 | |
636 | gst::panic_to_error!(imp, false, { imp.is_seekable() }).into_glib() |
637 | } |
638 | |
639 | unsafe extern "C" fn base_src_get_size<T: BaseSrcImpl>( |
640 | ptr: *mut ffi::GstBaseSrc, |
641 | size: *mut u64, |
642 | ) -> glib::ffi::gboolean { |
643 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
644 | let imp: &T = instance.imp(); |
645 | |
646 | gstbool::panic_to_error!(imp, false, { |
647 | match imp.size() { |
648 | Some(s) => { |
649 | *size = s; |
650 | true |
651 | } |
652 | None => false, |
653 | } |
654 | }) |
655 | .into_glib() |
656 | } |
657 | |
658 | unsafe extern "C" fn base_src_get_times<T: BaseSrcImpl>( |
659 | ptr: *mut ffi::GstBaseSrc, |
660 | buffer: *mut gst::ffi::GstBuffer, |
661 | start: *mut gst::ffi::GstClockTime, |
662 | stop: *mut gst::ffi::GstClockTime, |
663 | ) { |
664 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
665 | let imp: &T = instance.imp(); |
666 | let buffer: &BufferRef = gst::BufferRef::from_ptr(buffer); |
667 | |
668 | *start = gst::ffi::GST_CLOCK_TIME_NONE; |
669 | *stop = gst::ffi::GST_CLOCK_TIME_NONE; |
670 | |
671 | gst::panic_to_error!(imp, (), { |
672 | let (start_, stop_) = imp.times(buffer); |
673 | *start = start_.into_glib(); |
674 | *stop = stop_.into_glib(); |
675 | }); |
676 | } |
677 | |
678 | unsafe extern "C" fn base_src_fill<T: BaseSrcImpl>( |
679 | ptr: *mut ffi::GstBaseSrc, |
680 | offset: u64, |
681 | length: u32, |
682 | buffer: *mut gst::ffi::GstBuffer, |
683 | ) -> gst::ffi::GstFlowReturn { |
684 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
685 | let imp: &T = instance.imp(); |
686 | let buffer: &mut BufferRef = gst::BufferRef::from_mut_ptr(buffer); |
687 | |
688 | gstFlowReturn::panic_to_error!(imp, gst::FlowReturn::Error, { |
689 | imp.fill(offset, length, buffer).into() |
690 | }) |
691 | .into_glib() |
692 | } |
693 | |
694 | unsafe extern "C" fn base_src_alloc<T: BaseSrcImpl>( |
695 | ptr: *mut ffi::GstBaseSrc, |
696 | offset: u64, |
697 | length: u32, |
698 | buffer_ptr: *mut gst::ffi::GstBuffer, |
699 | ) -> gst::ffi::GstFlowReturn { |
700 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
701 | let imp: &T = instance.imp(); |
702 | // FIXME: Wrong signature in -sys bindings |
703 | // https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys/issues/3 |
704 | let buffer_ptr: *mut *mut GstBuffer = buffer_ptr as *mut *mut gst::ffi::GstBuffer; |
705 | |
706 | gstFlowReturn::panic_to_error!(imp, gst::FlowReturn::Error, { |
707 | match imp.alloc(offset, length) { |
708 | Ok(buffer) => { |
709 | *buffer_ptr = buffer.into_glib_ptr(); |
710 | gst::FlowReturn::Ok |
711 | } |
712 | Err(err) => gst::FlowReturn::from(err), |
713 | } |
714 | }) |
715 | .into_glib() |
716 | } |
717 | |
718 | #[allow (clippy::needless_option_as_deref)] |
719 | unsafe extern "C" fn base_src_create<T: BaseSrcImpl>( |
720 | ptr: *mut ffi::GstBaseSrc, |
721 | offset: u64, |
722 | length: u32, |
723 | buffer_ptr: *mut gst::ffi::GstBuffer, |
724 | ) -> gst::ffi::GstFlowReturn { |
725 | let instance = &*(ptr as *mut T::Instance); |
726 | let imp = instance.imp(); |
727 | let instance = imp.obj(); |
728 | let instance = instance.unsafe_cast_ref::<BaseSrc>(); |
729 | // FIXME: Wrong signature in -sys bindings |
730 | // https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys/issues/3 |
731 | let buffer_ptr = buffer_ptr as *mut *mut gst::ffi::GstBuffer; |
732 | |
733 | let mut buffer = if (*buffer_ptr).is_null() { |
734 | None |
735 | } else { |
736 | Some(gst::BufferRef::from_mut_ptr(*buffer_ptr)) |
737 | }; |
738 | |
739 | let instance_data = imp |
740 | .instance_data::<InstanceData>(BaseSrc::static_type()) |
741 | .unwrap(); |
742 | |
743 | // If there is a pending buffer list at this point then unset it. |
744 | if instance.type_() == T::Type::static_type() { |
745 | *instance_data.pending_buffer_list.borrow_mut() = None; |
746 | } |
747 | |
748 | let res = gst::panic_to_error!(imp, gst::FlowReturn::Error, { |
749 | match imp.create(offset, buffer.as_deref_mut(), length) { |
750 | Ok(CreateSuccess::NewBuffer(new_buffer)) => { |
751 | if let Some(passed_buffer) = buffer { |
752 | if passed_buffer.as_ptr() != new_buffer.as_ptr() { |
753 | gst::debug!( |
754 | gst::CAT_PERFORMANCE, |
755 | obj = instance, |
756 | "Returned new buffer from create function, copying into passed buffer" |
757 | ); |
758 | |
759 | let mut map = match passed_buffer.map_writable() { |
760 | Ok(map) => map, |
761 | Err(_) => { |
762 | gst::error!( |
763 | gst::CAT_RUST, |
764 | obj = instance, |
765 | "Failed to map passed buffer writable" |
766 | ); |
767 | return gst::FlowReturn::Error; |
768 | } |
769 | }; |
770 | |
771 | let copied_size = new_buffer.copy_to_slice(0, &mut map); |
772 | drop(map); |
773 | |
774 | if let Err(copied_size) = copied_size { |
775 | passed_buffer.set_size(copied_size); |
776 | } |
777 | |
778 | match new_buffer.copy_into(passed_buffer, gst::BUFFER_COPY_METADATA, ..) { |
779 | Ok(_) => gst::FlowReturn::Ok, |
780 | Err(_) => { |
781 | gst::error!( |
782 | gst::CAT_RUST, |
783 | obj = instance, |
784 | "Failed to copy buffer metadata" |
785 | ); |
786 | |
787 | gst::FlowReturn::Error |
788 | } |
789 | } |
790 | } else { |
791 | gst::FlowReturn::Ok |
792 | } |
793 | } else { |
794 | *buffer_ptr = new_buffer.into_glib_ptr(); |
795 | gst::FlowReturn::Ok |
796 | } |
797 | } |
798 | Ok(CreateSuccess::NewBufferList(new_buffer_list)) => { |
799 | if buffer.is_some() || instance.src_pad().mode() == gst::PadMode::Pull { |
800 | panic!("Buffer lists can only be returned in push mode" ); |
801 | } |
802 | |
803 | *buffer_ptr = ptr::null_mut(); |
804 | |
805 | // If this is the final type then submit the buffer list. This can only be done |
806 | // once so can only really be done here. |
807 | // FIXME: This won't work if a non-Rust subclass of a Rust subclass is created. |
808 | if instance.type_() == T::Type::static_type() { |
809 | ffi::gst_base_src_submit_buffer_list( |
810 | instance.to_glib_none().0, |
811 | new_buffer_list.into_glib_ptr(), |
812 | ); |
813 | } else { |
814 | *instance_data.pending_buffer_list.borrow_mut() = Some(new_buffer_list); |
815 | } |
816 | |
817 | gst::FlowReturn::Ok |
818 | } |
819 | Ok(CreateSuccess::FilledBuffer) => gst::FlowReturn::Ok, |
820 | Err(err) => gst::FlowReturn::from(err), |
821 | } |
822 | }) |
823 | .into_glib(); |
824 | |
825 | // If there is a pending buffer list at this point then unset it. |
826 | if instance.type_() == T::Type::static_type() { |
827 | *instance_data.pending_buffer_list.borrow_mut() = None; |
828 | } |
829 | |
830 | res |
831 | } |
832 | |
833 | unsafe extern "C" fn base_src_do_seek<T: BaseSrcImpl>( |
834 | ptr: *mut ffi::GstBaseSrc, |
835 | segment: *mut gst::ffi::GstSegment, |
836 | ) -> glib::ffi::gboolean { |
837 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
838 | let imp: &T = instance.imp(); |
839 | |
840 | gstbool::panic_to_error!(imp, false, { |
841 | let mut s = from_glib_none(segment); |
842 | let res = imp.do_seek(&mut s); |
843 | ptr::write(segment, *(s.to_glib_none().0)); |
844 | |
845 | res |
846 | }) |
847 | .into_glib() |
848 | } |
849 | |
850 | unsafe extern "C" fn base_src_query<T: BaseSrcImpl>( |
851 | ptr: *mut ffi::GstBaseSrc, |
852 | query_ptr: *mut gst::ffi::GstQuery, |
853 | ) -> glib::ffi::gboolean { |
854 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
855 | let imp: &T = instance.imp(); |
856 | let query: &mut QueryRef = gst::QueryRef::from_mut_ptr(query_ptr); |
857 | |
858 | gst::panic_to_error!(imp, false, { BaseSrcImpl::query(imp, query) }).into_glib() |
859 | } |
860 | |
861 | unsafe extern "C" fn base_src_event<T: BaseSrcImpl>( |
862 | ptr: *mut ffi::GstBaseSrc, |
863 | event_ptr: *mut gst::ffi::GstEvent, |
864 | ) -> glib::ffi::gboolean { |
865 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
866 | let imp: &T = instance.imp(); |
867 | |
868 | gst::panic_to_error!(imp, false, { imp.event(&from_glib_borrow(event_ptr)) }).into_glib() |
869 | } |
870 | |
871 | unsafe extern "C" fn base_src_get_caps<T: BaseSrcImpl>( |
872 | ptr: *mut ffi::GstBaseSrc, |
873 | filter: *mut gst::ffi::GstCaps, |
874 | ) -> *mut gst::ffi::GstCaps { |
875 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
876 | let imp: &T = instance.imp(); |
877 | let filter: Borrowed = Option::<gst::Caps>::from_glib_borrow(_ptr:filter); |
878 | |
879 | gst::panic_to_error!(imp, None, { imp.caps(filter.as_ref().as_ref()) }) |
880 | .map(|caps| caps.into_glib_ptr()) |
881 | .unwrap_or(default:ptr::null_mut()) |
882 | } |
883 | |
884 | unsafe extern "C" fn base_src_negotiate<T: BaseSrcImpl>( |
885 | ptr: *mut ffi::GstBaseSrc, |
886 | ) -> glib::ffi::gboolean { |
887 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
888 | let imp: &T = instance.imp(); |
889 | |
890 | gstbool::panic_to_error!(imp, false, { |
891 | match imp.negotiate() { |
892 | Ok(()) => true, |
893 | Err(err) => { |
894 | err.log_with_imp(imp); |
895 | false |
896 | } |
897 | } |
898 | }) |
899 | .into_glib() |
900 | } |
901 | |
902 | unsafe extern "C" fn base_src_set_caps<T: BaseSrcImpl>( |
903 | ptr: *mut ffi::GstBaseSrc, |
904 | caps: *mut gst::ffi::GstCaps, |
905 | ) -> glib::ffi::gboolean { |
906 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
907 | let imp: &T = instance.imp(); |
908 | let caps: Borrowed = from_glib_borrow(ptr:caps); |
909 | |
910 | gstbool::panic_to_error!(imp, false, { |
911 | match imp.set_caps(&caps) { |
912 | Ok(()) => true, |
913 | Err(err) => { |
914 | err.log_with_imp(imp); |
915 | false |
916 | } |
917 | } |
918 | }) |
919 | .into_glib() |
920 | } |
921 | |
922 | unsafe extern "C" fn base_src_fixate<T: BaseSrcImpl>( |
923 | ptr: *mut ffi::GstBaseSrc, |
924 | caps: *mut gst::ffi::GstCaps, |
925 | ) -> *mut gst::ffi::GstCaps { |
926 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
927 | let imp: &T = instance.imp(); |
928 | let caps: Caps = from_glib_full(ptr:caps); |
929 | |
930 | gst::panic_to_error!(imp, gst::Caps::new_empty(), { imp.fixate(caps) }).into_glib_ptr() |
931 | } |
932 | |
933 | unsafe extern "C" fn base_src_unlock<T: BaseSrcImpl>( |
934 | ptr: *mut ffi::GstBaseSrc, |
935 | ) -> glib::ffi::gboolean { |
936 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
937 | let imp: &T = instance.imp(); |
938 | |
939 | gstbool::panic_to_error!(imp, false, { |
940 | match imp.unlock() { |
941 | Ok(()) => true, |
942 | Err(err) => { |
943 | imp.post_error_message(err); |
944 | false |
945 | } |
946 | } |
947 | }) |
948 | .into_glib() |
949 | } |
950 | |
951 | unsafe extern "C" fn base_src_unlock_stop<T: BaseSrcImpl>( |
952 | ptr: *mut ffi::GstBaseSrc, |
953 | ) -> glib::ffi::gboolean { |
954 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
955 | let imp: &T = instance.imp(); |
956 | |
957 | gstbool::panic_to_error!(imp, false, { |
958 | match imp.unlock_stop() { |
959 | Ok(()) => true, |
960 | Err(err) => { |
961 | imp.post_error_message(err); |
962 | false |
963 | } |
964 | } |
965 | }) |
966 | .into_glib() |
967 | } |
968 | |
969 | unsafe extern "C" fn base_src_decide_allocation<T: BaseSrcImpl>( |
970 | ptr: *mut ffi::GstBaseSrc, |
971 | query: *mut gst::ffi::GstQuery, |
972 | ) -> glib::ffi::gboolean { |
973 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
974 | let imp: &T = instance.imp(); |
975 | let query: &mut Allocation = match gst::QueryRef::from_mut_ptr(query).view_mut() { |
976 | gst::QueryViewMut::Allocation(allocation: &mut Allocation) => allocation, |
977 | _ => unreachable!(), |
978 | }; |
979 | |
980 | gstbool::panic_to_error!(imp, false, { |
981 | match imp.decide_allocation(query) { |
982 | Ok(()) => true, |
983 | Err(err) => { |
984 | err.log_with_imp(imp); |
985 | false |
986 | } |
987 | } |
988 | }) |
989 | .into_glib() |
990 | } |
991 | |