2011年12月31日土曜日

avs2pipemod その9

更新しました。

avs2pipemod-20111230.zip
https://github.com/chikuzen/avs2pipemod

*ビデオ出力処理をavs2pipeの最新のものから移植。

久しぶりにdoobry氏がDoom9に現れgithubのレポを公開しました。
さっそく最新のコードを見てみると…うーむ、こんな手があったのか。
手元のベンチマーク結果をみてもこれのほうが速かったので、早速パクりました。
つくづく彼のコードは自分にとって素晴らしい教材です。

追記
たくあん氏から、以前のバージョンより遅くなっているとの報告を受けたので、検証して見ました。
#sample.avs
LoadPlugin("DGDecode.dll")
MPEG2Source("1400x1080x2990frames.d2v", idct=3)

これを前回(20110911)と今回(20111230)で比較
pattern1:
 $ time avs2pipemod -y4mp sample.avs > sample.y4m
pattern2:
 $ time avs2pipemod -y4mp sample.avs | x264 - --demuxer y4m --preset ultrafast -o sample.264
pattern3:
 $ time avs2pipemod -y4mp sample.avs | x264 - --demuxer y4m --preset medium -o sample.264

それぞれを3回ずつ回すと(数値はエンコード終了までの時間)
              pattern 1      |      pattern2      |      pattern3
          20110911  20111230 | 20110911  20111230 | 20110911  20111230
1st(sec)   122.094   112.451 |   39.919    42.416 |  181.153   183.238
2nd(sec)   122.200   113.405 |   40.099    42.426 |  183.994   182.490
3rd(sec)   118.490   114.094 |   39.976    42.716 |  184.112   182.664
avg(sec)   120.928   113.317 |   39.998    42.519 |  183.086   182.797
他のエンコーダにpipeせず、直接y4mやrawで保存する場合は20111230のほうが速いです。
そして、他のエンコーダにpipeした場合は、以前の方が速くなります。
エンコーダ側の設定がある程度重くなると律速する…どうしようかなぁ…。

現実的な使用例を考えるとpattern2よりも1か3の使い方のほうが多いと思いますので、このまま行くことにします。

2011年12月9日金曜日

AviSynth Script Reader for AviUtl

VFR_maniac改めMP4_maniac氏がlsmashinput.aui(L-SMASHとLibavを利用したAviUtl用入力プラグイン)を発作的に書き始めてしまったのに付き合っていた流れで、AviUtlの入力プラグインの書き方が少しだけ理解できるようになった。

AviUtlといえば前から不思議に思っていたのが「なぜavsを読むのにわざわざ別に入力プラグインが必要なのか」である。
そもそもAviSynthはスクリプトをAVIに偽装するソフトウェアである。
もし任意のソフトウェアがVFWのAVIFileOpen関数を使って拡張子がavsのファイルを開こうとすれば、レジストリ登録情報によりavisynth.dllが動いて、ただのテキストはAVIとして扱われるような仕組みになっている。
AviUtlにはVFWを使用する入力プラグイン(AVI File Reader)が内蔵されているのだから、本来外部プラグイン(avsinp.aui)は必要ないはずなのだ。

で、このたびPluginSDKのサンプルコード(avi_input.cpp)を読んでみたら、疑問はすぐに解決した。
AviUtlは、まずファイルの拡張子を見てプラグインが対応しているかどうかを判別するため、*.avsというファイルはAVI File Readerには渡されないというだけのことだった。

てなわけで、ちょっと実験。
まず、avi_input.cppのINPUT_PLUGIN_TABLE構造体のfilefilter変数の中身を*.aviから*.avsに変更。
入力プラグイン名をAviSynth Script Reader (VFW)にして、コメント以外の日本語文字を除去(CP932は色々面倒)、ついでにファイル名を.cppから.cにして(avi_input.cppはC++ではなくCで書かれている)、あとはGCCでコンパイルしてやれば…
gcc -c avi_input.c -o avsread.o
gcc -o avsread.aui -shared -Wl,--dll,--add-stdcall-alias avsread.o -lavifil32
ああ、読めた。

つまり、KENくん氏が内蔵のAVI File Readerに拡張子*.avsを追加してくれれば、avsinp.auiは要らなくなるんだよなぁ…。

2011年10月15日土曜日

Oneiric入れてみた

Ubuntu11.10(OneiricOcerot)が出たのでWindows7上のVMWarePlayer3.1.4(4.0は様子見中)に入れてみました。

インターフェース
とうとうVMWarePlayerでもUnityになってしまいました。
まあ、UbuntuのUIは最初に9.10を入れたときの感想が「なんか林檎臭くてやな感じ」で特に気に入っていたわけでもありませんし、別にどうということもありません。
メインで使ってるわけでもないし、多分一ヶ月もすれば慣れてるんじゃないかと思います。
それに当たり前のことではありますが、Terminalの使い勝手はMSYSやCygwinよりも遥かにいいわけですしね。
(でも、画面左のランチャーは、Windows7のタスクバーに比べて遥かに糞だと思います)

さて、自分にとってとりあえず重要なのはwine(というか、avisynthが動くこと)とmingwですので、早速試してみることにしましょう。

wineとavisynth
wineは使い始めた当初よりLatest official releaseのPPAを利用しています。
launchpadに行ってみたら、Oneiric用のパッケージも既に配布されていました。
今後は1.3だけの配布になるのかな?
$ sudo add-apt-repository ppa:ubuntu-wine/ppa
$ sudo apt-get update
$ sudo apt-get install wine1.3
あとはsourceforgeからavisynth2.6.0α3とVirtualDubをDLして、avisynthはwine経由でインストール、VirtualDubは~/.wine/drive_c/Program Files以下に展開。

さて、ここで注意したいのは、最近のwine1.3ではそのままではavisynthが動かないこと。
どうやらmsvcrt関連に1.3.1xのあたりで大きな変更があったらしく、runtimeの追加が必要になっています。
と言ってもやることは簡単で、Winetricks->Select the default wineprefix->Install a Windows DLL or componentでvcrun6をインストールするだけです。
Windows実機でMicrosoftからVC++XX再頒布可能パッケージとかをDLしてインストールするよりも遥かに速くて楽ですし、どのWindowsアプリケーションでどのruntimeが要求されるかもわかりませんので、vcrun*は全て入れてしまってもいいかも知れません。
これでavisynthは動きます。

mingw
GCCを使ったWindows用アプリケーションのビルドは、MSYSやCygwinよりもLinux上でクロスコンパイルしたほうが速いです。
特にconfigureのスピードは桁違いで、MSYS環境だと3分はかかるffmpegのconfigureが、LinuxだとVM上でも15秒で終わります。
ただ11.04までのUbuntuのmingw関連は、mingw32はGCC4.2.1のまま放置、mingw-w64はGCCこそ4.4.3と少しはマシのようだけどいろいろぶっ壊れていたりして、使いものになりませんでした(getopt.hとかが無いってどーいうことよ?)

さて、今回のパッケージはどうでしょうか?
とりあえずmingw32のほうは相変わらず放置のままのようですが、mingw-w64はGCC4.6.1に更新されていて抜けていたヘッダーもちゃんとあります。
triplexもi586-mingw32msvc/amd64-mingw32msvcという「お前はGCCなのかMSVCなのかはっきりしろ」と言いたくなるようなDebian流のものから、i686-w64-mingw32/x86_64-w64-mingw32というmingw-w64の標準的なものに変更されてていい感じです。

しかし、ここで一つ問題に気づきました。
このパッケージにはlibvfw32.aが入っていません。
mingw-w64はmingw32よりも開発が活発でどんどん良くなっていってはいるのですが、まだまだいくつかライブラリに抜けがあったりして、ときどきハマることがあります。
libvfw32.aが追加されたのはたしか7月の終わりあたり…そしてこのパッケージはバージョンを見ると5月終わり頃のもののよう。
折りしもmingw-w64は数日前にv2.0をリリースしたばかりだし、GCCも4.6.2がすぐに出ます(っていうか、たしか今月頭に出るはずだったんだが)…結局今回も11.04同様、自ビルドすることになりそうですorz

2011年10月11日火曜日

GPL violation?

x264LLCと契約した某社が、libx264を使うBD用エンコードソフトのベータ版を出した」とkierank氏に聞いたので、ダウンロードしてみることにした。
まずは配布ページに行ってユーザー登録。次にインストーラをDL。
商用ソフトのベータ版というだけあってインストーラはinnoやmsiではなく最新のInstall Shieldだった。うーむ、これでは7zipでは解凍できないね。
仕方ないのでインストーラをダブルクリックしてみると、EULAの次に表示されたのがこれ。
えー、なんでー? これって商用なんでしょ?
正式リリース後はお金払わなきゃ使えなくなるんでしょ?
開いたままふさがらない口を閉めつつ、早速カスタマーサポートに次のようなメールを送ってみることにした。
この度御社のhogehogeベータ版をインストールしたところ、fugafuga.dllのライセンスに関して、
GNU General Public License Version3であるとの提示がありました。
GPLなプログラムを配布する場合は、そのプログラム自体のソースコードはもとより、プログラムをプラグインとして
使用するアプリケーション本体等に関しても、OSやコンパイラが提供する「システムライブラリ」以外は全て
ソースコードの開示義務が発生することはご存知であると思います。
つきましては、GPLで保護された配布物の受領者として、全ソースコードの開示請求の権利を行使いたしたく思います
ので、よろしくお取り計らいいただけますようお願いいたします。
でもって数日後に返ってきたお返事はこんな感じ
お問い合わせの件ですが、まず、fugafuga.dllについては、GPLライセンス下のプログラムとなりますので、
ご要望とあれば、ソースコードを郵送でお送りさせていただきます。お届け先のお名前、ご住所、お電話番号を
お知らせください。
また、「(GPL)プログラムをプラグインとして使用するアプリケーション本体等に関しても、OSやコンパイラが
提供する「システムライブラリ」以外は全てソースコードの開示義務が発生すること」については、過去の例を含めて
再度確認いたしましたが、開示義務があると断定することはできません。
ただ、今後もこのようなご意見を頂戴することも考えられますので、本日よりfugafuga.dllの提供を停止させて
いただきました。
今後とも、hogehogeをよろしくお願いいたします。

