ASS-Erstellung / libass-Einbrennen - Praxis-Handbuch
1. Dateikopf-Vorlage (direkt übernehmen)
[Script Info]
ScriptType: v4.00+
PlayResX: 2560
PlayResY: 1080
WrapStyle: 2
ScaledBorderAndShadow: yes
YCbCr Matrix: TV.709
[V4+ Styles]
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
Style: X,Microsoft YaHei,100,&H00F4F1EA,&H00F4F1EA,&H00140F11,&HFF000000,0,0,0,0,100,100,0,0,1,0,0,5,30,30,30,1
[Events]
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
Dialogue: 0,0:00:00.39,0:00:03.75,X,,0,0,0,,{\an5\pos(500,300)\fnAnton\fs150\1c&H00F4F1EA&\bord3\3c&H00140F11&\frz-4\fscx118\fscy118\t(0,130,\fscx100\fscy100)\fad(100,100)}WALK
2. Vier fatale Formate-Fallen (alle in diesem Projekt erlebt)
- Zeitstempel müssen
H:MM:SS.ccsein- Richtig:
0:00:01.50,0:01:02.30 - Falsch:
0:01.50(libass meldetBad timestamp, ganze Zeile wird verworfen → kein Text im Video, aber ffmpeg gibt 0 zurück)
- Richtig:
- Style-Zeile Farben dürfen kein abschließendes
&haben- Richtig:
&H00F4F1EA,&H00F4F1EA,&H00140F11,&HFF000000 - Falsch:
&H00F4F1EA&,...→ Style-Zeile wird nicht erkannt → gleicher Effekt „kein Text“ - Inline-Farben im Ereignis müssen ein
&haben:\1c&H00F4F1EA&
- Richtig:
- Schriftartenverzeichnis
fontsdirmit relativem Pfad + Arbeitsverzeichnis- Lege
fonts/im Ausgabeverzeichnis an, wechsle dorthin (cd) und verwendeass=x.ass:fontsdir=fonts. - Absolute Pfade mit Laufwerksbuchstaben und Doppelpunkt sind in der Filtergraph anfällig; relative Pfade mit Chinesisch funktionieren (cwd kann Chinesisch sein, aber Filterparameter sollten möglichst ASCII sein).
- Lege
- ASS-Datei mit
utf-8-sigschreiben, ASCII-Dateiname- Chinesische Dateinamen in Filterparametern sind instabil; verwende z. B.
_s4.ass.
- Chinesische Dateinamen in Filterparametern sind instabil; verwende z. B.
Diagnosebefehl (siehe, was libass tatsächlich liest):
& $ff -hide_banner -v verbose -f lavfi -i "color=c=0x303040:s=2560x1080:r=30:d=2" `
-vf "ass=_s4.ass:fontsdir=fonts" -c:v libx264 -crf 22 -pix_fmt yuv420p _t.mp4 2>&1 | Select-String 'Bad timestamp|Style|font file'
3. Farben / Alpha-Semantik
- Farben:
&HBBGGRR&(Blau-Grün-Rot-Reihenfolge), z. B. Weiß&H00F4F1EA&, Tintenschwarz&H00140F11&, Pink&H00B35CFF&, Lavendel&H00FFA4C4&, Creme&H00D7EEF8&, Gold&H0054C9FF&. - Transparenz
\1a:&H00&= vollständig undurchsichtig;&HFF&= vollständig transparent (höherer Hex-Wert = transparenter). Der frühere Fehler beim Flackern war, dass Alpha umgekehrt war. - PrimaryColour der Style-Zeile ist
&HAABBGGRR(AA vorne, kein abschließendes&).
4. Schriftarten
- libass verwendet fontconfig/directwrite, der Familienname muss stimmen. Überprüfung mit PIL:
from PIL import ImageFont
ImageFont.truetype(r"...\fonts\Anton-Regular.ttf", 40).getname() # ('Anton','Regular')
- Schriftarten dieses Projekts: Anton / Archivo Black / Bebas Neue / Permanent Marker / Silkscreen / Rubik Glitch / Bungee / Monoton / Pirata One / UnifrakturCook; System Georgia, Microsoft YaHei direkt mit
\fnGeorgia,\fnMicrosoft YaHei. - Permanent Marker in libass ist tatsächlich ca. 0,79× fs – Schriftgröße / Farbblockgröße entsprechend vergrößern.
- Fehlende Glyphen (wie ♥ ★) werden automatisch auf ArialMT zurückgesetzt, sie sind sichtbar, aber die Form weicht ab; für Präzision
\fnMicrosoft YaHeiverwenden.
5. Animations-Tag-Referenz
| Tag | Verwendung |
|---|---|
\fad(ein,aus) | Millisekunden Ein-/Ausblenden |
\move(x1,y1,x2,y2,t1,t2) | Verschiebung (entweder \pos oder \move, \move hat Priorität) |
\t(t1,t2,\tag...) | Zeitliche Interpolation, z. B. \t(0,130,\fscx100\fscy100\blur(0)) |
\frz / \fscx / \fscy | Rotation / Skalierung (negative Werte für Spiegeln) |
\blur(n) | Weichzeichnen (effektiv für große Wörter: Unschärfe → Klarheit) |
\clip(x1,y1,x2,y2) | Rechteckiger Ausschnitt (für Slices, Lichteffekte, Einblendungen) |
\org(x,y) | Rotations-/Skalierungsmittelpunkt |
\p1 + Zeichnung | Rechteck m 0 0 l w 0 w h 0 h usw. |
Falle: Zwei aufeinanderfolgende \t für dasselbe Attribut werden ignoriert (z. B. bei einer schrumpfenden Linie); in zwei Ereignisse / zwei Durchläufe aufteilen.
Falle: \p1 Zeichnungskoordinaten sind oben links verankert, libass verschiebt das ganze Objekt zusätzlich um h/2 nach oben; \an7\pos(oben links) + absolute Koordinaten sind am stabilsten, Rotation/Scannen mit \org den Ursprung setzen.
Falle: Highlight-Textmarker soll hinter Wort „erscheinen“ – Zeichnungsebene mit \fscx0 → \t(0,150,\fscx100), Ursprung mit \org.
6. Render-Befehle
6.1 Direktes Einbrennen (häufigste Verwendung)
cd Ausgabeverzeichnis
& $ff -v error -y -i _base_30s.mp4 -vf "ass=_s4.ass:fontsdir=fonts" `
-c:v libx264 -preset medium -crf 16 -pix_fmt yuv420p -movflags +faststart OUT.mp4
30s / 2560×1080 / mit chinesischen Untertiteln ≈ 1–3 Minuten.
6.2 Transparente Überlagerung (für Schnittsoftware)
& $ff -v error -y -f lavfi -i "[email protected]:s=2560x1080:r=30,format=rgba" `
-vf "fps=30,ass=_sub.ass:alpha=1" -t 154.6 `
-c:v libvpx-vp9 -pix_fmt yuva420p -b:v 0 -crf 30 -row-mt 1 -auto-alt-ref 0 `
-metadata:s:v:0 alpha_mode=1 OUT_alpha.webm
- Der Decoder muss
-c:v libvpx-vp9sein; nativer vp9-Decoder verliert Alpha. - Kompatibilitätsfreundliche „Bildschirm-Überlagerung“ als mp4: Schwarzer Hintergrund + helle Buchstaben, in Schnittsoftware mit Screen/Lighten-Mischmodus.
6.3 Stichproben-Überprüfung (nicht auf Render-Logs schauen, Bild ansehen)
& $ff -v error -ss 12.4 -i OUT.mp4 -frames:v 1 -q:v 2 -y _check.jpg
Hinweis: Wenn
-ssvor-i(Input-Seek) steht, wird in manchen Fällen die ASS-Zeitachse relativ zur Ausgabe verschoben, die Vorschau ist leer. Für die Stichprobe Ausgabe-Seek (-i OUT.mp4 -ss 12.4) verwenden oder direkt einen gesamten Abschnitt rendern und dann Frame auswählen.
7. Fehlersuchtabelle
| Symptom | Ursache | Lösung |
|---|---|---|
| Ganzes Video ohne Text | Zeitstempel-Format / & am Ende von Style-Farbe | Ändere auf H:MM:SS.cc; Style-Farben ohne abschließendes & |
| Einige Sätze fehlen | Zeitstempel in diesem Satz falsch oder start>end | Satz für Satz prüfen |
| Schrift sehr klein / falsche Schriftart | Familienname falsch | Mit PIL getname() überprüfen |
\p1 Farbblock zu weit oben/unten | Zeichnungsanker + libass verschiebt um h/2 nach oben | \an7 + absolute Koordinaten oben links + Testframe zur Kalibrierung |
| Rotationszentrum falsch | Standardzentrum nicht gewünscht | \org(x,y) hinzufügen |
| Ausblenden funktioniert nicht / Flackern umgekehrt | Alpha-Semantik umgekehrt | &H00 = undurchsichtig, &HFF = transparent |
| 30s Rendering nur erste 4 Sätze | Schleife durchläuft nur die ersten Sätze | Überprüfe den Schleifenbereich der Ereigniserzeugung |
| Chinesischer Pfad/Dateiname schlägt fehl | Nicht-ASCII in Filterparametern | ASS und Quelle mit ASCII-Dateinamen + Chinesisches cwd |
8. Generator-Skelett (Python)
def ts(sec):
h=int(sec//3600); m=int(sec%3600//60)
return "%d:%02d:%05.2f" % (h,m,sec-h*3600-m*60)
class Ass:
def __init__(self,path,w=2560,h=1080): self.ev=[]; self.path=path; self.w=w; self.h=h
def add(self,layer,t0,t1,tags,text): self.ev.append((layer,t0,t1,tags,text))
def write(self):
head = open("template_header.ass",encoding="utf-8").read() # oder im Code inline
lines=[]
for layer,t0,t1,tags,text in sorted(self.ev,key=lambda e:(e[0],e[1])):
lines.append("Dialogue: %d,%s,%s,X,,0,0,0,,{%s}%s"%(layer,ts(t0),ts(t1),tags,text))
open(self.path,"w",encoding="utf-8-sig",newline="\n").write(head+"\n".join(lines)+"\n")
Referenzimplementationen: 字幕/build/styles_anim.py (S2/S4/S6), flare_wide.py, neon_wide.py, avoid_side2.py.