[Astro] #178 ブラウザだけで動く動画エディタ — 1.4GB・27分の動画を、アップロードなしで切って書き出す

[Astro] #178 ブラウザだけで動く動画エディタ — 1.4GB・27分の動画を、アップロードなしで切って書き出す

はじめに

前回は、監視室のモニタ壁で、MSX・動画・SID を動かしました。

今回は、ブラウザの中だけで動く、動画エディタです。

ブログに貼る動画を、サッと切って、つないで、書き出したい。それだけのために、毎回、重いソフトを開くのが面倒でした。そこで、ブラウザだけで完結する物を作りました。動画のファイルは、サーバーに送られません。

画面は、できるだけシンプルにしています。ふだんは「素材を入れる → 切る → 書き出す」だけで足ります。細かい機能は、右の欄の折りたたみに入れました。困ったときは、F1 キーで、「やりたいこと → やり方」を検索できます。

画面

全体

左に素材と追加ボタン、中央にプレビューとタイムライン、右にクリップの設定、という並び。

動画エディタの全体。左に素材、中央にプレビューとタイムライン、右にクリップの設定

1.4 GB の動画を読み込み。

動画エディタの全体。左に素材、中央にプレビューとタイムライン、右にクリップの設定

Steamの「Subsistence」の録画動画。

書き出し

書き出しの画面。用途のプリセットと、完了の結果

用途のプリセットを選んで、「書き出す」を押すだけです。いちばん上の「ブログ用」は、MP4・720p・30fps で、軽くて、どこでも再生できます。

F1 ヘルプ

F1 のヘルプ。やりたいことで検索できる F1 のヘルプ。やりたいことで検索できる

「ぼかしたい」「縦動画にしたい」のように、やりたいことで探せます。

作ったもの

編集

  • 分割、削除、詰めて削除、前後を削除、トリム(端をドラッグ)、複製、コピー、貼り付け
  • クリップの種類は、動画、音声、画像、文字、字幕、色の背景、図形、ぼかし/モザイクです
  • トラックは、文字、字幕、V2、V1、A1、A2 です。ロック、非表示、ミュートができます
  • 映像と音声は、リンクで連動します。Alt を押しながら操作すると、片方だけ動かせます
  • 位置、大きさ、回転、不透明度、反転、切り抜き、フィルタ、クロマキー、ズームや移動の動き
  • 切り替えは、フェード、ワイプ、スライド、ズーム、ぼかし、回転です
  • 速度は 0.25 倍から 8 倍まで。音の高さも変わります
  • 音声は、音量、フェード、ノーマライズ、無音カットなどです
  • 字幕は、一覧で編集できて、SRT と VTT の読み込みと書き出しに対応しています
  • 画面録画、カメラ、マイクの録音もできます

書き出し

種類内容
再エンコードMP4 / WebM / MKV / MOV。使えるコーデックに自動で切り替えます
無劣化カット再エンコードせずに、切るだけ。速くて、画質が落ちません
音声のみM4A / WAV / OGG
GIF自前のエンコーダで作ります
静止画・字幕その瞬間を PNG / JPG、字幕を SRT / VTT

Chrome と Edge では、保存先を選ぶと、ファイルへ直接書き込みます。それ以外のブラウザでは、メモリの上で作ってから、ダウンロードします。

自動保存

編集内容は、ブラウザの IndexedDB に自動で保存されます。ページを読み込み直すと、「続きから再開」と出ます。動画のファイルそのものは保存しません。素材が見つからないときは、同じファイルを入れ直すと、自動でつながります。

F1 のヘルプ。やりたいことで検索できる

作り方

ライブラリは Mediabunny

最初に、ffmpeg.wasm か、WebCodecs を使うか、で迷いました。

ffmpeg.wasm は、できることが多いのですが、1GB を超える動画では、メモリが厳しくなります。動きも重いです。

そこで、WebCodecs を使う、Mediabunny を選びました。ブラウザのデコーダとエンコーダを、そのまま使えます。動画の Blob から、必要な部分だけを読めるので、大きなファイルでも、全部をメモリに載せずに済みます。

代わりに、できることは、ブラウザの WebCodecs が対応しているコーデックまでです。H.264 や AAC が使えるかは、環境によって違います。使えないときは、VP9 や Opus などに、自動で切り替えて、結果の画面に注意を出します。

Mediabunny は、CDN を使わず、自分のサイトに置いて読み込んでいます。

1 つの描画関数

プレビューも、書き出しも、GIF も、同じ 1 つの関数で、1 フレームを描いています。2D キャンバスに、下のトラックから順番に重ねていきます。変形、切り抜き、フィルタ、切り替え、文字などが、全部この中です。

