pub struct Mp4Muxer { /* private fields */ }Expand description
Builds an MP4 (or any other container ffmpeg infers from path’s
extension) with one or more tracks, then opens it into one Sink per
track. Two-phase on purpose: a container’s header has to describe
every stream’s codec parameters up front — avformat_write_header
can’t run until every Mp4Muxer::add_stream this file will ever hold
has already happened — so there’s no way to make this a single
long-lived Sink that tracks attach to one at a time as their encoders
come online (contrast crate::elements::AudioMixer, whose inputs
can attach at any time — it has no “known shape before the first
byte” constraint the way a container header does).
let mut muxer = Mp4Muxer::create("out.mp4")?;
muxer.add_stream("video", video_encoder.parameters(), video_time_base)?;
muxer.add_stream("audio", audio_encoder.parameters(), audio_time_base)?;
let mut sinks = muxer.open()?; // writes the header
let audio_sink = sinks.pop().unwrap();
let video_sink = sinks.pop().unwrap();Implementations§
Source§impl Mp4Muxer
impl Mp4Muxer
Sourcepub fn create(path: impl AsRef<Path>) -> Result<Self>
pub fn create(path: impl AsRef<Path>) -> Result<Self>
Allocates the output file. No header is written yet — nothing is on
disk in a readable shape until Mp4Muxer::open runs.
Sourcepub fn add_stream(
&mut self,
name: impl Into<String>,
parameters: Parameters,
time_base: Rational,
) -> Result<()>
pub fn add_stream( &mut self, name: impl Into<String>, parameters: Parameters, time_base: Rational, ) -> Result<()>
Registers one more track this file will hold. parameters/
time_base describe it — typically
crate::elements::SwEncoder::parameters/the same time_base
passed to its own SwEncoderOptions (or the
crate::elements::SwAudioEncoder equivalents). name becomes
this track’s own Element::name/pp_log identity once
Mp4Muxer::open turns it into a Sink — pick something that
tells multiple tracks apart in logs/crate::bus::BusEvents,
e.g. "video"/"audio".
Add streams in the same order the caller will treat
Mp4Muxer::open’s returned Vec — index 0 is whichever stream
was added first, and so on.
Sourcepub fn open(self) -> Result<Vec<Box<dyn Sink>>>
pub fn open(self) -> Result<Vec<Box<dyn Sink>>>
Writes the container header — every Mp4Muxer::add_stream call
this file will ever get must already have happened — and returns
one Sink per track, in the order Mp4Muxer::add_stream added
them.
All returned Sinks write into the same underlying file behind a
shared lock: packets from independently-threaded branches (e.g. a
video encode chain and an audio encode chain, each on their own
crate::queue::Queue) can arrive concurrently, and neither
av_interleaved_write_frame nor av_write_trailer is safe to call
from multiple threads against the same file at once. They also
share one trailer: it’s written once every track has reported
itself done — via Eos or ControlMsg::Stop, either meaning
“this track is finished” rather than “abandon the whole file” —
not on whichever track finishes first, which would silently
truncate whatever the other track(s) still had left to write. A
single-track file (e.g. screen_record/audio_record) degenerates
to finalizing on that one track’s own Eos/Stop, same as before
this type supported more than one.
A caller driving multiple tracks from independent
crate::pipeline::Pipelines (today’s architecture: one
SourceElement per pipeline, so a live video capture and a live
audio capture are necessarily two separate pipelines) is
responsible for stopping all of them — the file’s trailer only
gets written once every track has actually reported done, so
stopping only one pipeline while another keeps running leaves the
file un-finalized (and unplayable) until the rest catch up too.