そりゃあ、義務があると断定するためには裁判所の判決が必要になるでしょうが、少なくともGPLの条文には義務が生じると書かれています
foobar2000とSecretRabitCodeの一件*とか、裁判まではいかなくても揉めた事例はいくつもあるわけで。
もし誰かがFSFに垂れ込んだら、ひょっとすると本気で食いついてくるかも知れないよ?
動画編集用Free-softwareの開発は、GNUのHigh Priority Free Software Projectsの一つとしてここ数年間、ずっと掲げられているのを知ってる?
そもそもGPLなライブラリを簡単に使えるんだったら、なんであんたらx264LLCと契約したの?
LGPLと勘違いしてないか?
まあ、自分は当初の目的(この会社をからかって遊ぶこと、及びこのライブラリの使用を即刻やめさせること)は果たしたので、これ以上何かするつもりはないんですけどね。

なんで使用をやめさせたかったかといえば、このソフトが商売としてちゃんと成功して欲しいと思っているから(自分が買う予定はまったくないけど)。
x264LLCに入った利益はlibx264の開発に貢献した度合いに応じて各開発者に分配されることになっており、現にPegasysのTMVW5やSplitMediaLabsのXSplitといった商用ソフトのライセンス料の分配は始まっている。
日本人の自分から見ればそれほどたいした金額ではないみたいなんだけど、例えばロシア人の某氏が受け取ったお金は、彼の本職のサラリー数カ月分に相当するそうである(JEEB氏によれば、彼の給料はロシアでは結構もらってるほうらしい)。
ソフトウェアの共同開発を楽しみながらそこそこの小遣い稼ぎも出来るのであれば、特に物価の安いロシア/東欧/南米といった地域から生きの良い開発者が新たに出現する可能性は高くなるだろう。
そして、そういう仕組みが出来上がったところでH.265が正式に勧告され、x264がx265になったら(もちろん彼らはそれくらいのことは既に考え始めている)、かなり面白いことになるんじゃないかな?
そういう夢をみるためには、一つでも多くの成功事例が必要なのです。

で、それはそれとして一人でニヤニヤしてればいいのに、なんでわざわざこんなのを書いているかといえば、似たようなライセンス爆弾を抱えているツールだのプラグインだのを結構見かけたりするから。
すでにそのようなバイナリを配布しているあなたや、これから配布しようと思っているあなた、ホントにそれで大丈夫ですか?
不注意から起こったトラブルでストレス貯めこんでハゲても知りませんよ?
まあ、うっかりなんてことはそれこそ誰でもやっちゃうものですから、直せるなら早めに直したほうがいいでしょう。

*foobar2000は無料で配布されているWindows用オーディオプレーヤー(プラグインSDK以外のコードは非公開)。
SecretRabitCode(別名libsamplerate)は現在最も高品質と言われているオーディオリサンプル用ライブラリ(x264と同様のGPLv2又は商用の二重ライセンス)。
かつてSRCを使用したfoobar2000用リサンプラープラグインが書かれたことがあるが、これを見つけたSRCの作者Erik氏はプラグイン作者にfoobar2000の全コード、もしくはSRCの商用ライセンス料の支払いを要求し、件のプラグインは開発/配布の永久停止となった(まあ、探せばどこかで拾えるでしょうが)。

2011年9月26日月曜日

RawSource.dll その6

RawSource26(avisynth2.6.0以降専用)を更新しました。

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

*widthの最大値を65536に変更。
*あらたに最大解像度を設定(width x height <= 134217728)。
*その他少々の手直し(出力には影響なし)

必要なもの
avisynth2.6.0α2以降
sseが使えるマシン
msvcr100.dll (Microsoft Visual C++ 2010 再頒布可能パッケージのことです)

以前、読み込み用のバッファの確保をオリジナルのMAX_WIDTH x 4から動的確保に変更したので、現在のコードベースにおけるwidth及び解像度の上限は、単に非常識に大きな数値を入力された場合のout of memory回避のために設けてあります。
とりあえず最大width4096で十分だろうと思っていたのですが、一部の変な人達にはそれでは足りないらしいので増やしました。
まあ、たとえwidth=65536, height=2048の場合でも、
読み込み用バッファのサイズは65536*4=256KiB (RGB32の場合)
avisynthが用意する1フレーム分のメモリは134217728x4=512MB(RGB32の場合)
なので、とりあえずこれだけでクラッシュすることは無い(はず)です......大丈夫だといいなぁ

それにしても最近のDoom9はMTとhigh-bit-colorと64bitでグチャグチャになっておりますな。
自分はそういうハックに夢中になる暇があるなら、とりあえずさっさと2.6.0の正式リリースに漕ぎ着けられるよう、協力体制を取って欲しいものですが。
2.6.0が正式リリースになれば2.5.8なんて誰も使わないのは目に見えてるんですから、もはや2.5.8でも使えるような配慮は単なる時間の無駄だと思っています。

2011年9月20日火曜日

xvidcore-1.4.0

今月に入ってxvidのMLに幾つかビルド関連のパッチを投げたりしてみた。
http://list.xvid.org/pipermail/xvid-devel/2011-September/thread.html

もともと自分はただビルドするだけなのにパッチを当てたりするのは嫌いである。
第一に、パッチの存在を知らない人間にはパッチは役に立たない。
第二に、パッチを管理するのはめんどくさい。
第三に、殆どの場合ビルドエラーの原因はあほらしい理由によるものなので、原因が分かったときに激しい虚しさに襲われることになる。

たしかに開発本家にパッチ投げるのってパッチ書く以上にめんどいけど、やらないといつまでもその状態が続いてしまうので、とりあえず出来そうなところは修正してもらったほうがいいだろう。

で、まあ、結果としていくつか採用されてsvnにコミットされたので、いままで必要だった手間は幾分減ることになった。
次のstable release予定の1.4.0では、インストール時にライブラリを別名でコピーするくらいで済むのかな。

追記 2011年10月22日
Ubuntu11.10上でクロスコンパイルしようかと思いsvnのログを確認してみたら、ライブラリ名変更のリクエストもちゃんと受理してもらえてました。
http://websvn.xvid.org/cvs/viewvc.cgi?view=rev&revision=2044
これで自分としてはパッチは完全に不要になりました。
Isibaarさん、ありがとうございました!

2011年9月19日月曜日

avs2pipemod その8

更新しました。

avs2pipemod-20110919.zip
https://github.com/chikuzen/avs2pipemod

*新機能'trim'を追加。

Doom9で「avs2yuvみたいに-seekや-framesをサポート出来ないか」とリクエストを受けたので追加してみました。
内部でavisynthのTrim()を呼び出すだけの簡単なお仕事だし、まああっても邪魔にはならないと思ったので。

使い方
avs2pipemod -y4mp -trim=100,200 input.avs > output.y4m
というふうにすれば、avsの最後にTrim(100,200)を書いたのと同じようになります。
-infoと-x264bdでは無視されます。

ところでリクエストしてきたStephen R. Savage氏は別名thewebchatというファンサブ界の厄介者らしい。
そーいや昔120fpsAVIの作り方とか調べてたな…物好きなこと。

2011年9月4日日曜日

コンパイラによる最適化の押し付けにむかついた件について

GCCの各オプティマイズレベルで有効になる最適化を調べるを読んでちょっと興味がわいたので、いろいろ手元の環境でも確認してみた。
試したマシンはQ9450とT7300のせいかどれもリンク先と同じ結果になったわけですが、とにかく意外だったのは
*-O2と-Osの違いは-finline-functionsの有無だけ(-Osは有り、-O2は無し)。

-Osはサイズ優先の最適化のはずだけど、-O3(とにかくスピード優先)でも-finline-functionsがつくのであれば、これを有効にすればそこそこスピードアップの可能性があるということだろう。
じゃあ、-O2の存在意義って一体なあに?
-O3程ではないが、それなりにスピード優先のはずなんだけど…。

とまあ、前置きはこのくらいにして、今度は各プロジェクトが設定しているデフォルトの最適化設定を調べてみた。

例えばx264は--extra-cflagsを設定しなければ
"-O3 -ffast-math -march=i686 -mfpmath=sse -msse -fomit-frame-pointer -fno-tree-vectorize -fno-zero-initialized-in-bss"
がつく(x86の場合)。
いかにも互換性を気にしつつも速そうな設定という感じですね。
まあ、クリティカルな部分はほぼすべてasmで書かれてCPU検出で自動的に有効にするので、コンパイラによるCコードの最適化はあまり影響しないそうですが。

これがxvidだと
"-O2 -fstrength-reduce -finline-functions -ffast-math -fomit-frame-pointer"
となっている。
configure.inには
First we test if CFLAGS have been passed on command line
I do that because autoconf defaults (-g -O2) suck and they would kill performance.
To prevent that we define a good defult CFLAGS at the end of the script if and only
if CFLAGS has not been passed on the command line
なんて書かれてますが、それにしては中途半端という印象が否めない。
現在でも更新は続いているんだから、いい加減sseをデフォルトにするくらいはしてもいいのでは?
configure.inにはこのデフォルト値に対して"Default CFLAGS -- Big impact on overall speed"とも書かれているあたり、コンパイラによる最適化はかなり重要みたいなんだけど…自分で設定したほうがよさそうですな。

