Membrane MoQ Plugin

Copy Markdown View Source

Hex.pm API Docs

Membrane plugin for Media over QUIC (MoQ) streams:

  • Membrane.MoQ.Sink publishes tracks to a broadcast on a MoQ relay.
  • Membrane.MoQ.Source subscribes to a broadcast's tracks and emits their frames, notifying its parent as tracks come and go.

The MoQ session, catalog and wire handling come from ex_moq.

Published broadcasts advertise both the hang catalog and the IETF MSF catalog, so they interoperate with the moq CLI, moq-gst and the JS @moq/hang player as well as MSF-based consumers. Subscribing picks the catalog from the broadcast name's suffix (.msf → MSF, otherwise hang).

Publishing encapsulates frames in the :legacy or :loc wire container. Consuming selects each track's container from the catalog automatically.

It is a part of Membrane Multimedia Framework.

Installation

The package can be installed by adding membrane_moq_plugin to your list of dependencies in mix.exs:

def deps do
  [
    {:membrane_moq_plugin, "~> 0.2.0"}
  ]
end

Building requires a Rust toolchain, as the ex_moq dependency compiles its NIFs from source.

Usage

Both elements talk to a MoQ relay. For local development run one with anonymous auth, e.g. moq-relay (cargo install moq-relay). The examples assume https://localhost:4443 with a self-signed certificate.

Publishing an H.264 track:

child(:source, %Membrane.File.Source{location: "video.h264"})
|> child(:parser, %Membrane.H264.Parser{
  output_stream_structure: :avc3,
  generate_best_effort_timestamps: %{framerate: {30, 1}}
})
|> child(:realtimer, Membrane.Realtimer)
|> via_in(Pad.ref(:input, :video), options: [track: "video"])
|> child(:sink, %Membrane.MoQ.Sink{
  url: "https://localhost:4443",
  broadcast: "demo.hang",
  disable_tls_verify?: true
})

Subscribing to it:

child(:source, %Membrane.MoQ.Source{
  url: "https://localhost:4443",
  broadcast: "demo.hang",
  disable_tls_verify?: true
})
|> via_out(Pad.ref(:output, :video), options: [track: "video"])
|> child(:parser, %Membrane.H264.Parser{
  generate_best_effort_timestamps: %{framerate: {30, 1}}
})

The examples/ directory has runnable scripts covering the common setups:

  • loopback publish+play (publish_and_play.exs)
  • multi-track A/V from an MP4 (publish_mp4.exs)
  • notification-driven subscribing (dynamic_subscriber.exs).

Testing

mix test runs the unit suite. Integration tests exercise a real relay and are opt-in:

mix test --include integration

Copyright 2026, Software Mansion

Software Mansion

Licensed under the Apache License, Version 2.0