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 | undefined, "programDescriptors": Descriptor[] | undefined, "program": Program | undefined, "si": Map | 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 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, . 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, . [msf] Law, W. and S. Nandakumar, "MOQT Streaming Format", Work in Progress, Internet-Draft, draft-ietf-moq-msf-01, 2 June 2026, . [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997, . [RFC4648] Josefsson, S., "The Base16, Base32, and Base64 Data Encodings", RFC 4648, DOI 10.17487/RFC4648, October 2006, . [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, May 2017, . 10.2. Informative References [dvbrep] ETSI, "Digital Video Broadcasting (DVB); Guidelines on implementation and usage of Service Information (SI)", ETSI TS 101 211, . [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, . [scte35] SCTE, "Digital Program Insertion Cueing Message", SCTE 35, . 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]