Skip to main content

Overview

HTTP Live Streaming (HLS) is an adaptive bitrate streaming protocol developed by Apple. Jellyfin generates dynamic HLS playlists and serves media segments for smooth, adaptive streaming across diverse network conditions and devices.

HLS Architecture

HLS streaming consists of:
  1. Master Playlist (.m3u8) - Lists available quality variants
  2. Media Playlists (.m3u8) - Lists segments for a specific quality
  3. Media Segments (.ts or .mp4) - Actual video/audio data chunks

Video HLS Endpoints

Get Master HLS Video Playlist

Retrieves the master playlist containing all available video stream variants.
GET /Videos/{itemId}/master.m3u8
Authentication: Required
itemId
string
required
The unique identifier of the video item
mediaSourceId
string
required
The media source identifier
deviceId
string
The device id of the client requesting
playSessionId
string
The play session identifier for tracking
segmentContainer
string
The segment container format:
  • ts - MPEG-TS (default, more compatible)
  • fmp4 - Fragmented MP4 (better compression, requires modern clients)
segmentLength
integer
The length of each segment in seconds (typically 3-10 seconds)
minSegments
integer
The minimum number of segments to generate before starting playback
videoCodec
string
Specify the video codec: h264, hevc, vp9, av1
audioCodec
string
Specify the audio codec: aac, mp3, opus, ac3
videoBitRate
integer
The video bitrate in bits per second
audioBitRate
integer
The audio bitrate in bits per second
maxWidth
integer
Maximum video width in pixels
maxHeight
integer
Maximum video height in pixels
enableAdaptiveBitrateStreaming
boolean
default:"false"
Enable adaptive bitrate streaming with multiple quality variants
enableTrickplay
boolean
default:"true"
Enable trickplay image playlists being added to master playlist for thumbnail previews
startTimeTicks
integer
Starting position in ticks
Playlist
string
M3U8 master playlist with available stream variants
Response Codes:
  • 200 OK - Master playlist returned
  • 401 Unauthorized - Authentication required
  • 404 Not Found - Item not found

Example Request

curl -X GET "https://your-jellyfin-server/Videos/12345678-1234-1234-1234-123456789abc/master.m3u8?mediaSourceId=12345678-1234-1234-1234-123456789abc&enableAdaptiveBitrateStreaming=true" \
  -H "Authorization: MediaBrowser Token=YOUR_API_KEY"

Example Response

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-STREAM-INF:BANDWIDTH=2400000,RESOLUTION=1280x720,CODECS="avc1.64001f,mp4a.40.2"
main.m3u8?videoBitRate=2000000&audioBitRate=192000&maxWidth=1280&maxHeight=720
#EXT-X-STREAM-INF:BANDWIDTH=5000000,RESOLUTION=1920x1080,CODECS="avc1.640028,mp4a.40.2"
main.m3u8?videoBitRate=4500000&audioBitRate=192000&maxWidth=1920&maxHeight=1080

Get Live HLS Video Stream

Generates a live HLS stream with on-demand transcoding.
GET /Videos/{itemId}/live.m3u8
Authentication: Required
itemId
string
required
The unique identifier of the video item
container
string
The output container format
mediaSourceId
string
The media source identifier
deviceId
string
The device id of the client
playSessionId
string
The play session identifier
segmentContainer
string
The segment container: ts or fmp4
segmentLength
integer
Length of each segment in seconds (default: 6)
minSegments
integer
Minimum number of segments before playback starts (default: 2)
videoCodec
string
Video codec to use
audioCodec
string
Audio codec to use
videoBitRate
integer
Video bitrate in bits per second
maxWidth
integer
Maximum width in pixels
maxHeight
integer
Maximum height in pixels
enableSubtitlesInManifest
boolean
default:"true"
Whether to include subtitle streams in the manifest
alwaysBurnInSubtitleWhenTranscoding
boolean
default:"false"
Whether to always burn in subtitles when transcoding
Playlist
string
M3U8 media playlist with segment URLs
Response Codes:
  • 200 OK - HLS live stream playlist returned
  • 401 Unauthorized - Authentication required

Example Request

curl -X GET "https://your-jellyfin-server/Videos/12345678-1234-1234-1234-123456789abc/live.m3u8?segmentContainer=ts&segmentLength=6&videoCodec=h264&audioCodec=aac" \
  -H "Authorization: MediaBrowser Token=YOUR_API_KEY"

Get Variant HLS Video Playlist

Retrieves a specific quality variant playlist.
GET /Videos/{itemId}/main.m3u8
Authentication: Required Parameters are similar to the live stream endpoint. This generates a media playlist for a specific quality level. Response Codes:
  • 200 OK - Variant playlist returned
  • 401 Unauthorized - Authentication required

Audio HLS Endpoints

Get Master HLS Audio Playlist

