pub trait Demuxer {
type Adapter: DemuxAdapter;
type Buffer: AsRef<[u8]>;
type TrackHandle: Clone + Deref<Target = TrackInfo<Self::Adapter>>;
type Error;
// Required methods
fn tracks(&self) -> &[Self::TrackHandle];
fn next_packet(
&mut self,
) -> Result<Option<DemuxedPacket<Self::Adapter, Self::Buffer>>, Self::Error>;
fn seek(&mut self, target: Timestamp) -> Result<(), Self::Error>;
}Expand description
An opened container session: the track table, a pull loop, and a seek.
§Delivery order
next_packet returns packets in interleaved
file order — the order the container stores them in, tracks mixed
together exactly as written. Ok(None) means end of file, and once
it is returned it stays returned until a seek moves
the session somewhere else.
§Why Option and not Received
The decoders’ three-state answer has a state this face does not:
needs-input cannot happen to a demuxer. A demuxer is pulled, not
fed — there is no caller-supplied input it could be waiting on, so a
NeedsInput arm here would be a state no backend can ever produce
and every consumer would still have to write a match arm for.
Ok(None) is the same fact in the shape that fits: two states, two
values, and the packet itself riding in the Ok arm rather than
into a dst.
What the two faces share is the law, not the type: a protocol
state never travels in Err. End of file is not a failure here
for the same reason Received::Ended is
not one there.
§The attachment contract
An Attachment track delivers exactly
one packet, before any timed packet. Attachments are not on the
timeline, so a consumer must be able to collect them all before it
starts consuming time — a subtitle renderer needs its fonts before
the first cue, and a thumbnailer wants the cover art without reading
the file to its end. Backends satisfy this by synthesising the
packet when the container keeps the payload outside the packet
stream (fonts, whose bytes live in the track’s codec extradata) and
by hoisting the natural one when it exists (cover art, which is a
real packet the container stores).
A track’s identity — the filename it was attached under, its MIME
type — is on TrackInfo, not repeated on every packet.
§Seeking
seek obeys three laws:
- It flushes session state. Anything buffered from before the
seek is discarded; the next
next_packetreads from the new position. - It lands on the nearest keyframe at or before the target. Never after. A decoder fed from a landing point past the target would have no reference frame, so “at or before” is a correctness requirement, not a preference — the caller discards the packets between the landing point and the target itself.
- Attachments are never replayed. An attachment already delivered is not delivered again, however many times the session seeks. One attachment track yields one packet for the life of the session — a seek moves the timeline, and attachments are not on it.
§The track table
tracks is a non-destructive read, and a
session holds its table for its whole life: the rows a caller reads
before the first pull are the same rows the session classifies
every packet against, and they are still there after end of file.
Reading the table therefore has no ordering rule at all — before
the first packet, between two of them, after EOF, twice, never.
The table is shared, not handed over. TrackInfo has no Clone
(see its own doc for the message-carrier law), so a caller that
needs a row beyond a borrow of &self — to fan it out, or simply
to hold it across the &mut self of the pull loop — clones a
TrackHandle instead.
This face used to carry a take_tracks that moved the table out
of the session. It is gone, root and branch: a demuxer that has
given its table away can no longer say which track a packet
belongs to, and the one backend that implemented it classified
against the very Vec the move emptied — so following the
documented order made every packet in a healthy file vanish. A
read that costs the session the state it runs on is not a door
worth having.
§What is not here
Opening. See the module docs.
Required Associated Types§
Sourcetype Adapter: DemuxAdapter
type Adapter: DemuxAdapter
Backend-specific vocabulary.
Sourcetype TrackHandle: Clone + Deref<Target = TrackInfo<Self::Adapter>>
type TrackHandle: Clone + Deref<Target = TrackInfo<Self::Adapter>>
A shareable handle on one row of the track table.
The row is read through the handle, and a consumer that needs
to keep a row past a borrow of the session clones the handle.
The backend picks the carrier, the same way it picks
Buffer: a heap-backed, thread-crossing backend
binds Arc<TrackInfo<..>>, a single-threaded one binds Rc,
and one whose rows live in memory it already borrows binds
&TrackInfo<..> — which is what keeps this whole tier
allocator-free.
Clone on a handle must be a refcount bump or a copied
borrow, never a deep copy of the row — the message-carrier law
TrackInfo states. An implementor is what upholds it; the
bound is what makes upholding it the path of least resistance,
since TrackInfo is not Clone, Box<TrackInfo<_>> therefore
is not either, and no #[derive(Clone)] reaches a carrier that
owns a row outright. A deep copy here would have to be
hand-written against the law.
Required Methods§
Sourcefn tracks(&self) -> &[Self::TrackHandle]
fn tracks(&self) -> &[Self::TrackHandle]
Returns the container’s track table.
Position i describes TrackIndex::new(i) —
the coordinate every DemuxedPacket carries.
Non-destructive, and callable whenever: see the track table on the trait.
Sourcefn next_packet(
&mut self,
) -> Result<Option<DemuxedPacket<Self::Adapter, Self::Buffer>>, Self::Error>
fn next_packet( &mut self, ) -> Result<Option<DemuxedPacket<Self::Adapter, Self::Buffer>>, Self::Error>
Pulls the next packet in interleaved file order, or Ok(None) at
end of file.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".