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

はじめに
Linux 上で、シーンカットやリサイズなどの編集を含めた動画エンコードをする場合、GUI であれば、Avidemux で簡単な処理は行えます。

しかし、x264 などのコマンドを使ってエンコードしたい場合や、エンコード速度を重視したい場合、また、より高度な編集を行いたい場合は、VapourSynth を使います。
VapourSynth について
公式サイト: http://www.vapoursynth.com/

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

AviSynth と異なるのは、スクリプト言語に Python3 を使っている点です。
VapourSynth のインストール
VapourSynth のスクリプトは Python3 で動作するので、まずは Python3 のインストールが必要です。

ディストリビューションによっては、最初からインストールされている場合もありますが、インストールされていない場合は、手動でインストールしてください。
Arch Linux の場合は、python パッケージです。

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

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

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

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

常に使うようなプラグインは、指定ディレクトリに置いておくと、プラグイン読み込みの記述を省略できます。
たまにしか使わなかったり、特定のスクリプトでしか使わないようなプラグインは、手動で読み込ませると良いでしょう。

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

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

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

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

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

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

※このプラグインでは、音声データは読み込まれません。

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

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

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

作成された libdamb.so ファイルを、プラグイン用のディレクトリにコピーしてください。
VapourSynth ビューアのインストール
スクリプトをプレビューして出力画像を確認したい場合や、カットするフレームの位置を確認したい場合は、VapourSynth スクリプトのエディタやビューアが別途必要になります。

※ VapourSynth R55 から、API に ver 4 が加わりました。VapourSynth R55 以降の環境で、API 3.x を使っているソフトを使用すると、正しく動作しない場合があります。

vasviewer自作の簡易ビューア。X11
VapourSynth Editor 2エディタ+ビューア。Qt5
API4 に対応。
VapourSynth Editorエディタ+ビューア。Qt5
API3 を使っているので、最新の VapourSynth では、画像が表示できません。

ソースコードからビルドする場合は、各ソフトの説明書を読んでください。
動作確認
動作に必要なものをインストールしたら、実際に VapourSynth が実行できる状態にあるか、確認してみます。
以下の内容を、test.vpy という名前でテキストファイルに保存してください。

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

test.vpy があるディレクトリ上で、以下のコマンドを実行します。
(python3 コマンドでスクリプトを読み込んで、実行します)

$ python3 test.vpy

VapourSynth Video Processing Library
Copyright (c) 2012-2021 Fredrik Mellbin
Core R57
API R4.0
API R3.6
Options: -

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

import vapoursynth as vs

core = vs.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.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 ライブラリを読み込んで、使えるようにします。
    この時、使いやすいように、'vapoursynth' を 'vs' として、名前を変更します。

  • core = vs.core
    VapourSynth のメイン機能である、コアオブジェクトを取得します。
    ※以前は "core = vs.get_core()" で取得していましたが、非推奨の期間を経て、現在では使用できなくなりました。

  • 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 のエディタやビューアを使います。

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

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

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

#!/usr/bin/python3

import vapoursynth as vs
core = vs.core
c = core.ffms2.Source(source='video.mkv')
c.set_output()
vspipe を使ってエンコード
スクリプトができたら、実際に映像をエンコードしていきます。

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

vspipe から出力される映像は、無圧縮のデータとなります。
-c y4m オプションで、y4m フォーマットのヘッダが付加され、映像の基本情報が渡されます。
以前は --y4m オプションでしたが、現在は -c で出力コンテナを指定する形となっています。

x264 コマンド側では、標準入力から、映像データを受け取ります。
--demuxer y4m で、入力が y4m フォーマットであることを指定します。

なお、デフォルトで、サンプリング比 (sar) が 0:0 (unknown) になってしまうので、x264 側の --sar オプションで、サンプリング比を指定してください。
Next
ここまでは、VapourSynth の基本情報を紹介しました。
次は、実際に、映像と音声をエンコードする手順を紹介していきます。