Replace AppSrcCallbacks/AppSinkCallbacks with a builder so that no empty closures have to be provided for unused callbacks

This commit is contained in:
Sebastian Dröge 2017-12-10 15:18:54 +02:00
parent dbe8eb9bd9
commit 49a6eb6a1f
4 changed files with 184 additions and 93 deletions

View file

@ -60,67 +60,64 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
],
));
appsink.set_callbacks(gst_app::AppSinkCallbacks::new(
/* eos */
|_| {},
/* new_preroll */
|_| gst::FlowReturn::Ok,
/* new_samples */
|appsink| {
let sample = match appsink.pull_sample() {
None => return gst::FlowReturn::Eos,
Some(sample) => sample,
};
appsink.set_callbacks(
gst_app::AppSinkCallbacksBuilder::new()
.new_sample(|appsink| {
let sample = match appsink.pull_sample() {
None => return gst::FlowReturn::Eos,
Some(sample) => sample,
};
let buffer = if let Some(buffer) = sample.get_buffer() {
buffer
} else {
gst_element_error!(
appsink,
gst::ResourceError::Failed,
("Failed to get buffer from appsink")
);
let buffer = if let Some(buffer) = sample.get_buffer() {
buffer
} else {
gst_element_error!(
appsink,
gst::ResourceError::Failed,
("Failed to get buffer from appsink")
);
return gst::FlowReturn::Error;
};
return gst::FlowReturn::Error;
};
let map = if let Some(map) = buffer.map_readable() {
map
} else {
gst_element_error!(
appsink,
gst::ResourceError::Failed,
("Failed to map buffer readable")
);
let map = if let Some(map) = buffer.map_readable() {
map
} else {
gst_element_error!(
appsink,
gst::ResourceError::Failed,
("Failed to map buffer readable")
);
return gst::FlowReturn::Error;
};
return gst::FlowReturn::Error;
};
let samples = if let Ok(samples) = map.as_slice().as_slice_of::<i16>() {
samples
} else {
gst_element_error!(
appsink,
gst::ResourceError::Failed,
("Failed to interprete buffer as S16 PCM")
);
let samples = if let Ok(samples) = map.as_slice().as_slice_of::<i16>() {
samples
} else {
gst_element_error!(
appsink,
gst::ResourceError::Failed,
("Failed to interprete buffer as S16 PCM")
);
return gst::FlowReturn::Error;
};
return gst::FlowReturn::Error;
};
let sum: f64 = samples
.iter()
.map(|sample| {
let f = f64::from(*sample) / f64::from(i16::MAX);
f * f
})
.sum();
let rms = (sum / (samples.len() as f64)).sqrt();
println!("rms: {}", rms);
let sum: f64 = samples
.iter()
.map(|sample| {
let f = f64::from(*sample) / f64::from(i16::MAX);
f * f
})
.sum();
let rms = (sum / (samples.len() as f64)).sqrt();
println!("rms: {}", rms);
gst::FlowReturn::Ok
},
));
gst::FlowReturn::Ok
})
.build(),
);
Ok(pipeline)
}

View file

