Language: Go (moqtransport, moqlivemock) + TypeScript/JavaScript (warp-player)
Organization: Eyevinn Technology
Maintainer: Torbjörn Einarsson
GitHub: Eyevinn/moqtransport · Eyevinn/moqlivemock · Eyevinn/warp-player
Demo: moqlivemock.demo.osaas.io
Draft support: draft-18 (migrated 2026-08-30, ALPN-based version negotiation). Latest tags: moqlivemock v0.16.1 (Sep-30, 2026) + warp-player v0.16.0 (Sep-29): priority-scheduled raw-QUIC streams plus paint-model and LOCMAF subtitle tracks (see Recent Highlights). They build on the v0.15.0 baseline of Sep-16, which put real Track Namespace tuples on the wire and moved to pull-based SUBSCRIBE_NAMESPACE discovery so the mlmpub → mlmrel → warp-player chain works through a relay (see Namespaces). Underneath is the Go library moqtransport v0.14.0 “§7.2 stream tiering over quic-go v0.62.0” (Sep-29; v0.13.0 “RENDEZVOUS_TIMEOUT on SUBSCRIBE” Sep-2; v0.11.0 draft-18 rewrite Aug-30, v0.11.1 “qlog payload cap” Aug-31, v0.12.0 “receive-side fixes for relays” Sep-1, the base of the mlmrel relay). Prior wave: v0.14.0 “draft-18 rewrite” tags on 2026-08-31.
Packaging formats: CMSF, LOC (HEVC + AVC + AAC + Opus), MSF, moq-mi (since v0.8.0), LOCMAF v0.1
Overview
Eyevinn’s MoQ stack spans three repositories that together cover the full media pipeline: a Go transport library, a Go live publisher/subscriber test app, and a browser-based TypeScript player using MSE. It exercises CMSF, LOC, MSF, moq-mi, and LOCMAF packaging with commercial DRM and interop testing.
Components
moqtransport
- GitHub: Eyevinn/moqtransport — Go. Latest: v0.13.0 “RENDEZVOUS_TIMEOUT on SUBSCRIBE” (Sep 2, 2026; v0.12.0 “receive-side fixes for relays” Sep 1, v0.11.1 “qlog payload cap” Aug 31, v0.11.0 draft-18 rewrite Aug 30).
- Media over QUIC Transport library implementing moq-transport draft-18 (migrated from draft-14/16 in v0.11.0; see moqtransport for the fork/upstream split).
moqlivemock
- GitHub: Eyevinn/moqlivemock — Go. Latest release: v0.16.1 (Sep-30, 2026), which fixes Safari opening no WebTransport streams to
mlmpub/mlmrelby advertising the server’s initial stream and data limits (#152). It follows v0.16.0 (Sep-29): publisher-priority stream scheduling (#148) and experimental paint-model subtitles (#149, +1,084/−262). Before that: v0.15.1 (Sep-21, auint64loop-duration fix +altGroupsnaming cleanup) on the v0.15.0 “real namespace tuples + pull-based namespace discovery” (Sep 16, 2026, #141, +740/−210 — breaking wire changes, see Namespaces; the first release to tag themlmrelrelay). Prior: v0.14.0 “draft-18 rewrite” (Aug 31, 2026, tagging the draft-18 migration merged tomainAug 30 via #129; v0.14.0 also moved the LOC Timestamp property to0x10per draft-ietf-moq-loc-04, #130). - Live MoQ publisher (
mlmpub) and subscriber (mlmsub) test tools with CMSF, LOC, MSF, moq-mi, and LOCMAF media support, DRM, and interop testing — plusmlmtestfor the interop-runner framework, and (since Sep-1, 2026) a relaymlmrel. mlmrel— MoQ relay (#136, Sep-1, 2026, +2913/−233): a MoQ relay with fanout, a group cache, and FETCH relaying, built on moqtransport v0.12.0. Gives the Eyevinn stack its own relay role alongside publisher/subscriber/interop-client. Hardened for the interop-runner on Sep-2 (see below), then shipped in a tagged release (v0.15.0, Sep-16) — the release notes report “All six moq-interop-runner relay test cases pass.” It accepts pub/sub over QUIC and WebTransport on one port, preserves group/subgroup/object IDs, priorities, statuses, object properties and the END_OF_GROUP bit, ends subgroups downstream exactly as upstream (FIN→FIN / reset→reset via moqtransportSubgroupEndEvents), serves FETCHes from its group cache when covered and proxies otherwise, and — as of v0.15.0 — answers namespace discovery via SUBSCRIBE_NAMESPACE (querying its own upstream), which is what lets a relay sit in front of another relay at all. OPEN:moqt://subscriber URLs + Setup-Options path/authority inmlmsub(#134).- Runner packaging (#137, +167/−0):
Dockerfile.mlmrel+entrypoint-relay.shpublishghcr.io/eyevinn/mlmrelfrom CI, mapping the runner’sMOQT_ROLE/MOQT_PORT/MOQT_CERT/MOQT_KEY/MOQT_MLOG_DIRcontract to mlmrel flags, with best-effort qlog when the bind-mounted mlog dir isn’t writable. - Answer-don’t-hang fixes (#138, +145/−12): a SUBSCRIBE the relay can’t accept now gets REQUEST_ERROR NOT_SUPPORTED with the decode error as reason (surfaced by moxygen’s undefined SUBSCRIPTION_FILTER type 250), and a new
-upstream-timeout(default 5s) bounds the wait for an upstream answer, replying TIMEOUT downstream instead of letting the requester hang. - Subscriber-owned rendezvous hold (#139, +105/−58): per draft-18 §10.2.6 the hold is now the subscriber’s RENDEZVOUS_TIMEOUT capped by
-max-rendezvous(default 10s) — DOES_NOT_EXIST at once when the parameter is absent, TIMEOUT when the hold expires. The fixed-pending-waitis gone; needs moqtransport v0.13.0.
- Runner packaging (#137, +167/−0):
warp-player
- GitHub: Eyevinn/warp-player — JavaScript / TypeScript. Latest: v0.16.0 (Sep 29, 2026 — #198, +3,362/−78: text subtitles from the catalog’s CMAF and LOCMAF subtitle tracks, with TTML laid out by imscJS and WebVTT by the player’s own renderer; the experimental paint-model
stpc/wvtcformats; a Subtitles/CC selector; a per-track bitrate/parse-cost table; and an MSF catalogversionof"1"now accepted alongside"draft-01"). Prior: v0.15.0 (Sep 16, 2026 — #193 “discover namespaces with SUBSCRIBE_NAMESPACE and encode them as tuples”, +486/−43: the player now sends SUBSCRIBE_NAMESPACE on connect with a “Namespace prefixes” filter field and encodes namespaces as real tuples, so it plays through a relay; pair with moqlivemock v0.15.0). Prior: v0.14.0 “draft-18 rewrite” (Aug 31, 2026 — breaking #190 “speak MoQ Transport draft-18 only”, dropping the draft-14/16 paths). - Browser-based player for CMSF media (MSE), LOC media (WebCodecs), and LOCMAF (compressed CMAF) over MoQ. Supports Widevine, PlayReady, FairPlay, and ClearKey on the MSE path. CTA-608 closed-caption extraction + overlay rendering landed Aug 2–3, 2026 on both the WebCodecs/LOC and MSE/CMAF+LOCMAF paths, with the CC on/off toggle completed Aug 3 (see Recent Highlights). Captions render for AVC and HEVC but not yet AV1 (AV1 caption extraction is not yet supported in the common media library); the CC button is struck through when captions are impossible.
Catalog Handling
Supports both FETCH and SUBSCRIBE for retrieving the MSF catalog. Each cmsf/* and msf/* namespace serves its own catalog describing the available tracks under that namespace. The moq-mi/clear namespace has no catalog — moq-mi is identified by namespace prefix convention (see IsMoqMINamespace in internal/sub/moqmi.go).
Media Support
- Video: H.264, HEVC, AV1 (AV1 in the CMSF/CMAF + LOCMAF path only — gracefully excluded from LOC/moq-mi; warp-player AV1 playback landed July 22 via the WebCodecs/LOC pipeline)
- Audio: AAC, Opus, AC-3
- Subtitles: wvtt, stpp (dynamically generated with timestamps and group numbers); since v0.16.0 also experimental paint-model tracks
subs_stpc_{lang}/subs_wvtc_{lang}(Eyevinn/paint-model-subtitles, off by default), a_locmafvariant of every subtitle track, and a measured catalogbitratefor each. Subtitle groups now carry one CMAF chunk per video object instead of one per second, and each format has its own altGroup. warp-player v0.16.0 renders all of them. - Closed captions: CTA-608 — auto-generated in-band caption SEI messages injected by
mlmpubacross the CMAF/LOCMAF/LOC/moq-mi serve paths and all three video codecs (AVC/HEVC/AV1), advertised in the catalog as an accessibility descriptor with cross-packaging decode round-trip verified (July 2026); a-cc608modeflag selects paint-on (default) / pop-on / roll-up presentation (Aug 2026). Player-side rendering is complete for AVC/HEVC; AV1 caption rendering is pending common-media-library support. - Sync: Wall-clock synchronized — group X starts at second X, video clock aligned with UTC modulo 10s, audio beeps on seconds
- Format: CMSF (CMAF chunks over MOQT)
Namespaces
mlmpub exposes a fixed set of namespaces, each carrying a different packaging and (for CMSF) protection mode. Subscribers pick a namespace to select packaging/protection.
Since v0.15.0 (Sep-16, 2026) namespaces are real ordered tuples on the wire, and discovery is pull-based. Per draft-18 §2.4.1 a Track Namespace is an ordered set of fields matched a field at a time (§8.4), so the earlier single slash-joined field (cmsf/clear as one field) never matched a prefix and could not work through a relay. The content namespaces now carry a leading publisher field set by -nsprefix (default mlm) — e.g. the tuple ("mlm","cmsf","clear"), written mlm/cmsf/clear in string form — so one SUBSCRIBE_NAMESPACE covers a whole publisher on a shared relay and two mlmpub instances on one relay can be told apart. ("moq-test","interop") keeps no prefix — the interop runner addresses it by that exact tuple. And mlmpub no longer announces unprompted: per §6.1 it answers SUBSCRIBE_NAMESPACE (the in-band discovery mechanism) and pushes nothing; mlmsub -discover and warp-player ask for namespaces (falling back to listening on NOT_SUPPORTED). The table below shows the packaging suffix of each namespace (the string form omitting the -nsprefix):
| Namespace (suffix) | Packaging | Protection | Details |
|---|---|---|---|
cmsf/clear | CMSF (CMAF chunks) | None | Unencrypted CMSF — default for mlmsub (full default tuple mlm/cmsf/clear) |
cmsf/drm-{scheme} | CMSF (CMAF chunks) | Commercial DRM | Widevine, PlayReady, FairPlay via CPIX; {scheme} = cenc or cbcs |
cmsf/eccp-{scheme} | CMSF (CMAF chunks) | ClearKey / ECCP | Explicit key delivery via HTTP /clearkey side endpoint |
msf/clear | LOC (raw codec frames) | None | MSF catalog describing LOC tracks (HEVC + AVC + AAC + Opus) |
moq-mi/clear | moq-mi | None | MoQ Media Interop format (no catalog; convention-based namespace prefix) |
All five namespaces are exposed concurrently when mlmpub runs, so subscribers can choose the packaging and protection model independently. The CMSF DRM/ECCP namespaces are only exposed when a DRM config or ClearKey IV/KID is provided. The CMSF catalog now carries the namespace actually announced (prefix included), so catalog and wire cannot drift.
CMSF ContentProtection
The CMSF ContentProtection signaling spec (moq-wg/cmsf PR #18, merged Apr 14) was proposed by Eyevinn based on the moqlivemock implementation. DRM support in moqlivemock and warp-player was implemented by Hugo Björs (Eyevinn). warp-player supports Widevine, PlayReady, FairPlay, and ClearKey/ECCP. It was the first running implementation, now joined by shaka-player (PR #9972, also merged Apr 14).
LOCMAF (Low Overhead CMAF)
LOCMAF is a compact LOC-inspired/compatible CMAF packaging format for MoQT, encoding only the non-derivable moof/moov fields as MoQT key-value pairs using QUIC varints (first object = full moof, subsequent objects = delta moofs). It carries a locmafVersion field in the CMSF catalog and follows a locmaf-vX.Y git-tag snapshot policy. v0.1 shipped in moqlivemock/warp-player v0.9.0 (May 17, 2026), including an encoder/decoder, a cmd/locmaf roundtrip CLI, a design doc, and a DRM section. Initial support originated in a Master’s-thesis context (Hugo Björs). See media-packaging for the full design and comparison vs. compressed-mp4.
Demo
- Live demo: moqlivemock.demo.osaas.io
- shaka-player by Álvaro Velad Galván (Atème) works with moqlivemock including subtitle display and DRM
Recent Highlights (as of September 2026)
Day-by-day PR/issue history lives in the wiki log; this section keeps only durable milestones.
- v0.16 wave: priority-scheduled streams, and subtitles become a first-class track type (Sep-29/30, 2026; moqlivemock v0.16.0/v0.16.1, warp-player v0.16.0, moqtransport v0.14.0). moqtransport v0.14.0 applies the transport draft’s §7.2 stream tiering (priority-ordered stream scheduling) over quic-go v0.62.0 (#26).
mlmpubandmlmrelnow use it to schedule raw-QUIC streams by publisher priority: catalog 0, audio and subtitles 64, video 128, where previously everything was 128. Go 1.26 is now required. On the media side, subtitles gain paint-modelstpc/wvtcformats and LOCMAF variants (see Media Support), and warp-player plays CMAF and LOCMAF text subtitles in sync with the picture. v0.16.1 fixes Safari WebTransport, which had stalled before SETUP because the server advertised no initial stream/data limits. - The stack learns to work through a relay — tuple namespaces + pull-based discovery (Sep-16, 2026, v0.15.0 across moqlivemock #141 and warp-player #193): the
mlmpub → mlmrel → warp-playerchain did not work with a relay in between, for two real reasons, both fixed as breaking wire changes. (1) Namespaces went out as a single slash-joined Track Namespace Field, which per draft-18 §2.4.1/§8.4 matched a prefix never (a probe showed prefix("cmsf")→ 0 matches); they are now ordered tuples with a-nsprefixpublisher field (defaultmlm, e.g.("mlm","cmsf","clear")), while("moq-test","interop")stays unprefixed for the runner. (2) Discovery was push-only (unsolicited PUBLISH_NAMESPACE to every session); per §6.1 it is now pull-based —mlmpubanswers SUBSCRIBE_NAMESPACE and pushes nothing,mlmrelannounces only to peers that asked and queries its own upstream (enabling relay-behind-relay), and warp-player sends SUBSCRIBE_NAMESPACE on connect with a “Namespace prefixes” filter. Testing also fixed a warp-player request-ID collision and anmlmreldead-upstream-detection bug. Net: the Eyevinn stack is now a relay-tested draft-18 media stack, andmlmrelships in its first tagged release (see below). mlmrel— the stack gains its own relay, and takes it into the interop runner (Sep-1→2, 2026): moqlivemock added a MoQ relay with fanout, group cache and FETCH relaying (#136, +2913/−233) on moqtransport v0.12.0, giving the Eyevinn stack a fourth role beyondmlmpub/mlmsub/mlmtest. On Sep-2 it was packaged and hardened for the interop-runner: a CI-publishedghcr.io/eyevinn/mlmrelimage (#137), two answer-don’t-hang fixes (#138 — REQUEST_ERROR NOT_SUPPORTED for un-decodable SUBSCRIBE parameters,-upstream-timeoutbounding the upstream wait), and a draft-18 §10.2.6 rendezvous fix (#139) moving the pending-SUBSCRIBE hold from a fixed-pending-waitto the subscriber’s RENDEZVOUS_TIMEOUT — which required exposing that parameter in moqtransport v0.13.0 (#25). Registered as a runner relay (runner #120,moqt://relay:4443, sincemlmtestdials raw QUIC). Now tagged — mlmrel ships in v0.15.0 (Sep-16), which also moved its namespace discovery to SUBSCRIBE_NAMESPACE (see the top highlight); the release reports all six runner relay cases pass.- Draft-18 migration → v0.14.0 tags (Aug 30–31, 2026): the Eyevinn stack moved off draft-14/16 to moq-transport draft-18 ahead of the Sep-2 virtual interop hackathon, and tagged v0.14.0 “draft-18 rewrite” across the stack on Aug-31. The Go library moqtransport shipped the draft-18 rewrite as v0.11.0 (PR #18, +16,989/−13,359, Aug-30), bumped to v0.11.1 (“qlog payload cap”, Aug-31); moqlivemock migrated in PR #129 (+977/−436, Aug-30) then cut v0.14.0 (Aug-31), which also moved the LOC Timestamp property to
0x10per draft-ietf-moq-loc-04 (#130); warp-player cut a breaking v0.14.0 (#190 “speak MoQ Transport draft-18 only”, Aug-31). The migration surfaced a §11.4.4.2 End-of-Range clarity question tobbee filed as moq-transport #1861, but afrind closed it Aug-31 as “agentic output” (part of a WG-wide crackdown on AI-generated issues; see moq-transport open questions and discussions-2026-08) — the underlying question stands unresolved, awaiting a re-file in the WG’s preferred human style. - Coordinated v0.13.0 release wave (Aug 6): moqlivemock v0.13.0, warp-player v0.13.0, and moqtransport v0.10.0 shipped together, consolidating the CTA-608 caption + AV1 work. moqlivemock gained a selectable
-cc608mode(paint-on default / pop-on / roll-up, #125), ago-608v0.9.0 bump (#124), and a deterministic catalog codec ordering (video AVC → HEVC → AV1, audio AAC → Opus → AC-3, #126); warp-player added a struck-through CC button when captions are impossible (#180) and completed its cc608 end-to-end verification (#177). AV1 now carries CTA-608 like AVC/HEVC on both the WebCodecs and MSE/EME paths, though warp-player does not yet render AV1 captions. This wave shipped on draft-14 & draft-16; the stack has since migrated to draft-18 (Aug 30, 2026 — see the top highlight). - CTA-608 in-band closed captions (Jul 24–25):
mlmpubgained an internalcc608package that generates CTA-608 caption data as H.264/HEVC SEI messages (PR #114), injected across all four serve paths — CMAF/LOCMAF/LOC/moq-mi (PR #115), then advertised in the catalog as an accessibility descriptor with cross-packaging decode-round-trip verification (PR #117, merged Jul 25, +278/−5) — completing the publisher side of the caption epic. The warp-player player side landed Aug 2 (resolving warp-player #156): CTA-608 extraction on both the WebCodecs/LOC path (warp-player #169) and the MSE/CMAF+LOCMAF path (#171), plus a timed-text overlay seam + CTA-608 renderer (#170, ~4,700 LOC total). The CC on/off toggle + caption-sink wiring completed Aug 3 (#173 merged), closing the CTA-608 capture→publish→extract→render round trip end to end. An encrypted-playback thread then opened: a test proving CTA-608 captions survive cbcs subsample encryption (#174 merged Aug 3) landed alongside a new bug — encrypted playback failing on the first audio packet (warp-player #175, OPEN, blocking the encrypted interop rows). Makes the Eyevinn stack an accessibility-signaling testbed on top of its AVC/HEVC/AV1 codec coverage. - AV1 as a first-class CMSF codec (Jul 21, PR #102): AV1 (
av01) joins AVC and HEVC in the CMSF/CMAF + LOCMAF path — SVT-AV1 low-delay CBR test content, appearing in every CMSF catalog as CMAF + LOCMAF renditions, with a newCodec:overlay line on all generated video. AV1 is gracefully excluded from LOC/moq-mi (those paths keep AVC/HEVC). moqlivemock’s first AV1-over-MoQ media path. warp-player AV1 playback landed the next day (Jul 22, warp-player PR #155, +440/−9) — AV1 (av01) video decode via the WebCodecs/LOC pipeline — completing the AV1 capture→publish→play round trip. Separately, a “Add TS support” request (issue #103) was filed by Álvaro Velad Galván (Shaka Player). - Joining-FETCH catalog retrieval (Jul 4) landed across all three repos: a subscriber retrieves the current catalog object via a relative joining FETCH instead of SUBSCRIBE-and-wait. moqtransport v0.9.0 (PR #14) added publisher-side joining-FETCH resolution (draft-16); moqlivemock (PR #95) added a
-catalog-modeflag; warp-player (PR #149) mirrored it in the TS/MSE player. - LOCMAF: frozen, DRM-capable, then extracted (May–Jul): the wire format froze at v0.1 in v0.9.0 (May 17), publisher and player released together for interop, with an end-to-end encrypted path (encrypted-CMAF → LOCMAF-wire → reconstructed-CMAF → MSE/EME/CDM, mdat bytes byte-equal so the CDM sees identical ciphertext; catalog
contentProtectionscovering cenc and cbcs). v0.12.0 (Jul 6) then pulled the implementation out into the standalone Eyevinn/locmaf module shared with the LOCMAF draft, shipping LOCMAF v0.3. Earlier, v0.8.0 (May 5) added HEVC LOC packaging, MSF/LOC/moq-mi support, and accurate per-packaging bitrate in the catalog.
Interop
- shaka-player subscribing to moqlivemock publisher (including CMSF ContentProtection)
mlmtest— registered draft-18 client in the interop-runner (moved to draft-18 via runner #114, Sep-1). Since v0.11.1 (June) it bounds interop SETUP by the per-test deadline and refuses a silent WebTransport draft-14 downgrade, so one hung peer can’t stall the sequential matrix. The fix lives in moqtransport itself, so every consumer gets it.mlmrel— relay role, now registered in the interop-runner (runner #120 merged Sep-2, at the draft-18 hackathon). Locally, mlmrel passes all six relay cases againstmlmtest, and 8 of the 12 registered draft-18 clients pass against it (aiomoqt, imquic, moq-dev-rs, moqlivemock, stitcher-moq, xquic-draft-18, moq5, moqtopus); the four failures are client-side — moq-dev-js needs a WebTransport URL, moq-rs fails only its own two extra PUBLISH cases (unimplemented in moqtransport), and moxygen/moqx send an undefined SUBSCRIPTION_FILTER type 250 (LargestGroup)- Draft-18 alignment (Aug-30) puts the stack on the current interop target shared with moq-rs, moxygen, libquicr, imquic and the rest of the draft-18 roster
Related
- moq-transport - Protocol spec
- moq-cmsf - CMAF format used by warp-player
- media-packaging - LOC vs CMAF approaches
- interop-status - Cross-implementation testing