うつろぐ

文章

Processingとffmpegで簡易BGA作成 その1(レンダリングとプレビューを分けるまで)

総コン Advent Calendar 2017 - Adventarの19日目の記事です。
 

先日M→Fes 2017 : ATNDを見に行ってきました。詳細は省きますが最高になりました。そして、衝動的な映像作品作成欲求に駆られました。しかし、僕はAdobeに課金をしていないので、これまで散々お世話になってきたProcessingを使って映像作品を作ろう!となりました。
 

今回は取り敢えずProcessingとffmpegで音声つきの動画を書き出すところと、そこから発展させて「音楽に同期した動画を作成する」環境にしていく為の第一段階として、レンダリングとプレビューを分けるところをやっていきます。

ProcessingとMinimのインストール、ffmpegのインストールとパスを通すところまではやっている前提で書いていきます。

 

 

取り敢えず動画ができろ

取り敢えずProcessingとffmpegで音声つきの動画を書き出します。
 

フレームの書き出し(Processing)

Processingで現在のフレームを書き出す方法は、色々なサイトにある通り
save("hoge.png");
を書くだけです。簡単ですね。

以下のコードを実行すると、アニメーション描画100フレーム分をpng画像としてframesフォルダに書き出したのち、描画が完了して黒画面になります。

int frameSum=100; //書き出すフレーム数

float size=0; //描画内の円のサイズ

void setup() {
  size(600, 600);
}

void draw() {
  if (frameCount<=frameSum) {
    background(-1);
    size=400+300*sin(radians(frameCount*10));

    fill(255, 0, 0);
    noStroke();
    ellipse(width/2.0, height/2.0, size, size);

    save("frames/"+nf(frameCount, 4)+".png");
  } else {
    background(0);
  }
}

こんな感じに出力されます。
f:id:Distorted_Unchi:20171219220237p:plain

動画に変換(ffmpeg

実は、書き出したフレームをmp4にするツールがProcessingに最初から搭載されている(ツール→ムービーメーカー)のですが、使ってみたところ何故かうまく動作しなかったので、書き出したフレームをmp4の形式にする為にffmpegを叩きます。
ffmpegで連番画像から動画生成 / 動画から連番画像を生成 ~コマ落ちを防ぐには~ - Qiita

ffmpegで動画と音声を結合する方法 - 何気に大変
を参考に、フレーム(連番画像:0001.png,0002.png,...)と音声から動画に変換するコマンドを1行にすると以下のようになります。

ffmpeg -framerate 40 -i frames\\%4d.png -i music.wav -vcodec libx264 -pix_fmt yuv420p -r 60 out.mp4

ここで「%4d」は0001,0002...のような4桁の連番整数の指定を示します。「%3d」だと001,002...のようになります。また、batファイルに書く際は「%%4d」となるようです。

結果としてこんな感じの動画が出ます。長さは音声ファイルに合わせられているのが分かるかと思います。

www.youtube.com


レンダリングとプレビュー(描画)を分ける

分けます。

なぜ

なぜそんなことをするのか。

Processingでプレビューがしたい

音声と同期した動きの確認を、いちいち動画を書き出してからやっているのでは面倒なので、Processingで大まかにプレビューがしたい。

フレーム書き出しとプレビューは分けたい

先ほどのコードで描画しながらフレームを書き出してみて分かったかもしれませんが、フレーム書き出しと描画を同時に行うとめちゃくちゃ重いです。プレビューどころではありません。

構造

大まかな流れは以下になります。
(setup()で以前のフレームデータを消去)→(setup()でフレーム書き出し)→(setup()でffmpegにより動画に変換)→draw()でプレビュー

実装

以下のコードを実行すると、最初にフレーム書き出しや動画への変換が行われ、それが完了すると音声と共にプレビューが始まります。
PBGA_step1.pde

import ddf.minim.*;
import ddf.minim.analysis.*;
import ddf.minim.effects.*;
import ddf.minim.signals.*;
import ddf.minim.spi.*;
import ddf.minim.ugens.*;

boolean render=true;
//フレーム書き出しと動画への変換を行うかどうか。
//falseにするとプレビューのみを行う

int frameSum=1000;

float size=0;

Minim minim;
AudioPlayer player;

void setup() {
  size(600, 600);
  minim=new Minim(this);
  player=minim.loadFile("music.wav");

  if (render) {
    //以前のフレームデータを消去
    launch("C:\\xxxx\\Desktop\\PBGA_step1\\clearFrames");
    
    //フレーム書き出し
    for (int i=0; i<frameSum; i++) {
      display(i);
      if (i%100==0) {
        println("Now I am dumping frame"+i);
      }
      save("frames/"+nf(i, 4)+".png");
    }
    
    //動画に変換。このbatは命令数が多いのでlaunch()から呼ぶと動作が不安定、手動でbatを実行する必要があるかも
    launch("C:\\xxxx\\Desktop\\PBGA_step1\\render");
  }
  player.play();
}

void draw() {
  display(frameCount-1);

  fill(0);
  noStroke();
  rect(0, 0, 100, 100);
  fill(-1);
  text(frameCount-1, 50, 50);
}

void stop() {
  player.close();
  minim.stop();
  super.stop();
}

//--------------------------------------

void display(int t) {
  background(0);
  size=400+300*sin(radians(t*10));

  fill(255, 0, 0);
  noStroke();
  ellipse(width/2.0, height/2.0, size, size);
}

以下は上のコードに必要なbatファイル

clearFrames.bat(フレーム書き出しの前に、以前のフレームデータを消去)

cd C:\\xxxx\\Desktop\\PBGA_step1\\frames
del *.png

render.bat(動画に変換)

cd C:\\xxxx\\Desktop\\PBGA_step1
del out.mp4
ffmpeg -framerate 40 -i frames\\%%4d.png -i music.wav -vcodec libx264 -pix_fmt yuv420p -r 60 out.mp4


動作している様子です。
www.youtube.com


次やること

今の状態では、FPSBPMを考慮して音楽に同期する映像を作る環境が整っていないため、次回はそれをやっていきます。
それではまた次回!