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(
|
appsink.set_callbacks(
|
||||||
/* eos */
|
gst_app::AppSinkCallbacksBuilder::new()
|
||||||
|_| {},
|
.new_sample(|appsink| {
|
||||||
/* new_preroll */
|
let sample = match appsink.pull_sample() {
|
||||||
|_| gst::FlowReturn::Ok,
|
None => return gst::FlowReturn::Eos,
|
||||||
/* new_samples */
|
Some(sample) => 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() {
|
let buffer = if let Some(buffer) = sample.get_buffer() {
|
||||||
buffer
|
buffer
|
||||||
} else {
|
} else {
|
||||||
gst_element_error!(
|
gst_element_error!(
|
||||||
appsink,
|
appsink,
|
||||||
gst::ResourceError::Failed,
|
gst::ResourceError::Failed,
|
||||||
("Failed to get buffer from appsink")
|
("Failed to get buffer from appsink")
|
||||||
);
|
);
|
||||||
|
|
||||||
return gst::FlowReturn::Error;
|
return gst::FlowReturn::Error;
|
||||||
};
|
};
|
||||||
|
|
||||||
let map = if let Some(map) = buffer.map_readable() {
|
let map = if let Some(map) = buffer.map_readable() {
|
||||||
map
|
map
|
||||||
} else {
|
} else {
|
||||||
gst_element_error!(
|
gst_element_error!(
|
||||||
appsink,
|
appsink,
|
||||||
gst::ResourceError::Failed,
|
gst::ResourceError::Failed,
|
||||||
("Failed to map buffer readable")
|
("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>() {
|
let samples = if let Ok(samples) = map.as_slice().as_slice_of::<i16>() {
|
||||||
samples
|
samples
|
||||||
} else {
|
} else {
|
||||||
gst_element_error!(
|
gst_element_error!(
|
||||||
appsink,
|
appsink,
|
||||||
gst::ResourceError::Failed,
|
gst::ResourceError::Failed,
|
||||||
("Failed to interprete buffer as S16 PCM")
|
("Failed to interprete buffer as S16 PCM")
|
||||||
);
|
);
|
||||||
|
|
||||||
return gst::FlowReturn::Error;
|
return gst::FlowReturn::Error;
|
||||||
};
|
};
|
||||||
|
|
||||||
let sum: f64 = samples
|
let sum: f64 = samples
|
||||||
.iter()
|
.iter()
|
||||||
.map(|sample| {
|
.map(|sample| {
|
||||||
let f = f64::from(*sample) / f64::from(i16::MAX);
|
let f = f64::from(*sample) / f64::from(i16::MAX);
|
||||||
f * f
|
f * f
|
||||||
})
|
})
|
||||||
.sum();
|
.sum();
|
||||||
let rms = (sum / (samples.len() as f64)).sqrt();
|
let rms = (sum / (samples.len() as f64)).sqrt();
|
||||||
println!("rms: {}", rms);
|
println!("rms: {}", rms);
|
||||||
|
|
||||||
gst::FlowReturn::Ok
|
gst::FlowReturn::Ok
|
||||||
},
|
})
|
||||||
));
|
.build(),
|
||||||
|
);
|
||||||
|
|
||||||
Ok(pipeline)
|
Ok(pipeline)
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,29 +16,76 @@ use glib_ffi::gpointer;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
pub struct AppSinkCallbacks {
|
pub struct AppSinkCallbacks {
|
||||||
eos: Box<Fn(&AppSink) + Send + Sync + 'static>,
|
eos: Option<Box<Fn(&AppSink) + Send + Sync + 'static>>,
|
||||||
new_preroll: Box<Fn(&AppSink) -> gst::FlowReturn + Send + Sync + 'static>,
|
new_preroll: Option<Box<Fn(&AppSink) -> gst::FlowReturn + Send + Sync + 'static>>,
|
||||||
new_sample: Box<Fn(&AppSink) -> gst::FlowReturn + Send + Sync + 'static>,
|
new_sample: Option<Box<Fn(&AppSink) -> gst::FlowReturn + Send + Sync + 'static>>,
|
||||||
callbacks: ffi::GstAppSinkCallbacks,
|
callbacks: ffi::GstAppSinkCallbacks,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppSinkCallbacks {
|
pub struct AppSinkCallbacksBuilder {
|
||||||
pub fn new<F, G, H>(eos: F, new_preroll: G, new_sample: H) -> Self
|
eos: Option<Box<Fn(&AppSink) + Send + Sync + 'static>>,
|
||||||
where
|
new_preroll: Option<Box<Fn(&AppSink) -> gst::FlowReturn + Send + Sync + 'static>>,
|
||||||
F: Fn(&AppSink) + Send + Sync + 'static,
|
new_sample: Option<Box<Fn(&AppSink) -> gst::FlowReturn + Send + Sync + 'static>>,
|
||||||
G: Fn(&AppSink) -> gst::FlowReturn + Send + Sync + 'static,
|
}
|
||||||
H: Fn(&AppSink) -> gst::FlowReturn + Send + Sync + 'static,
|
|
||||||
{
|
impl AppSinkCallbacksBuilder {
|
||||||
|
pub fn new() -> Self {
|
||||||
skip_assert_initialized!();
|
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 {
|
AppSinkCallbacks {
|
||||||
eos: Box::new(eos),
|
eos: self.eos,
|
||||||
new_preroll: Box::new(new_preroll),
|
new_preroll: self.new_preroll,
|
||||||
new_sample: Box::new(new_sample),
|
new_sample: self.new_sample,
|
||||||
callbacks: ffi::GstAppSinkCallbacks {
|
callbacks: ffi::GstAppSinkCallbacks {
|
||||||
eos: Some(trampoline_eos),
|
eos: if have_eos { Some(trampoline_eos) } else { None },
|
||||||
new_preroll: Some(trampoline_new_preroll),
|
new_preroll: if have_new_preroll {
|
||||||
new_sample: Some(trampoline_new_sample),
|
Some(trampoline_new_preroll)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
|
new_sample: if have_new_sample {
|
||||||
|
Some(trampoline_new_sample)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
_gst_reserved: [
|
_gst_reserved: [
|
||||||
ptr::null_mut(),
|
ptr::null_mut(),
|
||||||
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 _guard = CallbackGuard::new();
|
||||||
let callbacks = &*(callbacks as *const AppSinkCallbacks);
|
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(
|
unsafe extern "C" fn trampoline_new_preroll(
|
||||||
|
@ -64,7 +114,12 @@ unsafe extern "C" fn trampoline_new_preroll(
|
||||||
let _guard = CallbackGuard::new();
|
let _guard = CallbackGuard::new();
|
||||||
let callbacks = &*(callbacks as *const AppSinkCallbacks);
|
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(
|
unsafe extern "C" fn trampoline_new_sample(
|
||||||
|
@ -74,7 +129,12 @@ unsafe extern "C" fn trampoline_new_sample(
|
||||||
let _guard = CallbackGuard::new();
|
let _guard = CallbackGuard::new();
|
||||||
let callbacks = &*(callbacks as *const AppSinkCallbacks);
|
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) {
|
unsafe extern "C" fn destroy_callbacks(ptr: gpointer) {
|
||||||
|
|
|
@ -15,29 +15,63 @@ use glib_ffi::{gboolean, gpointer};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
pub struct AppSrcCallbacks {
|
pub struct AppSrcCallbacks {
|
||||||
need_data: Box<Fn(&AppSrc, u32) + Send + Sync + 'static>,
|
need_data: Option<Box<Fn(&AppSrc, u32) + Send + Sync + 'static>>,
|
||||||
enough_data: Box<Fn(&AppSrc) + Send + Sync + 'static>,
|
enough_data: Option<Box<Fn(&AppSrc) + Send + Sync + 'static>>,
|
||||||
seek_data: Box<Fn(&AppSrc, u64) -> bool + Send + Sync + 'static>,
|
seek_data: Option<Box<Fn(&AppSrc, u64) -> bool + Send + Sync + 'static>>,
|
||||||
callbacks: ffi::GstAppSrcCallbacks,
|
callbacks: ffi::GstAppSrcCallbacks,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppSrcCallbacks {
|
pub struct AppSrcCallbacksBuilder {
|
||||||
pub fn new<F, G, H>(need_data: F, enough_data: G, seek_data: H) -> Self
|
need_data: Option<Box<Fn(&AppSrc, u32) + Send + Sync + 'static>>,
|
||||||
where
|
enough_data: Option<Box<Fn(&AppSrc) + Send + Sync + 'static>>,
|
||||||
F: Fn(&AppSrc, u32) + Send + Sync + 'static,
|
seek_data: Option<Box<Fn(&AppSrc, u64) -> bool + Send + Sync + 'static>>,
|
||||||
G: Fn(&AppSrc) + Send + Sync + 'static,
|
}
|
||||||
H: Fn(&AppSrc, u64) -> bool + Send + Sync + 'static,
|
|
||||||
{
|
impl AppSrcCallbacksBuilder {
|
||||||
|
pub fn new() -> Self {
|
||||||
skip_assert_initialized!();
|
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 {
|
AppSrcCallbacks {
|
||||||
need_data: Box::new(need_data),
|
need_data: self.need_data,
|
||||||
enough_data: Box::new(enough_data),
|
enough_data: self.enough_data,
|
||||||
seek_data: Box::new(seek_data),
|
seek_data: self.seek_data,
|
||||||
callbacks: ffi::GstAppSrcCallbacks {
|
callbacks: ffi::GstAppSrcCallbacks {
|
||||||
need_data: Some(trampoline_need_data),
|
need_data: if have_need_data { Some(trampoline_need_data) } else { None },
|
||||||
enough_data: Some(trampoline_enough_data),
|
enough_data: if have_enough_data { Some(trampoline_enough_data) } else { None },
|
||||||
seek_data: Some(trampoline_seek_data),
|
seek_data: if have_seek_data { Some(trampoline_seek_data) } else { None },
|
||||||
_gst_reserved: [
|
_gst_reserved: [
|
||||||
ptr::null_mut(),
|
ptr::null_mut(),
|
||||||
ptr::null_mut(),
|
ptr::null_mut(),
|
||||||
|
@ -57,14 +91,14 @@ unsafe extern "C" fn trampoline_need_data(
|
||||||
let _guard = CallbackGuard::new();
|
let _guard = CallbackGuard::new();
|
||||||
let callbacks = &*(callbacks as *const AppSrcCallbacks);
|
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) {
|
unsafe extern "C" fn trampoline_enough_data(appsrc: *mut ffi::GstAppSrc, callbacks: gpointer) {
|
||||||
let _guard = CallbackGuard::new();
|
let _guard = CallbackGuard::new();
|
||||||
let callbacks = &*(callbacks as *const AppSrcCallbacks);
|
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(
|
unsafe extern "C" fn trampoline_seek_data(
|
||||||
|
@ -75,7 +109,7 @@ unsafe extern "C" fn trampoline_seek_data(
|
||||||
let _guard = CallbackGuard::new();
|
let _guard = CallbackGuard::new();
|
||||||
let callbacks = &*(callbacks as *const AppSrcCallbacks);
|
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) {
|
unsafe extern "C" fn destroy_callbacks(ptr: gpointer) {
|
||||||
|
|
|
@ -41,8 +41,8 @@ pub use auto::*;
|
||||||
|
|
||||||
mod app_src;
|
mod app_src;
|
||||||
mod app_sink;
|
mod app_sink;
|
||||||
pub use app_src::AppSrcCallbacks;
|
pub use app_src::*;
|
||||||
pub use app_sink::AppSinkCallbacks;
|
pub use app_sink::*;
|
||||||
|
|
||||||
// Re-export all the traits in a prelude module, so that applications
|
// Re-export all the traits in a prelude module, so that applications
|
||||||
// can always "use gst::prelude::*" without getting conflicts
|
// can always "use gst::prelude::*" without getting conflicts
|
||||||
|
|
Loading…
Reference in a new issue