Use case · Video library

Video library hosting: encoding, storage and transfer for a catalogue

Video library hosting is three sums and one choice: gigabytes per hour of content times hours in the catalogue gives storage, hours watched times the delivered bitrate gives monthly transfer, peak viewers times that bitrate gives the port, and the choice is whether a managed library plays the files from several cities or a server of your own packages and serves them from one. This page works the sums for a back catalogue, an archive or a run of event replays, then sets the two routes side by side.

See VOD hosting

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 titleSum of bitratesGB per hour of contentHours in 200 GBHours in 2 TB
One 960x540 file at 2,000 kbit/s2,000 kbit/s0.90about 222about 2,222
One 1280x720 file at 3,000 kbit/s3,000 kbit/s1.35about 148about 1,481
One 1280x720 file at 4,500 kbit/s4,500 kbit/s2.03about 99about 988
Six-rung ladder: 365, 730, 2,000, 3,000, 4,500, 6,00016,595 kbit/s7.47about 27about 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 libraryOwn origin on a dedicated server
RenditionsThe one MP4 you uploadAny ladder you encode
Codecs and sizeH.264 up to 1080p60, AACWhatever your encoder and players support
Who encodesYou, before upload; no re-encodingYou, on the server or elsewhere
DeliveryNearest of 5 citiesThe one city the server is in
TransferMonthly allowance per planUnmetered port, sized by peak
ExtrasPlayer and embed per file, 24/7 TV station, Samsung and LG appWhat you install: player, key server, access rules
Your workAudit and conform files, uploadPackaging, 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.

Put the archive on five cities

Upload finished MP4 files, get a player and embed code for each, and serve them from the nearest city.

See VOD hosting

Related on Server Room

Other use cases