Videos mit Rust in HLS und MPEG-DASH konvertieren
Adaptives Streaming ist entscheidend, um hochwertige Videoinhalte unter unterschiedlichen Netzwerkbedingungen an verschiedene Geräte auszuliefern. Dieser DevTip zeigt, wie Sie Videos mit Rust und FFmpeg in die Formate HLS (HTTP Live Streaming) und MPEG-DASH (Dynamic Adaptive Streaming over HTTP) konvertieren.
Einführung in HLS und MPEG-DASH
HLS und MPEG-DASH sind verbreitete Protokolle für adaptives Streaming, die Videodateien in kleine Segmente aufteilen und mehrere Bitraten-Optionen bieten. Durch diese Segmentierung können Clients nahtlos auf die optimale Qualität wechseln, abhängig von den aktuellen Netzwerkbedingungen und den Fähigkeiten des Geräts.
Adaptives Streaming verstehen
Adaptives Streaming umfasst typischerweise:
- Das Video in mehreren Bitraten und Auflösungen codieren.
- Jede codierte Fassung in kurze Segmente aufteilen.
- Manifest-Dateien erzeugen, die die verfügbaren Streams und Segmente beschreiben.
- Clients ermöglichen, während der Wiedergabe automatisch die am besten geeignete Qualität auszuwählen.
Ein Rust-Projekt einrichten
Installieren Sie zunächst die erforderlichen System-Abhängigkeiten:
sudo apt-get update
sudo apt-get install ffmpeg
Erstellen Sie ein neues Rust-Projekt:
cargo new video_converter
cd video_converter
Fügen Sie diese Abhängigkeiten Ihrer Datei Cargo.toml hinzu:
[dependencies]
anyhow = "1.0.75"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
warp = "0.3.7"
FFmpeg in Rust integrieren
Diese Beispiele führen die ausführbare FFmpeg-Datei aus, daher werden weder FFmpeg-Entwicklungsheader
noch Rust-Bindings benötigt. Beginnen Sie die Datei src/main.rs mit einer Prüfung,
ob FFmpeg verfügbar ist:
use anyhow::Result;
use std::process::Command;
fn check_ffmpeg() -> Result<()> {
let status = Command::new("ffmpeg").arg("-version").status()?;
anyhow::ensure!(status.success(), "FFmpeg version check failed");
Ok(())
}
fn main() -> Result<()> {
check_ffmpeg()?;
Ok(())
}
Videokonvertierung in HLS und MPEG-DASH implementieren
Um Videos in HLS und MPEG-DASH zu konvertieren, rufen wir die Kommandozeilenwerkzeuge von FFmpeg
über das Modul Command von Rust auf. Dieser Ansatz nutzt die leistungsfähige
CLI von FFmpeg und hält den Rust-Code zugleich einfach. Verwenden Sie eine Eingabe mit einem
Videostream und einem Audiostream. Das DASH-Beispiel setzt ein 16:9-Video mit mindestens 1280×720
voraus. Jede Konvertierung benötigt ein neues Ausgabeverzeichnis, um eine frühere Konvertierung
nicht zu überschreiben; das übergeordnete Verzeichnis muss bereits vorhanden sein.
In HLS konvertieren
Verwenden Sie die folgende Funktion, um eine Videodatei in das HLS-Format zu konvertieren. Sie
erstellt das erforderliche Ausgabeverzeichnis und ruft FFmpeg mit Parametern auf, die auf die
HLS-Erzeugung zugeschnitten sind. Fügen Sie diese Funktion in der Datei
src/main.rs unterhalb der Importe ein. Dieses HLS-Beispiel erzeugt eine
Qualitätsstufe; seine Master-Playlist verweist auf eine separate Media-Playlist:
fn convert_to_hls(input: &str, output_dir: &str) -> Result<()> {
std::fs::create_dir(output_dir)?;
let output_path = format!("{}/index.m3u8", output_dir);
let status = Command::new("ffmpeg")
.args(&[
"-nostdin", "-n",
"-i", input,
"-map", "0:v:0", "-map", "0:a:0",
"-c:v", "libx264",
"-c:a", "aac",
"-profile:v", "main",
"-preset", "medium",
"-crf", "23",
"-sc_threshold", "0",
"-force_key_frames", "expr:gte(t,n_forced*4)",
"-hls_time", "4",
"-hls_playlist_type", "vod",
"-hls_segment_filename", &format!("{}/segment_%03d.ts", output_dir),
"-master_pl_name", "master.m3u8",
"-var_stream_map", "v:0,a:0",
"-f", "hls",
&output_path,
])
.status()?;
if !status.success() {
return Err(anyhow::anyhow!("FFmpeg process failed"));
}
Ok(())
}
In MPEG-DASH konvertieren
Analog konvertiert die folgende Funktion eine Videodatei in das MPEG-DASH-Format. Sie richtet die Segmentbenennung und die Manifest-Erzeugung passend für DASH-Streaming ein. Fügen Sie sie derselben Datei hinzu. Wenn der erste Videostream zweimal gemappt wird, entstehen zwei Video-Repräsentationen mit aufeinander abgestimmten Keyframes im Abstand von vier Sekunden:
fn convert_to_mpeg_dash(input: &str, output_dir: &str) -> Result<()> {
std::fs::create_dir(output_dir)?;
let output_path = format!("{}/manifest.mpd", output_dir);
let status = Command::new("ffmpeg")
.args(&[
"-nostdin", "-n",
"-i", input,
"-map", "0:v:0",
"-map", "0:v:0",
"-map", "0:a:0",
"-c:v", "libx264",
"-c:a", "aac",
"-b:v:0", "2M",
"-b:v:1", "1M",
"-s:v:1", "1280x720",
"-profile:v", "main",
"-sc_threshold", "0",
"-force_key_frames", "expr:gte(t,n_forced*4)",
"-seg_duration", "4",
"-use_template", "1",
"-use_timeline", "1",
"-init_seg_name", "init-$RepresentationID$.m4s",
"-media_seg_name", "chunk-$RepresentationID$-$Number%05d$.m4s",
"-adaptation_sets", "id=0,streams=v id=1,streams=a",
"-f", "dash",
&output_path,
])
.status()?;
if !status.success() {
return Err(anyhow::anyhow!("FFmpeg process failed"));
}
Ok(())
}
Eine fehlgeschlagene Konvertierung kann unvollständige Dateien in ihrem neuen Ausgabeverzeichnis hinterlassen. Versuchen Sie es mit einem frischen Verzeichnis erneut und liefern Sie die Dateien erst aus, nachdem beide Konvertierungen erfolgreich abgeschlossen sind.
Einen einfachen Streaming-Server in Rust bauen
Nachdem Sie Ihre Videos konvertiert haben, können Sie die HLS- oder MPEG-DASH-Inhalte über einen
einfachen HTTP-Server ausliefern, der mit dem Crate warp erstellt wurde.
Speichern Sie diese separate ausführbare Datei als src/bin/server.rs (legen Sie zuerst
src/bin an). Der Server weist Playlists und MPEG-TS-Segmenten die üblichen
Streaming-Content-Types zu und behält für andere Dateien den von Warp ermittelten Content-Type bei:
use warp::{Filter, Reply};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let cors = warp::cors()
.allow_any_origin()
.allow_methods(vec!["GET", "HEAD", "OPTIONS"]);
let routes = warp::fs::dir("./output")
.map(|file: warp::fs::File| {
let content_type = match file.path().extension().and_then(|ext| ext.to_str()) {
Some("m3u8") => "application/vnd.apple.mpegurl",
Some("mpd") => "application/dash+xml",
Some("ts") => "video/mp2t",
_ => return file.into_response(),
};
let mut response = file.into_response();
response.headers_mut().insert(
warp::http::header::CONTENT_TYPE,
warp::http::HeaderValue::from_static(content_type),
);
response
})
.with(cors);
println!("Starting server at http://127.0.0.1:3030/");
warp::serve(routes)
.run(([127, 0, 0, 1], 3030))
.await;
Ok(())
}
Das Streaming-Setup testen
So testen Sie Ihre Streaming-Lösung:
-
Ersetzen Sie
maininsrc/main.rsdurch Folgendes und behalten Sie die obigen Funktionen bei:fn main() -> Result<()> { check_ffmpeg()?; std::fs::create_dir_all("./output")?; convert_to_hls("input.mp4", "./output/hls")?; convert_to_mpeg_dash("input.mp4", "./output/dash")?; println!("Conversion complete."); Ok(()) } -
Führen Sie den Konverter einmal aus und starten Sie dann den Streaming-Server aus dem Projektverzeichnis:
cargo run --bin video_converter && cargo run --bin server -
Verwenden Sie einen kompatiblen Player, etwa VLC oder Web-Bibliotheken wie hls.js oder dash.js, um den Stream über folgende Adressen abzuspielen:
Fazit
Dieser DevTip hat gezeigt, wie Sie Videos mit Rust und FFmpeg in die Formate HLS und MPEG-DASH konvertieren. Wir haben die Erzeugung von Playlists und Manifest-Dateien sowie die Einrichtung eines einfachen Streaming-Servers für adaptives Streaming behandelt. Für eine robustere Lösung bieten sich folgende Erweiterungen an:
- Erweitern Sie das HLS-Beispiel mit einer einzelnen Qualitätsstufe um mehrere aufeinander abgestimmte Qualitätsstufen für adaptive Wiedergabe.
- Experimentieren Sie mit fortgeschrittenen FFmpeg-Einstellungen, um die Videoqualität zu optimieren.
- Ergänzen Sie Unterstützung für zusätzliche Funktionen wie mehrere Audiospuren und Untertitel.
- Sichern Sie Ihr Streaming-Setup mit HTTPS und tokenbasierter Authentifizierung ab.
Wenn Sie eine verwaltete Lösung für Video-Encoding und adaptives Streaming suchen, bietet Transloadit leistungsfähige Videoverarbeitungsfunktionen, die mit Ihren Anforderungen skalieren.
