[Astro] #183 ブラウザだけで動く動画リサイズツール — 縦横比を保ったまま、大きさと容量を小さくする

[Astro] #183 ブラウザだけで動く動画リサイズツール — 縦横比を保ったまま、大きさと容量を小さくする

はじめに

前回は、EXE・DLL の中身を読むツール、PE Inspector を作りました。

今回は、動画の大きさを変えて、軽くするツールです。名前は Video Resize です。

きっかけは、公開用のミラー(Cloudflare Pages)のデプロイが、失敗したことでした。1 ファイルの上限は 25 MiB ですが、room2 に置いていた動画が 43.9 MiB ありました。縮めればいいだけなのですが、ちょうどいい道具がありませんでした。

  • 圧縮するだけのツールは、大きさを変えられません(自作の Video Compressor v1 も、そうでした)
  • 動画編集ツールは、できることが多すぎて、「大きさを変えて軽くする」だけには、重すぎます
  • ネットで探したものは、使いにくかったり、使っている間に広告が画面いっぱいに出たりしました

そこで、「縦横比を保ったまま小さくして、さらに軽くする」だけに絞って、作りました。ファイルは、サーバーに送られません。ブラウザの中だけで処理します。

画面

大きさと、画質・容量

Video Resize の画面。左に大きさと画質・容量のタブ、右に変換結果の一覧

左が設定、右が動画の一覧です。動画をドロップすると、元の大きさや長さが出ます。設定を変えると、一覧の各行に「→ 640×360 ・ 約 ○ MB」と、出来上がりの目安が、すぐ出ます。

「大きさ」は、4 つのタブから選びます。

  • プリセット: 4K、2K、フルHD、HD、1024、640、320
  • 長辺: 長い方の辺を、自由な数字で
  • 幅・高さ: 両方を指定。縦横比が合わないときは、黒帯を付けるか、引き伸ばすか
  • 倍率: 50% のように

「画質と容量」も、3 つのタブです。

  • 画質で決める: 最高、高、標準、小さめ、最小
  • 容量で決める: 「5 MB 以下」のように、上限を決める
  • ビットレート: 数字を直接

縦長の動画

縦長の動画を変換した結果。出力は 360×640 で、4.8 MB

プリセットの数字は、「長い方の辺」の長さです。1080×1920 の縦長の動画に「640」を選ぶと、360×640 になります。横長か縦長かは、読み込んだ動画から、自動で決まります。

幅・高さを両方指定する

幅と高さを両方 640 にした設定。出力は 640×640(黒帯あり)と出ている

両方を入れると、縦横比が合わないことがあります。そのときは、動画をゆがめずに小さくして、余った所を黒くするか(黒帯)、ゆがんでもいいので引き伸ばすか、を選べます。

F1 ヘルプ

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 です。