mux/mkv: spec-conformance fixes (field order, CICP, VobSub idx, SeekHead, AC-3)

- FieldOrder now derives from the bitstream's measured top_field_first
  (Some(true)→TFF, Some(false)→BFF) instead of hardcoding TFF for all
  interlaced content; falls back to TFF when unmeasured. Adds
  VideoStream::top_field_first; DVD/BD scan sets None with a precise
  TODO(spec) for parser→title plumbing.
- CICP (matrix/transfer/primaries/range) now prefers measured CICP from
  the bitstream (VideoStream::measured_cicp) over the coarse ColorSpace
  enum, so the container stops assuming a colour space the stream may
  contradict. Enum remains the fallback.
- VobSub S_VOBSUB CodecPrivate now emits a `size: WxH` line ahead of the
  palette per the .idx format so players place/scale subs correctly.
- SeekHead: when zero cues are written, the CUES Seek entry is Voided
  instead of leaving a dangling pointer to the Cues offset (now Tags/EOF).
- AC-3 Channels back-patch offset is captured from the writer instead of
  the hardcoded chan_elem_pos+2 (decoupled from the VINT width choice).
- Hoisted inline CICP codes and the dvcC fourcc to named constants citing
  ITU-T H.273 / RFC 9559; fixed the stale FieldOrder comment.
- DefaultDuration vs pulldown: precise TODO(spec) left (needs the same
  parser→title channel as top_field_first).

Tests: BFF-from-measured-flag, measured-CICP-overrides-enum, VobSub size:
line present/omitted, zero-cue SeekHead Void. precommit (1.86) green.
This commit is contained in:
Matthew Jackson
2026-06-25 18:40:30 -07:00
parent 8e0797eab0
commit 43fb97f71f
17 changed files with 514 additions and 54 deletions
+31
View File
@@ -196,6 +196,35 @@ pub struct VideoStream {
pub secondary: bool,
/// Extra label (e.g. "Dolby Vision EL")
pub label: String,
/// Field-display order MEASURED from the elementary stream's interlace
/// signalling (MPEG-2 picture coding extension `top_field_first`, H.264/HEVC
/// `pic_struct`), when available: `Some(true)` = top-field-first,
/// `Some(false)` = bottom-field-first. `None` = not measured — the muxer
/// falls back to TFF for interlaced content (the dominant DVD/HD case). The
/// container FieldOrder must agree with the bitstream, so a measured BFF
/// stream must NOT be stamped TFF. Ignored for progressive video.
pub top_field_first: Option<bool>,
/// CICP colour signalling (matrix, transfer, primaries, full_range) MEASURED
/// from the bitstream — HEVC/H.264 VUI `colour_description` or MPEG-2
/// `sequence_display_extension`. `Some(...)` takes precedence over the
/// coarse `color_space` enum (a playlist nibble / PAL-NTSC guess); `None`
/// means the bitstream did not state it, so the enum-derived triplet is used.
/// Codes are ITU-T H.273 (CICP); `range` is 1 = limited/TV, 2 = full.
pub measured_cicp: Option<MeasuredCicp>,
}
/// Measured CICP colour signalling read directly from a video elementary stream
/// (ITU-T H.273). Preferred over the coarse [`ColorSpace`] enum when present.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct MeasuredCicp {
/// MatrixCoefficients (ITU-T H.273 Table 4).
pub matrix: u8,
/// TransferCharacteristics (ITU-T H.273 Table 3).
pub transfer: u8,
/// ColourPrimaries (ITU-T H.273 Table 2).
pub primaries: u8,
/// Range: 1 = limited (studio/TV), 2 = full. Matroska Colour/Range values.
pub range: u8,
}
/// An audio stream.
@@ -3776,6 +3805,8 @@ mod tests {
display_aspect: None,
secondary: false,
label: String::new(),
top_field_first: None,
measured_cicp: None,
})],
chapters: Vec::new(),
extents: Vec::new(),