(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 のプラグインは共有ライブラリファイル (*.so) です。
プラグインは特別なインストール処理は必要なく、任意の場所、または VapourSynth 用のプラグインディレクトリにファイルを置いておくだけです。

プラグインの自動読み込み
VapourSynth は、システムのプラグインディレクトリと、ユーザー用のプラグインディレクトリが定義されていて、そこにあるプラグインファイルは、スクリプトを実行した時に自動で読み込まれます。
なので、それらのプラグインディレクトリにあるファイルは、スクリプト内で LoadPlugin() を記述して読み込む必要はありません。

システムのプラグインディレクトリは、VapourSynth を /usr にインストールした場合、/usr/lib/vapoursynth ディレクトリとなっています。
ユーザー用のプラグインディレクトリは、デフォルトで空です。

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

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

SystemPluginDir を変更したくない場合は、その行は記述しないでください。
UserPluginDir -> SystemPluginDir の順でプラグインが読み込まれます。
必要なプラグインの用意
必要なプラグインは、インストールまたはビルドしておきます。
公式サイトにプラグインの一覧があるので、それを参考にしてください。

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

音声サポート
音声ファイルを読み込んで、シーンカットを行いたい場合は、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 の開発環境が必要です。

## 作業用のディレクトリ上で実行します
$ git clone --depth 1 https://bitbucket.org/mystery_keeper/vapoursynth-editor.git
$ cd vapoursynth-editor/pro
$ qmake-qt5
$ make

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

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

そのファイルがあるディレクトリで、以下のコマンドを実行します。
※ Python3 コマンドのファイル名やパスが異なる場合は、python3 の部分を置き換えてください。

$ python3 test.vpy

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

バージョン情報などが出力されれば成功です。
スクリプトファイルを書く
スクリプトファイルの拡張子は、*.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')
    手動で指定したプラグインを読み込みます。
    プラグインファイルのパスを、絶対パスまたは相対パスで指定してください。
    自動で読み込まれるプラグインディレクトリに置いてあるファイルは、記述する必要はありません。

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

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

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

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

    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 にするので、8bit なら vs.YUV420P8、10bit なら vs.YUV420P10 にします。
    フォーマットの一覧は、Python3 上で「import vapoursynth as vs; print(dir(vs))」のコードで表示できます。

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

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

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

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

#!/usr/bin/python3

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

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

プレビュー中は、時間のバー部分をドラッグでシークができます。
細かい位置調整をする場合は、バーの左側にあるフレーム位置のエディタ部分をクリックして、入力フォーカスを置き、矢印の上下キーを押すと、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)