2012年9月30日日曜日

VFW module

VapourSynthのr10で新たにVFWモジュールが追加され、Video for Windows(又はDirectShow)を利用してAVIを読み込むソフトウェアでVSのスクリプトを読み込むことが出来るようになりました。
これによりAvsPmodやVirtualDub等でプレビューできるようになったので、この前書いたプレビュー用スクリプトは(Windowsでは)早くも用済みとなった次第です。いや、大変喜ばしい。

この記事はVapourSynth r18までを対象としています。
r19以降では使い方が一部変更されたので、この記事のとおりではうまくいきません。


VFWモジュールの使い方

1.スクリプトを書く

#sample.vpy
import vapoursynth as vs
core = vs.Core()
core.std.LoadPlugin('C:/foo/bar/ffms2.dll')
clip = core.ffms2.Source('D:/hoge/fuga/video.mp4')
clip = core.resize.Bicubic(clip, clip.width. clip.height, vs.YUV420P8)
last = clip

注意する点

・スクリプト名は普通のPythonのように拡張子".py"ではなく、".vpy"として保存すること。

・VFWモジュールを使う場合、出力先に渡すクリップのインスタンス名は必ず'last'とすること。
'last'以外の名前のクリップは渡せません。

・プラグインやソースファイルの読み込みは、ファイルパスを必ずフルパスで記述すること。
相対パスで扱うのは失敗のもとです。

・VFWで渡せるクリップのフォーマットは8bitのみで、10bitや16bitのものは渡せません。
これはVideo for Windowsが8bit以上のものを扱うことを想定していないことによる制限です。

なお、RGBでもVSのRGB24はplanarフォーマットなので、これも使えません。RGBの場合はCOMPATBGR32に変換する必要があります。

・VFWモジュールを使う際は、クリップのoutputメソッドは使えません。

2.読み込ませる


・AviSynthの場合

AviSynthにvpyを読みこませる場合はAVIFileSource(又はAVISource)を使います。


・VirtualDubの場合

通常のaviやavsと違ってVirtualDubではvpyをD&Dで読み込ませることはできません(拡張子vpyがVirtualDubには登録されていないため)。
VirtualDubのメニューから
File -> Open video file
-> 読み込ませるファイルをダイアログで指定 -> 'ファイルの種類'を'AVIFile input driver(compat)(*.avs,*vdr)'に変更 -> '開く’
と、現時点ではちょっと面倒な手順が必要になります。

追記:
こちらの最新テスト版から、vpyを直で開けるようになりました。

・AviUtlの場合

AviUtl0.99k以降であれば、内蔵の'AVI File Reader(Video for Windows)'、または'DirectShow File Reader'でvpyを読み込むことができます。
ただし、AviUtlですので、クリップのフォーマットはCOMPATYUY2に変換しておきましょう。
なお、vpyになんらかの誤りがあった場合(ファイルパスを相対パスで書いたため、読み込みで不備がおこったとか)、AviUtlが固まってエクスプローラごと落ちて一旦Ctrl+Alt+Delでログオフしなければならなくなったりますので、くれぐれも注意しましょう。


・avconv/ffmpegの場合

avconv/ffmpegはAVIの読み込みにはVFWを使用しませんが、avsの読み込みはVFWを使用します。
よって、これを利用すればvpyをpipeを使わずに渡すことができます。
avconv.exe -f avs -i "d:/herp/derp/sample.vpy" -c:v utvideo out.avi
もっとも、こういったコマンドラインツールはPythonスクリプトから操作するなりしたほうがラクだと思います。
10bitYUVとかの入力にも対応してるし。

追記:
2013年3月以降、ffmpeg.exeではこの方法は使えなくなりました(avs読み込みにVFWを使わなくなったため)。
avconv.exeならばまだ使えます。

2012年9月27日木曜日

vsavsreader.dll その2

更新

vsavsreader-10c62ad.7z
https://github.com/chikuzen/VS_AvsReader

更新といっても中身は変わってないのですが、VapourSynthがr9でAPIのバージョンを上げたのでいままでものは使えなくなりました。
いろいろとバグがとれたりしてるようなので、使ってる人はVSと一緒に更新して下さい。

追記:
ちょっとまずいところがあったようなので、修正版に差し替えました。

2012年9月21日金曜日

VapourSynthでプレビュー

とりあえず現時点ではVapourSynthでクリップのプレビューが出来るエディタ等はないので、間に合わせで書いてみました。

#vsshow.py

