1We tried non-stuffed VBR instead
MoQ bitstream is already correct, but clock is not yet correct (but fixable). You regulate to CBR, recompute the PCR, hand a uniform clock and it works.
But it named PR #1992 (now dropped), which tried a clever way to feed null-stripped VBR into an IRD; it works in software but not in hardware. Forcing constant bitrate (CBR) at the muxer pads the stream with null packets, and that can read as wasteful. The tempting alternative was to keep the stream variable (VBR), save those bytes, and only fix the part that was actually broken, the clock. Emit dense, uniform PCR in media-time and leave the bitrate variable. That is precisely what PR #1992 did; well, it failed every single time, on every workaround tested.
2The bitstream might pass every static test, and still fail, why?
A non-stuffed VBR output is not corrupt. Continuity is intact, the PCR is monotonic and, by design, evenly spaced in media-time. A conformance checker, run on the base tests, is happy. But the hardware still glitches.
Transport-stream conformance is not equivalent to hardware conformance. Valid MPEG-TS can pass base conformance and still be rejected by an IRD, because acceptance depends on pacing, buffering, and timing margin, not only on packet correctness. Tom Waschura wrote it straight in 1999: jitter and data rate, among other implementation realities, "can be the demise of an otherwise-good IRD design", and "the operation of an IRD depends on the absolute ability to always receive quasi-error-free data streams."2 Static checks only validate bytes, but a hardware decoder needs a (perfect) clock.
3The hidden 129 Mbps burst
We fed #1992 a known-good 4 Mbps CBR source and measured what came out the other side, in the file, before any question of delivery. Once the null packets were absent, the measured output averaged approximately 3.3 Mbps. One 20 ms window, the one carrying the I-frame, holds 1715 transport packets. That is 2.58 Mbit in 20 ms, about 129 Mbps instantaneous, roughly 39 times the output average and 11.7 times the 11 Mbps window budget.
A colorful way to picture it: read CBR as Constant-Bus-Rate. Buses leave on a fixed schedule and every bus goes out full. When there are not enough passengers, you seat mannequins in the empty places so the bus is always full; they are discarded on arrival, leaving only the real passengers. VBR takes the opposite view: do not waste the trip on mannequins, send real passengers only (dump mannequins from the start). The buses turn elastic, expanding and contracting so the average passenger rate stays about the same; some buses are very short, and a software receiver is happy to take them that way. The trouble comes when a concert lets out and a crowd arrives at once, which is what an I-frame is. CBR rations that crowd across many scheduled buses; VBR sends them all in a single huge multi-level bus, lifting the rate for a moment and then sending fewer. A single overloaded bus means nothing to a software receiver. But route that same bus, packed to 39 times its normal load, into a terminal built for a steady trickle, and you swamp the terminal and break every departure after it. That overloaded bus is the 129 Mbps burst arriving at a hardware IRD. (And the same is, in fact, applicable to very short buses, but let's leave it here for now.)
The colorful version ends here. In packet counts, the very short buses are the nearly empty inter-PCR windows, and the huge multi-level bus is the 1,715-packet window. Of 789 windows, more than a quarter are near-empty, most are sparse, and 10% exceed the 11 Mbps window budget. This is not smooth delivery with a rate that happens to vary; it is a stream that lurches. And that is perfectly normal. It is just our old friend VBR being VBR.
This measurement used the 4 Mbps CBR Bunny golden: H.264 Main, 1920x1080i59.94, plus AAC. The captured #1992 output contains 34,990 packets over 789 consecutive 20 ms PCR intervals, with no null packets. At 11 Mbps, one interval can carry 146 packets, so that is the meaningful boundary:
To reproduce the input fixture, download the original MOV from the Blender Foundation archive, then generate the 4 Mbps CBR transport stream:
ffmpeg -hide_banner -y \
-i big_buck_bunny_1080p_h264.mov \
-map 0:v:0 -map 0:a:0 \
-vf "fps=30000/1001" \
-c:v libx264 -preset veryfast -profile:v main -level:v 4.1 -pix_fmt yuv420p \
-flags +ilme+ildct \
-x264opts "interlaced=1:tff=1:nal-hrd=cbr:keyint=30" \
-b:v 3M -minrate 3M -maxrate 3M -bufsize 3M \
-c:a aac -b:a 160k \
-muxrate 4M -pcr_period 20 \
-f mpegts golden-bbb-1080i5994-4m.ts
| Packets between PCRs | Meaning over 20 ms | Count | Share |
|---|---|---|---|
| 1–2 | PCR-only or near-empty, at most 0.15 Mbps | 216 | 27.4% |
| 3–20 | sparse, 0.23–1.50 Mbps | 417 | 52.9% |
| 21–100 | moderate, 1.58–7.52 Mbps | 44 | 5.6% |
| 101–146 | within the 11 Mbps window budget | 33 | 4.2% |
| >146 | exceeds the 11 Mbps window budget | 79 | 10.0% |
The median interval carries 4 packets. The maximum carries 1,715 packets, equivalent to 128.97 Mbps over 20 ms: 11.7 times the 11 Mbps window budget and approximately 39 times the measured output average.
The null-packet count reflects the same distinction, rather than an error by itself. The golden carries almost a million null packets to maintain its constant transport rate; #1992 was carrying none because its output remains VBR. The current MoQ TS exporter follows the same non-stuffed VBR design, as its own TS/IRD harness documents.7
$ tsp -I file golden.ts -P count --pid 0x1fff --total -O drop
counted 901,466 packets out of 4,362,741 # golden: CBR, null-stuffed
$ tsp -I file 1992-out.ts -P count --pid 0x1fff --total -O drop
counted 0 packets out of 34,990 # #1992 output: zero nulls
That measurement lives in the bytestream, not in how it was delivered, so it identifies a change in transport shape independently of network pacing. Even if the input is a known-good CBR stream, the measured #1992 output is VBR, with bursts and empty windows.5
4To tune or not to tune, or "can VBR behave as CBR"?
The natural reaction is to tune it, and try to pick a better drain rate and maybe the burst should smooth out. It does not, because removing the padding forces the slack between the channel rate and the content rate to appear somewhere, and there are only two places it can go. The test fixture was again the good Bunny at 4.69 Mbps. We varied the experimental drain rate and mux delay across five runs:
| Drain rate | Mux delay | Empty windows | Windows over 100 packets | Observed outcome |
|---|---|---|---|---|
| 11 Mbps | 200 ms | 54.2% | 30.7% | lumpy delivery, glitches |
| 5.5 Mbps | 2,000 ms | 20.3% | 0% | bounded queue, but still lumpy and glitches |
| 3.9 Mbps | 2,000 ms | 6.7%, then rising | 0% | queue grows; dies after about 14 s |
| 3.9 Mbps | 1,000 ms | 0% over 177 windows | 0% | queue grows; dies after 3.5 s |
| 3.9 Mbps | 400 / 600 ms | 0% | 0% | queue grows; dies in under 2 s |
There is no point that is both smooth and stable. Drain fast and the gaps become empty windows; drain slow and the backlog never clears. Constant bitrate would have solved this trivially: set the rate at or above the peak and let null packets fill every gap. Zero empty windows, uniform byte rate, and the I-frame never overflows because the rate has headroom and the padding absorbs the slack between frames. Those empty windows the VBR case cannot avoid are, almost exactly, the null packets CBR would have inserted. VBR is not CBR, trying to make it behave like something it's not, is a road with no exit.
5Are null packets mandatory? What the evidence supports
The answer depends who you ask it to.
- At syntax: MPEG-2 Transport Stream does not require every stream to contain PID 0x1FFF3. H.222.0 states that null packets may be present and may be inserted or deleted by remultiplexing. However,
- At egress: ISO/IEC 13818-1 defines the null packet as the data-rate-stuffing mechanism,3 and
- ETSI states that the PCR-accuracy test "should only be performed on a constant bitrate TS."1
The standards framework therefore gives CBR a defined clock-conformance domain and gives null packets a defined role in maintaining that rate when payload alone does not fill it.
That does not prove that every valid CBR stream must contain null packets. A fully occupied multiplex may need none, and a managed transport system may remove them if another layer preserves or later reconstructs the required timing. It does mean that a no-null stream intended for direct hardware egress carries the burden of proof: its wire rate, PCR relationship, buffer behavior and receiver compatibility must be demonstrated independently. So we tested it!
| Output form | Standards and documentation | Evidence in this work | Direct IRD conclusion |
|---|---|---|---|
| CBR, null-stuffed | ISO data-rate stuffing; inside the ETSI CBR PCR-test domain | golden measured, replayed and hardware-tested | locks on the tested IRD |
| CBR-derived, nulls removed | Zixi option exists, but resulting wire schedule is not specified | not rigorously isolated here | unknown |
| VBR, non-stuffed | valid TS syntax; outside the CBR-only PCR-accuracy test domain | #1992 output measured with bursts and near-empty windows | glitches on the tested IRD |
Our experiment therefore resolves the first and third rows, not the second. The null-stuffed golden locks. The measured #1992 output carries no null packets, concentrates 1,715 packets into one 20 ms interval and glitches on the same IRD. Because null removal and re-timing occurred together, this experiment does not establish that null absence alone causes failure. It establishes that the measured non-stuffed VBR shape is not a portable substitute for the known-good CBR output.
Zixi's documentation must be read narrowly.4 Its "Remultiplex/Pad" option explicitly converts VBR to CBR for professional IRDs by adding null packets and adjusting PCR. Its separate "No NULL Packets" option is described as remultiplexing to CBR and then removing null packets to reduce bitrate. The document does not state the resulting byte schedule on the wire, whether a downstream component restores stuffing, or whether that mode is supported as direct input to a hardware IRD. It proves that null removal is a vendor feature; it does not prove direct-IRD portability or standards equivalence.
6Can a 27 MHz PLL live in software?
The subtitle is a real question, and the answer is where hardware and software part ways.
MPEG-2 Systems assumes a hardware decoder that recovers its 27 MHz clock with a phase-locked loop that slaves a local oscillator to the arrival cadence of the PCR values it receives. ETSI's measurement guideline says: "The PCRs are used to re-generate the local 27 MHz system clock. If the PCR do not arrive with sufficient regularity then this clock may jitter or drift. The receiver/decoder may even go out of lock."1 TR 101 290 notes that DVB permits up to 100 ms between PCR values; 40 ms was the earlier recommendation. That loop has a narrow capture range on purpose; it is a control system tracking a physical oscillator, not a software buffer. Shove the PCRs off their expected arrival instants with a byte burst, or starve the decode buffer between them, and it loses lock. That is the Sencore going to noise. Nor is the PLL an inference about our unit: the datasheet of the very IRD under test lists "Frame Synchronization Modes: PCR-Recovered Clock", the output raster is slaved to the clock recovered from PCR arrival.8
Software receivers do not run that loop. They buffer, read the decode and presentation timestamps, and schedule playback against a local or adaptive clock, absorbing jitter in the jitter buffer. A 129 Mbps burst is just a queue that drains a few milliseconds later; the timestamps still say when each frame is due. This is why, back in Part 2, the same publish that glitched the Sencore played clean on a native software MoQ client with no TS and no UDP in the path. Non-stuffed VBR is fine for software precisely because software never tried to be a PLL.
So, can you simulate a 27 MHz PLL in software? You can approximate one; adaptive clock recovery and resampling are real. But that is not what a software player does, and it is not what saves you here. The deeper obstacle is conformance, not engineering effort. The standard's PCR-accuracy test, the ±500 ns measurement a decoder's clock recovery is judged against, "should only be performed on a constant bitrate TS as defined in ISO/IEC 13818-1 [i.1] clause 2.4.2.2."13 A non-stuffed VBR stream does not merely fail that test; it can't even be put on the test bench. Non-stuffed VBR fails by non-compliances to the test itself! You cannot simulate your way into an envelope the specification only draws for CBR.
7Isolating the cause
A result like this is only as good as the confounds it ruled out. With five stages between source and screen, a glitch can come from any of them, and several looked like the culprit before the measurement separated them.
- Format. The first golden was 1080p24; the IRD did not even detect it (noise). Re-encoded to 1080i59.94 it detected 1920x1080i 29.97 correctly. 1080p24 is a cinema and web format, not a broadcast contribution format.
- Buffer model. A golden made with a plain stream copy to CBR carried 118 instances of bytes arriving after their decode time (worst 30.7 ms late). Re-encoding with a constant-rate encoder buffer (HRD CBR) fixed it, guaranteeing the bytes precede their DTS.
- Combing. Raw interlacing added combing on motion and looked guilty, but the same combed golden locked when it was CBR and delivered smoothly. The real variable was the delivery, not the combing. A fix that coincides with another change is a confound, not a cause.
- Pacing. With fixed good content, a live smooth encoder at 11 Mbps served fine; a file replayed at 11 Mbps burst and failed; the same file at 4 Mbps was tolerable. The multicast fabric was healthy the whole time. The variable was the sender's pacing.
- Egress interface. With a VPN and several NICs, multicast can leave by the wrong interface. Unicast always routes; multicast needs the outgoing interface pinned.
With format, buffer model, combing, pacing, and interface all accounted for, one variable remained: the transformation #1992 applies. The decisive test had a single degree of freedom. The golden went to the IRD directly and locked. The same golden went through MoQ main and #1992 to the IRD and glitched. Then we captured #1992's output and measured the burst and the empty windows in the file. Because the defect is in the bytes #1992 produces, the cause is that transformation, independent of delivery.
8Constant rate is the thesis in code
The cleanest proof that constant rate is the easy path is how little code it takes to serve. We have a minimal UDP sender, about 300 lines, that reads a transport stream and paces it out at a fixed rate. It does two things: derive one rate from two PCR values (bytes between them, over the media time between them), and send the Nth byte at the instant that rate places it. The send loop never looks at the PCR again. It only counts bytes.
It locks a real IRD with our goldens, and it locked not one but two real Broadcast streams, one for ATSC North America, and surprisingly, a third-party European transport stream with no tuning at all!. The reason it can be that simple is that constant bitrate makes byte position a linear function of the clock; the null packets are the padding that enforces that linearity. A CBR file carries its own delivery schedule in its byte layout, so a sender that parses no PCR and models no buffer is enough. The "magic" is the CBR, not the sender.
Point that same sender at a null-stripped stream and it breaks, by construction. The rate it derives is no longer the channel rate but the content rate of whatever window it sampled. Sending at that constant byte rate delivers the content off-schedule: after an I-frame the accumulated byte offset runs ahead of the line, so packets arrive late (the decode-before-display margin is violated), and in the sparse stretches they arrive early. There is no single rate that fixes both. (We have not captured this failure shape from this sender specifically; the analysis is close to definitional, since byte-to-time linearity is the definition of CBR, and the prediction is an I-frame burst with late-arriving bytes.) To do null-stripped delivery properly you would replace the byte pacer with a media-time scheduler that parses timestamps and respects the buffer model, which is a real muxer, not 300 lines. And even then the wire is no longer constant rate. (For scale: the easy direction, a full CBR null-stuffing remultiplexer bolted onto that same sender, cost about 700 lines of C; see the update below.)
9The right architecture
Strip the engineering away and a plain argument remains. The one benefit of non-stuffed VBR is fewer bytes. But to make an IRD accept it you have to deliver it at constant rate, which is the one thing that spends that benefit.
Variable bitrate earns its keep where variable rate actually saves: on packetized transport. That is MoQ, a lean transport that carries timed objects and lets the application decide what a stream means.6 There, the rate rises and falls with the content and nothing is padded. At the boundary where the stream meets a hardware decoder, it is constant bitrate. The correct shape is not a compromise in the middle; it is variable over MoQ and constant at the point of export.
Upstream now measures the same shape
After the hardware work described here, MoQ merged PR #2011, a TS/IRD compliance harness built by Thomas Drapier and wired into CI by Luke Curley.7 Its own documentation states that the current exporter is VBR, inserts no null packets and emits PCR once per media frame, so broadcast-shape checks are expected to warn. The analyzer measures PCR jitter against nominal transport rate, bitrate consistency, burstiness, null ratio and an approximate T-STD transport buffer. Those are the same axes this experiment isolated from the physical IRD.
This is independent software corroboration, but not a substitute for the wire test. The harness derives timing from PCR and packet position, not from socket arrival timestamps, so it evaluates the multiplex shape but cannot prove UDP pacing. Its shape findings are warnings rather than hard failures, and the current bitrate-spread calculation excludes null packets. A known-good CBR null-stuffed stream must therefore be its positive control: if that stream does not pass the strict CBR profile, the profile needs calibration before it can be called an IRD compliance certificate. The corresponding negative control is the current non-stuffed VBR export.
10What is next
- As of the latest draft of this document, the elegant path was closed. PR #1992, the windowed non-stuffed export, has been withdrawn. The direction that stands is constant bitrate reconstructed at egress. Our proposal to build null-stuffing CBR and paced UDP egress in-tree was declined by the moq-dev maintainer, on ownership rather than on the physics: his position is that IRD support should live out-of-tree, owned by someone with the hardware, until operators have battle-tested it. But we are warriors, of course we will battle-test it!
- So we built exactly that (see the update above), and we are still betting the capability lands upstream eventually, because MPEG-TS in moq-dev exists for precisely one clientele, broadcasters, and for them a MoQ TS egress that fails on some IRDs, and whether it locks on any other is unknown, is half baked, and that is definitely not battle ready.
- Broader than one vendor. Every hardware result here is against one Sencore. We will validate against as many IRDs as we can reasonably get our hands on; we are not generalizing from a sample of one.
- Calibrate the software gate. Run MoQ's merged TS/IRD harness against both controls: a known-good CBR null-stuffed golden and the current non-stuffed VBR export. The former must satisfy the CBR profile; the latter must expose the shape warnings. Keep network pacing as a separate timestamped-capture gate.
- End to end SDI to SDI. The full-cycle MoQ-driven device promised in Part 2 is still the goal, and the egress side of it is exactly the constant-rate reconstruction this report argues for. We can do end to end SDI with or without mpeg2ts hardware egress compatibility into moq-dev, the recipe was already in place and mentioned in Part 2, but we would love to see it implemented natively to avoid external patching.
✓In one line
We tried a hundred ways to make a clever VBR path work, and finally measured a 129 Mbps burst that no hardware buffer swallows. Also found that VBR cannot be flattened into CBR by reasonable means. Constant bitrate at the point of export is not nostalgia; it is what a 27 MHz PLL is built to receive and what the testing expects. Variable belongs on MoQ. Constant belongs at IRD decoders. And after the whole trip around the world, the answer was printed on the spec sheet all along: "Frame Synchronization Modes: PCR-Recovered Clock."8
Glossary
- PCR
- Program Clock Reference, timestamps embedded in an MPEG-TS that let a decoder's PLL recover a stable 27 MHz clock.
- PLL
- Phase-Locked Loop, the control loop in a hardware decoder that slaves a local 27 MHz oscillator to the arriving PCR values; it needs regular arrivals and smooth delivery to stay locked.
- IRD / MRD
- Integrated / Multi-channel Receiver-Decoder, broadcast hardware that decodes a compressed transport stream back to baseband (SDI). The unit tested here is a Sencore.
- CBR / VBR
- Constant and variable bitrate. A CBR transport stream pads with null packets to keep the byte rate uniform; a non-stuffed VBR stream does not, and its rate fluctuates with the content.
- Null packet
- A transport packet on PID 0x1FFF, defined by ISO/IEC 13818-1 as the data-rate-stuffing packet; it fills the gaps that keep a CBR stream at constant rate.
- T-STD
- The transport stream system target decoder buffer model: the bytes of a frame must arrive before its decode time, or the buffer underflows.
- TR 101 290
- The ETSI measurement guideline broadcast engineers use to classify transport-stream faults, including PCR accuracy and repetition.
References
- ETSI TR 101 290 V1.3.1, Digital Video Broadcasting (DVB); Measurement guidelines for DVB systems. PCR repetition (PDF p.23): irregular arrival may make the recovered clock jitter, drift or lose lock; DVB permits 100 ms, while 40 ms is identified as the earlier recommendation. PCR accuracy (PDF p.24): "This test should only be performed on a constant bitrate TS", tolerance ±500 ns. The repeated null sequence on p.41 is specifically the out-of-service BER stimulus, not a general operational-input rule. etsi.org (free PDF).
- Tom Waschura, "BER: an invaluable tool in integrated-receiver-decoder testing", EDN, 4 March 1999. On jitter and data rate as "the demise of an otherwise-good IRD design", on "data starving or buffer overrun", and: "ISO/IEC 13818-1 defines the MPEG-2 data-rate-stuffing packet as the null packet." edn.com.
- ISO/IEC 13818-1 / ITU-T H.222.0, MPEG-2 Systems. Primary authority for transport-stream syntax, the T-STD buffer model and PCR accuracy. Clause 2.4.1 (PDF p.27) states that transport packets may be null packets and may be inserted or deleted by remultiplexing, which makes their presence optional at the syntax level. Clause 2.4.2.2 defines T-STD input timing. ITU-T H.222.0 (official PDF).
- Zixi Broadcaster / ZEC v17, "Adding UDP Outputs". "Remultiplex/Pad" is documented as VBR-to-CBR conversion for professional IRDs, with null insertion and PCR adjustment. "No NULL Packets" is documented separately as removing null packets after remultiplexing to reduce bitrate. The page does not specify the resulting wire schedule, downstream re-stuffing or direct-IRD compatibility for the no-null mode. docs.zixi.com.
- TSDuck, MPEG transport stream toolkit, used here to count null packets and measure the inter-PCR window distribution. tsduck.io.
- Luke Curley, "MoQ: Not Another Tech Demo", talk on Media over QUIC: a lean transport that lets the application layer decide what a stream means. youtube.com.
- MoQ PR #2011 / Thomas Drapier and Luke Curley, "Wire the TS/IRD compliance harness into the smoke workflow". The merged harness round-trips MPEG-TS through MoQ and measures structural validity plus broadcast shape. Its README explicitly identifies the current exporter as VBR with no null packets and expected shape warnings; its caveats distinguish PCR-derived file timing from wall-clock delivery. PR #2011 · test/ts README.
- Sencore, MRD 4400 Modular Receiver Decoder datasheet (v24, 2023.02). Lists "Frame Synchronization Modes: PCR-Recovered Clock" for the decoder output, and, on the IP input module, "UDP or RTP" with "Constant Bitrate or Null-Stripped" input. sencore.com (PDF).
Engineering report for technical reference. Status current as of July 7, 2026 and may change. Hardware validation covers one IRD Brand (Sencore); PCR and buffer tolerance may vary across vendors and has not been generalized. Measured results (the burst, the empty windows, the null-packet counts, the confound matrix) are captured with TSDuck and confirmed on real hardware; a small number of statements are flagged in text as reasoned analysis rather than direct measurement. Codec, container, standards and vendor names are used for identification.