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