Hvorfor din video-forhåndsvisning lyver om eksport
Din videoeditor ser færdig ud. Forhåndsvisningen er skarp, teksten sidder præcis der, hvor brugeren trak den hen, og tidslinjen skrubber jævnt. Men når brugeren trykker på Eksportér, dukker teksten op det forkerte sted, i den forkerte størrelse, nogle gange helt klippet af kanten. Intet gik ned, der er ingen fejl i loggen – forhåndsvisningen og filen er simpelthen uenige.
Dette er den mest almindelige fejl i enhver videoeditor, og det er et datamodelleringsproblem snarere end et renderingsproblem. Nedenfor er den ene vane, der gør fejlen umulig, hvordan man dimensionerer rammer korrekt ud fra et sideforhold, og hvordan man holder træk hurtigt på billige telefoner. Idéerne gælder i ethvert sprog eller UI framework.
Sideforhold er en form, opløsning er en størrelse
De fleste ramme-fejl starter her. Et sideforhold beskriver rammens form og intet andet: 9:16 er høj, 16:9 er bred. En opløsning beskriver størrelsen i pixels, som 1080x1920. Én form understøtter mange størrelser, så de to værdier er aldrig udskiftelige.
| Sideforhold | Numerisk værdi | Typisk anvendelse |
| 16:9 | 1.78 | YouTube, liggende web |
| 9:16 | 0.56 | Reels, TikTok, Shorts |
| 1:1 | 1.00 | Firkantede feed-opslag |
| 4:5 | 0.80 | Stående feed-opslag |
Gem sideforholdet som almindelig tekst, og konverter det kun til et tal, når du foretager beregninger. Gem en målhøjde for eksporten, og udled derefter bredden fra sideforholdet, og tving begge tal til at være lige, før de når en encoder. Ulige dimensioner er den stille årsag til et overraskende antal mislykkede eksporter.
height = width / ratioToNumber(ratio) // dimensionering af forhåndsvisningsboksen
function widthFromHeight(ratio, height): raw = height * ratioToNumber(ratio) return makeEven(round(raw)) // encodere kræver lige sider
// 9:16 ved 1080 høj -> 608 x 1080// 16:9 ved 1080 høj -> 1920 x 1080
Gem positioner som brøker, aldrig pixels
En editor lever i tre verdener med tre forskellige størrelser: det gemte dokument, forhåndsvisningen på skærmen og den eksporterede fil. Dokumentet er den eneste kilde til sandhed – de to andre er blot gengivelser af det i en anden skala.
Project -> Clip (kilde, trim, filtre) -> Overlay (tekst / klistermærke)
Dokument Forhåndsvisnings-renderer Eksport-renderer x = 0.5, y = 0.9 --> x * 360 px --> x * 1080 px --> MP4 | ^ ^ +------------------------+------------------------+ én gemt brøk, én formel, to størrelser
Hvis du gemmer 540 pixels, er det tal kun korrekt på den enhed, det blev målt på. Hvis du gemmer 0.5, betyder det "det horisontale center" i enhver størrelse for evigt. Hver position, offset og skala i modellen skal være en brøk mellem 0 og 1.
type Overlay { x: number // 0.0-1.0 på tværs (0.5 = center) y: number // 0.0-1.0 ned (0.9 = nær bunden) scale: number // 1.0 = normal størrelse rotation: number // grader startTimeMs: number // hvornår den vises endTimeMs: number // hvornår den forsvinder}
Eksport bliver derefter næsten kedelig, hvilket er hele pointen. Renderer'en bruger den samme formel som forhåndsvisningen med en større multiplikator: px = overlay.x * exportWidth. FFmpeg håndterer selve rammen, og dets centreringsudtryk (ow-iw)/2 er den samme aritmetik, som forhåndsvisningen bruger til letterbox. Fordi den gemte værdi aldrig ændrede sig, lander billedteksten præcis det rigtige sted.
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
Tegn forhåndsvisningen i et enkelt pass
Mål forhåndsvisningsboksen ved runtime i stedet for at hardcode den, da en phone, en tablet og et skrivebordsvindue med ændret størrelse alle giver dig en forskellig størrelse. Tegn hvert overlay i et enkelt canvas-pass i stedet for at montere hvert element som et separat UI-element – et enkelt pass forbliver flydende, mens en finger bevæger sig.
To regler holder løkken ærlig. Spring enhver overlay over, der er uden for dens tidsinterval, og par altid save() med restore(), så ét element ikke kan lække sin transformation til det næste.
function drawPreview(canvas, overlays, currentTime, box): for each overlay in overlays: if currentTime < overlay.startTimeMs: spring over if currentTime > overlay.endTimeMs: spring over
px = overlay.x * box.width // den centrale formel 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() // aldrig valgfrit
Hold træk jævnt med to-lags tilstand
En trækkende finger rapporterer cirka tres positioner per sekund. Hvis hver enkelt skriver til din projektlager, betaler du for validering, persistens og en fuld genopbygning af tilstanden tres gange i sekundet, og trækket hakker synligt. Opdel arbejdet i to lag i stedet:
- Lag 1, flygtigt: et lille
liveDragmap, der indeholder, hvor fingeren er lige nu. Opdater det ved hver bevægelse og genmal canvas. Intet andet kører. - Lag 2, holdbart: ved træk-slutning, commit den endelige brøk til overlayet i projektmodellen, ryd
liveDrag-posten, og registrer ét fortrydelsestrin.
Fordelen rækker ud over frame rate. Fortrydelses-historikken forbliver nyttig, fordi et træk producerer én post i stedet for hundredvis, og autosave stopper med at tærte disken. Dette er, hvordan Figma og Canva holder direkte manipulation responsiv.
Reel-verden kontekst
Hos MicrocosmWorks overtog vi en short-form editor, hvis tekster drev rundt ved eksport. Teamet havde gemt overlay-positioner som enheds-pixels aflæst direkte fra forhåndsvisnings-canvas, så en tekst, der blev lavet på en lille phone, endte højt og småt i 1080p-filen, og ændring af sideforhold skubbede nogle overlays helt ud af rammen.
Vi migrerede modellen til normaliserede 0-til-1 koordinater, fik begge renderere til at dele en enkelt brøk-gange-størrelse hjælpefunktion og tvang lige output-dimensioner udledt fra det gemte sideforhold. Forhåndsvisning og eksport matchede på enhver test-enhed. Flytning af træk-commits til træk-slutning fjernede den forsinkelse, brugere havde rapporteret på lavere-end Android-hardware. Du kan se den slags short-form video og redigeringsarbejde, dette kom fra, i vores projektportfolio.
Konklusion
En forhåndsvisning og en eksport er to gengivelser af ét dokument, så giv dem én kilde til sandhed. Gem positioner som brøker, brug den samme brøk-gange-størrelse formel i begge renderere, udled bredden fra sideforholdet, hold dimensionerne lige, og commit kun trækændringer, når fingeren løftes. Disse fem vaner fjerner en hel kategori af fejl, før den skrives.
Opbygning af medie-engines, hvor den interaktive visning og den endelige fil stemmer overens, er et kernefokus for vores video- og streaming engineering-arbejde hos MicrocosmWorks.
Sender du en video- eller indholdseditor og ønsker, at forhåndsvisning og eksport faktisk skal stemme overens? Vi har løst præcis denne klasse af fejl i short-form redigeringsværktøjer. Tal med vores ingeniørteam →
Læs mere fra vores team
1. Optimering af kanallogo til forskellige videoopløsninger
2. Tag et billede af en tallerken, log et måltid: En Computer-Vision Ernæringspipeline

