[Astro] #183 ブラウザだけで動く動画リサイズツール — 縦横比を保ったまま、大きさと容量を小さくする
はじめに
前回は、EXE・DLL の中身を読むツール、PE Inspector を作りました。
[Astro] #182 ブラウザだけで動く EXE・DLL 解析ツール — 構造を読んで、機械語まで逆アセンブルする
ブラウザの中だけで動く、EXE・DLL の中身を読むツール PE Inspector を作りました。
lain-lab.com今回は、動画の大きさを変えて、軽くするツールです。名前は Video Resize です。
きっかけは、公開用のミラー(Cloudflare Pages)のデプロイが、失敗したことでした。1 ファイルの上限は 25 MiB ですが、room2 に置いていた動画が 43.9 MiB ありました。縮めればいいだけなのですが、ちょうどいい道具がありませんでした。
- 圧縮するだけのツールは、大きさを変えられません(自作の Video Compressor v1 も、そうでした)
- 動画編集ツールは、できることが多すぎて、「大きさを変えて軽くする」だけには、重すぎます
- ネットで探したものは、使いにくかったり、使っている間に広告が画面いっぱいに出たりしました
そこで、「縦横比を保ったまま小さくして、さらに軽くする」だけに絞って、作りました。ファイルは、サーバーに送られません。ブラウザの中だけで処理します。
画面
大きさと、画質・容量
左が設定、右が動画の一覧です。動画をドロップすると、元の大きさや長さが出ます。設定を変えると、一覧の各行に「→ 640×360 ・ 約 ○ MB」と、出来上がりの目安が、すぐ出ます。
「大きさ」は、4 つのタブから選びます。
- プリセット: 4K、2K、フルHD、HD、1024、640、320
- 長辺: 長い方の辺を、自由な数字で
- 幅・高さ: 両方を指定。縦横比が合わないときは、黒帯を付けるか、引き伸ばすか
- 倍率: 50% のように
「画質と容量」も、3 つのタブです。
- 画質で決める: 最高、高、標準、小さめ、最小
- 容量で決める: 「5 MB 以下」のように、上限を決める
- ビットレート: 数字を直接
縦長の動画
プリセットの数字は、「長い方の辺」の長さです。1080×1920 の縦長の動画に「640」を選ぶと、360×640 になります。横長か縦長かは、読み込んだ動画から、自動で決まります。
幅・高さを両方指定する
両方を入れると、縦横比が合わないことがあります。そのときは、動画をゆがめずに小さくして、余った所を黒くするか(黒帯)、ゆがんでもいいので引き伸ばすか、を選べます。
F1 ヘルプ
F1 キーで、使い方が出ます。「縦長」「目標」「黒帯」のように、やりたいことで探せます。ほかのツールと同じです。
作ったもの
- 動画(MP4、WebM など)を、ドロップか選択で開く。複数本でも、フォルダごとでも
- 大きさ: プリセット、長辺、幅・高さ(黒帯 / 引き伸ばし)、倍率。縦長でも横長でも、縦横比を保つ
- 画質: 画質で決める、容量の上限で決める、ビットレートを直接
- 形式: MP4(H.264 など)、WebM(VP9 など)。音声は、そのまま・音質を下げる・なし。コマ数の上限
- 変換前に、出来上がりの大きさと容量の目安を表示。変換後に、実際の数字
- 保存先フォルダを選んで、そこへ直接書き出し。または、ダウンロード
- 変換中の取り消し、変換した動画の再生
- F1 ヘルプ
作り方
変換は Mediabunny に任せる
動画の読み書きは、Mediabunny(v1.61.6)を使いました。ブラウザの WebCodecs という仕組みを使って、動画を、ブラウザの中で、デコードして、エンコードし直します。ライセンスは MPL-2.0 です。ファイルを自分のサイトに置いて、そこから読み込みます。
FFmpeg の WASM でも作れますが、WebCodecs は、ブラウザの機能を使うため、速くて、ファイルも小さく済みます。代わりに、使えるコーデックが、ブラウザ次第になります。
大きさの計算
大きさを決める部分は、画面から切り離して、size.js という、計算だけのファイルにしました。単体のテストは、23 件です。
- 長い方の辺を決めたら、短い方は、縦横比から計算します
- H.264 は、幅も高さも偶数でないと扱えないので、偶数に丸めます
- 元の動画より大きくなる指定は、既定では、元の大きさのままにします(「元より大きくしない」)
- 幅・高さを両方指定して、縦横が逆の枠のとき(縦長の動画に横長の枠)は、動画の向きに合わせて、自動で入れ替えます
スマホの動画は、画面の向きが「回転情報」として入っていることがあります。符号化された幅と高さではなく、表示される向きの幅と高さで、縦横を判定しています。
画質と、容量の上限
「画質で決める」は、1 画素あたりのビット数の表から、ビットレートを決めます。最高は多め、最小は少なめです。コーデックによって、同じ画質に要るビットレートが違うので、係数を掛けています。
「容量で決める」は、逆算です。「5 MB 以下」なら、動画の長さで割って、ビットレートを出します。実際の変換は、狙いどおりには収まらないことがあります。そこで、目標を超えたら、ビットレートを下げて、もう一度だけ自動でやり直します。
それでも収まらないときは、収まらなかったと、そのまま出します。「収めました」とは、言いません。逆に、元の動画が小さくて、目標よりずっと小さく収まるときは、ビットレートに上限を付けて、無駄に大きくならないようにしました。
詰まったこと
「最高」は、圧縮率ではない
朝、最初に言われたのは、「最高って圧縮率じゃないの? 画質設定ってどこにある?」でした。「最高」は、画質が最高(=容量が大きい)という意味でしたが、そう読めませんでした。「画質」という見出しを付けて、「← きれい(容量 大)」「軽い(容量 小)→」の説明を足しました。
タブが、ボタンに見えた
設定を切り替える部分を、ボタンの並びで作ったら、タブだと分かりませんでした。タブらしい見た目(選んだタブが、下の枠とつながる)に作り直しました。
その直しのあと、レイアウトが崩れました。原因は、設定の枠(.vr-sec)に、中身を縦に並べる gap: 8px が付いていて、タブの帯と、その下の枠のあいだにも、隙間ができたことでした。最初は、画面が低いときに中身が縮むのだと考えて、的外れな直しを入れました。DevTools で gap を外すと隙間が消える、という指摘で、分かりました。タブのすぐ下の枠にだけ、負の余白を入れて、つなげました。
見た目の問題は、画面のスクリーンショットと DevTools で、実物を見るのが、一番早いです。こちらの環境では、サイトのヘッダーも、DevTools もない画面で確かめていたので、見えていませんでした。
書き込みと、ストリームの閉じ方
変換した動画を、選んだフォルダへ直接書き出すときは、ストリームに書き込みます。最初、自分でストリームを閉じようとして、「閉じられません(ロックされています)」というエラーになりました。ストリームは、Mediabunny が、書き終わったときに、自分で閉じます。自分では、閉じないようにしました。取り消したときや失敗したときは、中途半端なファイルが残らないように、空のファイルを消します。
MP4 の「再生をすぐ始められる形」(fastStart)は、変換と組み合わせると、設定の形が合わず、エラーになりました。メモリ上で組み立てる方式にして、ファイルに書き出す場合で、出来上がりが 400 MB を超えそうなときだけ、組み立てをやめます。
目標より、小さすぎる
小さな動画に「24 MB 以下」を指定すると、見積もりが、元の動画の何十倍にもなりました。元のビットレートの 9 割と、「最高」の画質を、上限にしました。
実機で確認できたこと
Windows の Chrome で、確認しました。
- 横長の動画(3840×2160、60fps、46.0 MB)を、640×360、上限 5 MB にして、4.9 MB(−89%)になりました。最初の変換では、目標を超えて、自動の再やり直し(2 回目)で収まりました。VLC でも、再生できました
- 縦長のスマホ動画(1080×1920、47.6 MB)は、縦のまま 360×640、4.8 MB(−90%)になりました。サムネイルも、縦で出ました
- 幅・高さを両方入れて、黒帯を付ける設定を、確認しました。出力は 640×640(黒帯あり)でした
- 保存先フォルダ、F1 ヘルプ、ウィンドウで開いたときの表示も、確認しました
きっかけの動画(media_1783643408438.mp4、43.9 MiB)も、この設定で 4.9 MB になったので、25 MiB の上限には、収まります。
ヘッドレスの Chromium(H.264 のエンコーダーがない)では、VP9 で、次のことを確認しました。
- 横長・縦長・回転情報つきの動画で、出力の幅・高さ・向きが正しいこと(ffprobe と、画像の比較で)
- 黒帯と引き伸ばしの画素、奇数の指定が偶数になること
- 容量の上限と、自動のやり直し、取り消し、フォルダへの書き出し(OPFS で代用)
未確認のこと・制限
- ハードウェアエンコードの速度と、目標サイズのずれは、GPU 次第です。目標を一度超えて、やり直しになることがあります
- HEVC の読み込みは、確かめていません。ブラウザが対応していないと、読めません
- 数 GB の動画や、本数の多い一括変換は、確かめていません
- Firefox と Safari、スマホの画面は、確かめていません。スマホ向けの専用設計は、していません
- 切り抜き(クロップ)や、時間のカットは、入れていません。大きさを変えて軽くすることだけに、絞りました
- 使えるコーデックは、ブラウザ次第です。選んだ形式で書き出せないときは、別のコーデックに切り替えて書き出します
おわりに
「小さくするだけ」に見えて、縦横の判定、偶数への丸め、容量の上限からの逆算、表示のわかりやすさと、考えることがたくさんありました。特に、作った本人には分かる言葉と見た目が、初めて使う人には、通じませんでした。朝に使ってもらって、直したところが、いちばん多かった部分です。
次は、Git Inspector に取りかかります。今は、v1.0 です。