さて問題はa52dec。
これのconfigure.inは以下のような感じになっている。
if test x"$GCC" = x"yes"; then
    changequote(<<,>>)
    OPT_CFLAGS=`echo "$CFLAGS"|sed "s/-O[0-9]*//g"`
    changequote([,])
    OPT_CFLAGS="$OPT_CFLAGS -O3"
    AC_TRY_CFLAGS([$OPT_CFLAGS],[CFLAGS=$OPT_CFLAGS])
なんとコンパイラがGCCだったら有無を言わさず-O3強制です。
たとえば何らかの理由でデバッグビルドしようと思ってCFLAGS="-O0 -g"しても、-O0は削除されて"-g -O3"なんていうへんてこりんなコードが出力されてしまいます。
しかも-O3は勝手につけるのに、-fno-tree-vectorizeはなし。
liba52はとても古いプロジェクトでCVSの最終更新は7年前。もはや死んだといってもおかしくない。
当時は-O3だけでも問題なかったのかも知れませんが、現在ではまともな出力が得られるかどうか非常に疑わしい、地雷コードと化しています。
これは不安定な-ftree-vectorizeを-O3で有効にしたままなかなか直さない(直せない?)GCCが悪いとも言えるかも知れないけど、素人がコードいじらなきゃいけないような自体はなるべく避けて欲しいなぁ。
とりあえずこんなパッチを書いてみたので、何かの事情で今時a52decをビルドしなければならない人は当てたほうがいいかもしれません。

あともう一つ、openjpegプロジェクト。
現在のstable release?であるはずのopenjpeg_v1_4_sources_r697.tgzをビルドしてみたら、設定したCFLAGSが全く反映されません。
なんでかな?とlibopenjpeg/Makefile.amを見てみたら
INCLUDES = -I.. -I.
COMPILERFLAGS = -Wall -O3 -ffast-math -std=c99
if with_sharedlibs
COMPILERFLAGS += -DOPJ_EXPORTS
else
COMPILERFLAGS += -DOPJ_STATIC
libopenjpeg_la_LDFLAGS += -static
endif
CFLAGS = $(COMPILERFLAGS) $(INCLUDES)
お前もかよ(そしてこれも-fno-tree-vectorizeなし)。
svnの最新コードなら直ってるかなと見てみると今度はcomfigure.acのほうで
if test "x${want_debug}" = "xyes" ; then
   OPJ_COMPILER_FLAG([-g])
   OPJ_COMPILER_FLAG([-O0])
else
   OPJ_COMPILER_FLAG([-O3])
fi
あくまでも-O3は決定ですかそーですか...........むかつくわホント

追記:
gcc4.7ではOsに-foptimize-strlenも追加されたようです(O2は追加なし)。
ますますO2の存在意義って…?

2011年7月9日土曜日

バッファサイズ

前回の記事で筆者は「avs2yuvはバッファが512Bしかないから、256KiBのavs2pipemodよりも遅い」と書いたわけですが、これを読んだ人なら誰でも「じゃあ、avs2yuvのほうもバッファを増やせば速くなるんじゃね?」と考えるのではないでしょうか?

はい、もちろん速くなります。

バッファの拡張なんていうとなにやら大げさですが、やることといえば単にsetvbuf()というCの標準関数を使うだけです。
試しにavs2yuvの書き込みバッファを128KiBに増やして前回のベンチマークをもう一度回してみると…平均284.48fps。
ぐは、今度はavs2pipemodが負けた…orz

悔しいので、avs2pipemodのほうのバッファサイズを256KiBから128KiBに減らしてみると…平均285.05fps。 どうやら引き分けといったところでしょうか。
             avs2yuv     avs2pipemod     avs2pipemod
buffsize     128KiB         256KiB          128KiB
1st (fps)    285.18         279.97          281.66
2nd (fps)    283.45         274.59          285.96
3rd (fps)    281.75         272.27          286.85
4th (fps)    285.86         271.92          285.63
5th (fps)    286.16         274.00          285.18
avg (fps)    284.48         274.55          285.05
このように、バッファサイズは少なすぎてはいけませんが、かといって多ければいいというものでもない。
ハードや扱う素材等によっても最適値は変化するでしょう。
でもそこらへんまで追求を始めると「湾岸ミッドナイト」な世界に突入してしまいそうです。
まあ、64KiB~256KiBくらいにしておくのが無難じゃないですかね。

てなわけで、このへんでお開き。
とりあえずバッファを128KiBにしたavs2yuv(MasterNobody版ベース)とavs2pipemodを置いときます。
avs2yuv_c99-mod.zip
avs2pipemod-20110709.zip

追記 2011.09.21
Doom9でこのことについて少し書いたら、MasterNobody氏がこれを取り込んだバージョンを出しました。
http://forum.doom9.org/showthread.php?t=162578
avs2yuv-0.24bm2.zip
追加機能でi422/i444対応も入っているので、自分の改造板avs2yuvを使うメリットはもはやありません。
MasterNobody氏のavs2yuvを使うことをおすすめします。

avs2yuv その2

前回avs2yuvの修正/改造版をリリースしたら、直後に今度はMasterNobody(Anton Mitrofanov、別名BugMaster)氏がC言語版のavs2yuvを出した。
avsからy4mで出力するツールが一気に増えてしまったので、ここらへんで整理してみようかと思う。

まずavs2yuvを使うならどれがいいのか?
avs2yuvは本家(pengvado版)、kemuri-_9版、MasterNobody版、そして筆者のものの4種類がありますが、一番のオススメはMasterNobody氏の最新版です。
スピードや出力自体はどれもたいして変わりませんが、終了時、及びエラー時の処理が一番丁寧に行われています。
加えてバイナリのサイズも一番小さく、筆者版のように追加で必要なランタイムもありません。
さらにavisynthMTを使っている場合は自動でavsの最後にDistributor()を追加するようにもなっています。
おまけにmingw用のコードなので、LinuxやMacでも簡単にクロスコンパイル出来ます。
ついでに言えば、64bit用バイナリも同梱されています。
avs2yuvを使うなら、多分これが一番いいでしょう。

では他のツールも含めた場合ならどれがいいのか?
とりあえず使用目的が32bitのavisynthの出力をpipeで64bitのx264に渡すこと、もしくはwineでavisynthを使うことなら、現状ではavs2pipemodが一番いいです。
理由は単純に一番速いから。
avs2yuvの現在配布されているバイナリすべて、そしてavs2pipe-0.0.3は、ファイル書き込み用バッファを512Byteしか持っていません(stdio.hで定義されている値をそのまま使っています)。
非圧縮フォーマットであるy4mにとって、これはいささか少なすぎます。
ffmpegに至っては、avs2yuvよりもさらに遅い上にオプションがやたら長くなります。

ffmpeg -v 0 -i foo.avs -pix_fmt yuv420p -vcodec rawvideo -an -f yuv4mpegpipe - | x264 - --demuxer y4m ...

一方avs2pipemodは、以前書いたように書き込み用バッファを拡張しています(20110703版の時点では256KiByte)。
これにより発生するスピード差は次のようなベンチマークをしてみれば一目瞭然です。
#!/bin/bash

echo ColorBars\(1280,720,\"YV12\"\).Trim\(0,4999\) > ./ColorBars.avs

#avs2yuvとavs2pipemodで同じavs(5000フレーム)をそれぞれ5回ずつ回してみる。
#avs2yuvはMasterNobody版を使用

for i in {1..5}; do
avs2yuv ./ColorBars.avs -o - | x264 - --demuxer y4m --preset ultrafast -o /dev/null
done

for i in {1..5}; do
avs2pipemod -y4mp ./ColorBars.avs | x264 - --demuxer y4m --preset ultrafast -o /dev/null
done
さて、自分の環境での結果は以下の通りでした。
        avs2yuv     avs2pipemod
1st    213.04fps     276.53fps
2nd    211.18fps     273.69fps
3rd    213.53fps     275.32fps
4th    213.69fps     276.53fps
5th    213.07fps     276.59fps
avg    212.90fps     275.73fps
実際のエンコードにおいてはこんなに軽いavsを使うことはないでしょうし、x264の設定もずっと重くなりますから、差はかなり縮まるでしょう。
しかし、avs2pipemodがavs2yuvよりも遅くなることは、まずありえない話です。

2011年7月4日月曜日

avs2yuv

Windows7を使い始めてからしばらくした頃、avs2yuvがクラッシュするようになった。
Doom9とかでは特に問題になっていなかったので自分の環境だけかと思っていたのだが、しばらくしてdoom10のほうにこんなスレッドが立ち、自分以外にも同じ問題を抱えている人がいることを知った。

解決策が見つからないので、しばらくの間はavs2yuvのかわりにffmpegを使っていた。
そのうちにdoobry氏がavs2pipeをリリースしたので自分はこちらに乗り換え、さらにこれをより自分好みなツールに改造すべくC/C++の学習を本格的に始めてしまったわけだが、avs2yuvの件はずっと脳内の片隅に引っ掛かっていた。

さて、今日になってこのスレッドを何気なく読んでいたら、とても気になる記述が…。
avs2yuv 0.24 fix: http://forum.doom9.org/showthread.php?t=145912


まさか2年以上前に、すでに解決策が出ていたとはなぁ…不覚orz
とりあえず、このパッチを適用したバイナリはどこにもないようなので、ビルドして配布することにした。
ついでに-hfyu用のエンコーダーをmencoderからffmpegに変更(現在のmencoderはffmpeg以上に信用出来ない地雷ツールなので)したので、もうちょっと便利になったと思う。

avs2yuv-0.24m.zip (要msvcr100.dll)
https://github.com/chikuzen/avs2yuv

2011年7月3日日曜日

avs2pipemod その7

更新。
この前waviのコードを読んだのをきっかけに、RIFF-WAVEフォーマットについていろいろ調べてみました。
どうやらものに出来たようなので、avs2pipemodに新機能を追加。

avs2pipemod-20110703.zip
https://github.com/chikuzen/avs2pipemod

*'-audio'オプションを廃止し、'-wav'と'-extwav'オプションを追加
'-wav'は、一般的なriff-wave(.wav)フォーマットで出力します。
'-extwav'は、チャンネルマスク付きのwave extensible formatで出力します。
チャンネルマスクはチャンネル数に応じて決め打ちになるので、特殊なスピーカー配置の場合はwaviを使ったほうが良いでしょう。
PCM音声の場合、wave extensible formatが普通のwavよりいいところはチャンネルマスクを付けられる点だけなわけですが、これをサポートしているソフトはそれほど多くはないようです。
よく分からない場合は'-wav'を使いましょう。
ちなみにこれまでの'-audio'は「チャンネルマスク無しのwave extensible format」という微妙すぎるものしか出力できませんでした。

*'-rawvideo'の引数にvflipを追加
avs2pipemod -rawvideo=vflip input.avs とすれば、映像の上下を反転して出力します。
RGB出力時の反転対策です。

追記
Doom9に投稿したらIanB氏にオプションを変えたことでお小言をくらってしまったので、-audioでも-extwavと同じ挙動をするように変更しました。
avs2pipemod-20110703-2.zip

2011年6月23日木曜日

ARDeformation.dll その2

さて、この前公開してみたARDeformation.dllですが、よく考えてみると設計ミスをしていることに気づきました。
ARResizeの引数の順番が、どう考えてもおかしい。
modeを一番最初にもってきてしまっているため、使用時は"dar"であれ"sar"であれ、常にmodeを指定するか、引数を名前付きで指定しなければならなくなってしまっています。

例)
DAR16:9にリサイズしたい場合 … ARResize("dar", 16, 9) もしくは ARResize(ar_x=16, ar_y=9)
SAR40:33にリサイズしたい場合 … ARResize("sar", 40, 33)

