Files
libfreemkv/docs/truehd.md
T
Matthew Jackson 6e14fc0c0c libfreemkv: 1.7.0 groundwork — sector-recycle soundness + CI hardening
Security
- Remove the unsafe Vec::set_len over recycled sector buffers — UB reachable
  from safe code (GHSA-j8ww-f5fg-9pmh, low). Uses Vec::resize; pooling unchanged.

CI / tooling
- clippy on stable with the MSRV single-sourced from Cargo.toml; cargo-deny
  dependency-audit gate with first-party git sources allowed (#15); audience-based
  comment-guard (#17).

Docs
- README (keydb ownership, BD-J parser count), drive-access transport/reset
  notes, mux timeline module-doc links.
2026-09-02 12:40:55 -07:00

99 lines
5.0 KiB
Markdown

# TrueHD codec parser — extended notes
## `is_truehd_major_sync` — why 0xBA must be exact
The 32-bit word that FOLLOWS the sync is laid out per stream type: TrueHD's
`format_info` carries [31..28] audio_sampling_frequency, the 5-bit 6-channel
and 13-bit 8-channel presentation channel-assignment masks; MLP's (0xBB) same
word carries quantization word lengths and the MLP group sample-rate fields
instead. So every site that decodes `format_info` with the TrueHD layout must
require 0xBA exactly — masking the low sync bit there read a quantization code
as the rate nibble and pulled channel masks out of unrelated bits, giving the
track header a wrong `SamplingFrequency` and `truehd_au_duration_ns` a wrong
per-AU increment (audio drifting against video for the whole track).
`None` from these helpers is the safe outcome: the caller falls back to its
container-derived rate/channel count.
## `truehd_sample_rate_hz` — rate formula and rationale
The MLP rate formula is `(ratebits & 8 ? 44100 : 48000) << (ratebits & 7)`;
rather than evaluate it blindly, `truehd_sample_rate_hz` is a strict
whitelist of the only six rates that occur on real BD/UHD TrueHD. Every
other code — the invalid `0xF`, the formula-only `0x3`/`0xB`, and all
reserved values — returns `None`.
## `au_check` — corruption decision
Decide whether an access unit is corrupt, updating `num_substreams` from a
valid major sync. Per the MLP/TrueHD access-unit decode rules: a major sync
with a bad header CRC, or any AU whose header parity fails, is undecodable.
Returns `false` (not corrupt) when the AU is too short to judge or no
major sync has established `num_substreams` yet — we never drop what we
cannot verify. Verified against real TrueHD streams (3600/3600 AUs).
## `ac3_frame_at_head` — AC-3 size lookup
Size (bytes) of the AC-3 frame at the buffer head. Distinguishes three cases
the caller must treat differently:
- `Unmappable`: the header's fscod/frmsizecod don't map to a real frame
size (reserved fscod==3, or frmsizecod >= 38). The caller must drain
and resync, NOT wait for more data — waiting would stall forever.
- `NeedMore`: a valid size, but the frame isn't fully buffered yet.
- `Frame(n)`: a complete `n`-byte AC-3 frame is buffered.
Frame sizing reuses `ac3::ac3_frame_size` so the AC-3 size table has a
single source of truth shared with the AC-3 parser; a returned `0` there
(reserved fscod or out-of-range frmsizecod) is the unmappable case.
## `ac3_boundary_corroborated`
Secondary validation for an AC-3 frame of `frame_bytes` at the buffer head:
is its computed end a plausible boundary? Accept when the frame fills the
rest of the buffer, or the bytes that follow start another AC-3 sync
(0x0B77) or a plausible TrueHD access unit (non-zero 12-bit length within
the 32 KiB cap). If none holds, the leading 0x0B77 is more likely a TrueHD
AU header that happens to look like AC-3, so the AC-3 reading is rejected.
## `mlp_major_sync_header_size`
Major-sync header size in bytes: base 28, plus `2 + extensions*2` when the
extension flag (major-sync byte 25, bit 0) is set (`extensions` = byte 26
high nibble). `ms` is the major-sync header, i.e. AU bytes `[4..]`. `None`
when the AU is too short to contain the full header.
## `mlp_major_sync_crc_ok`
Validate the MLP/TrueHD major-sync header checksum (a CRC-16 with polynomial
0x002D). The stored trailer is the last 2 header bytes; because MLP's
checksum is byte-reversed relative to a standard CRC, a standard CRC of the
header body XOR the little-endian word before the trailer must equal the
trailer read LITTLE-endian. (Comparing it big-endian was the bug this
function was fixed for; the body and the inline note are authoritative.)
## `mlp_substr_header_size` — test rationale
The substream count and the substream-directory size are the two numbers
that position `mlp_parity_ok`'s check window over the AU header. Every
other fixture in this module uses the degenerate shape — one substream,
no extraword — so neither function's real behaviour was ever exercised:
a constant answer agreed with all of them, and would then mis-window the
parity check on the multi-substream AUs that carry 7.1 and Atmos, judging
clean audio corrupt (or corrupt audio clean).
## `ref_crc16_2d` test oracle
Independent bitwise CRC-16 (poly 0x002D, init 0, MSB-first) — a separate
oracle from `crc16_mlp`, so a fixture built with it is not tautological
with the validator under test. Anchored to the catalogue check value
(0x4FF7 for "123456789") so the oracle itself is proven correct without
reference to the code under test.
## `finalize_major_sync` test helper
Turn a synthetic major-sync AU (sync bytes already set at offset 4, any
`format_info` set) into one that passes the decodability gate: 1 substream,
a clean substream directory, a valid major-sync CRC-16, and a valid header
parity nibble. Mirrors what a real encoder writes (verified against real
TrueHD streams). The AU must be ≥ 36 bytes (4 AU header + 28 major-sync
header + 2 directory + slack), which every `make_truehd_unit(≥200)` is.