Media over QUIC (MoQ) Output
Publish a live encoding to a MoQ relay with the MoQ output.
BetaThe MoQ output is a beta feature. It currently has to be enabled for each Bitmovin account before you can use it. To test it, reach out to Bitmovin Support and ask to have the MoQ output enabled for your account.
Overview
Media over QUIC (MoQ) is an IETF protocol for low-latency media delivery over QUIC. With the MoQ output, a live encoding publishes its renditions directly to a MoQ relay using MoQ Transport (MoQT). Players subscribe to the relay to receive the stream.
The encoder publishes:
- one MoQT track per rendition (video and audio), carrying fMP4/CMAF fragments
- a
catalogtrack that lists all published tracks, so players can discover the renditions
All tracks are published under the track namespace you configure on the output.
Limitations
- Beta: the MoQ output is a beta feature and currently has to be enabled for each Bitmovin account. Reach out to Support to get it enabled for testing. Without it, starting a live encoding with a MoQ output fails with "MoQ outputs are not enabled for this organization."
- Live only: MoQ outputs can only be used in live encodings. VOD encodings with a MoQ output are rejected.
- Codecs: H.264 video and AAC audio only.
- No DRM and no ad insertion: DRM and ad insertion (SCTE-35 / ad markers) are not supported with MoQ outputs.
- No mixing with other output types: an encoding that uses a MoQ output cannot write to other output types (for example S3, GCS or Azure) at the same time.
- Relays: tested with Cloudflare's MoQ relay using MoQT
DRAFT_16. Other relays and draft versions may work but are not verified. - Encoder version: requires encoder version
2.292.0or later.
Configure the MoQ output
1. Create the MoQ output
POST /v1/encoding/outputs/moq
{
"name": "My MoQ relay",
"relayUrl": "moqt://draft-16.cloudflare.mediaoverquic.com:443",
"trackNamespace": ["my-live-event"],
"draftVersion": "DRAFT_16",
"authToken": "{{YOUR_RELAY_TOKEN}}"
}| Property | Required | Description |
|---|---|---|
relayUrl | yes | URL of the MoQ relay the encoder publishes to, for example moqt://<host>:443. |
trackNamespace | yes | MoQT track namespace under which the tracks are published. A list of 1 to 32 fields; it is a tuple, not a URI or path. Use a unique namespace per live event. |
draftVersion | yes | MoQ Transport draft version used for the session with the relay: DRAFT_16 or DRAFT_18. Use the version your relay supports. |
authToken | no | Token sent to the relay as the MoQT AUTHORIZATION TOKEN parameter. This is the only supported authentication mechanism; credentials in the relay URL are not used. |
authTokenType | no | Token type of the AUTHORIZATION TOKEN parameter (IANA MoQ Auth Token Type registry or private-use range). Only used together with authToken. If not set, the encoder applies its default token type. |
2. Reference the output in your muxings
Create an fMP4 muxing per rendition and add the MoQ output as its output:
POST /v1/encoding/encodings/{encoding_id}/muxings/fmp4
{
"streams": [{ "streamId": "{{VIDEO_STREAM_ID}}" }],
"outputs": [
{
"outputId": "{{MOQ_OUTPUT_ID}}",
"outputPath": "video/h264/1080/"
}
],
"segmentLength": 1.0
}Repeat this for every video rendition and for the audio stream. Short segments (for example 1 second) keep latency low.
3. Start the live encoding
Start the encoding as usual with POST /v1/encoding/encodings/{encoding_id}/live/start. Once the ingest is connected, the encoder opens a MoQT session to the relay and publishes the catalog and the media tracks under the configured namespace.
Encoding Template
The following Encoding Template creates a live encoding with an RTMP input and publishes three renditions to a MoQ relay:
- H.264 1080p at 3 Mbps
- H.264 360p at 800 kbps
- AAC stereo at 128 kbps
Replace the placeholders before you start it:
{{YOUR_STREAM_KEY}}: the stream key your RTMP encoder (for example OBS) uses{{YOUR_TRACK_NAMESPACE}}: a unique namespace for this live event{{YOUR_RELAY_TOKEN}}: the token issued by your relay provider. It needs permission to publish.
metadata:
type: LIVE
name: Live RTMP to MoQ
inputs:
redundantRtmp:
rtmp-input:
properties:
name: RTMP input
ingestPoints:
- applicationName: live
streamKey: "{{YOUR_STREAM_KEY}}"
outputs:
moq:
moq-output:
properties:
name: MoQ relay output
relayUrl: "moqt://draft-16.cloudflare.mediaoverquic.com:443"
trackNamespace: ["{{YOUR_TRACK_NAMESPACE}}"]
draftVersion: DRAFT_16
authToken: "{{YOUR_RELAY_TOKEN}}"
configurations:
video:
h264:
h264-1080p:
properties:
name: H.264 1080p 3 Mbps
width: 1920
bitrate: 3000000
rate: 25
presetConfiguration: LIVE_LOW_LATENCY
h264-360p:
properties:
name: H.264 360p 800 kbps
width: 640
height: 360
bitrate: 800000
rate: 25
presetConfiguration: LIVE_LOW_LATENCY
audio:
aac:
aac-128k:
properties:
name: AAC 128 kbps
bitrate: 128000
rate: 48000.0
encodings:
main-encoding:
properties:
name: Live RTMP to MoQ
cloudRegion: GOOGLE_EUROPE_WEST_1
encoderVersion: "2.292.0"
streams:
video-1080p:
properties:
inputStreams:
- inputId: $/inputs/redundantRtmp/rtmp-input
inputPath: /
selectionMode: AUTO
codecConfigId: $/configurations/video/h264/h264-1080p
video-360p:
properties:
inputStreams:
- inputId: $/inputs/redundantRtmp/rtmp-input
inputPath: /
selectionMode: AUTO
codecConfigId: $/configurations/video/h264/h264-360p
audio:
properties:
inputStreams:
- inputId: $/inputs/redundantRtmp/rtmp-input
inputPath: /
selectionMode: AUTO
codecConfigId: $/configurations/audio/aac/aac-128k
mode: STANDARD
muxings:
fmp4:
fmp4-1080p:
properties:
streams:
- streamId: $/encodings/main-encoding/streams/video-1080p
outputs:
- outputId: $/outputs/moq/moq-output
outputPath: "video/h264/1080/"
segmentLength: 1.0
segmentNaming: "seg_%number%.m4s"
fmp4-360p:
properties:
streams:
- streamId: $/encodings/main-encoding/streams/video-360p
outputs:
- outputId: $/outputs/moq/moq-output
outputPath: "video/h264/360/"
segmentLength: 1.0
segmentNaming: "seg_%number%.m4s"
fmp4-audio:
properties:
streams:
- streamId: $/encodings/main-encoding/streams/audio
outputs:
- outputId: $/outputs/moq/moq-output
outputPath: "audio/128kbps/"
segmentLength: 1.0
segmentNaming: "seg_%number%.m4s"
live:
start:
properties:
streamKey: "{{YOUR_STREAM_KEY}}"
manifestGenerator: V2
autoShutdownConfiguration:
bytesReadTimeoutSeconds: 600
streamTimeoutMinutes: 120Start the template with POST /v1/encoding/templates/start, then push your RTMP stream to the ingest URL of the encoding with the stream key {{YOUR_STREAM_KEY}}. When the encoding is connected, subscribe to {{YOUR_TRACK_NAMESPACE}} on the relay with a MoQ player (see Test playback).
The encoding stops automatically when no data is received for 10 minutes (bytesReadTimeoutSeconds) or after 2 hours (streamTimeoutMinutes). Adjust these values for your event.
Test playback
You can test playback with the Bitmovin MoQ demo player. Open the following URL after the encoding is connected:
https://demo.bitmovin.com/public/pwx-moq/?relay=https%3A%2F%2Fdraft-16.cloudflare.mediaoverquic.com%2F{{YOUR_SUBSCRIBE_TOKEN}}&namespace={{YOUR_TRACK_NAMESPACE}}&draftVersion=16&catalog=catalog&mediaTypes=audio%2Cvideo
| Parameter | Value |
|---|---|
relay | URL-encoded relay URL. For Cloudflare, the token is appended as the path: https://draft-16.cloudflare.mediaoverquic.com/{{YOUR_SUBSCRIBE_TOKEN}}. |
namespace | The trackNamespace of your MoQ output, {{YOUR_TRACK_NAMESPACE}}. |
draftVersion | MoQ Transport draft version of the relay, 16 for DRAFT_16. |
catalog | Name of the catalog track the encoder publishes, catalog. |
mediaTypes | Media types to play, audio,video (URL-encoded as audio%2Cvideo). |
Replace {{YOUR_SUBSCRIBE_TOKEN}} with a relay token that has permission to subscribe. Use a separate subscribe-only token for players rather than the publish token of the MoQ output.
Updated 7 days ago