これでは使いにくいので、引数の順番を変更しました。
とりあえずmodeは一番最後に変更したため、sar/parの場合は常にmode="sar"(or "par")とするようになりました。

例)
DAR16:9にリサイズしたい場合 … ARResize(16, 9)
SAR40:33にリサイズしたい場合 … ARResize(40, 33, mode="sar")

他の順番も少し変更したので、詳細はreadmeを読んでください。

ARDeformation_20110622.zip
https://github.com/chikuzen/ARDeformation

2011年6月17日金曜日

Fix wavi

昨日、ちょっとしたきっかけで、wavi.exeがクラッシュすることがあるのに気づいた。
なぜか音声ファイル(.wav)の書き出し終了時に落ちるのである。

(Chikuzen) wavi.exeが何故かクラッシュするのでコードを覗いてみたが
(Chikuzen) あまりにも汚いので10分の1で投げ出してしまった
(VFRmaniac) 笑
(Chikuzen)とりあえずCleanupAndExit()でクラッシュするみたいなので、そのあたりにfprintfを大量に仕込んでみると
(Chikuzen) LocalFree()で失敗することがわかった
(VFRmaniac) いきなり長文のstderrで吹いた
(VFRmaniac) 二重解放?
(Chikuzen) 多分そう >二重開放
(Chikuzen) そもそもどこでバッファ確保してるんだろ、これ
(VFRmaniac) ちょっとまて...
(VFRmaniac) LPBYTE buffer[2][BUFFER_SIZE];
(VFRmaniac) これ、動的に確保してなくね?
(VFRmaniac) LocalAlloc も LocalReAllocもみつかんねーぞ!
(VFRmaniac) http://msdn.microsoft.com/ja-jp/library/cc430156.aspx
(VFRmaniac) この行 不要じゃね?
(Chikuzen) そうよね、配列使って静的に確保してるよね

てなわけで直ったので、ついでにtebasuna51氏のパッチあててDoom9に置いてきました
http://forum.doom9.org/showthread.php?t=161639

2011年6月15日水曜日

RawSource.dll その5

AviSynth2.6用に大幅に書き直したものです。

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

*I444,YV24の読み込みに対応。
*YUV411をYUY2ではなくYV411で読み込むように変更。
*I422,YV16はYV16で読み込むように変更。
*Y8はYV12ではなくY8で読み込むように変更(これにより奇数解像度に対応)。

必要なもの
AviSynth2.6.0alpha2以降
SSEマシン
msvcr100.dll

2011年6月14日火曜日

ARDeformation.dll

さて、前回のコードにさらに手を加えてみたのがこのプラグインです。

更新しました
https://github.com/chikuzen/ARDeformation

使い方

DARPadding(clip, float "dar_x", float "dar_y", int "align", int "color")

  指定したDARにあわせて、左右または上下にベタを付与します。
  dar_x: DARの分子(水平方向)の値 (デフォルト:clip.width)
  dar_y: DARの分母(垂直方向)の値 (デフォルト:clip.height)
  align:左(または上)にパディングされるベタの幅を、この値の倍数になるように調整する(デフォルト:16)
  color:ベタの色指定 (デフォルト:$00000000(黒))

なんらかの理由でレターボックス/ピラーボックスにしてエンコしないといけない場合に使うといいかも知れません(もちろん使わないにこしたことはありませんが)。
alignのデフォルトは16なので、そのまま使えば若干左寄り(若しくは上寄り)になります。それが嫌な場合はalignを1にすれば、(ほぼ)ど真ん中になります。

ARResize(clip, string "mode", float "ar_x", float "ar_y", bool "expand", float "src_left", float "src_top",
     float "src_right", float "src_bottom", string "resizer", float "ep0", float "ep1", int "dest_w", int "dest_h")

  指定したアスペクト比にあわせて、本体内蔵のリサイザを使ってリサイズします。
  mode: アスペクト比のタイプ("dar","sar","par")を指定します。(デフォルト:"dar")
  ar_x: アスペクト比の分子(水平方向)の値 。(デフォルト:clip.width(dar) or 1(sar/par))
  ar_y: アスペクト比の分母(垂直方向)の値 。(デフォルト:clip.height(dar) or 1(sar/par))
  expand: 拡大するか縮小するかを選びます 。(デフォルト:true(拡大))
  src_*:avisynthの各リサイザの引数と同じです。 (デフォルト:0)
  resizer: 呼び出すリサイザを指定します 。(デフォルト:"Bicubic")
  ep0: 各リサイザ固有の引数その1。lanczosの"taps"やBicubicの"b"を指定します。 (デフォルト:各リサイザの規定値)
  ep1: 各リサイザ固有の引数その2。Bicubicの"c"がこれにあたります。(デフォルト:1.0/3)
  dest_w: 出力のwidthをこの値に矯正します。(デフォルト:0(無効))
  dest_h: 出力のheightをこの値に矯正します。dest_wが0以外の場合は無視されます。(デフォルト:0(無効))
  なおdest_w,dest_hを設定した場合は、expandは無視されます。

例えばDVDソースにARResize("dar",16,9,true,8,0,-8,0,"lanczos4")とすれば、無効領域を削ってLanczos4Resizeで16:9に拡大(854x480、PALなら1024x576)します。

二つとも必要な計算を行って、avisynth.dll内の関数を呼び出しているだけなので、スクリプトでも可能でしょう。
しかし、ARResizeのほうは…これと同等のものをスクリプトで書きたいとは思いませんね。めんどすぎます。そもそもavsのfloatでの計算だと精度が落ちるような気もするし。

興味がある人は、自分でもなにかやってみてください。
結構面白いです。

スクリプトをプラグインにしてみる

前回は簡単な関数をプラグインにしたので、今回は簡単なユーザースクリプト関数をプラグインにしてみることにしました。

まずこんなスクリプトを用意してみます。
#DAR_Padding.avs
function DAR_Padding(clip c, float "dar_x", float "dar_y", int "color", int "align") {
    dar_x = default(float(dar_x), float(c.width))
    dar_y = default(float(dar_y), float(c.height))
    color = default(color, $000000)
    align = default(align, 16)

    Assert(dar_x > 0 && dar_y > 0, "\"dar_x\" and \"dar_y\" need to be positive values.")
    Assert(align >= 1, "align needs to be 1 or heigher integer.")

    flag = c.width * dar_y - c.height * dar_x
    subsample_h = c.IsYUY2 || c.IsYV16 || c.IsYV12 ? 2 : 1
    #IsYV411は現時点(avisynth2.6.0a3)ではまだ作られてないので、YV411非対応
    subsample_v = c.IsYV12 ? 2 : 1

    dest_width  = flag < 0 ? int(ceil(c.height * dar_x / dar_y)) : c.width
    dest_width  = dest_width + (dest_width % subsample_h)

    dest_height = flag > 0 ? int(ceil(c.width * dar_y / dar_x)) : c.height
    dest_height = dest_height + (dest_height % subsample_v)

    pad_left = (dest_width - c.width) / 2
    pad_left = pad_left - (pad_left % subsample_h)
    pad_left = adjust_align(pad_left, align, subsample_h)

    pad_right = dest_width - (c.width + pad_left)

    pad_top = (dest_height - c.height) / 2
    pad_top = pad_top - (pad_top % subsample_v)
    pad_top = adjust_align(pad_top, align, subsample_v)

    pad_bottom = dest_height - (c.height + pad_top)

    return c.AddBorders(pad_left, pad_top, pad_right, pad_bottom, color)
}

