Skip to content

GStreamer Plugin

A GStreamer plugin for publishing and consuming MoQ streams.

Work in Progress

This plugin is currently under development, but it works okay.

Overview

The GStreamer plugin provides two elements:

  • moqsink - Publish media to a MoQ relay
  • moqsrc - Subscribe to MoQ broadcasts

Both elements support the following properties:

PropertyTypeDescription
urlstringThe relay URL to connect to
broadcaststringThe broadcast name
tls-disable-verifyboolDisable TLS certificate validation (rarely needed, default false)

INFO

For http:// URLs, moq-native automatically fetches the server's certificate fingerprint from /certificate.sha256 and verifies TLS against it. You don't need tls-disable-verify for local development.

Prerequisites

The plugin requires GStreamer development libraries. It is not built by default since most users don't have them installed.

If you're using Nix, GStreamer is included in the dev shell automatically. Otherwise, install manually:

  • macOS: brew install gstreamer
  • Debian/Ubuntu: apt install libgstreamer1.0-dev gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad
  • Arch: pacman -S gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad

Quick start with Nix

If you have Nix installed, you don't need to build anything or set any environment variables. The moq-gst flake output bundles the plugin with wrappers around gst-inspect-1.0 / gst-launch-1.0 that preload moq alongside gst-plugins-{base,good,bad}, so the standard tools find moqsink / moqsrc automatically.

Inspect the plugin

bash
nix shell github:moq-dev/moq#moq-gst --command gst-inspect-1.0 moq

Lists moqsink and moqsrc. As a one-liner: nix run github:moq-dev/moq#moq-gst -- moq.

Subscribe to the public test broadcast

cdn.moq.dev/demo hosts an always-on bbb.hang broadcast (looping Big Buck Bunny). Render it to a window:

bash
nix shell github:moq-dev/moq#moq-gst --command gst-launch-1.0 -v -e \
  moqsrc url=https://cdn.moq.dev/demo broadcast=bbb.hang \
  ! decodebin3 ! videoconvert ! autovideosink

Audio-only variant: swap the tail for ! decodebin3 ! audioconvert ! autoaudiosink.

Publish your own broadcast

cdn.moq.dev/anon accepts publishers without auth. Pick a name, publish, then subscribe to that same name (in another terminal or from another machine).

bash
# Download a pre-fragmented CMAF test file (one time).
curl -fsSL https://vid.moq.dev/bbb.mp4 -o bbb.mp4

# Terminal 1: loop the file as a broadcast named `<your-name>.hang`.
nix shell github:moq-dev/moq#moq-gst --command gst-launch-1.0 -v -e \
  multifilesrc location=bbb.mp4 loop=true ! parsebin name=parse \
    parse. ! queue ! identity sync=true ! mux.sink_0 \
    parse. ! queue ! identity sync=true ! mux.sink_1 \
    moqsink name=mux url=https://cdn.moq.dev/anon broadcast=<your-name>.hang
bash
# Terminal 2: render it.
nix shell github:moq-dev/moq#moq-gst --command gst-launch-1.0 -v -e \
  moqsrc url=https://cdn.moq.dev/anon broadcast=<your-name>.hang \
  ! decodebin3 ! videoconvert ! autovideosink

Local relay

If you'd rather run a relay yourself, the relay binary is in the same flake:

bash
# Terminal 1: start a relay on localhost:4443.
nix run github:moq-dev/moq#moq-relay -- demo/relay/localhost.toml

# Terminal 2: publish.
nix shell github:moq-dev/moq#moq-gst --command gst-launch-1.0 -v -e \
  multifilesrc location=bbb.mp4 loop=true ! parsebin name=parse \
    parse. ! queue ! identity sync=true ! mux.sink_0 \
    parse. ! queue ! identity sync=true ! mux.sink_1 \
    moqsink name=mux url=http://localhost:4443 broadcast=bbb.hang

# Terminal 3: subscribe.
nix shell github:moq-dev/moq#moq-gst --command gst-launch-1.0 -v -e \
  moqsrc url=http://localhost:4443 broadcast=bbb.hang \
  ! decodebin3 ! videoconvert ! autovideosink

TIP

http:// URLs auto-verify TLS via /certificate.sha256 fingerprint pinning, so localhost development needs no certificate setup.

Building

bash
cargo build -p moq-gst

This produces a shared library (cdylib) in target/debug/. GStreamer needs to find this plugin via the GST_PLUGIN_PATH_1_0 environment variable — the just commands below handle this automatically.

Running Locally

Start a relay server first:

bash
just relay

Publishing

Use the just shortcut to publish a test video via GStreamer:

bash
# Publish Big Buck Bunny (downloads automatically)
just pub gst bbb

# Publish to a remote relay
just pub gst bbb https://cdn.moq.dev/anon

Or run gst-launch-1.0 directly:

bash
# Point GST_PLUGIN_PATH_1_0 at the build output
export GST_PLUGIN_PATH_1_0="$PWD/target/debug${GST_PLUGIN_PATH_1_0:+:$GST_PLUGIN_PATH_1_0}"

# Publish a fragmented MP4 file
gst-launch-1.0 -v -e \
  multifilesrc location=demo/pub/media/bbb.mp4 loop=true ! parsebin name=parse \
    parse. ! queue ! identity sync=true ! mux.sink_0 \
    parse. ! queue ! identity sync=true ! mux.sink_1 \
    moqsink name=mux url="http://localhost:4443" broadcast="bbb"

TIP

The input video must be a fragmented MP4 (CMAF). The just pub download helper fetches pre-fragmented test videos from vid.moq.dev. To fragment your own video:

bash
ffmpeg -i input.mp4 -c copy \
  -f mp4 -movflags cmaf+separate_moof+delay_moov+skip_trailer+frag_every_frame \
  output.mp4

Subscribing

bash
# Subscribe and render to the screen
just sub gst bbb

# Subscribe from a remote relay
just sub gst bbb https://cdn.moq.dev/anon

Or directly:

bash
export GST_PLUGIN_PATH_1_0="$PWD/target/debug${GST_PLUGIN_PATH_1_0:+:$GST_PLUGIN_PATH_1_0}"

gst-launch-1.0 -v -e \
  moqsrc url="http://localhost:4443" broadcast="bbb" \
    ! decodebin3 ! videoconvert ! autovideosink

Supported Codecs

moqsink (publish)

MediaCodecGStreamer caps
VideoH.264video/x-h264
VideoH.265video/x-h265
VideoAV1video/x-av1
VideoVP8video/x-vp8
VideoVP9video/x-vp9
AudioAACaudio/mpeg (v4)
AudioOpusaudio/x-opus

moqsrc (subscribe)

Outputs the same caps based on the catalog, compatible with decodebin3.

Debugging

Enable GStreamer debug output:

bash
# GStreamer debug (verbose)
GST_DEBUG=*:4 just pub gst bbb

# Rust logging
RUST_LOG=debug just pub gst bbb

Licensed under MIT or Apache-2.0