Skip to main content

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 {}