function adjust_align(int pad, int align, int subsample) {
    return pad % align == 0 ? pad : adjust_align(pad - subsample, align, subsample)
}
はやい話が指定したDARにあわせて左右(または上下)に自動的にAddBordersでパディングするという関数です。
さて、これをC++で書いてみるとこうなりました。
//DAR_Padding.dll
#include <math.h>
#include "windows.h"
#include "avisynth26.h"

#pragma  warning(disable:4996)

class DAR_Padding : public GenericVideoFilter {

    PClip padded;

public:
    DAR_Padding(PClip _child, const float _dar_x, const float _dar_y,
                const int align, const int color, IScriptEnvironment* env);
    ~DAR_Padding() { }
    PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env);
};

DAR_Padding::
DAR_Padding(PClip _child, const float _dar_x, const float _dar_y, const int color,
            const int align, IScriptEnvironment* env) : GenericVideoFilter(_child)
{
    double dar_x = !_dar_x ? (double)vi.width : (double)_dar_x;
    double dar_y = !_dar_y ? (double)vi.height : (double)_dar_y;

    double flag = vi.width * dar_y - vi.height * dar_x;
    int dest_width = flag < 0 ? (int)ceil(vi.height * dar_x / dar_y) : vi.width;
    int dest_height = flag > 0 ? (int)ceil(dest_width * dar_y / dar_x) : vi.height;

    int subsample_h = vi.SubsampleH();
    int subsample_v = vi.SubsampleV();
    //SubsampleH(),SubsampleV()は、自分で作ってavisynth.hに追加した関数(YV411対応)。
    dest_width += dest_width % subsample_h;
    dest_height += dest_height % subsample_v;

    int pad_left = (dest_width - vi.width) >> 1;
    pad_left -= (pad_left % subsample_h);
    while(pad_left % align)
        pad_left -= subsample_h;

    int pad_right = dest_width - (vi.width + pad_left);

    int pad_top = (dest_height - vi.height) >> 1;
    pad_top -= (pad_top % subsample_v);
    while(pad_top % align)
        pad_left -= subsample_h;

    int pad_bottom = dest_height - (vi.height + pad_top);

    vi.width = dest_width;
    vi.height = dest_height;

    try {
        AVSValue padargs[6] = {child, pad_left, pad_top, pad_right, pad_bottom, color};
        padded = env->Invoke("AddBorders", AVSValue(padargs, 6)).AsClip();
    } catch (IScriptEnvironment::NotFound) {
        env->ThrowError("DAR_Padding: Couldn't Invoke AddBorders.");
    }
}

PVideoFrame __stdcall DAR_Padding::
GetFrame(int n, IScriptEnvironment* env)
{
    return padded->GetFrame(n, env);
}

AVSValue __cdecl Create_DAR_Padding(AVSValue args, void* user_data, IScriptEnvironment* env)
{
    const float dx = args[1].AsFloat(0.0);
    const float dy = args[2].AsFloat(0.0);
    const int cl = args[3].AsInt(0);
    const int al = args[4].AsInt(16);

    if (dx < 0 || dy < 0)
        env->ThrowError("DAR_Padding: \"dar_x\" and \"dar_y\" need to be positive values.");
    if (align < 1)
        env->ThrowError("DAR_Padding: \"align\" needs to be 1 or higher integer.");

    return new DAR_Padding(args[0].AsClip(), dx, dy, cl, al, env);
}

extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit2(IScriptEnvironment* env)
{
    env->AddFunction("DAR_Padding", "c[dar_x]f[dar_y]f[color]i[align]i", Create_DAR_Padding, 0);
    return 0;
}
わかったこと
たしかにC/C++で書くための煩雑な手続き(クラスの宣言とか)は必要になりますが、if/for/whileといったものが使える分、プラグインのほうがむしろ書きやすいかもしれません。
それに、AviSynthの内部情報に直接アクセスできる点も有利です。
三項演算子や再帰を使ってあれこれ考えるのに飽きた人は挑戦してみるといいかも。

2011年6月5日日曜日

FCollections.dll

RawSource.dllの改造も一段落ついたような気がしたので、なにか新しいものを書いてみたくなりました。

あまり難しいものは書けそうにないし、そもそもネタもない。
なにか簡単そうなやつがいいということで、あれこれ考えているうちに目をつけたのがfilter script用関数。
つまりint()とかstring()とかIsClip()とかの類のことですね。
すでに役に立ちそうな関数はあらかた本体の方に揃っているので、それほど役に立つものは書けないだろうけど、初心者の学習用には調度良いような気がしたのでやってみました。

FCollections-20110604.zip
https://github.com/chikuzen/FCollections

以下、説明。

必要なもの:
AviSynth2.5x or later
SSEが使えるマシン(拡張命令セットでSSE有効にしています)
msvcr100.dll

TimeStringToMilliSecond(string "time string"):
時間をあらわす文字列"xx:xx:xx.xxx"をミリ秒単位の整数に変換します。
関数名がやたら長いのでTS2MS()でも使えるようにしてあります。
最初は秒単位の浮動小数点に変換するつもりだったのですが、AviSynthスクリプトはdouble(倍精度浮動小数点)をfloat(単精度浮動小数点)にキャストしてしまうようで、仕方なく整数で返すようにしました(floatの精度では酷い誤差が出てしまう…orz)
SSE搭載マシン(PentiumIII)の発売が1999年、AviSynth2.5の開発はavisynth.hによれば2002年ですから、倍精度をサポートしてないのは首をひねってしまうところですが…。

GCD(int val1, int val2, ...):
最大公約数を返します。

LCM(int val1, int val2, ...):
最小公倍数を返します。

Fibo(int n):
フィボナッチ数を返します。
AviSynthスクリプトの扱える整数は(今のところ)int32_t(-2147483648から2147483647)なので、フィボナッチ数は46(1836311903)までしか扱えません(47は2971215073でout of range)。
0を含めて全部で47しかないなら、わざわざその場で計算させることもなかろうということで、テーブル化してしまいました。
はたしてこれに使い途があるのかどうかはさっぱりわかりません。

IsEven(int n):
nが偶数ならtrue、奇数ならfalseを返します。
(n % 2 == 0)と同じですね。

Clamp(val, low, high):
StickBoy氏のMinMax.dllのやつと全く同じです。
valがlowより小さければlowを、highより大きければhighを、lowとhighの間の値だったらvalをそのまま返します。
FCollectionsを書くに当たって参考にしたのがまさにMinMax.dllのコードだったわけですが、Min()とMax()はAviSynth2.5.8で本体にも入ったのにClamp()は入ってないのでついでに入れてしまいました。

なにか追加してみたい関数が見つかったら、更新するつもりです。

2011年5月30日月曜日

RawSource.dll その4

さて、これまで色々RawSourceのコードをいじって遊んできたわけですが、考えてみれば原著作者であるWarpEnterprises氏の許可は一切取っていませんでした。
avs2pipemodの場合はオリジナルがGPLv3だったのでなんの気兼ねもなくいじってよかったわけですが、RawSourceの場合はライセンスに関する記載が全くありません。
AviSynth自体はGPLv2ですが、プラグインに関しては過去の経緯から作者がライセンスを自分で決めてよいことになっています。
まあ、コードも公開されているわけですから多分問題は起きないとは思うけど、ほおっておくのも気持ち悪い。
てなわけで、とりあえずメールで問い合せてみたら、すぐにお返事が来ました。

Hi!
 The code has no explicit license, so I am glad someone uses it or the ideas behind,
as long as it keeps as open as possible (like GPL describes, I think).
 There were also some small contributions by others, if I remember correctly (Wilbert, billou2k),
