(Linux) VapourSynth で動画エンコード

はじめに
Linux でシーンカットやリサイズなどの編集を含めた動画エンコードをする場合、GUI なら Avidemux で簡単な処理は行えます。
しかし、x264 などのコマンドを使ってエンコードしたい場合や、速度を重視したい場合、また、より高度な編集を行いたい場合は、VapourSynth を使います。
VapourSynth について
公式サイト: http://www.vapoursynth.com/

Windows の AviSynth と同じように、スクリプトを記述して動画を処理します。
Windows/Linux/Mac OS X に対応しています。

AviSynth と違うのは、スクリプト言語に Python3 を使っている点と、まだ正式には音声のサポートが行われていない点です。
(プラグインで簡単な音声読み書きはできるので、映像のカットに合わせて音声をカットするだけの処理なら出来ます)
VapourSynth のインストール
VapourSynth スクリプトの動作には Python3 が必要なので、まずは Python3 のインストールが必要です。
Arch Linux の場合は、python パッケージ。

次に、VapourSynth のインストールです。
Arch Linux では、公式に vapoursynth パッケージがあります。
公式にパッケージがない場合は、VapourSynth のサイトにインストールの手順が書かれているので、そちらを参考にしてください。
プラグインについて
VapourSynth のプラグインは、共有ライブラリファイル (*.so) です。

プラグインの読み込み方法
プラグインは、以下のいずれかの方法で読み込めます。

(1) VapourSynth 指定のプラグイン用ディレクトリに置いて、自動で読み込ませる。
(2) スクリプト内で LoadPlugin() を記述して、手動でプラグインを読み込む。

VapourSynth 指定のディレクトリに置いておくと、そこにあるすべてのプラグインが、スクリプト実行時に自動で読み込まれます。

常に使うようなプラグインは指定ディレクトリに置いたり、たまにしか使わないようなプラグインは手動で読み込むといったように、使い分けることもできます。

プラグインのディレクトリ
VapourSynth のプラグインディレクトリは、「システム用」 と 「ユーザー用」 の2つのディレクトリに分かれています。

システム用主に、パッケージからインストールしたプラグインが置かれる場所。
/usr にインストールした場合、デフォルトで /usr/lib/vapoursynth
ユーザー用ユーザーが自分でダウンロードしたプラグインを置く場所。
デフォルトで空 (ユーザーが自分で指定する)。

プラグインディレクトリを指定したい場合は、VapourSynth 用の設定ファイルを作成します。
~/.config/vapoursynth ディレクトリを作成し、その中に vapoursynth.conf というテキストファイルを作って、以下の内容を記述します。

UserPluginDir=<ユーザー用のディレクトリパス>
SystemPluginDir=<システム用のディレクトリパス>

システム用のディレクトリを変更しない場合は、SystemPluginDir の行は記述しないでください。
ユーザー用 → システム用の順でファイルが検索され、プラグインが読み込まれます。
必要なプラグインの用意
必要なプラグインは、あらかじめ、インストールまたはビルドしておきます。
公式サイトにプラグインの一覧があるので、それを参考にしてください。

読み込みプラグイン
まず最初に、動画を読み込むプラグインが必要です。
FFMS2 は ffmpeg/libav のライブラリを使うので、大抵の動画は読み込めます。
Arch Linux の場合は、公式に ffms2 パッケージがあります。

※ VapourSynth はまだ音声のサポートを行っていないので、このプラグインでは、音声データは読み込まれません。

音声サポート
シーンカットを行いたい場合は、音声データを読み込む必要があるので、Damb を使います。
このプラグインでは、音声の読み込みと出力しか行えないので、「読み込み→シーンカット→カット後の音声出力」という動作しかできません。

Arch Linux の場合、AUR に vapoursynth-plugin-damb-git があります。

<ソースコードからビルドする場合>
$ ./autogen.sh
$ ./configure
$ make

作成された libdamb.so ファイルをプラグイン用のディレクトリにコピーしてください。
VapourSynth Editor のインストール
スクリプトをプレビューして画像を確認したい場合や、カットするフレームの位置を確認したい場合は、VapourSynth Editor を使います。
これは、VapourSynth 用の簡易エディタです。
Arch Linux の場合、AUR に vapoursynth-editor-git があります。

