mirror of
https://github.com/freemkv/libfreemkv.git
synced 2026-10-07 18:13:10 +00:00
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.
99 lines
5.0 KiB
Markdown
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.
|