@ -16,29 +16,76 @@ use glib_ffi::gpointer;
use std::ptr;
pub struct AppSinkCallbacks {
eos: Box<Fn(&AppSink) + Send + Sync + 'static>,
new_preroll: Box<Fn(&AppSink) -> gst::FlowReturn + Send + Sync + 'static>,
new_sample: Box<Fn(&AppSink) -> gst::FlowReturn + Send + Sync + 'static>,
eos: Option<Box<Fn(&AppSink) + Send + Sync + 'static>>,
new_preroll: Option<Box<Fn(&AppSink) -> gst::FlowReturn + Send + Sync + 'static>>,
new_sample: Option<Box<Fn(&AppSink) -> gst::FlowReturn + Send + Sync + 'static>>,
callbacks: ffi::GstAppSinkCallbacks,
}
impl AppSinkCallbacks {
pub fn new<F, G, H>(eos: F, new_preroll: G, new_sample: H) -> Self
where
F: Fn(&AppSink) + Send + Sync + 'static,
G: Fn(&AppSink) -> gst::FlowReturn + Send + Sync + 'static,
H: Fn(&AppSink) -> gst::FlowReturn + Send + Sync + 'static,
{
pub struct AppSinkCallbacksBuilder {
eos: Option<Box<Fn(&AppSink) + Send + Sync + 'static>>,
new_preroll: Option<Box<Fn(&AppSink) -> gst::FlowReturn + Send + Sync + 'static>>,
new_sample: Option<Box<Fn(&AppSink) -> gst::FlowReturn + Send + Sync + 'static>>,
}
impl AppSinkCallbacksBuilder {
pub fn new() -> Self {
skip_assert_initialized!();
AppSinkCallbacksBuilder {
eos: None,
new_preroll: None,
new_sample: None,
}
}
pub fn eos<F: Fn(&AppSink) + Send + Sync + 'static>(self, eos: F) -> Self {
Self {
eos: Some(Box::new(eos)),
..self
}
}
pub fn new_preroll<F: Fn(&AppSink) -> gst::FlowReturn + Send + Sync + 'static>(
self,
new_preroll: F,
) -> Self {
Self {
new_preroll: Some(Box::new(new_preroll)),
..self
}
}
pub fn new_sample<F: Fn(&AppSink) -> gst::FlowReturn + Send + Sync + 'static>(
self,
new_sample: F,
) -> Self {
Self {
new_sample: Some(Box::new(new_sample)),
..self
}
}
pub fn build(self) -> AppSinkCallbacks {
let have_eos = self.eos.is_some();
let have_new_preroll = self.new_preroll.is_some();
let have_new_sample = self.new_sample.is_some();
AppSinkCallbacks {
eos: Box::new(eos),
new_preroll: Box::new(new_preroll),
new_sample: Box::new(new_sample),
eos: self.eos,
new_preroll: self.new_preroll,
new_sample: self.new_sample,
callbacks: ffi::GstAppSinkCallbacks {
eos: Some(trampoline_eos),
new_preroll: Some(trampoline_new_preroll),
new_sample: Some(trampoline_new_sample),
eos: if have_eos { Some(trampoline_eos) } else { None },
new_preroll: if have_new_preroll {
Some(trampoline_new_preroll)
} else {
None
},
new_sample: if have_new_sample {
Some(trampoline_new_sample)
} else {
None
},
_gst_reserved: [
ptr::null_mut(),
ptr::null_mut(),
@ -54,7 +101,10 @@ unsafe extern "C" fn trampoline_eos(appsink: *mut ffi::GstAppSink, callbacks: gp
let _guard = CallbackGuard::new();
let callbacks = &*(callbacks as *const AppSinkCallbacks);
(callbacks.eos)(&from_glib_borrow(appsink));
callbacks
.eos
.as_ref()
.map(|f| f(&from_glib_borrow(appsink)));
}
unsafe extern "C" fn trampoline_new_preroll(
@ -64,7 +114,12 @@ unsafe extern "C" fn trampoline_new_preroll(
let _guard = CallbackGuard::new();
let callbacks = &*(callbacks as *const AppSinkCallbacks);
(callbacks.new_preroll)(&from_glib_borrow(appsink)).to_glib()
callbacks
.new_preroll
.as_ref()
.map(|f| f(&from_glib_borrow(appsink)))
.unwrap_or(gst::FlowReturn::Error)
.to_glib()
}
unsafe extern "C" fn trampoline_new_sample(
@ -74,7 +129,12 @@ unsafe extern "C" fn trampoline_new_sample(
let _guard = CallbackGuard::new();
let callbacks = &*(callbacks as *const AppSinkCallbacks);
(callbacks.new_sample)(&from_glib_borrow(appsink)).to_glib()
callbacks
.new_sample
.as_ref()
.map(|f| f(&from_glib_borrow(appsink)))
.unwrap_or(gst::FlowReturn::Error)
.to_glib()
}
unsafe extern "C" fn destroy_callbacks(ptr: gpointer) {

View file

@ -15,29 +15,63 @@ use glib_ffi::{gboolean, gpointer};
use std::ptr;
pub struct AppSrcCallbacks {
need_data: Box<Fn(&AppSrc, u32) + Send + Sync + 'static>,
enough_data: Box<Fn(&AppSrc) + Send + Sync + 'static>,
seek_data: Box<Fn(&AppSrc, u64) -> bool + Send + Sync + 'static>,
need_data: Option<Box<Fn(&AppSrc, u32) + Send + Sync + 'static>>,
enough_data: Option<Box<Fn(&AppSrc) + Send + Sync + 'static>>,
seek_data: Option<Box<Fn(&AppSrc, u64) -> bool + Send + Sync + 'static>>,
callbacks: ffi::GstAppSrcCallbacks,
}
impl AppSrcCallbacks {
pub fn new<F, G, H>(need_data: F, enough_data: G, seek_data: H) -> Self
where
F: Fn(&AppSrc, u32) + Send + Sync + 'static,
G: Fn(&AppSrc) + Send + Sync + 'static,
H: Fn(&AppSrc, u64) -> bool + Send + Sync + 'static,
{
pub struct AppSrcCallbacksBuilder {
need_data: Option<Box<Fn(&AppSrc, u32) + Send + Sync + 'static>>,
enough_data: Option<Box<Fn(&AppSrc) + Send + Sync + 'static>>,
seek_data: Option<Box<Fn(&AppSrc, u64) -> bool + Send + Sync + 'static>>,
}
impl AppSrcCallbacksBuilder {
pub fn new() -> Self {
skip_assert_initialized!();
AppSrcCallbacksBuilder {
need_data: None,
enough_data: None,
seek_data: None,
}
}
pub fn need_data<F: Fn(&AppSrc, u32) + Send + Sync + 'static>(self, need_data: F) -> Self {
Self {
need_data: Some(Box::new(need_data)),
..self
}
}
pub fn enough_data<F: Fn(&AppSrc) + Send + Sync + 'static>(self, enough_data: F) -> Self {
Self {
enough_data: Some(Box::new(enough_data)),
..self
}
}
pub fn seek_data<F: Fn(&AppSrc, u64) -> bool + Send + Sync + 'static>(self, seek_data: F) -> Self {
Self {
seek_data: Some(Box::new(seek_data)),
..self
}
}
pub fn build(self) -> AppSrcCallbacks {
let have_need_data = self.need_data.is_some();
let have_enough_data = self.enough_data.is_some();
let have_seek_data = self.seek_data.is_some();
AppSrcCallbacks {
need_data: Box::new(need_data),
enough_data: Box::new(enough_data),
seek_data: Box::new(seek_data),
need_data: self.need_data,
enough_data: self.enough_data,
seek_data: self.seek_data,
callbacks: ffi::GstAppSrcCallbacks {
need_data: Some(trampoline_need_data),
enough_data: Some(trampoline_enough_data),
seek_data: Some(trampoline_seek_data),
need_data: if have_need_data { Some(trampoline_need_data) } else { None },
enough_data: if have_enough_data { Some(trampoline_enough_data) } else { None },
seek_data: if have_seek_data { Some(trampoline_seek_data) } else { None },
_gst_reserved: [
ptr::null_mut(),
ptr::null_mut(),
@ -57,14 +91,14 @@ unsafe extern "C" fn trampoline_need_data(
let _guard = CallbackGuard::new();
let callbacks = &*(callbacks as *const AppSrcCallbacks);
(callbacks.need_data)(&from_glib_borrow(appsrc), length);
callbacks.need_data.as_ref().map(|f| f(&from_glib_borrow(appsrc), length));
}
unsafe extern "C" fn trampoline_enough_data(appsrc: *mut ffi::GstAppSrc, callbacks: gpointer) {
let _guard = CallbackGuard::new();
let callbacks = &*(callbacks as *const AppSrcCallbacks);
(callbacks.enough_data)(&from_glib_borrow(appsrc));
callbacks.enough_data.as_ref().map(|f| f(&from_glib_borrow(appsrc)));
}
unsafe extern "C" fn trampoline_seek_data(
@ -75,7 +109,7 @@ unsafe extern "C" fn trampoline_seek_data(
let _guard = CallbackGuard::new();
let callbacks = &*(callbacks as *const AppSrcCallbacks);
(callbacks.seek_data)(&from_glib_borrow(appsrc), offset).to_glib()
callbacks.seek_data.as_ref().map(|f| f(&from_glib_borrow(appsrc), offset)).unwrap_or(false).to_glib()
}
unsafe extern "C" fn destroy_callbacks(ptr: gpointer) {

View file

@ -41,8 +41,8 @@ pub use auto::*;
mod app_src;
mod app_sink;
pub use app_src::AppSrcCallbacks;
pub use app_sink::AppSinkCallbacks;
pub use app_src::*;
pub use app_sink::*;
// Re-export all the traits in a prelude module, so that applications
// can always "use gst::prelude::*" without getting conflicts