fix(libfreemkv): rc6 hardening pass — mux timeline/colour/PCR, demux panic sentinel, parser robustness + doc accuracy
Surgical fixes (each with a regression test that fails without the change): mux/mkv.rs, mux/demux_sink.rs: drive the clip-boundary timeline epoch off the resolved PRIMARY VIDEO track, not the literal stream index 0. An M2TS/PMT title can list an audio ES before video, so streams[0] may be audio; a non-video epoch driver ratchets the frontier and inflates the timeline. mkv cluster-opening falls back to track 0 for audio-only titles so they still open clusters. mux/codec/ac3.rs: correct ACMOD_CHANNELS — acmod=5 (3/1) is 4 channels, not 3 (was undercounting a 3/1 stream); fix the A/52 Table 5.8 doc. disc/mod.rs: HDMV coding_type 0x91 (Interactive Graphics / menus) no longer maps to PGS subtitle — it falls through to Unknown so the PMT/STN walker drops it instead of surfacing a bogus subtitle track. mux/videomap.rs + mux/mkv.rs: FVI colour now mirrors the MKV muxer's CICP precedence (measured CICP authoritative; HDR-driven PQ/HLG transfer override) via a shared cicp_for_video helper, so the two sinks can't disagree (HDR10 BT.2020 no longer emits SDR transfer 14). mux/mkvstream.rs: saturating_add on cluster_ts + rel_ts so an adversarial CLUSTER_TIMESTAMP near i64::MAX can't overflow/panic before the existing saturating_mul. mux/timeline.rs: tighten the tail-straggler clamp so a normal new-epoch non-video frame leading the sparse video frontier by >3s is not demoted into the previous clip's epoch. mux/m2ts_mux/mod.rs: re-stamp PCR per video TS packet (mid-PES), not only at PES boundaries, so a large UHD I-frame can't open a multi-second PCR gap; modular 33-bit PTS rebasing so a real 90 kHz clock wrap is not collapsed to PTS 0 (pre-base frames still floor to 0). io/byte_prefetcher.rs, sector/prefetched.rs: wrap the producer feed loop in catch_unwind and emit a typed error sentinel on panic, so a mid-stream producer panic is not read as a clean EOF at the demux boundary (which would silently truncate the mux). mux/codec/h264.rs: extend HIGH_PROFILES to the full ISO/IEC 14496-15 set that mandates the avcC chroma/bit-depth extension (adds 244 et al.). Doc/comment accuracy: css/mod.rs (50000 sectors, not scrambled-sectors), aacs/decrypt.rs (decrypt_unit already-clear path), ifo.rs (TT_SRPT at 0xC4), css/lfsr.rs (LFSR0 24-bit; TAB1-then-XOR cipher; real scramble-flag predicate), disc/read_error.rs (for_sweep does bounded transient retries). Skipped: keydb.rs SSRF guard (low/latent, no live caller) — a hard loopback block breaks an existing behavioral test that exercises the header-EOF path over a loopback server; a clean fix needs a resolver test seam beyond this surgical pass. The sibling keydb_fetch.rs comment fix is out of scope (freemkv crate).
This commit is contained in:
+20
-1
@@ -603,7 +603,12 @@ impl Codec {
|
||||
// lossless pair, parallel to 0x81/0xA1 for AC-3. 0xA2 is
|
||||
// lossless MA, not lossy HR.
|
||||
0xA2 => Codec::DtsHdMa,
|
||||
0x90 | 0x91 => Codec::Pgs,
|
||||
// 0x90 = Presentation Graphics (PG / subtitles). 0x91 = Interactive
|
||||
// Graphics (IG / menus) and 0x92 = Text subtitles are distinct HDMV
|
||||
// coding types and are NOT PG subtitle streams; only 0x90 maps to
|
||||
// Pgs. IG (0x91) falls through to Unknown so the PMT/STN walker drops
|
||||
// it rather than surfacing a bogus PGS subtitle track for a menu ES.
|
||||
0x90 => Codec::Pgs,
|
||||
ct => Codec::Unknown(ct),
|
||||
}
|
||||
}
|
||||
@@ -5776,6 +5781,20 @@ mod tests {
|
||||
assert_eq!(Codec::from_coding_type(0x86), Codec::DtsHdMa);
|
||||
}
|
||||
|
||||
/// HDMV coding_type 0x90 = Presentation Graphics (PG / subtitles) → Pgs,
|
||||
/// but 0x91 = Interactive Graphics (IG / menus) is NOT a subtitle stream.
|
||||
/// It must NOT map to Pgs (whose kind() is Subtitle), else a menu ES would
|
||||
/// surface as a bogus PGS subtitle track. 0x91 falls through to Unknown so
|
||||
/// the PMT/STN walker drops it.
|
||||
#[test]
|
||||
fn coding_type_ig_0x91_is_not_pgs_subtitle() {
|
||||
assert_eq!(Codec::from_coding_type(0x90), Codec::Pgs);
|
||||
assert_eq!(Codec::from_coding_type(0x90).kind(), CodecKind::Subtitle);
|
||||
// IG must not be a PGS subtitle.
|
||||
assert_eq!(Codec::from_coding_type(0x91), Codec::Unknown(0x91));
|
||||
assert_ne!(Codec::from_coding_type(0x91).kind(), CodecKind::Subtitle);
|
||||
}
|
||||
|
||||
/// chapter_name emits a bare 1-based ordinal (no localized prose).
|
||||
#[test]
|
||||
fn chapter_name_is_bare_ordinal() {
|
||||
|
||||
Reference in New Issue
Block a user