Documentation
¶
Overview ¶
Package container defines the demuxer, muxer, and seeker interfaces and the track-routed packet model that wrap codec-level packets (ADR-0005). Import DAG: audio <- codec <- container <- format; codec never imports this package.
Every demuxer obeys the hostile-input invariants: bounded nesting depth, size validation before any allocation, caps on metadata allocations, and a strict progress guarantee (every parse-loop iteration consumes input). Demuxers default tolerant of real-world mess, emitting structured Warnings; strict mode turns those into errors for conformance tests.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ReadFull ¶
ReadFull reads exactly len(p) bytes from src at off. It exists because the io.ReaderAt contract permits a read ending exactly at the end of the source to return io.EOF alongside a full buffer; demuxers that checked only the error would misread that as failure (or worse, as a clean end of stream once the io.EOF is unwrapped upstream). Full reads return nil, short ones io.ErrUnexpectedEOF, and real failures pass through.
func ValidTagKey ¶
ValidTagKey reports whether key is legal as a Vorbis comment field name: printable ASCII 0x20 to 0x7D excluding '=', non-empty. The canonical vocabulary always passes; the check guards the muxers that write caller-supplied keys verbatim, where a stray '=' would corrupt the comment's key/value split and out-of-range bytes violate the spec. Muxers skip an invalid key rather than mangling it.
Types ¶
type Chapter ¶
Chapter is one chapter marker for muxers (and demuxers) that carry chapters. End is zero for start-only chapter forms (Nero chpl), which players read as "until the next chapter, or end of stream".
type Chapterer ¶
type Chapterer interface {
Chapters() []Chapter
}
Chapterer is implemented by demuxers that parse chapter markers, in the same idiom as Warner and Indexer: an honest capability gate rather than a method every demuxer carries, since a container with no chapter form has nothing to answer and does not implement it.
Chapters is a field read, so asking is free: a demuxer that implements this resolved its chapters during the header parse. The parse itself is not free, and an mp4 chapter text track is why: its chapters live in a sample table, which costs one read each. That is the reason they are resolved once, with the header, rather than per caller.
type Contextual ¶
type Contextual interface {
// WithContext returns a Source whose reads honor ctx. The receiver is
// unchanged, so a caller may hold both.
WithContext(ctx context.Context) Source
}
Contextual is implemented by a Source whose reads can be bound to a context, as a network-backed source can. io.ReaderAt has no ctx by construction, so a struct field is the only place one can live; this gate makes that handoff explicit instead of implicit. A file-backed source does not implement it, so the assertion is an honest capability gate rather than a universal wrapper.
The ctx bound here must be the engine's, never a request's. Live pipelines resolve under the server's base context by design, so that read-behind can finish an encode after the client has left; binding a request ctx to a Source would make those reads die on disconnect.
Bind at the outermost Source, before handing it to Open or Probe. A Source may be wrapped internally (skipping a leading ID3v2 tag hides the tag from drivers behind an offsetting wrapper), and such a wrapper carries the binding for free by delegating its reads inward: it need not implement Contextual itself, and does not. The invariant is the ordering, not the delegation. A wrapper that is itself handed to BindContext, rather than wrapping something already bound, silently drops the ctx.
type Demuxer ¶
Demuxer yields a container's tracks and packets. ReadPacket returns the bare io.EOF sentinel after the last packet; consumers compare with ==, so wrapped errors that happen to contain io.EOF in their chain (an I/O failure mid-stream, say) are never mistaken for a clean end. Implementations may reuse pkt.Data across calls; consumers copy what they keep.
type Indexer ¶
type Indexer interface {
// IndexSnapshot serializes the index built so far, or nil when it is
// not worth keeping (too small, or unchanged since RestoreIndex).
IndexSnapshot() []byte
// RestoreIndex adopts a previously snapshotted index and reports
// whether the blob was accepted. Implementations validate the blob
// against the open source and reject anything inconsistent, so a
// stale or foreign blob degrades to a fresh walk, never to bad
// positions.
RestoreIndex(blob []byte) bool
}
Indexer is implemented by demuxers whose seeking builds an expensive source index (exact frame tables, seek tables) worth persisting across sessions: the cacheDir/idx sidecar. Both methods are cheap when there is nothing to do.
type Muxer ¶
type Muxer interface {
Begin(tracks []Track) error
WritePacket(pkt Packet) error
End(trailer codec.Trailer) error
NeedsSeek() bool
}
Muxer writes one audio track to a container. Muxers are single-track by design; track selection happens upstream in the engine, and End takes that track's Trailer for gapless finalization.
A muxer whose NeedsSeek reports true requires a writer it can seek for header back-patching; the engine gives jobs a file and refuses live streams. Muxers with NeedsSeek false write a compliant stream to a plain io.Writer and use seekability, when present, only to improve the result (exact sizes instead of streaming placeholders). Seekability is probed, not read off the method set (see internal/muxseek).
WritePacket must not retain pkt.Data past the call: it writes the payload through, or copies what it holds. This is the reciprocal of the Demuxer contract above, and remux is what makes it load-bearing rather than incidental. An encoder's packets are borrowed for the emit callback alone (see codec.Encoder), and a demuxer's are reused across ReadPacket calls, so a muxer feeding straight from either sees its payload overwritten under it. The corruption would be cross-packet and silent, which no test over a single packet can catch, so the rule is stated rather than left to hold by construction.
type Seeker ¶
Seeker is implemented by demuxers that can reposition. SeekSample lands on the nearest sync point at or before the target sample and returns the landed position; sample-exact landing is format.Media's job, via decode-and-discard pre-roll from there. When the stream has no sync point at or before the target (its first frame starts later, say after tolerated damage at the head), the landing is the earliest sync point and may exceed the target; consumers treat the returned position as authoritative either way.
type Source ¶
Source is random-access input. Demuxers require io.ReaderAt because real files put indexes at either end (the moov-at-end reality); uploads and pipes spool to disk first.
func BindContext ¶
BindContext binds ctx to src when src is Contextual, and returns src unchanged otherwise. It is the assertion side of the Contextual gate, in one place so callers do not each rewrite it.
Pass the owning pipeline's context, not a request's: see Contextual.
func BytesSource ¶
BytesSource wraps an in-memory blob as a Source, mainly for tests and probes of spooled uploads. bytes.Reader already satisfies the interface (ReadAt plus Size).
type Tag ¶
Tag is one canonical metadata field for muxers that can embed tags in their stream form. Keys use the uppercase Vorbis/Picard vocabulary (TITLE, ARTIST, ALBUM, REPLAYGAIN_TRACK_GAIN, ...); each muxer maps the keys it can represent natively and skips the rest silently, since the caller decides what to offer and the format decides what it can hold. A multi-valued field repeats its key, one Tag per value.
type Tagger ¶
Tagger is implemented by demuxers that parse embedded tags, the same capability gate as Chapterer and for the same reason: a container with no tag form has nothing to answer and does not implement it.
Tags is a field read, so asking is free: a demuxer that implements this resolved its tags during the header parse. Keys use the same canonical uppercase vocabulary Tag does, values in file order.
Cover art is deliberately not here. A picture is megabytes, so it cannot be held per demuxer on the streaming path; serving it needs an opt-in accessor rather than a field read, which is the same reason meta.ReadOptions.Pictures exists.
This is not dead code, though it can read that way: container/mp4, container/wv, and container/apen implement it, and the tag library now reads every MP4 shape, so on a mapper-wired route the fold rarely has anything left to add. What it still serves is an embedder that wires no mapper at all, where it is the only tag source there is; for a .wv or a .ape it is the only one either way.
Keep the keys a mapper would also produce. Nothing enforces it: the fold gives the mapper priority per key, so an atom exposed here under a spelling the mapper projects differently surfaces as two tags rather than one.
type Track ¶
type Track struct {
// ID is the track identifier that packets reference: a demuxer must
// tag every Packet.Track with the ID of the Track it belongs to.
ID int
Codec codec.ID
CodecConfig []byte
Fmt audio.Format
// Samples is the track length in samples after gapless trimming, or
// -1 when unknown.
Samples int64
// Delay and Padding are the container-signaled gapless trims
// (LAME tag, iTunSMPB, Opus pre-skip, edit lists), in samples.
Delay int64
Padding int64
// SamplesExact marks Samples as an authoritative hard length the decoder
// must be trimmed to, not an advisory total. Ogg-Vorbis and Ogg-Opus set
// it (the last page granule is exact and the decoder over-produces past
// it); formats whose declared total can lie (a bad FLAC STREAMINFO) leave
// it false so a mismatch stays a tolerated oddity rather than a truncation.
SamplesExact bool
// SourceBitDepth is the depth the source stores samples at when that
// differs from Fmt.BitDepth, 0 when the two agree. Two cases reach it.
// audio.Format carries floats as float32, so a 64-bit float source
// decodes at BitDepth 32 and probing it reports a number the file does
// not hold. And a WavPack stream that stripped constant zero LSBs codes
// a narrower depth than the word width its samples come back in, so a
// 20-bit source decodes in 24-bit words. The pipeline reads Fmt.BitDepth
// as before; only reporting surfaces prefer this.
SourceBitDepth int
// Default marks the container's designated default track.
Default bool
}
Track describes one elementary stream in a container.
type Warner ¶
type Warner interface {
Warnings() []Warning
}
Warner is implemented by demuxers that record Warnings: tolerated damage, or a decoder limitation against a well-formed file.
type Warning ¶
type Warning struct {
// Offset is the byte position of the oddity, -1 when not localized.
Offset int64
Msg string
}
Warning is a structured note about input this decoder accepted but a caller should know about, surfaced through probe results. That covers two kinds: tolerated damage (a truncated table, a sample running past end of file), and a limitation of this decoder against a file that is perfectly well formed (an HE-AAC config whose high band is not synthesized).
The distinction matters to strict mode, which escalates the first kind and not the second: strict exists to reject real-world mess for conformance runs, so it must not reject a conformant file merely because a codec is scoped below it.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package adts demuxes the ADTS elementary stream framing for AAC (ISO/IEC 14496-3 1.A).
|
Package adts demuxes the ADTS elementary stream framing for AAC (ISO/IEC 14496-3 1.A). |
|
Package aiff reads and writes AIFF and AIFF-C, the Apple/SGI audio container.
|
Package aiff reads and writes AIFF and AIFF-C, the Apple/SGI audio container. |
|
Package apen reads and writes native Monkey's Audio framing: the descriptor, format header, and mandatory seek table a .ape file opens with, the run of frames behind them, and the APEv2 tag most files carry after the audio.
|
Package apen reads and writes native Monkey's Audio framing: the descriptor, format header, and mandatory seek table a .ape file opens with, the run of frames behind them, and the APEv2 tag most files carry after the audio. |
|
Package asf demuxes the Advanced Systems Format container, the .wma/.asf file Windows Media Audio ships in: a flat tree of GUID-tagged objects (header, data, index) whose Data Object holds a run of fixed-size packets, each carrying one or more payload fragments that reassemble into media objects.
|
Package asf demuxes the Advanced Systems Format container, the .wma/.asf file Windows Media Audio ships in: a flat tree of GUID-tagged objects (header, data, index) whose Data Object holds a run of fixed-size packets, each carrying one or more payload fragments that reassemble into media objects. |
|
Package flacn demuxes native FLAC framing (RFC 9639): the fLaC marker, metadata blocks, and the self-framing audio stream.
|
Package flacn demuxes native FLAC framing (RFC 9639): the fLaC marker, metadata blocks, and the self-framing audio stream. |
|
internal
|
|
|
apev2
Package apev2 parses APEv2 tags: the key/value block WavPack and Monkey's Audio files carry, almost always appended after the audio.
|
Package apev2 parses APEv2 tags: the key/value block WavPack and Monkey's Audio files carry, almost always appended after the audio. |
|
id3
Package id3 parses the byte length of an ID3v2 tag, from its header at the front of a stream or from the footer of one appended to the back.
|
Package id3 parses the byte length of an ID3v2 tag, from its header at the front of a stream or from the footer of one appended to the back. |
|
srcwin
Package srcwin is the shared read-ahead window demuxers scan through: byte access over a container.Source with chunked read-ahead, forward extension, rebasing, and a sticky I/O error that the owner surfaces on its packet and seek paths.
|
Package srcwin is the shared read-ahead window demuxers scan through: byte access over a container.Source with chunked read-ahead, forward extension, rebasing, and a sticky I/O error that the owner surfaces on its packet and seek paths. |
|
trailer
Package trailer peels the non-audio structures taggers bolt onto the end of a file: an APEv2 tag, an ID3v1 tag, an ID3v2 tag appended after the audio, and NUL padding, stacked in any order.
|
Package trailer peels the non-audio structures taggers bolt onto the end of a file: an APEv2 tag, an ID3v1 tag, an ID3v2 tag appended after the audio, and NUL padding, stacked in any order. |
|
Package mka demuxes Matroska and WebM (ISO/IEC 14496 EBML) audio: the .mka/.mkv/.webm family carrying Opus, Vorbis, FLAC, AAC-LC, or PCM.
|
Package mka demuxes Matroska and WebM (ISO/IEC 14496 EBML) audio: the .mka/.mkv/.webm family carrying Opus, Vorbis, FLAC, AAC-LC, or PCM. |
|
Package mp4 demuxes ISO base media files (ISO/IEC 14496-12) and their QuickTime kin: the .m4a/.m4b/.mp4 family carrying AAC-LC or ALAC audio.
|
Package mp4 demuxes ISO base media files (ISO/IEC 14496-12) and their QuickTime kin: the .m4a/.m4b/.mp4 family carrying AAC-LC or ALAC audio. |
|
Package mpa demuxes the MP3 elementary stream: a bare sequence of Layer III frames, usually wrapped in ID3 tags, often led by a Xing, Info, or VBRI metadata frame.
|
Package mpa demuxes the MP3 elementary stream: a bare sequence of Layer III frames, usually wrapped in ID3 tags, often led by a Xing, Info, or VBRI metadata frame. |
|
Package ogg demuxes Ogg streams (RFC 3533): page parsing with CRC verification, packet reassembly across pages, and per-mapping content handling.
|
Package ogg demuxes Ogg streams (RFC 3533): page parsing with CRC verification, packet reassembly across pages, and per-mapping content handling. |
|
Package riff reads and writes RIFF/WAVE, the WAV container, including the RF64/BW64 64-bit extension: RF64 is always read, and the muxer switches to it automatically when output projects past RIFF's 4 GiB size fields (24-bit/96 kHz audiobooks overflow plain WAV at about two hours; decided here, not discovered in production).
|
Package riff reads and writes RIFF/WAVE, the WAV container, including the RF64/BW64 64-bit extension: RF64 is always read, and the muxer switches to it automatically when output projects past RIFF's 4 GiB size fields (24-bit/96 kHz audiobooks overflow plain WAV at about two hours; decided here, not discovered in production). |
|
Package wv demuxes native WavPack framing: the self-delimiting run of "wvpk" blocks a .wv file is, plus the APEv2 tag most of them carry after the audio.
|
Package wv demuxes native WavPack framing: the self-delimiting run of "wvpk" blocks a .wv file is, plus the APEv2 tag most of them carry after the audio. |