# Workflow Streaming Distribution

> Deliver live or VOD content over HLS / DASH / RTMP / SRT / WHIP / RIST with adaptive bitrate ladders, DRM (Widevine / PlayReady / FairPlay cbcs), multi-protocol fanout via MediaMTX, and CDN upload (Cloudflare Stream / Mux / Bunny / S3). Use when the user says "stream to HLS", "build an ABR ladder", "add Widevine", "multi-bitrate DASH", "WHIP ingest", "low-latency HLS", "SRT contribution", "stream to multiple platforms", "SFU for WebRTC", or anything involving large-scale distribution.

- Skill: `damionrashford/workflow-streaming-distribution` (Agent Skill)
- Install (CLI): `npx skillmds@latest add damionrashford/workflow-streaming-distribution`
- Raw SKILL.md: https://api.skillmd.com/api/skills/damionrashford/workflow-streaming-distribution/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Productivity
- Author: damionrashford (https://skillmd.com/u/damionrashford)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/damionrashford/workflow-streaming-distribution

---


# Workflow — Streaming Distribution

**What:** Ship live or VOD content out to every playback surface. Package once, protect optionally, deliver everywhere.

## Skills used

`ffmpeg-streaming`, `ffmpeg-whip`, `ffmpeg-rist-zmq`, `ffmpeg-hwaccel`, `ffmpeg-drm`, `media-shaka`, `media-gpac`, `mediamtx-server`, `gstreamer-pipeline`, `media-cloud-upload`, `media-batch`, `ffmpeg-quality`, `webrtc-spec`, `webrtc-pion`, `webrtc-mediasoup`, `webrtc-livekit`, `ffmpeg-docs`.

## Pipeline

### Step 1 — Pick contribution protocol

Latency vs. reliability vs. tooling:

| Protocol | Latency | Pros | Cons |
|---|---|---|---|
| WHIP (WebRTC) | sub-second | lowest latency; browser-native | needs HTTPS in prod; ffmpeg 7+ |
| SRT | 120 ms default (tunable) | reliable UDP, forward error recovery | needs port forwarding |
| RTMP | 2–5 s | ubiquitous ingest | TCP, no FEC, aging |
| RIST | low | FEC + ARQ pro contribution | fewer CDN endpoints |

### Step 2 — Build the ABR ladder

Use `ffmpeg-streaming` with the split-scale-encode pattern — one decode, N rate/size variants emitted in parallel. Netflix-style default: 4 video renditions (240p, 480p, 720p, 1080p) + 2 audio tracks (stereo + 5.1). Force keyframe alignment with `-g <fps*seg_len>`, `-keyint_min <fps*seg_len>`, `-sc_threshold 0`.

### Step 3 — Package

Canonical target is CMAF (unified fMP4 segments serving both HLS and DASH manifests). Use `media-shaka` (Shaka Packager) for one-command HLS+DASH output from the same segment set. For pure HLS classic, `ffmpeg-streaming`'s `hls` muxer works directly.

### Step 4 — Optional DRM

- **HLS AES-128** — simplest; encrypts segment payload only.
- **Widevine / PlayReady / FairPlay unified** — CMAF with `cbcs` scheme. `media-shaka` handles the three simultaneously; key server URL in `${user_config.SHAKA_KEY_SERVER_URL}`.
- **DASH CENC** — `ffmpeg-drm` or Shaka for ClearKey / Widevine.

### Step 5 — Fanout via MediaMTX

The `mediamtx-server` skill ingests RTMP/SRT/WebRTC and republishes to every other protocol. One YAML → every playback client served.

### Step 6 — CDN upload

Use `media-cloud-upload`: Cloudflare Stream (tus resumable), Mux (token id + secret), Bunny (PUT to storage zone), S3 (aws CLI / rclone). Tokens live in plugin userConfig.

### Step 7 — Scale — SFU for large interactive audiences

For bidirectional many-to-many (> ~50 peers), deploy an SFU instead of MediaMTX: `webrtc-livekit` (Go + JWT minter), `webrtc-mediasoup` (Node), or `webrtc-pion` (Go, lower-level).

## Variants

- **Low-latency HLS** (LL-HLS) — `-hls_segment_type fmp4`, short `-hls_time` (1–2 s), `-hls_flags +independent_segments+omit_endlist`.
- **DASH with SegmentTemplate** — manifest-side list generation, no explicit segment enum.
- **RIST + ZMQ live control** — dynamic filter parameter changes at runtime via `ffmpeg-rist-zmq`.
- **SRT listener mode** — receiver listens on a port, sender `?mode=caller`.
- **Multicast MPEG-TS** — LAN distribution, no CDN needed.

## Gotchas

- **MP4 output needs `-movflags +faststart`** — second-pass rewrite to move moov atom to front. Required for progressive web playback.
- **`-hls_time` is a target, not a guarantee.** Keyframe cadence determines actual segment length. Force alignment: `-g <fps*seg_len> -keyint_min <fps*seg_len> -sc_threshold 0`.
- **`independent_segments` flag required for CMAF/LL-HLS.** ABR switching breaks without it.
- **HLS AES-128 encrypts segment PAYLOAD only**, not the playlist. Protect the key URI via server-side auth.
- **`-hls_key_info_file` needs a trailing newline on the IV line.** Many editors strip it silently, then decryption fails.
- **Widevine L1 requires hardware CDM** (ChromeOS, Android TEE). Test locally with L3 in Chrome.
- **FairPlay uses `cbcs` scheme; Widevine/PlayReady default to `cenc`.** For unified CMAF DRM, ALL three use `cbcs`.
- **CMAF audio must be fMP4, not TS.** Mixed TS-video + fMP4-audio HLS breaks Safari.
- **WHIP in production needs HTTPS.** Chrome blocks `getUserMedia` over http except on `localhost`.
- **ffmpeg WHIP requires FFmpeg 7+.** Older builds silently fail.
- **MediaMTX default ports: 1935 RTMP, 8554 RTSP, 8888 HLS, 8889 WebRTC, 8890 SRT, 9997 API.** Open all the ones you use.
- **MediaMTX `/v3/*` Control API needs `api: yes` in config** (off by default).
- **`-re` flag reads input at native framerate** — essential for live from file; without it ffmpeg reads as fast as possible.
- **`-f flv` explicit for RTMP** — ffmpeg can pick the wrong muxer from the URL alone.
- **RTMP chunk size default is 128 bytes** — for 4K/HEVC ingest use `-rtmp_chunk_size 4096`.
- **AAC LC floor** — 64 k mono, 96 k stereo. Below that, use HE-AAC.
- **LiveKit JWT tokens expire** (default 6 h). Mint fresh tokens client-side on refresh.
- **Pion SFU needs STUN/TURN** for NAT traversal. Set `ICEServers` in config.
- **mediasoup needs Node 18+ and a platform-specific native `mediasoupworker` build.**

## Example — 4-variant CMAF HLS + DASH with unified DRM

Invoke `media-shaka` to take a single master ProRes/MOV through Shaka Packager with 4 video renditions + AAC stereo + `cbcs` key rotation, emitting both `master.m3u8` and `manifest.mpd` pointing at the same `*.m4s` segments. Upload with `media-cloud-upload`. QC the result with `workflow-analysis-quality`.

## Related

- `workflow-live-production` — where the contribution stream originates.
- `workflow-broadcast-delivery` — for broadcast-spec contribution paths.
- `workflow-analysis-quality` — VMAF + manifest validation on the encoded output.

