Warum Ihre Videovorschau beim Export lügt
Ihr Video-Editor sieht fertig aus. Die Vorschau ist gestochen scharf, die Beschriftung sitzt genau dort, wo der Benutzer sie hingezogen hat, und die Timeline lässt sich flüssig durchsuchen. Dann drückt der Benutzer auf Exportieren, und die Beschriftung erscheint an der falschen Stelle, in der falschen Größe, manchmal sogar ganz am Rand abgeschnitten. Nichts ist abgestürzt, es gibt keinen Fehler im Log – die Vorschau und die Datei stimmen einfach nicht überein.
Dies ist der häufigste Fehler in jedem Video-Editor, und es ist eher ein Datenmodellierungs- als ein Rendering-Problem. Im Folgenden erfahren Sie, welche eine Gewohnheit diesen Fehler unmöglich macht, wie man Frames anhand eines Aspect ratio korrekt dimensioniert und wie man das Ziehen auf günstigen Telefonen schnell hält. Die Ideen sind in jeder Sprache oder jedem UI-Framework anwendbar.
Aspect ratio ist eine Form, Resolution ist eine Größe
Die meisten Frame-Fehler beginnen hier. Ein Aspect ratio beschreibt die Form des Frames und nichts weiter: 9:16 ist hoch, 16:9 ist breit. Eine Resolution beschreibt die Größe in pixels, wie 1080x1920. Eine Form unterstützt viele Größen, daher sind die beiden Werte niemals austauschbar.
| Aspect ratio | Numerischer Wert | Typische Verwendung |
| 16:9 | 1.78 | YouTube, Querformat-Web |
| 9:16 | 0.56 | Reels, TikTok, Shorts |
| 1:1 | 1.00 | Quadratische Feed-Beiträge |
| 4:5 | 0.80 | Portrait-Feed-Beiträge |
Speichern Sie das Verhältnis als Klartext und konvertieren Sie es erst dann in eine Zahl, wenn Sie Berechnungen durchführen. Speichern Sie eine Zielhöhe für den Export, leiten Sie dann die Breite aus dem Verhältnis ab und erzwingen Sie, dass beide Zahlen gerade sind, bevor sie einen Encoder erreichen. Ungerade Dimensionen sind die stille Ursache für eine überraschende Anzahl fehlgeschlagener Exporte.
height = width / ratioToNumber(ratio) // sizing the preview box
function widthFromHeight(ratio, height): raw = height * ratioToNumber(ratio) return makeEven(round(raw)) // encoders require even sides
// 9:16 at 1080 tall -> 608 x 1080// 16:9 at 1080 tall -> 1920 x 1080
Positionen als Brüche speichern, niemals als Pixels
Ein Editor existiert in drei Welten mit drei verschiedenen Größen: dem gespeicherten Dokument, der On-Screen-Vorschau und der exportierten Datei. Das Dokument ist die einzige Quelle der Wahrheit – die anderen beiden sind lediglich Renderings davon in einem anderen Maßstab.
Project -> Clip (source, trim, filters) -> Overlay (text / sticker)
Document Preview renderer Export renderer x = 0.5, y = 0.9 --> x * 360 px --> x * 1080 px --> MP4 | ^ ^ +------------------------+------------------------+ one stored fraction, one formula, two sizes
Wenn Sie 540 pixels speichern, ist diese Zahl nur auf dem Gerät korrekt, auf dem sie gemessen wurde. Wenn Sie 0.5 speichern, bedeutet dies "die horizontale Mitte" bei jeder Größe für immer. Jede Position, jeder Offset und jede Skalierung im Modell sollte ein Bruch zwischen 0 und 1 sein.
type Overlay { x: number // 0.0-1.0 across (0.5 = centre) y: number // 0.0-1.0 down (0.9 = near bottom) scale: number // 1.0 = normal size rotation: number // degrees startTimeMs: number // when it appears endTimeMs: number // when it disappears}
Der Export wird dann fast langweilig, was der Sinn der Sache ist. Der Renderer verwendet dieselbe Formel wie die Vorschau mit einem größeren Multiplikator: px = overlay.x * exportWidth. FFmpeg handhabt den Frame selbst, und sein Zentrierungsausdruck (ow-iw)/2 ist dieselbe Arithmetik, die die Vorschau zum Letterboxing verwendet. Da der gespeicherte Wert sich nie geändert hat, landet die Beschriftung genau an der richtigen Stelle.
ffmpeg -i input.mp4 \ -vf "scale=1080:1920:force_original_aspect_ratio=decrease,\ pad=1080:1920:(ow-iw)/2:(oh-ih)/2:0xD3D3D3" \ -c:v libx264 -crf 23 -pix_fmt yuv420p -c:a aac output.mp4
Die Vorschau in einem einzigen Durchgang zeichnen
Messen Sie die Vorschau-Box zur Laufzeit, anstatt sie fest zu codieren, da ein Telefon, ein Tablet und ein in der Größe geändertes Desktop-Fenster alle unterschiedliche Größen liefern. Zeichnen Sie jedes Overlay in einem einzigen Canvas-Durchgang, anstatt jedes als separates UI-Element zu montieren – ein einziger Durchgang bleibt flüssig, während ein Finger bewegt wird.
Zwei Regeln halten die Schleife sauber. Überspringen Sie jedes Overlay außerhalb seines Zeitbereichs und paaren Sie immer save() mit restore(), damit ein Element seine Transformation nicht auf das nächste übertragen kann.
function drawPreview(canvas, overlays, currentTime, box): for each overlay in overlays: if currentTime < overlay.startTimeMs: skip if currentTime > overlay.endTimeMs: skip
px = overlay.x * box.width // the key formula py = overlay.y * box.height
canvas.save() canvas.move(px, py) canvas.rotate(overlay.rotation) canvas.resize(overlay.scale) canvas.drawText(overlay.content) canvas.restore() // never optional
Flüssiges Ziehen mit zweistufigem Zustand beibehalten
Ein ziehender Finger meldet ungefähr sechzig Positionen pro Sekunde. Wenn jede davon in Ihren Projektspeicher schreibt, zahlen Sie sechzig Mal pro Sekunde für Validierung, Persistenz und einen vollständigen Neuaufbau des Zustands, und das Ziehen stottert sichtbar. Teilen Sie die Arbeit stattdessen in zwei Stufen auf:
- Stufe 1, ephemer: eine kleine
liveDrag-Map, die die aktuelle Position des Fingers speichert. Aktualisieren Sie diese bei jeder Bewegung und zeichnen Sie den Canvas neu. Nichts anderes läuft. - Stufe 2, dauerhaft: Am Ende des Ziehvorgangs übergeben Sie den endgültigen Bruch an das Overlay im Projektmodell, löschen den
liveDrag-Eintrag und speichern einen Rückgängig-Schritt.
Der Vorteil geht über die Bildrate hinaus. Die Undo-Historie bleibt nützlich, da ein Ziehvorgang einen Eintrag statt Hunderte erzeugt, und die automatische Speicherung belastet die Festplatte nicht mehr so stark. So halten Figma und Canva die direkte Manipulation reaktionsschnell.
Praxisbezug
Bei MicrocosmWorks haben wir einen Kurzform-Editor übernommen, dessen Beschriftungen beim Export verrutschten. Das Team hatte die Overlay-Positionen als Geräte-pixels direkt vom Vorschaubildschirm gelesen, sodass eine auf einem kleinen Telefon erstellte Beschriftung in der 1080p-Datei hoch und klein erschien, und das Wechseln des Aspect ratio drängte einige Overlays ganz aus dem Frame.
Wir migrierten das Modell zu normalisierten 0-bis-1-Koordinaten, ließen beide Renderer einen einzigen Fraction-Times-Size-Helfer teilen und erzwangen gerade Ausgabedimensionen, die aus dem gespeicherten Verhältnis abgeleitet wurden. Vorschau und Export stimmten auf jedem Testgerät überein. Die Verlagerung der Drag-Commits auf Drag-Ende beseitigte die Verzögerung, die Benutzer auf Low-End-Android-Hardware gemeldet hatten. Die Art der Kurzform-Video- und Bearbeitungsarbeit, aus der dies hervorging, können Sie in unserem Projektportfolio sehen.
Fazit
Eine Vorschau und ein Export sind zwei Renderings eines Dokuments, geben Sie ihnen daher eine einzige Quelle der Wahrheit. Speichern Sie Positionen als Brüche, verwenden Sie dieselbe Formel für 'Bruch mal Größe' in beiden Renderern, leiten Sie die Breite aus dem Aspect ratio ab, halten Sie die Dimensionen gerade und committen Sie Zieh-Änderungen nur, wenn der Finger angehoben wird. Diese fünf Gewohnheiten eliminieren eine ganze Kategorie von Fehlern, bevor sie überhaupt entstehen.
Der Bau von Media-Engines, bei denen die interaktive Ansicht und die endgültige Datei übereinstimmen, ist ein Kernbereich unserer Video- und Streaming-Engineering-Arbeit bei MicrocosmWorks.
Sie versenden einen Video- oder Content-Editor und möchten, dass Vorschau und Export tatsächlich übereinstimmen? Wir haben genau diese Art von Fehler in Kurzform-Bearbeitungstools gelöst. Sprechen Sie mit unserem Engineering-Team →
Lesen Sie mehr von unserem Team
1. Optimierung des Kanallogos für verschiedene Videoauflösungen
2. Teller knipsen, Mahlzeit erfassen: Eine Computer-Vision Ernährungs-Pipeline
3. Optimierung des Kanallogos für verschiedene Videoauflösungen

