Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ Architectural decision records (ADRs) capture durable choices, their context, an

## Guides

- [Roadmap](roadmap.md) lists every step needed for segmentor to replace nginx-vod-module, by phase and status.
- [Operating the origin](operations.md) covers probes, shutdown, CORS, metrics, and limits for production deployments.
- [Performance budgets](benchmarks.md) records how the budgets are measured and the current results.
- [Releasing](releasing.md) explains the commit convention, automatic version tags, and the manual release workflow.
Expand Down
1 change: 1 addition & 0 deletions docs/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
# Design

- [Architecture](architecture.md)
- [Roadmap](roadmap.md)
- [Using segmentor](usage.md)
- [Supported input](supported-input.md)
- [Deploying](deployment.md)
Expand Down
30 changes: 29 additions & 1 deletion docs/mapper-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ Instead of a single `location`, an answer may list clips: each a file and an opt
| `location` | Yes | A `file` or `http` location with the same rules as a single asset's |
| `from_ms` | No | Default `0`. A time on the file's own clock, the one subtitle cues are read against |
| `to_ms` | No | Default: the end of the file. Must be later than `from_ms`; a value past the end is clamped to the end |
| `encryption` | No | This clip's own [`encryption`](#encryption) object, with the same rules as the answer's. Absent means the clip uses the answer's own `encryption` (or is clear if the answer has none). See [Different keys per clip](#different-keys-per-clip) |

Both times are at most 4294967295 ms, and an answer may list at most `limits.max_clips` (default 64) clips.

