forked from mirrors/gstreamer-rs
Replace AppSrcCallbacks/AppSinkCallbacks with a builder so that no empty closures have to be provided for unused callbacks
This commit is contained in:
parent
dbe8eb9bd9
commit
49a6eb6a1f
4 changed files with 184 additions and 93 deletions
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue