Media over QUIC (MoQ) Output

Publish a live encoding to a MoQ relay with the MoQ output.

🚧

Beta

The 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 catalog track 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.0 or 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}}"
}
PropertyRequiredDescription
relayUrlyesURL of the MoQ relay the encoder publishes to, for example moqt://<host>:443.
trackNamespaceyesMoQT 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.
draftVersionyesMoQ Transport draft version used for the session with the relay: DRAFT_16 or DRAFT_18. Use the version your relay supports.
authTokennoToken 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.
authTokenTypenoToken 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: 120

Start 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
ParameterValue
relayURL-encoded relay URL. For Cloudflare, the token is appended as the path: https://draft-16.cloudflare.mediaoverquic.com/{{YOUR_SUBSCRIBE_TOKEN}}.
namespaceThe trackNamespace of your MoQ output, {{YOUR_TRACK_NAMESPACE}}.
draftVersionMoQ Transport draft version of the relay, 16 for DRAFT_16.
catalogName of the catalog track the encoder publishes, catalog.
mediaTypesMedia 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.


Did this page help you?