バスキュール技術ブログ

バスキュールが得意とするインタラクティブエンジニアリングを、あますことなくお届け!

AfterEffectsをサーバーサイドで使って動的に動画を生成する

f:id:bascule-dev:20170911153626j:plain

エンジニアの丸山(@maruware)です。
7月末に開催されたWRCフィンランド戦でToyota Gazoo RacingさんとEchoCamというコンテンツをやっていました。
そのときに、AfterEffectsによる動的動画生成をしていたのですが、あんまり日本語の記事がなさそうなので多少参考になるかなということで 今回はそちらを紹介したいと思います。

EchoCamとは

↑の紹介動画の通り、
ユーザー(観戦者)が撮影した写真の時刻とドライブレコーダーの時刻を同期して、動画を生成、ユーザーに届ける
というものです。

f:id:bascule-dev:20170911141618j:plain

図で書くとこんな感じ。
その中の動画生成にAfterEffectsを使っています。紹介動画の40秒あたりからが生成される動画です。

AfterEffectsを使った動的動画生成

①aerenderでAfterEffects自動化

AfterEffectsにはCLIから実行できるようにaerenderという実行ファイルが含まれています。
詳しくは↓のAdobe公式ガイドをご覧ください。

helpx.adobe.com

②AfterEffects内のアセットの動的差し替え

ユーザーの投稿それぞれに動画を生成したいので、画像・動画・テキストなどを差し替えます。
以下の記事が英語ですが参考になるかと思います。

www.themarketingtechnologist.co

基本的には

  • 画像や動画はフッテージとして配置してファイルを差し替えればOK
  • テキストはJavaScriptのファイルを参照してExpressionで処理すればOK

です。
外部ファイルは$.evalFile(path)としてevalするしかないようなので
以下のようなjsファイルを実装しておくような形になります。

var model = {
    "baseTime": 1496984724659,
    "left": 100,
    "name": "Taro",
    "right": 3740,
    "ssName": "ss2",
    "top": 320,
    "window": {
        "h": 1080,
        "w": 1920
    }
};

ここで1つ面倒なことがあって、$.evalFile(path)で参照できるパスは絶対パスじゃないといけません。
開発時にgitで管理するときのポータビリティ的にも運用時の配置的にも使いづらいです。

③nexrenderでポータブル化

nexrenderというありがたいライブラリがあります。
github.com

Node.js製です。
今回は使っていませんがサーバーとして起動する機能もあるようで多機能です。
(ちょろっとContributeしたりもしています)

nexrenderを使うことで、

  • AEのプロジェクトファイルとそのアセットをセットにして宣言的に定義できる(フォーマット化されている)
  • アセットのソースをリモートのURLまたはローカルのパスで指定できる
  • ②で問題だったjsファイルの絶対パス問題が解決できる

というよさがあります。
AEのプロジェクトファイルはaepx(XMLファイル形式)にする必要があります。

jsファイルの絶対パス問題はけっこうな力技で解決していて、

  1. aepx内にバイナリで保存されているExpressionをBufferでデコード
  2. 正規表現でパス文字列を検索して置換する
  3. 再度バイナリ化してaepx内に設定

ということをしています。
このあたりの処理が少しゆるいようで

  • 通常のjsの式がパスとして解釈されることがある(カッコの位置がけっこう影響する)
  • Expression内に日本語などマルチバイト文字を含んでいると壊れる

という不具合があり、注意が必要です。
せっかくバグ踏んだので時間があるときにパッチかこうかなと思います。

④いろいろ動かす

Expression内で動的な値を読み込むことができるので、
Expressionでできることは動的にすることができます。

例えば、EchoCamでは"位置"のExpressionに

$.evalFile('/your-project-path/model.js');
var dx = (model.left + (model.window.w / 2.0));
var dy = (model.top + (model.window.h / 2.0));

easeIn(time, 9.0, 10.0, [dx / 2, dy / 2], [960, 540])

と設定、またスケールも対応したExpressionを設定して
「特定の位置に向かってズーム」をしています。

また、時刻のカウンタを

$.evalFile('/your-project-path/model.js');
var baseTime = model.baseTime;
var frameCount = timeToFrames();
var msec = frameCount * 10 * 100 / 99;

var curr = new Date(baseTime + msec);

var h = ((curr.getUTCHours() + 3) % 24).toString();
var m = ('00' + curr.getMinutes()).slice(-2);
var s = ('00' + curr.getSeconds()).slice(-2);
var ms = ('000' + curr.getMilliseconds()).slice(-3);

h + ':' + m + "'" + s + '"' + ms;

のようにして回したりしています。

おわりに

動的動画生成にはよくffmpeg+ImageMagickを使いますが、そちらと比較して

  • 凝った演出がやりやすい
  • デザイナーや映像クリエイターと分業しやすい

といったメリットがあります。
一方、デメリットして

  • 処理時間がかかる(GPUそこそこのマシンで30秒の動画生成に2分くらいかかったりする)
  • AEのライセンスが必要
  • WindowsまたはMacをレンダリングサーバーとして用意する必要

といったあたりがあります。

EchoCamのようにユーザー数が限られていたり、札束をぶちこめるようなときには選択肢の1つとして検討してみてはいかがでしょうか。