gstreamer_base/subclass/
push_src.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::ptr;
4
5use glib::{prelude::*, subclass::prelude::*, translate::*};
6use gst::{prelude::*, subclass::prelude::*};
7
8use super::base_src::{BaseSrcImpl, CreateSuccess};
9use crate::{ffi, prelude::*, PushSrc};
10
11pub trait PushSrcImpl: BaseSrcImpl + ObjectSubclass<Type: IsA<PushSrc>> {
12    /// Ask the subclass to fill the buffer with data.
13    fn fill(&self, buffer: &mut gst::BufferRef) -> Result<gst::FlowSuccess, gst::FlowError> {
14        PushSrcImplExt::parent_fill(self, buffer)
15    }
16
17    /// Allocate memory for a buffer.
18    ///
19    /// # Returns
20    ///
21    fn alloc(&self) -> Result<gst::Buffer, gst::FlowError> {
22        PushSrcImplExt::parent_alloc(self)
23    }
24
25    /// Ask the subclass to create a buffer, the default implementation will call alloc if
26    /// no allocated `buf` is provided and then call fill.
27    fn create(&self, buffer: Option<&mut gst::BufferRef>) -> Result<CreateSuccess, gst::FlowError> {
28        PushSrcImplExt::parent_create(self, buffer)
29    }
30}
31
32pub trait PushSrcImplExt: PushSrcImpl {
33    fn parent_fill(&self, buffer: &mut gst::BufferRef) -> Result<gst::FlowSuccess, gst::FlowError> {
34        unsafe {
35            let data = Self::type_data();
36            let parent_class = data.as_ref().parent_class() as *mut ffi::GstPushSrcClass;
37            (*parent_class)
38                .fill
39                .map(|f| {
40                    try_from_glib(f(
41                        self.obj().unsafe_cast_ref::<PushSrc>().to_glib_none().0,
42                        buffer.as_mut_ptr(),
43                    ))
44                })
45                .unwrap_or(Err(gst::FlowError::NotSupported))
46        }
47    }
48
49    fn parent_alloc(&self) -> Result<gst::Buffer, gst::FlowError> {
50        unsafe {
51            let data = Self::type_data();
52            let parent_class = data.as_ref().parent_class() as *mut ffi::GstPushSrcClass;
53            (*parent_class)
54                .alloc
55                .map(|f| {
56                    let mut buffer_ptr: *mut gst::ffi::GstBuffer = ptr::null_mut();
57
58                    // FIXME: Wrong signature in -sys bindings
59                    // https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys/issues/3
60                    let buffer_ref = &mut buffer_ptr as *mut _ as *mut gst::ffi::GstBuffer;
61
62                    gst::FlowSuccess::try_from_glib(f(
63                        self.obj().unsafe_cast_ref::<PushSrc>().to_glib_none().0,
64                        buffer_ref,
65                    ))
66                    .map(|_| from_glib_full(buffer_ref))
67                })
68                .unwrap_or(Err(gst::FlowError::NotSupported))
69        }
70    }
71
72    fn parent_create(
73        &self,
74        mut buffer: Option<&mut gst::BufferRef>,
75    ) -> Result<CreateSuccess, gst::FlowError> {
76        unsafe {
77            let data = Self::type_data();
78            let parent_class = data.as_ref().parent_class() as *mut ffi::GstPushSrcClass;
79            (*parent_class)
80                .create
81                .map(|f| {
82                    let instance = self.obj();
83                    let instance = instance.unsafe_cast_ref::<PushSrc>();
84                    let orig_buffer_ptr = buffer
85                        .as_mut()
86                        .map(|b| b.as_mut_ptr())
87                        .unwrap_or(ptr::null_mut());
88                    let mut buffer_ptr = orig_buffer_ptr;
89
90                    // FIXME: Wrong signature in -sys bindings
91                    // https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys/issues/3
92                    let buffer_ref = &mut buffer_ptr as *mut _ as *mut gst::ffi::GstBuffer;
93                    let instance_data = self.instance_data::<super::base_src::InstanceData>(crate::BaseSrc::static_type()).unwrap();
94
95                    if let Err(err) = gst::FlowSuccess::try_from_glib(
96                        f(
97                            instance.to_glib_none().0,
98                            buffer_ref,
99                        )
100                    ) {
101                        *instance_data.pending_buffer_list.borrow_mut() = None;
102                        return Err(err);
103                    }
104
105                    let pending_buffer_list = instance_data.pending_buffer_list.borrow_mut().take();
106                    if pending_buffer_list.is_some() &&
107                        (buffer.is_some() || instance.src_pad().mode() == gst::PadMode::Pull) {
108                        panic!("Buffer lists can only be returned in push mode");
109                    }
110
111                    let pending_buffer_list = instance_data.pending_buffer_list.borrow_mut().take();
112                    if buffer_ptr.is_null() && pending_buffer_list.is_none() {
113                        gst::error!(
114                            gst::CAT_RUST,
115                            obj = instance,
116                            "No buffer and no buffer list returned"
117                        );
118                        return Err(gst::FlowError::Error);
119                    }
120
121                    if !buffer_ptr.is_null() && pending_buffer_list.is_some() {
122                        gst::error!(
123                            gst::CAT_RUST,
124                            obj = instance,
125                            "Both buffer and buffer list returned"
126                        );
127                        return Err(gst::FlowError::Error);
128                    }
129
130                    if let Some(passed_buffer) = buffer {
131                        if buffer_ptr != orig_buffer_ptr {
132                            let new_buffer = gst::Buffer::from_glib_full(buffer_ptr);
133
134                            gst::debug!(
135                                gst::CAT_PERFORMANCE,
136                                obj = instance,
137                                "Returned new buffer from parent create function, copying into passed buffer"
138                            );
139
140                            let mut map = match passed_buffer.map_writable() {
141                                Ok(map) => map,
142                                Err(_) => {
143                                    gst::error!(
144                                        gst::CAT_RUST,
145                                        obj = instance,
146                                        "Failed to map passed buffer writable"
147                                    );
148                                    return Err(gst::FlowError::Error);
149                                }
150                            };
151
152                            let copied_size = new_buffer.copy_to_slice(0, &mut map);
153                            drop(map);
154
155                            if let Err(copied_size) = copied_size {
156                                passed_buffer.set_size(copied_size);
157                            }
158
159                            match new_buffer.copy_into(passed_buffer, gst::BUFFER_COPY_METADATA, ..) {
160                                Ok(_) => Ok(CreateSuccess::FilledBuffer),
161                                Err(_) => {
162                                    gst::error!(
163                                        gst::CAT_RUST,
164                                        obj = instance,
165                                        "Failed to copy buffer metadata"
166                                    );
167
168                                    Err(gst::FlowError::Error)
169                                }
170                            }
171                        } else {
172                            Ok(CreateSuccess::FilledBuffer)
173                        }
174                    } else if let Some(buffer_list) = pending_buffer_list {
175                        Ok(CreateSuccess::NewBufferList(buffer_list))
176                    } else {
177                        Ok(CreateSuccess::NewBuffer(from_glib_full(buffer_ptr)))
178                    }
179                })
180                .unwrap_or(Err(gst::FlowError::NotSupported))
181        }
182    }
183}
184
185impl<T: PushSrcImpl> PushSrcImplExt for T {}
186
187unsafe impl<T: PushSrcImpl> IsSubclassable<T> for PushSrc {
188    fn class_init(klass: &mut glib::Class<Self>) {
189        Self::parent_class_init::<T>(klass);
190        let klass = klass.as_mut();
191        klass.fill = Some(push_src_fill::<T>);
192        klass.alloc = Some(push_src_alloc::<T>);
193        klass.create = Some(push_src_create::<T>);
194    }
195}
196
197unsafe extern "C" fn push_src_fill<T: PushSrcImpl>(
198    ptr: *mut ffi::GstPushSrc,
199    buffer: *mut gst::ffi::GstBuffer,
200) -> gst::ffi::GstFlowReturn {
201    let instance = &*(ptr as *mut T::Instance);
202    let imp = instance.imp();
203    let buffer = gst::BufferRef::from_mut_ptr(buffer);
204
205    gst::panic_to_error!(imp, gst::FlowReturn::Error, {
206        PushSrcImpl::fill(imp, buffer).into()
207    })
208    .into_glib()
209}
210
211unsafe extern "C" fn push_src_alloc<T: PushSrcImpl>(
212    ptr: *mut ffi::GstPushSrc,
213    buffer_ptr: *mut gst::ffi::GstBuffer,
214) -> gst::ffi::GstFlowReturn {
215    let instance = &*(ptr as *mut T::Instance);
216    let imp = instance.imp();
217    // FIXME: Wrong signature in -sys bindings
218    // https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys/issues/3
219    let buffer_ptr = buffer_ptr as *mut *mut gst::ffi::GstBuffer;
220
221    gst::panic_to_error!(imp, gst::FlowReturn::Error, {
222        match PushSrcImpl::alloc(imp) {
223            Ok(buffer) => {
224                *buffer_ptr = buffer.into_glib_ptr();
225                gst::FlowReturn::Ok
226            }
227            Err(err) => gst::FlowReturn::from(err),
228        }
229    })
230    .into_glib()
231}
232
233#[allow(clippy::needless_option_as_deref)]
234unsafe extern "C" fn push_src_create<T: PushSrcImpl>(
235    ptr: *mut ffi::GstPushSrc,
236    buffer_ptr: *mut gst::ffi::GstBuffer,
237) -> gst::ffi::GstFlowReturn {
238    let instance = &*(ptr as *mut T::Instance);
239    let imp = instance.imp();
240    // FIXME: Wrong signature in -sys bindings
241    // https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys/issues/3
242    let buffer_ptr = buffer_ptr as *mut *mut gst::ffi::GstBuffer;
243
244    let mut buffer = if (*buffer_ptr).is_null() {
245        None
246    } else {
247        Some(gst::BufferRef::from_mut_ptr(*buffer_ptr))
248    };
249
250    let instance_data = imp
251        .instance_data::<super::base_src::InstanceData>(crate::BaseSrc::static_type())
252        .unwrap();
253
254    gst::panic_to_error!(imp, gst::FlowReturn::Error, {
255        match PushSrcImpl::create(imp, buffer.as_deref_mut()) {
256            Ok(CreateSuccess::NewBuffer(new_buffer)) => {
257                // Clear any pending buffer list
258                *instance_data.pending_buffer_list.borrow_mut() = None;
259
260                if let Some(passed_buffer) = buffer {
261                    if passed_buffer.as_ptr() != new_buffer.as_ptr() {
262                        gst::debug!(
263                            gst::CAT_PERFORMANCE,
264                            imp = imp,
265                            "Returned new buffer from create function, copying into passed buffer"
266                        );
267
268                        let mut map = match passed_buffer.map_writable() {
269                            Ok(map) => map,
270                            Err(_) => {
271                                gst::error!(
272                                    gst::CAT_RUST,
273                                    imp = imp,
274                                    "Failed to map passed buffer writable"
275                                );
276                                return gst::FlowReturn::Error;
277                            }
278                        };
279
280                        let copied_size = new_buffer.copy_to_slice(0, &mut map);
281                        drop(map);
282
283                        if let Err(copied_size) = copied_size {
284                            passed_buffer.set_size(copied_size);
285                        }
286
287                        match new_buffer.copy_into(passed_buffer, gst::BUFFER_COPY_METADATA, ..) {
288                            Ok(_) => gst::FlowReturn::Ok,
289                            Err(_) => {
290                                gst::error!(
291                                    gst::CAT_RUST,
292                                    imp = imp,
293                                    "Failed to copy buffer metadata"
294                                );
295
296                                gst::FlowReturn::Error
297                            }
298                        }
299                    } else {
300                        gst::FlowReturn::Ok
301                    }
302                } else {
303                    *buffer_ptr = new_buffer.into_glib_ptr();
304                    gst::FlowReturn::Ok
305                }
306            }
307            Ok(CreateSuccess::NewBufferList(new_buffer_list)) => {
308                if buffer.is_some()
309                    || imp.obj().unsafe_cast_ref::<PushSrc>().src_pad().mode() == gst::PadMode::Pull
310                {
311                    panic!("Buffer lists can only be returned in push mode");
312                }
313
314                *buffer_ptr = ptr::null_mut();
315
316                // Store it in the instance data so that in the end base_src_create() can
317                // submit it.
318                *instance_data.pending_buffer_list.borrow_mut() = Some(new_buffer_list);
319
320                gst::FlowReturn::Ok
321            }
322            Ok(CreateSuccess::FilledBuffer) => {
323                // Clear any pending buffer list
324                *instance_data.pending_buffer_list.borrow_mut() = None;
325
326                gst::FlowReturn::Ok
327            }
328            Err(err) => gst::FlowReturn::from(err),
329        }
330    })
331    .into_glib()
332}