1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
//! A small, GStreamer-flavored media pipeline library built on
//! [`ffmpeg-next`](https://docs.rs/ffmpeg-next).
//!
//! A pipeline has one or more [`SourceElement`](element::SourceElement)s,
//! each feeding a graph of [`Filter`](element::Filter)s that ends in a
//! [`Sink`](element::Sink):
//!
//! ```text
//! FileDemuxer -> SwDecoder -> Queue -> Pacer -> FrameCounter
//! ```
//!
//! Each source registered with a [`Pipeline`](pipeline::Pipeline) runs on its
//! own background thread. Within that source's graph,
//! [`Sink::consume`](element::Sink::consume) is otherwise a plain synchronous
//! call that returns [`Result`], so a stage's failure propagates straight back
//! up the call stack with `?`. A [`Queue`](queue::Queue) adds another explicit
//! thread boundary inside a branch: it owns a worker thread and a bounded
//! channel, which is also where error handling changes shape — past that
//! boundary a downstream failure can no longer be returned to the pusher, so
//! it is reported on the [`Bus`](bus::Bus) as
//! [`BusEvent::Error`](bus::BusEvent::Error) and the worker keeps going.
//!
//! ```no_run
//! use std::{sync::atomic::Ordering, time::Duration};
//!
//! use media_pp::{
//! elements::{FrameCounter, TestVideoOptions, TestVideoSource},
//! pipeline::Pipeline,
//! };
//!
//! # fn main() -> media_pp::Result<()> {
//! media_pp::init()?;
//!
//! let source = TestVideoSource::new("source", TestVideoOptions::default());
//! let (counter, frames) = FrameCounter::new("counter");
//!
//! let pipeline = Pipeline::new("demo", source, |source, ctx| {
//! let branch = ctx.branch().to(Box::new(counter))?;
//! ctx.attach(source, 0, branch)?;
//! Ok(())
//! })?;
//!
//! pipeline.run()?;
//! std::thread::sleep(Duration::from_millis(200));
//! pipeline.stop();
//!
//! println!("frames: {}", frames.load(Ordering::Relaxed));
//! # Ok(())
//! # }
//! ```
//!
//! # Where to start
//!
//! - [`elements`] is the inventory of built-in sources, filters, and sinks.
//! Each type's own documentation states what buffers it accepts, what it
//! owns, and how it behaves under error and runtime control.
//! - [`pipeline`] builds and runs a graph; [`element`] and [`pad`] are the
//! traits and the one output port everything is wired through.
//! - [`buffer`] is what travels between elements, [`control`] is what
//! Pause/Resume/Stop/Seek travel through, and [`bus`] is how an element
//! reports something the caller could not have been handed directly.
//!
//! # Buffer and timeline contract
//!
//! [`MediaBuffer`](buffer::MediaBuffer) payloads are `Arc`-wrapped, so
//! fan-out clones a reference rather than the media itself. PTS, duration,
//! packet time bases, and video color information survive every stage that
//! does not deliberately create a new timeline.
//!
//! [`Eos`](buffer::MediaBuffer::Eos) is data, and it is forwarded like data:
//! stateful stages (encoders holding delayed frames, muxers, resamplers)
//! flush on it before passing it on. That is what separates the two ways a
//! pipeline ends — [`Pipeline::finish`](pipeline::Pipeline::finish) sends
//! ordered EOS from the source and drains everything behind it, while
//! [`Pipeline::stop`](pipeline::Pipeline::stop) abandons buffered work.
//!
//! # Features and platforms
//!
//! The crate has no default features. Hardware backends (`d3d11`, `d3d12`,
//! `dxgi-capture`, `cuda`, `wasapi-*`, `pipewire-*`) and the optional `ort`
//! and `webrtc` integrations are each behind their own Cargo feature, and
//! backend-specific types carry the backend's prefix. [docs.rs] builds this
//! crate for Linux and therefore omits the Windows-only API; the complete
//! reference is published separately (see the repository README).
//!
//! # Logging
//!
//! Diagnostics never install a global `log` logger or `tracing` subscriber.
//! The file logger in [`log`] is private and opt-in through
//! [`log::init`], and the caller owns the returned guard for as long as
//! records must keep being written and flushed.
//!
//! [docs.rs]: https://docs.rs/media-pp
// docs.rs passes `--cfg docsrs` (see `package.metadata.docs.rs`), which labels
// every feature-gated item with the Cargo feature that enables it. Stable
// builds never see the `feature` attribute.
// Flat re-export: `core/` only exists to group these files on disk (see
// its module doc) — every external and internal caller keeps using
// `crate::pipeline`/`media_pp::pipeline` etc., never `crate::core::...`.
pub use ;
// Same flat-namespace reasoning as above, but crate-private: `schedule`/
// `time` are pacing/rescale internals `crate::elements` builds on, not
// exposed in any public element's own field/method signature — nothing
// downstream of this crate needs `PeriodicSchedule`/`ActiveTimeline`/
// `MediaTimestamp`/`TimeBase` itself. `pub(crate) use` keeps the same
// `crate::schedule`/`crate::time` paths working for every internal caller
// without also making them part of this crate's external API surface.
pub use ;
pub use ;
/// The [`ffmpeg-next`](https://docs.rs/ffmpeg-next) this crate is built on.
///
/// Re-exported because it is part of this crate's API, not an implementation
/// detail behind it: [`MediaBuffer`](buffer::MediaBuffer) carries `ffmpeg`
/// packets and frames directly, an encoder's `parameters()`/`time_base` are
/// `ffmpeg` types, and [`Error::Ffmpeg`] wraps `ffmpeg`'s own error.
///
/// Use this rather than depending on `ffmpeg-next` separately. A separate
/// dependency has to resolve to the same version as this crate's — when it
/// does not, the two `ffmpeg-next`s are distinct crates to the compiler and
/// every one of the types above stops matching, with nothing in the error
/// pointing at the version as the cause.
pub use ffmpeg_next as ffmpeg;
/// Must be called once before using any element that touches ffmpeg.