import vapoursynth as vs
from ctypes import *
from PIL import Image

def show(core, clip, frame_number, vflip=1):
    format = clip.format.id
    width = clip.width
    height = clip.height
    if format == vs.GRAY16:
        clip = core.resize.Point(clip, width, height, vs.GRAY8)
    if format != vs.GRAY8 and format != vs.RGB24:
        clip = core.resize.Bicubic(clip, width, height, vs.COMPATBGR32)

    format = clip.format.id
    planes = range(clip.format.num_planes)
    frame = clip.get_frame(frame_number)
    data = [(frame.get_read_ptr(p), frame.get_stride(p)) for p in planes]
    buff = [b'\0' * data[p][1] * height for p in planes]
    for p in planes:
        memmove(buff[p], data[p][0], data[p][1] * height)

    if format == vs.COMPATBGR32:
        mode, src = 'RGBA', 'BGRA'
    else:
        mode, src = 'L', 'L'
    img = [Image.frombytes(mode, (width, height), buff[p], 'raw', src,
                           data[p][1], vflip) for p in planes]
    if len(planes) != 1:
        img = Image.merge('RGB', (img[2], img[0], img[1]))
    else:
        img = img[0]

    img.show()

使い方
>>> import vapoursynth as vs
>>> import vsshow
>>> core = vs.Core()
>>> core.std.LoadPlugin('vsavsreader.dll')
>>> clip = core.avsr.Eval('ColorBars()')
>>> vsshow.show(core, clip, 1234)

こんな感じで指定したフレーム番号のフレームがプレビューできます。
vsshow.pyはvapoursynth.pydと同じ場所に置いておけばいいです。
ビューワーにはPIL(Python Imaging Library)の仕様上、.bmpファイルに関連付けされているアプリケーションが使われます(MSペイントだったりPicasaだったりMangameeyaだったり)。
なお、Python3用のPILは、こちらからDLしてインストールして下さい。
フレームがYUVの場合のRGB変換はVS内蔵のswscaleが使われる都合上、BT601のlimitted-range限定です。
色々ひどいと我ながら思いますが、ないよりはマシくらいのおおらかな気持ちで使いましょう。

だれかPySideあたりでもっといいの書いてくれないかしら。


Pythonはいろいろ不慣れでこれだけでも苦労しました(おかげでPythonの学習自体ははかどりましたが)。
Twitterでnu774氏(qaacの中の人)に色々アドバイス頂いたおかげで随分助かりました。

vsavsreader.dll

VapourSynth用のプラグインを書きました。

vsavsreader-8e7f46c.7z
https://github.com/chikuzen/VS_AvsReader

使い方
readmeに具体例を書いてあるので、そちらを読んで下さい。

必要なもの
VapourSynth-r8以降
AviSynth2.6alpha3以降

VapourSynthはAviSynth用プラグインをVapourSynthプラグインとして使えるようになってはいますが、対応しているものは2.5x用のもので、2.6以降専用のプラグインは使えません。
また、2.5x用のプラグインでもAviSynthの内蔵フィルタを利用しているものは出力が若干違ったり(DGDecodeで読み込むと、縦1088が1080にCropされないとか)します。
これを使うことにより、RawSource26.dllのような2.6以降用のプラグイン等もVapourSynthで活用できるようになりますし、DGDecodeを使った入力でもCropを改めて掛ける必要はなくなります。

あくまでもVapourSynthでavsを読み込めるようにするだけなので、勘違いはしないよう注意して下さい。

2012年9月12日水曜日

VapourSynth

巷で話題沸騰中?のVapourSynthを、ここ数日ちょこちょこいじっております。

VapourSynthとはffms2でお馴染みのMyrsloikことFredric Mellbin氏によって開発されているもので、
・動画を扱うためのPython3用モジュール。
・AviSynth2.5のプラグインをマルチスレッドで利用できる。
といった特徴があります。

早い話がAviSynthの開発が過去との互換性やらinline-asmやらでMT化も64bit化も一向に進まないので、新しいAviSynthを作ってしまったわけですな。

とりあえず現時点ではまだまだ試作段階ですが、MVTools2やTIVTC(mode次第では)がマルチスレッドで安定して動くあたりを見るに、かなり期待できそうです。

というわけで、試しにこんなのを書いてみました。

#!/bin/env python3
#coding: utf-8

import vapoursynth as vs
import subprocess as sp

