Open-source film distribution and white-label streaming platform
Upload once. Set your terms. Reach every screen.
Quick start • Features • Costs • Architecture • Modules • Deploy • License
Status: 0.1.0-alpha — Pavilion is under active development. The core platform works (auth, films, licensing, transcoding, secure delivery, payments, ratings, events, admin — 121 passing tests), but some features are still being wired together. We're using it internally and looking for early feedback. Expect rough edges. If you want to try it or contribute, open an issue.
We built Pavilion because the options for indie filmmakers are bad. Aggregators take 30% and give you a quarterly PDF. White-label platforms charge per subscriber and cap your bandwidth. Building on AWS means your CloudFront bill eats your ticket sales.
Pavilion is self-hosted. You run it on a dedicated server with flat-rate bandwidth, keep 100% of your revenue, and see every transaction as it happens. Curators get white-label streaming sites they can launch in hours. The whole thing is Apache 2.0.
Filmmakers upload a film, set licensing terms (rental, subscription, ad-supported, event, educational, Creative Commons — mix and match by territory and time window), and Pavilion handles transcoding up to 4K, storage, delivery, and revenue splits.
Curators browse a catalog that only shows films they can actually license, pick what fits their brand, and get a streaming platform with their own domain, colors, player, and monetization. Stripe Connect handles the money.
Self-hosters run the whole stack on their own hardware. Set the platform fee to zero. Swap in a different payment processor. Fork it.
50 films, 5,000 monthly viewers, ~25 TB bandwidth:
| OTT service | AWS | Pavilion (self-hosted) | |
|---|---|---|---|
| Monthly | $500 – $1,500+ | ~$2,200 | ~$75 – $150 |
| Per subscriber | $0.50 – $1.00 | — | None |
| Bandwidth | Metered / capped | $0.085/GB | Included |
| Transcoding | Limited | $0.024/min | Your CPU |
| Revenue cut | 5 – 20% | — | 0% |
| Own the code | No | Some | Yes |
A screening for 1,000 viewers costs about $425 on CloudFront just in bandwidth. On a Hetzner box running Pavilion, that's $0 — bandwidth is part of the monthly rate.
The math is simple: AWS charges per gigabyte, one 1080p viewer burns 5 GB, and it adds up fast. Dedicated servers from Hetzner (from €44/month) or OVH ($70/month) include 20 TB+ at full speed.
These numbers are just one example. Pavilion runs fine on a single machine — database, storage, transcoding, and the web server all on one box — which is plenty for a small catalog and a few hundred concurrent viewers. If you need more, split the services across machines: dedicate a box to transcoding, cluster the database, add more web servers behind a load balancer. The architecture scales from a $44/month single server to a multi-node production setup without changing any code.
- Transcoding from 360p to 4K (H.264, CMAF, HLS + DASH)
- 7 licensing models: TVOD, SVOD, AVOD, hybrid, event, educational, Creative Commons
- Per-territory and time-window licensing
- Revenue dashboard with per-film, per-platform breakdowns and automatic 3-way splits
- TMDB metadata import — cast, crew, posters, synopses in one click
- Poster auto-resize to 4 variants
- DMCA counter-notification tools
- GDPR data export, consent management, account deletion
- Branded streaming sites (custom domain, colors, fonts, dark mode)
- Rights-aware catalog — you only see what you can license
- Stripe Connect for subscriptions, pay-per-view, and ad-supported models
- Platform analytics: subscribers, views, revenue, popular films
- Event screenings with ticketing and attendee caps
- Per-platform ratings with moderation
- System dashboard, person management, DMCA review
- Per-filmmaker storage metering with pricing tiers
- 121 integration tests across auth, films, licensing, catalog, platforms, player, payments, ratings, revenue, DMCA, events, billing, and admin
Every segment request goes through the full chain before anything is served:
- Platform is active
- Film is published
- Platform carries the film via a license
- License is within its time window
- No active DMCA claims
- Viewer has a valid entitlement (for paid content)
- Segment URL is HMAC-signed, tied to that user, and expires in 5 minutes
Storage is never public. No direct URLs. No way around it.
When a film is uploaded, Pavilion transcodes it into six renditions using FFmpeg:
| Rendition | Resolution | Bitrate | Typical use |
|---|---|---|---|
| 360p | 640×360 | 800 kbps | Mobile on slow connections |
| 480p | 854×480 | 1.4 Mbps | Mobile on decent connections |
| 720p | 1280×720 | 2.8 Mbps | Tablets, small screens |
| 1080p | 1920×1080 | 5 Mbps | Laptops, desktops |
| 1440p | 2560×1440 | 10 Mbps | Large monitors |
| 2160p | 3840×2160 | 16 Mbps | 4K displays |
Output format is CMAF (Common Media Application Format) — fMP4 segments that work with both HLS and DASH. One set of segments, two manifest formats. No duplicate storage.
The player (HLS.js on non-Safari, native HLS on Safari) picks the right rendition based on the viewer's bandwidth and switches mid-stream if conditions change. A viewer on a train watching on their phone gets 480p. The same viewer at home on fiber gets 4K. Same URL, same segments.
Transcode jobs live in a SurrealDB-backed queue. Workers claim jobs atomically (SELECT + UPDATE with a WHERE guard to prevent double-claims), send heartbeats every 30 seconds, and get reaped if they go silent for 5 minutes. Failed jobs retry up to 3 times before being marked permanently failed. Workers scale independently — run one on a dev machine, ten on a render farm.
The full pipeline: download the master from RustFS → transcode all renditions → generate HLS and DASH manifests → upload everything back to RustFS → create asset records in SurrealDB.
All video files (masters, segments, manifests, posters) live in RustFS, an S3-compatible object storage server. RustFS is open source (Apache 2.0), written in Rust, and supports distributed mode with erasure coding for redundancy.
Pavilion never exposes storage URLs to the client. Every segment is served through a proxy that validates a signed token before fetching from RustFS. The tokens are HMAC-SHA256 signed, contain the viewer's identity, and expire in 5 minutes.
Poster images are automatically processed into 4 sizes on upload (92×138 thumbnail, 185×278 small, 370×556 medium, 780×1170 large) so templates can pick the right one for the context.
SurrealDB v3 with a graph-first data model. Relationships between people, films, platforms, licenses, and ratings are all graph edges (RELATE person->filmmaker_of->film), which means ownership checks and rights resolution are single-hop traversals instead of multi-table joins.
All tables are SCHEMAFULL with field-level type assertions and unique indexes. The schema is idempotent (IF NOT EXISTS on every definition) so you can re-run make db-init safely.
For clustering, SurrealDB uses TiKV as the storage backend. In dev, it runs single-node with SurrealKV (embedded).
Streaming video is one of the hardest things to do efficiently on a web server. Every concurrent viewer is sustained bandwidth, CPU work for manifest rewriting, and I/O for segment delivery. Language choice matters here more than most places.
| Rust | Node.js | |
|---|---|---|
| Memory (idle) | ~15–30 MB | ~80–200 MB |
| Concurrency | Async I/O, no GC | Event loop, GC pauses |
| Tail latency | Predictable | GC spikes |
| CPU throughput | Near C | 3–10x slower |
| Safety | Compile-time | Runtime exceptions |
| Deploy size | ~15 MB binary | ~200 MB with node_modules |
When you're serving thousands of concurrent viewers and every millisecond of segment delivery matters, the difference between 15 MB and 200 MB of memory per process isn't academic.
Pavilion runs on Axum / Tokio for async HTTP, Askama for compiled templates, and Datastar for server-driven reactivity. No React. No Next.js. No client-side framework.
┌─────────────────┐
│ Load Balancer │
└────┬───────┬────┘
│ │
┌──────────┴┐ ┌┴──────────┐
│ Pavilion │ │ Pavilion │ Stateless Rust servers
│ Node 1 │ │ Node N │ (JWT, no sticky sessions)
└─────┬─────┘ └─────┬──────┘
│ │
┌───────────┼─────────────────┼───────────┐
│ │ │ │
┌─────┴─────┐ ┌───┴────┐ ┌──────┴──┐ ┌─────┴─────┐
│ SurrealDB │ │SurrealDB│ │ RustFS │ │ Qdrant │
│ (TiKV) │ │(TiKV) │ │ Cluster │ │ Cluster │
└───────────┘ └─────────┘ └──────────┘ └───────────┘
Pavilion servers are stateless. Session state lives in JWT tokens, data lives in SurrealDB. Put as many instances behind a load balancer as you need.
SurrealDB clusters via TiKV. RustFS (S3-compatible) runs in distributed mode with erasure coding. Qdrant handles vector search for semantic film discovery (planned). Transcode workers poll the job queue independently and scale with demand.
The project is a Cargo workspace with two crates. We split the video infrastructure from the business logic on purpose — so you can build a streaming backend without the licensing layer if that's what you need.
The full distribution platform: auth, licensing, payments, ratings, events, admin, everything above.
Lives at crates/pavilion-media/. Handles storage (any S3-compatible service), FFmpeg transcoding (360p–4K, CMAF), HLS/DASH manifest generation, and HMAC-signed segment tokens.
The API uses generic names (subject/resource/scope) instead of Pavilion-specific ones, so it works for other things:
| Use case | subject | resource | scope |
|---|---|---|---|
| Film distribution | person ID | film ID | platform ID |
| Acting reels | "public" |
reel ID | "default" |
| Course platform | student ID | lesson ID | course ID |
| Internal video | user ID | video ID | org ID |
Add it as a dependency, wire your own auth, done. Crate docs are here.
You'll need Rust 1.85+, Docker, the SurrealDB CLI, and FFmpeg.
git clone https://github.com/secedastudios/pavilion.git
cd pavilion
cp .env-example .env
make services # SurrealDB, RustFS, Qdrant
make db-init # apply schema
make dev # http://localhost:3000| Command | What it does |
|---|---|
make dev |
Run the app |
make services |
Start backing services |
make services-down |
Stop them |
make build |
Release binary |
make db-init |
Apply schema |
make db-drop |
Drop database |
make db-seed |
Load seed data |
make test |
Run all 121 tests |
make docs |
Build rustdocs to docs/ |
make healthcheck |
Ping the running instance |
cp .env-example .env
# fill in production credentials, your domain, Stripe keys if you want payments
docker compose -f docker-compose.prod.yml up -dThat starts Pavilion, SurrealDB, RustFS, and Qdrant. Data persists in Docker volumes. The Pavilion image is a distroless container.
To scale, put more instances behind nginx/Caddy/HAProxy. SurrealDB clusters via TiKV, RustFS distributes, transcode workers scale independently.
Everything is in environment variables, loaded from .env. Full list in .env-example.
| Variable | What it does |
|---|---|
STRIPE_SECRET_KEY |
Enables payments. Leave empty to run without Stripe. |
FACILITATION_FEE_PCT |
Platform fee. Set to 0 for self-hosted instances. |
TMDB_API_KEY |
Enables metadata, cast, crew, and poster import from TMDB. |
BASE_URL |
Your public domain. Used for OAuth redirects and cookie settings. |
make test121 tests, 14 files, in-memory SurrealDB. No running services needed.
| Technology | ||
|---|---|---|
| Language | Rust 2024 | Memory safe, fast, predictable |
| HTTP | Axum | Async, composable, tower ecosystem |
| Database | SurrealDB v3 | Graph-first, SCHEMAFULL, clusterable |
| Templates | Askama | Compiled, type-safe, auto-escaping |
| Reactivity | Datastar | Server-sent events, no JS framework |
| Storage | RustFS | S3-compatible, Apache 2.0 |
| Transcoding | FFmpeg | H.264, HEVC, AV1 |
| Payments | Stripe Connect | Pluggable via trait |
| Video | pavilion-media | Standalone reusable crate |
We're actively working on this. If you're interested — filmmaker, curator, or developer — open an issue or send a PR.
The build plan covers all 16 phases. Run make docs for API documentation.
Seceda Studios builds open-source tools for film and creative industries. We think filmmakers should own their infrastructure, control their platforms, and actually be able to verify their revenue. Pavilion is how we're trying to make that real.
If you work in film, TV, or content creation, take a look at SlateHub too. It's a free networking platform where actors, crew, and filmmakers manage their profiles, credits, and reels in one place. We built that as well.
Made with Rust. For filmmakers, by filmmakers.