gstreamer_base/subclass/
push_src.rs1use 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 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 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 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 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 *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 *instance_data.pending_buffer_list.borrow_mut() = Some(new_buffer_list);
312
313 gst::FlowReturn::Ok
314 }
315 Ok(CreateSuccess::FilledBuffer) => {
316 *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}