What makes a library different from a live channel
An on-demand title is encoded once and then read thousands of times, at any hour, from any point in the file. That turns the problem around compared with live streaming: encoding cost is paid once per title, while storage grows with every hour you add and transfer grows with every hour anyone watches. A live channel needs ingest and real-time transcoding; a library needs disk, a correct packaging of static files, and delivery that copes with a long tail of rarely watched titles next to a few that everybody opens on the same evening.
Apple's HLS authoring specification separates the two cases explicitly. The rules a library has to meet:
| Rule (item number) | What it means for a stored title |
|---|---|
| Playlists made from static content MUST carry EXT-X-PLAYLIST-TYPE:VOD (8.6) | The player knows the file is complete and can offer the full seek bar |
| All VOD media playlists of one asset MUST cover the same time range (8.7) | Every rung of the ladder holds the whole title, so storage multiplies by rungs |
| Target segment duration SHOULD be 6 seconds (7.5); each segment MUST start with an IDR (7.4) | Key frames placed every 2 seconds (1.13) line up with every cut |
| VOD SHOULD keep a natural frame rate (1.18) and the source colour space (1.22) | Archive footage keeps its 25 or 23.976 fps; no forced conversion |
| VOD average segment bitrate MUST be within 10% of AVERAGE-BANDWIDTH (1.26); peak SHOULD be no more than 200% of average (1.30) | Cap the encoder's peak rate, or players will misjudge the rung |
Apple's specification also requires I-frame playlists (6.1): renditions built from key frames that players use for scrubbing and scanning, which is what makes a long archive recording easy to search. The FFmpeg ladder command further down does not write them, so full Apple compliance needs a packager that does.
Storage: gigabytes per hour of catalogue
Storage per hour is bitrate x 3,600 s / 8. The figures below are our arithmetic on Apple's published H.264 rungs, video only, in decimal gigabytes; add about 0.06 GB an hour for 128 kbit/s stereo audio.
| What you store per title | Sum of bitrates | GB per hour of content | Hours in 200 GB | Hours in 2 TB |
|---|---|---|---|---|
| One 960x540 file at 2,000 kbit/s | 2,000 kbit/s | 0.90 | about 222 | about 2,222 |
| One 1280x720 file at 3,000 kbit/s | 3,000 kbit/s | 1.35 | about 148 | about 1,481 |
| One 1280x720 file at 4,500 kbit/s | 4,500 kbit/s | 2.03 | about 99 | about 988 |
| Six-rung ladder: 365, 730, 2,000, 3,000, 4,500, 6,000 | 16,595 kbit/s | 7.47 | about 27 | about 268 |
Two conclusions follow. A full ladder costs several times the disk of a single rendition, because rule 8.7 makes every rung carry the whole title. And the master you edited from is not the file you serve: keep mezzanine copies in cold storage of your own, and size the serving library only for what viewers actually receive.
Transfer and peak load
Monthly transfer is viewing hours x GB per hour at the rung viewers actually receive, not the top rung you encoded. Peak bandwidth is the number of people watching in the same minute x that bitrate. A library's traffic is lumpy: a replay published the morning after an event can draw more viewers in a day than the archive behind it draws in a month.
- A training archive with 8,000 viewing hours a month at 3,000 kbit/s: 8,000 x 1.35 GB = 10.8 TB a month.
- A back catalogue watched for 40,000 hours, delivered at 2,000 kbit/s: 40,000 x 0.9 GB = 36 TB a month.
- A replay with 2,500 people watching at the same time, each pulling 4,500 kbit/s: 2,500 x 4.5 Mbit/s = 11.25 Gbit/s at the peak.
The third line is the one that breaks a single server: the transfer total is modest, but the minute it happens it needs a port above 10 Gbps. That shape, small average and sharp peak, is the case for spreading delivery across cities.
Route one: the managed library on the video CDN
Our video on demand hosting takes a finished MP4 per title and plays it to each viewer from the nearest of five cities: New York, Miami, San Francisco, Amsterdam and Bucharest. Nothing is re-encoded. Each file passes a format check on upload and is then ready, with its own player and embed code. The library lives on our own storage: Starter holds 50 GB, Pro 200 GB, Platinum 2 TB, with files up to 100 GB each. Transfer counts against the plan's monthly allowance, shared with any live channels on the account; the video CDN plans list every row.
The accepted format: MP4 (.mp4 or .m4v); H.264 Baseline, Main or High, 8-bit 4:2:0, up to 1920x1080 and 60 frames a second; AAC-LC at 44.1 or 48 kHz, mono or stereo, or no sound. Because nothing is re-encoded, the library holds the single rendition you export, so the work is auditing the archive before it goes up. ffprobe prints, per file, a video line (codec, profile, size, pixel format, frame rate) and an audio line (codec, profile, sample rate, channels):
shopt -s nullglob
for f in archive/*.mp4 archive/*.mov archive/*.mkv; do
v=$(ffprobe -v error -select_streams v:0 \
-show_entries stream=codec_name,profile,width,height,pix_fmt,r_frame_rate \
-of csv=p=0 "$f")
a=$(ffprobe -v error -select_streams a:0 \
-show_entries stream=codec_name,profile,sample_rate,channels \
-of csv=p=0 "$f")
echo "$f | $v | $a"
done > audit.txt
Anything not in an MP4 container, not h264 with yuv420p, larger than 1920x1080, faster than 60 fps, or with audio other than AAC LC at 44,100 or 48,000 Hz in 1 or 2 channels (phone recordings in HEVC, 4K camera masters, 10-bit grading exports) gets conformed once. HDR material (PQ or HLG, including most phone HDR clips) needs tone-mapping or an SDR export first, or it looks washed out after conversion. This command fits the picture inside 1920x1080 without stretching it, keeps the source frame rate up to a 60 fps ceiling, forces a key frame every two seconds and moves the MP4 index to the front so playback starts before the whole file is read:
ffmpeg -i masters/replay-0914.mov \
-vf "scale='min(1920,iw)':'min(1080,ih)':force_original_aspect_ratio=decrease:force_divisible_by=2" \
-fpsmax 60 \
-c:v libx264 -profile:v high -pix_fmt yuv420p \
-crf 20 -maxrate 6000k -bufsize 12000k \
-force_key_frames "expr:gte(t,n_forced*2)" \
-c:a aac -b:a 128k -ar 48000 -ac 2 \
-movflags +faststart \
library/replay-0914.mp4
Upload the result in the Media tab of the dashboard. The same files can also run as a 24/7 TV station built from playlists, rotations and ad breaks, and every library plan includes a Samsung and LG TV app in your own name. Batch conforming a large archive on a GPU is covered in FFmpeg GPU transcoding.
Route two: your own origin on a dedicated server
When the library needs a full ladder, HEVC or 4K rungs, or access rules of your own, package it yourself and serve the segments from a dedicated streaming server: one physical machine with root, an out-of-band console and an unshared, unmetered port, 1 Gbps on 10 of 18 lines and up to 100 Gbps on the order form, with no transfer allowance and no overage. The FFmpeg HLS muxer writes the ladder, the VOD playlist type and a master playlist in one pass (not the I-frame playlists). Three rungs from Apple's table, each kept within its peak rule:
mkdir -p out
ffmpeg -i library/replay-0914.mp4 \
-filter_complex "[0:v]split=3[a][b][c];[a]scale=-2:540[r1];[b]scale=-2:720[r2];[c]scale=-2:1080[r3]" \
-map "[r1]" -map 0:a:0 -map "[r2]" -map 0:a:0 -map "[r3]" -map 0:a:0 \
-c:v libx264 -pix_fmt yuv420p -force_key_frames "expr:gte(t,n_forced*2)" \
-b:v:0 2000k -maxrate:v:0 3000k -bufsize:v:0 4000k \
-b:v:1 4500k -maxrate:v:1 6750k -bufsize:v:1 9000k \
-b:v:2 6000k -maxrate:v:2 9000k -bufsize:v:2 12000k \
-c:a aac -b:a 128k -ac 2 \
-f hls -hls_time 6 -hls_playlist_type vod -hls_flags independent_segments \
-var_stream_map "v:0,a:0,name:540p v:1,a:1,name:720p v:2,a:2,name:1080p" \
-master_pl_name master.m3u8 \
-hls_segment_filename "out/%v_%04d.ts" out/%v.m3u8
Any web server can then hand out the files over HTTPS. The port arithmetic is the one on our dedicated streaming server page: with a fifth of the port kept spare and every viewer on Apple's 4.5 Mbit/s 720p rung, about 177 viewers fit on 1 Gbps and about 1,777 on 10 Gbps; on the 6 Mbit/s 1080p rung, about 1,330 fit on 10 Gbps. The 11.25 Gbit/s replay peak above needs a 20 Gbps port on one machine, or several machines.
The two routes side by side
| Managed VOD library | Own origin on a dedicated server | |
|---|---|---|
| Renditions | The one MP4 you upload | Any ladder you encode |
| Codecs and size | H.264 up to 1080p60, AAC | Whatever your encoder and players support |
| Who encodes | You, before upload; no re-encoding | You, on the server or elsewhere |
| Delivery | Nearest of 5 cities | The one city the server is in |
| Transfer | Monthly allowance per plan | Unmetered port, sized by peak |
| Extras | Player and embed per file, 24/7 TV station, Samsung and LG app | What you install: player, key server, access rules |
| Your work | Audit and conform files, upload | Packaging, web server, TLS, updates, monitoring |
Where each route stops
- The library will not build a ladder from your file. A viewer on a weak mobile connection gets the rung you exported or nothing smooth; if a large share of your audience is on mobile data, export a lower bitrate or run route two. Apple's authoring spec asks for several bit rates (9.9), so a single-rendition library is a deliberate trade, not a full Apple ladder.
- 4K, HEVC, 10-bit and HDR masters, and anything above 60 fps, must be conformed to H.264 SDR at 1080p or below before they go into the library.
- A single origin serves every viewer from one city. Viewers on another continent see longer start times; several machines in our data centers or the library's five cities solve that.
- Lessons behind a login, with expiring links and encrypted segments, are a different job: see video hosting for online courses. For the live broadcast that produces tomorrow's replay, see live event streaming.
Questions
How much storage does an hour of on-demand video need?
Multiply the bitrate in kbit/s by 3,600 and divide by 8 for kilobytes per hour: 3,000 kbit/s is 1.35 GB an hour, 6,000 kbit/s is 2.7 GB. A ladder multiplies that by its rungs, because every rung stores the whole title. Our six-rung example adds up to about 7.5 GB per hour.
Does the VOD library convert my files into several bitrates?
No. The library does not re-encode: it checks each MP4 against its format and plays exactly what you uploaded. Pick one bitrate per title that suits your audience, or package a full ladder yourself on a dedicated server.
Which segment length should a VOD library use?
Apple's HLS authoring specification says target durations should be 6 seconds, every segment must start with an IDR frame, and key frames should come every 2 seconds. Static titles must be marked with the VOD playlist type. FFmpeg's HLS muxer sets these with hls_time 6 and hls_playlist_type vod.
Can I play archive files as a TV channel instead of on demand?
Yes, on any plan with a library. The same uploaded files can run as a 24/7 TV station scheduled from playlists, rotations and ad breaks, delivered like a live channel. Platinum also accepts VAST ads from an ad server.
When is my own server better than a managed library?
When you need several renditions, HEVC or 4K, your own key server or access rules, or traffic large enough that an unmetered port is the simpler bill. Budget for the work that comes with it: packaging, the web server, TLS and keeping it updated.