MoQ MPEG-TS Catalog Extension
draft-lcurley-moq-mpegts-00
This document is an Internet-Draft (I-D).
Anyone may submit an I-D to the IETF.
This I-D is not endorsed by the IETF and has no formal standing in the
IETF standards process.
| Document | Type | Active Internet-Draft (individual) | |
|---|---|---|---|
| Author | Luke Curley | ||
| Last updated | 2026-09-24 | ||
| RFC stream | (None) | ||
| Intended RFC status | (None) | ||
| Formats | |||
| Stream | Stream state | (No stream defined) | |
| Consensus boilerplate | Unknown | ||
| RFC Editor Note | (None) | ||
| IESG | IESG state | I-D Exists | |
| Telechat date | (None) | ||
| Responsible AD | (None) | ||
| Send notices to | (None) |
draft-lcurley-moq-mpegts-00
moq L. Curley
Internet-Draft 24 September 2026
Intended status: Informational
Expires: 28 March 2027
MoQ MPEG-TS Catalog Extension
draft-lcurley-moq-mpegts-00
Abstract
This document defines the mpegts catalog section, which records what
demultiplexing an MPEG-2 Transport Stream [mpeg2] into a MoQ
broadcast would otherwise lose: each track's PID and PMT descriptors,
the program identity, the service information tables, and a carriage
record for every elementary stream the publisher did not decode. It
is a root member of either the hang catalog [hang] or the MSF catalog
[msf], so a subscriber that ignores it still plays the broadcast and
one that reads it can rebuild the source multiplex.
Note to Readers
This document was generated by an AI model from the implementation at
github.com/moq-dev/moq (https://github.com/moq-dev/moq) and is
maintained alongside it. Submit an issue (https://github.com/moq-
dev/moq/issues) or PR (https://github.com/moq-dev/moq/pulls) if this
spec sucks and you want to fix anything.
Status of This Memo
This Internet-Draft is submitted in full conformance with the
provisions of BCP 78 and BCP 79.
Internet-Drafts are working documents of the Internet Engineering
Task Force (IETF). Note that other groups may also distribute
working documents as Internet-Drafts. The list of current Internet-
Drafts is at https://datatracker.ietf.org/drafts/current/.
Internet-Drafts are draft documents valid for a maximum of six months
and may be updated, replaced, or obsoleted by other documents at any
time. It is inappropriate to use Internet-Drafts as reference
material or to cite them other than as "work in progress."
This Internet-Draft will expire on 28 March 2027.
Curley Expires 28 March 2027 [Page 1]
Internet-Draft moq-mpegts September 2026
Copyright Notice
Copyright (c) 2026 IETF Trust and the persons identified as the
document authors. All rights reserved.
This document is subject to BCP 78 and the IETF Trust's Legal
Provisions Relating to IETF Documents (https://trustee.ietf.org/
license-info) in effect on the date of publication of this document.
Please review these documents carefully, as they describe your rights
and restrictions with respect to this document. Code Components
extracted from this document must include Revised BSD License text as
described in Section 4.e of the Trust Legal Provisions and are
provided without warranty as described in the Revised BSD License.
Table of Contents
1. Conventions and Definitions . . . . . . . . . . . . . . . . . 3
2. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3
3. Comparison with m2ts Packaging . . . . . . . . . . . . . . . 3
4. The mpegts Section . . . . . . . . . . . . . . . . . . . . . 4
4.1. tracks . . . . . . . . . . . . . . . . . . . . . . . . . 5
4.2. programDescriptors . . . . . . . . . . . . . . . . . . . 5
4.3. program . . . . . . . . . . . . . . . . . . . . . . . . . 5
4.4. si . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
4.5. muxRate . . . . . . . . . . . . . . . . . . . . . . . . . 7
4.5.1. SI Track . . . . . . . . . . . . . . . . . . . . . . 7
4.6. Descriptor . . . . . . . . . . . . . . . . . . . . . . . 7
5. Verbatim Tracks . . . . . . . . . . . . . . . . . . . . . . . 8
6. Carriage . . . . . . . . . . . . . . . . . . . . . . . . . . 8
6.1. hang . . . . . . . . . . . . . . . . . . . . . . . . . . 9
6.2. MSF . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
7. Rebuilding a Transport Stream . . . . . . . . . . . . . . . . 9
8. Security Considerations . . . . . . . . . . . . . . . . . . . 10
9. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 10
10. References . . . . . . . . . . . . . . . . . . . . . . . . . 10
10.1. Normative References . . . . . . . . . . . . . . . . . . 10
10.2. Informative References . . . . . . . . . . . . . . . . . 11
Appendix A: Example . . . . . . . . . . . . . . . . . . . . . . . 11
Appendix B: Changelog . . . . . . . . . . . . . . . . . . . . . . 12
draft-lcurley-moq-mpegts-00 . . . . . . . . . . . . . . . . . . 12
Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . 13
Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 13
Curley Expires 28 March 2027 [Page 2]
Internet-Draft moq-mpegts September 2026
1. Conventions and Definitions
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and
"OPTIONAL" in this document are to be interpreted as described in
BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all
capitals, as shown here.
This document uses [mpeg2] terminology for PID, PSI, PAT, PMT, PES,
descriptor, section, and stream_type, and [hang] terminology for
broadcast, track, group, and frame.
A *verbatim* track carries an elementary stream the publisher did not
decode, byte-for-byte.
2. Introduction
A transport stream reaches MoQ in one of two shapes. A publisher can
leave the multiplex intact and carry the packet stream as opaque
payload, which is what [msfts] specifies. Or it can demultiplex,
which is what this document addresses: each elementary stream becomes
its own MoQ track with a codec description, so a relay can drop and
prioritize per track and a subscriber can decode without a transport-
stream parser (Section 3).
Demultiplexing loses everything that is not media: the PID layout,
the PMT descriptors, the program identity, the service information,
and any stream the publisher has no decoder for. The mpegts section
records that. It defines no packaging and no container: decoded
media keeps the container its catalog entry declares, and verbatim
tracks use the framing in Section 5.
3. Comparison with m2ts Packaging
[msfts] carries the transport stream as it arrives: each object is a
run of whole 188- or 192-byte packets, and the receiver demultiplexes
as it always has. This document takes the stream apart at the
publisher and discards the packetization layer, because MoQ already
provides what it was there for:
* *Packet framing* interleaves elementary streams onto one serial
pipe. MoQ delivers each track separately.
* *Null packets* pad a multiplex to a constant bitrate. There is no
bitrate to pad to.
* *The PCR* distributes the multiplex's timebase. Each track
carries its own timestamps.
Curley Expires 28 March 2027 [Page 3]
Internet-Draft moq-mpegts September 2026
* *Continuity counters* detect loss within a stream. That is the
transport's job.
* *PSI repetition* lets a receiver join mid-stream. The catalog is
a track a subscriber fetches on join.
What remains is media in a codec-neutral catalog, plus the signaling
a demultiplexer cannot reconstruct: that is the mpegts section.
+===========+==================+=================================+
| | m2ts packaging | mpegts section |
+===========+==================+=================================+
| MoQ track | one per program | one per elementary stream |
+-----------+------------------+---------------------------------+
| Object | whole source | one media frame, or one |
| payload | packets | verbatim PES payload or section |
+-----------+------------------+---------------------------------+
| Packaging | m2ts | none defined; media keeps its |
| | | own |
+-----------+------------------+---------------------------------+
| Catalog | m2ts* members on | one mpegts root member |
| | each track | |
+-----------+------------------+---------------------------------+
| Relay | caches and drops | drops and prioritizes per |
| | whole objects | elementary stream |
+-----------+------------------+---------------------------------+
Table 1
The two overlap only on program identity: m2tsProgramNumber and
m2tsPmtPid against Section 4.3, and m2tsPsiInterval against a per-PID
interval (Section 4.4). They do not collide, since those members sit
on a track and this section sits at the root. A track is one shape
or the other.
4. The mpegts Section
A publisher that demultiplexed a transport stream SHOULD add an
mpegts root member to its catalog (Section 6):
type Mpegts = {
"tracks": Map<TrackName, Track> | undefined,
"programDescriptors": Descriptor[] | undefined,
"program": Program | undefined,
"si": Map<PidString, Si> | undefined,
"muxRate": number | undefined,
}
Curley Expires 28 March 2027 [Page 4]
Internet-Draft moq-mpegts September 2026
Every member is optional and a publisher MUST omit an empty one, so a
broadcast with nothing to record omits the section entirely.
4.1. tracks
tracks maps a MoQ track name to that track's MPEG-TS identity:
type Track = {
"pid": number,
"descriptors": Descriptor[] | undefined,
"verbatim": Verbatim | undefined,
}
pid is the track's PID in the source, 0..8191. A publisher MUST NOT
record 0x0000 (PAT) or 0x1FFF (null packets), which carry no
elementary stream.
descriptors are the track's ES-level descriptors from the PMT
(Section 4.6), in PMT order.
verbatim marks a track carrying an undecoded elementary stream
(Section 5). A decoded track MAY appear here too, to preserve its
pid and descriptors. A consumer MUST ignore an entry with neither a
verbatim record nor a track the catalog describes.
4.2. programDescriptors
The PMT's program-level descriptors (program_info), in PMT order
(Section 4.6).
4.3. program
The program identity from the PAT:
type Program = {
"transportStreamId": number,
"programNumber": number,
"pmtPid": number,
}
transportStreamId, programNumber (the DVB service id), and pmtPid
come from the PAT. They are the only service-layer fields this
document parses; everything else about the program stays inside the
opaque si tables.
A publisher MUST include program when the broadcast came from a
transport stream, and omit it otherwise.
Curley Expires 28 March 2027 [Page 5]
Internet-Draft moq-mpegts September 2026
4.4. si
The standalone service information tables, keyed by the PID they ride
on and then by table_id:
type Si = Map<TableIdString, SiEntry>
type SiEntry = {
"track": string,
"interval": number | undefined,
}
JSON object keys are strings, so both are decimal with no leading
zeros: "17" for PID 0x0011, "66" for table_id 0x42. A consumer MUST
refuse a catalog whose PID key is not an integer in 0..8191, or whose
table_id key is not an integer in 0..255. A consumer MAY
additionally accept the pre-table_id form, where a PID maps to
{"interval", "sections"} with the sections inline: it decodes into
one entry per table_id (byte 0 of each section) naming no track. A
producer MUST NOT write that form.
table_id is byte 0 of generic section syntax ([mpeg2] Section 2.4.4),
so the key is no less generic than the PID; which ranges mean what is
a delivery-system convention this document does not rely on.
track names the snapshot track carrying the entry's sections
(Section 4.5.1), published in the same broadcast as the catalog. The
sections are not in the catalog: a full EPG is megabytes and would be
republished on every unrelated catalog change.
interval bounds how often a rebuilt stream repeats the entry's
sections, in milliseconds. A publisher SHOULD use its delivery
system's maximum repetition interval for that table_id, for example
[dvbrep] for DVB: 2000 for SDT actual and EIT present/following
actual, 10000 for the NIT, the BAT, SDT other and EIT schedule
actual, 30000 for EIT schedule other. It MUST omit interval for a
table_id whose requirement it does not know; a consumer then falls
back to its own PSI cadence. The key is table_id rather than PID
because that is the granularity the requirements are defined at: one
PID carries tables wanting different rates.
PAT and PMT are never carried here: they are rebuilt from program,
programDescriptors, and the per-track entries.
Curley Expires 28 March 2027 [Page 6]
Internet-Draft moq-mpegts September 2026
4.5. muxRate
The rate the source's PCR clock paced the whole multiplex at, in bits
per second: every PID, the PSI, and the null packets, measured as the
packets between two PCRs over the time they span. It is not a sum of
the elementary streams, and a track's own bitrate keeps its codec
meaning.
A publisher MUST include muxRate only while the source holds a
constant rate, and MUST omit it for a variable-rate or unpaced
source; a value that has become invalid is removed rather than left
stale. A consumer rebuilding a transport stream SHOULD pad its
output with null packets to muxRate (Section 7).
4.5.1. SI Track
Each group is a complete picture of the entry's current sections: one
frame per sub-table, each frame that sub-table's sections
concatenated verbatim in section_number order. Sections are self-
delimiting through section_length, so a frame needs no further
framing. A joiner reads only the newest group.
Frames apply in order and a later frame replaces an earlier one of
the same sub-table, so a publisher MAY append a revision within a
group rather than opening a new one. A publisher MUST commit a
revised sub-table whole: no group may expose part of one version
beside part of another.
A sub-table is identified by its table_id_extension, plus the bytes
that disambiguate it where the extension alone does not:
original_network_id for SDT other, and transport_stream_id with
original_network_id for the EIT, whose extension is a service id
unique only within a transport stream. A short-form section carries
no extension, version, or numbering, so its table_id is one latest-
value slot and each arrival replaces the last; that is what lets a
time table be proxied rather than synthesized.
4.6. Descriptor
One PMT descriptor:
type Descriptor = {
"tag": number,
"data": string,
}
Curley Expires 28 March 2027 [Page 7]
Internet-Draft moq-mpegts September 2026
tag is the descriptor_tag (0x05 registration, 0x0A ISO-639 language,
...), 0..255. data is the body after the tag and length, base64
([RFC4648], Section 4).
Descriptors are never parsed, so a consumer MUST re-emit a list in
order and MUST NOT reorder, merge, or drop entries.
5. Verbatim Tracks
An elementary stream the publisher does not decode rides its own MoQ
track, byte-for-byte:
type Verbatim = {
"streamType": number,
"framing": "pes" | "section",
"streamId": number | undefined,
}
streamType is the PMT stream_type to re-announce: 0x86 for SCTE-35
[scte35], 0x06 for private PES, 0x05 for private sections.
framing says how the payload is framed, defaulting to "pes". With
"pes" each frame is one complete PES payload, timestamped with its
PTS, or 0 if it carried none. With "section" each frame is one
complete section, header and CRC included, timestamped with the media
time it arrived at. A consumer MUST refuse a catalog that names a
framing it does not recognize, rather than guess.
streamId is the original PES stream_id, for example 0xBD
(private_stream_1) for teletext, DVB subtitles, and DVB AC-3. It
applies only to "pes" framing. A publisher SHOULD record it, since
strict demultiplexers reject a relabeled PES; a consumer with none
falls back to private_stream_1.
Each frame MUST be a keyframe in its own group: a verbatim payload is
all-or-nothing.
A verbatim track has no codec, dimensions, or decoder configuration,
so a publisher MUST NOT describe it as a media rendition and MUST
describe it only by its tracks entry. Nothing there declares a
container, so its frames use hang's legacy container ([hang]): a
varint microsecond timestamp followed by the payload.
6. Carriage
The section is the same JSON in either catalog format.
Curley Expires 28 March 2027 [Page 8]
Internet-Draft moq-mpegts September 2026
6.1. hang
A root member named mpegts, alongside video and audio ([hang]). hang
carries a decoder config's raw bytes as hex while every binary field
here is base64; the alphabets overlap, so the encoding cannot be
detected and is stated per field above.
6.2. MSF
A root member named mpegts, alongside tracks ([msf]). A publisher
MUST NOT name a section after a member MSF itself defines.
The keys of the section's own tracks member are MSF track names; a
decoded track also has an MSF track object, a verbatim track does
not.
This document defines no packaging value; [msfts] registers m2ts for
the passthrough shape (Section 3).
7. Rebuilding a Transport Stream
A consumer rebuilding a transport stream:
* MUST place each track on its recorded pid, and MUST assign an
unused PID to a track with none.
* MUST put the PMT on program.pmtPid and build the PAT and PMT from
program.
* MUST re-emit each track's descriptors as its ES-level descriptors,
and programDescriptors as the PMT's program_info.
* MUST re-emit each si entry's sections byte-for-byte on that
entry's PID, reading them from its track (Section 4.5.1), at least
as often as its interval when declared.
* MUST repacketize each verbatim track per its framing and
streamType, using streamId when recorded.
* SHOULD pad the output with null packets to muxRate when present,
so the rebuilt stream is constant-rate again; a source that
exceeds the rate is passed through rather than delayed or dropped.
With no program the consumer synthesizes an identity, and SHOULD then
omit any carried si, which describes a program that no longer exists.
Curley Expires 28 March 2027 [Page 9]
Internet-Draft moq-mpegts September 2026
A consumer MAY derive implied signaling: a program carrying a
section-framed 0x86 stream and no programDescriptors implies the
SCTE-35 CUEI registration descriptor. A consumer MUST NOT derive one
that contradicts a recorded descriptor.
8. Security Considerations
Every binary field here is re-emitted without inspection, by a
publisher that never parsed it and a relay that never looked, so a
consumer MUST treat all of it as untrusted input.
Nothing bounds the number of entries in the section, nor the size of
an SI track: a publisher controls both, and an EPG is large by
nature. A consumer MUST bound what it accepts of each, and MUST
reject a catalog it cannot bound rather than truncate it into a
stream that silently differs from what was described. PIDs, program
numbers, and stream types are 13-, 16-, and 8-bit values in a JSON
document that can hold any number, so a consumer MUST range-check
each one. A catalog can also name one PID twice, so a consumer MUST
NOT emit a stream in which two elementary streams share a PID, or in
which an SI table shares a PID with PAT, PMT, null packets, or an
elementary stream.
The section makes a broadcast's provenance legible to anything that
can read the catalog, relays included: the service name, provider,
and network inside the carried SI, and the original PID layout. A
publisher that does not want that MUST omit the section.
9. IANA Considerations
This document requests no registrations.
Should [msf] establish a registry of catalog root members, this
document requests registration of mpegts with this document as the
reference.
10. References
10.1. Normative References
[hang] Curley, L., "Media over QUIC - Hang", Work in Progress,
Internet-Draft, draft-lcurley-moq-hang-02, 3 August 2026,
<https://datatracker.ietf.org/doc/html/draft-lcurley-moq-
hang-02>.
Curley Expires 28 March 2027 [Page 10]
Internet-Draft moq-mpegts September 2026
[mpeg2] ISO/IEC, "Information technology - Generic coding of
moving pictures and associated audio information:
Systems", ISO/IEC 13818-1, 2023,
<https://www.iso.org/standard/83239.html>.
[msf] Law, W. and S. Nandakumar, "MOQT Streaming Format", Work
in Progress, Internet-Draft, draft-ietf-moq-msf-01, 2 June
2026, <https://datatracker.ietf.org/doc/html/draft-ietf-
moq-msf-01>.
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119,
DOI 10.17487/RFC2119, March 1997,
<https://www.rfc-editor.org/rfc/rfc2119>.
[RFC4648] Josefsson, S., "The Base16, Base32, and Base64 Data
Encodings", RFC 4648, DOI 10.17487/RFC4648, October 2006,
<https://www.rfc-editor.org/rfc/rfc4648>.
[RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC
2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174,
May 2017, <https://www.rfc-editor.org/rfc/rfc8174>.
10.2. Informative References
[dvbrep] ETSI, "Digital Video Broadcasting (DVB); Guidelines on
implementation and usage of Service Information (SI)",
ETSI TS 101 211, <https://www.etsi.org/standards>.
[msfts] Gregoire, P. and G. Simon, "MPEG-2 Transport Stream
Packaging for MOQT", Work in Progress, Internet-Draft,
draft-gregoire-moq-msfts-01, 24 September 2026,
<https://datatracker.ietf.org/doc/html/draft-gregoire-moq-
msfts-01>.
[scte35] SCTE, "Digital Program Insertion Cueing Message", SCTE 35,
<https://www.scte.org/standards/>.
Appendix A: Example
A broadcast demultiplexed from a DVB transport stream: video and
audio described as ordinary renditions, a verbatim SCTE-35 stream,
and the source's SDT Actual (table_id 0x42 on PID 0x0011) carried
opaquely on its own track.
Curley Expires 28 March 2027 [Page 11]
Internet-Draft moq-mpegts September 2026
{
"mpegts": {
"program": {
"transportStreamId": 4660,
"programNumber": 1,
"pmtPid": 100
},
"programDescriptors": [
{ "tag": 5, "data": "Q1VFSQ==" }
],
"tracks": {
"video0": { "pid": 257 },
"audio0": {
"pid": 258,
"descriptors": [ { "tag": 10, "data": "ZW5nAA==" } ]
},
"0.ts": {
"pid": 500,
"verbatim": { "streamType": 134, "framing": "section" }
}
},
"si": {
"17": {
"66": { "track": "si/17/66", "interval": 2000 }
}
}
}
}
Appendix B: Changelog
draft-lcurley-moq-mpegts-00
* Initial version.
* The Si type is keyed by table_id only; the PID lives on the
enclosing si map.
* A consumer refuses a catalog with an unrecognized framing or an
invalid si map key.
* Added muxRate, the source's constant multiplex rate.
* A consumer may read the pre-table_id inline sections form; writing
stays track-only.
Curley Expires 28 March 2027 [Page 12]
Internet-Draft moq-mpegts September 2026
Acknowledgments
This document was drafted with the assistance of Claude, an AI
assistant by Anthropic.
Author's Address
Luke Curley
Email: kixelated@gmail.com
Curley Expires 28 March 2027 [Page 13]