【PowerShell】ffmpegとgif2webpでmp4動画のサイズを小さくしたい

Code

はじまり

リサちゃん
リサちゃん

これ、音声は要らんのよなあ

135ml
135ml

gifかwebpにしたら減らせるのだろうか

動画のサイズを小さくしたい。

mp4ファイルって重いですよね・・・。

ということで、動画のサイズをなんとか小さく出来ないものかと色々試行錯誤した結果をまとめてみました。今回は音声をサポートしていない拡張子(.gifおよび.webp)によるアニメーションに変換することで、ファイルサイズを小さくしていこうと思います。

今回使う変換方法

今回、動画を別の拡張子に変換するために使った方法は、「ffmpeg」と「gif2webp」のパッケージです。

WindowsであればどちらのパッケージもScoopからインストールすることが可能です。

cd C:
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
Invoke-RestMethod -Uri https://get.scoop.sh | Invoke-Expression
$username = (Get-ChildItem Env:USERNAME).Value; Set-Location "C:\Users\$username\Downloads\picture_backup";
scoop update
scoop install libwebp
scoop install ffmpeg

ffmpeg

「ffmpeg」は、メディアファイルを別のメディアファイルに変換するパッケージです。かなり昔から使われているみたいです。

FFmpeg

gif2webp

「gif2webp」は、Google公式の「libwebp」の機能群の一部のパッケージです。GIFアニメーションからWebpアニメーションを生成することが出来ます。

gif2webp  |  WebP  |  Google for Developers

今回使う動画素材

そしてちなみに、今回変換に使ったmp4の動画は、以前にアズールレーン公式がX(旧Twitter)から表現内容を修正するように依頼されたプロモーション動画をスクリーン録画したものです。動画だとちょっと重いので冒頭のスクショだけ。

変換結果のまとめ

今回色々試した結果が以下の表になります。

No変換用コマンド元ファイル変換後の拡張子変換後のサイズ(MB)画質フレーム
1mp4動画 (1920×1080, 60fps)mp489そのまま
2ffmpeg -i "$srcMovieAbsName" -vf split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse -r 60 -loop 0 $dstMovieAbsName;mp4動画 (1920×1080, 60fps)gif1,413劣化なし。再生速度が遅い。
3ffmpeg -i "$srcMovieAbsName" -vf split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse -r 30 -loop 0 $dstMovieAbsName;mp4動画 (1920×1080, 60fps)gif767劣化なし。変わらない。
4ffmpeg -i "$srcMovieAbsName" -vf scale=1920:-1 -r 60 -loop 0 $dstMovieAbsName;mp4動画 (1920×1080, 60fps)gif341少し劣化する。再生速度が遅い。
5ffmpeg -i "$srcMovieAbsName" -vf scale=1920:-1 -r 30 -loop 0 $dstMovieAbsName;mp4動画 (1920×1080, 60fps)gif276少し劣化する。変わらない。
6ffmpeg -i "$srcMovieAbsName" -vf scale=1080:-1 -r 30 -loop 0 $dstMovieAbsName;mp4動画 (1920×1080, 60fps)gif93劣化する。変わらない。
7ffmpeg -i "$srcMovieAbsName" -vf split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse -r 60 -loop 0 $dstMovieAbsName;mp4動画 (1920×1080, 60fps)webp223少し劣化する。抜けるフレームが散見された。
8ffmpeg -i "$srcMovieAbsName" -vf scale=1920:-1 -r 60 -loop 0 $dstMovieAbsName;mp4動画 (1920×1080, 60fps)webp72かなり劣化する。アーティファクトが残ってしまう。変わらない。
9gif2webp "$srcMovieAbsName" -o $dstMovieAbsName3のGIFwebp576劣化なし。抜けるフレームがあった。
10gif2webp "$srcMovieAbsName" -o $dstMovieAbsName -kmin 9 -kmax 173のGIFwebp576劣化なし。抜けるフレームがあった。
11gif2webp "$srcMovieAbsName" -o $dstMovieAbsName -kmin 6 -kmax 133のGIFwebp575劣化なし。抜けるフレームがあった。
12gif2webp "$srcMovieAbsName" -o $dstMovieAbsName -kmin 3 -kmax 53のGIFwebp566劣化なし。抜けるフレームがあった。
13gif2webp "$srcMovieAbsName" -o $dstMovieAbsName2のGIFwebp1,101劣化なし。再生速度が遅い。
14gif2webp "$srcMovieAbsName" -o $dstMovieAbsName -kmin 3 -kmax 52のGIFwebp1083ほぼ劣化なし。再生速度が遅い。
15gif2webp "$srcMovieAbsName" -o $dstMovieAbsName4のGIFwebp285劣化する。再生速度が遅い。
16gif2webp "$srcMovieAbsName" -o $dstMovieAbsName5のGIFwebp220少し劣化する。抜けるフレームがあった。
17gif2webp "$srcMovieAbsName" -o $dstMovieAbsName -kmax 02のGIFwebp1,111劣化なし。再生速度が遅い。
18gif2webp "$srcMovieAbsName" -o $dstMovieAbsName -kmax 12のGIFwebp1,015劣化なし。再生速度が遅い。
19gif2webp "$srcMovieAbsName" -o $dstMovieAbsName -kmax 03のGIFwebp582劣化なし。抜けるフレームが散見された。
20gif2webp "$srcMovieAbsName" -o $dstMovieAbsName -kmax 13のGIFwebp508劣化なし。抜けるフレームが散見された。
21ffmpeg -i "$srcMovieAbsName" -lavfi "scale=1920:-1,setpts=PTS/2" -r 60 -loop 0 $dstMovieAbsName;mp4動画 (1920×1080, 60fps)gif277少し劣化する。変わらない。
22ffmpeg -i "$srcMovieAbsName" -lavfi "split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse,setpts=PTS/2" -r 60 -loop 0 $dstMovieAbsName;mp4動画 (1920×1080, 60fps)gif768劣化なし。少し遅い? コンマ秒レベル。
23gif2webp "$srcMovieAbsName" -o $dstMovieAbsName -kmax 122のGIFwebp508劣化なし。少し遅い? コンマ秒レベル。
24ffmpeg -i "$srcMovieAbsName" -vf split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse -r 60 -loop 0 $dstMovieAbsName;22のGIFwebpエラーになるエラーになるエラーになる
25ffmpeg -i "$srcMovieAbsName" -lavfi split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse -r 60 -loop 0 $dstMovieAbsName;22のGIFwebpエラーになるエラーになるエラーになる
26$itsScale = "[float](1 / 2)"; ffmpeg -i "$srcMovieAbsName" -vf scale=1920:-1 -r 60 -loop 0 $dstMovieAbsName -itsscale $itsScalemp4動画 (1920×1080, 60fps)gif341劣化なし。再生速度が遅い。(なぜだ。)
27$itsScale = "[float](1 / 2)"; ffmpeg -i "$srcMovieAbsName" -vf scale=1920:-1 -r 60 -loop 0 $dstMovieAbsName -itsscale $itsScalemp4動画 (1920×1080, 60fps)webp72かなり劣化する。アーティファクトが残ってしまう。抜けるフレームがあった。再生速度は変わらない。(なぜだ。)

