HTTP Live Streaming (HLS) is an adaptive bitrate streaming protocol that delivers media as a series of segmented files over standard HTTP. It uses .m3u8 playlists to manage segment references and supports multiple bitrate renditions for dynamic client-side switching. Implementation involves segment creation, manifest configuration, and HTTP-based delivery using tools like FFmpeg and NGINX.
HLS Architecture Overview
HLS splits a continuous video stream into short .ts segments and generates an .m3u8 playlist (manifest) that references these chunks. The client downloads the manifest and fetches segments using standard HTTP GET requests. Bitrate adaptation occurs when multiple renditions (bitrates/resolutions) are specified in a master playlist.
Core Components
- Media Segments: .ts files (typically 4"6 seconds each)
- Media Playlist: .m3u8 file listing segments for a single bitrate
- Master Playlist: .m3u8 file referencing multiple media playlists with different bandwidths
Segmenting and Encoding with FFmpeg
FFmpeg can be used to generate HLS-compatible .ts segments and playlists from a source video.
ffmpeg -i input.mp4 -codec: copy -start_number 0 -hls_time 6 -hls_list_size 0 -f hls stream.m3u8This command creates a single-bitrate HLS stream without re-encoding. It splits the input into .ts segments, generates a media playlist, and names segments starting from 0.
Explanation:
- -codec: copy: Avoid re-encoding (faster but requires H.264/AAC input)
- -hls_time 6: Segment duration in seconds
- -hls_list_size 0: Include all segments in playlist (VOD use case)
- -start_number 0: Start segment numbering from 0
To encode and segment with transcoding:
ffmpeg -i input.mp4 -c:v libx264 -b:v 1500k -c:a aac -f hls -hls_time 6 -hls_segment_filename "segment_%03d.ts" stream.m3u8This version re-encodes video at 1500 kbps and saves segments as segment_000.ts, segment_001.ts, etc.
Multi-Bitrate Streaming (ABR)
Adaptive Bitrate Streaming (ABR) enables seamless switching between renditions depending on current network conditions. This is achieved by encoding the source into multiple versions and generating a separate .m3u8 playlist for each.
Generate renditions:
ffmpeg -i input.mp4 \
-map 0:v -s:v:0 1920x1080 -b:v:0 5000k \
-map 0:v -s:v:1 1280x720 -b:v:1 3000k \
-map 0:v -s:v:2 854x480 -b:v:2 1500k \
-map 0:a -c:a aac -b:a 128k \
-var_stream_map "v:0,a:0 v:1,a:0 v:2,a:0" \
-c:v libx264 -f hls -hls_time 6 -hls_segment_filename "v%v_segment_%03d.ts" -master_pl_name master.m3u8 v%v.m3u8
Explantation:
- master.m3u8: Contains stream info for v0.m3u8, v1.m3u8, v2.m3u8.
- v0_segment_000.ts, v1_segment_000.ts, etc.: Corresponding segments for each resolution.
- -var_stream_map: Maps each video and audio stream pair to a unique variant.
MIME Types and CORS Settings
HLS requires specific MIME types and CORS headers for correct behavior across different browsers and environments.
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
Enable CORS for cross-origin playback:
add_header Access-Control-Allow-Origin *;Improper MIME types will cause HLS playback to fail on some clients.
Live Streaming with HLS
Live HLS streaming requires segmenting the input stream in real time and updating the playlist dynamically to reflect the most recent segments. FFmpeg handles this by maintaining a sliding window of segments in the playlist and deleting older files to save storage.
ffmpeg -re -i input.mp4 -c:v libx264 -c:a aac -f hls \
-hls_time 4 -hls_list_size 5 -hls_flags delete_segments \
-hls_segment_filename live_%03d.ts live.m3u8
Explantation:
- -re: Read input at native frame rate (simulates live input)
- -hls_list_size: Limits number of entries in the playlist
- -hls_flags delete_segments: Deletes old segments after rotation
This configuration provides a moving window of recent segments for a continuous live feed.
Encryption (AES-128)
HLS supports AES-128 encryption for content protection. Encrypted segments can only be played if the key is accessible and valid.
Generate key and key file:
To enable AES-128 encryption in HLS, a 16-byte key must be generated and stored securely. This key will be used to encrypt each .ts segment. In addition, FFmpeg requires a key information file (.keyinfo) that specifies the public URL of the key, the local path to the key file, and the path to write the initialization vector (IV).
openssl rand 16 > enc.key
echo "https://yourdomain.com/hls/enc.key" > enc.keyinfo
echo "enc.key" >> enc.keyinfo
echo "iv" >> enc.keyinfo
This creates:
- enc.key: A binary 16-byte encryption key.
- enc.keyinfo: A 3-line file with a Public URL of the key, a local file path for FFmpeg to read the key, and a path to write the initialization vector.
Run FFmpeg with encryption enabled:
Once the key and .keyinfo file are ready, FFmpeg can be instructed to encrypt each segment during HLS generation. Use the -hls_key_info_file flag to pass the key information:
ffmpeg -i input.mp4 -hls_time 6 -hls_key_info_file enc.keyinfo \-hls_segment_filename secure_%03d.ts -f hls secure.m3u8Explantation:
- -hls_key_info_file: Instructs FFmpeg to use the key and IV paths defined in enc.keyinfo
- -hls_segment_filename secure_%03d.ts: Sets the naming pattern for encrypted segment files
- secure.m3u8: The output playlist will contain an #EXT-X-KEY tag pointing to the key URL
Latency Considerations
HLS introduces inherent delay due to segmenting. Factors impacting latency are segment duration (hls_time), playlist size (hls_list_size), player buffer size, and CDN edge cache TTL.
To reduce latency, you must use 2-second segments (-hls_time 2), lLimit playlist to 3"5 entries, use HTTP/2 with CDN support, and combine with LL-HLS extensions if supported by player and server.
Directory Structure and Deployment
A standard HLS deployment consists of the master playlist, media playlists, and segment files organized in a single directory. This structure can be served via a web server or CDN.
/hls/
"" → master.m3u8
"" → v0.m3u8
"" → v1.m3u8
"" → v2.m3u8
"" → v0_segment_000.ts
"" → v1_segment_000.ts
"" → v2_segment_000.ts
This directory should be served over HTTP by a CDN or static web server. No server-side session state is required. HLS clients (HTML5 video players, Apple TV, Safari, etc.) will request only the necessary playlists and segments.
Best Practices for HLS Deployment
- Use 2"6 second segments for a balance of latency and efficiency.
- Align keyframes with segment boundaries for smooth playback and ABR.
- Always test streams on multiple devices and players (Safari, hls.js, etc.).
- Monitor CDN and server logs for segment delivery issues.
- Secure encryption keys and playlists with HTTPS and proper access controls.

