Skip to main content

Mp4Muxer

Struct Mp4Muxer 

Source
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

Source

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.

Source

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.

Source

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.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more