これからはGIF画像をやめて動画を使った方が良さそうな話

2022/03/16

今まではプログレスバーの記事にあるようなちょっとした画面の録画内容を見せたい時はGIF画像を使ってた。

でもGIFって高解像度だと10秒で1MBとかどうも容量が大きくなりがちで、記事に載せるようなレベル感だと高画質にするのは絶対無理なんだよね。

それだけのために帯域が数MB消費されるのも嫌だし😥

そこでGIFの代わりにMP4とかの動画ファイルを直接使ってみたら良い感じ!

画像ホスティングサービスのGIPHYimgurなんかも今ではパフォーマンス的な理由でGIFの代わりに動画ファイルを使ってるみたい。

最近のブラウザはvideoタグで動画の自動再生とインライン再生、コントロールの非表示が簡単に出来るからほぼGIF画像みたいなノリで使えるんだね。

フォーマットの比較

まず実際のパフォーマンスを見るためにこの記事に載せた13秒の動画をGIF MP4 WebM3つのフォーマットで比較してみる。

iOSのSafariはまだWebMに対応してないからiPhoneやiPadだと表示されないかも。

GIF 145Kb

MP4 44Kb

WebM 33Kb

GIF145KbMP444Kbともうこの時点で13\bold{\Large \frac{1}{3}}以下になってる上に画質も圧倒的に良い。

WebMに至ってはMP4と変わらないかむしろ良いぐらいの画質で33Kbとさすがだなー。

WebM

Googleが2010年頃から開発・推進してるオープンな動画フォーマット。

Web経由でhtmlに組み込んで表示することを前提としているだけあってかなり軽量なサイズで高画質を実現できる優秀なやつ。

YouTubeの動画などはちょっと前からWebMで配信されてるから意識してなくても既に大多数は利用経験があるはず。

とにかく普及させたいみたいで最初からオープンでロイヤリティフリーを謳ってる。実はMP4H.264とかって普通に商用フォーマットだからビジネスに利用すると特許料が発生する可能性があるんだよね。

色々な動画フォーマットが乱立しててスタンダードが定まってないのもこれまで無料で使える高品質なものが無かったっていう理由が大きいみたい。なら俺が作るよ!って作っちゃうのがGoogleのすごいところだよね。

色々なブラウザが次々とWebMに対応する中でiOSだけは長らく非対応の姿勢を貫いてきた。故スティーブ・ジョブズさんが「Googleのコーデックはめちゃくちゃだ」って言ったなんてこともあったみたい。

Steve Jobs says no to Google’s VP8 WebM codec | Apple Insider

そんなAppleもとうとうiOS 15からなんとWebMの音声コーデックにだけ対応し始めて、映像含めて完全に対応するのも時間の問題っぽそう。

ちなみに画像フォーマット版のWebPもあってやはりJPEGなんかとは比較にならないぐらい高画質を実現できるよ。こちらは既にiOSでも対応済み。

やっぱりGIFは画質が悪い上にサイズが大きいのが目立つね。

コスパの悪いGIF画像は動画ファイルに変換して良い感じにしよう!サクッとできるやり方を紹介するよ。

GIF画像を動画ファイルに変換

まずは手元のGIFをFFmpegを使って動画に変換しよう。

FFmpeg

動画や音声の加工・変換を行うコマンドラインツールのデファクトスタンダード。

対応してるフォーマットやオプションが異常に多く、これ1つで割とどんな動画も書き出せる。超便利。

FFmpeg

ちなみにここで紹介するやり方はGIFだけじゃなくて他の動画ファイルでも同様に使えるよ。

例えばMacでスクリーン録画をすると保存されるMOVMP4に変換する場合なんかもOK。

FFmpegのインストールと使い方

MacではHomebrewで簡単にインストールできるよ。Ubuntuでもaptで簡単に入れられると思う。

ちょっと前までは色々コーデックのオプションがあったんだけど今はデフォルトで全部入りなのかな?

brew install ffmpeg

基本的な使い方はこう↓

ffmpeg -i input.gif output.mp4

なんとこれだけでファイル名の拡張子から判断して自動的にフォーマットを変換してくれるという便利さ。

詳しい使い方についてはFFmpegのサイトに載ってるんだけど、量が膨大で分かりにくいと思うから大体使いそうな機能をさらっと紹介。

コーデックの指定

