Skip to content

Latest commit

 

History

History
227 lines (184 loc) · 8.76 KB

File metadata and controls

227 lines (184 loc) · 8.76 KB

OpenMOQ Publisher

English | Español | Français | Italiano | 日本語 | Português | 中文

moqxr is a C++20 OpenMOQ publisher for Linux, macOS, and Windows.

It turns MP4 input into CMSF-style publishable objects, builds draft-aware MOQT publish plans, and can either inspect those plans locally or publish them over picoquic-backed Raw QUIC and WebTransport paths.

What It Does

  • Parses fragmented MP4 input with ftyp + moov + moof/mdat.
  • Remuxes progressive MP4 input into synthesized fragmented media objects.
  • Extracts track metadata and RFC 6381 codec identifiers.
  • Preserves HEVC signaling and normalizes hev1 to hvc1 when needed.
  • Builds publish plans with catalog, optional MSF media timeline and SAP event timeline metadata, and media objects.
  • Emits generated objects and catalog metadata to disk for inspection.
  • Supports draft-aware MOQT framing for drafts 14, 16, 17, and 18.
  • Publishes over Raw QUIC or WebTransport when picoquic and picotls are available.
  • Accepts live CTE LL-DASH/CMAF ingest over HTTP/1.1 chunked POST or PUT requests.

Quick Start

Build and test:

cmake -S . -B build -DOPENMOQ_RUN_PICOQUIC_SMOKE_TESTS=OFF
cmake --build build
ctest --test-dir build --output-on-failure

The default build creates both 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-plan

Emit catalog and media objects:

./build/openmoq-publisher --input sample.mp4 --emit-dir out/

Publish to a relay:

OPENMOQ_PICOQUIC_TRACE=1 ./build/openmoq-publisher \
  --input sample.mp4 \
  --endpoint moqt://relay.example.com:443/moq \
  --namespace media \
  --forward 0 \
  --timeout 10 \
  --paced

Live ingest examples (choose one path):

  1. SRT ingest path (--live-source srt)

Create an SRT config file (example: /tmp/srt_callers.json):

{
  "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
      }
    }
  ]
}

Start the publisher (SRT receiver + 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 0

Feed MPEG-TS over SRT from ffmpeg:

ffmpeg -hide_banner -stream_loop -1 -re \
  -i /home/ubuntu/bbb_sunflower_1080p_30fps_normal.mp4 \
  -filter_complex "[0:v]drawtext=fontcolor=white:fontsize=36:box=1:boxcolor=black@0.45:boxborderw=8:x=w-tw-20:y=20:text='%{localtime\\:%Y-%m-%d %T}\\:%{eif\\:mod(t*1000\\,1000)\\:d\\:3}'[vclock]" \
  -map "[vclock]" -map 0:a:0 \
  -c:v libx265 -preset veryfast -r 30 -g 60 -keyint_min 60 -bf 0 \
  -x265-params "keyint=60:min-keyint=60:scenecut=0:open-gop=0:repeat-headers=1" \
  -c:a aac -b:a 160k -ar 48000 -ac 2 \
  -f mpegts "srt://0.0.0.0:9000?mode=listener&pkt_size=1316"
  1. stdin fragmented-MP4 path (--live-source stdin)
ffmpeg -i /home/ubuntu/bbb_sunflower_1080p_30fps_normal.mp4 \
  -map 0:v:0 -map 0:a:0 \
  -map_metadata -1 \
  -sn -dn \
  -c:v libx264 -preset medium -r 30 -g 60 -keyint_min 60 -sc_threshold 0 -bf 0 \
  -c:a aac -b:a 160k -ar 48000 -ac 2 \
  -movflags +frag_keyframe+empty_moov+default_base_moof+separate_moof \
  -f mp4 - | ./build/openmoq-publisher \
    --live-source stdin \
    --input - \
    --endpoint 127.0.0.1:4443 \
    --transport raw \
    --namespace live \
    --draft 16 \
    --timeout 120 \
    --forward 0
  1. CTE LL-DASH ingest path (--live-source dash)

Start the publisher with an HTTP/1.1 chunked CMAF ingest 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 \
  --insecure

Send CMAF/fMP4 bytes with chunked transfer encoding. Multiple concurrent paths under the prefix are accepted, for example /ingest/video and /ingest/audio; each path gets path-prefixed track names in the MoQ catalog.

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/video

FFmpeg can push live DASH/CMAF requests directly to the ingest prefix. This example creates two video representations plus audio; FFmpeg writes representation requests such as /ingest/video0, /ingest/video1, and /ingest/video2.

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/

Use --forward 1 when the relay should receive objects immediately. Use --forward 0 for await-subscribe mode, where media is sent after the relay forwards subscriber interest for the published tracks. A printed connection_id= confirms transport and MOQT setup only; it does not confirm namespace acceptance or a downstream subscription.

--live-source both is intentionally not supported.

On Windows, replace ./build/openmoq-publisher with build\Release\openmoq-publisher.exe or the matching build configuration path. The DASH ingest listener itself is currently supported on Unix-like platforms; Windows builds report the mode as unsupported.

Documentation

Topic Link
Build and dependencies docs/build.md
CLI quick start docs/quickstart.md
Testing docs/testing.md
Design overview docs/design.md
FFmpeg input recipes docs/ffmpeg.md
Relay interoperability docs/relay-interop.md
C++ Publisher API docs/publisher-api.md
CAT4MOQ auth example examples/auth/README.md
Protocol mapping docs/protocol-mapping.md
WebTransport compliance docs/webtransport-compliance.md
macOS DASH shutdown behavior docs/macos-accept-shutdown-quirk.txt
Transport plan docs/transport-plan.md
Project status and roadmap docs/status.md

Localized Publisher API guides are available in Spanish, French, Italian, Japanese, Portuguese, and Chinese.

Repository Layout

  • include/openmoq/publisher: public headers
  • src: static library and CLI implementation
  • tests: CTest-based unit coverage
  • docs: protocol notes, integration guides, and design references
  • examples: example publisher integrations
  • .github/workflows/ci.yml: Linux, macOS, and Windows CI
  • .github/workflows/release.yml: release artifact builds for the CLI, headers, and static library

Current Status

The publisher can generate publish plans, emit inspectable output, and publish over picoquic-backed Raw QUIC and WebTransport transports. Draft 14 is the primary target, draft 16 is maintained as a compatibility profile, and drafts 17 and 18 provide the newer VI64 and request-stream protocol profiles. Draft-18 subscriber interest is accepted on fragmented request-stream reads and answered on the same request stream. The draft-19 text is archived under docs/superpowers/specs/ for review only; --draft 19 is not implemented.

For the detailed roadmap, see docs/status.md.