Skip to content
Nekopanda edited this page Nov 23, 2018 · 10 revisions

Avisynth Neo(ダウンロードはこちら)は Avisynth+ をベースに拡張されたAvisynthの派生版です。

Avisynth+で追加された機能はAvisynth+を参照。

新しい構文が追加されているので、AvsPmodは対応版を使うことを推奨します。

以下、Neoで追加された機能の説明です。

CUDA対応

専用に書かれたCUDA対応フィルタを使うと、CUDAで処理できます。CUDAフィルタはOnCPUとOnCUDAで囲います。

サンプルスクリプト(KNNEDI3はKTGMCに含まれてるKNNEDI.dllが必要)

srcfile="..."
LWLibavVideoSource(srcfile)
OnCPU(2)
KNNEDI3(field=-2)
OnCUDA(2)

OnCPUとOnCUDAでGPUとCPU間のデータ転送が行われます。OnCPUは「OnCPUの前までをCPUで動かす」という意味です。OnCPUより「後」じゃなくて「前」です。OnCUDAも同様です。

最後のOnCUDAを忘れると酷いことになるので気をつけてください。

CUDA用にNeoで追加された関数

OnCPU(clip, int "num_prefetch")

指定したクリップをCPUで処理します。

  • clip
    • このクリップはCPUで処理されます。つまり、これより前の処理がCPUで処理されます。
  • int num_prefetch = 0
    • ここでプリフェッチするフレーム数を指定します。2くらいでだいたい十分な性能が出ます。GPUとCPUでの処理を並列化するためのプリフェッチなので、Prefetchと違ってスレッドは1つだけです。0を指定するとスレッドを使わず同期呼び出しになります。

OnCUDA(clip, int "num_prefetch", int "device_index")

指定したクリップをGPUで処理します。

  • clip
    • このクリップはCUDAで処理されます。つまり、これより前の処理がCUDAで処理されます。CUDA処理に対応していないフィルタはエラーになります。現状、内部フィルタはほとんど対応していないので、使えるのは専用に作られた外部フィルタだけです。
  • int num_prefetch = 0
    • OnCPUのプリフェッチと同じです。
  • int device_index = 0
    • 実行するGPUを指定します。GPUが1つしかない場合は0しか使えません。GPUが2つあれば0か1が指定できます。数の制限とかはありません。

OnCPU/OnCUDAのより詳しい動作

SetDeviceOpt(int)

オプション設定

  • int
    • 以下の値が使用できます。
      • DEV_CUDA_PINNED_HOST: CPU側フレームデータをpinnedメモリで確保することで、GPU⇔CPU間データ転送が速くなります。ただし、pinnedメモリは物理メモリを専有するので、システムのメモリが足りなくなると不安定になるかもしれません。

SetMemoryMax(int, int "type", int "index")

元からある関数ですが、GPUなどのデバイス用に引数が追加されています。GPUなどのデバイスは個別にメモリ使用量が管理されています。

  • int
    • デバイス(CPUを含む)のメモリ上限(MB)
  • int type = DEV_TYPE_CPU
    • デバイスのタイプ。以下の値が使用できます。
      • DEV_TYPE_CPU: CPU
      • DEV_TYPE_CUDA: GPU
  • int index = 0
    • デバイスの番号。OnCUDAのdevice_indexと同じです。DEV_TYPE_CPUの場合は0のみ。

MT改良

オリジナルのPlusでは、Prefetchが1つしか使えませんでしたが、Neoではいくつでも使えます。また、プリフェッチするフレーム数を指定する引数が追加されています。

Prefetch(clip, int "threads", int "frames")

  • clip
    • 並列化するクリップ
  • int threads = (システムの論理コア数)+1
    • スレッド数。0だと何もしないで素通りします。
  • int frames = threads * 2
    • プリフェッチするフレーム数。これも、0だと何もしないで素通りします。

例: パイプライン並列化

フィルタ処理A
Prefetch(1,4)
フィルタ処理B
Prefetch(1,4)
フィルタ処理C
Prefetch(1,4)

Prefetch(1,4)は、1スレッド立てて4フレーム先読みさせます。上の例では、フィルタ処理A,B,Cがパイプライン的に並列化されて実行されます。各Prefetchのスレッド数は任意なので、例えばフィルタ処理Bが重いので、そこだけ並列数を増やしたい場合は、以下のようにスレッド数を増やせます。

フィルタ処理A
Prefetch(1,4)
フィルタ処理B
Prefetch(4)
フィルタ処理C
Prefetch(1,4)

フィルタグラフダンプ機能

フィルタ処理の流れをグラフとして出力する機能です。avsスクリプトの最初にSetGraphAnalysis(true)を置いて、出力クリップに対して、DumpFilterGraph()を呼び出すと、フィルタグラフを出力します。

例)

SetGraphAnalysis(true)
srcfile="..."
LWLibavVideoSource(srcfile)
QTGMC()
DumpFilterGraph("graph.txt", mode=2)

dot形式で出力されるので、以下のようにGraphvizで画像に変換できます。

dot -Tsvg graph.txt -o graph.svg

SetGraphAnalysis(bool)

  • bool
    • インスタンス化されるフィルタへのグラフノード挿入を有効化(True)もしくは無効化(False)します。フィルタグラフを出力するには、フィルタにグラフノードが挿入されている必要があります。グラフノードが挿入されると、内部の関数呼び出しが増えるので、若干性能が落ちる可能性があります。(ほとんどの場合、観測できるような性能低下はないと思います。)

DumpFilterGraph(clip, string "outfile", int "mode", int "nframes", bool "repeat")

フィルタグラフを出力します。

  • clip
    • フィルタグラフを出力するクリップ
  • string outfile = ""
    • 出力ファイルパス
  • int mode = 0 *
  • int nframes = -1
    • 指定フレームを処理するときにフィルタグラフを出力します。その時点での各フィルタのキャッシュサイズとメモリ使用量が一緒に出力されます。各フィルタのメモリ使用量を把握したい場合に有効です。-1の場合は、DumpFilterGraph呼び出し時(フレームが処理される前)に出力します。
  • bool repeat = false
    • nframes>0の場合のみ有効です。nframes間隔で繰り返しフィルタグラフを出力します。

CUDAフィルタの開発方法

サンプルAviSynthCUDAFiltersを見てください。

また、デバイスチェックPlugin Interface 仕様も参考になると思います。