Video Preview'ınızın Export Hakkında Neden Yanıltıcı Olduğu
Video düzenleyiciniz bitmiş gibi görünüyor. Preview net, başlık kullanıcının sürüklediği yere tam oturuyor ve Timeline sorunsuz ilerliyor. Ardından kullanıcı Export'a basıyor ve başlık yanlış yerde, yanlış boyutta, bazen tamamen kenardan kesilmiş olarak geri geliyor. Hiçbir şey çökmedi, log'da hata yok – Preview ve dosya basitçe uyuşmuyor.
Bu, her video düzenleyicideki en yaygın bug'dır ve bir Rendering probleminden ziyade bir Data modeling sorunudur. Aşağıda, bu bug'ı imkansız hale getiren tek alışkanlık, bir Aspect ratio'dan karelerin doğru şekilde nasıl boyutlandırılacağı ve ucuz telefonlarda sürüklemeyi nasıl hızlı tutacağınız anlatılmaktadır. Bu fikirler her dilde veya UI framework'ünde geçerlidir.
Aspect Ratio Bir Şekil, Resolution Bir Boyuttur
Çoğu kare bug'ı burada başlar. Bir Aspect ratio, çerçevenin şeklini ve başka hiçbir şeyi tanımlar: 9:16 dikey, 16:9 yataydır. Bir Resolution, 1080x1920 gibi Pixel cinsinden boyutu tanımlar. Tek bir şekil birçok boyutu destekler, bu nedenle iki değer asla birbirinin yerine geçmez.
| Aspect ratio | Sayısal değer | Tipik kullanım |
| 16:9 | 1.78 | YouTube, landscape web |
| 9:16 | 0.56 | Reels, TikTok, Shorts |
| 1:1 | 1.00 | Kare akış gönderileri |
| 4:5 | 0.80 | Dikey akış gönderileri |
Ratio'yu düz metin olarak depolayın ve yalnızca matematik yaparken bir sayıya dönüştürün. Export için hedef bir Height depolayın, ardından Width'i Ratio'dan türetin ve her iki sayıyı da bir Encoder'a ulaşmadan önce çift sayı olmaya zorlayın. Tek boyutlar, şaşırtıcı sayıda başarısız Export'un sessiz nedenidir.
height = width / ratioToNumber(ratio) // Preview kutusunun boyutlandırılması
function widthFromHeight(ratio, height): raw = height * ratioToNumber(ratio) return makeEven(round(raw)) // Encoder'lar çift taraflar gerektirir
// 1080 uzunluğunda 9:16 -> 608 x 1080// 1080 uzunluğunda 16:9 -> 1920 x 1080
Pozisyonları Hiçbir Zaman Pixel Olarak Değil, Kesir Olarak Depolayın
Bir editör üç farklı boyutta üç ayrı dünyada yaşar: kaydedilmiş Document, ekran üzerindeki Preview ve Export edilmiş dosya. Document tek Source of truth'tur – diğer ikisi sadece farklı bir ölçekte onun Rendering'leridir.
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 | ^ ^ +------------------------+------------------------+ bir depolanmış kesir, bir formül, iki boyut
Eğer 540 Pixel depolarsanız, bu sayı yalnızca ölçüldüğü cihazda doğrudur. Eğer 0.5 depolarsanız, bu sonsuza dek her boyutta “yatay merkez” anlamına gelir. Modeldeki her Position, Offset ve Scale, 0 ile 1 arasında bir kesir olmalıdır.
type Overlay { x: number // Yatayda 0.0-1.0 (0.5 = merkez) y: number // Dikeyde 0.0-1.0 (0.9 = alta yakın) scale: number // 1.0 = normal boyut rotation: number // derece startTimeMs: number // ne zaman göründüğü endTimeMs: number // ne zaman kaybolduğu}
Export, o zaman neredeyse sıkıcı hale gelir, ki zaten amaç da budur. Renderer, Preview ile aynı formülü daha büyük bir çarpanla kullanır: px = overlay.x * exportWidth. FFmpeg, çerçevenin kendisini işler ve merkezleme ifadesi (ow-iw)/2, Preview'ın Letterbox yapmak için kullandığı aritmetik ile aynıdır. Depolanan değer hiç değişmediği için başlık tam doğru noktaya yerleşir.
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
Preview'ı Tek Bir Pass'ta Çizin
Preview kutusunu Hard-coding yerine Runtime'da ölçün, çünkü bir telefon, bir tablet ve yeniden boyutlandırılmış bir masaüstü penceresi size farklı boyutlar verecektir. Her Overlay'i ayrı bir UI element olarak bağlamak yerine tek bir Canvas pass'ında çizin — tek bir pass, parmak hareket ederken sorunsuz kalır.
İki kural döngüyü düzgün tutar. Zaman aralığının dışındaki herhangi bir Overlay'i atlayın ve save() ile restore()'u her zaman eşleştirin, böylece bir öğe Transform'unu bir sonraki öğeye sızdıramaz.
function drawPreview(canvas, overlays, currentTime, box): for each overlay in overlays: if currentTime < overlay.startTimeMs: atla if currentTime > overlay.endTimeMs: atla
px = overlay.x * box.width // ana formül 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() // asla isteğe bağlı değil
İki Katmanlı State ile Sürüklemeyi Pürüzsüz Tutun
Sürükleyen bir parmak saniyede yaklaşık altmış pozisyon bildirir. Her biri Project store'unuza yazarsa, saniyede altmış kez Validation, Persistence ve tam bir State rebuild için ödeme yaparsınız ve sürükleme gözle görülür şekilde takılır. Bunun yerine işi iki katmana bölün:
- Tier 1, ephemeral: parmağın şu an nerede olduğunu tutan küçük bir
liveDragMap'i. Her harekette güncelleyin ve Canvas'ı yeniden çizin. Başka hiçbir şey çalışmaz. - Tier 2, durable: sürükleme sonunda, son kesiri Project modelindeki Overlay'e kaydedin,
liveDraggirişini temizleyin ve bir Undo step'i kaydedin.
Bunun getirisi Frame rate'in ötesine geçer. Undo history, bir sürüklemenin yüzlerce yerine bir giriş üretmesi nedeniyle kullanışlı kalır ve Autosave diski yormayı durdurur. Figma ve Canva Direct manipulation'ı bu şekilde duyarlı tutar.
Gerçek Dünya Bağlamı
MicrocosmWorks'te, Export sırasında başlıkları kayan kısa biçimli bir editör devraldık. Ekip, Overlay pozisyonlarını doğrudan Preview Canvas'ından okunan cihaz Pixel'leri olarak kalıcı hale getirmişti, bu nedenle küçük bir telefonda oluşturulan bir başlık 1080p dosyada yüksek ve küçük kalıyor, ve Aspect ratio değiştirmek bazı Overlay'leri tamamen çerçeveden çıkarıyordu.
Modeli normalize edilmiş 0 ila 1 Coordinates'a taşıdık, her iki Renderer'ın tek bir fraction-times-size helper'ını paylaşmasını sağladık ve depolanan Ratio'dan türetilen çift çıktı boyutlarını zorunlu kıldık. Preview ve Export, her test cihazında eşleşti. Sürükleme kayıtlarını sürükleme sonuna taşımak, düşük seviyeli Android donanımında kullanıcıların bildirdiği Lag'ı ortadan kaldırdı. Bu tür kısa biçimli video ve düzenleme çalışmalarını Project portfolio'muzda görebilirsiniz.
Sonuç
Bir Preview ve bir Export, tek bir Document'ın iki Rendering'idir, bu yüzden onlara tek bir Source of truth verin. Pozisyonları kesir olarak depolayın, her iki Renderer'da aynı fraction-times-size formülünü kullanın, Width'i Aspect ratio'dan türetin, boyutları çift tutun ve sürükleme değişikliklerini yalnızca parmak kalktığında kaydedin. Bu beş alışkanlık, yazılmadan önce bütün bir bug kategorisini ortadan kaldırır.
Etkileşimli görünüm ile nihai dosyanın uyumlu olduğu Media engines inşa etmek, MicrocosmWorks'teki video ve Streaming engineering çalışmalarımızın temel odak noktasıdır.
Bir video veya içerik editörü yayınlıyor ve Preview ile Export'un gerçekten uyumlu olmasını mı istiyorsunuz? Bu tam olarak bu tür bir bug sınıfını kısa biçimli düzenleme araçlarında çözdük. Engineering team'imizle konuşun →
Ekibimizden daha fazlasını okuyun
1. Optimizing Channel Logo for Different Video Resolutions
2. Snap a Plate, Log a Meal: A Computer-Vision Nutrition Pipeline

