Mengapa Pratonton Video Anda Menipu Mengenai Eksport
Editor video anda kelihatan siap. Pratontonnya jelas, kapsyen berada tepat di tempat pengguna menyeretnya, dan garis masa bergerak lancar. Kemudian pengguna menekan Eksport, dan kapsyen kembali di tempat yang salah, dengan saiz yang salah, kadang-kadang terpotong sepenuhnya dari tepi. Tiada apa-apa yang ranap, tiada ralat dalam log — pratonton dan fail hanya tidak sepadan.
Ini adalah pepijat paling biasa dalam setiap editor video, dan ia adalah masalah pemodelan data berbanding masalah rendering. Di bawah ialah satu tabiat yang menjadikan pepijat ini mustahil berlaku, cara menentukan saiz frame dengan betul dari nisbah aspek, dan cara mengekalkan pergerakan seretan (dragging) yang pantas pada telefon murah. Idea-idea ini boleh digunakan dalam mana-mana bahasa atau UI framework.
Nisbah Aspek Adalah Bentuk, Resolusi Adalah Saiz
Kebanyakan pepijat frame bermula di sini. Nisbah aspek menerangkan bentuk frame dan tiada yang lain: 9:16 adalah tinggi, 16:9 adalah lebar. Resolusi menerangkan saiz dalam pixels, seperti 1080x1920. Satu bentuk menyokong banyak saiz, jadi kedua-dua nilai tidak boleh ditukar ganti.
| Nisbah aspek | Nilai berangka | Kegunaan biasa |
| 16:9 | 1.78 | YouTube, web landskap |
| 9:16 | 0.56 | Reels, TikTok, Shorts |
| 1:1 | 1.00 | Siaran suapan segi empat sama |
| 4:5 | 0.80 | Siaran suapan potret |
Simpan nisbah sebagai teks biasa dan tukarkannya kepada nombor hanya apabila anda melakukan pengiraan matematik. Simpan ketinggian sasaran untuk eksport, kemudian dapatkan lebar daripada nisbah, dan paksa kedua-dua nombor menjadi genap sebelum ia sampai ke encoder. Dimensi ganjil adalah punca senyap kepada bilangan eksport yang gagal yang mengejutkan.
height = width / ratioToNumber(ratio) // menentukan saiz kotak pratonton
function widthFromHeight(ratio, height): raw = height * ratioToNumber(ratio) return makeEven(round(raw)) // encoder memerlukan sisi genap
// 9:16 at 1080 tall -> 608 x 1080// 16:9 at 1080 tall -> 1920 x 1080
Simpan Kedudukan sebagai Pecahan, Jangan Sesekali Pixels
Sesuatu editor berfungsi dalam tiga dunia pada tiga saiz berbeza: dokumen yang disimpan, pratonton pada skrin, dan fail yang dieksport. Dokumen adalah satu-satunya sumber kebenaran — dua yang lain hanyalah rendering daripadanya pada skala yang berbeza.
Projek -> Klip (sumber, pangkas, penapis) -> Tindanan (teks / pelekat)
Dokumen Renderer pratonton Renderer eksport x = 0.5, y = 0.9 --> x * 360 px --> x * 1080 px --> MP4 | ^ ^ +------------------------+------------------------+ satu pecahan yang disimpan, satu formula, dua saiz
Jika anda menyimpan 540 pixels, nombor itu hanya betul pada peranti di mana ia diukur. Jika anda menyimpan 0.5, ia bermaksud "pusat mendatar" pada setiap saiz untuk selama-lamanya. Setiap kedudukan, offset dan skala dalam model haruslah pecahan antara 0 dan 1.
type Overlay { x: number // 0.0-1.0 melintang (0.5 = tengah) y: number // 0.0-1.0 ke bawah (0.9 = hampir bawah) scale: number // 1.0 = saiz normal rotation: number // darjah startTimeMs: number // bila ia muncul endTimeMs: number // bila ia hilang}
Eksport kemudian menjadi hampir membosankan, itulah intinya. Renderer menggunakan formula yang sama seperti pratonton dengan pengganda yang lebih besar: px = overlay.x * exportWidth. FFmpeg mengendalikan frame itu sendiri, dan ungkapan pemusatan (ow-iw)/2 adalah aritmetik yang sama digunakan oleh pratonton untuk letterbox. Kerana nilai yang disimpan tidak pernah berubah, kapsyen berada tepat di tempat yang betul.
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
Lukis Pratonton dalam Satu Laluan
Ukur kotak pratonton pada runtime dan bukannya hard-codingnya, kerana telefon, tablet, dan tetingkap desktop yang diubah saiz semuanya memberikan saiz yang berbeza. Lukis setiap overlay dalam satu laluan canvas dan bukannya memasang setiap satu sebagai elemen UI yang berasingan — satu laluan kekal lancar semasa jari bergerak.
Dua peraturan mengekalkan gelung (loop) ini jujur. Abaikan mana-mana overlay di luar julat masanya, dan sentiasa pasangkan save() dengan restore() supaya satu item tidak dapat membocorkan transformasinya ke item seterusnya.
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 // formula utama 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() // tidak pernah pilihan
Kekalkan Pergerakan Seretan Lancar dengan Keadaan Dua Peringkat
Jari yang menyeret melaporkan kira-kira enam puluh kedudukan sesaat. Jika setiap satu menulis ke stor projek anda, anda membayar untuk pengesahan (validation), ketekalan (persistence) dan pembinaan semula keadaan penuh enam puluh kali sesaat, dan pergerakan seretan tersangkut-sangkut. Bahagikan kerja kepada dua peringkat sebagai gantinya:
- Peringkat 1, fana (ephemeral): peta
liveDragkecil yang menyimpan kedudukan jari sekarang. Kemas kini pada setiap pergerakan dan cat semula canvas. Tiada yang lain berjalan. - Peringkat 2, kekal (durable): pada akhir seretan, komit pecahan akhir ke overlay dalam model projek, kosongkan entri
liveDrag, dan rekod satu langkah undo.
Manfaatnya melangkaui kadar frame. Sejarah undo kekal berguna kerana satu pergerakan seretan menghasilkan satu entri dan bukannya beratus-ratus, dan autosave berhenti membebani cakera. Beginilah cara Figma dan Canva mengekalkan manipulasi langsung responsif.
Konteks Dunia Nyata
Di MicrocosmWorks, kami mengambil alih editor video pendek yang kapsyennya beralih pada eksport. Pasukan tersebut telah mengekalkan kedudukan overlay sebagai pixels peranti yang dibaca terus dari canvas pratonton, jadi kapsyen yang dicipta pada telefon kecil kelihatan tinggi dan kecil dalam fail 1080p, dan menukar nisbah aspek menolak beberapa overlay keluar dari frame sepenuhnya.
Kami memindahkan model kepada koordinat 0-ke-1 yang normal, menjadikan kedua-dua renderer berkongsi satu pembantu fraction-times-size, dan menguatkuasakan dimensi output genap yang diperoleh daripada nisbah yang disimpan. Pratonton dan eksport sepadan pada setiap peranti ujian. Memindahkan komit seretan ke hujung seretan menghilangkan lag yang dilaporkan pengguna pada perkakasan Android hujung rendah. Anda boleh melihat jenis video pendek dan kerja penyuntingan yang terhasil daripada ini dalam portfolio projek kami.
Kesimpulan
Pratonton dan eksport adalah dua rendering dari satu dokumen, jadi berikan mereka satu sumber kebenaran. Simpan kedudukan sebagai pecahan, gunakan formula fraction-times-size yang sama dalam kedua-dua renderer, dapatkan lebar daripada nisbah aspek, pastikan dimensi genap, dan komit perubahan seretan hanya apabila jari diangkat. Lima tabiat ini menghilangkan keseluruhan kategori pepijat sebelum ia ditulis.
Membangunkan enjin media di mana pandangan interaktif dan fail akhir sepadan adalah tumpuan utama kerja kejuruteraan video dan streaming kami di MicrocosmWorks.
Menghantar editor video atau kandungan dan mahu pratonton dan eksport benar-benar sepadan? Kami telah menyelesaikan kelas pepijat yang tepat ini dalam alatan penyuntingan video pendek. Bercakap dengan pasukan kejuruteraan kami →
Baca lebih lanjut daripada pasukan kami
1. Mengoptimumkan Logo Saluran untuk Resolusi Video Berbeza
2. Ambil Gambar Pinggan, Rekod Hidangan: Saluran Paip Nutrisi Penglihatan Komputer