class RawSource(object):
    def __init__(self, core, path='C:\\AviSynth2\\plugins\\rawsource_2.5x.dll'):
        self.avs = core.avs
        if core.list_functions().find('RawSource') == -1:
            self.avs.LoadPlugin(path=path)

    def rawsource(self, file):
        return self.avs.RawSource(file=file)


class MVTools(object):
    def __init__(self, core, path='C:\\AviSynth2\\plugins\\mvtools2.dll'):
        self.avs = core.avs
        if core.list_functions().find('MSuper') == -1:
            self.avs.LoadPlugin(path=path)

    def superclip(self, clip, pel=2, chroma=True, sharp=2):
        return self.avs.MSuper(c1=clip, chroma=chroma, sharp=sharp)

    def analyseclip(self, super, delta, blksize=8, overlap=4):
        return [[self.avs.MAnalyse(
            c1=super, delta=d, blksize=blksize, isb=b, overlap=overlap)
            for b in (True, False)]
            for d in range(1, delta + 1)]

    def mdegrain1(self, clip, pel=2, chroma=True, sharp=2, blksize=8,
                  overlap=4, thSAD=400):
        super = self.superclip(clip, pel, chroma, sharp)
        vec = self.analyseclip(super, 1, blksize, overlap)
        return self.avs.MDegrain1(
            c1=clip, c2=super, c3=vec[0][0], c4=vec[0][1], thSAD=thSAD)

    def mdegrain2(self, clip, pel=2, chroma=True, sharp=2, blksize=8,
                  overlap=4, thSAD=400):
        super = self.superclip(clip, pel, chroma, sharp)
        vec = self.analyseclip(super, 2, blksize, overlap)
        return self.avs.MDegrain2(
            c1=clip, c2=super, c3=vec[0][0], c4=vec[0][1], c5=vec[1][0],
            c6=vec[1][1], thSAD=thSAD)

    def mdegrain3(self, clip, pel=2, chroma=True, sharp=2, blksize=8,
                  overlap=4, thSAD=400):
        super = self.superclip(clip, pel, chroma, sharp)
        vec = self.analyseclip(super, 3, blksize, overlap)
        return self.avs.MDegrain3(
            c1=clip, c2=super, c3=vec[0][0], c4=vec[0][1], c5=vec[1][0],
            c6=vec[1][1], c7=vec[2][0], c8=vec[2][1], thSAD=thSAD)

    def mflowblur(self, clip, pel=2, chroma=True, sharp=2, blksize = 8,
                   overlap=4, blur=15):
        super = self.superclip(clip, pel, chroma, sharp)
        vec = self.analyseclip(super, 1, blksize, overlap)
        return self.avs.MFlowBlur(
            c1=clip, c2=super, c3=vec[0][0], c4=vec[0][1], blur=blur)


if __name__ == '__main__':
    core = vs.Core(threads=4)
    rs = RawSource(core)
    mvt = MVTools(core)
    clip = mvt.mdegrain2(rs.rawsource("D:\\source\\derf\soccer.y4m"))
    cmd = ('D:\\tools\\x264.exe - --demuxer y4m --frames %i'
           ' --preset ultrafast -o output.mp4' % clip.num_frames)
    clip.output(sp.Popen(cmd.split(), stdin=sp.PIPE).stdin, y4m=True)

for文やif文、リスト内包表記、そして様々な他のPythonモジュール等が使えるあたり、可能性はAviSynthよりも高そうです。
それにPythonですから、avsと違って仕事や学業等にも汎用的に使えます。
憶えて損はないでしょうね。

2012年9月2日日曜日

avs2pipemod その17

更新しました。

avs2pipemod-0.4.2.7z
https://github.com/chikuzen/avs2pipemod

*エラーチェックを少し強化

avisynthからフレームを受け取った際に-benchmark以外のモードなら、エラーチェックをするようにしました。

追記:
どうも解凍時に不具合が出る人がいるようなのでzip版も上げてみました。
avs2pipemod-0.4.2.zip

2012年9月1日土曜日

RawSource.dll その7

久しぶりに更新

rawsource_26_dll_20120831.zip
https://github.com/chikuzen/RawSource_2.6x

*読み込み用バッファサイズを最大1フレーム分に拡張しスピードアップ。

これまで1ライン分のデータをファイルから読み込んではメモリに書き出していたのをやめて、なるべくBitBltでまとめて処理するようにしました。
手元の計測では201109版に比べてPlanarフォーマット及びBGR/BGRA/YUY2の場合、4~7倍くらい速くなりました。