動画作りのためのプレリュード

このエントリは、サステナブルなぴょこりんクラスタ Advent Calendar 2023のために書かれたものです。

前回のエントリで開発目標が達成できなかったということを書きましたが、今回はもともと作りたいと思いつつ作っていなかったものをなんとか12月に作ろうとしていることを書きたいと思います。これもギリギリに書いている状態なので、ものすごく自転車操業感があります。仕事と同じような感じになってしまって、よろしくないですね。

動機

さて、今回作るツールは、動画を作るためのツールです。こちらで書いたようにGoPro HEROを昨年新しいのを買ったので、有効活用をしたいなあと思っていたことによります。まあ有効活用するには、編集して動画を作るくらいしかないわけなのですが、動画を編集するソフトといえば、マウスでカチカチしたりするイメージが大きく、ちゃんとテキストというかスクリプト的に行いたいなあというところがあります。

これは、やっぱりIaC(Infrastructure as Code)とかPaC(Policy as Code)とかいわれるように、なんでもコードにするのがメンテナンス性とか再現性とか再利用性を高めるうえでも大切なんじゃないかという世の中の潮流にあっているのではないでしょうか。

と、無理やりの正当化したうえで、そんなツールを作っていきたいと思います。Movie as Codeとでもいえばいいんでしょうか。

関連研究と方針

もちろん画像の各フレームを生成するプログラムを一から作れば、動画づくりはできてしまいます。しかしそれではおもしろくありませんし、とてつもない車輪の再発明になるだけです。せっかくなら世の中にあるものを使って、うまくやりたいものです。

既存のものを調べてみると、たとえば、Movisのようなものがあるようです。これは、基本的には自前でレイヤーとかもろもろのAPIを提供しているようです。

しかし、世の中にはもっと手軽に使える、身近なレンダリングエンジンがあります。そう、Webブラウザです。

今や世の中なんでもWebブラウザです。スマートフォンのアプリだって、ネイティブで書いてあるものもありますが、結局ブラウザのエンジンを載せてWebアプリとほぼ同じようなものを動かしているようなアプリだってあるのです。そして、アニメーションの類であっても、CSSがやたらと充実しています。

Hello, world

こんなのをcssだけで書けるわけですから、これを使わない手はありません。ということで、今回の方向性は、ブラウザをレンダリングエンジンとして利用した動画作成ツールということになります。

・・・で、さらに調べると、Creatomateなんてものもありました。やっぱり世の中考えることは同じなんですねえ。

まあ有料のサービスっぽいので、とりあえず無視して車輪の再発明をすることにしましょう。(結局そんなオチ)

おおまかな設計

全体の設計概要
全体の設計概要

もうPowerpointの図という投げやりな感じになってしまってますが(これも本当はちゃんとスクリプトで図を描けという話なのですが)、大まかな設計はこんな感じです。言語は書いていませんがサーバー側はTypeScript、ブラウザ側はここでViteとかかませるとわけがわからなくなりそうなので、JavaScriptそのままです。JavaScriptをそのまま書くのは、現代においてはかなりの蛮行と思われますが、今回の目的では複雑な処理を書くことはほとんどないでしょうから、とりあえずよしとします。

ブラウザを動かすのは、SeleniumとかPuppeteerが有名ですが、最近流行ってきている気がするPlaywrightを使うことにしました。いざとなったらブラウザをChromiumからWebkitとかFirefoxに変えることができますしね。する予定はないですが。

右上のプロジェクトとしているのが、肝心の動画のソースとなるものです。全体のメタ情報やタイムライン情報を含むyamlファイルと、実際に描画するhtmlファイルなどからなります。htmlファイルは、シーンごとなど、複数作ることを想定しています。タイムライン情報に従って、シーンごとにそれぞれのファイルを開いて、フレーム撮りをスクリーンショットによって行っていき、最終的に一つの動画としてエンコードする形となります。

CSSアニメーションのコマ送り

そして問題はCSSのアニメーションなのですが、これは時刻で指定し、ブラウザで表示するとアニメーションが動きっぱなしになります。今回、コードにするのは、再現性を高める、つまりdeterministicにするためなので、これをリアルタイムに録画するようなのは避けたいです。あくまで1フレーム1フレームを(再現性ある形で)ちゃんと描画して行きたいところです。

ということで、どうしたらいいのか考えた結果、CSSの animation-play-state プロパティと、animation-delay プロパティを使うことにしました。 要は、アニメーションを初期状態でポーズした状態にしておき、1コマ動かすごとに負のanimation-delayを各要素に与えていけばよいということになります。

制約事項としては、もともとのアニメーションでanimation-delayを使っている場合にはコンフリクトするので、なんらかの処理を必要とすることです。 このあたりは、既存のものを使いまわすのではなく、このツールのためにcssなどを書くことになるので、まあどうにでもなるでしょう。 (結局、このために、特定のJavaScriptの関数を提供することになるので、完全に標準に従う形にならないのが残念なところです)

まずは、簡単にhtmlで書いた内容を動画にしてみるところまでできたので、下記にリンクを張ります。

ソースのhtmlファイル (pauseしてないので動画の生成に使ったものとは厳密に同じものではない)

出来上がった動画ファイル (1920x1080, 60fps, mp4)

プログラムはまだまだなので、もう少しちゃんと作ったら公開したいと思います。(よくない傾向)

次のステップ

今回は単純にCSSアニメーションを録画するだけでしたが、本来は動画編集なので、既存の動画を組み合わせたりするのがやりたいことです。今回のどこかのエントリでそこまでいったものを紹介したいところです。

本当にこれができたかどうかは、12月23日まで読んだ各位にあっては既にご存じのことでしょう・・・というか、たったこれだけの内容でも結構妥協したポイントがいろいろあるので、推して知るべしではありますが・・。