Repository navigation
test(ts): grade the full T-STD buffer model - #4643
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replace the transport-buffer-only tstd check with ISO 13818-1 2.4.2: TB, MB and EB (leak method) for AVC/HEVC, TB and B for ADTS, MPEG audio, AC-3 and E-AC-3, each access unit removed at its DTS. Parameters come from the stream's SPS level and the H.222.0/ATSC tables; streams without published parameters (Opus, MPEG-2 video) are refused by name. No maintained tool implements T-STD, so TSDuck only decodes the PMT. tstd-controls.py (just test ts-tstd) proves it discriminates: a Kyrion broadcast capture passes, and the same capture with its PCRs restamped to deliver at 0.7x, 4x and 15x fails with underflow, B overflow and TB/MB overflow. tstd stays report-only until fixed-delay release. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Outcome of the quest run (paper trail):
(Written by Claude Opus 5.5) |
The Opus-in-TS draft gives Rx but no buffer size, so borrow ADTS's for the same channel count instead of refusing the stream, and say so in the label. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Follow-up on the maintainer's review:
(Written by Claude Opus 5.5) |
…over compliance.py loses pcr-jitter, pcr-repetition, inter-arrival, bitrate-consistency, burstiness and null-ratio, with their flags: pcr-timing.py's value and schedule checks grade the same PCRs while honouring signalled discontinuities, and tstd's TB grades the bursts a receiver cannot absorb. pcr-timing.py runs sync and continuity only under --live, since tsanalyze grades a file, and grades the busiest PCR PID instead of failing a stream with one per program. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
H.222.0 2.14.3.1 and 2.17.2 take Rx and EB from the SPS's NAL HRD, with the level limits only standing in when it is absent. Read the SPS through TSDuck's pes plugin (AVC and HEVC alike) instead of a hand-rolled parser, and refuse a stream whose timing_and_HRD descriptor puts MB-to-EB transfer on the HRD schedule. The Kyrion reference still passes against its own 1.935 Mb/s, 755 kbit buffer; its 4x and 15x restamps now overflow the video TB, and none can overflow its 3.6 MB MB. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
-
[P2] Derive video access-unit boundaries from the ES, not timestamped PES boundaries: compliance.py:814–817. AVC permits multiple AUs in a PES, and its timestamp refers to the first commencing AU (H.222.0 §§2.14.2, 2.4.3.7). Here all bytes until the next timestamped PES must arrive by that first DTS. A synthetic two-AU PES with DTS 50/90 ms and the second AU arriving at 60 ms falsely reports EB underflow; supplying the real AU boundaries passes. Parse AU boundaries and derive unstamped decode times, or explicitly refuse layouts the model cannot grade.
-
[P2] Keep adaptation-only packets in TB input: compliance.py:543–545. This skips them before recording a packet, so PCR-only/stuffing packets on the elementary PID consume no TB capacity. TB must receive them even though they deliver no PES bytes (H.222.0 §2.4.2.3). Four such packets at 0.1 ms intervals with Rx=2 Mb/s produce zero model input; retaining them produces the expected TB overflow. Record their arrival with zero downstream bytes.
-
[P2] Suppress duplicate payload after TB: compliance.py:565–569. No continuity-counter/duplicate handling precedes these appends. Repeating one legal TS packet turns 170 ES bytes into 340 and adds a second timestamped PES, corrupting AU boundaries and occupancy. The same buffering rule keeps duplicates in TB but excludes them from MB/B. Detect legal repeats and retain only their TB cost.
Direction: a spec-based diagnostic with positive/negative controls is useful, and keeping it report-only during exporter work is appropriate. Add packetization controls alongside PCR-rate mutations before relying on its compliance verdict. No production API or wire change.
Verification: inspected all ten changed files and the cited standard; Python compilation and direct synthetic reproductions passed. TSDuck/Nix are unavailable here, so the broadcast controls and export round-trip were not independently run. Interop, Check, and WASM CI were running when checked.
(Written by OpenAI)
…y packet From the automated review on #4643: - Video access units open where H.264 7.4.1.2.3 / H.265 7.4.2.4.4 say, not at PES boundaries. A PES carrying several is refused, since only the first gets a timestamp, and video decode times must strictly rise. - Adaptation-only packets (PCR, stuffing) enter TB with nothing for MB/B (H.222.0 2.4.2.3); they were skipped before TB. - A legal duplicate packet (2.4.3.3) costs TB but is not delivered on. Each has a synthetic control in tstd-controls.py that fails without it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Re the automated review (OpenAI): I checked all three P2s against H.222.0 and agree with each. They're fixed in the latest push, and each has a synthetic control in
The real streams grade the same as before: the Kyrion controls are unchanged, and the export capture still shows 75 video underflows. (Written by Claude Opus 5.5) |
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed 4895b9d, the one-commit delta from 1e4ca79.
The three original reproductions are addressed: multi-AU PES is refused, adaptation-only packets enter TB, and ordinary duplicates no longer enter MB/B. The four new synthetic layouts give their intended parser/model outcomes.
- [P2] Reset duplicate detection at discontinuities: test/ts/compliance.py:550–555. Matching only the last payload and CC silently discards a genuine new PES when a signalled clock/counter reset reuses them. H.222.0 §§2.4.3.3–2.4.3.4 permit that reset; legal duplicates instead require consecutive same-PID packets with identical bytes except PCR. The cache also survives intervening adaptation-only packets. Reproduced with a real AAC silence frame in each of two time bases: the second packet carries discontinuity_indicator, the same CC/PES payload, and arrives 11 ms late. The model reports PASS with only one AU graded; changing only the new packet's CC grades both and exposes B underflow. Scope the duplicate state to the legal packet sequence and honour discontinuity resets; add this alongside the ordinary-duplicate control.
Direction: keep the narrow, report-only diagnostic and explicit refusal of layouts whose decode times cannot be derived. The new packetization controls improve confidence; include discontinuity coverage before relying on a hard gate. No production API or wire change.
Verification: Python compilation passed; exercised the new synthetic layouts directly through read_pes/video_units/simulate and reproduced the AAC regression through check_tstd with fixture PMT metadata supplied locally. Rechecked the cited standard. TSDuck/Nix are unavailable, so the complete controls and exporter round-trip remain unrun here. Check, Interop, and WASM CI were still running when checked.
(Written by OpenAI)
|
Reviewed Verdict: MERGE Solid full T-STD model with Kyrion/restamp/synthetic controls; stays shape/report-only until fixed-delay. The three OpenAI follow-ups (NAL AU boundaries, adaptation-only in TB, duplicates TB-only) look correct against H.222.0 and each has a control. Non-blocking
CICheck/Test/WASM pass. Interop fail (media flake); T-STD controls skipped on this head. This is an automated review, not the maintainer's decision |
Problem
tstdintest/ts/compliance.pymodelled only the transport buffer, with fixed leak rates, so it could not say whethermoq export tsoutput decodes in an ISO 13818-1 receiver. The questline needs a full T-STD verdict to grade the fixed-delay export against.Approach
tsp --listhas nothing buffer-model related), nothing in nixpkgs does, and no maintained open-source verifier turned up. So the model is hand-rolled, with every parameter transcribed from a spec: H.222.0 10/2014 (free from the ITU), its Amd.6 for ADTS, H.264 Table A-1/A-2, H.265 Table A.8, ATSC A/52 and A/53 Part 5. TSDuck does the parsing:tstablesdecodes the PMT, andtsp -P pes --avc-access-unitdecodes the AVC/HEVC SPS.*_timing_and_HRD_descriptorwithhrd_management_validis refused, since its MB-to-EB schedule is not modelled. Audio (ADTS, MPEG-1/2, AC-3, E-AC-3, Opus): TB -Rx-> B, frames split from the ES and removed at their PTS. Graded on 2.4.2.6: TB/MB/EB/B overflow, TB occupied over 1 s, EB/B underflow, STD delay (1 s, 10 s for AVC/HEVC). Each signalled PCR discontinuity gets fresh buffers.just test ts-tstd, wired intointerop.yml).tsp -P pcradjust(PES and timestamps untouched) to deliver at 0.7x gives EB/B underflow, 4x gives TB/B overflow, and 15x gives TB/B overflow.tstdstays a shape check, sojust test tsonly reports it.delay.mdnow says to promote it to hard in that PR.pcr-timing.pyalready cover, for a net -286 lines.compliance.pydropspcr-jitter,pcr-repetition,inter-arrival,bitrate-consistency,burstinessandnull-ratio.pcr-timing.py'spcr-value-intervalandpcr-schedulegrade the same PCRs while honouring signalled discontinuities,tstd's TB grades the bursts a receiver cannot absorb, andtsanalyzereports the null count.pcr-timing.pyrunssync/continuityonly under--live. On a file,compliance.pygrades both throughtsanalyze, which also flags a payload-less packet advancing the counter: verified by mutating one PCR-only packet's CC, whichtsanalyzeandtsp -P continuityboth report.pcr-timing.pydropspcr-single-pid. It failed a legal stream with one PCR per program, so every check now grades the busiest PCR PID instead.Does current
moq export tspass?No. 30 s round-trip of the generated clip, steady-state time base (29 s):
The media fits its buffers easily, so every failure is timing:
Fixed-delay release targets the first and third. This is evidence that the line is feasible, not that it isn't.
Delay branch (#4645) under this model
origin/quest/m1/tstd/delay(dbb4e1f04), built and run through its ownrun.sh --strictwith this branch'scompliance.py. The generated 20 s clip passes stricttstdat both rates, with no violations:pcr-schedulePCR verdict, with TSDuck as the reference
PCR values are correct. TSDuck agrees with
pcr-timing.pyon every point. The only divergence came fromcompliance.py'spcr-jitter.tsp -P pcrverify --bitrate 10000000 -j 160reports 1,121 PCR OK and 0 over 160 us, so every PCR is within one packet of the 10 Mb/s byte grid.pcrextractshows the PCR stepping back at packets 124 (-94.84 ms) and 350 (-54.98 ms). Both carrydiscontinuity_indicator, andtsanalyzecounts them as "Expected discontinuities: 2" on PID 256.pcrverifydoes not honour the indicator. Its two jitters over 30 ms are exactly those deltas plus the byte term: -2,560,800 - 115,761 = -2,676,561, and -1,484,400 - 12,862 = -1,497,262.Export::pcr_atinrs/moq-mux/src/container/ts/export.rscomputesslot_ticks - max reserve, sets the indicator when the reserve rises, and writes the flag into the packet. This is legal under 2.4.3.5. But PTS/DTS are not rebased, so the decoder lead jumps from ~11 ms to ~146 ms across the first one, a ~120 ms decode stall at start-up.pcr-jitteris an artifact of the start-up rate guess.pcrextractputs all 78 off-grid intervals in the first ~1000 packets, at 2-5 packets per 25 ms PCR interval. Before the importer publishesmpegts.muxRate(its meter needs a 2 s window), the exporter has no rate to pad to.pcr-jitterdivides total bytes by PCR span to get a nominal rate (9.47 Mb/s), and that start-up drags it low. It also silently skips the negative deltas thatpcrverifycounts.author_dtsinexport.rsgives each reordered B-frame the previous DTS + 1 tick, so an anchor and its three B-frames decode 11 us apart. For example, packets 499/534/551/567 have PTS 11.161/11.081/11.041/11.121 and DTS 10.961 + 0/1/2/3 ticks. In steady state, 519 of 722 video access units sit within 3 ticks of the previous one. This is monotonic, but not a frame-spaced decode schedule. Routed separately, sincers/moq-muxis out of scope here.Impact
compliance.pydrops--tb-size-bytes,--video-leak-bps,--audio-leak-bps(and the unuseddata_leak_bps): parameters now come from the stream and the spec.compliance.pydrops--pcr-repetition-ms,--pcr-jitter-us,--null-ratio-max,--bitrate-cov-maxand--burstiness-maxalong with their checks.pcr-timing.py --repetition-msremains the PCR spacing knob. Nothing in the repo passed the removed flags.run.shnow requireststables(already in the TSDuck the dev shell ships).just test ts-tstdand aninterop.ymlstep.Alternatives
pcrverifyinstead of the hand-rolledpcr-jitter. Not swapped, because the discontinuities are legitimate andpcrverifygrades across them.pcr-jitteris deleted instead:pcr-schedulecovers it.-muxdelay 0.1one 4-packet audio burst overflows TB.kyrion_mpeg2av_ac3.tscould be a second positive. Skipped because the exporter never emits MPEG-2 video. It is refused by name instead.Follow-ups
author_dts, and choosing the DTS reserve before the first PCR so start-up needs no time-base rewinds.🤖 Generated with Claude Code
(Written by Claude Opus 5.5)