ビルド手順
※ Qt5 で作られているので、ビルドには Qt5 の開発環境が必要です。
Arch Linux の場合、ビルド時に「git qt5-base qt5-websockets」のパッケージが必要です。

## ソースファイルをダウンロード
$ git clone --depth 1 https://bitbucket.org/mystery_keeper/vapoursynth-editor.git

## ビルド
$ cd vapoursynth-editor/pro
$ qmake-qt5
$ make

vapoursynth-editor/build ディレクトリに、作成されたバイナリがあります。
vsedit がメインの実行ファイルです。
なお、インストールはしなくても、vsedit ファイルだけあれば実行できます。
動作確認
ちゃんと VapourSynth が実行できる状態にあるか、確認してみます。
以下の内容を test.vpy という名前でテキストファイルに保存してください。

import vapoursynth as vs
core = vs.get_core()
print(core.version())

そのファイルがあるディレクトリで、以下のコマンドを実行します。
(python3 コマンドでスクリプトを読み込んで、実行します)

$ python3 test.vpy

VapourSynth Video Processing Library
Copyright (c) 2012-2017 Fredrik Mellbin
Core R37
API R3.4
Options: -

バージョン情報などが出力されれば成功です。
スクリプトファイルを書く
VapourSynth スクリプトの拡張子は、*.vpy にします。
中身は、基本的に Python3 スクリプトと同じ方法で書いていきます。
サンプルスクリプト
1. 映像のみ、シーンカットとリサイズ
#!/usr/bin/python3

import vapoursynth as vs

core = vs.get_core()
clip = core.ffms2.Source(source='video.mkv')
clip = clip[0:100] + clip[200:300] + clip[500:]
clip = core.resize.Spline36(clip,width=1280,height=720,format=vs.YUV420P8)
clip.set_output()

2. 映像と音声のシーンカットとリサイズ
#!/usr/bin/python3

import vapoursynth as vs

core = vs.get_core()

core.std.LoadPlugin('libdamb.so')

clip = core.ffms2.Source(source='video.mkv')
clip = core.damb.Read(clip, 'audio.wav')

clip = clip[0:100] + clip[200:300] + clip[500:]

clip = core.resize.Spline36(clip,width=1280,height=720,format=vs.YUV420P8)

clip = core.damb.Write(clip, 'out.wav')
clip.set_output()
解説
VapourSynth のスクリプトファイルには実行権限を付ける必要はないので、そのまま普通のテキストファイルとして扱ってください。
行頭 (空白・タブは除く) が 「#」 の場合、その行はコメントとして扱われます。

  • #!/usr/bin/python3
    一行目は必ず Python3 のコマンドのパスを記述する必要があります。
    この行で Python3 コマンドの場所が取得されて実行されます。
    コマンドのパスが異なる場合は、変更してください。

  • import vapoursynth as vs
    VapourSynth ライブラリを読み込んで、使えるようにします。

  • core = vs.get_core()
    VapourSynth のメイン機能のオブジェクトを取得します。

  • core.std.LoadPlugin('libdamb.so')
    プラグインを手動で読み込みます。
    プラグインファイルのパスを、絶対パスまたは相対パスで指定してください。
    VapourSynth 指定のプラグインディレクトリに置いてあるファイルは、記述しなくても自動で読み込まれます。

  • clip = core.ffms2.Source(source='video.mkv')
    FFMS2 プラグインで、動画ファイルから映像を読み込み、clip 変数に格納します。
    以降は、読み込んだデータを編集する場合、clip 変数を使います。
    なお、動画内の音声データは読み込まれません。

    FFMS2 で動画が読み込まれると、動画ファイルと同じディレクトリにキャッシュファイル (*.ffindex) が作成されます。
    キャッシュファイルがあると、以降の読み込みの処理が速くなります。
    キャッシュファイルが必要なくなった場合は手動で削除してください。

  • clip = core.damb.Read(clip, 'audio.wav')
    映像に合わせて音声もシーンカットしたい場合は、Damb プラグインで音声ファイルを読み込みます。
    Damb が対応している形式は、WAV, W64, FLAC, OGG です。
    基本的には、元動画から音声を取り出し、WAV 変換したファイルを使ってください。

  • clip = clip[0:100] + clip[200:300] + clip[500:]
    フレーム単位でのシーンカットを行います。
    フレーム位置は、0が先頭です。
    切り取る部分の範囲ではなく、残したい部分の範囲を指定して、それらを連結させます。

    clip[0:100]clip から [ 先頭位置 0 〜 フレーム位置 99 ] の範囲のデータを取り出します。
    clip[200:300][ フレーム位置 200 〜 299 ] のデータを取り出します。
    clip[500:][ フレーム位置 500 〜 終端 ] のデータを取り出します。

    最終的に、取り出した3つの範囲のデータを + で連結して、clip に再セットしています。

    [○:○] において、左側は取り出す先頭位置、右側は取り出す終端位置+1の位置です。
    ※ 右側の位置は+1することに注意してください。
    0〜99 の範囲のデータを取り出したいなら、[0:100] と記述します。
    右側の値を省略すると、終端までとなります。

  • clip = core.resize.Spline36(clip,width=1280,height=720,format=vs.YUV420P8)
    映像のリサイズを行います。
    拡大縮小の方法は、Bilinear, Bicubic, Lanczos, Point, Spline16, Spline36 があります。
    Spline36 が一番高品質かと思います。

    width, height で幅と高さを指定。
    format でリサイズ後のカラーフォーマットを指定します。
    x264 でエンコードする場合は YV12 が最適なので、通常は vs.YUV420P8、10bit なら vs.YUV420P10 にします。

    フォーマットの一覧は、以下のスクリプトコードで確認できます。
    import vapoursynth as vs
    print(dir(vs))


  • clip = core.damb.Write(clip, 'out.wav')
    シーンカットした音声データを、別のファイルに出力します。
    出力先のファイル名を指定してください。
    映像のフレームが処理される毎にその位置の音声データが出力されていくので、映像が最後まで処理されないと、音声も最後まで出力されません。

  • clip.set_output()
    最後に、映像のデータを出力します。
