なぜビデオプレビューがエクスポートについて嘘をつくのか
ビデオエディターは完成したように見えます。プレビューは鮮明で、キャプションはユーザーがドラッグした場所に正確に配置され、タイムラインはスムーズにスクラブします。しかし、ユーザーが「Export」を押すと、キャプションが間違った場所、間違ったサイズで表示され、時には端から完全に切り取られてしまうことがあります。クラッシュはせず、ログにもエラーはありません。プレビューとファイルが単に一致しないだけなのです。
これは、すべてのビデオエディターで最も一般的なバグであり、レンダリングの問題ではなくデータモデリングの問題です。以下に、このバグを不可能にする唯一の習慣、アスペクト比からフレームを正しくサイズ設定する方法、安価なスマートフォンでドラッグを高速に保つ方法について説明します。これらのアイデアは、あらゆる言語やUIフレームワークに適用できます。
アスペクト比は「形」、解像度は「サイズ」
ほとんどのフレームに関するバグはここから始まります。アスペクト比はフレームの「形」のみを記述します。例えば、9:16は縦長、16:9は横長です。解像度は1080x1920のようにピクセル単位の「サイズ」を記述します。一つの形は多くのサイズをサポートするため、これら二つの値は決して互換性がありません。
| アスペクト比 | 数値 | 一般的な用途 |
| 16:9 | 1.78 | YouTube、横向きのウェブ |
| 9:16 | 0.56 | Reels, TikTok, Shorts |
| 1:1 | 1.00 | スクエア型フィード投稿 |
| 4:5 | 0.80 | ポートレート型フィード投稿 |
比率はプレーンテキストとして保存し、計算を行うときにのみ数値に変換してください。エクスポート用の目標高さを保存し、その比率から幅を導出し、エンコーダーに渡す前に両方の数値を偶数になるように強制します。奇数サイズのディメンションは、驚くほど多くのエクスポート失敗の静かな原因となります。
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
位置は分数で保存し、ピクセルでは保存しない
エディターは、保存されたドキュメント、画面上のプレビュー、エクスポートされたファイルの3つの異なるサイズの世界で動作します。ドキュメントが唯一の信頼できる情報源であり、他の2つは異なるスケールでのレンダリングに過ぎません。
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
540ピクセルとして保存すると、その数値は測定されたデバイスでのみ正しいものとなります。0.5として保存すると、あらゆるサイズで常に「水平方向の中央」を意味します。モデル内のすべての位置、オフセット、スケールは0から1の間の分数であるべきです。
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}
そうなると、エクスポートはほとんどつまらない作業になりますが、それが重要な点です。レンダラーはプレビューと同じ式を、より大きな乗数(px = overlay.x * exportWidth)で使います。FFmpegがフレーム自体を処理し、そのセンタリング式(ow-iw)/2はプレビューがレターボックス処理に使用するのと同じ計算です。保存された値は決して変更されないため、キャプションは正確な場所に配置されます。
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
プレビューをシングルパスで描画する
電話、タブレット、サイズ変更されたデスクトップウィンドウではすべて異なるサイズになるため、プレビューボックスをハードコーディングするのではなく、実行時に測定してください。各オーバーレイを個別のUI要素としてマウントするのではなく、単一のキャンバスパスで描画します。これにより、指が動いている間もスムーズな状態を保てます。
2つのルールがループの整合性を保ちます。時間範囲外のオーバーレイはスキップし、save()とrestore()は常にペアで使用して、あるアイテムの変換が次のアイテムに漏れ出さないようにします。
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
2段階の状態管理でドラッグをスムーズに保つ
ドラッグ中の指は、毎秒およそ60回位置を報告します。もしその一つ一つがプロジェクトストアに書き込まれると、毎秒60回ものバリデーション、永続化、および完全な状態再構築のコストがかかり、ドラッグが目に見えて途切れてしまいます。代わりに、作業を2つの層に分割してください。
- ティア1、一時的: 指が現在どこにあるかを保持する小さな
liveDragマップ。すべての動きでこれを更新し、キャンバスを再描画します。他には何も実行しません。 - ティア2、永続的: ドラッグ終了時に、最終的な分数をプロジェクトモデルのオーバーレイにコミットし、
liveDragエントリをクリアし、1つのアンドゥステップを記録します。
この利点はフレームレートだけにとどまりません。ドラッグが数百のエントリではなく1つのエントリを生成するため、アンドゥ履歴は有用なままであり、自動保存によるディスクへの過度な負荷もなくなります。これがFigmaやCanvaがダイレクトマニピュレーションの応答性を保つ方法です。
現実世界での状況
MicrocosmWorksでは、エクスポート時にキャプションがずれるショートフォームエディターを扱いました。チームはオーバーレイの位置をプレビューキャンバスから直接読み取ったデバイスピクセルとして永続化していたため、小さな電話で作成されたキャプションは1080pファイルでは上部に小さく表示され、アスペクト比を切り替えると一部のオーバーレイがフレームから完全に押し出されていました。
私たちはモデルを正規化された0から1の座標に移行し、両方のレンダラーが単一の「分数×サイズ」ヘルパーを共有するようにし、保存された比率から導出される偶数の出力ディメンションを強制しました。プレビューとエクスポートはすべてのテストデバイスで一致しました。ドラッグコミットをドラッグ終了時に移動させることで、低スペックのAndroidハードウェアでユーザーが報告していた遅延が解消されました。このショートフォームビデオと編集作業の種類は、私たちのプロジェクトポートフォリオでご覧いただけます。
結論
プレビューとエクスポートは一つのドキュメントの二つのレンダリングであるため、それらには単一の信頼できる情報源を与えましょう。位置を分数として保存し、両方のレンダラーで同じ「分数×サイズ」の式を使用し、アスペクト比から幅を導出し、ディメンションを偶数に保ち、ドラッグの変更は指が離れたときのみコミットします。これらの5つの習慣は、バグが書き込まれる前にそのカテゴリ全体を排除します。
インタラクティブなビューと最終ファイルが一致するメディアエンジンを構築することは、MicrocosmWorksのビデオおよびストリーミングエンジニアリング作業の主要な焦点です。
ビデオまたはコンテンツエディターをリリースしていて、プレビューとエクスポートが実際に一致するようにしたいですか? 私たちは、ショートフォーム編集ツールでこの種のバグを正確に解決してきました。当社のエンジニアリングチームにご相談ください →

