High-level Rust bindings for AAC and xHE-AAC encoding and decoding built on top
of libxaac-sys.
An optional python feature also exposes the full high-level API as a PyO3
extension module importable as xaac_rs.
This crate wraps the low-level FFI API exposed by
libxaac-sys
crate and provides a safer, more idiomatic Rust interface for:
- AAC-LC encoding
- HE-AACv1 and HE-AACv2 encoding
- AAC-LD and AAC-ELD encoding
- USAC/xHE-AAC encoder configuration
- Streaming decoder initialization and frame decoding
- Decoder stream metadata and DRC status reporting
- Optional MPEG-D DRC sidecar handling for streams that expose DRC payloads
Basic AAC-LC ADTS encoding:
use xaac_rs::{Encoder, EncoderConfig, OutputFormat};
let mut encoder = Encoder::new(EncoderConfig {
output_format: OutputFormat::Adts,
..EncoderConfig::default()
})?;
let pcm = vec![0i16; encoder.input_frame_bytes() / 2];
let packet = encoder.encode_i16_interleaved(&pcm)?;
assert!(!packet.data.is_empty());
# Ok::<(), xaac_rs::Error>(())Chunked AAC decoding:
use xaac_rs::{DecodeStatus, Decoder, DecoderConfig};
let mut decoder = Decoder::new(DecoderConfig::default())?;
let data: &[u8] = &[];
match decoder.decode_stream_chunk(data)? {
DecodeStatus::Frame(frame) => {
assert!(!frame.pcm.is_empty());
}
DecodeStatus::NeedMoreInput(progress) => {
assert!(!progress.initialized || progress.stream_info.is_some());
}
DecodeStatus::EndOfStream => {}
}
# Ok::<(), xaac_rs::Error>(())The crate includes a runnable example that converts a typical PCM WAV file to AAC ADTS:
cargo run --example convert_wav_to_aac -- input.wav output.aac
cargo run --example convert_wav_to_aac -- input.wav output.aac 192000The example:
- parses RIFF/WAVE input directly
- supports PCM WAV and
WAVE_FORMAT_EXTENSIBLE - supports 16-bit, 24-bit, and 32-bit PCM
- zero-pads the final partial frame before encoding
See examples/convert_wav_to_aac.rs. The Python equivalent lives at examples/python/convert_wav_to_aac.py.
Inspect stream metadata:
cargo run --example file_info -- input.aacDecode a stream incrementally:
cargo run --example decode_stream -- input.aacPython equivalents:
uv run python examples/python/file_info.py input.aac
uv run python examples/python/decode_stream.py input.aac
uv run python examples/python/convert_wav_to_aac.py input.wav output.aacThe decoder API now supports:
decode_stream_chunkfor incremental inputfinishto flush/end the stream explicitlyDecodeStatusforFrame,NeedMoreInput, andEndOfStream- richer
StreamInforeporting, including channel mode, DRC state, preroll, and gain payload metadata
Raw and Mp4Raw decoder modes remain explicit through DecoderTransport plus RawStreamConfig.
Build and install the Python module locally with maturin:
python3 -m venv .venv
.venv/bin/pip install maturin
VIRTUAL_ENV="$PWD/.venv" .venv/bin/maturin build --features python -i .venv/bin/python
.venv/bin/pip install target/wheels/xaac_rs-*.whlExample:
import xaac_rs
config = xaac_rs.EncoderConfig()
config.output_format = xaac_rs.OutputFormat.Adts
encoder = xaac_rs.Encoder(config)
pcm = [0] * (encoder.input_frame_bytes() // 2)
packet = encoder.encode_i16_interleaved(pcm)
decoder = xaac_rs.Decoder()
status = decoder.decode_stream_chunk(packet.data)Main exported types:
EncoderEncoderConfigProfileOutputFormatDecoderDecoderConfigDecoderDrcConfigDecodeStatusDecodeProgressDecodedFrameEncodedPacketEncodedFrameEncoderDrcConfigInverseQuantizationModeError
Verified locally with:
cargo check
cargo test
cargo check --features python
cargo test --features python
cargo check --example convert_wav_to_aac
cargo check --example file_info
cargo check --example decode_stream
uv run python -m unittest discover -s python_tests -v