One rule for which packet a unit's facts come from

A parser that assembles an access unit across PES packets has to answer
one question for every unit it emits: which packet carried this unit's
FIRST byte? Its timestamp comes from that packet, and so does the source
byte offset that says which clip of a multi-clip title it belongs to.
The packets that complete the unit carry later values that must not
override it.

That question was being answered three ways. DTS kept a deque of
(offset, pts) markers and took the one covering offset 0. AC-3 kept a
single carry-over timestamp. TrueHD kept its own. PGS and DVD subtitles
each held a pending unit with just a start time. None of them carried
the source offset at all, which is why provenance existed only for video
and why nine audio and subtitle tracks on a branched title had nothing
to place them by.

So it lives in one place now. PesBuf owns the bytes AND the marks;
PesFacts returns a packet's timestamp, source and discontinuity
together, so a parser cannot take one from one packet and another from
the next, because it does not assemble them itself.

The type answers WHICH packet. How a codec reads a timestamp out of that
packet stayed the codec's business at first, and that turned out to be
the same drift one level down: dvdsub read pts alone and returned 0 for
a packet carrying only dts, while everything else took pts.or(dts). Now
there is one derivation. It is not a choice between two fields — for
audio and subtitles there is no reordering, so dts IS the presentation
time and reading it is reading the same value from whichever field the
packet used. Reordering video never calls it; that path reconstructs
display order instead.

Migrated: adts, pgs, dvdsub. dts, ac3 and truehd follow.
This commit is contained in:
Matthew Jackson
2026-08-07 07:19:58 -07:00
parent b16eacd6b4
commit 813edd0965
5 changed files with 356 additions and 25 deletions
+6 -2
View File
@@ -112,10 +112,14 @@ impl CodecParser for AdtsParser {
}
self.tally.record_kept();
// One PES is one unit here, so the unit's first byte is in THIS packet
// and its facts are this packet's -- the same rule the buffering
// parsers apply through `PesBuf::front`, with nothing carried over.
let facts = super::pesbuf::PesFacts::of(pes);
vec![Frame {
discontinuity: pes.discontinuity,
discontinuity: facts.discontinuity,
coding: None,
source: None,
source: facts.source,
pts_ns,
keyframe: true,
data: pes.data.clone(),