System Design: [Video platform name]
Reference design for video upload and adaptive bitrate streaming: resumable
upload, a transcoding pipeline that produces a renditions ladder, CMAF
packaging for HLS and DASH, CDN delivery, a DRM note, view counting, storage
tiers and cost. It follows the structure of the System Design Document
template and is pre-filled with a worked design to adapt. Values marked
Example are assumptions: replace them and recompute; egress and storage
numbers move by orders of magnitude with your audience.
Document control
| Field | Value |
|---|
| Document ID | [SDD-VID-001] |
| System / feature | [Video upload and streaming] |
| Version | [0.1] |
| Status | [Draft / In review / Approved / Implemented / Superseded] |
| Author(s) | [@author] |
| Reviewers | [@reviewer-1], [@reviewer-2] |
| Last updated | YYYY-MM-DD |
| Related | [PRD], [CDN contract], [Content licensing requirements], [ADR: codec strategy] |
Approvals
| Role | Name | Decision | Date |
|---|
| Tech lead | [@name] | [Approved / Changes requested] | YYYY-MM-DD |
| Staff / principal engineer | [@name] | [Decision] | YYYY-MM-DD |
| SRE / operations | [@name] | [Decision] | YYYY-MM-DD |
| Media / video engineering lead | [@name] | [Decision] | YYYY-MM-DD |
| Finance (CDN and storage cost) | [@name] | [Decision] | YYYY-MM-DD |
Revision history
| Version | Date | Author | Change summary |
|---|
| 0.1 | YYYY-MM-DD | [@name] | First draft for design review |
| 0.2 | YYYY-MM-DD | [@name] | Example: CMAF packaging to serve HLS and DASH from one set of segments |
| 0.3 | YYYY-MM-DD | [@name] | Example: AV1 renditions only for videos above 1 000 views |
| 1.0 | YYYY-MM-DD | [@name] | Example: Approved |
Contents
1. Overview
1.1 Problem statement
[Example: Creators upload MP4 files that we serve as progressive downloads
from a single bucket. Mobile viewers on weak networks stall every 20 seconds,
a 4 GB upload fails if the connection drops, and our cloud egress bill grew
4x in a year.]
1.2 Proposed solution
[Example: Clients upload directly to object storage with resumable,
chunked uploads. An upload event starts a transcoding workflow that splits
the source into chunks, encodes them in parallel into a ladder of renditions,
and packages fragmented MP4 segments (CMAF) with HLS and DASH manifests.
Players choose the rendition per segment based on measured throughput (adaptive
bitrate). A CDN serves segments from the edge with an origin shield in front
of storage. View events stream into an aggregation pipeline for counts and
analytics. Older and rarely watched renditions move to cheaper storage tiers.]
1.3 Decisions requested from reviewers
| ID | Question | Recommended option | Section |
|---|
| Q-01 | Example: Codecs at launch? | H.264 for all; AV1 added for popular videos | 7.2, 10 |
| Q-02 | Example: Segment duration? | 4 s segments, 2 s GOP | 7.3 |
| Q-03 | Example: DRM in v1? | Only for licensed catalogue; user uploads use signed URLs | 7.5 |
| Q-04 | Example: Keep source files? | Yes, in archive tier after 30 days | 7.7 |
| [Q-nn] | [Question] | [Option] | [Section] |
2. Requirements
2.1 Functional requirements
| ID | Requirement | Priority |
|---|
| FR-01 | Example: Upload files up to 20 GB and 4 h, resumable after network loss | Must |
| FR-02 | Example: Transcode to an adaptive ladder from 240p to 1080p (4K for eligible creators) | Must |
| FR-03 | Example: Play on web, iOS, Android and TV apps with adaptive bitrate | Must |
| FR-04 | Example: Thumbnails and preview sprites | Must |
| FR-05 | Example: Captions (WebVTT) uploaded or generated | Should |
| FR-06 | Example: View counts visible within 5 minutes | Should |
| FR-07 | Example: DRM for licensed content | Must for licensed catalogue |
| [FR-nn] | [Requirement] | [Must / Should / Could] |
2.2 Non-functional requirements
| ID | Quality | Target | Measured as |
|---|
| NFR-01 | Startup time | Example: Video start p90 at or below 1.5 s | Player telemetry |
| NFR-02 | Rebuffering | Example: Rebuffer ratio below 0.5% of watch time | Player telemetry |
| NFR-03 | Processing time | Example: 10-minute 1080p video playable within 5 min of upload | Workflow metrics |
| NFR-04 | Availability | Example: 99.95% playback availability | Synthetic playback probes per region |
| NFR-05 | Durability | Example: Sources and renditions 11 nines (object storage class) | Provider SLA, checksums |
| [NFR-nn] | [Quality] | [Target] | [Measurement] |
2.3 Out of scope
- [Example: live streaming (separate design: ingest, low-latency packaging)]
- [Example: recommendations and search]
- [Example: in-browser video editing]
- [Item deferred, with the release that will take it]
3. Capacity estimation
3.1 Assumptions
| Input | Symbol | Value | Source |
|---|
| Uploads per day | U | Example: 100 000 | Growth plan |
| Average duration | d | Example: 10 min | Current uploads |
| Average source bitrate | bs | Example: 8 Mbit/s | Current uploads |
| Ladder bitrate sum (H.264) | bl | Example: 10.7 Mbit/s | 7.2 |
| Views per day | V | Example: 100 million | Analytics forecast |
| Average watch time per view | w | Example: 5 min | Analytics |
| Average delivered bitrate | bd | Example: 3 Mbit/s | Player telemetry |
| Encoding cost | e | Example: 6 vCPU-min per minute of video (full ladder) | Benchmark |
| Peak to average factor | k | Example: 2 (evening) | Traffic history |
3.2 Storage
Source per video: 600 s×8 Mbit/s=4800 Mbit=600 MB.
Renditions per video: 600×10.7=6420 Mbit≈800 MB.
Sday=U×(600+800) MB=105×1.4 GB=140 TB/day Syear≈140 TB×365≈51 PB/year Storage tiering (7.7) is therefore part of the design, not an afterthought.
3.3 Transcoding compute
C=U×d×e=105×10×6=6×106 vCPU-min/day=105 vCPU-hours/day average concurrency=24105≈4200 vCPU,peak≈8400 vCPU Spot or preemptible capacity suits this load because chunks are short and
retryable.
3.4 Egress
Eday=V×w×bd=108×300 s×3 Mbit/s=9×1010 Mbit=11.25 PB/day Bˉ=86400 s9×1010 Mbit≈1.04 Tbit/s,Bpeak≈2.1 Tbit/s 3.5 Summary
| Quantity | Estimate | Design consequence |
|---|
| New storage | ~140 TB/day, ~51 PB/year | Tiering, source archive, delete unused renditions |
| Transcoding | ~4 200 vCPU average, ~8 400 peak | Chunked parallel encoding on spot capacity |
| Egress | ~11 PB/day, ~2 Tbit/s peak | Multi-CDN with origin shield; cache hit ratio is the key cost lever |
| View events | ~1 160/s average (plus heartbeats) | Stream aggregation, not database counters |
4. API design
4.1 Endpoints
| Method | Path | Purpose | Auth | Idempotent |
|---|
| POST | /v1/videos | Create video record, get resumable upload session | Creator token | With Idempotency-Key |
| PUT | upload session URL (object storage) | Upload chunks with byte ranges | Signed session | Yes per chunk |
| POST | /v1/videos/{id}/complete | Finish upload, start processing | Creator token | Yes |
| GET | /v1/videos/{id} | Metadata and processing state | Token or public | Yes |
| GET | /v1/videos/{id}/playback | Manifest URLs, signed CDN token, DRM licence URL | Viewer token or public | Yes |
| POST | /v1/views | View start and heartbeat events | Viewer session | Dedup by viewId + sequence |
4.2 Request and response examples
The playback endpoint returns short-lived signed URLs for both manifest types:
GET /v1/videos/v_9QK2/playback HTTP/1.1
Authorization: Bearer [viewer token]
{"videoId": "v_9QK2", "hls": "https://cdn.example.net/v/v_9QK2/master.m3u8?token=eyJ...", "dash": "https://cdn.example.net/v/v_9QK2/manifest.mpd?token=eyJ...", "expiresAt": "2026-03-14T20:00:00Z", "drm": null, "captions": [{"lang": "en", "url": "https://cdn.example.net/v/v_9QK2/en.vtt"}]}
4.3 Errors and limits
| Status | Problem type | When |
|---|
| 403 | geo-restricted | Viewer region not licensed |
| 409 | not-ready | Processing not finished |
| 413 | upload-too-large | Source over limit |
| 422 | unsupported-media | Source cannot be decoded |
| 429 | upload-quota-exceeded | Creator daily upload quota reached |
5. Data model
5.1 Entities
Video metadata lives in a database; media objects live in object storage and
are referenced by key.
5.2 Storage choices
| Data | Store | Key | Main queries | Why |
|---|
| Video metadata | Relational database (sharded by video_id) | video_id | Get by ID; list by owner | Transactions on state changes |
| Sources | Object storage, standard then archive tier | src/{video_id} | Read for re-encode | Large, rarely read after processing |
| Segments and manifests | Object storage, standard then infrequent-access tier | v/{video_id}/{rendition}/{n}.m4s | Read by CDN origin | Immutable, cacheable forever |
| Workflow state | Durable workflow engine | job_id | Resume and retry steps | Long-running, failure-prone |
| View counts | Stream aggregates into wide-column store | video_id, day | Totals and daily series | High write rate |
6. High-level design
Uploads and playback never pass through application servers; the API only
issues signed URLs and tracks state.
| Component | Responsibility | Scales by |
|---|
| Video API | Create videos, issue upload sessions and playback tokens | Stateless replicas |
| Workflow orchestrator | Run processing steps with retries and timeouts | Workflow workers |
| Encoder pool | Encode chunks per rendition | vCPU or GPU instances, spot |
| CMAF packager | Produce segments, HLS and DASH manifests, encryption when DRM is on | Stateless workers |
| CDN and origin shield | Serve segments; collapse origin requests | Provider capacity |
| Stream aggregation | Deduplicate and count views | Stream partitions |
| [Component] | [Responsibility] | [Scaling unit] |
7. Detailed design
7.1 Upload and processing workflow
Processing state is a small state machine stored on the video record; the
workflow engine drives transitions and retries each step independently.
A video becomes ready as soon as the 360p and 720p renditions exist, so
viewers can start watching while higher renditions finish.
7.2 Renditions ladder
| Rendition | Resolution | Video bitrate (H.264) | Audio | Typical use |
|---|
| Example: 1080p | 1920x1080 | 5 000 kbit/s | 128 kbit/s AAC | Wi-Fi, TV |
| 720p | 1280x720 | 3 000 kbit/s | 128 kbit/s | Good mobile, laptop |
| 480p | 854x480 | 1 500 kbit/s | 96 kbit/s | Average mobile |
| 360p | 640x360 | 800 kbit/s | 96 kbit/s | Weak mobile, fast start |
| 240p | 426x240 | 400 kbit/s | 64 kbit/s | Very weak networks |
The video bitrates sum to 10.7 Mbit/s (the bl input in 3.1; audio is
shared across renditions and adds little). Per-title encoding can lower these
bitrates substantially for simple content such as slides or animation; adopt
it once quality metrics (for example VMAF) are in place. AV1 renditions save
roughly 30% or more bandwidth at equal quality on supporting devices but cost
several times more compute, so they are produced only for videos above
Example: 1 000 views, where egress savings exceed encoding cost.
7.3 Chunked encoding and packaging
- The source is probed, then split at keyframes into chunks of about 30 s.
- Each chunk is encoded per rendition with a fixed GOP of 2 s and
closed GOPs so segments align across renditions; players can switch at any
segment boundary.
- The packager writes CMAF fragmented MP4 segments of 4 s, one HLS master
playlist with media playlists, and one DASH MPD, all referencing the same
segment files.
- Failed chunks are retried individually (up to 3 attempts, then on
on-demand capacity), so a spot interruption costs at most one chunk.
7.4 Playback path (critical path)
The player fetches a manifest, then segments, choosing a rendition per segment
from throughput and buffer level.
Manifests for on-demand videos are immutable after ready, except when
renditions are added; they are cached for minutes, segments for a year.
7.5 DRM note
For licensed content, segments are encrypted with Common Encryption (CENC)
using the cbcs scheme, which lets one set of CMAF segments work with
FairPlay (Apple devices), Widevine (Chrome, Android) and PlayReady (Windows,
many TVs). The licence service checks entitlement and issues keys with
policies (rental expiry, output protection). DRM requires licensing agreements
with each DRM vendor, adds a licence round trip to startup and complicates
offline playback; user uploads without licensing obligations use signed URLs
and token-authenticated CDN access instead.
7.6 View counting and consistency model
- Players send a view-start event with a random
viewId, then heartbeats.
A view counts once watch time passes Example: 30 s, which filters
autoplay noise.
- The stream job deduplicates by
viewId, drops bot traffic by rules and
reputation, and updates per-minute aggregates; public counts are refreshed
every 5 minutes. Counts are eventually consistent and can be corrected
downward after fraud review.
- Video metadata and state changes are strongly consistent in the database.
Segments are immutable objects, so CDN caches can never serve a mixed
version of a segment; deletions propagate by CDN purge within minutes.
7.7 Storage tiers
| Object | Day 0-30 | Day 31-365 | After 365 days |
|---|
| Source | Standard | Archive tier (hours to restore) | Archive tier |
| Popular renditions (views in last 30 days) | Standard | Standard | Standard |
| Unpopular renditions | Standard | Infrequent access | Infrequent access; delete 1080p if no views for a year and re-encode on demand from source |
| Thumbnails, manifests | Standard | Standard | Standard |
8. Scalability and performance
| Concern | Approach | Limit before redesign |
|---|
| Egress | Multi-CDN, origin shield, long cache lifetimes | CDN commit levels; consider own edge caches above ~10 Tbit/s |
| Viral video | Shield collapses requests; first segments pre-warmed for trending videos | Edge capacity per region |
| Encoding backlog | Spot pool autoscaling on queue depth; priority for short videos | Regional spot availability |
| Metadata reads | Cache playback responses for 60 s | [Limit] |
| Origin requests | Target CDN hit ratio of 95% or more | Shield capacity |
Startup budget for a video start (target p90 1.5 s):
| Step | Budget |
|---|
| Playback API | 150 ms |
| Master and media playlists | 200 ms |
| First segment at 360p (4 s x 0.9 Mbit/s, about 450 KB) | 600 ms |
| Decoder start | 150 ms |
| Headroom | 400 ms |
9. Reliability, security and operations
9.1 Failure modes
| Failure | Impact | Detection | Mitigation |
|---|
| CDN provider degraded in a region | Rebuffering, failed starts | Player error and rebuffer rates per CDN | Multi-CDN switching by player or DNS steering |
| Spot capacity reclaimed | Slower processing | Workflow queue age | Chunk retries; fallback to on-demand for jobs older than 15 min |
| Corrupt rendition | Playback errors at a point | Player decode errors by rendition | Automated validation after packaging; re-encode |
| Metadata DB unavailable | New playback sessions fail | API error rate | Cached playback responses; read replicas |
| Upload interrupted | Creator frustration | Session abandonment rate | Resumable sessions valid 7 days |
| [Failure] | [Impact] | [Signal] | [Mitigation] |
9.2 Security and abuse
| Threat | Control |
|---|
| Hotlinking and unauthorised redistribution | Signed CDN tokens bound to path and expiry; DRM for licensed content |
| Malicious media files exploiting decoders | Decode in sandboxed, unprivileged workers with resource limits; patch media libraries promptly |
| Illegal or harmful content | Upload scanning against hash lists, classifiers, reporting and takedown workflow |
| View count fraud | Dedup by viewId, bot detection, retroactive correction |
| [Threat] | [Control] |
9.3 Observability
| Signal | Metric or log | Alert threshold |
|---|
| Startup time | Player p90 | Above 1.5 s for 15 min in a region |
| Rebuffer ratio | Rebuffer time / watch time | Above 0.5% |
| Playback errors | Fatal errors per 1 000 starts | Above 2 |
| Processing time | Upload complete to ready p95 | Above 5 min for 10-min videos |
| CDN hit ratio | Edge hits / requests | Below 95% |
9.4 Cost estimate
| Item | Unit cost | Quantity | Monthly cost |
|---|
| CDN egress | Example: $0.005/GB at committed volume | Example: ~337 PB | Example: ~$1.7 million |
| Object storage (standard, IA, archive) | [$/TB-month per tier] | Example: +4.2 PB/month | [$] |
| Transcoding compute (spot) | [$/vCPU-hour] | Example: 3 million vCPU-hours | [$] |
| DRM licences | [$/licence or flat] | [n] | [$] |
| Total | | | [$] |
10. Trade-offs and alternatives
| Decision | Options | Chosen | Why | What we give up |
|---|
| Delivery | Progressive MP4; HLS only; DASH only; CMAF for both | CMAF for HLS and DASH | One set of segments for all devices | Older devices without fMP4 support need a TS fallback or are unsupported |
| Codecs | H.264 only; H.264 + HEVC; H.264 + AV1 | H.264 + AV1 for popular videos | Universal compatibility plus bandwidth savings where it pays | Two encoder pipelines |
| Encoding | Whole file per worker; chunked parallel | Chunked parallel | Fast turnaround, cheap retries on spot | Chunk boundary handling and stitching complexity |
| Transcoding service | Managed cloud service; own pipeline | [Own / Managed] | [Reason: cost at scale, control of ladder] | [Cost] |
| CDN | Single CDN; multi-CDN | Multi-CDN | Resilience and price leverage | Steering logic and per-CDN tokens |
| Storage of unpopular renditions | Keep all; delete and re-encode on demand | Delete 1080p after a year without views | Large storage savings | First viewer waits or gets 720p |
| [Decision] | [Options] | [Chosen] | [Why] | [Cost] |
11. Delivery plan and risks
11.1 Milestones
| Milestone | Scope | Exit criterion | Target date |
|---|
| M1 | Resumable upload, H.264 ladder, HLS via one CDN | Rebuffer ratio below 1% in beta | YYYY-MM-DD |
| M2 | CMAF HLS + DASH, origin shield, view counting | CDN hit ratio 95%; counts within 5 min | YYYY-MM-DD |
| M3 | Multi-CDN and storage tiering | Egress cost per GB down 20% | YYYY-MM-DD |
| M4 | DRM for licensed catalogue; AV1 for popular videos | Licence partner certification | YYYY-MM-DD |
11.2 Rollout and rollback
[Example: Re-encode the existing catalogue in the background, most viewed
first. The player chooses adaptive streaming when a ready ladder exists and
falls back to the old MP4 otherwise; rollback sets a flag that forces the MP4
path.]
11.3 Risks
| ID | Risk | Likelihood | Impact | Mitigation | Owner |
|---|
| R-01 | Example: Egress cost exceeds forecast | Medium | High | Per-title encoding, AV1, committed-use CDN contracts | [@name] |
| R-02 | Example: Spot shortage delays processing | Medium | Medium | On-demand fallback; multiple instance types and regions | [@name] |
| R-03 | Example: DRM integration delays licensed launch | Medium | High | Start certification early; use a packaging vendor | [@name] |
| [R-nn] | [Risk] | [L / M / H] | [L / M / H] | [Mitigation] | [@name] |
12. Appendices
12.1 Open questions
| ID | Question | Owner | Due |
|---|
| OQ-01 | Example: Do we offer 4K for all creators or only partners? | [@name] | YYYY-MM-DD |
| OQ-02 | Example: Automatic captions: in-house model or vendor? | [@name] | YYYY-MM-DD |
| [OQ-nn] | [Question] | [@name] | YYYY-MM-DD |
12.2 Glossary
| Term | Meaning |
|---|
| ABR | Adaptive bitrate: player switches renditions based on network conditions |
| Rendition | One encoded version of a video at a resolution and bitrate |
| Ladder | Set of renditions offered for a video |
| CMAF | Common Media Application Format: fragmented MP4 segments shared by HLS and DASH |
| GOP | Group of pictures: frames between keyframes |
| Origin shield | Cache layer between CDN edges and storage that reduces origin load |
| [Term] | [Meaning] |
12.3 References
| Reference | Use |
|---|
| RFC 8216 HTTP Live Streaming | HLS playlists |
| ISO/IEC 23009-1 (MPEG-DASH) | DASH manifests |
| ISO/IEC 23000-19 (CMAF) | Segment format |
| ISO/IEC 23001-7 (Common Encryption) | DRM encryption schemes |
| W3C WebVTT | Captions |
Standard and licence note
Based on common industry practice for video-on-demand platforms and on the
specifications cited in 12.3; no text from ISO/IEC standards is reproduced.
This is a reference design to adapt, with illustrative numbers and prices.
Original text written for this collection. Template licence: MIT.