# HlsKit
**HlsKit** is a high-performance Rust library for transcoding MP4 videos into [HLS (HTTP Live Streaming)](https://developer.apple.com/streaming/) streams with adaptive bitrate support and multiple resolutions. It leverages `ffmpeg` under the hood and will soon support `gstreamer` as a pluggable backend.
Whether you're building a video streaming platform or need offline transcoding tools for video delivery, **HlsKit** provides an ergonomic, async-first API to handle the full conversion process: segmenting videos, creating resolution-specific playlists, and generating a master `.m3u8` playlist for adaptive streaming.
Wanna contribute? Check [CONTRIBUTING.md](./CONTRIBUTING.md)
---
## ๐ How It Works
```mermaid
flowchart TD
A[Input MP4 Bytes] --> B{For Each Resolution}
B -->|1080p| C1[Spawn ffmpeg Task]
B -->|720p| C2[Spawn ffmpeg Task]
B -->|480p| C3[Spawn ffmpeg Task]
C1 & C2 & C3 --> D[Generate .ts Segments & .m3u8 Playlists]
D --> E[Generate Master Playlist - master.m3u8 file]
E --> F[Return HlsVideo Struct]
```
---
## โจ Features
- โ
Convert MP4 videos to HLS format with multiple resolutions.
- โ
Adaptive bitrate support via master playlist.
- โ
Async-native using `tokio`.
- โ
Configurable CRF-based encoding and speed presets.
- ๐ Pluggable backends: GStreamer coming soon.
---
## ๐ Usage Example
```rust
use std::{env, fs::File, io::Read};
use hlskit::{
models::hls_video_processing_settings::{FfmpegVideoProcessingPreset, HlsVideoProcessingSettings},
process_video,
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut buf = Vec::new();
File::open("src/sample.mp4")?.read_to_end(&mut buf)?;
let result = process_video(
buf,
vec![
HlsVideoProcessingSettings {
resolution: (1920, 1080),
constant_rate_factor: 28,
preset: FfmpegVideoProcessingPreset::Fast,
},
HlsVideoProcessingSettings {
resolution: (1280, 720),
constant_rate_factor: 28,
preset: FfmpegVideoProcessingPreset::Fast,
},
HlsVideoProcessingSettings {
resolution: (854, 480),
constant_rate_factor: 28,
preset: FfmpegVideoProcessingPreset::Fast,
},
],
)
.await?;
println!("Master playlist:\n{}", String::from_utf8_lossy(&result.master_m3u8_data));
Ok(())
}
```
---
## ๐ Web Server Integration Example + S3 Upload
You can integrate **HlsKit** into an `axum` web server and upload results to Amazon S3:
```toml
# Cargo.toml
[dependencies]
hlskit = { git = "https://github.com/like-engels/hlskit-rs" }
axum = "0.7"
tokio = { version = "1", features = ["full"] }
aws-sdk-s3 = "0.30"
mime = "0.3"
uuid = { version = "1", features = ["v4"] }
```
```rust
use axum::{
extract::Multipart,
response::IntoResponse,
routing::post,
Router,
};
use aws_sdk_s3::Client as S3Client;
use hlskit::{
models::hls_video_processing_settings::{FfmpegVideoProcessingPreset, HlsVideoProcessingSettings},
process_video,
};
use std::net::SocketAddr;
use uuid::Uuid;
#[tokio::main]
async fn main() {
let app = Router::new().route("/upload", post(upload));
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
println!("Server running at http://{}", addr);
axum::Server::bind(&addr).serve(app.into_make_service()).await.unwrap();
}
async fn upload(mut multipart: Multipart) -> impl IntoResponse {
let mut video_bytes = Vec::new();
while let Some(field) = multipart.next_field().await.unwrap() {
if field.name() == Some("video") {
video_bytes = field.bytes().await.unwrap().to_vec();
break;
}
}
let profiles = vec![
HlsVideoProcessingSettings {
resolution: (1920, 1080),
constant_rate_factor: 28,
preset: FfmpegVideoProcessingPreset::Fast,
},
HlsVideoProcessingSettings {
resolution: (1280, 720),
constant_rate_factor: 28,
preset: FfmpegVideoProcessingPreset::Fast,
},
];
match process_video(video_bytes, profiles).await {
Ok(hls_video) => {
let s3 = S3Client::new(&aws_config::load_from_env().await);
let uuid = Uuid::new_v4().to_string();
let bucket = "my-hls-videos";
s3.put_object()
.bucket(bucket)
.key(format!("{}/master.m3u8", uuid))
.body(hls_video.master_m3u8_data.into())
.send()
.await
.unwrap();
for resolution in hls_video.resolutions {
s3.put_object()
.bucket(bucket)
.key(format!("{}/{}", uuid, resolution.playlist_name))
.body(resolution.playlist_data.into())
.send()
.await
.unwrap();
for segment in resolution.segments {
s3.put_object()
.bucket(bucket)
.key(format!("{}/{}", uuid, segment.segment_name))
.body(segment.segment_data.into())
.send()
.await
.unwrap();
}
}
format!("HLS stream uploaded to s3://{}/{}", bucket, uuid)
}
Err(e) => format!("Processing failed: {:?}", e),
}
}
```
> โ
Requires `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_REGION` to be set in the environment.
---
## ๐ฆ Installation
```toml
[dependencies]
hlskit = { git = "https://github.com/like-engels/hlskit-rs" }
```
---
## ๐ Requirements
- Rust 1.70+
- FFmpeg must be installed in your system and available in `$PATH`
---
## ๐ฃ๏ธ Roadmap
- ๐ GStreamer backend
- ๐ฆ Crates.io publish
- ๐งช Comprehensive test coverage
- ๐ก Custom audio profiles & watermarking
- ๐ Better documentation
---
## ๐ชช License
AGPL-3
---