demux: solidify sink — reuse canonical primitives, fix 3 bugs

Delete re-implementations in the demux:// sink and wire to proven helpers;
keep only genuinely-new functionality.

- AnnexB reframing: delete the sink's local length_prefixed_to_annexb (it
  break'd on a zero-length NAL, dropping the rest of the access unit) and
  call the canonical append_length_prefixed_as_annex_b in mux::hevc, which
  skips just the empty NAL.
- HEVC param sets: delete hvcc_param_sets; reuse hvcc_to_annex_b.
- avcC param sets: hoist as the new canonical avcc_to_annex_b in mux::hevc,
  next to hvcc_to_annex_b (the symmetry point); the sink calls it.
- PGS .sup: emit a synthetic clear display set (empty PCS + END) at
  pts + duration_ns so subtitles time out instead of lingering to EOF.
- TimelineContinuity: move verbatim into the shared mux::timeline module
  (with the prev_offset straggler-remap intact) and use it from both the
  MKV muxer and the demux sink; delete the sink's drifted TimelineRebase
  copy (which lacked the straggler branch).
- VobSub .idx: emit the conventional 'id: <lang2>, index: 0' line mkvmerge
  reads to assign the subtitle language; palette reuse unchanged.
- output(): seed DemuxOptions.base from title.playlist when non-empty.

New constants for the PGS clear-segment framing and avcC header cite the
public HDMV PGS (BD-ROM Part 3) and ISO/IEC 14496-15 specs.

Tests: a zero-length NAL mid-frame no longer truncates the AU; a frame with
duration_ns produces a .sup clear segment; existing demux tests stay green.
This commit is contained in:
Matthew Jackson
2026-06-25 17:58:49 -07:00
parent 8e2e22af5c
commit 9b6a48e9d9
6 changed files with 786 additions and 624 deletions
+10 -3
View File
@@ -466,10 +466,17 @@ pub fn output(
// `output()` call with the default option set.
StreamUrl::Demux { ref dir } => {
validate_file_path(dir, "demux")?;
// The full `--demux/--naming/--delay/--container/--chapters` flag
// surface is parsed in the CLI, which constructs `DemuxSink` directly.
// This bare `output()` arm uses defaults but still seeds the filename
// `base` from the title's playlist name when present (the default
// "title" stem is only a last resort for an unnamed title).
let mut opts = super::demux_sink::DemuxOptions::default();
if !title.playlist.is_empty() {
opts.base = title.playlist.clone();
}
Ok(Box::new(super::demux_sink::DemuxSink::create(
dir,
title,
&super::demux_sink::DemuxOptions::default(),
dir, title, &opts,
)?))
}
StreamUrl::Unknown { ref raw } => {