0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

動画をGIFに変換すると色が汚い問題、ffmpeg.wasmのパレット最適化で解決する

0
Posted at

SNS用の短いアニメや、操作説明のGIF——「動画の一部だけGIFにしたい」ことは地味に多いです。でも無料の変換サイトは動画をアップロードさせるものが多く、重いしプライバシーも気になります。

この記事では、動画をアップロードせず、ブラウザの中だけでGIFに変換する方法を ffmpeg.wasm でまとめます。ポイントは、素朴に作ると汚くなるGIFを、パレット最適化できれいに仕上げるところです。

ゴール:ブラウザ内で、動画の指定範囲を「軽くて・きれいな」GIFに変換できるようになること。


まずは素朴な変換(そして、なぜ汚いか)

ffmpeg.wasm はブラウザ内で ffmpeg のコマンドをそのまま実行できます。

<script src="https://unpkg.com/@ffmpeg/ffmpeg@0.11.6/dist/ffmpeg.min.js"></script>
const { createFFmpeg, fetchFile } = FFmpeg;
const ffmpeg = createFFmpeg({ log: true });

async function toGif(file) {
  await ffmpeg.load();
  ffmpeg.FS("writeFile", "in.mp4", await fetchFile(file));

  // 素朴なGIF(実はこれは色が汚くなりがち)
  await ffmpeg.run("-i", "in.mp4", "-vf", "fps=10,scale=320:-1:flags=lanczos", "out.gif");

  const data = ffmpeg.FS("readFile", "out.gif");
  return URL.createObjectURL(new Blob([data.buffer], { type: "image/gif" }));
}

GIFは 1フレームあたり256色までしか使えません。ffmpeg の既定パレットは固定なので、写真や実写の動画では色バンディング(帯状のムラ)が目立ち、汚くなります。


きれいにする:2パスのパレット最適化

そこで、動画から最適な256色パレットを作り(palettegen)→ それを使ってGIF化する(paletteuse) の2パスにします。これがffmpegでGIFをきれいに作る定番テクニックです。

const vf = "fps=10,scale=320:-1:flags=lanczos";

// パス1:この動画に最適な256色パレットを生成
await ffmpeg.run("-i", "in.mp4", "-vf", vf + ",palettegen", "palette.png");

// パス2:生成したパレットを使ってGIF化
await ffmpeg.run(
  "-i", "in.mp4",
  "-i", "palette.png",
  "-lavfi", vf + " [x];[x][1:v] paletteuse",
  "out.gif"
);

const data = ffmpeg.FS("readFile", "out.gif");
  • fps=10:フレームレート。GIFは高fpsだと一気に重くなるので 8〜15 が現実的
  • scale=320:-1:flags=lanczos:幅320pxに縮小(-1で縦横比維持)。lanczos できれいに縮小
  • palettegen / paletteuse:色を最適化する肝。ディザリングもかかり、バンディングが激減します

サイズを抑える・範囲を切り出す

GIFは長い・大きい・高fpsだとすぐ数MB〜数十MBになります。軽くするコツと、範囲切り出しは次の通り。

// 開始2秒から3秒ぶんだけGIFにする(-ss と -t を入力の前に置くと速い)
const args1 = ["-ss", "2", "-t", "3", "-i", "in.mp4", "-vf", vf + ",palettegen", "palette.png"];
const args2 = ["-ss", "2", "-t", "3", "-i", "in.mp4", "-i", "palette.png",
               "-lavfi", vf + " [x];[x][1:v] paletteuse", "out.gif"];
await ffmpeg.run(...args1);
await ffmpeg.run(...args2);

軽くするポイント:

  • 長さは短く(数秒)
  • 幅を小さく(240〜320px)
  • fpsを下げる(8〜10)

環境の注意(初回だけハマるところ)

  • エンジンの初回読み込み:ffmpeg.wasm のコアは数十MB。初回のみ読み込みが入ります(以降はキャッシュ)。createFFmpeg({ corePath }) で自ホスティングも可能。
  • マルチスレッド版は COOP/COEP が必要SharedArrayBuffer を使うため)。ヘッダーを触れない場合はシングルスレッド版(コアは大きめ)。
  • CSPを使っているなら blob:script-src / connect-src に許可(ffmpegがBlobワーカー/Blob fetchを使うため。ローカルでは気づけず本番で出がち)。

※ この3点は動画→音声のときと同じで、別記事で詳しく書いています。


コードを書かずに使いたいとき

「1回だけGIFにしたい」「動画をアップロードしたくない」なら、ブラウザ完結のツールが手軽です。

私が作っている Morphy の「動画→GIF」なら、

  • 動画を選んで、開始位置・長さ・fps・幅を指定するだけ
  • 内部で**パレット最適化(2パス)**して、きれいなGIFを生成
  • 処理はすべてブラウザ内で完結し、動画はアップロードされません
  • 登録不要・無料

👉 動画→GIF 変換ツールhttps://morphytools.com/video-to-gif.html


まとめ

  • ffmpeg.wasm を使えば、サーバーなし・ブラウザだけで動画をGIFにできる
  • 素朴な変換は色が汚い → palettegen + paletteuse の2パスできれいに
  • fps・幅・長さでサイズを制御、-ss / -t で範囲を切り出す
  • マルチスレッド版は COOP/COEP、CSPは blob: に注意

「動画をアップロードせずに、きれいなGIFを作りたい」に、ブラウザ完結はよく合います。参考になれば嬉しいです。


0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?