こうしておくと、プレビューで見た絵と、書き出した絵が、同じになります。

音

プレビューの再生は、AudioContext の時計を、マスターにしています。映像の側が、その時計に合わせます。

書き出しの音は、OfflineAudioContext で、5 秒ずつ作ります。音量、フェード、エフェクトの部分は、プレビューと書き出しで、同じ処理を使っています。

重なったときの扱い

クリップを同じトラックに落として、重なったときは、間に挿入して、後ろを右へ押し出します。Alt を押しながら落とすと、そのまま重ねられます。文字、字幕、図形、ぼかしは、最初から、自由に重ねられます。

無劣化カット

素材が 1 本で、拡大縮小もフィルタも文字も使っていないときだけ、再エンコードをせずに、パケットをそのままコピーします。切れ目は、直前のキーフレームに合います。

実機で確認できたこと

  • 1.4GB・約 25 分の動画の読み込みは、問題ありませんでした
  • 27 分 18 秒の動画を、「ブログ用」で、そのまま書き出して、94.8 秒で終わりました。約 17 倍の速さです。結果は、AVC + AAC の 430.9MB で、書き出し前の目安(424.9MB)とほぼ同じでした
27 分 18 秒の動画を、「ブログ用」で、そのまま書き出して、94.8 秒
  • タスクマネージャーでは、GPU の Video Decode と Video Encode が動いていました。エンコーダは、ブラウザが自動で選んだ物です
タスクマネージャー // GPU  Video Decode /  Video Encode タスクマネージャー // GPU  Video Decode /  Video Encode
  • 日本語のファイル名で、保存できました
  • ページを読み込み直したあとの、自動保存からの復元が、動きました
  • 切って、つないだ動画の書き出しも、動きました

環境は、Windows 11、Chrome、Core i7-12700K、RTX 4070 Ti です。

詰まったこと

書き出しで、fastStart のエラー

最初の実機チェックで、書き出しが失敗しました。

options.fastStart, when provided, must be false, "in-memory", or "fragmented".
書き出しで、fastStart のエラー

MP4 は、ふつう、再生に必要な情報が、ファイルの最後に入ります。ブログに貼る用途だと、先頭に置いたほうが、再生が早く始まります。そこで、ファイルへ直接書き込むときは、fastStart: 'reserve'(先頭に場所を確保しておく方式)を使っていました。

ところが、実機で読み込まれた mediabunny.min.mjs が、'reserve' に対応していない、古い版でした。私の環境では、新しい版を使っていたので、気づけませんでした。

直し方は、次のとおりです。

  • 起動時に、new Mp4OutputFormat({ fastStart: 'reserve' }) が通るか、試す
  • 通らなければ、'in-memory' に切り替える

古い版でも、書き出しは、できるようになりました。ただ、大きなファイルでは、メモリを多く使います。

日本語のファイル名で、テスト環境が落ちた

自分の環境の検証では、「無題.mp4」のような、日本語のファイル名を保存先に渡すと、ブラウザごと落ちることがありました。ただ、これは、古い Chromium を使った、テスト環境の問題でした。実機の Chrome では、日本語のファイル名でも、問題なく保存できました。

見た目のバグ

右の欄の「時間」に、[object HTMLDivElement] と出ていました。配列の中に、さらに配列を入れていたことが原因でした。F1 の検索欄が、右にはみ出していたのも、直しました。

未確認のこと・制限

  • 字幕と文字の、実機での確認は、これからです。 ヘッドレスブラウザ(画面なしのテスト環境)では、書き出した画像に、文字と字幕が焼き込まれることを、確認しています
  • M4A の書き出しと、無劣化カットは、実機で試していません。
  • Safari と Firefox では、確かめていません。Safari は、フィルタが、プレビューに出ません
  • 画面録画は、本物の画面では、試していません
  • 速度を変えると、音の高さも変わります。音の高さを保ったまま、速度を変えることはできません
  • 速度を変えたあとの隙間は、自動では詰まりません。右クリックの「隙間を詰める」で詰めます
  • MP3 の書き出しは、ありません
  • 無劣化カットは、切れ目が、キーフレームの単位になります

おわりに

「シンプルだけど、多機能」という、矛盾したお願いから始めました。ふだんの画面は、素材を入れて、切って、書き出すだけにして、そのほかの機能は、折りたたみと、F1 のヘルプに入れました。あとから機能を足したくなったときに、困らないようにするためです。

1.4GB の動画を、そのまま、アップロードなしで、1 分半ほどで書き出せたのは、うれしい誤算でした。

今は、v1 です。動かしながら、バグを見つけて、直していきます。