VapourSynth Editor で確認
実際にエンコードする前に処理後の映像を確認したい場合や、カットするフレーム位置の確認をしたい場合は、VapourSynth Editor を使います。

※ スクリプト内に Damb の音声処理を記述している場合、プレビュー中に音声ファイルが出力されてしまうので、音声処理部分は消すか、コメントにしてください。

vsedit コマンドを実行して起動し、スクリプトファイルを読み込みます。
メニューの 「Script」 > 「Preview」 でプレビュー表示が行えます。

最初のプレビュー時は、画面が表示されるまで少し時間がかかるかもしれません。
FFMS2 プラグインでの動画読み込み時にキャッシュファイルが作成されているためです。

カット時のフレーム位置確認
カットするフレーム位置の確認だけしたい場合は、以下のように映像を読み込むコードだけを書いたスクリプトを用意して、プレビューします。

#!/usr/bin/python3

import vapoursynth as vs
core = vs.get_core()
c = core.ffms2.Source(source='video.mkv')
c.set_output()

使い方
プレビュー中は、時間のバー部分をクリック/ドラッグでシークができます。
細かい位置調整をする場合は、バーの左側にあるフレーム位置のエディタ部分をクリックして、入力フォーカスを置き、上下キーを押すと (上で +1、下で -1)、1フレーム単位で位置を移動できます。
また、上下キーを押した後は、常にフレーム位置のテキストが全選択された状態になるので、そのまま Ctrl+C を押せばクリップボードにコピーできるため、便利です。
vspipe を使ってエンコード
スクリプトができたら、実際に映像をエンコードしていきます。

VapourSynth 用のツールである vspipe コマンドを使うと、指定したスクリプトを処理して、結果の映像をファイルまたは標準出力に出力できます。
基本的には、パイプでつないでエンコーダに渡します。
x264 コマンドでエンコード
$ vspipe --y4m enc.vpy - | x264 --demuxer y4m --sar 1:1 - -o out.mp4 ...

vspipe から出力される映像は、無圧縮のデータとなります。
--y4m オプションで、y4m フォーマットのヘッダが付加され、映像の基本情報が渡されます。

x264 側では、標準入力から映像データを受け取ります。
--demuxer y4m で、入力が y4m フォーマットであることを指定します。
なお、デフォルトでサンプリング比 (sar) が 0:0 (unknown) になってしまうので、x264 側で --sar でサンプリング比を指定してください。
Next
ここまでは、VapourSynth の基本情報を紹介しました。
次は、実際に映像と音声をエンコードする手順を紹介していきます。

>> VapourSynth で動画エンコード (2)