pub struct CarrierDemuxer<C: FfmpegCarrier> { /* private fields */ }Expand description
mediadecode::demuxer::Demuxer impl wrapping ffmpeg::format::context::Input.
Construction is deliberately not on the trait — see Self::open
and Self::open_reader.
Implementations§
Source§impl CarrierDemuxer<View>
impl CarrierDemuxer<View>
Sourcepub fn open<P: AsRef<Path> + ?Sized>(path: &P) -> Result<Self, DemuxError>
pub fn open<P: AsRef<Path> + ?Sized>(path: &P) -> Result<Self, DemuxError>
Opens a container from a filesystem path.
Runs avformat_open_input followed by
avformat_find_stream_info, then builds the track table and
captures every attachment payload.
Call ffmpeg_next::init once before the first open if you
want FFmpeg’s logging and network protocols configured;
probing a local container does not require it.
Sourcepub fn open_with<P: AsRef<Path> + ?Sized>(
path: &P,
limits: DemuxLimits,
) -> Result<Self, DemuxError>
pub fn open_with<P: AsRef<Path> + ?Sized>( path: &P, limits: DemuxLimits, ) -> Result<Self, DemuxError>
Self::open, with the session’s resource budgets named.
The budgets are taken at open rather than through a
with_* builder because the attachment half of them is spent
here: every attachment payload is captured during this call.
Sourcepub fn open_reader<R: Read + Seek + Send + 'static>(
reader: R,
url: Option<&str>,
) -> Result<Self, DemuxError>
pub fn open_reader<R: Read + Seek + Send + 'static>( reader: R, url: Option<&str>, ) -> Result<Self, DemuxError>
Opens a container from any Read + Seek source.
Sourcepub fn open_reader_with<R: Read + Seek + Send + 'static>(
reader: R,
url: Option<&str>,
limits: DemuxLimits,
) -> Result<Self, DemuxError>
pub fn open_reader_with<R: Read + Seek + Send + 'static>( reader: R, url: Option<&str>, limits: DemuxLimits, ) -> Result<Self, DemuxError>
Self::open_reader, with the session’s budgets named.
Sourcepub const fn limits(&self) -> DemuxLimits
pub const fn limits(&self) -> DemuxLimits
The budgets this session was opened with.
Sourcepub const fn format(&self) -> Option<&ContainerFormat>
pub const fn format(&self) -> Option<&ContainerFormat>
What the container IS, as libavformat identified it from the bytes — the demuxer it chose, with the short names that demuxer handles and its description.
Decided during the open and fixed for the life of the session, so this answers the same thing at any point and costs nothing to ask.
None only where libavformat left iformat null or its name
is not readable text; neither happens on a session that
opened successfully.
Nothing here looked at a path. A file’s extension is a
claim about its bytes, and this is a reading of them — which
is what makes the answer usable on a content-addressed row,
where the same bytes under two names are one content. See
ContainerFormat for what the
demuxer’s name does and does not narrow to.
Source§impl CarrierDemuxer<Owned>
impl CarrierDemuxer<Owned>
Sourcepub fn open<P: AsRef<Path> + ?Sized>(path: &P) -> Result<Self, DemuxError>
pub fn open<P: AsRef<Path> + ?Sized>(path: &P) -> Result<Self, DemuxError>
Opens a container from a filesystem path.
Runs avformat_open_input followed by
avformat_find_stream_info, then builds the track table and
captures every attachment payload.
Call ffmpeg_next::init once before the first open if you
want FFmpeg’s logging and network protocols configured;
probing a local container does not require it.
Sourcepub fn open_with<P: AsRef<Path> + ?Sized>(
path: &P,
limits: DemuxLimits,
) -> Result<Self, DemuxError>
pub fn open_with<P: AsRef<Path> + ?Sized>( path: &P, limits: DemuxLimits, ) -> Result<Self, DemuxError>
Self::open, with the session’s resource budgets named.
The budgets are taken at open rather than through a
with_* builder because the attachment half of them is spent
here: every attachment payload is captured during this call.
Sourcepub fn open_reader<R: Read + Seek + Send + 'static>(
reader: R,
url: Option<&str>,
) -> Result<Self, DemuxError>
pub fn open_reader<R: Read + Seek + Send + 'static>( reader: R, url: Option<&str>, ) -> Result<Self, DemuxError>
Opens a container from any Read + Seek source.
Sourcepub fn open_reader_with<R: Read + Seek + Send + 'static>(
reader: R,
url: Option<&str>,
limits: DemuxLimits,
) -> Result<Self, DemuxError>
pub fn open_reader_with<R: Read + Seek + Send + 'static>( reader: R, url: Option<&str>, limits: DemuxLimits, ) -> Result<Self, DemuxError>
Self::open_reader, with the session’s budgets named.
Sourcepub const fn limits(&self) -> DemuxLimits
pub const fn limits(&self) -> DemuxLimits
The budgets this session was opened with.
Sourcepub const fn format(&self) -> Option<&ContainerFormat>
pub const fn format(&self) -> Option<&ContainerFormat>
What the container IS, as libavformat identified it from the bytes — the demuxer it chose, with the short names that demuxer handles and its description.
Decided during the open and fixed for the life of the session, so this answers the same thing at any point and costs nothing to ask.
None only where libavformat left iformat null or its name
is not readable text; neither happens on a session that
opened successfully.
Nothing here looked at a path. A file’s extension is a
claim about its bytes, and this is a reading of them — which
is what makes the answer usable on a content-addressed row,
where the same bytes under two names are one content. See
ContainerFormat for what the
demuxer’s name does and does not narrow to.
Trait Implementations§
Source§impl Demuxer for CarrierDemuxer<View>
impl Demuxer for CarrierDemuxer<View>
Source§fn tracks(&self) -> &[TrackArc<TrackInfo<Ffmpeg>>]
fn tracks(&self) -> &[TrackArc<TrackInfo<Ffmpeg>>]
The track table, held for the life of the session.
A row’s duration is libavformat’s figure for the stream as it
stood after avformat_open_input and before
avformat_find_stream_info. It is no claim about the file — a
format’s reader may compute it itself — and a value that
appears only after probing is libavformat’s fill, which hands a
stream that supplied no timing the container’s length, so it is
not carried; neither is one for a stream libavformat creates
during probing. The last packet end this backend observed on
the track’s timeline is measured_end;
a length needs the track’s start and its presentation edits
applied, which is the composer’s job.
Reading the table takes nothing away — clone the handles worth
keeping. Arc is the carrier because
CodecTicket mirrors an
AVCodecParameters into owned Rust, which is what makes a
row Send + Sync and a table shareable across tasks.
Source§fn chapters(&self) -> &[Chapter<Ffmpeg>]
fn chapters(&self) -> &[Chapter<Ffmpeg>]
The container’s chapter table, in the order
AVFormatContext.chapters holds it, mirrored at open and
held for the life of the session.
Empty where the file declares no chapters — which is the provided answer too, so the override changes nothing for a container that has none.
Nothing is repaired. A chapter whose end precedes its
start, and one whose end libavformat left at its
no-timestamp sentinel because the file declared none, are
mirrored exactly as written; see Chapter for why this
layer reports rather than clamps.
Source§fn duration(&self) -> Option<ContainerDuration>
fn duration(&self) -> Option<ContainerDuration>
The container-level duration with libavformat’s account of it,
from AVFormatContext.duration and
AVFormatContext.duration_estimation_method, read once at
open and held for the life of the session.
The container’s figure, never a track’s: Matroska reports a
length here and none on any track, and the tracks’ rows keep
saying so. None where libavformat holds no positive figure.
The figure is counted in AV_TIME_BASE ticks — microseconds —
and carried in that timebase, not rescaled. The account is
libavformat’s own, word for word: FROM_PTS is
FromPts, FROM_STREAM is
FromStream, FROM_BITRATE is
FromBitrate, and a method this
build does not name is Unknown.
Source§fn measured_end(&self, track: TrackIndex) -> Option<MeasuredEnd>
fn measured_end(&self, track: TrackIndex) -> Option<MeasuredEnd>
Where track’s packets ended, as this session’s walk measured
it: the greatest pts + duration over the timed packets read
on it, in the track’s own timebase.
The figure is an endpoint on the track’s own timeline, not a
length. The container’s duration is a length, and the two
are different quantities: a track that starts at ten seconds
and runs for two ends at twelve. Turning an end into a length
means subtracting the track’s start — the backend’s
TrackExtra::start_time
is AVStream.start_time as it stands after probing, which
libavformat may itself have filled in — and honouring
presentation edits, which is the composer’s job and not this
crate’s. The figure’s own promise is only that it is exact when
MeasuredEnd::exact says so, and covers what
MeasuredEnd::walk_complete says.
A packet that carries no duration contributes its pts
alone; libavformat derives a duration from the stream’s frame
rate or frame size for most packets whose demuxer wrote none,
so that is the rare case. A packet with no pts moves no end.
A timed packet with no payload still counts: it is timed
before the payload conversion runs, because it is a real
endpoint and a later one is the end. Nothing is read for this
and nothing is sought: the figure rides the pulls the caller
makes.
Exactness. MeasuredEnd::exact turns false, for good,
the first time a timed packet on the track is read with a
duration that is not positive (libavformat writes zero for one
it does not know) or a packet on it is read with no usable
pts. The mark is made when the packet is read, before the
payload conversion, so it does not depend on whether the packet
is then delivered, refused or parked, nor on whether it carries
a payload. A packet with no usable duration advances the end to
its pts only; either way the figure is a lower bound. A
duration libavformat derived from the stream’s frame rate or
frame size counts as a duration, and is only as exact as that
derivation.
Completeness. MeasuredEnd::walk_complete holds once a
walk that skipped nothing has answered Ok(None), and a
complete walk is frozen: a later read or seek neither moves
its figures nor takes the flag back. The walk stops being
complete for good, before it completes, at a
seek and at every packet av_read_frame
produced that this session did not observe: refused and
dropped, skipped as corrupt (AVERROR_INVALIDDATA), or on a
stream the table never described — which is what a container
that adds streams after open (MPEG-TS, RTP) produces, so a
session that read a packet on a grown stream never answers
complete. Accounting for such streams as they appear is not
done here. A cover picture’s duplicate packet, whose one
delivery happened at open, and an untimed empty packet lose
nothing and do not break the walk (the untimed one still costs
the track its exactness). After a break the
figure keeps rising as a “so far” maximum and stays a lower
bound.
What it does not cover. libavformat probes while the container opens, before this session’s first read. It buffers the packets it reads and replays them, but a read error it swallows during probing is not exposed anywhere, so data skipped there is invisible and a complete walk does not vouch for it.
An attachment track answers None, and so does a track whose
end does not fit in an i64, which breaks the walk as well.
Source§fn next_packet(
&mut self,
) -> Result<Option<DemuxedPacket<Ffmpeg, Self::Buffer>>, DemuxError>
fn next_packet( &mut self, ) -> Result<Option<DemuxedPacket<Ffmpeg, Self::Buffer>>, DemuxError>
Pulls the next packet.
A refusal that another attempt could survive costs no
packet. av_read_frame advances the container, so a
conversion that then fails on an allocation would otherwise
drop bytes nothing can ask for again. Such a packet is parked
instead, and this method re-attempts it before reading
another — so a caller who pulls again loses nothing. A refusal
about the packet itself is not parked: retrying a malformed
packet forever would be worse than passing it by.
Source§type Buffer = <View as FfmpegCarrier>::Buffer
type Buffer = <View as FfmpegCarrier>::Buffer
Source§type TrackHandle = Arc<TrackInfo<Ffmpeg>>
type TrackHandle = Arc<TrackInfo<Ffmpeg>>
Source§type Error = DemuxError
type Error = DemuxError
Source§impl Demuxer for CarrierDemuxer<Owned>
impl Demuxer for CarrierDemuxer<Owned>
Source§fn tracks(&self) -> &[TrackArc<TrackInfo<Ffmpeg>>]
fn tracks(&self) -> &[TrackArc<TrackInfo<Ffmpeg>>]
The track table, held for the life of the session.
A row’s duration is libavformat’s figure for the stream as it
stood after avformat_open_input and before
avformat_find_stream_info. It is no claim about the file — a
format’s reader may compute it itself — and a value that
appears only after probing is libavformat’s fill, which hands a
stream that supplied no timing the container’s length, so it is
not carried; neither is one for a stream libavformat creates
during probing. The last packet end this backend observed on
the track’s timeline is measured_end;
a length needs the track’s start and its presentation edits
applied, which is the composer’s job.
Reading the table takes nothing away — clone the handles worth
keeping. Arc is the carrier because
CodecTicket mirrors an
AVCodecParameters into owned Rust, which is what makes a
row Send + Sync and a table shareable across tasks.
Source§fn chapters(&self) -> &[Chapter<Ffmpeg>]
fn chapters(&self) -> &[Chapter<Ffmpeg>]
The container’s chapter table, in the order
AVFormatContext.chapters holds it, mirrored at open and
held for the life of the session.
Empty where the file declares no chapters — which is the provided answer too, so the override changes nothing for a container that has none.
Nothing is repaired. A chapter whose end precedes its
start, and one whose end libavformat left at its
no-timestamp sentinel because the file declared none, are
mirrored exactly as written; see Chapter for why this
layer reports rather than clamps.
Source§fn duration(&self) -> Option<ContainerDuration>
fn duration(&self) -> Option<ContainerDuration>
The container-level duration with libavformat’s account of it,
from AVFormatContext.duration and
AVFormatContext.duration_estimation_method, read once at
open and held for the life of the session.
The container’s figure, never a track’s: Matroska reports a
length here and none on any track, and the tracks’ rows keep
saying so. None where libavformat holds no positive figure.
The figure is counted in AV_TIME_BASE ticks — microseconds —
and carried in that timebase, not rescaled. The account is
libavformat’s own, word for word: FROM_PTS is
FromPts, FROM_STREAM is
FromStream, FROM_BITRATE is
FromBitrate, and a method this
build does not name is Unknown.
Source§fn measured_end(&self, track: TrackIndex) -> Option<MeasuredEnd>
fn measured_end(&self, track: TrackIndex) -> Option<MeasuredEnd>
Where track’s packets ended, as this session’s walk measured
it: the greatest pts + duration over the timed packets read
on it, in the track’s own timebase.
The figure is an endpoint on the track’s own timeline, not a
length. The container’s duration is a length, and the two
are different quantities: a track that starts at ten seconds
and runs for two ends at twelve. Turning an end into a length
means subtracting the track’s start — the backend’s
TrackExtra::start_time
is AVStream.start_time as it stands after probing, which
libavformat may itself have filled in — and honouring
presentation edits, which is the composer’s job and not this
crate’s. The figure’s own promise is only that it is exact when
MeasuredEnd::exact says so, and covers what
MeasuredEnd::walk_complete says.
A packet that carries no duration contributes its pts
alone; libavformat derives a duration from the stream’s frame
rate or frame size for most packets whose demuxer wrote none,
so that is the rare case. A packet with no pts moves no end.
A timed packet with no payload still counts: it is timed
before the payload conversion runs, because it is a real
endpoint and a later one is the end. Nothing is read for this
and nothing is sought: the figure rides the pulls the caller
makes.
Exactness. MeasuredEnd::exact turns false, for good,
the first time a timed packet on the track is read with a
duration that is not positive (libavformat writes zero for one
it does not know) or a packet on it is read with no usable
pts. The mark is made when the packet is read, before the
payload conversion, so it does not depend on whether the packet
is then delivered, refused or parked, nor on whether it carries
a payload. A packet with no usable duration advances the end to
its pts only; either way the figure is a lower bound. A
duration libavformat derived from the stream’s frame rate or
frame size counts as a duration, and is only as exact as that
derivation.
Completeness. MeasuredEnd::walk_complete holds once a
walk that skipped nothing has answered Ok(None), and a
complete walk is frozen: a later read or seek neither moves
its figures nor takes the flag back. The walk stops being
complete for good, before it completes, at a
seek and at every packet av_read_frame
produced that this session did not observe: refused and
dropped, skipped as corrupt (AVERROR_INVALIDDATA), or on a
stream the table never described — which is what a container
that adds streams after open (MPEG-TS, RTP) produces, so a
session that read a packet on a grown stream never answers
complete. Accounting for such streams as they appear is not
done here. A cover picture’s duplicate packet, whose one
delivery happened at open, and an untimed empty packet lose
nothing and do not break the walk (the untimed one still costs
the track its exactness). After a break the
figure keeps rising as a “so far” maximum and stays a lower
bound.
What it does not cover. libavformat probes while the container opens, before this session’s first read. It buffers the packets it reads and replays them, but a read error it swallows during probing is not exposed anywhere, so data skipped there is invisible and a complete walk does not vouch for it.
An attachment track answers None, and so does a track whose
end does not fit in an i64, which breaks the walk as well.
Source§fn next_packet(
&mut self,
) -> Result<Option<DemuxedPacket<Ffmpeg, Self::Buffer>>, DemuxError>
fn next_packet( &mut self, ) -> Result<Option<DemuxedPacket<Ffmpeg, Self::Buffer>>, DemuxError>
Pulls the next packet.
A refusal that another attempt could survive costs no
packet. av_read_frame advances the container, so a
conversion that then fails on an allocation would otherwise
drop bytes nothing can ask for again. Such a packet is parked
instead, and this method re-attempts it before reading
another — so a caller who pulls again loses nothing. A refusal
about the packet itself is not parked: retrying a malformed
packet forever would be worse than passing it by.