Skip to main content

MoQ MPEG-TS Catalog Extension
draft-lcurley-moq-mpegts-00

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]