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