pub struct FrameRateLimiter { /* private fields */ }Expand description
Forwards video frames at a fixed rate lower than the one they arrive at, stamping what it forwards as a constant-rate stream of its own.
§What it is for
A branch that wants a different rate from the source everything else on
the Tee shares. A compositor runs at one rate because the Preview and
the reported figure are made of it; a recording made from the same frames
need not be written at that rate, and at 60 into 30 it is half the encode
and half the file for a result most viewers cannot tell apart.
Lowering the compositor instead would lower everything — the Preview, and the rate the status bar reports a recording would be made at. So the choice belongs on the branch, which is what this is.
§It re-stamps rather than passing timestamps through
Output pts is this element’s own count of what it has forwarded, in
1/rate. That makes the output constant-rate by construction, which is
what a recording wants: converting the input timeline instead would leave
uneven gaps wherever the ratio is not a whole number — 60 into 24 is two
input frames for one output frame and then three — and write a
variable-rate file out of a source that was perfectly regular.
The consequence is that a source which stalls is elided rather than represented: ten seconds of nothing becomes a cut, not ten seconds of still picture. That is the same choice a constant frame rate always makes, and it is why the rate this is given has to be the rate the encoder after it is configured for.
Because the count starts at zero, so does the output — a
TimestampOrigin after the encoder
then has nothing left to shift, and is only needed on a branch that has no
limiter.
§Which frames it keeps
The first frame whose own timestamp has reached each output tick, so the spacing follows the input’s timeline rather than its frame count. A source that drops a frame, or pauses and resumes, still comes out at the rate asked for; counting arrivals instead would let a stall shift every frame after it.
§Cost
A reference to the frames it keeps and nothing at all for the ones it drops. No pixels are read, copied or converted here.
Implementations§
Source§impl FrameRateLimiter
impl FrameRateLimiter
Sourcepub fn new(
name: impl Into<String>,
input_time_base: Rational,
rate: Rational,
) -> Self
pub fn new( name: impl Into<String>, input_time_base: Rational, rate: Rational, ) -> Self
input_time_base is the unit the incoming frames’ pts are in — the
producer’s own, such as CudaVideoCompositor::time_base. rate is
frames per second out, and must be the rate whatever follows this is
configured for: the timestamps this writes mean nothing else.
Trait Implementations§
Source§impl Element for FrameRateLimiter
impl Element for FrameRateLimiter
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§fn graph_id(&self) -> Option<ElementId>
fn graph_id(&self) -> Option<ElementId>
ChainBuilder and keep the default None implementation.Source§fn attach_context(&mut self, _context: &Arc<Context>)
fn attach_context(&mut self, _context: &Arc<Context>)
Element::pp_log_mut hands it the pipeline’s
identity: the clock, the playback clock and the bus are the
pipeline’s to give, not the caller’s to choose. Read moreSource§impl Sink for FrameRateLimiter
impl Sink for FrameRateLimiter
Source§fn input_contract(&self) -> InputContract
fn input_contract(&self) -> InputContract
Video frames. It reads a timestamp and forwards a reference, so where the pixels live is not its business — but packets are not what it handles, and audio has no frame rate to limit.
Source§fn consume(&mut self, buf: MediaBuffer) -> Result<()>
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.Source§fn ready_consume(&mut self) -> bool
fn ready_consume(&mut self) -> bool
Self::consume can make progress now. Read more