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::{sync::Arc, time::Duration};
13
14use crate::pp_log::PpLog;
15
16use crate::{
17    buffer::MediaBuffer,
18    bus::Bus,
19    clock::Clock,
20    control::{ControlMsg, ControlReceiver},
21    error::Result,
22    graph::{ElementId, PipelineGraph},
23    pad::SrcPad,
24    playback_clock::PlaybackClock,
25};
26
27/// Which kind of element posted a [`crate::bus::BusEvent`] — cheap to
28/// compare/match, unlike the accompanying `name: Arc<str>` (an
29/// instance-level identifier chosen by whoever constructed it, needed
30/// alongside this to tell apart e.g. two `Queue`s in the same pipeline;
31/// see [`Element::element_type`]).
32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33pub enum ElementType {
34    /// File or container demultiplexer source.
35    FileDemuxer,
36    /// Application-fed buffer source.
37    AppSource,
38    /// RTSP network stream source.
39    RtspSource,
40    /// Synthetic video source.
41    TestVideoSource,
42    /// Synthetic audio source.
43    TestAudioSource,
44    /// Windows desktop-duplication capture source.
45    DxgiCaptureSource,
46    /// PipeWire audio capture source.
47    PipeWireAudioCaptureSource,
48    /// PipeWire screen capture source.
49    PipeWireScreenCaptureSource,
50    /// Windows WASAPI audio capture source.
51    WasapiCaptureSource,
52    /// Multi-input audio mixer source.
53    AudioMixer,
54    /// CPU video compositor source.
55    SwVideoCompositor,
56    /// CUDA video compositor source.
57    CudaVideoCompositor,
58    /// D3D11 video compositor source.
59    D3d11VideoCompositor,
60    /// WebRTC connection driver.
61    WebRtcPeer,
62    /// FFmpeg software decoder filter.
63    SwDecoder,
64    /// CUDA hardware decoder filter.
65    CudaDecoder,
66    /// System-memory to CUDA upload filter.
67    CudaUpload,
68    /// CUDA to system-memory download filter.
69    CudaDownload,
70    /// CUDA pixel-format converter filter.
71    CudaConverter,
72    /// D3D12 hardware decoder filter.
73    D3d12Decoder,
74    /// System-memory to D3D12 upload filter.
75    D3d12Upload,
76    /// D3D12 to system-memory download filter.
77    D3d12Download,
78    /// D3D12 video scaler filter.
79    D3d12Scaler,
80    /// D3D11 hardware decoder filter.
81    D3d11Decoder,
82    /// System-memory to D3D11 upload filter.
83    D3d11Upload,
84    /// D3D11 to system-memory download filter.
85    D3d11Download,
86    /// Software video encoder filter.
87    SwEncoder,
88    /// CUDA video encoder filter.
89    CudaEncoder,
90    /// D3D11-backed NVENC filter.
91    D3d11NvencEncoder,
92    /// Software audio encoder filter.
93    SwAudioEncoder,
94    /// Audio format and rate converter filter.
95    AudioResampler,
96    /// Runtime-adjustable audio gain filter.
97    AudioVolume,
98    /// Timestamp-to-wall-clock pacing filter.
99    Pacer,
100    /// Playback-master-aware video scheduling filter.
101    VideoSynchronizer,
102    /// CPU video scaler filter.
103    SwScaler,
104    /// CPU chroma-key filter.
105    SwChromaKey,
106    /// CUDA video scaler filter.
107    CudaScaler,
108    /// D3D11 video scaler filter.
109    D3d11Scaler,
110    /// D3D11 chroma-key filter.
111    D3d11ChromaKey,
112    /// Dynamic one-to-many branch filter.
113    Tee,
114    /// Bounded asynchronous queue filter.
115    Queue,
116    /// Diagnostic decoded-frame counter sink.
117    FrameCounter,
118    /// Diagnostic compressed-packet counter sink.
119    PacketCounter,
120    /// CUDA video renderer sink.
121    CudaRenderer,
122    /// D3D12 video renderer sink.
123    D3d12Renderer,
124    /// D3D11 video renderer sink.
125    D3d11Renderer,
126    /// PipeWire audio renderer sink.
127    PipeWireAudioRenderer,
128    /// Windows WASAPI audio renderer sink.
129    WasapiRenderer,
130    /// RTSP publishing sink.
131    RtspSink,
132    /// Application callback or channel sink.
133    AppSink,
134    /// ONNX Runtime object-detection sink.
135    OrtDetector,
136    /// HTTP Live Streaming muxer sink.
137    HlsMuxer,
138    /// MP4 muxer sink.
139    Mp4Muxer,
140    /// Rotating segmented MP4 muxer sink.
141    SegmentedMp4Muxer,
142    /// Anything outside this crate's own elements — a test double, or a
143    /// custom `Sink`/`SourceElement` implemented downstream of this
144    /// crate. Keeps this enum from needing to grow every time someone
145    /// adds their own element.
146    Other,
147}
148
149/// A node in the pipeline graph with a name. Plain identity only — says
150/// nothing about whether the node has an input, an output, both, or
151/// neither.
152pub trait Element: Send {
153    /// Returns a cheap clone (refcount bump, not a deep copy) of this
154    /// element's name — [`crate::bus::BusEvent`] stores names as
155    /// `Arc<str>` for exactly this reason: a hot path like
156    /// [`crate::queue::Queue`] posting `BusEvent::Dropped` once per
157    /// overflowed buffer shouldn't pay for a fresh heap allocation every
158    /// time it wants to report which element it is.
159    fn name(&self) -> Arc<str>;
160
161    /// See [`ElementType`].
162    fn element_type(&self) -> ElementType;
163
164    /// A pre-reserved graph identity for elements that expose dynamic
165    /// attachment handles. Most elements receive an ID from
166    /// `ChainBuilder` and keep the default `None` implementation.
167    fn graph_id(&self) -> Option<ElementId> {
168        None
169    }
170
171    /// This element's identity for [`crate::bus::Bus::post`] — same
172    /// `id`/`name` as [`Element::name`], just already wrapped as the
173    /// [`crate::pp_log::PpLog`] its `pp_info!`/`pp_warn!`/`pp_error!` macros need. A
174    /// stored private field, not built fresh per call, for the same reason
175    /// `name()` returns a cheap `Arc<str>` clone instead of a fresh `String`
176    /// — see its own docs.
177    fn pp_log(&self) -> &PpLog;
178
179    /// Mutable access to the same field [`Element::pp_log`] reads — used by
180    /// [`crate::pipeline::ChainBuilder`] to stamp the owning
181    /// [`crate::pipeline::Pipeline`]'s id onto every element that
182    /// passes through it, via [`element_pp_log`]. Not meant to be called
183    /// from anywhere else.
184    fn pp_log_mut(&mut self) -> &mut PpLog;
185}
186
187/// Builds the [`PpLog`] every element constructs for its own [`Element::pp_log`]
188/// field, and that [`crate::pipeline::ChainBuilder`]/[`crate::pipeline::Pipeline`]
189/// rebuild once they know which pipeline an element belongs to. Keeps the
190/// element type, instance name, and pipeline id as separate fields, so a log
191/// reader does not need to parse a combined display string. The pipeline id is
192/// `None` for an element that isn't wired into a `Pipeline` at all (e.g. most
193/// of this crate's own tests). Public so a custom `Element`
194/// implemented outside this crate (see [`ElementType::Other`]) can build
195/// its own `pp_log` field the same way.
196pub fn element_pp_log(element_type: ElementType, name: &str, pipeline_id: Option<&str>) -> PpLog {
197    PpLog::new(&format!("{element_type:?}"), name, pipeline_id)
198}
199
200/// Builds the [`PpLog`] used for records a [`crate::pipeline::Pipeline`]
201/// emits about itself rather than about any one element — `run` and the
202/// `topology` diagram. A pipeline is not a graph node and so has no
203/// [`ElementType`]; its instance name is its own id. Kept here next to
204/// [`element_pp_log`] so the literal element name appears exactly once.
205pub(crate) fn pipeline_pp_log(pipeline_id: &str) -> PpLog {
206    PpLog::new("Pipeline", pipeline_id, Some(pipeline_id))
207}
208
209/// Everything a [`crate::pipeline::ChainBuilder`]/[`crate::elements::Tee`]
210/// needs to wire itself into a [`crate::pipeline::Pipeline`] — bundled into
211/// one `Arc` instead of threading `bus`/`pipeline_id`/`graph`/the wall and
212/// playback clocks through separately. Built once per source by
213/// [`crate::pipeline::PipelineBuilder::add_source`] (what
214/// [`crate::pipeline::Pipeline::new`] itself calls, for its own
215/// single-source case) and handed to that source's own `wire` closure; a
216/// [`crate::elements::Tee`] keeps its own clone while it is alive, and its
217/// [`crate::elements::TeeHandle`] accesses that clone weakly so retaining
218/// the handle cannot keep the pipeline's `Bus` open after the `Tee` itself
219/// is gone.
220pub struct Context {
221    /// Sender used by this source and its attached branches for asynchronous
222    /// errors, EOS, drops, and seek completion.
223    pub bus: Bus,
224
225    /// Caller-selected identity of the pipeline currently being wired.
226    pub pipeline_id: Arc<str>,
227
228    /// Shared live topology graph updated by successful attach and detach
229    /// operations.
230    pub graph: PipelineGraph,
231
232    /// Wall-time clock shared by paced elements in this pipeline.
233    pub clock: Arc<Clock>,
234    /// Shared media-position clock used to hand video scheduling from the
235    /// wall clock to an audio output master without changing pipelines.
236    pub playback_clock: Arc<PlaybackClock>,
237    /// Graph identity of the source whose wiring closure owns this context.
238    pub source_id: ElementId,
239}
240
241#[cfg(test)]
242impl Context {
243    pub(crate) fn for_test(
244        bus: Bus,
245        pipeline_id: impl Into<Arc<str>>,
246        graph: PipelineGraph,
247        source_id: ElementId,
248    ) -> Self {
249        let clock = Arc::new(Clock::new());
250        Self {
251            bus,
252            pipeline_id: pipeline_id.into(),
253            graph,
254            playback_clock: Arc::new(PlaybackClock::new(clock.clone())),
255            clock,
256            source_id,
257        }
258    }
259}
260
261/// Anything that can receive a buffer pushed from upstream — the input
262/// side of an element, or a plain terminal sink. Every `Sink` is named
263/// (via `Element`) so bus events (e.g. EOS) can identify which one they
264/// came from.
265///
266/// This is the only "connection" primitive in the pipeline. By default,
267/// consuming a buffer is a plain function call on the caller's thread —
268/// zero overhead. Thread boundaries are introduced explicitly by wrapping
269/// a `Sink` in a [`crate::queue::Queue`], not by elements spawning their
270/// own threads.
271pub trait Sink: Element {
272    /// Processes one buffer synchronously on the caller's thread.
273    ///
274    /// An error is returned directly to upstream until the call crosses a
275    /// [`crate::queue::Queue`] boundary. A queue instead reports the error on
276    /// its [`crate::bus::Bus`], drops that buffer, and keeps its worker alive.
277    /// Implementations must forward [`MediaBuffer::Eos`] after flushing any
278    /// delayed state they own.
279    fn consume(&mut self, buf: MediaBuffer) -> Result<()>;
280
281    /// Reacts to a [`ControlMsg`] (pause/resume/stop) and, for anything
282    /// with a downstream of its own, forwards it on — same shape as
283    /// `consume`, just a separate channel from `MediaBuffer` so it can
284    /// reach every element (not just ones that already know how to
285    /// interpret a data buffer) and, at a [`crate::queue::Queue`], jump
286    /// ahead of whatever data is backed up instead of waiting behind it.
287    /// No default: every `Sink` has to consciously decide what this means
288    /// for it, rather than silently dropping it.
289    fn control(&mut self, msg: ControlMsg) -> Result<()>;
290}
291
292/// An element with one or more output ports. It sends data downstream by
293/// pushing into its own `src_pads()` (e.g. `self.src_pads()[0].push(buf)`)
294/// — it's never handed a `downstream` argument from the outside. See
295/// [`SrcPad`].
296///
297/// `Source` and `Sink` are the two halves of the duality: `Sink` is "has
298/// an input", `Source` is "has an output". An element that both receives
299/// and produces (a decoder, say) implements both side by side — `Sink` to
300/// receive, `Source` to push whatever it produces into its own pad(s)
301/// from inside `consume`. There's no separate "processing element" trait
302/// or wrapper needed for that.
303pub trait Source: Element {
304    /// Returns every output pad owned by this element.
305    ///
306    /// The slice order is the element's public pad-index contract. Implementors
307    /// use the mutable access to push buffers and propagate control; callers
308    /// normally connect pads through [`Context::attach`] instead of linking
309    /// them directly.
310    fn src_pads(&mut self) -> &mut [SrcPad];
311}
312
313/// A pure source: has output but no input. Its `run` method drives the
314/// production loop and pushes buffers into its own src pad(s) until EOS or
315/// an error. [`crate::pipeline::Pipeline::run`] normally invokes that loop
316/// on the pipeline's background source thread; a caller may also invoke a
317/// concrete implementation directly. Sources typically wrap blocking I/O
318/// reads (demuxer, file/network source).
319pub trait SourceElement: Source {
320    /// Drives this source until `Eos` (normal completion),
321    /// [`crate::pipeline::Pipeline::finish`], or `Stop` (see
322    /// [`ControlMsg::Stop`]) — call [`crate::control::drain_control`]
323    /// once per loop iteration to make `control` responsive between
324    /// blocking reads.
325    ///
326    /// `bus` is this source's own way to report a failure pushing into
327    /// one of its pads *without* treating it as fatal — post a
328    /// [`crate::bus::BusEvent::Error`] and keep going (drop that one
329    /// buffer), the same way a [`crate::queue::Queue`] handles a failing
330    /// downstream `Sink` — rather than returning `Err` and ending this
331    /// source's thread over one bad buffer. A returned `Err` is still
332    /// how genuinely fatal failures (this source can't continue at all)
333    /// reach [`crate::pipeline::Pipeline::run`], which posts it to `bus`
334    /// itself.
335    fn run(&mut self, control: &ControlReceiver, bus: &Bus) -> Result<()>;
336
337    /// Repositions this source to `target`, an absolute position from the
338    /// start of the media (e.g. `av_seek_frame` for
339    /// [`crate::elements::FileDemuxer`]). Called by
340    /// [`crate::control::drain_control`] as part of handling
341    /// [`ControlMsg::Seek`], *before* that message is forwarded to the
342    /// source's own pads — so whatever's read next comes from the new
343    /// position by the time downstream elements are told to flush for it.
344    ///
345    /// Returns where this actually landed, which is allowed to differ
346    /// from `target` — a container seek can only ever reposition to a
347    /// keyframe at or before it (landing mid-GOP would leave downstream
348    /// decoders/muxers with no reference frame to start from), so
349    /// `target` is a request, not a guarantee. `drain_control` reports
350    /// the gap between the two via [`crate::bus::BusEvent::Seeked`];
351    /// callers that need to know where playback actually resumed should
352    /// watch that instead of assuming `target` took effect verbatim.
353    fn seek(&mut self, target: Duration) -> Result<Duration>;
354}
355
356/// An element with both an input and an output — decoder, encoder,
357/// filter, thumbnail extractor, ... Just a name for "has a `Sink` to
358/// receive and a `Source` to push what it produces into"; nothing new to
359/// implement beyond those two.
360pub trait Filter: Source + Sink {}
361
362impl<T: Source + Sink> Filter for T {}