English | Español | Français | Italiano | 日本語 | Português | 中文
moqxr is a C++20 OpenMOQ publisher for Linux, macOS, and Windows.
It packages file and live media for Media over QUIC Transport (MOQT), builds MSF/CMSF catalogs and publish plans, and publishes through picoquic-backed Raw QUIC or WebTransport connections.
- Parses fragmented MP4 (
ftyp+moov+moof/mdat) and remuxes progressive MP4 into fragmented media objects. - Extracts track metadata and RFC 6381 codec identifiers, including HEVC signaling and
hev1tohvc1normalization. - Builds MSF/CMSF version 1 catalogs, initialization data, optional media timelines, and SAP event timelines.
- Detects and signals existing CMAF CENC content protection for batch input, live fragmented MP4 on stdin, and CTE LL-DASH ingest. It does not encrypt or decrypt media.
- Emits catalog, initialization, media, probe, and publish-plan files for local inspection.
- Publishes with the main CLI's supported MOQT draft profiles: draft 16 (default) and draft 18.
- Publishes over Raw QUIC or WebTransport when picoquic and picotls are available.
- Accepts live fragmented MP4 from stdin, MPEG-TS over SRT when libsrt is available, and CMAF over HTTP/1.1 chunked CTE LL-DASH ingest.
- Parses MSF URLs with
--urland prints the catalog discovery URL with--print-msf-urls. - Provides C++ Publisher API examples for FFmpeg-generated live media, CAT4MOQ authorization, and MPEG-2 TS/M2TS packaging.
- Optionally routes publishing through the moq5 C11 Media-over-QUIC library for drafts 16 and 18.
Build and test:
cmake -S . -B build -DOPENMOQ_RUN_PICOQUIC_SMOKE_TESTS=OFF
cmake --build build
ctest --test-dir build --output-on-failureThe default build creates the openmoq-publisher executable and the static Publisher library: build/libopenmoq_publisher.a on Linux/macOS, or build\<config>\openmoq_publisher.lib with Visual Studio generators on Windows.
Inspect a publish plan:
./build/openmoq-publisher --input sample.mp4 --dump-planEmit the catalog and packaged media objects:
./build/openmoq-publisher --input sample.mp4 --emit-dir out/Publish to a relay with the default draft-16 profile:
OPENMOQ_PICOQUIC_TRACE=1 ./build/openmoq-publisher \
--input sample.mp4 \
--endpoint moqt://relay.example.com:443/moq \
--namespace media \
--draft 16 \
--forward 0 \
--timeout 10 \
--paced--forward 1 sends objects immediately. --forward 0 waits for the relay to forward subscriber interest. A printed connection_id= confirms transport and MOQT setup only; it does not confirm namespace acceptance or a downstream subscription.
On Windows, replace ./build/openmoq-publisher with build\Release\openmoq-publisher.exe or the path for the selected build configuration.
The CLI exposes one live source at a time:
| Source | CLI selection | Input | Notes |
|---|---|---|---|
| Fragmented MP4 | --live-source stdin --input - |
CMAF/fMP4 on standard input | Available on all supported platforms |
| SRT | --live-source srt --srt-config FILE |
MPEG-TS over SRT | Requires libsrt; CENC metadata is unavailable in this path |
| CTE LL-DASH | --live-source dash --dash-listen HOST:PORT |
Chunked CMAF POST or PUT requests |
Listener currently requires a Unix-like platform |
The publisher is an SRT caller. Create /tmp/srt_callers.json with the SRT listener address and MPEG-TS/CMAF settings:
{
"srt_callers": [
{
"id": "cam1",
"srt": {
"mode": "caller",
"host": "127.0.0.1",
"port": 9000,
"latency_ms": 120
},
"mpegts": {
"auto_detect_program": true,
"program_number": null,
"video_pid": null,
"audio_pid": null
},
"cmaf": {
"fragment_on_keyframe": true,
"empty_moov": true,
"default_base_moof": true,
"separate_moof_per_track": true,
"target_fragment_duration_ms": 1000
}
}
]
}In the first terminal, start an FFmpeg SRT listener that sends MPEG-TS after the publisher connects:
ffmpeg -hide_banner -stream_loop -1 -re \
-i input.mp4 \
-map 0:v:0 -map 0:a:0 \
-c:v libx264 -preset veryfast -r 30 -g 60 -keyint_min 60 -sc_threshold 0 -bf 0 \
-c:a aac -b:a 160k -ar 48000 -ac 2 \
-f mpegts "srt://0.0.0.0:9000?mode=listener&pkt_size=1316"In the second terminal, start the SRT caller and MoQ publisher:
./build/openmoq-publisher \
--live-source srt \
--srt-config /tmp/srt_callers.json \
--endpoint 127.0.0.1:4443 \
--transport raw \
--namespace live \
--draft 16 \
--timeout 120 \
--forward 0The only supported SRT mode is caller; the configured host and port must identify an existing SRT listener. Use --forward 1 for an immediate relay smoke test, or keep --forward 0 to wait for subscriber interest.
Start the publisher with an HTTP/1.1 chunked CMAF listener and a MoQ relay target:
./build/openmoq-publisher \
--live-source dash \
--dash-listen 0.0.0.0:8080 \
--dash-path /ingest \
--endpoint https://127.0.0.1:4433/moq \
--transport webtransport \
--namespace live \
--draft 18 \
--publish-catalog \
--forward 1 \
--insecureSend an existing CMAF/fMP4 stream with HTTP/1.1 chunked transfer encoding:
curl -X PUT \
-H 'Transfer-Encoding: chunked' \
-H 'Content-Type: video/iso.segment' \
--data-binary @live-video.cmaf \
http://127.0.0.1:8080/ingest/videoFFmpeg can instead create two video representations plus audio and push them directly to the ingest prefix:
ffmpeg -re \
-f lavfi -i "testsrc2=size=1280x720:rate=25" \
-f lavfi -i "anullsrc=r=48000:cl=stereo" \
-filter_complex "[0:v]split=2[v1][v2];[v1]scale=1280:720[v720];[v2]scale=640:360[v360]" \
-map "[v720]" -c:v:0 libx264 -b:v:0 1500k -g 50 -keyint_min 50 -sc_threshold 0 \
-map "[v360]" -c:v:1 libx264 -b:v:1 500k -g 50 -keyint_min 50 -sc_threshold 0 \
-map 1:a -c:a aac -b:a 128k \
-f dash -seg_duration 2 -use_template 1 -use_timeline 0 \
-init_seg_name 'video$RepresentationID$' \
-media_seg_name 'video$RepresentationID$' \
-adaptation_sets "id=0,streams=v id=1,streams=a" \
-multiple_requests 1 -streaming 1 -remove_at_exit 0 \
-window_size 20 -extra_window_size 20 \
http://127.0.0.1:8080/ingest/Each path below /ingest maintains independent parser state and produces path-prefixed MoQ track names. Use --forward 1 to send objects immediately, or --forward 0 to wait for subscriber interest. The DASH listener currently requires a Unix-like platform.
See the CLI quick start, FFmpeg recipes, and SRT technical note for additional details.
The opt-in moq5 backend routes batch, live stdin, live SRT, and live-object publishing through moq5's service tier. The service tier handles catalog publication, CMSF/CMAF validation, subscriber-demand gating, bounded backpressure, and graceful transport draining.
CMake fetches current openmoq/moq5 main when this backend is enabled. Set
OPENMOQ_LIBMOQ_SOURCE_DIR only to use a local or offline source override:
cmake -S . -B build-libmoq \
-DOPENMOQ_USE_LIBMOQ_PUBLISHER=ON
cmake --build build-libmoq
ctest --test-dir build-libmoq --output-on-failureThe default build keeps the built-in transport path. See docs/build.md for backend status, dependency discovery, and configuration details.
| Example | Target | Purpose |
|---|---|---|
| Psychedelic live publisher | openmoq-publisher-psychedelic-example |
Runs one FFmpeg audio/video pipeline through Publisher::publish_live(...) |
| CAT4MOQ authorization | openmoq-publisher-auth-example |
Publishes deterministic live objects with token files or a Catapult token command |
| MSFTS publisher | openmoq-publisher-msfts-example |
Publishes packet-aligned MPEG-2 TS or M2TS objects through Publisher::publish_live_objects(...) |
The MSFTS example follows the local text draft in examples/msfts-publisher/docs/, discovers PAT/PMT data, selects one program, filters unrelated PIDs, and emits an MSF version 1 catalog with packaging: "m2ts".
./build/examples/msfts-publisher/openmoq-publisher-msfts-example \
--input sample.m2ts \
--endpoint https://relay.example.com:443/moq \
--namespace media.msfts \
--track transport \
--draft 17Add --program NUMBER to select a program, --packets-per-object COUNT to change object sizing, or --insecure only when the relay certificate is intentionally untrusted.
| Topic | Link |
|---|---|
| Build and dependencies | docs/build.md |
| CLI and live-ingest quick start | docs/quickstart.md |
| Testing | docs/testing.md |
| Design overview | docs/design.md |
| FFmpeg input recipes | docs/ffmpeg.md |
| SRT ingest technical note | docs/srt-ingest-technical-note.md |
| Relay interoperability | docs/relay-interop.md |
| C++ Publisher API | docs/publisher-api.md |
| CAT4MOQ auth example | examples/auth/README.md |
| MSFTS text draft | examples/msfts-publisher/docs/draft-gregoire-moq-msfts.txt |
| Protocol mapping | docs/protocol-mapping.md |
| WebTransport compliance | docs/webtransport-compliance.md |
| Local MSF version 1 draft | docs/draft-ietf-moq-msf-01.txt |
| Local CMSF version 1 draft | docs/draft-ietf-moq-cmsf-01.txt |
| macOS DASH shutdown behavior | docs/macos-accept-shutdown-quirk.txt |
| Project status and roadmap | docs/status.md |
Localized Publisher API guides are available in Spanish, French, Italian, Japanese, Portuguese, and Chinese.
include/openmoq/publisher: public C++ headerssrc: static library and CLI implementationtests: CTest-based unit and integration coveragedocs: local draft text, protocol notes, integration guides, and design referencesexamples: Publisher API integrations.github/workflows/ci.yml: Linux, macOS, and Windows CI.github/workflows/release.yml: CLI, header, and static-library release artifacts
The main openmoq-publisher CLI accepts drafts 16 and 18; draft 16 remains the default while draft 18 provides the newer request-stream profile. Text for drafts 14, 17, and 19 remains in docs/ for implementation history and protocol review, but those versions are not selectable in the main CLI. The separate MSFTS example retains draft 14/16/17/18 selection for draft-specific testing.
The default picoquic backend and the opt-in moq5 backend are both under active interoperability testing. For detailed feature coverage, limitations, and roadmap work, see docs/status.md and docs/protocol-mapping.md.
Originally created by Paul Gregoire for OpenMOQ