* craft-audio: AC-3 and E-AC-3 decoder
FilmCraft's AC-3 decoder as `craft_audio::ac3` behind `ac3-decode`:
every AC-3 channel mode and frame size, and E-AC-3 independent
substream 0 with spectral extension, in WAV order without downmix.
`TrackDecoder` and the native read path take AC-3 and E-AC-3 in MP4,
Matroska and raw streams.
Not bit-exact: zero-bit mantissas are filled with decoder-specific
dither (A/52 §7.3.4), so tests compare at 65-94 dB SNR on tones and
27-48 dB on white noise. 7.1 E-AC-3 decodes as its 5.1 core.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* craft-audio: review fixes, round 1 (#447)
An AC-3 / E-AC-3 packet is as long as all the primary syncframes in it.
Before the first decode, TrackDecoder::frames_per_packet gave 1536 for any
AC-3 track, and conceal used the first syncframe's header only. An E-AC-3
stream of one-, two- or three-block syncframes then got the wrong MP4 length
and seek positions and the wrong Matroska positions. A packet that groups
several such syncframes concealed at a fraction of its length.
Seeks in AC-3 and E-AC-3 now have to match the whole-file decode bit for bit,
as every other codec's do. The dither is seeded from each syncframe, so the
old 25 dB bound was looser than the decoder needs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* craft-audio: review fixes, round 2 (#447)
- AC-3 / E-AC-3 packets that decode to different lengths (in the packets
read ahead, or any decoded since) have no frames_per_packet, so a
Matroska seek finds its packet by timestamp rather than by index times
the first packet's length.
- E-AC-3 syncframes of fewer than six blocks may reuse exponents from any
syncframe before them: once one is seen, a seek decodes from the start
of the stream instead of 1536 frames before the target.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* craft-audio: review fixes, round 3 (#447)
- Matroska E-AC-3: the first seek reads every packet's syncframe headers (only the headers,
header stripping undone) and places packets by the frames their primary syncframes hold.
Packets that started to differ in length after the eight read ahead were placed as the first
packet's length times their index.
- A packet whose later syncframe fails no longer sets the length lost packets are concealed at,
nor marks the packets' lengths as differing: it decoded only in part.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Merge main; E-AC-3 in Matroska: read packet headers only up to the seek target, and count a packet of dependent syncframes as zero frames
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Dylan M. Taylor <dylan@dylanmtaylor.com>