which I integrated but not mentioned them (shame on me, didn't care and know much about licenses back then).
I hope it's ok for you if I put your version on my filter colllection website occasionally.

Greetings from Austria,
Ernst / WarpEnterprises

結局ライセンスは決まらずじまいですがとりあえず許可は貰えたので、これからも好きにやってよさそうですね。
よかった、よかった。

気を良くしたので更新
RawSource_25_dll_20110529.zip
*widthの最大値を2880から4096に変更
*引数にfpsnumとfpsdenを追加(デフォルトはそれぞれ25と1)
*エラーチェックを強化

2011年5月23日月曜日

RawSource.dll その3

更新。
ABGRとNV12/NV21をサポートしました。

RawSource_25_dll_20110523.zip

ソースコード
https://github.com/chikuzen/RawSource_2.5x

これでAviSynth2.5でサポートできそうな8bitフォーマットはだいたい網羅できたはず。
次は2.6用に書き直してみるかな。

2011年5月21日土曜日

RawSource.dll その2

ここ最近、avs2pipemodを色々いじったおかげで、C/C++及びYUV4MPEG2/RAWデータ、そしてAviSynthの内部処理への理解が自分としては結構進んだように思います。
なんだかようやく初心者といっても良いレベルになれたかも。

さて、今年の1月にやったRawSource.dllの改造は、実は結構まずいものでした(YUV422なY4Mに対応したようでいて、実はUとVがswapしてしまったりとか)。
どーしたもんかとずっと気にはなっていたけど悲しいことに実力不足で手が付けられなかったわけですが…昨日改めてコードを読みなおしてみたらあらびっくり、理解できるようになっていました。
てなわけで早速修正版リリース。
あとついでに、YV411の対応とか、Y4Mのインタレ周りの処理(これは元々WarpEnterprises氏のころから変だった)の修正とかもやりました。

バイナリ
更新したので削除しました

RawSource_25_dll_20060728(WarpEnterprises最終版)からの変更点
*64文字以上のYUV4MPEG2ヘッダーに対応(最大128文字)
*I422(YUV422planar)に対応
*I411(YUV411planar)、YV411(YVU411planar)に対応(出力は色差補間なしのYUY2)
*ARGBに対応
*pixel_type指定にYUY2とIYUVを追加(これまではYUYV/I420しか指定できなかった)
*I420以外の色空間のYUV4MPEG2に対応(ただし、YUV444/YUV444alphaを除く)
*YUV4MPEG2ヘッダーのIタグによるフィールドオーダー指定を修正(これまではなぜかItやIbだとフィールドベースになるという謎仕様だった。なお、Imには未対応のまま)
*msvcr100.dllが必要(どーやったらstatic linkに出来るんでしょうね?)

ソースコードはこちら
https://github.com/chikuzen/RawSource_2.5x

2011年5月14日土曜日

contributor

自分が書いたパッチがx264の公式gitレポにコミットされました。

まあ、パッチと言ってもわずか一行、lavf入力時のエラーチェックを増やしただけなんですが。

2011年4月28日、#x264dev@freenode
(Chikuzen) Dark_Shikari: http://pastebin.com/xxxxxxxx
(Dark_Shikari) explain?
(Chikuzen) e.g x264 - --demuxer lavf --input-csp yuyv420 --input-res ... <- go to fail
(Dark_Shikari) what about ffms?
(Dark_Shikari) and why
(Chikuzen) I mistook yuyv420 for yuyv422 a minute ago
(Chikuzen) but encoding was done, and i wasted my time
(saintdev) yuyvvuy444
(Chikuzen) this is a case in raw input
(Chikuzen) ffms can't accept raw
(Dark_Shikari) ok

パッチを書いた理由も効果も取るに足らないものですが、これでもx264のrevは一つ上がり、晴れて自分はcontributorとしてChangelogに名前がのることになったわけです。

何が言いたいかといえば、
・不具合や不満があるなら開発者本人に伝えること。
 英語が苦手? 俺だってそうだよ。
 "All your base are belong to us"レベルの間違いは山ほどやってらぁ
・どんなつまらないパッチでも、そう変更すべき理由があると思うならちゃんと提出すること。
ですかね。

2011年5月11日水曜日

High-bit-depth AVCデコーダ

この度、ついにlibavにH.264/AVCのHigh bit depth対応デコーダがコミットされた。

思い起こせばx264がhigh-bit-depthをサポートしたのがr1666(2010年7月)だから、かれこれ10ヶ月前。
以来、使いたくてもデコーダがないから使う甲斐が無いというなんとももどかしい状態からやっと開放される時がやって来た!(MainConcept? 悪いけど趣味に合わないんで…)

というわけで、以下、色々なところで起こったちょっとしたお祭り騒ぎの記録より。

#x264dev@freenode
(BBB) irock: 10bit pushed

#L-SMASH@freenode
(Chikuzen) うお、10bitデコーダがlibavにも入った?
(JEEB) yes
(Chikuzen) ええい、mplayer2の次のリリースはまだか
(Chikuzen) JEEB: ちょっとuau氏かlachs0r氏をぶん殴って新しいの出させてきてよ
(JEEB) おう

#mplayer2@freenode
(JEEB) 10bit H.264 decoding got into libav \o/
(JEEB) uau, how much work do you think it'd be to add 10bit H.264 support into mplayer2? libswscale seems to handle 10bit 4:2:0 to "your usual" RGB already :3

秘密の某所にて
(JEEB) 10bit support getting into libav patch-by-patch gentlemen!
(JEEB) YEAAAAAAAH
(elenril) all hail BBB
(JEEB) all hail BBB!
(Dark_Shikari) now we need:
(Dark_Shikari) 1) dither
(Dark_Shikari) 2) support in ffdshow
(Dark_Shikari) 3) make sure normal playback does the dither
(elenril) send patches =p
(Dark_Shikari) 4) cccp release
(Dark_Shikari) elenril: dither patches are already sent
(JEEB) also, just kicked uau on the issue :3
(jfs) ooooh I know, patch vsfilter to render subs on 16 bit/plane surfaces!
(jfs) ._.
(Dark_Shikari) when we switch to 10 bit
(Dark_Shikari) THIS MEANS YOU HAVE TO STOP ENCODING AT 5 BILLION MBPS OK?
(Dark_Shikari) crf 22 is now OK. No crf 14.
(Dark_Shikari) Because you can no longer complain about banding.

#libav-devel@freenode
*Dark_Shikari join #libav-devel
*ChanServ mode +o Dark_Shikari
(Dark_Shikari) so, explain to me how this 10-bit h264 templating works
(Dark_Shikari) and how it'll apply to asm
(Dark_Shikari) and I'll submit some asm patches
(kshishkov) Dark_Shikari: it's easy - you just initialize pointer to different functions depending on bits provided
(Dark_Shikari) kshishkov: I meant how do I make it compile a file twice?
(Dark_Shikari) once with 10-bit, once with 8-bit
(Dark_Shikari) also where the fuck did my fate samples folder go
(kshishkov) Dark_Shikari: templating - define things, include file, redefint things, include file again
(Dark_Shikari) in asm?
(kshishkov) why not?
(kshishkov) even Nasm has %include
(Dark_Shikari) where's the rsync command to download fate samples?
(Dark_Shikari) I lost mine
(lu_zero) Dark_Shikari: there is a make target that should work
(lu_zero) make fate-rsync
(lu_zero) rsync -vaLW rsync://fate-suite.libav.org/fate-suite/ $place
(Dark_Shikari) lu_zero: thx, running
(BBB) Dark_Shikari you're awesome if you do the asm
(Jumpyshoes) has 10-bit been pushed?
(Dark_Shikari) yes
(Jumpyshoes) oh
(Jumpyshoes) well there goes my excuse
(Dark_Shikari) wwww
(Dark_Shikari) so yeah, time to asm

#L-SMASH
(Chikuzen) 10bitがコミットされるやいなや#libav-develにjoinするD_S
(Chikuzen) ホント、現金なアンチャンだこと
(JEEB) ですな
(silverfilain) その貪欲さが彼をあそこまでにしてるんだろうなぁ
(Chikuzen) この前#libav-develでわめき散らしたのはなんだったのかと
(Chikuzen) まあ、君子豹変と言えなくもないが…

#mplayer2
(lachs0r) http://**********/mplayer2-high-bit-depth-20110510.7z

#L-SMASH
(Chikuzen) もう来たのか
(JEEB) いぇす
(Chikuzen) やっぱ、みんな待ち焦がれてたのね


なんで騒いでるのかわからない?
ならばあなたはまだ動画エンコードの泥沼に浸かってない(もしくは足を洗った)一般人ってことですね。
それはとても良いことですから、気にしなくてもいいですよ、いやほんとに。

追記、というか登場人物紹介
BBB  Ronald S. Bultje、Libav developerのリーダー格、ffmpeg-mtや今回のデコーダの不具合解消に大活躍中の人
Chikuzen  筆者
Dark_Shikari  Jason Garrett-Glaser、x264 lead developer
elenril  Anton Khirnov、Libav developer/committer
irock  Oskar Arvidsson、x264のhigh-bit-depthエンコーダ、そして今回のデコーダを書いた人
Jumpyshoes  Daniel Kang、x264 / Libav developer
JEEB  アニオタフィンランド人 兼 二代目CCCP maintainer?
jfs  Niels Martin Hansen、Aegisub main developer
kshishkov  Kostya Shishkov、Libav developer/committer
lachs0r  mplayer2 project member、Windows用ビルド担当
lu_zero  Luca Barbato、Gentoo developer、Libav developer/committer
silverfilain  L-SMASH developer、猫科研究所の中の人
uau  Uoti Urpala、mplayer2 project leader

2011年5月10日火曜日

avs2pipemod その6

…更新。

x264のchangelogを眺めていたらr1939でbluray-compat+fake-interlacedのときはpic-structが要らなくなったと書いてあったので、こっちも削っておくかとコードを見直してみたら…なんか色々、avs2pipe0.0.3の時点で間違ってるようです。

とりあえずNTSC/PALのSDでDARが4:3なソースの場合の対応のために、オプションをまた変更。
これまでのx264bd=tffをx264bdtにしてしまい、=4:3を付けた場合はDAR4:3のソースとみなすことにしました。
具体的には`avs2pipemod.exe -x264bdt=4:3 720x480x60i.avs`といった感じです。
それとBD規格ではやはりBFFはないようなので、x264bdbは作りませんでした。
BFFなソースは事前にDoubleWeave().SelectOdd()でもして、フィールドオーダーをTFFにしてください。

バイナリ
追記:バグあったわ…自分の書いたところでorz
最新は20110510.zipです。
avs2pipemod-20110510.zip

ソース
http://github.com/chikuzen/avs2pipemod

2011年5月7日土曜日

avs2pipemod その5

しつこく更新。
一つ一つの関数が長すぎるのをなんとかしようと、分割したり色々していたら、いつの間にか一部の機能が変わってしまった。

 *'packedraw'を廃止して'rawvideo'に変更
 これまでは映像のraw出力はpacked formatのみでしたが、planar formatでも出来るようにしました。
 planar YUVの出力部はYUV4MPEG2と共通なので、planeの並び方はY->U->Vに限定されています。
 この並び方はffmpeg/libavのpix_fmt(YUV444pとかYUV422pとか)と同じなので、使用上の都合はYV16やYV24(並び方がY->V->U)より良いのですが、いくら探してもFourCCみたいなものが見つかりません。
 x264のfullhelpでは、これをi422とかi444と書いていますが…そんな呼び方、他所では聞いたことがない。
 どうもkemuri_-9氏が、i420を真似て自分で作ってしまったのではないだろうか…。

