gnaggnoyil
gnaggnoyil

將會取代AviSynth的新工具——VapourSynth

VapourSynth簡介

VapourSynth這個東西估計這裡現在知道的人不多.它是個新出的東西,在今年8月的時候才出現在doom9上,到現在流行了也不過一個月的時間.但是VapourSynth所展現的強大功能和優秀性能已經使其開始被廣泛應用.可以預見VapourSynth將會成為Avisynth的絕佳替代品,而現在VapourSynth的開發路線也表明著這一點.
VapourSynth由doom9上的
Myrsloik開發(
http://forum.doom9.org/showthread.php?t=165771),目前最新版本是r9版.官方網站是
http://www.vapoursynth.com/
簡單的來說,VapourSynth是一個用來支持開發python腳本的frameserver的庫.在安裝python和VapourSynth之後就可以編寫相應的python腳本,輸出相應的raw視頻流來.輸出的raw視頻流通過搭橋,可以送給x264,mencoder,ffmpeg等壓制工具壓制成視頻.
咋看一下VapourSynth和Avisynth沒什麼兩樣,而且後者還不需要安裝python運行環境.然而,VapourSynth相比avisynth擁有如下優點:
1.VapourSynth能夠跨平臺,相比于avisynth只能在windows平臺下運行的特點(linux下運行需要wine avs2yuv.exe),VapourSynth能夠在多平臺內運行生成最終的raw視頻流.
2.VapourSynth具有32位和64位的版本.avisynth的64位版本其鬼畜程度相信用過的人都能體會到.
3.VapourSynth具有原生的多線程處理能力,這對於多核CPU來說是一個非常大的福音.avisynth其所有幀的解碼都是單線程運行的,當濾鏡處理數據較多,運行很慢的時候,avs的解碼速度就成為視頻壓制速度的桎梏.爲了能夠讓AviSynth使用多線程,必須要額外添加濾鏡比如sorathread()或者MP_Pipeline()等等.而VapourSynth的多線程處理則省去了這個麻煩
4.VapourSynth可以加載avisynth的插件,掛載avisynth的濾鏡.當然此時要求VapourSynth必須是32位的windows版本.但是即使是此時,VapourSynth仍然能夠進行多線程處理,即使碰到運行很慢的濾鏡,VapourSynth也能很好的處理.
當然,VapourSynth的缺點也是有的:
1.目前VapourSynth並不支持音頻處理.開發者Myrsloik本人聲稱只有當他明白如何做音頻的frameserver額的時候他才會考慮加入音頻支持.
2.對於windows版沒有VfW支持,這意味著目前無法直接預覽VapourSynth的腳本,只有在命令行下使用mplayer預覽.

3.VapourSynth
對於有些avisynth濾鏡,例如ColorMatrix()和TFM(),TDecimate()濾鏡,支持的不夠好.TFM()和
TDecimate()濾鏡由於其幀處理順序十分奇怪,從而使VapourSynth無法事先知道處理那些幀來加速,因此使得VapourSynth的多線程加速效果大打折扣.但是即便如此,VapourSynth的速度比起avisynth仍然是快了不少的.所以VapourSynth值得一用.
 4.脫離了AviSynth過於簡單的語法結構.藉助Python這種專業的腳本語言,frameserver腳本將可以寫的很強大.

VapourSynth的安裝

接下來以Windows系統為例,介紹VapourSynth的安裝和使用.

要想使用VapourSynth,必須先要安裝Python3.x,并將Python的安裝路徑加入到系統PATH變量中.官網的說明文檔聲稱還需要安裝VC++的SP1再發行組件,不過我沒安裝目前也沒碰到什麽大問題.然
後去官方網站(
http://www.vapoursynth.com/)下載最新版的VapourSynth的windows二進制包.下載后按照官方文檔所言將其解壓到Python安裝路徑的\Lib\site-packages\文件夾中.這樣VapourSynth就安裝完成了.
 安裝后就可以試著用一下了.新建一個文件foo.py,用任意文本編輯器輸入如下內容:
import vapoursynth
 core=vapoursynth.Core()
 print(core. version())
 print(core.list_functions())

打開cmd,運行python foo.py,就會顯示如下內容
 VapourSynth video processing thingamajig
 Core r9
 API r2
 VapourSynth Avisynth Compatibility
         namespace:      avs
         identifier:     com.vapoursynth.avisynth
                 LoadPlugin(path:data;)
 VapourSynth Resize
         namespace:      resize
         identifier:     com.vapoursynth.resize
                 Area(clip:clip;width:int:opt;height:int:opt;format:int:opt;yuvrange:int:opt;)
                 Bicubic(clip:clip;width:int:opt;height:int:opt;format:int:opt;yuvrange:int:opt;)
                Bicublin(clip:clip;width:int:opt;height:int:opt;format:int:opt;yuvrange:int:opt;)
                 Bilinear(clip:clip;width:int:opt;height:int:opt;format:int:opt;yuvrange:int:opt;)
                FastBilinear(clip:clip;width:int:opt;height:int:opt;format:int:opt;yuvrange:int:opt;)
                Gauss(clip:clip;width:int:opt;height:int:opt;format:int:opt;yuvrange:int:opt;)
                Lanczos(clip:clip;width:int:opt;height:int:opt;format:int:opt;yuvrange:int:opt;)
                Point(clip:clip;width:int:opt;height:int:opt;format:int:opt;yuvrange:int:opt;)
                Sinc(clip:clip;width:int:opt;height:int:opt;format:int:opt;yuvrange:int:opt;)
                Spline(clip:clip;width:int:opt;height:int:opt;format:int:opt;yuvrange:int:opt;)
                X(clip:clip;width:int:opt;height:int:opt;format:int:opt;yuvrange:int:opt;)
 VapourSynth Core Functions
         namespace:      std
         identifier:     com.vapoursynth.std
                AddBorders(clip:clip;left:int:opt;right:int:opt;top:int:opt;bottom:int:opt;)
                AssumeFPS(clip:clip;src:clip:opt;fpsnum:int:opt;fpsden:int:opt;)


BlankClip(clip:clip:opt;width:int:opt;height:int:opt;format:int:opt;length:int:opt;fpsnum:int:opt;fpsden:int:opt;color:int[]:opt;)
                 Cache(clip:clip;size:int:opt;fixed:int:opt;)
                CropAbs(clip:clip;width:int;height:int;x:int:opt:link;y:int:opt:link;)
                CropRel(clip:clip;left:int:opt;right:int:opt;top:int:opt;bottom:int:opt;)
                 DoubleWeave(clip:clip;tff:int;)
                FlipHorizontal(clip:clip;)
                 FlipVertical(clip:clip;)
                Interleave(clips:clip[];mismatch:int:opt;)
                 LoadPlugin(path:data;forcens:data:opt;)
                Loop(clip:clip;times:int:opt;)
                 Lut(clip:clip;lut:int[];planes:int[];)
                Lut2(clips:clip[];lut:int[];planes:int[];)
                ModifyProps(clip:clip;selector:func;)
                Reverse(clip:clip;)
                SelectClip(clips:clip[];selector:func;src:clip[]:opt;)
                 SelectEvery(clip:clip;cycle:int;offsets:int[];)
                SeparateFields(clip:clip;tff:int;)
                ShufflePlanes(clips:clip[];planes:int[];format:int;)
                 Splice(clips:clip[];mismatch:int:opt;)
                StackHorizontal(clips:clip[];)
                 StackVertical(clips:clip[];)
                Transpose(clip:clip;)
                Trim(clip:clip;first:int:opt;last:int:opt;length:int:opt;)
                 Turn180(clip:clip;)
VapourSynth的使用

下面我們再來看一個python腳本foo1.py
 #初始化
 import vapoursynth
 import sys
 core=vapoursynth.Core()
 #載入視頻
 core.avs.LoadPlugin(r"D:\soft\encoding\MeGUI\tools\dgindex\DGDecode.dll")
 video=core.avs.MPEG2Source(d2v=r"D:\soft\encoding\SAO_12.d2v",  info=3)
 #向stderr中輸出視頻寬高
 print(video.width,video.height,file=sys.stderr)
 #ITVC處理
 core.avs.LoadPlugin(r"D:\soft\encoding\MeGUI\tools\avisynth_plugin\TIVTC.dll")
 video=core.avs.TFM(c1=video,order=1)
video=core.avs.TDecimate(c1=video,mode=1)
 #切廣告,清除台標,降噪
 video=core.std.Trim(video,693,5583)+core.std.Trim(video,7023,17763)+core.std.Trim(video,19201,37735)+core.std.Trim(video,39174,39533)
 core.avs.LoadPlugin(r"D:\soft\AviSynth 2.5\plugins\delogo.dll")
video=core.avs.EraseLOGO(video,r"D:\soft\encoding\MeGUI\TOKYO MX 1440x1088.lgd")
 core.avs.LoadPlugin(r"D:\soft\encoding\MeGUI\tools\avisynth_plugin\UnDot.dll")
video=core.avs.UnDot(video)
 #調整大小,掛載字幕
 video=core.resize.Lanczos(video,1280,720)
 core.avs.LoadPlugin(r"D:\soft\DirectVobSub\vsfilter.dll")
 video=core.avs.TextSub(video,r"sao12_final.ass")
#向stdout中輸出y4m格式的raw視頻流
 video.output(sys.stdout,y4m=True)
 在
VapourSynth中,一個video clip被定義成了一個類.正如腳本中所示,載入VapourSynth庫后video clip類就能和avisynth的video clip一樣執行連接'+'操作.從這個腳本中我們可以看到VapourSynth是如何使用avisynth插件和濾鏡的.大部份avisynth插件濾鏡都被用於avs命名空間下,使用avs.LoadPlugin()載入插件,使用avs.濾鏡名(參數)來使用濾鏡,而濾鏡的返回值也是一個video clip.
 在這裡順便插幾句.Python腳本的語法和avisynth的語法是不一樣的.比如Python中的所有函數名,變量名等都是大小寫敏感的,而avisynth腳本中的變量名函數名都不是大小寫敏感的.因此,要想正確的使用avisynth濾鏡,就必須明白原濾鏡名的大小寫問題.通常情況下濾鏡的大小寫都可以在avisynth.org上查到.此外,在python語法中'\'被看做是一個保留符,因此對於載入windows下帶路徑的文件,就要注意一下

#下面這條語句是錯誤的
LoadPlugin(path='c:\plugins\filter.dll')
#下面三條語句是正確的
LoadPlugin(path='c:/plugins/filter.dll')
LoadPlugin(path=r'c:\plugins\filter.dll')
LoadPlugin(path='c:\\plugins\\filter.dll')
此外,VapourSynth還提供了很多內置濾鏡.VapourSynth並不能直接使用avisynth的內置濾鏡,作為替代,VapourSynth有很多自帶濾鏡,這些濾鏡幾乎都能替代avisynth的濾鏡,除了原avisynth的DirectShowSource()濾鏡.實際上VapourSynth並不需要DirectShowSource()濾鏡.如果實在需要的話,
https://gist.github.com/3549096 這裡的python腳本就完全可以完成.
常用的VapourSynth內置濾鏡可以去這裡查閱:
http://www.vapoursynth.com/doc/avisynthcomp.html
 當然也有很多可以直接用於VapourSynth的濾鏡插件.這些插件可以使用std.LoadPlugin()來載入,比如這個用來在python腳本中使用avisynth腳本字符串的vsavsreader插件:
http://forum.doom9.org/showthread.php?t=165957
 最後,當獲得所需要的video clip之後,便可以將其輸出了.video.output(sys.stdout,y4m=True)這句話就將video這個video clip的視頻流以y4m格式,輸出到stdout中.
最後就是如何使用這個腳本了.前面說過這個腳本運行之後會將處理后的視頻以y4m視頻流的格式輸出到stdout中.這時候熟悉cmd/shell的人肯定就已經想到了一個東西:pipe.
具體說來,如下所示.
如果要預覽腳本生成的視頻流的話,目前只能使用命令行版本的mplayer播放:
 python foo.py | mplayer - -demuxer y4m
 並且播放時無法快進回退.
如果要使用腳本壓制成視頻,那麼可以使用如下命令行
 python foo.py | x264 --demuxer y4m {x264_options} -o test.mp4 -
 或者
 python foo.py | mencoder - -demuxer y4m -o test.mp4 -of lavf -vf {video filters} -ovc x264 -x264encopts {x264_options} -nosound
 等等.
 VapourSynth和Avisynth的性能比較
 就以上面的VapourSynth腳本為例,等價的avisynth腳本在不加專門的多線程濾鏡的情況下,x264壓制速度只有12fps左右,而如果使用VapourSynth腳本,壓制速度就輕鬆達到17-18fps.而且這還是在TFM()和TDecimate()濾鏡的幀索引順序特別混亂,VapourSynth的多線程優勢無法完全發揮的情況下達到的.

這裡再轉載一個比較:
 Avisynth 2.5.8
 $ time avs2yuv.exe test.avs - > NUL
 test.avs: 640x368, 24000/1001 fps, 5000 frames
 real 1m23.680s
 user 0m0.000s
 sys 0m0.015s
 VapourSynth r3:
 $ time /c/Python32/python.exe test.py > NUL
 real 0m23.753s
 user 0m0.015s
 sys 0m0.000s
Script:
 Code:
 import vapoursynth as vs
 import sys
core = vs.Core(threads=4)
 core.avs.LoadPlugin(path='ffms2.dll')
core.avs.LoadPlugin(path='mvtools2.dll')
 ret = core.avs.FFVideoSource(source='possible rule 6 violation.avi', threads=0)
 ret = core.std.Trim(clip=ret, first=10000, length=5000)
src = ret
 c = core.avs.MSuper(c1=src)
 b1v = core.avs.MAnalyse(c1=c, delta=1, isb=False)
 f1v = core.avs.MAnalyse(c1=c, delta=1, isb=True)
 b2v = core.avs.MAnalyse(c1=c, delta=2, isb=False)
 f2v = core.avs.MAnalyse(c1=c, delta=2, isb=True)
 ret = core.avs.MDegrain2(c1=src, c2=c, c3=b1v, c4=f1v, c5=b2v, c6=f2v)
ret.output(sys.stdout, y4m=True)

可以看出VapourSynth對MDegran的效率提升是很明顯的