上記の表を踏まえて、以下の所感を得ました。

  • 同じアスペクト比で幅が半分以下になる画質かつノイズが入るのを許容できないのであれば、MP4からGIFへの変換はオススメじゃない。
  • GIFアニメーションからWebpアニメーションに変換すると、画質を落とさずにファイルサイズを減らせる。

ffmpeg

ffmpegでは、mp4ファイルをgifもしくはwebpに変換することが可能です。そして、フィールドに対する設定値の詳細は以下の通りです。

  • 基本的に、-vfフィールドにsplit[s0][s1];[s0]palettegen[p];[s1][p]paletteuseを指定すると変換時間が長くなりサイズが大きくなる。その代わり、画質の劣化が発生しない。(この指定の仕方は「グローバルパレット」と呼ぶらしい。)
  • -vfフィールドにscale=1920:-1を指定すると、アスペクト比を変えずに幅の値を変えることが出来る。そして、変換時間が短くなりサイズを減らせるが、画質の劣化が発生する。
  • -lavfiフィールドにsetpts=PTS/2という風に指定すると、出力されるGIFを2倍速に出来る。
  • ちなみに、-itsscaleフィールドで倍速指定しても、なぜか倍速にならなかった。「$itsScale = “[float](1 / 2)”; ffmpeg -i "$srcMovieAbsName" -vf $vfStr -r $fps -loop $loop $dstMovieAbsName -itsscale $itsScale」という風に指定したのだが。(26の記録)

同じアスペクト比で動画の幅を半分にすれば、元の動画よりも少ないサイズに出来そうです。しかし、そうなると変換後の方がサイズに対する画質のコスパが悪いですね・・・。

gif2webp

gif2webpでは、gifファイルをwebpに変換することが可能です。ffmpegで少ない欠損で変換したgifを変換しました。そして、フィールドに対する設定値の詳細は以下の通りです。

-kminフィールドおよび-kmaxフィールドの詳細を公式リファレンスから抜粋して、llama-3.1-nemotron-70b-instructに和訳してもらいました。

出力アニメーションの中で、連続するキーフレーム(独立してデコード可能なフレーム)間の最小距離と最大距離を指定します。ツールは、必要に応じて出力アニメーションにいくつかのキーフレームを挿入して、この基準を満たします。

kmax の値が 0 の場合、キーフレームの挿入がオフになります。kmax の値が 1 の場合、すべてのフレームがキーフレームになります。これらの特殊なケースでは、kmin の値は考慮されません。典型的な値は、3 から 30 の範囲です。デフォルト値は、無損失圧縮の場合 kmin = 9、kmax = 17、有損圧縮の場合 kmin = 3、kmax = 5 です。

これら 2 つのオプションは、フレーム数が多い (>50) アニメーション画像にのみ関連します。

より低い値を使用すると、より多くのフレームがキーフレームに変換されます。これにより、平均してフレームをデコードするために必要なフレーム数が少なくなる可能性があり、デコード性能が向上する可能性があります。しかし、ファイルサイズがわずかに大きくなる可能性があります。より高い値を使用すると、デコード性能が低下する可能性がありますが、ファイルサイズが小さくなる可能性があります。

kmin = 9、kmax = 17で変換すると無損失圧縮になり、kmin = 3、kmax = 5で変換すると有損圧縮になるみたいですね。しかし、個人的にはあまり画質に変わりはなかったので、どちらかというとkmin = 3、kmax = 5の方が良いでしょうか。また、-kmax 1の方が-kmax 0より少しだけサイズを減らせます。その二者間の画質の違いにもあまり差はありません。

まとめ

今回は、ffmpegとgif2webpを使って、.mp4ファイルから.gifもしくは.webpの拡張子に変換して、サイズを減らす試みでした。

ffmpegのリファレンスはここにあります。さらに詳細に設定できるかもしれません。

ffmpeg Documentation

音声をサポートしていない拡張子に変換すればファイルサイズを減らせると思ったのですが、そういうことでもありませんでした。ムズカシイですねぇ。

おしまい

リサちゃん
リサちゃん

あんまり減らせないかあ

135ml
135ml

難しかったか・・・。

以上になります!

コメント

タイトルとURLをコピーしました