atelier-socle/swift-hls-kit
Enterprise-grade pure Swift HLS library — parse, segment, transcode, encrypt, stream live with LL-HLS, MV-HEVC spatial video, IMSC1 subtitles & transport-aware ABR. Cross-platform, RFC 8216 compliant
Features
VOD
- Parse — Full HLS manifest parsing with typed models for master and media playlists, including Low-Latency HLS extensions
- Generate — Produce spec-compliant M3U8 output with imperative API and
@resultBuilderDSL - Validate — Check conformance against RFC 8216 and Apple HLS rules with 3 severity levels
- Segment (fMP4) — Split MP4 files into fragmented MP4 segments with init segment and auto-generated playlist
- Segment (MPEG-TS) — Split MP4 files into MPEG-TS segments for legacy compatibility
- Byte-range — Single-file byte-range segmentation mode
- Auto-transcode — Non-ISOBMFF files (MP3, WAV, FLAC) auto-transcoded to M4A before segmentation
- Transcode (Apple) — Hardware-accelerated encoding via Apple VideoToolbox
- Transcode (FFmpeg) — Cross-platform transcoding with quality presets and multi-variant output
- Cloud Transcode — Delegate to Cloudflare Stream, AWS MediaConvert, or Mux via
ManagedTranscoder - Encrypt (AES-128) — Full-segment AES-128-CBC encryption with key rotation
- Encrypt (SAMPLE-AES) — Sample-level encryption for video NAL units and audio ADTS frames
- Key management — Key generation, IV derivation (RFC 8216), key file I/O, and
EncryptedPlaylistBuilder - I-Frame playlists — Generate
EXT-X-I-FRAMES-ONLYplaylists for trick play and thumbnails - MP4 inspection — Container-level MP4 box reading, track analysis, and sample table parsing
Live Streaming & Advanced Features (0.6.0)
- Live Pipeline — End-to-end
LivePipelinefacade: input → encoding → segmentation → playlist → push - Live Encoding —
LiveEncoderprotocol withAudioEncoder(AAC),VideoEncoder(H.264/HEVC), FFmpeg-based encoders, andMultiBitrateEncoder - Live Segmentation — CMAF fMP4 segmentation with
AudioSegmenter,VideoSegmenter(H.264 + HEVC),CMAFWriter, and ring buffer - Live Playlists —
SlidingWindowPlaylist,DVRPlaylist,EventPlaylistwithPlaylistRenderer - LL-HLS — Low-Latency HLS with partial segments, blocking reload, delta updates, and server control
- Transport-Aware Push —
HTTPPusher,RTMPPusher,SRTPusher,IcecastPusherwith quality monitoring, ABR, and health dashboard - Timed metadata — ID3, SCTE-35, DateRange, HLS Interstitials injection
- Recording — Simultaneous recording with live-to-VOD conversion and auto chapter generation
- Spatial Audio — Dolby Atmos, AC-3/E-AC-3, multi-channel layouts (5.1, 7.1.4, JOC), Hi-Res audio
- HDR Video — HDR10, HLG, Dolby Vision with adaptive variant ladder generation
- Live DRM — FairPlay Streaming, key rotation, multi-DRM (CENC) interoperability
- Accessibility — CEA-608/708 closed captions, live WebVTT subtitles, audio descriptions
- Resilience — Redundant streams, failover, gap signaling (
EXT-X-GAP), content steering - Audio Processing — Format conversion, loudness metering (LUFS), silence detection, channel mixing, normalization
- Transport v2 Contracts —
QualityAwareTransport,AdaptiveBitrateTransport,RecordingTransportwith 10 RTMP presets, SRT FEC/bonding, Icecast auth modes - Variable Substitution —
EXT-X-DEFINEwith NAME/VALUE, IMPORT, and QUERYPARAM for CDN templating - IMSC1 Subtitles — W3C TTML parse, render, and fMP4 segment with
IMSC1Parser,IMSC1Renderer,IMSC1Segmenter - MV-HEVC Spatial Video — Stereoscopic packaging for Apple Vision Pro with
MVHEVCPackager, Dolby Vision Profile 8/20 - Video Projections —
REQ-VIDEO-LAYOUTwith 360°, 180°, Apple Immersive Video viaVideoLayoutDescriptor - Pipeline Presets —
podcastLive,radioLive,videoLive,videoSimulcast,spatialVideo,multiDRMLive, and more
Cross-Cutting
- CLI —
hlskit-clicommand-line tool with 10 commands for common HLS workflows - Strict concurrency — All public types are
Sendable, built with Swift 6.2 strict concurrency throughout - Zero dependencies — Core library has no third-party dependencies
Installation
Requirements
- Swift 6.2+ with strict concurrency
- Library platforms: macOS 14+, iOS 17+, tvOS 17+, watchOS 10+, visionOS 1+
- CLI platforms: macOS 14+, Linux
- Zero third-party dependencies in the core library (
swift-argument-parserfor CLI only)
Swift Package Manager
Add the dependency to your Package.swift:
dependencies: [
.package(url: "https://github.com/atelier-socle/swift-hls-kit.git", from: "0.6.0")
]Then add it to your target:
.target(
name: "YourTarget",
dependencies: ["HLSKit"]
)Quick Start — VOD
import HLSKit
let engine = HLSEngine()
// 1. Parse a manifest
let m3u8 = """
#EXTM3U
#EXT-X-VERSION:7
#EXT-X-STREAM-INF:BANDWIDTH=800000,RESOLUTION=640x360,CODECS="avc1.4d401e,mp4a.40.2"
360p/playlist.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2800000,RESOLUTION=1280x720,CODECS="avc1.4d401f,mp4a.40.2"
720p/playlist.m3u8
"""
let manifest = try engine.parse(m3u8)
// 2. Validate against RFC 8216
let report = engine.validate(manifest)
print("Valid: \(report.isValid)")
// 3. Segment an MP4 file
let config = SegmentationConfig(containerFormat: .fragmentedMP4, generatePlaylist: true)
let result = try engine.segment(data: mp4Data, config: config)
print("Segments: \(result.segmentCount), Duration: \(result.totalDuration)s")Quick Start — Live Streaming
import HLSKit
let audioConfig = CMAFWriter.AudioConfig(
sampleRate: 48000, channels: 2, profile: .lc
)
let segConfig = LiveSegmenterConfiguration(
targetDuration: 2.0,
keyframeAligned: false
)
let segmenter = AudioSegmenter(
audioConfig: audioConfig,
configuration: segConfig
)
// Ingest encoded frames from your capture pipeline
for frame in encodedFrames {
try await segmenter.ingest(frame)
}
let finalSegment = try await segmenter.finish()
// Collect emitted CMAF segments
for await segment in segmenter.segments {
print("Segment \(segment.index): \(segment.duration)s")
}Or use a pre-built pipeline preset:
let config = LivePipelineConfiguration.podcastLive
// config.audioBitrate == 128_000
// config.videoEnabled == falseQuick Start — Spatial Video
Build a manifest for Apple Vision Pro with MV-HEVC stereoscopic video and Dolby Vision:
import HLSKit
let playlist = MasterPlaylist(
version: .v7,
variants: [
Variant(
bandwidth: 15_000_000,
resolution: Resolution(width: 3840, height: 2160),
uri: "spatial/4k_dv.m3u8",
codecs: "hvc1.2.4.L153.B0",
videoRange: .pq,
supplementalCodecs: "dvh1.20.09/db4h",
videoLayoutDescriptor: .immersive180
),
Variant(
bandwidth: 4_000_000,
resolution: Resolution(width: 1920, height: 1080),
uri: "video/1080p_2d.m3u8",
codecs: "avc1.640028,mp4a.40.2"
)
],
independentSegments: true
)
let output = ManifestGenerator().generateMaster(playlist)
// Contains: SUPPLEMENTAL-CODECS="dvh1.20.09/db4h"
// Contains: REQ-VIDEO-LAYOUT="CH-STEREO,PROJ-HEQU"Quick Start — IMSC1 Subtitles
Parse a TTML file and segment it into fMP4 for HLS delivery:
import HLSKit
let xml = """
<tt xml:lang="en" xmlns="http://www.w3.org/ns/ttml">
<body><div>
<p begin="00:00:01.000" end="00:00:04.000">Hello world</p>
</div></body>
</tt>
"""
let document = try IMSC1Parser.parse(xml: xml)
let segmenter = IMSC1Segmenter()
let initSegment = segmenter.createInitSegment(language: "eng", timescale: 1000)
let mediaSegment = segmenter.createMediaSegment(
document: document, sequenceNumber: 1, baseDecodeTime: 0, duration: 6000
)Quick Start — Transport-Aware Pipeline
Monitor transport quality and adjust bitrate automatically:
import HLSKit
var config = LivePipelineConfiguration()
config.transportPolicy = TransportAwarePipelinePolicy(
autoAdjustBitrate: true,
minimumQualityGrade: .fair,
abrResponsiveness: .responsive
)
let pipeline = LivePipeline()
try await pipeline.start(configuration: config)
for await event in pipeline.events {
if case .transportQualityDegraded(let dest, let quality) = event {
print("\(dest) degraded: \(quality.grade)")
}
}Key Concepts
Parsing Manifests
let parser = ManifestParser()
let manifest = try parser.parse(m3u8String)
guard case .master(let playlist) = manifest else { return }
for variant in playlist.variants {
print("\(variant.resolution) — \(variant.bandwidth) bps")
}Generating Manifests
Build playlists with the @resultBuilder DSL:
let playlist = MasterPlaylist {
Variant(bandwidth: 800_000, resolution: .p480, uri: "480p/playlist.m3u8")
Variant(bandwidth: 2_800_000, resolution: .p720, uri: "720p/playlist.m3u8")
Variant(bandwidth: 5_000_000, resolution: .p1080, uri: "1080p/playlist.m3u8")
}
let m3u8 = ManifestGenerator().generateMaster(playlist)Or use the imperative API:
let playlist = MediaPlaylist(targetDuration: 6, playlistType: .vod, hasEndList: true, segments: [
Segment(duration: 6.006, uri: "segment000.ts"),
Segment(duration: 5.839, uri: "segment001.ts")
])
let m3u8 = ManifestGenerator().generateMedia(playlist)Validation
let report = HLSValidator().validate(playlist)
print("Errors: \(report.errors.count), Warnings: \(report.warnings.count)")Segmentation
let config = SegmentationConfig(
targetSegmentDuration: 6.0,
containerFormat: .fragmentedMP4,
generatePlaylist: true
)
let result = try MP4Segmenter().segment(data: mp4Data, config: config)
// result.initSegment, result.mediaSegments, result.playlistNon-ISOBMFF files (MP3, WAV, FLAC) can be segmented via auto-transcoding:
let result = try await engine.segmentToDirectory(
url: mp3URL,
outputDirectory: outputURL,
config: config
)Transcoding
let transcoder = AppleTranscoder()
let result = try await transcoder.transcode(
input: inputURL, outputDirectory: outputURL,
config: TranscodingConfig(), progress: { print("\($0 * 100)%") }
)Quality presets: .p360, .p480, .p720, .p1080, .p2160, .audioOnly
Cloud Transcoding
For server-side applications where local GPU or FFmpeg are not available, ManagedTranscoder delegates to cloud providers while conforming to the same Transcoder protocol. Upload and download stream data to/from disk without loading entire files into memory.
let config = ManagedTranscodingConfig(
provider: .cloudflareStream,
apiKey: "cf-api-token",
accountID: "cf-account-123"
)
let transcoder = ManagedTranscoder(config: config)
let result = try await transcoder.transcode(
input: inputURL, outputDirectory: outputDir,
config: TranscodingConfig(),
progress: { print("\($0 * 100)%") }
)| Provider | Authentication | Best For | |---|---|---| | Cloudflare Stream | API token (Bearer) | Zero egress costs, global CDN | | AWS MediaConvert | Access key + secret (SigV4) | Enterprise, existing AWS infra | | Mux | Token ID + secret (Basic Auth) | Simplest API, auto-adaptive bitrate |
Encryption
let key = try KeyManager().generateKey()
let iv = try KeyManager().generateIV()
let encrypted = try SegmentEncryptor().encrypt(segmentData: data, key: key, iv: iv)
let decrypted = try SegmentEncryptor().decrypt(segmentData: encrypted, key: key, iv: iv)Key rotation via EncryptedPlaylistBuilder:
let builder = EncryptedPlaylistBuilder()
let encrypted = builder.addEncryptionTags(
to: playlist,
config: encryptionConfig,
segmentCount: 10
)I-Frame Playlists
let generator = IFramePlaylistGenerator(
mediaPlaylist: mediaPlaylist,
inputDirectory: inputDir
)
let iframePlaylist = generator.generate()Architecture
Sources/
├── HLSKit/ # Core library (zero dependencies)
│ ├── Manifest/ # Models (MasterPlaylist, MediaPlaylist, Variant, Segment, ...)
│ ├── Parser/ # ManifestParser, TagParser, AttributeParser
│ ├── Generator/ # ManifestGenerator, TagWriter
│ ├── Builder/ # @resultBuilder DSL for playlists
│ ├── Validator/ # HLSValidator, RFC 8216 + Apple HLS rules
│ ├── Segmenter/ # MP4Segmenter, TSSegmenter
│ ├── Transcoder/ # AppleTranscoder, FFmpegTranscoder, ManagedTranscoder
│ ├── Encryption/ # SegmentEncryptor, SampleEncryptor, KeyManager, EncryptedPlaylistBuilder
│ ├── Container/ # MP4BoxReader, MP4InfoParser, BinaryReader/Writer
│ ├── Transport/ # TSSegmentBuilder, TSPacket, PES, ADTS/AnnexB
│ ├── IFrame/ # IFramePlaylistGenerator, IFrameStreamInfo
│ ├── Input/ # MediaSource, FileSource, AudioFormat, RawMediaBuffer
│ ├── Encoder/ # LiveEncoder, AudioEncoder, VideoEncoder, MultiBitrateEncoder
│ ├── LiveSegmenter/ # AudioSegmenter, VideoSegmenter, CMAFWriter, SegmentRingBuffer
│ ├── LivePlaylist/ # SlidingWindowPlaylist, DVRPlaylist, EventPlaylist, PlaylistRenderer
│ ├── LowLatency/ # LLHLSManager, PartialSegmentManager, BlockingPlaylistHandler
│ ├── Push/ # HTTPPusher, RTMPPusher, SRTPusher, IcecastPusher, MultiDestinationPusher
│ ├── Metadata/ # LiveMetadataInjector, DateRangeManager, SCTE35, ID3
│ ├── Recording/ # SimultaneousRecorder, LiveToVODConverter, AutoChapterGenerator
│ ├── Audio/ # AudioFormatConverter, LevelMeter, LoudnessMeter, SilenceDetector
│ ├── SpatialAudio/ # SpatialAudioConfig, DolbyAtmosEncoder, MultiChannelLayout
│ ├── HDR/ # HDRConfig, HDRVariantGenerator, DolbyVisionProfile
│ ├── DRM/ # LiveDRMPipeline, FairPlayLiveConfig, LiveKeyManager, CENCConfig
│ ├── Accessibility/ # AccessibilityRenditionGenerator, ClosedCaptionConfig, LiveWebVTTWriter
│ ├── Resilience/ # FailoverManager, RedundantStreamConfig, GapHandler, ContentSteering
│ ├── Subtitles/ # IMSC1Parser, IMSC1Renderer, IMSC1Segmenter
│ ├── Spatial/ # MVHEVCPackager, MVHEVCSampleProcessor, SpatialVideoConfiguration
│ ├── LivePipeline/ # LivePipeline, LivePipelineConfiguration, LivePipelineState
│ ├── Engine/ # HLSEngine facade
│ └── Documentation.docc/ # 33 DocC articles
├── HLSKitCommands/ # CLI command implementations
└── HLSKitCLI/ # CLI entry point (@main)CLI
Installation
swift build -c release
cp .build/release/hlskit-cli /usr/local/bin/Usage
# Inspect a file
hlskit-cli info video.mp4
hlskit-cli info playlist.m3u8 --output-format json
# Segment an MP4 (auto-transcodes MP3/WAV/FLAC)
hlskit-cli segment video.mp4 --output /tmp/hls/ --format fmp4 --duration 6
# Transcode to multiple variants
hlskit-cli transcode video.mp4 --presets 360p,720p,1080p
# Validate a playlist
hlskit-cli validate playlist.m3u8 --strict
# Encrypt segments
hlskit-cli encrypt /tmp/hls/ --key-url "https://cdn.example.com/key" --write-key
# Parse or generate manifests
hlskit-cli manifest parse playlist.m3u8
hlskit-cli manifest generate /tmp/hls/
# Generate I-Frame playlist
hlskit-cli iframe --input media.m3u8 --output iframe.m3u8
# Live streaming
hlskit-cli live start --config pipeline.json
hlskit-cli live stop
hlskit-cli live stats
hlskit-cli live convert-to-vod --input /tmp/live/ --output /tmp/vod/
hlskit-cli live metadata --key title --value "Episode 42"
# IMSC1 subtitles
hlskit-cli imsc1 parse subtitles.ttml
hlskit-cli imsc1 render subtitles.ttml --output rendered.ttml
hlskit-cli imsc1 segment subtitles.ttml --output /tmp/subs/ --language eng
# MV-HEVC spatial video
hlskit-cli mvhevc package input.hevc -o /tmp/spatial/ --layout stereo --width 3840 --height 2160
hlskit-cli mvhevc info init.mp4Commands
| Command | Description | |---------|-------------| | info | Inspect MP4 or M3U8 files (tracks, codec, duration, segments) | | segment | Split MP4 files into fMP4 or MPEG-TS segments (auto-transcodes non-ISOBMFF) | | transcode | Transcode media to one or more HLS quality variants | | validate | Validate M3U8 playlists against RFC 8216 and Apple HLS rules | | encrypt | Encrypt HLS segments with AES-128 or SAMPLE-AES | | manifest | Parse or generate M3U8 manifests (2 subcommands: parse, generate) | | iframe | Generate I-Frame playlists for trick play | | live | Live streaming pipeline (5 subcommands: start, stop, stats, convert-to-vod, metadata) | | imsc1 | IMSC1 subtitle pipeline (3 subcommands: parse, render, segment) | | mvhevc | MV-HEVC spatial video (2 subcommands: package, info) |
Test Suite
The project includes a comprehensive test suite using Swift Testing (import Testing):
| Category | Focus | |----------|-------| | Model | Type conformances, Codable round-trip, HLS models | | Parser | Master/media playlists, LL-HLS, byte-range, encryption tags | | Generator | M3U8 output, builder DSL, tag writing | | Validator | RFC 8216, Apple HLS rules, severity levels | | Segmenter | fMP4, MPEG-TS, byte-range, config, playlist generation | | Transcoder | Quality presets, Apple/FFmpeg/Managed availability, multi-variant | | Encryption | AES-128, SAMPLE-AES, key management, key rotation, round-trip | | Container | MP4 box reading, sample tables, init/media segment writing | | Transport | TS packets, PAT/PMT, PES, ADTS/AnnexB conversion | | I-Frame | Playlist generation, stream info, byte-range I-frames | | Input | MediaSource, FileSource, AudioFormat, buffer management | | Encoder | LiveEncoder, audio/video encoding, multi-bitrate | | LiveSegmenter | AudioSegmenter, VideoSegmenter, CMAFWriter, ring buffer | | LivePlaylist | Sliding window, DVR, event, renderer, sequence tracking | | LowLatency | LL-HLS manager, partial segments, blocking, delta updates | | Push | HTTP, RTMP, SRT, Icecast, multi-destination, bandwidth | | Metadata | ID3, SCTE-35, DateRange, interstitials | | Recording | Simultaneous recording, live-to-VOD, auto chapters | | Audio | Format conversion, loudness, silence, channel mixing | | SpatialAudio | Dolby Atmos, multi-channel, Hi-Res | | HDR | HDR10, HLG, Dolby Vision, ultra-resolution | | DRM | FairPlay, key rotation, CENC, multi-DRM | | Accessibility | Captions, subtitles, audio descriptions, renditions | | Resilience | Failover, redundancy, gap signaling, content steering | | LivePipeline | Pipeline lifecycle, presets, statistics, components | | Engine | HLSEngine facade, segmentation, encryption, manifest ops | | Showcase | Public API demonstrations (executable documentation) | | CLI | All 10 commands, argument parsing, integration | | EndToEnd | Cross-feature integration scenarios |
5,165 tests across 617 suites. All tests run on macOS in CI. No XCTest — 100% Swift Testing.
The project also includes Scripts/mock-hls-server.py (a Python-based test server with 5 modes) and Scripts/run-cli-scenarios.sh (an automated 38-scenario CLI regression runner).
Documentation
Full API documentation is available as a DocC catalog bundled with the package. Open the project in Xcode and select Product > Build Documentation to browse it locally.
The catalog includes 33 guides:
| Guide | Content | |-------|---------| | Getting Started | Installation, first workflow, builder DSL, live quick start | | Manifest Parsing | ManifestParser, TagParser, AttributeParser, error handling | | Manifest Generation | ManifestGenerator, TagWriter, builder DSL, LL-HLS models | | Validating Manifests | HLSValidator, rule sets, severity levels, reports | | Segmenting Media | MP4Segmenter, TSSegmenter, byte-range, auto-transcode | | Transcoding Media | Quality presets, Apple/FFmpeg transcoders, multi-variant, output codecs | | Cloud Transcoding | ManagedTranscoder, Cloudflare/AWS/Mux providers, streaming upload | | Encrypting Segments | AES-128, SAMPLE-AES, KeyManager, EncryptedPlaylistBuilder, key rotation | | HLSEngine | High-level facade for end-to-end workflows | | CLI Reference | 10 commands with options, examples, JSON config | | Live Streaming | Pipeline architecture overview and use cases | | Live Encoding | MediaSource, LiveEncoder, audio/video encoding, multi-bitrate | | Live Segmentation | AudioSegmenter, VideoSegmenter, CMAFWriter, CMAF fMP4 (H.264 + HEVC) | | Live Playlists | Sliding window, DVR, event playlists, renderer | | Low-Latency HLS | Partial segments, blocking reload, delta updates, server control | | Segment Pushing | HTTP, RTMP, SRT, Icecast, multi-destination push | | Live Metadata | ID3, SCTE-35, DateRange, HLS Interstitials | | Live Recording | Simultaneous recording, live-to-VOD, auto chapters | | I-Frame Playlists | IFramePlaylistGenerator, trick play, thumbnails | | Audio Processing | Format conversion, loudness metering, silence detection | | Spatial Audio | Dolby Atmos, multi-channel layouts, Hi-Res audio | | HDR Video | HDR10, HLG, Dolby Vision, ultra-resolution | | Live DRM | FairPlay Streaming, key rotation, multi-DRM (CENC) | | Accessibility & Resilience | Captions, subtitles, failover, gap signaling | | Live Presets | Pipeline presets and composition | | Transport Contracts v2 | Quality monitoring, ABR, RTMP/SRT/Icecast v2 | | Transport-Aware Pipeline | Pipeline integration with transport quality | | Variable Substitution | EXT-X-DEFINE, CDN templating, validation | | IMSC1 Subtitles Guide | TTML parse, render, fMP4 segment | | Spatial Video Guide | MV-HEVC packaging for Apple Vision Pro | | Video Projection Specifiers | REQ-VIDEO-LAYOUT, 360°, Apple Immersive | | Testing Guide | Test suite, mock server, CLI scenarios |
Specification References
- RFC 8216 — HTTP Live Streaming
- Apple HLS Authoring Specification
- Pantos HLS Draft
- ISO 14496-12 — ISO Base Media File Format
- ISO 13818-1 — MPEG-TS
Contributing
See CONTRIBUTING.md for guidelines on how to contribute.
License
This project is licensed under the Apache License 2.0.
Copyright 2026 Atelier Socle SAS. See NOTICE for details.
Package Metadata
Repository: atelier-socle/swift-hls-kit
Homepage: https://atelier-socle.com/en/solutions/swift-hls-kit
Stars: 5
Forks: 1
Open issues: 0
Default branch: main
Primary language: swift
License: Apache-2.0
Topics: cross-platform, generator, hls, http-live-streaming, ios, linux, m3u8, macos, manifest, parser, rfc8216, streaming, swift, swift-package-manager, validator, video
README: README.md