- craft-media: Mp4Writer counts written bytes with a checked sum, so a
writer that takes bytes past the last position gets an error, not an
overflow (correction to round 3, which checked only the header).
- Docs: the AAC bit-rate floor keeps a margin above where the encoder
codes silence, about half of it.
Refs #1230
- craft-media: Mp4Writer::new refuses a writer positioned where the header
would end past u64::MAX instead of overflowing the sum (correction to
round 2, which let the M4A writer reach that addition).
- AAC is written at 6 kbit/s or a quarter of the sample rate per channel at
least: the encoder accepts lower rates but codes only silence at them, so
with_bitrate(128) gave a silent file.
- README: what to do with a layout a coded format refuses, and the names
encode_format_for takes for M4A.
Refs #1230
- craft-media: Mp4Writer counts chunk offsets from the first byte of the
file, not from position 0 of the writer, so a file begun mid-writer is
valid. This replaces the seek adapter the M4A writer wrapped its sink in.
- Tests pin the bytes of the roll sample group and each format's feature.
- Docs: ALAC's length comes from the sample durations, not an edit list;
which readers take an empty AAC file; speaker names as the errors print
them; craft-media's README lists roll_distance.
- Error messages for a layout a format has not no longer suggest setting
a layout that was set.
Refs #1230
- craft-media: TrackConfig::roll_distance writes a `roll` sample group
(sgpd + sbgp) over every sample. The AAC M4A track sets -1: Apple's
decoders took 2112 frames of priming and dropped the start of the audio
without it (afinfo now reports the frames written and 1024 priming).
- EncodeFormat::is_built and feature: which formats this build writes.
- Clippy: the writer enum's variants differ in size with flac-encode and
a codec feature but no pcm-encode.
- Tests for the finished sample entry (AAC bit rate, ALAC cookie), ALAC
dither and afinfo's reading of the priming.
- README: ffmpeg's reading of 8-channel AAC, and files with no audio.
Refs #1230
EncodeFormat gains Aac and Alac (M4A through craft-media's MP4 muxer) and
Mp3, Ac3 and Eac3 (raw streams), so one call writes any of them from
WAV-order f32 audio and EncodeOptions.
- EncodeOptions::rate_control (with_bitrate, with_quality): a bit rate is
moved to the nearest one the stream can carry; quality is AAC's VBR.
- Channels are mapped onto the codec's order by speaker, from
EncodeOptions::layout. A layout the format has not is Unsupported
instead of reaching the wrong speakers.
- M4A: the edit list skips the AAC priming, and the last sample's duration
is cut so the track ends at the last frame written.
- encode_format_for, ENCODE_EXTENSIONS and EncodeFormat::ALL list the new
formats; aac-encode and alac-encode now turn on craft-media's isobmff.
Refs #1230
- `Encoder::with_application` checks the channel count before clamping
the bitrate, so 86 channels or more return `Error::Channels` instead
of panicking in `clamp`. Tested with 86 and 255.
- The ffmpeg oracle test skips a missing `opus`/`libopus` decoder
through the testkit's `skip`, so `CRAFT_MEDIA_REQUIRE_ORACLES=1` fails
it.
- README: the encode example pads at least the pre-skip after the audio
before rounding up to a frame, so the encoder delay is flushed; the
MP4 note says an explicit edit replaces the `media_start` edit and
gives its fields.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
EffectCraft's `effectcraft-opusenc` as `opus::encoder` (and
`opus::Encoder`) behind `opus-encode`: SILK, hybrid and CELT, 48 kHz,
20 ms frames, mono or stereo. The constructors and `encode_float`
return `Result` instead of panicking. `Bandwidth` is one type for the
decoder and the encoder, and the two `Mode` enums convert into each
other. `encode` now turns on `opus-encode`.
The encoder tests (modes, ffmpeg's two Opus decoders as oracles) and
`TrackDecoder` on Opus without an `OpusHead` come with it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>