上記の例ように特に何も指定しない場合は元の形式と出力先の関係から自動でコーデックが決定されるっぽいんだけど、それだと意図しないものになっちゃう可能性があるからなるべく指定しよう。

コーデック

メディアファイルの圧縮・変換方式のこと。

普段意識するMP4WebMなどのコンテナフォーマットよりさらに細かい概念で、ざっくり言うとコンテナフォーマット=映像コーデック+音声コーデックって感じ。

だからファイルによってコンテナは同じでもコーデックが違うなんてこともありえるんだね。

拡張子が同じなのに再生できない動画ファイルはコーデックの違いが原因だったりするよ。

ネットが遅くてストリーミングサービスもまだ無いような時代はせっかく時間をかけてダウンロードした動画のコーデックが合わなくて再生出来ない!なんて悲しいこともよくあった😇

フォーマット別のおすすめコーデック指定はこんな感じ↓

MP4にはH.264, WebMにはVP9が良さそう。

MP4
ffmpeg -i input.gif -c:v libx264 output.mp4
WebM
ffmpeg -i input.gif -c:v vp9 output.webm

元ファイルがGIFじゃなくて動画のケースでコーデックをそのまま維持したい場合は-c:v copyを指定する。

指定しないと入出力のコーデックが同じ場合でも再エンコードされちゃうみたいだから、コーデックを変えずに他の部分だけ変更したい時はcopyを指定しないといけないね。

フレームレートの指定

ちょっとした説明用の動画など多少カクカクしても問題ない時はフレームレート(FPS)を下げて容量を節約しよう。

-rオプションで1秒あたりのフレーム数を指定できるよ。

これはフレームレートを20にする例。1秒間に20枚のペースってことだね。

MP4
ffmpeg -i input.gif -c:v libx264 -r 20 output.mp4

元の動画に存在しないタイミングのフレームに対しては単純に時間的に最も近いものが選択されるみたい。

元動画のフレームレートに対して割り切れない数字を指定したりすると場合によっては変な感じのラグがある動画になっちゃうかもしれないから気をつけよう。

解像度の指定

大きいサイズの元動画を配信用に縮小したい場合なんかは-sオプション。

解像度をpx単位で-s 横x縦形式で指定して変換することができる。

MP4
ffmpeg -i input.gif -c:v libx264 -s 1280x720 output.mp4

16:9の代表的な解像度

widthheightオプション
8K76804320-s 7680x4320
4K38402160-s 3840x2160
WQHD25601440-s 2560x1440
FHD19201080-s 1920x1080
WXGA++1600900-s 1600x900
HD1280720-s 1280x720

4:3の代表的な解像度

width(px)height(px)オプション
QUXGA32002400-s 3200x2400
QXGA20481536-s 2048x1536
UXGA16001200-s 1600x1200
QVGA1280960-s 1280x960
XGA1024768-s 1024x768
SVGA800600-s 800x600
VGA640480-s 640x480
QVGA320240-s 320x240
QQVGA160120-s 160x120

アスペクト比を保ったまま変換

-vfオプションを使うと縦横どちらか一方を指定するだけでアスペクト比を保ったまま変換ができる。便利だね。

-vf scale=横:縦の形式で自動で設定して欲しいほうに-1を指定しよう。

MP4
ffmpeg -i input.gif -c:v libx264 -vf scale=1280:-1 output.mp4

品質の指定

画質を下げてファイルサイズをなるべく節約したい時もあるよね。

これにはビットレートから指定する方法品質から指定する方法の2つあるんだけど、おすすめは品質を指定してビットレートはお任せにするやり方。

品質の指定には-crf(Constant Rate Factor)オプションを使おう。

主に圧縮率を調整するものみたいで、低い数字の方が画質が良い(ロスレスに近い)代わりにファイルサイズも大きくなるよ。

VP9はデフォルトだとビットレートが最大200Kbpsに制限されてるから併せて-b:v 0も指定するようにしよう。

MP4
ffmpeg -i input.gif -c:v libx264 -crf 36 output.mp4
WebM
ffmpeg -i input.gif -c:v vp9 -crf 36 -b:v 0 output.webm

H.264の場合は-crfを指定すると固定品質になるんだけどVP9は目安って感じで多少変動するみたい。

コーデック別のデフォルト値/最小値/最大値/推奨値はこんな感じ。

コーデックデフォルト最小最大公式の推奨
H.2642305118~28
VP93206315~35

