HLS for Dart

A robust, type-safe HLS (HTTP Live Streaming) library for Dart and Flutter. This library provides high-performance tools to Parse, Normalize, and Compose HLS playlists while maintaining strict compliance with RFC 8216.


🚀 Core Features

1. Universal Parsing

The library automatically detects whether a source is a Master or Media playlist. It handles URI resolution automatically if a baseUri is provided.

final manifest = await http.read(Uri.parse('https://example.com/video/master.m3u8'));

// Auto-detect and parse
final playlist = HlsParser.parse(manifest, baseUri: Uri.parse('https://example.com/video/'));

if (playlist is HlsMasterPlaylist) {
  print('Found ${playlist.variants.length} variants');
}

2. Advanced Normalization

Normalization solves the headache of relative paths and variable placeholders. It transforms a playlist into its "final" form where all URIs are absolute and variables are injected.

// Resolves relative URIs to absolute and replaces {$VARIABLE} placeholders
final cleanPlaylist = HlsComposer.normalize(playlist);

print(cleanPlaylist.variants.first.uri);
// Output: https://example.com/video/1080p/index.m3u8

3. Exact Composition

Convert your HlsPlaylist objects back into valid .m3u8 strings. The composer ensures that types, quotes, and attributes follow the spec perfectly—ideal for playlist proxies or manipulators.

final String m3u8String = HlsComposer.compose(updatedPlaylist);


🛠 Feature Deep-Dive

Media Playlist Management

Access granular data for VOD and Live streams, including initialization segments (#EXT-X-MAP) and encryption keys.

final media = playlist as HlsMediaPlaylist;

print('Target Duration: ${media.targetDuration}');
print('Is Live: ${media.isLive}'); // Computed: no ENDLIST and not VOD type

for (var segment in media.segments) {
  if (segment.key != null) {
    print('Segment is encrypted with ${segment.key!.method}');
  }
  print('URI: ${segment.uri}');
}

Master Playlist & Multi-Variant Support

Easily filter and select variants based on bandwidth, resolution, or codecs.

// Find the best quality variant
final bestVariant = master.variants.reduce((a, b) => a.bandwidth > b.bandwidth ? a : b);

// Access specific renditions (Audio/Subtitles)
final audioRenditions = master.renditions.where((r) => r.type == HlsMediaType.audio);

Immutability with copyWith

All models are immutable. To modify a playlist (e.g., adding a custom tag or changing the version), use the copyWith pattern.

final modified = mediaPlaylist.copyWith(
  version: 6,
  playlistType: 'VOD',
  hasEndTag: true,
);


📋 Supported Tags

Category Tags Supported
Playlist #EXT-X-VERSION, #EXT-X-TARGETDURATION, #EXT-X-MEDIA-SEQUENCE, #EXT-X-PLAYLIST-TYPE, #EXT-X-INDEPENDENT-SEGMENTS, #EXT-X-START
Master #EXT-X-STREAM-INF, #EXT-X-I-FRAME-STREAM-INF, #EXT-X-MEDIA, #EXT-X-SESSION-KEY, #EXT-X-DEFINE
Segments #EXTINF, #EXT-X-BYTERANGE, #EXT-X-DISCONTINUITY, #EXT-X-KEY, #EXT-X-MAP, #EXT-X-PROGRAM-DATE-TIME

💡 Why use this library?

  • Round-Trip Integrity: Parse a manifest, change one value, and compose it back—the structure remains intact.
  • Zero Dependencies: Lightweight and fast, utilizing core Dart libraries.
  • Error Handling: Throws descriptive HlsParserException or FormatException for invalid manifests rather than failing silently.

Libraries

hls