pub struct TestVideoSource { /* private fields */ }Expand description
Generates a synthetic, moving-diagonal-gradient video stream —
GStreamer’s videotestsrc equivalent. No real decode/demux involved:
run() fabricates one Pixel::YUV420P frame per tick, stamps it with
an increasing pts (one tick per frame, in TestVideoSource::time_base’s
units), and pushes it straight downstream — useful for exercising
Scaler/Pacer/D3d12Renderer/etc. without a real file or camera.
D3d12Renderer in particular already handles Pixel::YUV420P on its
CPU-upload path, so this can feed a renderer directly, no decoder
needed.
Self-paces to options.framerate on a drift-free absolute schedule
(next_due += frame_interval each tick in run, not “sleep
frame_interval since the last push” — the latter accumulates drift,
since generation itself always takes some nonzero time) — unlike
FileDemuxer/RtspSource (which push as fast as they can and leave
real-time pacing entirely to a downstream Pacer), this element’s
“real time” isn’t defined by anything external; it’s whatever
framerate says it should be, so there’s no reason not to generate at
exactly that rate itself.
Confirmed (examples/render/test_video, with and without a
downstream Pacer) that this is actually enough on its own for
smooth D3d12Renderer output, vsync-locked presentation included — an
earlier version of this doc claimed self-pacing alone was not
enough and a Pacer was still required, reasoning that only the
average rate was being kept correct, not when each frame lines up
against the vsync grid. That reasoning wasn’t wrong about the
mechanism, but the fix turned out to already be in place here: a
relative “since last push” schedule genuinely can drift out of phase
over time, but this element was rewritten to the absolute schedule
described above specifically to close that gap, and testing without a
Pacer afterward showed no judder. See
crate::elements::DxgiCaptureSource’s own docs for the same
conclusion reached the same way, including a case (Scaler sitting
between source and renderer) this element doesn’t have.
Runs until Stop — never reaches Eos on its own (no frame-count
limit is exposed, deliberately, mirroring a live camera source more
than a file).
Implementations§
Source§impl TestVideoSource
impl TestVideoSource
pub fn new(name: impl Into<String>, options: TestVideoOptions) -> Self
Sourcepub fn time_base(&self) -> Rational
pub fn time_base(&self) -> Rational
The unit each generated frame’s pts is expressed in — what you
need to construct a matching crate::elements::Pacer.
Trait Implementations§
Source§impl Element for TestVideoSource
impl Element for TestVideoSource
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 SourceElement for TestVideoSource
impl SourceElement for TestVideoSource
Source§fn run(&mut self, control: &ControlReceiver, bus: &Bus) -> Result<()>
fn run(&mut self, control: &ControlReceiver, bus: &Bus) -> Result<()>
Eos (normal completion),
crate::pipeline::Pipeline::finish, or Stop (see
ControlMsg::Stop) — call crate::control::drain_control
once per loop iteration to make control responsive between
blocking reads. Read moreSource§fn seek(&mut self, _target: Duration) -> Result<Duration>
fn seek(&mut self, _target: Duration) -> Result<Duration>
target, an absolute position from the
start of the media (e.g. av_seek_frame for
crate::elements::FileDemuxer). Called by
crate::control::drain_control as part of handling
ControlMsg::Seek, before that message is forwarded to the
source’s own pads — so whatever’s read next comes from the new
position by the time downstream elements are told to flush for it. Read more