pub struct AppSink<F, C> { /* private fields */ }Expand description
Terminal sink that hands every buffer (and, optionally, every control
message) to a plain closure instead of requiring a bespoke struct +
Element/Sink impl — the equivalent of GStreamer’s appsink: the
pipeline’s job ends here, and whatever the caller does with the data
(run inference, forward it to a channel, write it out, …) is none of
this crate’s concern.
FrameCounter/PacketCounter are what a one-off consumer looked
like before this existed — this is the general case of the same
pattern, for when a whole new type per use site is more ceremony than
the actual logic warrants:
let mut count = 0usize;
let sink = AppSink::new("counter", move |buf: MediaBuffer| {
if matches!(buf, MediaBuffer::Video(_)) {
count += 1;
}
Ok(())
});Implementations§
Source§impl<F> AppSink<F, fn(ControlMsg) -> Result<()>>
impl<F> AppSink<F, fn(ControlMsg) -> Result<()>>
Sourcepub fn new(name: impl Into<String>, consume: F) -> Self
pub fn new(name: impl Into<String>, consume: F) -> Self
consume is the only thing this reacts to — every ControlMsg
(Pause/Resume/Stop/Seek) is silently ignored, the same as
FrameCounter/PacketCounter. Reach for
AppSink::with_control instead if the closure needs to know
about one of those — e.g. resetting a tracker’s history, or a
batch buffer, on Seek, the same way SwDecoder/Pacer react to
it internally.
Source§impl<F, C> AppSink<F, C>where
F: FnMut(MediaBuffer) -> Result<()> + Send + 'static,
C: FnMut(ControlMsg) -> Result<()> + Send + 'static,
impl<F, C> AppSink<F, C>where
F: FnMut(MediaBuffer) -> Result<()> + Send + 'static,
C: FnMut(ControlMsg) -> Result<()> + Send + 'static,
Sourcepub fn with_control(name: impl Into<String>, consume: F, control: C) -> Self
pub fn with_control(name: impl Into<String>, consume: F, control: C) -> Self
Same as AppSink::new, but also hands every ControlMsg to
control instead of silently dropping it.
let sink = AppSink::with_control(
"detector",
|_buf| Ok(()),
|msg| {
if let ControlMsg::Seek(_) = msg {
// e.g. clear a tracker's history here
}
Ok(())
},
);Trait Implementations§
Source§impl<F, C> Element for AppSink<F, C>where
F: FnMut(MediaBuffer) -> Result<()> + Send + 'static,
C: FnMut(ControlMsg) -> Result<()> + Send + 'static,
impl<F, C> Element for AppSink<F, C>where
F: FnMut(MediaBuffer) -> Result<()> + Send + 'static,
C: FnMut(ControlMsg) -> Result<()> + Send + 'static,
Source§fn name(&self) -> Arc<str> ⓘ
fn name(&self) -> Arc<str> ⓘ
crate::bus::BusEvent stores names as
Arc<str> for exactly this reason: a hot path like
crate::queue::Queue posting BusEvent::Dropped once per
overflowed buffer shouldn’t pay for a fresh heap allocation every
time it wants to report which element it is.Source§fn element_type(&self) -> ElementType
fn element_type(&self) -> ElementType
ElementType.Source§fn pp_log(&self) -> &PpLog
fn pp_log(&self) -> &PpLog
crate::bus::Bus::post — same
id/name as Element::name, just already wrapped as the
crate::pp_log::PpLog its pp_info!/pp_warn!/pp_error! macros need. A
stored private field, not built fresh per call, for the same reason
name() returns a cheap Arc<str> clone instead of a fresh String
— see its own docs.Source§fn pp_log_mut(&mut self) -> &mut PpLog
fn pp_log_mut(&mut self) -> &mut PpLog
Element::pp_log reads — used by
crate::pipeline::ChainBuilder to stamp the owning
crate::pipeline::Pipeline’s id onto every element that
passes through it, via element_pp_log. Not meant to be called
from anywhere else.Source§impl<F, C> Sink for AppSink<F, C>where
F: FnMut(MediaBuffer) -> Result<()> + Send + 'static,
C: FnMut(ControlMsg) -> Result<()> + Send + 'static,
impl<F, C> Sink for AppSink<F, C>where
F: FnMut(MediaBuffer) -> Result<()> + Send + 'static,
C: FnMut(ControlMsg) -> Result<()> + Send + 'static,
fn consume(&mut self, buf: MediaBuffer) -> Result<()>
Source§fn control(&mut self, msg: ControlMsg) -> Result<()>
fn control(&mut self, msg: ControlMsg) -> Result<()>
ControlMsg (pause/resume/stop) and, for anything
with a downstream of its own, forwards it on — same shape as
consume, just a separate channel from MediaBuffer so it can
reach every element (not just ones that already know how to
interpret a data buffer) and, at a crate::queue::Queue, jump
ahead of whatever data is backed up instead of waiting behind it.
No default: every Sink has to consciously decide what this means
for it, rather than silently dropping it.