Membrane MoQ Plugin
Membrane plugin for Media over QUIC (MoQ) streams:
Membrane.MoQ.Sinkpublishes tracks to a broadcast on a MoQ relay.Membrane.MoQ.Sourcesubscribes 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 and License
Copyright 2026, Software Mansion
Licensed under the Apache License, Version 2.0