個人的な目安としては超高品質=~18 高品質=~24 標準品質=~36 低品質=~44 超低品質=それ以上ぐらいだと思う。

範囲で指定する

品質が場面で可変になるように範囲で指定することも出来る。品質に併せて最小値,最大値をそれぞれ-qmin -qmaxで指定すればOK。

VP9の変動幅もこのオプションで設定できる。特に固定品質にする理由が無ければ使っておいた方が良さそう。

MP4
ffmpeg -i input.gif -c:v libx264 -crf 36 -qmin 28 -qmax 44 output.mp4
WebM
ffmpeg -i input.gif -c:v vp9 -crf 36 -qmin 28 -qmax 44 -b:v 0 output.webm

ピクセルフォーマットの指定

これまで出てきたコンテナ コーデックに加えてなんとピクセルフォーマットという各ピクセルの色情報についての形式があるんだけど、動画ファイルを変換する時はこれも指定しとかないとスマホで再生できなかったりする。

元がGIF画像の場合は多分気にしないでOKなんだけどね。動画の場合も大抵は-pix_fmtオプションでyuv420pを指定しておけば大丈夫。

MP4
ffmpeg -i input.mov -c:v libx264 -pix_fmt yuv420p output.mp4

動画ファイルをWebサイトに表示する

変換した動画をWebサイトに表示するにはvideoタグを使おう。

videoタグの中にsourceを複数入れておくとブラウザが上から順に再生可能かどうかチェックして使ってくれる。これめちゃめちゃ便利!

ここでは優先度順に効率の良いWebM, 対応範囲の広いMP4, 最後に動画が再生できない場合のフォールバックとしてGIFを指定してるよ。

<video autoplay loop playsinline muted>
  <source src="video.webm" type='video/webm; codecs="vp9"' />
  <source src="video.mp4" type='video/mp4; codecs="avc1"' />
  <img src="video.gif" />
</video>

冒頭の比較動画もこのやり方で表示してる。

ポイントはautoplay loopを指定して自動でループ再生を開始するところとplaysinlineで普通の画像と変わらない埋め込み形式の表示にしているところ。

スマホのブラウザなどはmutedにしないと自動再生できないからこれも忘れずに指定しておこう。例え無音の動画でも指定しないと再生できないみたい。

codecs

再生するだけならsourceタグのtype属性にcodecsを書かなくても大丈夫。type="video/webm"みたいに省略できる。

変わってくるのはjsでvideo.canPlayType()とかを使う時なんだけど、ここではあんまり関係ないよね。

それでも一応書いておいた方がお行儀が良いからコーデックが分かってる場合はなるべく書くようにしよう。

VP8VP9の場合はシンプルにvp8 vp9H.264の場合はavc1って書いておけば問題なさそう。

まとめ

やってみたら動画がめっちゃ簡単にhtmlに埋め込めて普通にブラウザの進化を感じた。マジで。時代かー。

ついでにGIF自体についてもちょっと調べたんだけど、元々は単に複数枚の画像を1ファイルに格納するために作られたフォーマットだったみたい。

格納された画像を一連のアニメーションとして表示させるっていうのは副次的な応用方法だったのね。

画像何枚も格納してんなら次々表示を切り替えれば動画っぽく使えるじゃん、みたいな。

しかもNetscape Navigator 2の時代からあるやり方らしい。超古い。ネットスケープっていうのは1995年に発表された当時革新的だったブラウザなんだけど、知ってる?笑

当時のブラウザは動画を表示するなんて全然出来なかったはずだし、そんな中で画像ファイル1つでちょっとした動画っぽいものを表示できるとなると確かに超便利だ。

ってかそこまで遡らなくても一昔前まではブラウザで動画を表示するために結構頑張る必要があったんだよね。今となっては嘘みたいだけど。

2000年代でもSilverlight Shockwave FLASHとかのもれなく無くなっちゃった独立した実行環境をブラウザと連携させて動かす系のやつでプレイヤーを実装して表示したり、objectembedとかのタグとしてブラウザが独自実装した機能を使うけど環境依存だから使いにくい上にろくに外部から制御が出来なかったり、そんな感じだった気がする。

YouTubeも確か2015年ぐらいまではFLASHで作ったプレイヤーで動画再生してたんだよね。拡張子が.swfのやつ。

それが今では普通にvideoタグ一発😇 もう動画の表示にGIF画像なんて使う必要無いってことなんだろうね。

これからは積極的に動画ファイルを使っていこう。