追記:Y8の処理でバグがあったので修正、バイナリを更新しました。

バイナリ
更新しました

ソース
http://github.com/chikuzen/avs2pipemod

2011年5月4日水曜日

avs2pipemod その4

更新。 いろいろオプションを増やしすぎた感じがしたのでgetoptを使うことにしました。
その他、いろいろ書きなおしたりヘッダーファイルを追加したりあれこれ…かえってカオスな感じになったような…

使い方は以下のようになります。
avs2pipemod -audio=24bit input.avs | neroAacEnc -q 0.3 -if - -of output.mp4
avs2pipemod -y4mt=40:33 input.avs | x264 - --demuxer y4m -o output.mkv
aud16やrawaud24とかはなくなり、かわりにオプションの後ろに'=16bit'とかを付けるようにしました。
付けない場合は、音声出力なら変更なし、y4m出力ならアスペクト比の指定なし(0:0)として扱われます。

あと、x264bdの出力をx264のr1936以降(--bluray-compatあり)用に変更(正直、自分にはほとんど興味のない分野だけど…この機能、使ってる人いるのかな?)。
こちらもこれまでのように、avsのフィールドベース/フレームベースによる判定ではなく、'=tff(bff)'で、インタレの判定を行います(ところでBDでbottom firstってありえるのかいな?)。

バイナリはこちら
更新したので削除

ソースはこちら
https://github.com/chikuzen/avs2pipemod

2011年5月1日日曜日

avs2pipemod その3

更新しました。

 *YUV4MPEG2出力時の色空間変換を改良
 これまでの色空間変換はインタレやBT.709は特に考慮されていませんでしたが、今回の更新で対応しました。
 高さが720以上のRGBはRec.709でYUVに、またy4mt/y4mbの際に他の色空間からYUV420で出力する場合はConvertToYV12(interlaced=True)の処理が入ります(これまではすべてinterlaced=falseで処理されています)。

追記:
さらに更新。

 *新オプション'rawaudio''rawaud16''rawaud24'を追加
 このツールの音声出力はwav extensible formatという、RIFF-WAVE(いわゆる.wav)の拡張形式を使います。
 ただのwavよりもいいところも色々あるのですが、あまり一般的ではないため、いくつかのオーディオエンコーダー(例:LAME、oggenc2等)はこれを入力として受け取ることが出来ません。
 今回の新規オプションはこの対策のため、ヘッダーの全くない生のPCMとして出力します。

バイナリ
更新したので削除

ソース
https://github.com/chikuzen/avs2pipemod

2011年4月28日木曜日

avs2pipemod その2

バグ修正、および新機能の追加等を行いました。

*'packedraw'オプションを追加
入力がpacked format(RGB32/24、YUY2、Y8)のときのみ使える限定機能。
RAW(非圧縮)データをそのままなんのヘッダーも付けずに標準出力します。
RGBをYUVに変換せずに出力したい、及びavisynth2.5でYUY2をYV12に変換せずに出力したい場合に使います。
YV24/YV16/YV411/YV12はY4Mで出力できるので、あえてRAWで出力する必要はないかと思い対象から除外。
実際にこれを使うとすれば、*nix+wineでavisynthを使っていて、これらのデータをネイティブなFFmpeg/MEncoderに入力したい場合くらいでしょうかね。

しかし我ながら、なんとも間の抜けた響きのオプション名ですな…orz

バイナリはこちら
更新したので削除

ソースはこちらへ
https://github.com/chikuzen/avs2pipemod

2011年4月26日火曜日

avs2pipemod

ここ最近、avs2pipeのコードをずっといじっておりました。

最初はavisynth2.6用にYUV444やYUV422でYUV4MPEG2出力出来る機能を追加するだけのつもりだったのが、ついでに自分のほしい機能を幾つか追加したり既存の機能を自分向けに改造したり色々試していたらこうなった。

オリジナルとの違い

*'audio'オプションの他に'aud16''aud24'というオプションを作った
aud16はConvertAudioTo16bit、aud24はConvertAudioTo24bitを入力音声に追加して出力を行う機能。
avs2pipeの売りの一つはvfwインターフェイスを通さないから音声の16bit整数自動変換を避けられることなんだけど、世の中にはあえて32bit浮動小数点を16bit/24bit整数で出力したいということもあるだろうと思い追加した。
スクリプトにConvertAudioTo16bit/24bitを書けばいいだけなのだが、こっちのほうが多分楽である。

*'video'オプションを'y4mp''y4mt''y4mb'の3種類に変更
avs2pipeの'video'オプションは、avsがフィールドベースだったらインタレと判定し、さらにAssumeBFFしていればBFF、それ以外はTFFとして扱うようになっている。
しかし、この判定を利用するためにわざわざスクリプトにAssumeFieldBased().AssumeBFF()とか書くのはどうも煩雑に感じる。
ということで、あえてオプションでフィールドオーダーを指定することにした。
y4mpを指定すれば問答無用でプログレ、y4mtならTFFなインタレ、y4mbならBFFなインタレとしてY4M出力を行う。

*入力がフィールドベースだったときのフレームベースへの変換
上記のvideoオプションの変更を行ったことで、あえてフィールドベースでの入力を許容する意味が無くなってしまったので、強制的にフレームベースにしてしまうことにした。
もしY4M出力時に入力がフィールドベースだったら、AssumeFrameBased()かWeave()を行う(手動選択)。

*'info'の出力情報を変更
pixel_type(色空間)を16進数表示って手抜きすぎるだろってことで、ちゃんとRGB32とかYUY2とか表示するようにした。

*経過時間の表示
音声/Y4M出力終了時に総経過時間を表示するようにした(途中経過はなし)。
bashなりを使っていればtimeコマンドがあるので本当は不要だが、まあ、'time 'と5文字打つ手間が省けるということで。

*'benchmark'オプションを追加
いままで筆者はフィルタのスピードを計測するのにavs2aviかx264cliをNULL出力で使っていたが不満な点があった。
avs2aviはvfwインターフェースを通してavsを読むため、読み込み時に余分な処理が入る。
x264はCインターフェースを使うからavs2aviよりも速いが、たとえpreset ultrafastでも必ずエンコード処理が入る。
そしてどちらもNULL出力とはいえ、書き込み処理も一応入る。
そういう不満を解消すべく作ったのがこのbenchmarkモードである。
処理内容はひたすらavs_get_frame()とavs_release_frame()だけを繰り返し、50フレームごとに途中経過を報告する。
時間計算/表示以外の余分な処理は一切入らないから、理論上はこれが最速だろうし、実際x264よりもわずかながら速い(環境によっては遅いかも知れないけど)。
つーかx264速すぎだろ…こっちも時間計算はdoubleではなくint64で行うべきなのかなぁ…
ちなみにCインターフェースなので、SetMTModeとか使ってる人はDistributor()が当然要ります。

*Y4M出力時のstdoutのバッファを拡張
これはもともとオリジナルの作者のdoobry氏がすでに実装しているようなのだが、現時点ではそれをリリースしていない。
参考:http://forum.doom9.org/showpost.php?p=1490576&postcount=59
つーか、何をもったいつけてるのか知らんが一向にリリースしないので、待ちきれずに自分で実装してしまった。
なるほど、彼の言うとおり随分速くなりますね。


ここまでやったところで、一旦公開してみることにします。

追記:試しに時間計算でx264を真似てみたら、本当にわずかながら速くなりました。
追記:ひどいバグを見つけたので公開停止。
追記:更新しました

ソースコードが欲しい人はこちらへ。
https://github.com/chikuzen/avs2pipemod

とりあえずひと月ほど待っても彼が新バージョンをリリースしないようなら、Doom9でも発表してしまおうかな。

2011年3月5日土曜日

AviSynth2.6.0α on *nix

以前やったベンチマークがWindowsだけであることに、某フランス人が不満そうだったので。
#benchmark.avs
ImageSource("Z:\home\chikuzen\Pictures\1920x1080.bmp", 0, 999)
BlackmanResize(720, 480)  
Spline64Resize(1920, 1080)  
GaussResize(512, 384)  
 
