Skip to main content

Crate syom

Crate syom 

Source
Expand description

§syom

AAC to planar f32.

crates.io docs.rs ci license

An AAC codec in Rust. AAC-LC, HE-AAC v1/v2, and AAC-LD. ADTS, LATM/LOAS, M4A, and bounded fragmented MP4. Encode defaults to AAC-LC at 128 kbps, ADTS or M4A. HE and LD are opt-in. Output is planar f32 at the bitstream rate (HE is twice the core rate). The product path pulls no crates. ffmpeg is an offline oracle, not a runtime dependency.

§Examples

fn main() -> syom::Result<()> {
    let pcm: Vec<f32> = (0..48_000).map(|i| 0.3 * (i as f32 * 0.06).sin()).collect();
    let adts = syom::encode(&[&pcm], 48_000)?;
    let back = syom::decode_with(&adts, &syom::DecodeOptions::audio())?;
    assert_eq!((back.channels.len(), back.sample_rate), (1, 48_000));
    Ok(())
}

decode is the speech default (mono mix, 2 h at up to 48 kHz; higher rates keep that sample budget). DecodeOptions::audio() keeps the coded channels. From a path: syom::read. Push decode and encode: Decoder::feed, Encoder::feed. The guide has one compiling example per task.

tasksection
one-call encode / decode, speech vs full fidelity1
borrowed PCM, Read / Write / Seek2
priming, tail, exact length3
push Encoder / Decoder, bounded memory4
raw access units and AudioSpecificConfig5
probe, sample-exact M4A seek6
LC, quality VBR, HE v1/v2, surround7
limits and typed errors8
profiles and containers9
behaviour changes since 0.6.010

§Decode and encode

ADTSM4ALATM/LOASfMP4
AAC-LC decodeyesyesyesyes
HE-AAC v1/v2 decodeyesyesyesyes
AAC-LD decode (512)noyesyesyes
LC encodeyesyesyesno
HE v1/v2 encodeyesyesyesno
AAC-LD encodenoyesyesno

LC encode is the default; M/S is per-band. with_he, with_he_v2, and with_ld are opt-in. ADTS cannot signal AAC-LD. Fragmented MP4 uses the same ASC path as M4A, so AAC-LD decodes there too; there is no separate LD fMP4 golden. Surround LC is 3, 4, 5, 6, or 8 planes (channel_configuration 3–7). Seven planes have no layout. No resample.

§Compared with rusty_aac, Symphonia, oxideav-aac

syomrusty_aac 0.5symphonia 0.6oxideav-aac 0.1.7
JobAAC codecLC decodermedia pipelineADTS decoder
Default depsnonenoneseveraloxideav-core
HE-AAC v1/v2 decodeyessignalledLC coreADTS
AAC-LDyesnonono
M4A / LATM / fMP4yesnoM4A, no fMP4no
LC / HE / LD encodeLC; HE and LD opt-innonono
Outputplanar f32, native rateinterleaved f32packetsinterleaved i16
Duration / RAM capsyesnonono
One call decode(&[u8])yesnonodecode_all

§Speed

Linux x86_64, AMD Ryzen AI 9 HX 370, rustc 1.97.1, taskset -c 0, profile.bench (thin LTO), 20 reps after 4 warmup, 2026-10-01. Same bitstream and the same output shape. Sample checksums differ. A peer that cannot produce that shape is left blank. Older rows of a different protocol: BENCH.md.

Workloadsyomsymphonia 0.6.1rusty_aac 0.5.0oxideav-aac 0.1.7
LC ADTS, 48 kHz mono, 13312 samples72.2 µs123 µs179 ms175 ms
HE-AAC v2 ADTS, 48 kHz stereo, 53248 samples4.61 ms369 ms
LC 5.1 ADTS, 48 kHz, 20480 samples640 µs1.67 s

§Install

[dependencies]
syom = "0.8"

rustc 1.89.

guide | BENCH.md | CHANGELOG

No resample. MIT. AAC patents: NOTICE.

Modules§

guide
Task-oriented guide (TASK-107). Every example here is self-contained — it makes its own PCM — so it runs from the published crate as well as from the repository.

Structs§

