media_pp/core/element.rs
1//! The traits every element implements, and the identity it carries.
2//!
3//! [`Sink`] consumes buffers, [`Source`] owns the [`SrcPad`](crate::pad::SrcPad)s
4//! they leave through, and [`Filter`] is simply both. [`SourceElement`] adds
5//! the one thing a graph needs exactly once: a `run` loop that drives the
6//! whole pipeline.
7//!
8//! [`Element`] itself is the identity half — an element's type and its
9//! caller-chosen name, which every log record and every
10//! [`BusEvent`](crate::bus::BusEvent) is attributed to.
11
12use std::{
13 sync::{Arc, Mutex},
14 time::Duration,
15};
16
17use crate::pp_log::PpLog;
18
19use crate::{
20 buffer::MediaBuffer,
21 bus::Bus,
22 clock::Clock,
23 contract::InputContract,
24 control::{ControlMsg, ControlReceiver},
25 error::Result,
26 graph::{ElementId, PipelineGraph},
27 pad::SrcPad,
28 playback_clock::PlaybackClock,
29};
30
31/// Which kind of element posted a [`crate::bus::BusEvent`] — cheap to
32/// compare/match, unlike the accompanying `name: Arc<str>` (an
33/// instance-level identifier chosen by whoever constructed it, needed
34/// alongside this to tell apart e.g. two `Queue`s in the same pipeline;
35/// see [`Element::element_type`]).
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37pub enum ElementType {
38 /// File or container demultiplexer source.
39 FileDemuxer,
40 /// Application-fed buffer source.
41 AppSource,
42 /// RTSP network stream source.
43 RtspSource,
44 /// Synthetic video source.
45 TestVideoSource,
46 /// Synthetic audio source.
47 TestAudioSource,
48 /// Windows desktop-duplication capture source.
49 DxgiCaptureSource,
50 /// Windows Graphics Capture window source.
51 WgcCaptureSource,
52 /// PipeWire audio capture source.
53 PipeWireAudioCaptureSource,
54 /// PipeWire screen capture source.
55 PipeWireScreenCaptureSource,
56 /// Windows WASAPI audio capture source.
57 WasapiCaptureSource,
58 /// Windows Media Foundation camera capture source.
59 MfCaptureSource,
60 /// Linux V4L2 camera capture source.
61 V4l2CaptureSource,
62 /// Multi-input audio mixer source.
63 AudioMixer,
64 /// One input registered with an [`ElementType::AudioMixer`], which is a
65 /// `Sink` in whichever pipeline feeds it rather than part of the mixer's
66 /// own.
67 ///
68 /// Its own variant because it reads as one: an input that called itself
69 /// `AudioMixer` put a mixer at the end of every branch feeding one, and a
70 /// topology diagram with four of them in it is a diagram nobody can count
71 /// the mixers from.
72 AudioMixerInput,
73 /// CPU video compositor source.
74 SwVideoCompositor,
75 /// CUDA video compositor source.
76 CudaVideoCompositor,
77 /// D3D11 video compositor source.
78 D3d11VideoCompositor,
79 /// WebRTC connection driver.
80 WebRtcPeer,
81 /// Packet timestamp rebase filter.
82 FrameRateLimiter,
83 PauseGate,
84 TimestampOrigin,
85 /// Video change/rate gate filter.
86 ChangeGate,
87 /// FFmpeg software decoder filter.
88 SwDecoder,
89 /// CUDA hardware decoder filter.
90 CudaDecoder,
91 /// System-memory to CUDA upload filter.
92 CudaUpload,
93 /// CUDA to system-memory download filter.
94 CudaDownload,
95 /// CUDA pixel-format converter filter.
96 CudaConverter,
97 /// D3D12 hardware decoder filter.
98 D3d12Decoder,
99 /// System-memory to D3D12 upload filter.
100 D3d12Upload,
101 /// D3D12 to system-memory download filter.
102 D3d12Download,
103 /// D3D12 video scaler filter.
104 D3d12Scaler,
105 /// D3D11 hardware decoder filter.
106 D3d11Decoder,
107 /// System-memory to D3D11 upload filter.
108 D3d11Upload,
109 /// D3D11 to system-memory download filter.
110 D3d11Download,
111 /// Software video encoder filter.
112 SwEncoder,
113 /// CUDA video encoder filter.
114 CudaEncoder,
115 /// D3D11-backed NVENC filter.
116 D3d11VideoEncoder,
117 /// Software audio encoder filter.
118 SwAudioEncoder,
119 /// Audio format and rate converter filter.
120 AudioResampler,
121 /// Runtime-adjustable audio gain filter.
122 AudioVolume,
123 /// Timestamp-to-wall-clock pacing filter.
124 Pacer,
125 /// Playback-master-aware video scheduling filter.
126 VideoSynchronizer,
127 /// CPU video scaler filter.
128 SwScaler,
129 /// CPU chroma-key filter.
130 SwChromaKey,
131 /// CUDA video scaler filter.
132 CudaScaler,
133 /// D3D11 video scaler filter.
134 D3d11Scaler,
135 /// D3D11 chroma-key filter.
136 D3d11ChromaKey,
137 /// Dynamic one-to-many branch filter.
138 Tee,
139 /// Bounded asynchronous queue filter.
140 Queue,
141 /// Diagnostic decoded-frame counter sink.
142 FrameCounter,
143 /// Diagnostic compressed-packet counter sink.
144 PacketCounter,
145 /// CUDA video renderer sink.
146 CudaRenderer,
147 /// D3D12 video renderer sink.
148 D3d12Renderer,
149 /// D3D11 video renderer sink.
150 D3d11Renderer,
151 /// PipeWire audio renderer sink.
152 PipeWireAudioRenderer,
153 /// Windows WASAPI audio renderer sink.
154 WasapiRenderer,
155 /// RTSP publishing sink.
156 RtspSink,
157 /// Application callback or channel sink.
158 AppSink,
159 /// ONNX Runtime object-detection sink.
160 OrtDetector,
161 /// HTTP Live Streaming muxer sink.
162 HlsMuxer,
163 /// Container file muxer sink — the container is whichever one
164 /// FFmpeg infers from the output path.
165 FileMuxer,
166 /// Rotating segmented container file muxer sink.
167 SegmentedFileMuxer,
168 /// Anything outside this crate's own elements — a test double, or a
169 /// custom `Sink`/`SourceElement` implemented downstream of this
170 /// crate. Keeps this enum from needing to grow every time someone
171 /// adds their own element.
172 Other,
173}
174
175/// A node in the pipeline graph with a name. Plain identity only — says
176/// nothing about whether the node has an input, an output, both, or
177/// neither.
178pub trait Element: Send {
179 /// Returns a cheap clone (refcount bump, not a deep copy) of this
180 /// element's name — [`crate::bus::BusEvent`] stores names as
181 /// `Arc<str>` for exactly this reason: a hot path like
182 /// [`crate::queue::Queue`] posting `BusEvent::Dropped` once per
183 /// overflowed buffer shouldn't pay for a fresh heap allocation every
184 /// time it wants to report which element it is.
185 fn name(&self) -> Arc<str>;
186
187 /// See [`ElementType`].
188 fn element_type(&self) -> ElementType;
189
190 /// A pre-reserved graph identity for elements that expose dynamic
191 /// attachment handles. Most elements receive an ID from
192 /// `ChainBuilder` and keep the default `None` implementation.
193 fn graph_id(&self) -> Option<ElementId> {
194 None
195 }
196
197 /// This element's identity for [`crate::bus::Bus::post`] — same
198 /// `id`/`name` as [`Element::name`], just already wrapped as the
199 /// [`crate::pp_log::PpLog`] its `pp_info!`/`pp_warn!`/`pp_error!` macros need. A
200 /// stored private field, not built fresh per call, for the same reason
201 /// `name()` returns a cheap `Arc<str>` clone instead of a fresh `String`
202 /// — see its own docs.
203 fn pp_log(&self) -> &PpLog;
204
205 /// Mutable access to the same field [`Element::pp_log`] reads — used by
206 /// [`crate::pipeline::ChainBuilder`] to stamp the owning
207 /// [`crate::pipeline::Pipeline`]'s id onto every element that
208 /// passes through it, via [`element_pp_log`]. Not meant to be called
209 /// from anywhere else.
210 fn pp_log_mut(&mut self) -> &mut PpLog;
211
212 /// Hands this element the pipeline it is being wired into, at the moment
213 /// and for the reason [`Element::pp_log_mut`] hands it the pipeline's
214 /// identity: the clock, the playback clock and the bus are the
215 /// pipeline's to give, not the caller's to choose.
216 ///
217 /// # Why this is not a constructor argument
218 ///
219 /// It used to be, and an element could then be handed a clock from
220 /// somewhere else entirely. That fails quietly. A [`Pacer`] on a foreign
221 /// clock never sees `Pipeline::pause` shift the anchor and goes on
222 /// pacing through a paused pipeline; an audio renderer registered on a
223 /// foreign [`PlaybackClock`] *succeeds* — nothing is holding that one —
224 /// and the video scheduled against the pipeline's own clock simply never
225 /// hears about it. No error either way, just timing that does not work.
226 ///
227 /// Taking it here instead makes the mistake unrepresentable: there is
228 /// nowhere else to get one from.
229 ///
230 /// # What an implementation should do
231 ///
232 /// Take what it needs and let the rest go. Holding the context keeps the
233 /// graph and the bus alive for as long as the element, and invites
234 /// reaching into the pipeline at moments it is not expecting one.
235 /// [`crate::elements::Tee`] is the exception and has a reason: it builds
236 /// branches later.
237 ///
238 /// Called once, before any buffer arrives — from the branch wiring for a
239 /// filter or a terminal, and from
240 /// [`crate::pipeline::PipelineBuilder::add_source`] for a source. An
241 /// element that needs something from it and never receives one has been
242 /// built outside a pipeline, which is a wiring mistake rather than a
243 /// runtime condition; say so with a typed error rather than carrying on
244 /// unpaced.
245 ///
246 /// Claiming something exclusive here — the playback clock's audio master
247 /// is the only such thing today — is settled once, when the element is
248 /// wired. A second claimant loses and is not offered the role again if
249 /// the first one later goes away.
250 ///
251 /// [`Pacer`]: crate::elements::Pacer
252 /// [`PlaybackClock`]: crate::playback_clock::PlaybackClock
253 fn attach_context(&mut self, _context: &Arc<Context>) {}
254}
255
256/// Builds the [`PpLog`] every element constructs for its own [`Element::pp_log`]
257/// field, and that [`crate::pipeline::ChainBuilder`]/[`crate::pipeline::Pipeline`]
258/// rebuild once they know which pipeline an element belongs to. Keeps the
259/// element type, instance name, and pipeline id as separate fields, so a log
260/// reader does not need to parse a combined display string. The pipeline id is
261/// `None` for an element that isn't wired into a `Pipeline` at all (e.g. most
262/// of this crate's own tests). Public so a custom `Element`
263/// implemented outside this crate (see [`ElementType::Other`]) can build
264/// its own `pp_log` field the same way.
265pub fn element_pp_log(element_type: ElementType, name: &str, pipeline_id: Option<&str>) -> PpLog {
266 PpLog::new(&format!("{element_type:?}"), name, pipeline_id)
267}
268
269/// Builds the [`PpLog`] used for records a [`crate::pipeline::Pipeline`]
270/// emits about itself rather than about any one element — `run` and the
271/// `topology` diagram. A pipeline is not a graph node and so has no
272/// [`ElementType`]; its instance name is its own id. Kept here next to
273/// [`element_pp_log`] so the literal element name appears exactly once.
274pub(crate) fn pipeline_pp_log(pipeline_id: &str) -> PpLog {
275 PpLog::new("Pipeline", pipeline_id, Some(pipeline_id))
276}
277
278/// Everything a [`crate::pipeline::ChainBuilder`]/[`crate::elements::Tee`]
279/// needs to wire itself into a [`crate::pipeline::Pipeline`] — bundled into
280/// one `Arc` instead of threading `bus`/`pipeline_id`/`graph`/the wall and
281/// playback clocks through separately. Built once per source by
282/// [`crate::pipeline::PipelineBuilder::add_source`] (what
283/// [`crate::pipeline::Pipeline::new`] itself calls, for its own
284/// single-source case) and handed to that source's own `wire` closure; a
285/// [`crate::elements::Tee`] keeps its own clone while it is alive, and its
286/// [`crate::elements::TeeHandle`] accesses that clone weakly so retaining
287/// the handle cannot keep the pipeline's `Bus` open after the `Tee` itself
288/// is gone.
289pub struct Context {
290 /// Sender used by this source and its attached branches for asynchronous
291 /// errors, EOS, drops, and seek completion.
292 pub bus: Bus,
293
294 /// Caller-selected identity of the pipeline currently being wired.
295 pub pipeline_id: Arc<str>,
296
297 /// Shared live topology graph updated by successful attach and detach
298 /// operations.
299 pub graph: PipelineGraph,
300
301 /// Wall-time clock shared by paced elements in this pipeline.
302 pub clock: Arc<Clock>,
303 /// Shared media-position clock used to hand video scheduling from the
304 /// wall clock to an audio output master without changing pipelines.
305 pub playback_clock: Arc<PlaybackClock>,
306 /// Serializes topology attachment with pipeline timeline operations.
307 ///
308 /// A branch may be detached while preroll is waiting (the waiter removes
309 /// the departed terminal), but publishing a new branch in the middle of a
310 /// seek would leave it outside the seek's terminal snapshot and control
311 /// cascade.
312 pub(crate) operation: Arc<Mutex<()>>,
313 /// Graph identity of the source whose wiring closure owns this context.
314 pub source_id: ElementId,
315}
316
317#[cfg(test)]
318impl Context {
319 pub(crate) fn for_test(
320 bus: Bus,
321 pipeline_id: impl Into<Arc<str>>,
322 graph: PipelineGraph,
323 source_id: ElementId,
324 ) -> Self {
325 Self::for_test_with_clock(bus, pipeline_id, graph, source_id, Arc::new(Clock::new()))
326 }
327
328 /// The same, around a clock the test already holds — what a test that
329 /// interrupts or pauses a paced element needs, since the element now
330 /// takes its clock from a context rather than from the caller.
331 pub(crate) fn for_test_with_clock(
332 bus: Bus,
333 pipeline_id: impl Into<Arc<str>>,
334 graph: PipelineGraph,
335 source_id: ElementId,
336 clock: Arc<Clock>,
337 ) -> Self {
338 Self {
339 bus,
340 pipeline_id: pipeline_id.into(),
341 graph,
342 playback_clock: Arc::new(PlaybackClock::new(clock.clone())),
343 clock,
344 operation: Arc::new(Mutex::new(())),
345 source_id,
346 }
347 }
348}
349
350/// Anything that can receive a buffer pushed from upstream — the input
351/// side of an element, or a plain terminal sink. Every `Sink` is named
352/// (via `Element`) so bus events (e.g. EOS) can identify which one they
353/// came from.
354///
355/// This is the only "connection" primitive in the pipeline. By default,
356/// consuming a buffer is a plain function call on the caller's thread —
357/// zero overhead. Thread boundaries are introduced explicitly by wrapping
358/// a `Sink` in a [`crate::queue::Queue`], not by elements spawning their
359/// own threads.
360pub trait Sink: Element {
361 /// Returns whether calling [`Self::consume`] can make progress now.
362 ///
363 /// Thread boundaries check this before removing the next queued buffer,
364 /// so a paused or completed-preroll terminal applies backpressure without
365 /// dropping that buffer. Filters should delegate to their downstream pad;
366 /// sinks that are always ready may keep the default.
367 fn ready_consume(&mut self) -> bool {
368 true
369 }
370
371 /// Processes one buffer synchronously on the caller's thread.
372 ///
373 /// An error is returned directly to upstream until the call crosses a
374 /// [`crate::queue::Queue`] boundary. A queue instead reports the error on
375 /// its [`crate::bus::Bus`], drops that buffer, and keeps its worker alive.
376 /// Implementations must forward [`MediaBuffer::Eos`] after flushing any
377 /// delayed state they own.
378 ///
379 /// For a terminal sink, returning `Ok(())` means the buffer has been
380 /// accepted into that sink's output path. Pipeline preroll uses precisely
381 /// this boundary: a video renderer must not return success until it has
382 /// installed the frame as its current presentation content or submitted
383 /// it to its presentation queue. This does not promise physical display
384 /// scanout, audible playback, or remote receipt.
385 fn consume(&mut self, buf: MediaBuffer) -> Result<()>;
386
387 /// What this sink can be fed, checked when it is wired rather than
388 /// when the first buffer arrives — see [`crate::contract`].
389 ///
390 /// The default declares nothing, so an element that does not override
391 /// it links to anything and is validated exactly as before, when a
392 /// buffer reaches `consume`. Declaring a contract never replaces that
393 /// runtime check; it only moves the subset of failures that are
394 /// knowable at wiring time to where they are unambiguously a wiring
395 /// mistake rather than a bad buffer.
396 fn input_contract(&self) -> InputContract {
397 InputContract::Unknown
398 }
399
400 /// Reacts to a [`ControlMsg`] (pause/resume/stop) and, for anything
401 /// with a downstream of its own, forwards it on — same shape as
402 /// `consume`, just a separate channel from `MediaBuffer` so it can
403 /// reach every element (not just ones that already know how to
404 /// interpret a data buffer) and, at a [`crate::queue::Queue`], jump
405 /// ahead of whatever data is backed up instead of waiting behind it.
406 /// No default: every `Sink` has to consciously decide what this means
407 /// for it, rather than silently dropping it.
408 fn control(&mut self, msg: ControlMsg) -> Result<()>;
409}
410
411/// An element with one or more output ports. It sends data downstream by
412/// pushing into its own `src_pads()` (e.g. `self.src_pads()[0].push(buf)`)
413/// — it's never handed a `downstream` argument from the outside. See
414/// [`SrcPad`].
415///
416/// `Source` and `Sink` are the two halves of the duality: `Sink` is "has
417/// an input", `Source` is "has an output". An element that both receives
418/// and produces (a decoder, say) implements both side by side — `Sink` to
419/// receive, `Source` to push whatever it produces into its own pad(s)
420/// from inside `consume`. There's no separate "processing element" trait
421/// or wrapper needed for that.
422pub trait Source: Element {
423 /// Returns every output pad owned by this element.
424 ///
425 /// The slice order is the element's public pad-index contract. Implementors
426 /// use the mutable access to push buffers and propagate control; callers
427 /// normally connect pads through [`Context::attach`] instead of linking
428 /// them directly.
429 fn src_pads(&mut self) -> &mut [SrcPad];
430}
431
432/// A pure source: has output but no input. Its `run` method drives the
433/// production loop and pushes buffers into its own src pad(s) until EOS or
434/// an error. [`crate::pipeline::Pipeline::run`] normally invokes that loop
435/// on the pipeline's background source thread; a caller may also invoke a
436/// concrete implementation directly. Sources typically wrap blocking I/O
437/// reads (demuxer, file/network source).
438pub trait SourceElement: Source {
439 /// Whether this source produces data from a live, externally advancing
440 /// input rather than from a finite or application-controlled timeline.
441 ///
442 /// A live source cannot normally produce a first buffer while a pipeline
443 /// is paused, so pipeline state handling may use this distinction to
444 /// report that preroll is unavailable. Every implementation must classify
445 /// itself explicitly so a new live source cannot silently opt into file-
446 /// style preroll behavior.
447 fn is_live(&self) -> bool;
448
449 /// Whether this source can reposition its own input timeline through
450 /// [`Self::seek`].
451 ///
452 /// This only describes the source's capability. A seekable source does
453 /// not imply that every downstream branch can accept a pipeline seek;
454 /// that must be validated across the complete graph before mutation.
455 fn is_seekable(&self) -> bool;
456
457 /// Drives this source until `Eos` (normal completion),
458 /// [`crate::pipeline::Pipeline::finish`], or `Stop` (see
459 /// [`ControlMsg::Stop`]) — call [`crate::control::drain_control`]
460 /// once per loop iteration to make `control` responsive between
461 /// blocking reads.
462 ///
463 /// `bus` is this source's own way to report a failure pushing into
464 /// one of its pads *without* treating it as fatal — post a
465 /// [`crate::bus::BusEvent::Error`] and keep going (drop that one
466 /// buffer), the same way a [`crate::queue::Queue`] handles a failing
467 /// downstream `Sink` — rather than returning `Err` and ending this
468 /// source's thread over one bad buffer. A returned `Err` is still
469 /// how genuinely fatal failures (this source can't continue at all)
470 /// reach [`crate::pipeline::Pipeline::run`], which posts it to `bus`
471 /// itself.
472 fn run(&mut self, control: &ControlReceiver, bus: &Bus) -> Result<()>;
473
474 /// Reacts to one control message before it is forwarded to this source's
475 /// own pads — the same ordering [`Self::seek`] gets, and for the same
476 /// reason: whatever this source holds must already reflect the message by
477 /// the time downstream elements see it.
478 ///
479 /// This is the source-side counterpart of [`Sink::control`], and exists
480 /// for a source that holds state of its own. [`crate::elements::FileDemuxer`]
481 /// uses it for both messages that touch its read-ahead: `Flush` discards
482 /// packets belonging to the timeline being left, and `Preroll` is what
483 /// makes it hold a blocked pad's packets instead of waiting on that pad.
484 ///
485 /// The default is a no-op. A source that hands every packet straight to a
486 /// pad has nothing of its own to keep in step.
487 fn on_control(&mut self, _msg: &ControlMsg) {}
488
489 /// Repositions this source to `target`, an absolute position from the
490 /// start of the media (e.g. `av_seek_frame` for
491 /// [`crate::elements::FileDemuxer`]). Called by
492 /// [`crate::control::drain_control`] as part of handling
493 /// [`ControlMsg::Seek`], *before* that message is forwarded to the
494 /// source's own pads — so whatever's read next comes from the new
495 /// position by the time downstream elements receive the new timeline
496 /// announcement. Buffered and stateful old-timeline data is discarded by
497 /// the preceding [`ControlMsg::Flush`].
498 ///
499 /// Returns where this actually landed, which is allowed to differ
500 /// from `target` — a container seek can only ever reposition to a
501 /// keyframe at or before it (landing mid-GOP would leave downstream
502 /// decoders/muxers with no reference frame to start from), so
503 /// `target` is a request, not a guarantee. `drain_control` reports
504 /// the gap between the two via [`crate::bus::BusEvent::Seeked`];
505 /// callers that need to know where playback actually resumed should
506 /// watch that instead of assuming `target` took effect verbatim.
507 fn seek(&mut self, target: Duration) -> Result<Duration>;
508}
509
510/// An element with both an input and an output — decoder, encoder,
511/// filter, thumbnail extractor, ... Just a name for "has a `Sink` to
512/// receive and a `Source` to push what it produces into"; nothing new to
513/// implement beyond those two.
514pub trait Filter: Source + Sink {}
515
516impl<T: Source + Sink> Filter for T {}