Documentation
¶
Overview ¶
Package m4a muxes AAC-LC, Opus, or FLAC access units into an MP4/M4A container and demuxes them back out. It is the container half that codecs like go-aac deliberately leave to an external muxer: an edit list (elst) trims the encoder priming so the written file is sample-accurate and gapless. The public surface is stdlib-only; the codec bridges (aacm4a, opusm4a, flacm4a) are optional subpackages. The ISO-BMFF byte mechanics live in the internal/box package, whose layout is fixed by docs/box-layout.md.
Index ¶
Constants ¶
const DefaultEncoderDelay = 1024
DefaultEncoderDelay is the number of leading priming samples an AAC-LC encoder emits before the first real sample. It is go-aac's measured low-level encoder priming (one 1024-sample frame) and is the value used when WriterConfig leaves EncoderDelay at zero.
const DefaultOpusPreSkip = 312
DefaultOpusPreSkip is the pre-skip an Opus encoder emits before the first real sample, in samples at the 48 kHz Opus timescale. It is go-opus's measured value (Encoder.PreSkip) and the value used when a CodecOpus WriterConfig leaves OpusPreSkip at zero.
const NoEdit = -1
NoEdit is the WriterConfig.EncoderDelay sentinel that suppresses the edit list entirely: the writer emits no edts/elst and presents every decoded sample.
Variables ¶
var ( // ErrCorrupt indicates a malformed container: a truncated box, a size field // that overflows the stream, a missing required box (moov, stbl, esds), or // an inconsistent sample table. ErrCorrupt = errors.New("go-m4a: corrupt container") // ErrUnsupported indicates a well-formed MP4 that falls outside the v1 // scope: fragmented input, no AAC-LC audio track, a non-mp4a codec, or an // object type other than AAC-LC. ErrUnsupported = errors.New("go-m4a: unsupported container") // ErrClosed is returned by WriteFrame and Close once the Writer has been // closed. A second Close, or any WriteFrame after Close, reports this // instead of panicking. ErrClosed = errors.New("go-m4a: writer is closed") )
Package-wide sentinel errors. They are returned wrapped (via fmt.Errorf with %w) so callers can match with errors.Is while still getting a descriptive message. The Reader shares these with the Writer, so they live here rather than beside a single implementation.
Functions ¶
This section is empty.
Types ¶
type Codec ¶ added in v0.2.0
type Codec uint8
Codec identifies the audio codec of a track. It is the discriminator the reader reports in Info.Codec and the writer selects with WriterConfig.Codec. The zero value is CodecAACLC, so existing writers that set only ASC keep muxing AAC-LC.
const ( // CodecAACLC is MPEG-4 AAC-LC, carried in an mp4a sample entry with an esds // box holding the AudioSpecificConfig. It is the zero value and the default. CodecAACLC Codec = iota // CodecOpus is Opus, carried in an Opus sample entry with a dOps // OpusSpecificBox, per the Encapsulation of Opus in ISOBMFF. CodecOpus // CodecFLAC is FLAC, carried in a fLaC sample entry with a dfLa FLACSpecificBox // holding the STREAMINFO metadata block, per the Encapsulation of FLAC in // ISOBMFF. CodecFLAC )
type Info ¶
type Info struct {
// SampleRate is the audio sample rate in Hz, derived from the ASC and, when
// the ASC does not carry an explicit rate, the mp4a AudioSampleEntry.
SampleRate int
// Channels is the channel count, normally 1 (mono) or 2 (stereo).
Channels int
// Codec identifies the audio codec of the selected track: CodecAACLC,
// CodecOpus, or CodecFLAC.
Codec Codec
// ASC is the MPEG-4 AudioSpecificConfig from the esds DecoderSpecificInfo,
// suitable for go-aac's pcm.WithRawStream. It is set only for AAC-LC; it is nil
// for Opus and FLAC. Info returns a fresh copy.
ASC []byte
// CodecConfig is the codec-specific configuration recovered from the sample
// entry: the AudioSpecificConfig for AAC-LC (same bytes as ASC), the
// OpusSpecificBox (dOps) body for Opus, or the FLAC STREAMINFO metadata block
// for FLAC. It is what a codec bridge passes to its decoder. Info returns a
// fresh copy.
CodecConfig []byte
// FrameCount is the number of access units (MP4 "samples") in the track.
FrameCount int
// EncoderDelay is the leading priming sample count taken verbatim from the
// edit list media_time. It is 0 when there is no edit list or the first edit
// is an empty edit (media_time -1).
EncoderDelay int64
// Duration is the track presentation duration after the edit list.
Duration time.Duration
// Brand is the ftyp major brand.
Brand string
}
Info summarizes an MP4/M4A file's single audio track (AAC-LC, Opus, or FLAC), populated by NewReader from the moov metadata. The fields come straight from the file's own sample tables, the codec-specific box (esds, dOps, or dfLa), and the edit list; Codec reports which codec, and CodecConfig carries its configuration.
type Reader ¶
type Reader struct {
// contains filtered or unexported fields
}
Reader demuxes a non-fragmented MP4/M4A file (AAC-LC, Opus, or FLAC) into its access units. NewReader parses the moov metadata up front; ReadFrame then returns each access unit in order by seeking to its computed (offset, size). The reader is not safe for concurrent use, and ReadFrame, RawStream, and their shared cursor advance together.
func NewReader ¶
func NewReader(r io.ReadSeeker) (*Reader, error)
NewReader reads and parses the moov metadata from r and returns a Reader positioned at the first access unit. It locates moov whether it precedes or follows mdat, selects the first "soun" track carrying a supported sample entry (mp4a AAC-LC, Opus, or fLaC), and builds the sample geometry from the stsc/stsz/stco tables. It returns a wrapped ErrCorrupt for malformed input and a wrapped ErrUnsupported for well-formed input outside scope (fragmented files, no supported audio track, an unsupported codec, or an AAC object type that is not MPEG-4 Audio).
func (*Reader) ASC ¶
ASC returns a fresh copy of the AudioSpecificConfig, suitable for passing to go-aac's pcm.WithRawStream.
func (*Reader) Info ¶
Info returns a copy of the parsed track summary, including a fresh copy of the ASC so the caller cannot mutate the Reader's state.
func (*Reader) RawStream ¶
RawStream returns an io.Reader that emits each access unit framed as a 2-byte big-endian length prefix followed by the access-unit bytes, exactly the framing go-aac's pcm.WithRawStream consumes. It shares the Reader's cursor with ReadFrame and reports ErrUnsupported if any access unit exceeds 65535 bytes (impossible for AAC-LC, guarded regardless).
func (*Reader) ReadFrame ¶
ReadFrame returns the next access unit in decode order and advances the cursor. It returns io.EOF after the last access unit. A frame whose computed extent falls outside the stream, or a short read, is a wrapped ErrCorrupt.
func (*Reader) ReadFrameInto ¶ added in v0.1.1
ReadFrameInto reads the next access unit into dst and returns its length, advancing the cursor. It is the zero-allocation form of ReadFrame for callers that reuse a buffer across frames. If dst is too small to hold the frame, ReadFrameInto reads nothing, does not advance, and returns the required length with io.ErrShortBuffer, so the caller can grow dst and call again. It returns io.EOF after the last access unit, and a wrapped ErrCorrupt for a frame whose extent falls outside the stream or a short read.
type Writer ¶
type Writer struct {
// contains filtered or unexported fields
}
Writer streams AAC-LC, Opus, or FLAC access units into an MP4/M4A file (selected by WriterConfig.Codec, defaulting to AAC-LC). The on-disk layout is ftyp | mdat | moov: ftyp and the mdat header are written up front, each WriteFrame (or WriteFrameDuration) appends one access unit to the mdat payload, and Close patches the mdat size and writes the moov metadata. It requires an io.WriteSeeker because the mdat size is a placeholder patched once at Close.
func NewWriter ¶
func NewWriter(w io.WriteSeeker, cfg WriterConfig) (*Writer, error)
NewWriter validates cfg for its codec (the AAC-LC ASC against SampleRate and Channels, the Opus rate, or the FLAC STREAMINFO), then writes the ftyp box and the placeholder mdat header to w. It returns an error, prefixed "go-m4a: ", when the writer is nil, the codec configuration is malformed or disagrees with SampleRate or Channels, the sample rate is unsupported, or an initial write fails.
func (*Writer) Close ¶
Close finalizes the file: it patches the streamed mdat largesize, seeks past the payload, and writes the moov metadata (mvhd, trak with tkhd, optional edts/elst, and mdia down to the sample tables). It reports an error if no frames were written or a write fails. After a successful Close a second call returns ErrClosed. A Close that fails on a transient Seek or Write may be retried (WriteFrame stays rejected in between); a Close after a failed WriteFrame returns that latched error and writes nothing.
func (*Writer) WriteFrame ¶
WriteFrame appends one access unit to the mdat payload using the codec's fixed per-sample duration. It works for AAC-LC, whose every AU is 1024 samples. For Opus and FLAC, whose frames vary in duration, it returns an error directing the caller to WriteFrameDuration. It rejects a nil or empty access unit, and any call after Close.
func (*Writer) WriteFrameDuration ¶ added in v0.2.0
WriteFrameDuration appends one access unit to the mdat payload and records its size for the stsz table and sampleDuration (in the media timescale) for the stts table. sampleDuration is the number of samples per channel the access unit decodes to: 1024 for an AAC-LC AU, the packet's 48 kHz sample count for Opus, or the block size for FLAC. It rejects a nil or empty access unit, a zero duration, and any call after Close.
type WriterConfig ¶
type WriterConfig struct {
// Codec selects the audio codec. The zero value is CodecAACLC, so a config
// that sets only ASC keeps muxing AAC-LC. For CodecOpus set OpusPreSkip and
// OpusInputSampleRate (and SampleRate must be 48000); for CodecFLAC set
// STREAMINFO.
Codec Codec
// SampleRate is the audio sample rate in Hz (for example 48000). Required. For
// AAC-LC it must match the rate encoded in ASC; for Opus it must be 48000 (the
// fixed Opus container timescale).
SampleRate int
// Channels is the channel count, 1 (mono) or 2 (stereo). Required, and for
// AAC-LC it must match the channel configuration encoded in ASC.
Channels int
// ASC is the MPEG-4 AudioSpecificConfig (two bytes for AAC-LC). Required for
// CodecAACLC; ignored otherwise. The writer copies the bytes verbatim into the
// esds DecoderSpecificInfo.
ASC []byte
// OpusPreSkip is the Opus pre-skip in samples at 48 kHz (go-opus's
// Encoder.PreSkip). It fills the dOps PreSkip field and the edit-list media
// time. Used only for CodecOpus; zero selects DefaultOpusPreSkip.
OpusPreSkip int
// OpusInputSampleRate is the original source sample rate recorded in the dOps
// InputSampleRate field (informational; Opus always decodes at 48 kHz). Used
// only for CodecOpus; zero selects SampleRate.
OpusInputSampleRate int
// STREAMINFO is the 34-byte FLAC STREAMINFO metadata block, the payload of the
// dfLa box (from go-flac's pcm.FrameEncoder.StreamInfoBytes). Required for
// CodecFLAC; ignored otherwise.
STREAMINFO []byte
// EncoderDelay is the number of leading priming samples to trim with an edit
// list. Zero uses the codec's default priming (DefaultEncoderDelay, 1024, for
// AAC-LC; the resolved OpusPreSkip, default 312, for Opus; 0 for FLAC); NoEdit
// writes no edit list at all; a positive value trims exactly that many samples.
EncoderDelay int
// MediaLength, when greater than zero, is the number of PCM samples per
// channel the source contained. It sets the edit-list segment duration
// exactly, so trailing final-frame padding is also excluded. Zero presents
// every decoded sample after the priming.
MediaLength int64
// Brand overrides the ftyp major brand (default "M4A "). When set it must be
// exactly four bytes (space-padded, for example "mp42"); NewWriter rejects
// any other length. The compatible brands always include "M4A ", "mp42", and
// "isom".
Brand string
}
WriterConfig configures a Writer. SampleRate and Channels must agree with ASC; NewWriter validates them against it and refuses a mismatch.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package aacm4a is an optional convenience bridge that couples go-aac's AAC-LC codec to the go-m4a container.
|
Package aacm4a is an optional convenience bridge that couples go-aac's AAC-LC codec to the go-m4a container. |
|
Package flacm4a is an optional convenience bridge that couples go-flac's FLAC codec to the go-m4a container.
|
Package flacm4a is an optional convenience bridge that couples go-flac's FLAC codec to the go-m4a container. |
|
internal
|
|
|
box
Package box implements the low-level ISO Base Media File Format (ISO/IEC 14496-12) byte primitives and typed marshalers that the go-m4a writer emits.
|
Package box implements the low-level ISO Base Media File Format (ISO/IEC 14496-12) byte primitives and typed marshalers that the go-m4a writer emits. |
|
Package opusm4a is an optional convenience bridge that couples go-opus's Opus codec to the go-m4a container.
|
Package opusm4a is an optional convenience bridge that couples go-opus's Opus codec to the go-m4a container. |