$ for i in {1..3}; do wine avs2avi benchmark.avs -c null -o n; done
 
            2.5.8                 2.6.0α(JEEB's)
1st   00:03:40.414 (4.54fps)   00:01:56.483 (8.58fps)
2nd   00:03:32.149 (4.71fps)   00:01:56.722 (8.57fps)
3rd   00:03:31.894 (4.72fps)   00:01:56.471 (8.59fps)
 
Ubuntu 10.10 / wine 1.3.14
Core2Duo T7300@2GHz / 2GB RAM
やっぱり速いよ、2.6.0。

2011年2月1日火曜日

ふわふわさん part2

(Chikuzen) TheFluff氏が叫んでますな
(Chikuzen) 「空の境界」ってもともとSD制作だったの?
(JEEB) いや
(JEEB) ハイビジョン制作っす
(JEEB) 画像を見れば一部だけがなぜかワープシャープかかってる
(Chikuzen) なぜにwarpsharp...
(JEEB) その答えを見つけるためとりあえずマスタリングした会社の連絡先を見つけないとなぁ・・・
(Chikuzen) そこだけmasterなくしちゃったから、DVDソース使ったとか

カワイソス

2011年1月31日月曜日

中間出力のマルチプロセス化

先日、JEEB氏がAviSynth2.6.0αの非公式ビルドを始めた。

(JEEB) そういや、うちのAvs2.6ビルドってChikuzen氏がテストした奴と性能がどんな感じ?
(Chikuzen) 若干スピードが上がってるみたいよ
(Chikuzen) ちょっとベンチマーク回してみるか
      official 2.6.0α2       JEEB's 2.6.0(20110125)
1st   00:01:11.003(14.08fps)   00:01:07.254(14.87fps)
2nd   00:01:11.010(14.08fps)   00:01:07.003(14.92fps)
3rd   00:01:10.753(14.13fps)   00:01:07.003(14.92fps) (スクリプト等は前回と同じ)
(JEEB) interesting

たしかに興味深い。
どうやら最適化はα2配布後にさらに進んでいたようである。

さて、前回、自分はマルチスレッドによる高速化ではなく、マルチプロセスによる高速化を選んだことを書いた。
ここで問題となるのが、同時にエンコードするための複数のソースがない場合である。
そもそも自分は放送ソースの保存用エンコなんてまったくしない。そんなことには興味がない。
いろいろなフィルタやエンコーダーを試して遊ぶのが好きなのである。
当然、エンコードするべきソースは大抵1本しかなく、3本同時にエンコードなんていままでに数えるほどしかやったことがない。

では、どうすればいいのか?
エンコード対象がひとつしかないのであれば、ひとつを複数に分割してやればいいだけだ。
3本同時にエンコードできる余裕があるなら、1本を3分割してそれぞれ中間出力し、ふたたびくっつけてやればよい。
それが簡単にできるのがAviSynthである。
中間出力用のファイルサイズを気にするような時代でもないしね。

てことで、自動で分割->中間出力->結合->エンコードを行うAvsPマクロを書いた。
#multiprocess intermediate file generator.py
#dividing source script into X -> generate intermediate files at same time -> final encode
#requiaments : VirtualDub.exe, vcf file, ffmpeg or x264 (optional)
import sys
import os.path
import subprocess

vdub = r'C:\VirtualDub-1.9.11\VirtualDub.exe'
vcf  = r'C:\VirtualDub-1.9.11\fastrecomp_uly0_noaudio.vcf'

entries = avsp.GetTextEntry(['Number of dividing', 'SetMemoryMax(?)'], ['3', '1024'])
dnum, mmax = [int(i) for i in entries]

imf_outdir = avsp.GetDirectory('Select a directory to output intermediate files.')

encbin  = avsp.GetFilename('Set Path to Encoder(ffmpeg or x264)')
#encbin = r'G:\Enctools\ffmpeg.exe'
#encbin = r'G:\Enctools\x264_x64.exe'
encout  = avsp.GetSaveFilename('Set final output file name')
encopts = avsp.GetTextEntry('Input commandline options').split(' ')

source = avsp.SaveScript()
frames = avsp.GetVideoFramecount()

if dnum > 1 and mmax > 0 and imf_outdir and frames and os.path.isfile(vdub) and os.path.isfile(vcf):
    start = 0
    vdubprocess = []
    catfilename = os.path.splitext(source)[0] + '_imf.avs'
    catfile = open(catfilename, 'w')

    for i in range(dnum):
        end = frames / dnum * (i + 1)
        if i < dnum - 1:
            trimline = 'trim(%i, %i)' % (start, end)
        else:
            trimline = 'trim(%i, 0)' % start
        lines = 'SetMemoryMax(%i)\nImport("%s")\n%s\n' % (mmax, source, trimline)
        start = end + 1

        imf_avsname = os.path.join(imf_outdir, os.path.basename(source)).rstrip('avs') + 'imf_%02i.avs' % i
        file = open(imf_avsname, 'w')
        file.write(lines)
        file.close()

        imf_aviname = os.path.splitext(imf_avsname)[0] + '.avi'
        vdubargs = [vdub, '/s', vcf, '/p', imf_avsname, imf_aviname, '/r', '/c', '/x']
        p = subprocess.Popen(vdubargs)
        vdubprocess.append(p)

        if i < dnum - 1:
            catfile.write('AVISource("%s") + \\\n' % imf_aviname)
        else:
            catfile.write('AVISource("%s")\n' % imf_aviname)

    catfile.close()

    if encbin and encout:
        for p in vdubprocess:
            p.wait()

        if os.path.basename(encbin).count('ffmpeg'):
            encargs = [encbin, '-i', catfilename] + encopts + ['-y', encout]
        elif os.path.basename(encbin).count('x264'):
            encargs = [encbin, catfilename, '-o', encout] + encopts
        else:
            sys.exit()

        subprocess.Popen(encargs)

2011年1月18日火曜日

AviSynth2.6.0α

さまざまな試行と思索(ってほどのものでもないが)の結果、現在の自分はAviSynth2.6.0α(32bit)を使っている。

Q.なぜ64bitAviSynthじゃないの?
A.いろいろ不具合が多い上に開発が止まっているから。
 開発が順調なら人柱覚悟で使ってバグレポートもするが、現状停止中でforkする人もいないでは使う甲斐がない。
 まあ、気長に待つしかないかなぁ。

Q.なんでMT使わないの?
A.SetMTMode()はとにかく不安定すぎる。
 しかも同じスクリプトでもクラッシュしたりしなかったりと運用で回避を図ろうにも傾向がつかめない。
 たとえ速くても、完走出来ないマラソンランナーは正選手にはなれないのである。
 MT()のほうはSetMTMode()ほどひどくはないが…。

Q.なんでstableな2.5.8ではなく、2.6.0αなの?
A.安定していて速いから。

そう、2.6.0αはまだアルファなのに安定している。
どれくらい安定しているかといえば、既知の問題がα2公開後1年以上経つのにこの程度しかないくらい堅い。
しかも2.5.8に存在するバグもいくつか取れている。(これではどちらがstableなのかと小一時間…)

そして速い。 2.5.8->2.6.0の最適化の進み具合はすさまじい。 例えば次のようなベンチマークをしてみるとよくわかる。
#benchmark.avs
ImageReader("test_1280x720.bmp", 0, 999)
BlackmanResize(720, 480)
Spline64Resize(1920, 1080)
GaussResize(512, 384)

$ for i in {1..3}; do avs2avi benchmark.avs -c null -o n; done
これを2.5.8と2.6.0αでやってみると結果は
              2.5.8                   2.6.0α
1st   00:02:26.256(6.84fps)    00:01:10.753(14.13fps)
2nd   00:02:26.256(6.84fps)    00:01:10.764(14.13fps)
3rd   00:02:26.257(6.84fps)    00:01:10.753(14.13fps)  (CPU使用率はすべて30%弱)
特に重めなresizerをRGB32でかけた結果がこれである。
たまに高速化のためと称してMT()使って縦横別々にリサイズとかしてる人を見かけるけど、そんなもの手間をかけて無駄にCPU使用率を上げているだけですな。

2.6.0αはMT対応はしていないが、それ自体は高速である。
問題はプラグインのほうで、これがボトルネックになるわけだが…でもその場合はCPU自体はそれほど使ってないよね?
CPUに余裕があるなら同時に複数本走らせればいいだけだ。
この場合、1本あたりのスピードは低下してしまうが、3本同時にやれば終了するまでにかかる時間は1本ずつ3本エンコするのと比べてだいたい半分程度にはなるだろう。
1本あたり最大2GBのメモリを使うことになるが(pipeを使えばもう少し増える)、自分の環境は64bitOSで8GBつんでいるので、まだ余裕はある。
・スピードが結果的に倍程度まであがり
・CPUを無駄なく使い
・安定した出力を得られ
・互換性も特に気にする必要がない

現状ではやはりこれが一番いいんじゃないかなぁ。

2011年1月11日火曜日

RawSource.dll

AviSynthのRawSourceがffmpegやy4m.auoで出力したY4Mファイルを読めないので何とかしたいというお話。

YUV4MPEG2(Y4M)は非圧縮なYUVデータに動画の解像度やフレームレートといったものをヘッダーとして追加したシンプルなファイル形式である。
もともとはMJPEGToolsなるもので使われていたものらしいが、なかなか取り扱いが便利なので、今日ではffmpeg,MEncoder,x264といろいろなエンコーダーがY4M入力に対応している。
たとえばx264はただのYUVもY4Mも入力に使用出来るが、ただのYUVだと
$ x264 input.yuv --input-csp i420 --input-res 720x480 --fps 24000/1001 --sar 40:33 \
[other options] -o output.h264
てな具合にオプションを指定しなければならない。
一方、Y4Mファイルであれば、解像度等はヘッダーに書かれているので
$ x264 input.y4m [other options] -o output.h264
と、手間が省ける。
うん、便利だね。

さて、RawSource.dllは非圧縮ファイルを扱うためのAviSynthプラグインである。
このRawSource、Y4Mも読めることになってはいるのだが、いかんせん書かれたのが2006年と古いせいか、想定されているヘッダーが旧式である。ffmpegやAviUtlのYUV4MPEG2出力プラグインで出力される新しい形式(Cタグで色空間指定付)のものだと"YUV4MPEG2 header error"となって手が出ない。
「だれか何とかしてくれないかなー」と最初にこのことに気づいてから、かれこれ一年半ほど待ってみたが、そのような奇特な人はついに現れなかった(まあ黙って待っててもそうそう都合のいいことが起こるわけもないわな)。
そこで一念発起して自分でやってみることにしたのである。

まずC言語入門講座とかその手のサイトを2つほど回って、Hello Worldとかfizzbuzzとかを書くこと5日間。
そろそろ出来るかなと、ためしにやってみたら本当に出来た。ちなみに一番難しかったのはVisualStudioの操作方法だった。なんでAviSynthプラグインはmingwでビルドできないんだよチクショウめ。

とりあえず出来上がったものはDoom9に投稿したので、あとはツッコミ待ちである。