gstreamer_base/subclass/
push_src.rs
1use 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> {
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
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 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 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 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 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 *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 *instance_data.pending_buffer_list.borrow_mut() = Some(new_buffer_list);
319
320 gst::FlowReturn::Ok
321 }
322 Ok(CreateSuccess::FilledBuffer) => {
323 *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}