BudgetExceeded
Exact-boundary / overflow failure. TASK-24 maps this to a public error.
DecodeOptions
Options for decode_with.
DecodedAac
Decoded AAC at native sample rate (planar f32, mono-mixed or split).
Decoder
Resumable push decoder for ADTS and LATM/LOAS byte streams, bounded fragmented MP4 (init moov + moof/mdat fragments, TASK-125), or raw access units after Decoder::from_asc. Peak PCM RAM is O(frame). Flat M4A/ISOBMFF input is rejected on feed (moov needs random access; use decode_streaming on the full slice).
EncodeInfo
Tallies from a finished streaming encode.
EncodeOptions
Options for encode_with / write_with.
EncodedFrame
One encoded AAC frame.
Encoder
Resumable push encoder: planar f32 chunks in, ADTS, LOAS, or raw units out.
Frame
One decoded AAC frame: planar f32 in [-1, 1], one plane per channel.
FrameMeta
Copy metadata for one decoded frame or a finished stream.
M4aSeek
Seekable M4A source: presentation-sample seek with codec preroll.
MemoryBudgets
Named memory limits. Default is the speech-ingest set.
Probe
Read-only AAC metadata. Copy; no PCM.
StreamInfo
Tallies from a finished stream decode.

Enums§

AacError
Errors produced while sniffing, decoding, or encoding AAC.
BudgetKind
Which budget a BudgetExceeded refers to.
Channel
One output plane’s identity.
ChannelMode
Whether decoded channels are mixed to mono or kept separate.
EncodeContainer
#[non_exhaustive]: further transports may follow.
InputScope
Which compressed-byte policy applies.
Layout
How the plane vector was produced.
LifecycleState
Push Decoder / Encoder used after finish or fail.
MalformedKind
Malformed syntax (CRC, Huffman, lengths). Truncation is AacError::Truncated.
PcmReject
Encoder rejected the PCM domain (not a bitrate/container knob).
ProbeContainer
Advertised transport the probe locked onto.
ProbeDuration
How sure we are about presentation length.
ProbeProfile
Codec profile from the header or ASC. ADTS implicit HE stays Self::Lc (SBR is in-band, not in the 7-byte header). Self::Ld is ER AAC LD (AOT 23, 512- or 480-sample frames). Both grids probe as Self::Ld.
ProbeTrim
Encoder delay and unplayed tail. An ADTS iTunSMPB tag reports Self::Exact only when its counts match the buffered frames (1024 or 2048 samples each). An M4A edit list reports Self::Exact. A stale tag, untagged ADTS, and LATM stay Self::Unknown.
UnsupportedFeature
Unsupported AOT / transport / tool (not malformed syntax).

Constants§

DEFAULT_MAX_BOX_DEPTH
ISOBMFF box nesting depth.
DEFAULT_MAX_BUFFERED_INPUT_BYTES
Streaming Decoder compressed bytes after compact (partial AU + unconsumed).
DEFAULT_MAX_CHANNELS
Output / PCE plane ceiling: product layouts are 1–8 (7.1 since TASK-62); a PCE beyond eight planes is a Format error, not a memory bomb.
DEFAULT_MAX_DECLARED_AU_BYTES
Declared access-unit length (ADTS 13-bit max is 8191; LATM/M4A stsz).
DEFAULT_MAX_DECODE_SAMPLE_RATE
Ceiling when converting duration → a per-channel sample budget.
DEFAULT_MAX_DURATION_SECS
Duration / rate caps for a lecture-length MP4.
DEFAULT_MAX_INDEX_ENTRIES
Sample-table entry count (stsz samples, stts/stsc rows, chunks).
DEFAULT_MAX_INPUT_BYTES
Hard upper bound on a finite compressed buffer or file (1 GiB).
DEFAULT_MAX_METADATA_BYTES
M4A table / box-payload bytes (stsz/stts/stsc/stco plus names).
DEFAULT_MAX_OUTPUT_BYTES
Collected planar f32 cap (4 GiB). Covers 2 h stereo @ 48 kHz; 2 h 5.1 split does not fit (F07). Same default as ryf max_output_bytes.
DEFAULT_MAX_SAMPLE_RATE
DEFAULT_MAX_WORKSPACE_BYTES
Resident codec + compressed-buffer workspace, independent of duration.
MAX_PLANES
Product plane ceiling (crate::DEFAULT_MAX_CHANNELS).

Functions§

