Convert screen capture to animation GIFの話でffmpegを使ってキャプチャをGIFに変えるということをした。Macだとffmpegのインストールは簡単だしその方が良いと思うけど、環境によっては難しい場合もあるだろうし、そもそもインストールしてはならない状況もあるかもしれない。そんな時にffmpeg.jsをWeb Workersで動かすのはどうだろうかと思ってやってみた。
デモ。ソースコードはmemolog/ffmpeg_workerあたりにある(とりあえず動くというだけの実装だけど)。ファイルを選択すると、読み込んだファイルをwebmに変換して表示する。見た目は下のキャプチャような感じになる。このデモサイトでは、mp4やmovファイルをwebmに変換できるけれど、iPhoneで撮った動画はエラーになって変換できない(おそらくエンコーダ的にffmpeg-worker-mp4.jsの方を使わないといけない)
基本的な実装は二つで、一つはWeb Workerを起動させて実行結果を受け取る処理。ffmpeg.jsは変換処理が終わるとWorker自身にdone
イベントを送るのでそこで実行結果を受け取る。
this.worker = new Worker("./lib/ffmpeg-worker-webm.js");
this.worker.addEventListener("message", ev => {
const msg = ev.data;
const type = msg?.type ?? "";
switch (type) {
case "done":
const data = msg?.data?.MEMFS[0]?.data;
this.setState({
converted: URL.createObjectURL(new Blob([data])),
});
break;
}
});
もう一つはtype="file"
のchangeイベントで、event.target.files
からファイルオブジェクトを受け取って、ArrayBufferにしてworkerに渡す処理。
const reader = new FileReader();
reader.onload = () => {
const result = reader.result;
if (result instanceof ArrayBuffer) {
this.worker.postMessage({
type: "run",
MEMFS: [{ name: file.name, data: result }],
arguments: ["-y", "-i", file.name, "-crf", "30", "-b:v", "0", "out.webm"],
});
}
};
reader.readAsArrayBuffer(file);
上のキャプチャで使った動画はCosmic Origin of the Chemical Elementsの講義からダウンロードしてきたものだけど、12MBのデータを10MBに、見た感じ劣化もなく変換することができたと思う。実行時間は測ってないけど10分とかもうちょっとかかってたかも。
それで、動画をGIFに変換できるのかというと、、できない。GithubのGIF Encoding?のissueによると、Makefileにgifを追加してビルドすれば対応できるらしい。それでBuild instructionsを参考にビルドしようと試みたのだが、Can’t compile with recent emscripten.と同じところでエラーになって手詰まりになって諦めた。
というメモ。