Retrieves the master playlist for audio streaming.
GET /Audio/{itemId}/master.m3u8
Authentication: Required
itemId
string
required
The unique identifier of the audio item
mediaSourceId
string
required
The media source identifier
deviceId
string
The device id of the client
playSessionId
string
The play session identifier
segmentContainer
string
The segment container format
segmentLength
integer
Length of each segment in seconds
audioCodec
string
Audio codec to use: aac, mp3, opus
audioBitRate
integer
Audio bitrate in bits per second
maxStreamingBitrate
integer
Maximum streaming bitrate
maxAudioChannels
integer
Maximum number of audio channels
enableAdaptiveBitrateStreaming
boolean
default:"false"
Enable adaptive bitrate streaming
Playlist
string
M3U8 master playlist for audio streaming
Response Codes:
  • 200 OK - Master playlist returned
  • 401 Unauthorized - Authentication required

Example Request

curl -X GET "https://your-jellyfin-server/Audio/12345678-1234-1234-1234-123456789abc/master.m3u8?mediaSourceId=12345678-1234-1234-1234-123456789abc&audioCodec=aac&audioBitRate=192000" \
  -H "Authorization: MediaBrowser Token=YOUR_API_KEY"

HLS Segment Endpoints

Get HLS Video Segment

Retrieves a specific video segment.
GET /Videos/{itemId}/hls/{playlistId}/{segmentId}.{segmentContainer}
itemId
string
required
The video item identifier
playlistId
string
required
The playlist identifier
segmentId
string
required
The segment identifier
segmentContainer
string
required
The segment container extension: ts or mp4
Response Codes:
  • 200 OK - Segment returned
  • 404 Not Found - Segment not found

Get HLS Audio Segment (Legacy)

Retrieves a specific audio segment.
GET /Audio/{itemId}/hls/{segmentId}/stream.{extension}
itemId
string
required
The audio item identifier
segmentId
string
required
The segment identifier
extension
string
required
The file extension: mp3 or aac
Response Codes:
  • 200 OK - Segment returned
  • 400 Bad Request - Invalid segment

Stopping Active Encoding

Stop Encoding Process

Stops an active encoding/transcoding process.
DELETE /Videos/ActiveEncodings
Authentication: Required
deviceId
string
required
The device id of the client
playSessionId
string
required
The play session identifier
Response Codes:
  • 204 No Content - Encoding stopped successfully
  • 401 Unauthorized - Authentication required

Example Request

curl -X DELETE "https://your-jellyfin-server/Videos/ActiveEncodings?deviceId=my-device&playSessionId=abc123def456" \
  -H "Authorization: MediaBrowser Token=YOUR_API_KEY"

HLS Best Practices

Segment Length

Recommended Values:
  • Low Latency: 2-3 seconds
  • Standard: 6 seconds (Jellyfin default)
  • High Efficiency: 10 seconds
Trade-offs:
  • Shorter segments: Lower latency, faster quality switching, higher overhead
  • Longer segments: Better compression, less overhead, slower adaptation

Segment Container

MPEG-TS (ts)
  • ✅ Maximum compatibility
  • ✅ Works with older devices
  • ❌ Less efficient compression
  • ❌ Larger file sizes
Fragmented MP4 (fmp4)
  • ✅ Better compression
  • ✅ Smaller file sizes
  • ✅ Supports more codecs (including FLAC)
  • ❌ Requires FFmpeg 7.0+ for certain features
  • ❌ May not work with older clients

Adaptive Bitrate Streaming

When enableAdaptiveBitrateStreaming=true, Jellyfin generates multiple quality variants:
#EXTM3U
#EXT-X-VERSION:3
# Low quality - mobile/poor connection
#EXT-X-STREAM-INF:BANDWIDTH=800000,RESOLUTION=640x360
main.m3u8?videoBitRate=600000&maxWidth=640&maxHeight=360

# Medium quality - standard broadband
#EXT-X-STREAM-INF:BANDWIDTH=2400000,RESOLUTION=1280x720
main.m3u8?videoBitRate=2000000&maxWidth=1280&maxHeight=720

# High quality - fast connection
#EXT-X-STREAM-INF:BANDWIDTH=5000000,RESOLUTION=1920x1080
main.m3u8?videoBitRate=4500000&maxWidth=1920&maxHeight=1080
The client automatically switches between variants based on available bandwidth.

Playlist Types

VOD (Video on Demand)
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:6.0,
segment0.ts
#EXTINF:6.0,
segment1.ts
#EXT-X-ENDLIST
Live/Event
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:42
#EXTINF:6.0,
segment42.ts
#EXTINF:6.0,
segment43.ts
# Playlist updates as new segments become available

Trickplay Thumbnails

When enableTrickplay=true, the master playlist includes thumbnail image playlists for seek previews:
#EXT-X-IMAGE-STREAM-INF:BANDWIDTH=50000,RESOLUTION=320x180,CODECS="jpeg"
trickplay/index.m3u8

Client Implementation Tips

  1. Segment Buffering: Buffer at least 3 segments ahead of playback position
  2. Quality Switching: Switch quality variants at segment boundaries
  3. Error Handling: Retry failed segments with exponential backoff
  4. Bandwidth Estimation: Track download speed to predict optimal quality
  5. Playlist Refresh: Refresh live playlists periodically (every target duration)

Server Configuration

Transcoding Path: Ensure adequate disk space in the transcoding directory for temporary segments Cleanup: Jellyfin automatically removes old segment files, but monitor disk usage during active streams Hardware Acceleration: Enable for better performance with multiple concurrent HLS streams