allocable_bytes
Vec capacity is isize::MAX bytes. None if planned cannot be a usize length on this target.
check_planned
Exact-boundary: planned == max is allowed; planned == max + 1 is not. Overflow and 32-bit isize::MAX clip are the same class as over-budget. TASK-24/25 map a failed try_reserve to BudgetExceeded — never panic.
decode
Decode ADTS, M4A, LATM/LOAS, or bounded fragmented MP4 with speech defaults.
decode_bytes
Alias of decode.
decode_read
Decode ADTS, LOAS, or bounded fMP4 from a generic Read with speech defaults. Does not materialize the whole stream. Flat M4A is AacError::Unsupported (it needs std::io::Seek).
decode_read_streaming
Stream-decode ADTS, LOAS or bounded fMP4 from reader. Same lifecycle as a push Decoder: feed_read then Decoder::finish. Flat M4A is AacError::Unsupported.
decode_read_with
Decode ADTS, LOAS, or bounded fMP4 from reader under opts. Peak compressed RAM is the streaming resident cap, not the stream duration.
decode_seek
Decode seekable M4A with speech-ingest defaults. Peak compressed RAM is moov plus one access unit.
decode_seek_streaming
Stream-decode M4A from a seekable reader. Peak compressed RAM is the moov box plus one access unit (mdat is skipped, then sampled).
decode_seek_with
Decode seekable M4A under opts.
decode_streaming
Stream-decode a complete in-memory buffer (any container, incl. M4A).
decode_with
Decode ADTS, M4A, LATM/LOAS, or bounded fragmented MP4 under opts.
encode
Encode planar f32 PCM in [-1, 1] to an ADTS stream: AAC-LC at 128 kbps.
encode_with
Encode planar f32 PCM under opts (container, bitrate, lookahead, quality VBR, HE v1/v2, AAC-LD, or the opt-in LC tools).
encode_write
Encode planar PCM incrementally into any std::io::Write sink (TASK-59): ADTS, LOAS, or raw access units are written as they are produced, so the codec workspace stays one frame and no compressed buffer is collected. ADTS and LOAS match [encode_with]. Raw is push-only (crate::UnsupportedFeature::EncodeRawOneShot from one-shot). M4A is crate::UnsupportedFeature::EncodeM4aStreaming.
encode_write_m4a
Encode planar PCM into an M4A written incrementally to a Write + Seek sink (TASK-60): ftyp and an mdat header go out first, every access unit is written as it is produced, and finish seeks back to patch the mdat size and appends moov (sample tables, elst priming, exact presentation duration). Retained memory is one frame of codec state plus 4 bytes per access unit (the stsz index, at most 2^20 units); compressed media is never accumulated. opts.container is ignored — the output is always M4A. Bytes are identical to [encode_with] with EncodeContainer::M4a; offsets are relative to the sink position at entry, so the M4A must start at that position.
input_cap_applies
Finite complete buffers use DEFAULT_MAX_INPUT_BYTES. Streaming feed must not: a lifetime sum is F07 and is a no-go.
mpeg_channels
MPEG default-layout labels (lavc / Table 4.1 order). Empty if cfg is not 1–7. Config 7 (7.1) is FL FR FC LFE BL BR SL SR: ISO calls the third CPE “left/right outside front”; lavc presents it as the side pair, and so does syom.
mux_raw_he_m4a
Mux raw HE v1 access units (push crate::Encoder with EncodeOptions::with_he + EncodeContainer::Raw) into M4A: explicit two-rate ASC, output-rate timeline, elst priming as reported by crate::EncodeInfo::priming.
mux_raw_lc_m4a
Mux raw LC access units into M4A (elst priming 1024, presentation valid_samples).
pcm_bytes
n_ch * n_samples * size_of::<f32>(); None on overflow.
preroll_aus
Extra LC mono/stereo overlap AUs (measured). HE/PS and any channel_configuration above stereo replay from AU 0 (see M4aSeek::seek).
probe
Inspect data under default memory budgets. Does not decode PCM.
probe_with
probe with explicit metadata / AU / channel fences.
read
Read a file and decode it. M4A uses seekable sample access (no whole-mdat load); ADTS/LOAS still cap the file at DEFAULT_MAX_INPUT_BYTES.
read_with
Read a file and decode_with it.
sniff_aac
True if the buffer looks like ADTS, LATM/LOAS, or ISO-BMFF M4A.
sniff_is_adts
Sniff ADTS: 12-bit sync, layer 0, plausible frame length.
sniff_is_isobmff
sniff_is_latm
LOAS syncword 0x2B7 in the first 11 bits.
workspace_lower_bound_bytes
Lower-bound resident workspace (codec state + streaming input buffer). Collected PCM is the output budget, not this.
wrap_adts_au
Wrap one raw_data_block in an ADTS frame (no CRC, fullness 0x7FF). For HE v1 access units pass the core rate (half the input rate): ADTS signals SBR implicitly and the header carries the core rate.
wrap_loas_au
Wrap one raw access unit in a LOAS AudioSyncStream frame whose StreamMuxConfig carries asc (crate::Encoder::asc: 2-byte LC, 3-byte AAC-LD, or 4-byte HE). Every frame is a sync point. An AudioMuxElement above 8191 bytes is an error (LC and HE v1 frames never reach it).
write
Encode to ADTS and write the file.
write_with
Encode under opts and write the file.

Type Aliases§

Result
Result alias for this crate.