Expand All @@ -229,7 +230,7 @@ Both times are at most 4294967295 ms, and an answer may list at most `limits.max

## Encryption

An answer may carry an `encryption` object. segmentor then encrypts what it serves with Common Encryption in the `cbcs` scheme, and signals the DRM systems you name in the HLS and DASH manifests. One set of segments plays under Widevine, FairPlay, PlayReady, and Clear Key. The object applies to the whole asset: every track, every rendition, and every clip.
An answer may carry an `encryption` object. segmentor then encrypts what it serves with Common Encryption in the `cbcs` scheme, and signals the DRM systems you name in the HLS and DASH manifests. One set of segments plays under Widevine, FairPlay, PlayReady, and Clear Key. The object applies to the whole asset: every track, every rendition, and every clip that does not carry its own (see [Different keys per clip](#different-keys-per-clip)).

```json
{
Expand Down Expand Up @@ -288,6 +289,33 @@ Any other system ID is accepted and signalled in DASH only (its `pssh` and `lice

**The answer now carries secrets.** The mapper must be reached over `https` and must require the bearer token; do not use `allow_insecure_mapper` with real keys.

### Different keys per clip

In a [clips](#clips) answer, each clip may carry its own `encryption` object. A clip without one uses the answer's own `encryption`; if the answer has none either, that clip is served clear. This covers a clear pre-roll before an encrypted movie, or two programmes under different keys:

```json
{
"asset_id": "movie-with-preroll",
"version": "2026-10-02-a",
"clips": [
{ "location": { "type": "file", "path": "ads/preroll.mp4" } },
{ "location": { "type": "file", "path": "movies/movie.mp4" },
"encryption": {
"scheme": "cbcs",
"keys": [{ "key_id": "0123456789abcdef0123456789abcdef", "key": "00112233445566778899aabbccddeeff" }],
"systems": [{ "system_id": "94ce86fb-07ff-4f43-adb8-93d2fa968ca2", "hls_uri": "skd://movie" }]
} }
]
}
```

- **HLS.** Each media playlist gives an `#EXT-X-KEY` line set wherever a clip's encryption differs from the clip before it, after the `#EXT-X-DISCONTINUITY` and before that clip's `#EXT-X-MAP`. Moving from an encrypted clip to a clear one writes `#EXT-X-KEY:METHOD=NONE`, because a key line otherwise applies to every later segment. The master playlist's `#EXT-X-SESSION-KEY` lines cover every key used by any clip, each system line given once.
- **DASH.** Each clip's `Period` carries its own `ContentProtection` elements, or none if that clip is clear.
- **Versioning.** Each clip's own keys are hashed into the URL version, so re-keying one clip, or turning its encryption on or off, gives the whole sequence new URLs.
- **Validation.** A clip's `encryption` follows every rule above; a bad one makes the whole answer malformed (`502`), with the error naming the clip.
- **Limitation.** A clip cannot opt out of the answer's own `encryption`: absent and `null` both mean "use the answer's". To mix clear and encrypted clips, leave the answer's `encryption` out and set it on the encrypted clips.
- `/admin/status` lists the key IDs of every clip.

## What a `version` means to the server

The server keeps one loaded copy per asset, keyed by `(asset_id, version)`. A different `version`, or the same version at a different location (a rotated signed URL), makes it reload from the new location. There is **no grace period**: players holding URLs from the old version get `404` and recover by fetching the playlist again. Change `version` only when the media actually changes.
Expand Down
112 changes: 112 additions & 0 deletions docs/roadmap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# Roadmap

This page lists everything segmentor still needs before it can replace [nginx-vod-module](research/nginx-vod-module.md) in production. Each step is grouped into a phase, with its status and the design it belongs to.

- **Feature parity** means segmentor does everything nginx-vod-module does that someone actually relies on. It does not mean copying nginx-vod-module's configuration syntax or URL scheme. Migrating an existing deployment is a separate step (Phase 5).
- **Out of scope by design** lists features that conflict with segmentor's architecture. They would need an ADR before any code.

The baseline is nginx-vod-module's [published feature list](https://github.com/kaltura/nginx-vod-module#features), compared with the status lines of TDDs 0001 to 0009.

## Where segmentor already matches

| nginx-vod-module feature | segmentor | Design |
| --- | --- | --- |
| On-the-fly repackaging of MP4 to HLS and DASH | Done | [TDD 0001](technical-design/0001-on-demand-mp4-packaging-core.md) |
| Local, remote (HTTP range), and mapped working modes | Done; mapped mode uses segmentor's own mapper API | [TDD 0002](technical-design/0002-asset-map-interface.md) |
| Adaptive bitrate, alternative audio renditions | Done | [TDD 0006](technical-design/0006-trick-play-subtitles-and-renditions.md) |
| HLS I-frame playlists | Done, for clear assets and encrypted ones | [TDD 0006](technical-design/0006-trick-play-subtitles-and-renditions.md) |
| WebVTT subtitles (HLS and DASH) | Done, as sidecar files | [TDD 0006](technical-design/0006-trick-play-subtitles-and-renditions.md) |
| H.264, HEVC, VP9, AV1 video; AAC, AC-3, E-AC-3, Opus, FLAC audio | Done (clear) | [TDD 0004](technical-design/0004-broader-mp4-input-support.md) |
| Audio-only and video-only files | Done | [TDD 0004](technical-design/0004-broader-mp4-input-support.md) |
| Fragmented MP4 input | Done | [TDD 0005](technical-design/0005-fragmented-mp4-input.md) |
| Source clipping; playing several files back to back | Done | [TDD 0008](technical-design/0008-clipping-and-concatenation.md) |
| Variable segment lengths | Done, inherent to keyframe-aligned planning | [TDD 0001](technical-design/0001-on-demand-mp4-packaging-core.md) |
| DRM: CENC `cbcs` for DASH, `SAMPLE-AES` for HLS (Widevine, FairPlay, PlayReady, Clear Key) | Done for H.264 and audio, including different keys per clip | [TDD 0009](technical-design/0009-common-encryption-and-drm.md) |
| Metadata caching, asynchronous I/O, CDN-friendly output | Done | [TDD 0001](technical-design/0001-on-demand-mp4-packaging-core.md), [TDD 0003](technical-design/0003-production-grade-http-api.md) |

## Phase 1: Finish DRM

DRM is the most common reason a studio-licensed catalog cannot move. These steps extend the accepted [TDD 0009](technical-design/0009-common-encryption-and-drm.md) and need no new design document.

| Step | Status | Notes |
| --- | --- | --- |
| Different keys per clip | Done | Clear pre-roll before encrypted content; `METHOD=NONE` transitions |
| HEVC encryption | To do | Slice-header parser for HEVC (the `hvcC` path); same `cbcs` pattern as H.264 |
| Whole-segment HLS AES-128 | To do | nginx-vod-module's "HLS AES-128": simple protection without a DRM vendor. Whole-fragment AES-128-CBC with a key URI, independent of `cbcs` |
| Key rotation within an asset | To do | Key periods over the timeline. HLS: new `EXT-X-KEY` at period boundaries. DASH: per-Period or `pssh` in fragments |
| Decrypting CENC-encrypted source files | To do | nginx-vod-module repackages already-encrypted MP4s. Needs `encv`/`enca` parsing and a source-key field in the mapper answer |
| AV1 and VP9 encryption | To do | OBU-aware and superframe-aware subsample rules |
| Opus and FLAC encryption | To do | Whole-sample protection, as for AAC |
| `cenc` (AES-CTR) scheme | Decide first | Only needed for players that cannot do `cbcs`. Confirm a real target device needs it before building |
| SPEKE v2 key exchange | To do, mapper side | segmentor never talks to a licence server, so this is a reference mapper adapter and guide, not server code |
| Widevine, FairPlay, PlayReady playback on real devices | To do | Manual release check with an operator's DRM vendor account; only Clear Key is verified in browsers today |

## Phase 2: Captions and codecs

| Step | Status | Notes |
| --- | --- | --- |
| SRT input converted to WebVTT | To do | The most common format in source libraries ([TDD 0006](technical-design/0006-trick-play-subtitles-and-renditions.md) open question) |
| TTML/DFXP input | To do | Needs an XML parser; keep styling out of scope as nginx-vod-module does |
| CAP (Cheetah) input | Decide first | Rare; build only for a known catalog that uses it |
| Segmented subtitles | To do | Segmented WebVTT for HLS, and WebVTT or SMPTE-TT segments for DASH, instead of one sidecar file |
| Text tracks inside the MP4 (`tx3g`, `wvtt`) | To do | Today only sidecar files are served |
| Subtitles together with clips | To do | Rejected today because cues would drift by up to a GOP ([TDD 0008](technical-design/0008-clipping-and-concatenation.md)) |
| MP3 audio | To do | HLS only in nginx-vod-module; today rejected inside `mp4a` |
| DTS audio | Decide first | HLS only in nginx-vod-module |
| Vorbis audio | Decide first | DASH only, and mostly a WebM concern |
| Muxing audio and video from separate files into one stream | To do | nginx-vod-module serves a separate audio file as part of the video's stream, without client support for rendition groups |
| Track selection for files with several audio or video tracks | To do | Let the mapper choose which tracks of a file to serve |

## Phase 3: Delivery modes and protocols

These change what segmentor is, so each starts with a new TDD.

| Step | Status | Notes |
| --- | --- | --- |
| Simulated live from VOD files | New TDD | A live playlist, a sliding window, and a wall-clock timeline over the clip sequences that already exist. [TDD 0008](technical-design/0008-clipping-and-concatenation.md) defers it explicitly |
| Fallback on file not found | New TDD | nginx-vod-module retries another datacenter on a miss. In segmentor this is a mapper concern (a second location) or an origin failover list |
| Ad markers (`EXT-X-DATERANGE`, DASH events) | New TDD | Deferred by [TDD 0008](technical-design/0008-clipping-and-concatenation.md), together with linear channels |
| Microsoft Smooth Streaming (MSS) | Decide first | A third manifest and fragment layout, plus PlayReady for MSS. Only worth it for a known Xbox or legacy smart-TV audience |
| Adobe HDS | Not recommended | Requires Flash, which no current player supports |
| MPEG-TS segments for HLS | Decide first | nginx-vod-module serves TS; segmentor serves fMP4 ([ADR 0001](adr/0001-use-fragmented-mp4-for-media-segments.md)). Needed only for very old HLS players |
| Clipped MP4 for progressive download | Decide first | A whole-file MP4 response for a window, for players that cannot do HLS or DASH |

## Phase 4: Production readiness

| Step | Status | Notes |
| --- | --- | --- |
| Viewer authorization (signed tokens, optional live check) | Draft | [TDD 0007](technical-design/0007-viewer-authorization.md). nginx-vod-module relies on NGINX modules for this |
| Apple Media Stream Validator on served HLS | To do | Release-time check ([conformance](conformance.md)) |
| DASH-IF conformance tool on served MPDs | To do | Release-time check |
| Browser playback suite (hls.js, dash.js, Safari native) | To do | Start, seek, and play, across the codecs and DRM modes above |
| Benchmarks on the reference host | To do | Budgets are met on a laptop ([benchmarks](benchmarks.md)); record them on the documented four-core host |
| Load test against a production-like catalog | To do | Cold storage, many assets, remote origins, and CDN miss traffic, not one warm file |
| Mapper bearer-token rotation without restart | To do | Re-read the token file periodically |
| Tests against a real HTTPS mapper and origin | To do | Today only in-process mocks |

## Phase 5: Migration from nginx-vod-module

| Step | Status | Notes |
| --- | --- | --- |
| Mapping-JSON compatibility layer | New TDD | An adapter that turns nginx-vod-module's mapped-mode JSON into a segmentor mapper answer, so existing mapping services keep working. [TDD 0008](technical-design/0008-clipping-and-concatenation.md) defers "vod-module mapping compatibility" |
| URL compatibility, or a redirect layer | Decide first | nginx-vod-module URLs differ from segmentor's. Players that load URLs from the mapper need nothing; hard-coded URLs need a rewrite at the proxy |
| Migration guide | To do | Feature mapping, configuration translation, and a shadow-traffic comparison procedure |
| Shadow comparison in production | To do | Run both behind the same CDN on a sample of traffic, and compare manifests, segment decodes, and error rates before cutover |

## Out of scope by design

segmentor never decodes media. The following nginx-vod-module features need decoding (it uses FFmpeg libraries for them), so they would need an ADR that changes that principle:

- thumbnail capture and resizing;
- volume maps;
- playback-rate change, gain, and audio mixing filters.

If one of them is needed, the usual approach is a separate service next to segmentor (for example a thumbnail service reading the same storage), keeping the packaging path decode-free.

## order

1. **Phase 1** (finish DRM): it is the most common blocker for premium catalogs, and it needs no new designs.
2. **Phase 4**, done in parallel: the vendor validators, browser suite, and reference benchmarks give the evidence a production cutover needs, whatever features are added.
3. **Phase 2**: SRT input, segmented subtitles, and MP3 cover most remaining catalogs.
4. **Phase 5**: the migration path, once the features a given deployment uses are covered.
5. **Phase 3**: only the items a real deployment needs; simulated live is the most likely.
Loading
Loading