From 343658abc1ee30b3ce0ae190ac80f88d0ce76847 Mon Sep 17 00:00:00 2001 From: Thomas Drapier Date: Sat, 10 Oct 2026 23:27:15 +0100 Subject: [PATCH 1/2] quest(m1): plan the TS repeated-tables fix Co-authored-by: Claude Opus 5.5 Co-authored-by: Cursor --- quest/m1/README.md | 1 + quest/m1/ts-psi-repeat.md | 40 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 quest/m1/ts-psi-repeat.md diff --git a/quest/m1/README.md b/quest/m1/README.md index efb4f35a3f..b35efeedd1 100644 --- a/quest/m1/README.md +++ b/quest/m1/README.md @@ -173,6 +173,7 @@ bench all require its crate. - [T-STD TS export](/quest/m1/tstd/README.md) - `moq export ts` is a proper remux that passes the T-STD buffer model, starting with a fixed `--delay` - [Multi-packet PMT](/quest/m1/ts-pmt-split.md) - `export ts` splits a PMT longer than one packet instead of exiting before its first packet - [ATSC AC-3](/quest/m1/ts-atsc-ac3.md) - `export ts` carries 48 kHz ATSC AC-3 at every A/52 rate up to 640 kb/s instead of aborting from 384 kb/s up +- [TS table bursts](/quest/m1/ts-psi-repeat.md) - `export ts` lays a repeated PAT and PMT once where aligned keyframes would bunch them past their transport buffer - [TS damage log](/quest/m1/ts-damage-log.md) - a burst of damaged TS units logs a first warning and a periodic summary per PID, not one warning per unit - [TS adaptation field length](/quest/m1/ts-adaptation-only.md) - a TS adaptation field with the wrong length for its packet (183 adaptation-only, at most 182 with a payload) is refused as damage - [Rust non-continuous signal](/quest/m1/rust-continuous.md) - the Rust container consumer reports a frame after a subscribe or discontinuity as non-continuous, like JS, for the tune-in and warmup trims diff --git a/quest/m1/ts-psi-repeat.md b/quest/m1/ts-psi-repeat.md new file mode 100644 index 0000000000..1087d01a7b --- /dev/null +++ b/quest/m1/ts-psi-repeat.md @@ -0,0 +1,40 @@ +# [M] TS export never bunches repeated program tables + +## Goal + +`moq export ts` never lays copies of the program tables back to back where +they would overrun the PAT's or a PMT's 512-byte transport buffer, drained at +Rxsys = 1 Mb/s (ISO 13818-1 2.4.2.3). Every copy that marks its own tune-in +point still goes out, and changed tables still go out in order. Export carries +every video rendition and writes the tables ahead of each video keyframe, so an +ABR ladder of three or more renditions with aligned keyframes overruns the +PAT's buffer today: three PATs back to back, about 526 B at 25 Mb/s. +`compliance.py` grades the program tables' buffers too, so every TS Interop arm +catches a regression. + +## Plan + +Decided (2026-10-10), from Codex's review of #5207 and kixelated's reply +there. `Slot::layout` (`rs/moq-mux/src/container/ts/schedule.rs`) lays the +tables just ahead of the first packet muxed after them, so when a heavier lane +goes first, every table group in the slot flushes at once. `main` bunched them +the same way at high fill before #5207. + +- Start from the diff in + [the review thread](https://github.com/moq-dev/moq/pull/5207#discussion_r4239051134): + a run of tables that the same flush would lay right behind an identical run + is dropped and padded back with nulls at the end of a padded slot, and + `Slot::nulls` becomes `Option` so an unpadded slot gains none. + Carrying each table once per slot was tried and reverted in #5207: it dropped + the copies that lead each send-ahead unit, breaking the tune-in points + `aac_program_config_follows_each_table` checks. +- A new table version that bunches with the old one stays as rare as it is; + spacing it out is not in scope. +- `compliance.py` gains a hard system-buffer check for the PAT and every PMT + PID: TBsys of 512 B drained at Rxsys, then Bsys, per ISO 13818-1 2.4.2.3. Its + strict T-STD check models only elementary streams today. DVB SI (SDT, EIT) + and SCTE-35 stay out, since ISO defines those buffers for program-specific + information. Every existing TS arm still passes. +- Test: a unit test runs laid slots' PAT and PMT through a 512-byte buffer + drained at 1 Mb/s, with keyframes aligned on three video PIDs at 25 Mb/s, + and fails without the fix; plus the diff's `a_repeated_table_run_is_laid_once`. From e6bad36bf5e824dbfa89f781b33c1d62e642fb2f Mon Sep 17 00:00:00 2001 From: Thomas Drapier Date: Sat, 10 Oct 2026 23:30:51 +0100 Subject: [PATCH 2/2] quest(m1): ground the PAT overflow figure and the two-rendition case Co-authored-by: Claude Opus 5.5 Co-authored-by: Cursor --- quest/m1/ts-psi-repeat.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/quest/m1/ts-psi-repeat.md b/quest/m1/ts-psi-repeat.md index 1087d01a7b..5984ce45be 100644 --- a/quest/m1/ts-psi-repeat.md +++ b/quest/m1/ts-psi-repeat.md @@ -8,7 +8,9 @@ Rxsys = 1 Mb/s (ISO 13818-1 2.4.2.3). Every copy that marks its own tune-in point still goes out, and changed tables still go out in order. Export carries every video rendition and writes the tables ahead of each video keyframe, so an ABR ladder of three or more renditions with aligned keyframes overruns the -PAT's buffer today: three PATs back to back, about 526 B at 25 Mb/s. +PAT's buffer today. At 25 Mb/s, three PAT and PMT pairs back to back deliver +564 B of PAT in about 301 µs, of which about 38 B drains, peaking near 526 B. +Two renditions' 376 B fit. `compliance.py` grades the program tables' buffers too, so every TS Interop arm catches a regression. @@ -24,7 +26,8 @@ the same way at high fill before #5207. [the review thread](https://github.com/moq-dev/moq/pull/5207#discussion_r4239051134): a run of tables that the same flush would lay right behind an identical run is dropped and padded back with nulls at the end of a padded slot, and - `Slot::nulls` becomes `Option` so an unpadded slot gains none. + `Slot::nulls` becomes `Option` so an unpadded slot gains none. A slot + still opens with its clock packet and keeps its length, so no PCR moves. Carrying each table once per slot was tried and reverted in #5207: it dropped the copies that lead each send-ahead unit, breaking the tune-in points `aac_program_config_follows_each_table` checks. @@ -35,6 +38,7 @@ the same way at high fill before #5207. strict T-STD check models only elementary streams today. DVB SI (SDT, EIT) and SCTE-35 stay out, since ISO defines those buffers for program-specific information. Every existing TS arm still passes. -- Test: a unit test runs laid slots' PAT and PMT through a 512-byte buffer - drained at 1 Mb/s, with keyframes aligned on three video PIDs at 25 Mb/s, - and fails without the fix; plus the diff's `a_repeated_table_run_is_laid_once`. +- Test: a unit test runs laid slots' PAT and each PMT PID through its own + 512-byte buffer drained at 1 Mb/s, with keyframes aligned at 25 Mb/s on three + video PIDs, which fails without the fix, and on two, which passes either way; + plus the diff's `a_repeated_table_run_is_laid_once`.