Untertitel mit Lua und FFmpeg in Videos einbrennen
Führen Sie FFmpeg mit Lua aus und brennen Sie eine vorhandene SRT-Datei in ein Video ein. Das folgende Skript erstellt eine MP4-Datei mit eingebrannten Untertiteln und kopiertem Audio. Mit einem generierten Testvideo prüfen Sie Text und Timing, bevor Sie eigene Dateien verwenden.
Eingebrannte Untertitel werden zu Videopixeln. Zuschauer können sie weder ausschalten noch eine andere Sprache wählen, und Screenreader können sie nicht als Textspur lesen. Bewahren Sie die SRT-Datei separat auf, wenn Ihr Player auswählbare Untertitel benötigt. Dieses Beispiel rendert bereitgestellten Text; es transkribiert oder übersetzt kein Audio.
Linux-Voraussetzungen prüfen
Verwenden Sie eine POSIX-Shell, /dev/fd, Lua 5.4 oder 5.5 sowie FFmpeg mit dem
Filter subtitles von libass und dem Encoder libx264.
Diese Anleitung richtet sich an Linux-Nutzer. Die folgenden Befehle installieren die Voraussetzungen
unter Ubuntu 24.04; andere Paket-Builds bieten möglicherweise andere FFmpeg-Funktionen.
Die Decodierungsprüfung nutzt außerdem mktemp,
cat und rm aus dem üblichen Linux-Paket coreutils.
Das Beispiel wurde mit Lua 5.4.6 und FFmpeg 6.1.1 von Ubuntu sowie mit Lua 5.5.1 und FFmpeg 9.0.1 getestet. Verwenden Sie gepflegte Pakete, statt eine alte Version zu installieren, nur um diese getesteten Versionen nachzubilden.
Installieren Sie Lua, FFmpeg und eine Schriftart mit den Zeichen aus diesem Beispiel:
sudo apt-get update && sudo apt-get install lua5.4 ffmpeg fonts-dejavu-core
Prüfen Sie die ausführbare Datei namens lua, bevor Sie Dateien erstellen.
Falls Ihre Distribution nur lua5.4 bereitstellt, verwenden Sie diesen Namen
bei jedem folgenden Lua-Aufruf. Die
Dokumentation zum Untertitelfilter von FFmpeg erläutert die
libass-Voraussetzung.
lua -v &&
ffmpeg -hide_banner -h filter=subtitles &&
ffmpeg -hide_banner -h encoder=libx264 &&
ffprobe -version &&
command -v mktemp && command -v cat && command -v rm
Brechen Sie ab, wenn der Filter oder Encoder unbekannt ist. Lua führt den Shell-Befehl aus; FFmpeg übernimmt Decodierung, Rendering und Encoding. Eine Lua-Medienbibliothek ist nicht nötig.
Video und zeitlich abgestimmte Untertitel erstellen
Arbeiten Sie in einem neuen privaten Verzeichnis ohne gleichzeitige Schreibzugriffe. Generieren Sie ein 8,25 Sekunden langes schwarzes Video mit einem 660 Hz-Testton und AAC-Audio. Die kleine Bildgröße und die begrenzte Zahl an Encoder-Threads halten den Ressourcenbedarf für diese Prüfung gering:
(
mkdir lua-subtitles-demo && cd lua-subtitles-demo &&
ffmpeg -nostdin -n -f lavfi -i 'color=c=black:s=640x360:r=24:d=8.25' \
-f lavfi -i 'sine=frequency=660:sample_rate=48000:duration=8.25' \
-c:v libx264 -threads 2 -pix_fmt yuv420p -c:a aac -shortest input.mp4
)
Wenn der Befehl erfolgreich ausgeführt wurde, wechseln Sie für die restlichen Schritte in das neue Verzeichnis:
cd lua-subtitles-demo
Speichern Sie Folgendes als subtitles.srt in UTF-8. SRT-Zeitstempel verwenden ein
Komma vor den Millisekunden; Leerzeilen trennen die Untertiteleinträge. Mit dem Wort mit Akzent
prüfen Sie, ob Schriftart und Zeichenkodierung zusammenpassen.
1
00:00:01,000 --> 00:00:02,000
Hello from Lua: café!
2
00:00:04,000 --> 00:00:05,000
The second subtitle.
Wenn die Einrichtung vorzeitig stoppt, behalten Sie die erstellten Dateien. Die FFmpeg-Option
-n lehnt eine vorhandene Datei input.mp4 ab.
Prüfen Sie diese vor einem erneuten Versuch oder beginnen Sie in einem anderen neuen Verzeichnis;
führen Sie den Befehl mkdir nicht erneut innerhalb des ersten Verzeichnisses aus.
Lua-Programm speichern und ausführen
Speichern Sie dies als add_subtitles.lua neben dem Video und der SRT-Datei.
Das Programm setzt Shell-Argumente in Anführungszeichen und übergibt die Untertiteldatei über
Dateideskriptor 3. So wird ihr Dateiname nie Teil der FFmpeg-Filtersyntax. Damit werden Leerzeichen,
Apostrophe, Doppelpunkte, Klammern und führende Bindestriche in lokalen Dateinamen korrekt behandelt.
#!/usr/bin/env lua
if #arg ~= 0 and #arg ~= 3 then
io.stderr:write("Usage: lua add_subtitles.lua <video.mp4> <subtitles.srt> <new-output.mp4>\n")
os.exit(1)
end
local video_file = arg[1] or "input.mp4"
local subtitles_file = arg[2] or "subtitles.srt"
local output_file = arg[3] or "output.mp4"
local existing = io.open(output_file, "rb")
if existing then
existing:close()
io.stderr:write("Output already exists; choose a new filename.\n")
os.exit(1)
end
local function shell_quote(value)
return "'" .. value:gsub("'", "'\\''") .. "'"
end
local function local_path(value)
if value:sub(1, 1) == "/" then return value end
return "./" .. value
end
local filter = "subtitles=/dev/fd/3"
local command = string.format(
"ffmpeg -nostdin -n -filter_threads 1 -i %s -vf %s -c:v libx264 -threads 2 -crf 23 -c:a copy %s 3<%s",
shell_quote(local_path(video_file)),
shell_quote(filter),
shell_quote(local_path(output_file)),
shell_quote(local_path(subtitles_file))
)
local success = os.execute(command)
if not success then
io.stderr:write("Subtitle conversion failed. Inspect any partial output before retrying.\n")
os.exit(1)
end
print("Subtitles added successfully.")
Führen Sie es mit dem Video, der Untertiteldatei und einem neuen Ausgabedateinamen in dieser Reihenfolge aus:
lua add_subtitles.lua input.mp4 subtitles.srt output.mp4
Nach Abschluss von FFmpeg gibt das Programm Folgendes aus:
Subtitles added successfully.
Das Programm meldet eine vorhandene Ausgabedatei als Fehler, und -n
weist FFmpeg an, sie nicht zu ersetzen. Es nutzt den
Status von Shell-Befehlen in Lua, um bei einem FFmpeg-Fehler keine
Erfolgsmeldung auszugeben. Dies ist keine transaktionale Veröffentlichung: Eine fehlgeschlagene
Konvertierung kann eine neue unvollständige Datei hinterlassen, und die Existenzprüfung koordiniert
keine gleichzeitigen Schreibzugriffe. Prüfen Sie jede unvollständige Ausgabe und wählen Sie vor
einem erneuten Versuch einen neuen Ausgabepfad.
Sichtbares Ergebnis und Audio prüfen
Öffnen Sie output.mp4 in Ihrem Videoplayer. Sie sollten den Ton durchgehend hören,
von 1 bis 2 Sekunden „Hello from Lua: café!“ und von 4 bis 5 Sekunden „The second subtitle.“ sehen.
Außerhalb dieser Zeiträume sollte der Hintergrund schwarz und ohne Text sein. Prüfen Sie neben dem
Timing auch den Akzent; erfolgreiches Encoding allein belegt keine lesbaren Untertitel.
Prüfen Sie die Streams und decodieren Sie die Ausgabe vollständig als zusätzliche Kontrolle:
ffprobe -v error -show_entries stream=codec_type,codec_name -of compact output.mp4 &&
(
decode_log=$(mktemp) || exit 1
trap 'rm -f "$decode_log"' EXIT
if ffmpeg -nostdin -v error -xerror -i output.mp4 -map 0:v:0 -map 0:a:0 -f null - \
2>"$decode_log" && [ ! -s "$decode_log" ]; then
printf 'Full decode finished without errors.\n'
else
cat "$decode_log" >&2
false
fi
)
Für das generierte Fixture sind H.264-Video, AAC-Audio und die Meldung „Full decode finished without
errors.“ zu erwarten. Die Subshell prüft sowohl die Fehlerausgabe von FFmpeg als auch dessen Status:
Einige Builds melden einen Decoderfehler und geben dennoch den Status null zurück. Sie entfernt ihr
temporäres Protokoll und lässt die aufrufende Shell unabhängig vom Ergebnis weiterlaufen.
Diese Prüfung bewertet weder Untertiteltext noch Timing; führen Sie weiterhin die Sichtprüfung
durch. Verwenden Sie für eigene Medien ein gültiges lokales Video und einen Audiocodec, den MP4
unterstützt, denn -c:a copy kopiert den ausgewählten Audiostream ohne Konvertierung.
Durch das Kopieren kann der Lua-Befehl auch dann abgeschlossen werden, wenn die Ausgabe noch ein beschädigtes Audiopaket enthält. Die vollständige Decodierung oben kann solche Schäden aufdecken, selbst wenn die Stream-Auflistung korrekt aussieht. Die Erfolgsmeldung allein ist keine Integritätsprüfung.
Untertitel verzögern oder eine Schriftart wählen
Um jeden Untertiteleintrag um 2,5 Sekunden zu verzögern, erstellen Sie eine separate SRT-Datei mit
verschobenen Zeitstempeln und übergeben sie an dasselbe Programm. Die
Option -itsoffset von FFmpeg addiert den Versatz
zu den Eingabezeitstempeln:
ffmpeg -nostdin -n -itsoffset 2.5 -i subtitles.srt -c:s srt shifted.srt &&
lua add_subtitles.lua input.mp4 shifted.srt delayed.mp4
In delayed.mp4 sollte der erste Untertiteleintrag von 3,5 bis 4,5 Sekunden und der
zweite von 6,5 bis 7,5 Sekunden erscheinen. Bei 1,5 Sekunden sollte kein Text zu sehen sein.
Öffnen Sie shifted.srt, um die geänderten Zeitstempel zu prüfen, falls das Ergebnis
noch dem ursprünglichen Timing folgt.
Für eine feste Schriftart und Schriftgröße ersetzen Sie im gespeicherten Programm nur die Variable
filter durch diese Zeile. DejaVu Sans muss installiert sein:
local filter = "subtitles=/dev/fd/3:force_style='FontName=DejaVu Sans,FontSize=24'"
Führen Sie das geänderte Programm mit einem neuen Ausgabedateinamen aus:
lua add_subtitles.lua input.mp4 subtitles.srt styled.mp4
Belassen Sie diese Stilzeichenfolge als festen Wert im Skript. Beliebige Filterausdrücke von Nutzern
benötigen eine eigene Validierung; Shell-Quoting validiert keine FFmpeg-Filtersyntax. FFmpeg
beschreibt die Einstellungen für force_style in der oben verlinkten Referenz zum
Untertitelfilter.
Eigene Dateien verwenden und Fehler diagnostizieren
Übergeben Sie Ihre eigenen Pfade als die drei Argumente. Die Originale bleiben Eingaben;
wählen Sie eine separate Ausgabe mit der Erweiterung .mp4.
Fehlende Dateien, eine ungültige SRT-Datei und Audio, das sich nicht in MP4 kopieren lässt,
sollten einen Exit-Status ungleich null auslösen. Lesen Sie vor einem erneuten Versuch die
Diagnosemeldung von FFmpeg. Dieser kleine Wrapper validiert nicht jedes Paket oder jeden
Untertiteleintrag; Decoder können beschädigte Medien wiederherstellen. Vergleichen Sie deshalb
das Ergebnis bis zum Ende der Aufnahme mit dem Original.
Wenn Zeichen mit Akzenten falsch dargestellt werden, prüfen Sie, ob die SRT-Datei UTF-8 verwendet und die gewählte Schriftart diese Zeichen enthält. Konvertieren Sie eine bekannte ältere Zeichenkodierung in eine separate Datei, statt die Quelldatei zu überschreiben:
iconv -f ISO-8859-1 -t UTF-8 legacy.srt > converted.srt
Verwenden Sie für diese Umleitung ein noch unbenutztes Ziel. Andernfalls kann sie eine Datei überschreiben, selbst wenn die Konvertierung fehlschlägt. Übergeben Sie nicht vertrauenswürdige Uploads nicht direkt an diesen lokalen Befehl: Führen Sie FFmpeg in einem isolierten Worker mit Beschränkungen für Dateisystem, Netzwerk, Arbeitsspeicher und Ausführungszeit aus. Shell-Quoting ist keine Sandbox für Medien.
