更新しました。
convo2d-0.1.3.7z
https://github.com/chikuzen/convo2d
* 5x5マトリクスが効かなくなっていたのを修正
* ちょっと高速化
追記:
本フィルタはGenericFiltersに統合されましたので、開発/配布を終了しました。
今後はGenericFiltersをお使い下さい。
2012年12月14日金曜日
2012年12月13日木曜日
convo2d その2
更新しました。
convo2d-0.1.2-2.7z
https://github.com/chikuzen/convo2d
・入力クリップの各フレームのフォーマットが一定でない場合、及びフレームのサンプルがfloatの場合の処理を追加。
VapourSynthはAviSynthと違って、クリップの各フレームの解像度や色空間がすべて同じであるとは限りません。フレーム0は720x480のYUV420P8なのに、フレーム1は1920x1080のRGBということもありえます。
そこらへんを忘れていたので処理を追加しました。
さて、せっかく書いたプラグインなので、なにかやってみようと思います。
とりあえず簡単そうなやつで、アンシャープマスクでもいってみましょうか。
一般にアンシャープマスクと呼ばれる処理は次のようなことを行います。
1. 元画像と、それをぼかした画像を用意する。
2. 元画像とぼかした画像の差分をとる。
3. 差分をそのまま、もしくは何かしら手を加えてから元画像にかぶせる。
この結果として、なんかコントラストがきつくなったような画像が得られます。
まずは元画像を読み込みます。
差分のクリップに閾値をつけたり、値に倍率を掛けたり、あるいはぼかし方を変えてみたりしてみるのも面白いかもしれません。
しかし、これではconvo2dの使い方というよりLut2の使い方みたいですな…。
追記:
0.1.2では修正が不十分だったので、0.1.2-2に更新しました。
convo2d-0.1.2-2.7z
https://github.com/chikuzen/convo2d
・入力クリップの各フレームのフォーマットが一定でない場合、及びフレームのサンプルがfloatの場合の処理を追加。
VapourSynthはAviSynthと違って、クリップの各フレームの解像度や色空間がすべて同じであるとは限りません。フレーム0は720x480のYUV420P8なのに、フレーム1は1920x1080のRGBということもありえます。
そこらへんを忘れていたので処理を追加しました。
さて、せっかく書いたプラグインなので、なにかやってみようと思います。
とりあえず簡単そうなやつで、アンシャープマスクでもいってみましょうか。
一般にアンシャープマスクと呼ばれる処理は次のようなことを行います。
1. 元画像と、それをぼかした画像を用意する。
2. 元画像とぼかした画像の差分をとる。
3. 差分をそのまま、もしくは何かしら手を加えてから元画像にかぶせる。
この結果として、なんかコントラストがきつくなったような画像が得られます。
まずは元画像を読み込みます。
import vapoursynth core = vapoursynth.Core() core.std.LoadPlugin('/path/to/vsimagereader.dll') clip = core.imgr.Read('/path/to/lena.bmp')次にぼかした画像を用意する。
core.std.LoadPlugin('/path/to/convo2d.dll') blur = core.convo2d.Convolution(clip, [1, 1, 1, 1, 1, 1, 1, 1, 1])二つの画像の差分をとります。
def clamp(value): if value < 1: return 0 if value > 254: return 255 return value lut_diff = [] for y in range(256): for x in range(256): lut_diff.append(clamp(x - y + 128)) diff = core.std.Lut2([clip, blur], lut_diff, [0, 1, 2])とりあえず今回はそのままかぶせます。
lut = [] for y in range(256): for x in range(256): lut.append(clamp(x + y - 128)) result = core.std.Lut2([clip, diff], lut, [0, 1, 2])では元画像と結果を並べてみましょう。
last = core.std.StackHorizontal([clip, result])
差分のクリップに閾値をつけたり、値に倍率を掛けたり、あるいはぼかし方を変えてみたりしてみるのも面白いかもしれません。
しかし、これではconvo2dの使い方というよりLut2の使い方みたいですな…。
追記:
0.1.2では修正が不十分だったので、0.1.2-2に更新しました。
2012年12月10日月曜日
convo2d
VapourSynth用に空間convolutionフィルタを書きました。
convo2d-0.1.1.7z
https://github.com/chikuzen/convo2d
マトリクスを変更することによって様々な処理が行えることから、カスタムフィルタと呼ばれたりするものです。
単純な平滑化/先鋭化からエッジ検出、エンボス、ピクセルシフトといろいろ出来るので、ググってマトリクスを探してみるのもいいかもしれません。
追記:
メモリリーク、及び画像端の処理が間違ってたのを直しました。
convo2d-0.1.1.7z
https://github.com/chikuzen/convo2d
マトリクスを変更することによって様々な処理が行えることから、カスタムフィルタと呼ばれたりするものです。
単純な平滑化/先鋭化からエッジ検出、エンボス、ピクセルシフトといろいろ出来るので、ググってマトリクスを探してみるのもいいかもしれません。
追記:
メモリリーク、及び画像端の処理が間違ってたのを直しました。
2012年11月20日火曜日
FineSharpen for VapourSynth
VapourSynth用にFineSharpenを移植してみました。
https://gist.github.com/4111749
avs scriptの移植のサンプルにと考えて、規模的にちょうどよさそうだったのでこれを選んだわけですが、よく考えてみたらRemoveGrain、Repairというavisynthプラグインに依存してしまうので、あまりよくなかったかもしれません。
まあ、「masktoolsの代替をどうするか」の参考くらいにはなるということで。
これで使っているspline()は、こちらの方のものを参考にさせていただきました。
これだけのためにNumpyとか使うわけにもいかんからなぁ…
使い方:
gistからスクリプトをDLして、Python3.x\\Lib\\site-packages以下にfinesharp.pyという名前で保存して下さい。
ちなみに 'print(fs.usage())' で、sharpen()の説明が読めます。
https://gist.github.com/4111749
avs scriptの移植のサンプルにと考えて、規模的にちょうどよさそうだったのでこれを選んだわけですが、よく考えてみたらRemoveGrain、Repairというavisynthプラグインに依存してしまうので、あまりよくなかったかもしれません。
まあ、「masktoolsの代替をどうするか」の参考くらいにはなるということで。
これで使っているspline()は、こちらの方のものを参考にさせていただきました。
これだけのためにNumpyとか使うわけにもいかんからなぁ…
使い方:
gistからスクリプトをDLして、Python3.x\\Lib\\site-packages以下にfinesharp.pyという名前で保存して下さい。
import vapoursynth as vs import finesharp core = vs.Core() core.std.LoadPlugin('path/to/the/ffms2.dll') core.std.LoadPlugin('path/to/the/RemoveGrain.dll') core.std.LoadPlugin('path/to/the/Repair.dll') fs = finesharp.FineSharp(core) clip = core.ffms2.Source('path/to/the/video.mp4') clip = fs.sharpen(clip) ...
ちなみに 'print(fs.usage())' で、sharpen()の説明が読めます。
2012年11月18日日曜日
vsrawsource その3
更新しました。
vsrawsource-0.3.0.7z
https://github.com/chikuzen/vsrawsource
* アルファチャンネルの読み込みに対応
* sarnum/sardenでsarを指定できるように機能追加
VapourSynth-r15以降専用です
vsrawsource-0.3.0.7z
https://github.com/chikuzen/vsrawsource
* アルファチャンネルの読み込みに対応
* sarnum/sardenでsarを指定できるように機能追加
VapourSynth-r15以降専用です
vsavsreader その6
更新しました
vsavsreader-79a12496.7z
https://github.com/chikuzen/VS_AvsReader
* アルファチャンネルの読み込みに対応
VapourSynthはr15からAPIバージョンが3にあがりました。
それにあわせてこちらもAPIを上げたので、r15以降でないと動きません。
vsavsreader-79a12496.7z
https://github.com/chikuzen/VS_AvsReader
* アルファチャンネルの読み込みに対応
VapourSynthはr15からAPIバージョンが3にあがりました。
それにあわせてこちらもAPIを上げたので、r15以降でないと動きません。
2012年11月16日金曜日
ある日の会話より
(Chikuzen) Doom9とかにたまに書き込んでる Mr.VacBobってastrange氏だったのか (JEEB) いぇす (JEEB) http://forum.doom9.org/showpost.php?p=1600803&postcount=501 (JEEB) I have a new (NIH) resizer project in progress myself, but it's just for thumbnailing and not really worth trying to do much else with it.←リサイザー作ってるのか。まぁ、 libavcodec等にはもうAppleのせいで触れられないんで、何か別のプロジェクトを作るのは時間の 問題だった 笑 (Chikuzen) あら、あの人appleに就職したの? (JEEB) うん (JEEB) それであのQT用のlibavcodecうんたらが開発停止になったわけだし (Chikuzen) なるほど、そーいうことだったのか (Chikuzen) Perian開発終了はAppleのせいだった! (JEEB) あとlibavcodecの-mtに触れられないのもそれが原因だったりw (Chikuzen) なんだ、最近ffmpeg-mt関連にあの人ほとんど触らなくなったと思ったら (Chikuzen) GoogleなんかBBB氏を使ってガンガン進めてるのにねぇ (Chikuzen) やっぱAppleはオープンソースの敵だよ (JEEB) オープンソースを敵にもなりそうな相手として扱ってるからねぇ・・・ 「外部で仕事でやった ような感じのプログラミングはしちゃダメダメよ(はーと)」という条件が仕事の契約に入ってるw
つくづく俺はAppleは嫌いだよ...
2012年11月2日金曜日
vsimagereader
というわけで(?)、これまで書いた4つの画像入力用プラグインを一つに統合しました。
vsimagereader-0.1.0.7z
https://github.com/chikuzen/vsimagereader
いまのところ、これで読めるのはBMP、JPEG、PNG、TGAの4種類です。
いちおうそこそこ拡張しやすいように書いたつもりなので、ひょっとすると対応フォーマットが増えるかも知れません。
でも、殆どの場合、JPEGとPNGさえ読めれば、あとはどうとでもなるような気がするんですが…JPEG2000とかWebPとか、誰も使ってないでしょ?
なお、旧プラグイン4つはこれを持ちまして開発終了としますので、なにかバグをみつけても直しません。
不具合があった場合は、とりあえずこちらを試してみて、それでもダメだった場合のみ報告をお願いします。
vsimagereader-0.1.0.7z
https://github.com/chikuzen/vsimagereader
いまのところ、これで読めるのはBMP、JPEG、PNG、TGAの4種類です。
いちおうそこそこ拡張しやすいように書いたつもりなので、ひょっとすると対応フォーマットが増えるかも知れません。
でも、殆どの場合、JPEGとPNGさえ読めれば、あとはどうとでもなるような気がするんですが…JPEG2000とかWebPとか、誰も使ってないでしょ?
なお、旧プラグイン4つはこれを持ちまして開発終了としますので、なにかバグをみつけても直しません。
不具合があった場合は、とりあえずこちらを試してみて、それでもダメだった場合のみ報告をお願いします。
2012年10月29日月曜日
vstgareader
結局libtgaをそのまま使うのは諦めて、コードを一部流用するほかは全部自分で書くことにしました。
まあ、そのほうがビルドしやすいし、使いやすいですからね。
vstgareader-0.1.0.7z
https://github.com/chikuzen/vstgareader
さて、これでBMP,JPEG,PNG,TGAとだいたい揃ってきたので、これらをなんとか一つに統合したいところですが…どうしようかなぁ。
まあ、そのほうがビルドしやすいし、使いやすいですからね。
vstgareader-0.1.0.7z
https://github.com/chikuzen/vstgareader
さて、これでBMP,JPEG,PNG,TGAとだいたい揃ってきたので、これらをなんとか一つに統合したいところですが…どうしようかなぁ。
2012年10月25日木曜日
libtga
PNGもなんとかなったので今度はTGAに挑戦です。
TGAを扱うライブラリにはlibtgaとその改造版のlibtga-exがあります。
で、使い方を確認するために、とりあえずこんなのを書いてみました。
こいつにtgaファイルを食わせてやればBGRなrawデータとして出力するわけですが、試しにtgaではないファイルを食わせるとなぜかクラッシュします。
いちおうTGAReadHeaderのところでチェックはしているみたいなんですが…はて?
で、TGAReadHeaderの部分のコードを読んでみると
ではTGA_OKの中身は何かとtga.hのほうを読んでみると…
TGA_OKが全然OKになってねえよ…そりゃクラッシュもするわ。
なんで誰もこれを直してないんだ?
TGAを扱うライブラリにはlibtgaとその改造版のlibtga-exがあります。
で、使い方を確認するために、とりあえずこんなのを書いてみました。
/* TARGA2BGR */ #include <stdio.h> #include <stdlib.h> #include "tga.h" typedef struct { TGA *tga; unsigned char *buff; } tga_read_t; int close(const char *msg, tga_read_t *tr, int ret) { fprintf(stderr, "%s\n", msg); if (tr->buff) { free(tr->buff); } if (tr->tga) { TGAClose(tr->tga); } return ret; } int main(int argc, char **argv) { if (argc < 2) { return -1; } tga_read_t tr = {0}; tr.tga = TGAOpen(argv[1], "rb"); if (!tr.tga || tr.tga->last != TGA_OK) { return close("TGAOpen failed", &tr, -1); } if (TGAReadHeader(tr.tga) != TGA_OK) { return close("TGAReadHeader failed", &tr, -1); } fprintf(stderr, "width: %u\n", tr.tga->hdr.width); fprintf(stderr, "height: %u\n", tr.tga->hdr.height); fprintf(stderr, "depth: %d\n", tr.tga->hdr.depth); fprintf(stderr, "alpha: %d\n", tr.tga->hdr.alpha); size_t buf_size = tr.tga->hdr.width * tr.tga->hdr.height * tr.tga->hdr.depth >> 3; tr.buff = malloc(buf_size); if (!tr.buff) { return close("malloc failed", &tr, -1); } if (TGAReadScanlines(tr.tga, tr.buff, 0, tr.tga->hdr.height, TGA_BGR) != tr.tga->hdr.height) { return close("couldn't read all lines\n", &tr, -1); } char out_name[1024]; sprintf(out_name, "%s.raw", argv[1]); FILE *out = fopen(out_name, "wb"); if (!out) { return close("open output file failed", &tr, -1); } fwrite(tr.buff, 1, buf_size, out); fclose(out); return close("finish", &tr, 0); }
こいつにtgaファイルを食わせてやればBGRなrawデータとして出力するわけですが、試しにtgaではないファイルを食わせるとなぜかクラッシュします。
いちおうTGAReadHeaderのところでチェックはしているみたいなんですが…はて?
で、TGAReadHeaderの部分のコードを読んでみると
int TGAReadHeader (TGA *tga) { tbyte *tmp; if (!tga) return 0; __TGASeek(tga, 0, SEEK_SET); if (tga->off != 0) { TGA_ERROR(tga, TGA_SEEK_FAIL); return 0; } /* 中略 */ return TGA_OK; }と問題なしならTGA_OKを返し、問題有りなら0を返すようになっています。
ではTGA_OKの中身は何かとtga.hのほうを読んでみると…
/* error codes */ enum { TGA_OK = 0, /* success */ TGA_ERROR, TGA_OOM, /* out of memory */ TGA_OPEN_FAIL, TGA_SEEK_FAIL, TGA_READ_FAIL, TGA_WRITE_FAIL, TGA_UNKNOWN_SUB_FORMAT /* invalid bit depth */ };
TGA_OKが全然OKになってねえよ…そりゃクラッシュもするわ。
なんで誰もこれを直してないんだ?
2012年10月23日火曜日
vsbmpreader/vspngreader
vsjpgreaderに続いて今度はbmpとpngです。
vsbmpreader-0.1.0.7z
vspngreader-0.1.0.7z
https://github.com/chikuzen/
TurboJPEG/OSSが非常に簡単だったので「じゃあ次はlibpngだぜ、ヘヘッ」てな感じでまずvspngreaderのほうに取り掛かったわけですが、これがなんともまあ厄介なシロモノでした。
前世紀から開発継続中の非常に歴史のあるライブラリなせいか、とにかくドキュメントの情報量はやたら充実してはおりますが、これが非常に読みにくい。
サンプルコード見てみても、そこら中に#ifdef/#elseifが散りばめられており、追うのが辛い。
void*をわざわざpng_voidpにしたり、unsigned charをpng_byteはいいとしてpng_byte*がpng_bytep、png_bytep*をpng_byteppと、わざと使いにくくしてるとしか思えないtypedefの乱発もまた辛い。
おまえらそこまでアスタリスク嫌いなのかよと小一時間…。
なんとか書き上げてはみたものの、動かしてみると原因不明のクラッシュで、もうすっかりお手上げです。
で、とりあえず気分転換にとbmpのほうを半日で書き上げてみてから、ふと気づいたのがlibpngのバージョン。
それまでは最新の1.5.13を使っていたわけですが、libpng.orgの説明書き(これも無駄に冗長でわかりにくい)をよくよく読んでみると、どうも自分の目的(48bitRGB/16bitGrayscaleの読み込み)は1.2.50でもよさそうです。
で、ものは試しと1.2.50に差し替えてみたらあっさりと動きました…。
vsbmpreader-0.1.0.7z
vspngreader-0.1.0.7z
https://github.com/chikuzen/
TurboJPEG/OSSが非常に簡単だったので「じゃあ次はlibpngだぜ、ヘヘッ」てな感じでまずvspngreaderのほうに取り掛かったわけですが、これがなんともまあ厄介なシロモノでした。
前世紀から開発継続中の非常に歴史のあるライブラリなせいか、とにかくドキュメントの情報量はやたら充実してはおりますが、これが非常に読みにくい。
サンプルコード見てみても、そこら中に#ifdef/#elseifが散りばめられており、追うのが辛い。
void*をわざわざpng_voidpにしたり、unsigned charをpng_byteはいいとしてpng_byte*がpng_bytep、png_bytep*をpng_byteppと、わざと使いにくくしてるとしか思えないtypedefの乱発もまた辛い。
おまえらそこまでアスタリスク嫌いなのかよと小一時間…。
なんとか書き上げてはみたものの、動かしてみると原因不明のクラッシュで、もうすっかりお手上げです。
で、とりあえず気分転換にとbmpのほうを半日で書き上げてみてから、ふと気づいたのがlibpngのバージョン。
それまでは最新の1.5.13を使っていたわけですが、libpng.orgの説明書き(これも無駄に冗長でわかりにくい)をよくよく読んでみると、どうも自分の目的(48bitRGB/16bitGrayscaleの読み込み)は1.2.50でもよさそうです。
で、ものは試しと1.2.50に差し替えてみたらあっさりと動きました…。
2012年10月19日金曜日
vsrawsource その2
更新しました。
vsrawsource-0.2.0.7z
https://github.com/chikuzen/vsrawsource
* 新オプション 'rowbytes_align'を追加
* Windows Bitmap(.bmp)の読み込みサポート
rowbytes_alignは、画像のstrideの境界指定用です(と書いて、分かる人は説明しなくてもわかる人だよなぁ)。
とりあえず世に出回ってるファイルの殆どはwidth==strideか、さもなくばDWORD(4バイト)境界のどちらかだと思いますので、1か4のどちらかにすればいけると思います。
まあ、中にはv210みたいに128バイトにアライメントされてるクソ仕様もありますが…どのみち対応する気もないから別にいいやってことで。ffms2で読めるし。
vsrawsource-0.2.0.7z
https://github.com/chikuzen/vsrawsource
* 新オプション 'rowbytes_align'を追加
* Windows Bitmap(.bmp)の読み込みサポート
rowbytes_alignは、画像のstrideの境界指定用です(と書いて、分かる人は説明しなくてもわかる人だよなぁ)。
とりあえず世に出回ってるファイルの殆どはwidth==strideか、さもなくばDWORD(4バイト)境界のどちらかだと思いますので、1か4のどちらかにすればいけると思います。
まあ、中にはv210みたいに128バイトにアライメントされてるクソ仕様もありますが…どのみち対応する気もないから別にいいやってことで。ffms2で読めるし。
2012年10月16日火曜日
vsjpgreader その2
更新しました。
vsjpgreader-0.1.2-2.7z
https://github.com/chikuzen/vsjpgreader
*デコード時の幅の計算を間違えていたのを修正。
ところでこれに関するバグ報告をDoom9でもらったついでにわかったのですが、どうも現時点ではVSFSはwidthがmod8でないと変になるようです。
vsjpgreader-0.1.2-2.7z
https://github.com/chikuzen/vsjpgreader
*デコード時の幅の計算を間違えていたのを修正。
ところでこれに関するバグ報告をDoom9でもらったついでにわかったのですが、どうも現時点ではVSFSはwidthがmod8でないと変になるようです。
2012年10月14日日曜日
vsjpgreader
VapourSynth用のJPEG入力プラグインを書きました。
vsjpgreader-0.1.1.7z
https://github.com/chikuzen/vsjpgreader
追記:
JPEG圧縮時のYUV変換がYUV420/YUV440だった場合の高さが奇数の際の処理を忘れていたので修正しました。
JPEGの読み込みはffms2でも出来ますし、vsavsreaderを使えばavisynthのimagesourceも利用できますが、前者は読み込むファイルの数だけffindexが作られるのがウザすぎるし、後者はWindowsでしか動きません。
imagemagickとか使えばJPEGだけでなく色々な形式に対応できるんだろうけど、なんか巨大すぎてわけわからんし、「ぽーたびりてぃ」ってもんに欠けるような気がしたので、よさげなライブラリはないものかと探してみたら、TurboJPEG/OSSなるものが見つかりました。
いやぁ、これ、いいっすねぇ。
ヘッダも小さくすっきりしててほんの数時間で完読できるし、それでいて必要な機能はあらかた揃ってるじゃないですか。それにlibjpeg-turboのラッパーだから、SIMD化も進んでいてスピードも文句なし。
ヘッダ読みながらこんなコードを書いてみて感じもつかめたので、そのまま一気にVSプラグインに仕上げました。
vsjpgreader-0.1.1.7z
https://github.com/chikuzen/vsjpgreader
追記:
JPEG圧縮時のYUV変換がYUV420/YUV440だった場合の高さが奇数の際の処理を忘れていたので修正しました。
JPEGの読み込みはffms2でも出来ますし、vsavsreaderを使えばavisynthのimagesourceも利用できますが、前者は読み込むファイルの数だけffindexが作られるのがウザすぎるし、後者はWindowsでしか動きません。
imagemagickとか使えばJPEGだけでなく色々な形式に対応できるんだろうけど、なんか巨大すぎてわけわからんし、「ぽーたびりてぃ」ってもんに欠けるような気がしたので、よさげなライブラリはないものかと探してみたら、TurboJPEG/OSSなるものが見つかりました。
いやぁ、これ、いいっすねぇ。
ヘッダも小さくすっきりしててほんの数時間で完読できるし、それでいて必要な機能はあらかた揃ってるじゃないですか。それにlibjpeg-turboのラッパーだから、SIMD化も進んでいてスピードも文句なし。
ヘッダ読みながらこんなコードを書いてみて感じもつかめたので、そのまま一気にVSプラグインに仕上げました。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <sys/stat.h> | |
#include "turbojpeg.h" | |
typedef struct { | |
tjhandle tjh; | |
FILE *src; | |
unsigned char *src_buff; | |
unsigned char *dst_buff; | |
} j2y_hnd_t; | |
int close(char *msg, j2y_hnd_t *j, int ret) | |
{ | |
fprintf(stderr, "%s\n", msg); | |
if (j->src_buff) { | |
free(j->src_buff); | |
} | |
if (j->dst_buff) { | |
free(j->dst_buff); | |
} | |
if (j->src) { | |
fclose(j->src); | |
} | |
if (j->tjh && tjDestroy(j->tjh)) { | |
fprintf(stderr, "%s\n", tjGetErrorStr()); | |
} | |
return ret; | |
} | |
const char *get_yuv_type(int subsample) | |
{ | |
const struct { | |
int tjsamp; | |
char *type; | |
} table[] = { | |
{ TJSAMP_444, "YUV444" }, | |
{ TJSAMP_422, "YUV422" }, | |
{ TJSAMP_420, "YUV422" }, | |
{ TJSAMP_440, "YUV440" }, | |
{ TJSAMP_GRAY, "Gray" }, | |
{ subsample, "UNKNOWN" } | |
}; | |
int i = 0; | |
while (table[i].tjsamp != subsample) i++; | |
return table[i].type; | |
} | |
int main(int argc, char **argv) | |
{ | |
if (argc < 2) { | |
return -1; | |
} | |
struct stat st; | |
if (stat(argv[1], &st) != 0) { | |
return -1; | |
} | |
j2y_hnd_t j = {0}; | |
j.src_buff = calloc(1, st.st_size); | |
if (!j.src_buff) { | |
return close("src calloc failed", -1); | |
} | |
j.src = fopen(argv[1], "rb"); | |
if (!j.src) { | |
return close("failed to open src", &j, -1); | |
} | |
if (fread(j.src_buff, 1, st.st_size, j.src) < st.st_size) { | |
return close("failed to read file", &j, -1); | |
} | |
j.tjh = tjInitDecompress(); | |
if (!j.tjh) { | |
return close(tjGetErrorStr(), &j, -1); | |
} | |
int width, height, subsample; | |
if (tjDecompressHeader2(j.tjh, j.src_buff, st.st_size, &width, &height, | |
&subsample) != 0) { | |
return close(tjGetErrorStr(), &j, -1); | |
} | |
width = ((width + 3) >> 2) << 2; | |
if (subsample == TJSAMP_420 || subsample == TJSAMP_440) { | |
height += height & 1; | |
} | |
unsigned long dst_size = tjBufSizeYUV(width, height, subsample); | |
j.dst_buff = calloc(1, dst_size); | |
if (!j.dst_buff) { | |
return close("dst calloc failed\n", &j, -1); | |
} | |
if (tjDecompressToYUV(j.tjh, j.src_buff, st.st_size, j.dst_buff, 0)) { | |
return close(tjGetErrorStr(), &j, -1); | |
} | |
char dst_name[256]; | |
sprintf(dst_name, "%s_dst.yuv", argv[1]); | |
FILE *dst_yuv = fopen(dst_name, "wb"); | |
if (!dst_yuv) { | |
return close("failed to open dst file\n", &j, -1); | |
} | |
fwrite(j.dst_buff, 1, dst_size, dst_yuv); | |
fclose(dst_yuv); | |
fprintf(stderr, "width: %d, height: %d, subsample: %s\n", | |
width, height, get_yuv_type(subsample)); | |
return close("finished", &j, 0); | |
} |
2012年10月12日金曜日
HBVFWSource.dll その3
更新しました。
HighBitDepth_VFWSource-0.2.2.7z
https://github.com/chikuzen/HighBitDepth_VFWSource
マクロをinline関数に変更した際にとってもおバカさんなことをしておりました…orz
HighBitDepth_VFWSource-0.2.2.7z
https://github.com/chikuzen/HighBitDepth_VFWSource
マクロをinline関数に変更した際にとってもおバカさんなことをしておりました…orz
2012年10月11日木曜日
vsrawsource
rawsource.dllをVapourSynth用に一から書き直しました。
vsrawsource-0.1.0.7z
https://github.com/chikuzen/vsrawsource
一応VSがサポートしている全色空間で使えるようになっています。
ところでMacOS X用にビルドする場合、configureはどう書けばいいんでしょうかね?
最近Wipple氏が音信不通なので、相談相手がおりません。
vsrawsource-0.1.0.7z
https://github.com/chikuzen/vsrawsource
一応VSがサポートしている全色空間で使えるようになっています。
ところでMacOS X用にビルドする場合、configureはどう書けばいいんでしょうかね?
最近Wipple氏が音信不通なので、相談相手がおりません。
2012年10月7日日曜日
HBVFWSource.dll その2
更新しました。
HighBitDepth_VFWSource-0.2.1.7z
https://github.com/chikuzen/HighBitDepth_VFWSource
* Dither stacked formatでの出力をサポート
stacked formatでの出力はinterleaved formatよりも遅くなります。
特に必要でない場合はinterleaved formatで使って下さい。
追記:
0.2.1に更新。
stacked formatが少し速くなりました。
HighBitDepth_VFWSource-0.2.1.7z
https://github.com/chikuzen/HighBitDepth_VFWSource
* Dither stacked formatでの出力をサポート
stacked formatでの出力はinterleaved formatよりも遅くなります。
特に必要でない場合はinterleaved formatで使って下さい。
追記:
0.2.1に更新。
stacked formatが少し速くなりました。
2012年10月6日土曜日
vsavsreader.dll その5
更新しました。
vsavsreader-d219012.7z
https://github.com/chikuzen/VS_AvsReader
* 入力がRGB24/RGB32の場合のplaneの順番をG->B->RからR->G->Bに変更。
vsavsreaderは入力するavsがRGB24/32の場合、planar-RGBに変換します。
これはVSがpacked-RGBで展開することを禁止しているためです。
さて、RGB24/32をplanarに変換すること自体はとても簡単なのですが、問題はR,G,B各planeをどの順番でVSに渡すべきかです。
VapourSynth.hを読む限りでは特にどの順番で渡すのが既定なのか書かれていませんし、AviSynthのplanar-YUVのようにPLANAR_RとがPLANAR_Bのようなマクロも定義されていません。
で、とりあえずswscaleにあわせてG->B->Rの順番にしていましたが、つい先程vfw経由でプレビューしてみたら、どうやらR->G->Bで渡すのが標準のようでした。
ついでに今回から要求スペックをSSE2以上に上げました。
これはVSの大きな特徴であるマルチスレッド処理を活かすなら、最低でもCore2が要求されるからです。
と言っても、ビルド時のオプションで-msse2をつけただけなので、どうしてもPentium3やAthlonXPで使いたい人は、自分でオプションいじってビルドして下さい。
追記:
Myrsloik氏の公式発表により、VapourSynthはSSE2が使えるCPUを最低ラインとすることが決定しました。というわけで、Pen3/AthlonXPは完全にさようならです。
vsavsreader-d219012.7z
https://github.com/chikuzen/VS_AvsReader
* 入力がRGB24/RGB32の場合のplaneの順番をG->B->RからR->G->Bに変更。
vsavsreaderは入力するavsがRGB24/32の場合、planar-RGBに変換します。
これはVSがpacked-RGBで展開することを禁止しているためです。
さて、RGB24/32をplanarに変換すること自体はとても簡単なのですが、問題はR,G,B各planeをどの順番でVSに渡すべきかです。
VapourSynth.hを読む限りでは特にどの順番で渡すのが既定なのか書かれていませんし、AviSynthのplanar-YUVのようにPLANAR_RとがPLANAR_Bのようなマクロも定義されていません。
で、とりあえずswscaleにあわせてG->B->Rの順番にしていましたが、つい先程vfw経由でプレビューしてみたら、どうやらR->G->Bで渡すのが標準のようでした。
ついでに今回から要求スペックをSSE2以上に上げました。
これはVSの大きな特徴であるマルチスレッド処理を活かすなら、最低でもCore2が要求されるからです。
と言っても、ビルド時のオプションで-msse2をつけただけなので、どうしてもPentium3やAthlonXPで使いたい人は、自分でオプションいじってビルドして下さい。
追記:
Myrsloik氏の公式発表により、VapourSynthはSSE2が使えるCPUを最低ラインとすることが決定しました。というわけで、Pen3/AthlonXPは完全にさようならです。
2012年10月5日金曜日
vsavsreader.dll その4
vsavsreaderは最初からdither hackのinterleaved formatに対応していたわけですが、readmeにはそのことについては何も書いていませんでした。
これは単にreadmeに書くのが非常にめんどかったので放置していただけなわけですが、この度Doom9のほうで奇特にも書いてくれた人がいましたので追加しました。
vsavsreader-8c6c94a.7z
http://github.com/chikuzen/VS_AvsReader
いやはや、ありがたいことです。
これは単にreadmeに書くのが非常にめんどかったので放置していただけなわけですが、この度Doom9のほうで奇特にも書いてくれた人がいましたので追加しました。
vsavsreader-8c6c94a.7z
http://github.com/chikuzen/VS_AvsReader
いやはや、ありがたいことです。
P216改めP21x VFW Reader for AviUtl
HBVFWSourceのほうをいろいろいじっているうちに、P210やP010といったフォーマットについて誤解していたことに気づきました。
P210は10bitYUVだと思い込んでいたのですが、こちらをよくよく読んでみると
たしかにそのほうが色々扱いやすいわけですな。
で、P210もP216と全く同じ計算式でYC48に変換できることになりますので、P210も読めるように変更しました。
P21x_VFW_Reader_for_AviUtl-0.2.0.7z
https://github.com/chikuzen/P216_VFW_Reader_for_AviUtl
P210も読めるのであれば名前がP216 Readerってのもなんかおかしいので、ついでに名前をP21x VFW Readerに変更しましたが、gitレポはP216のままと、だんだんカオスなことに…まあ、いいか。
P210は10bitYUVだと思い込んでいたのですが、こちらをよくよく読んでみると
The 10-bit formats also use 16 bits for each channel, with the lowest 6 bits set to zero, as shown in the following diagram. Because the 10-bit and 16-bit representations of the same YUV format have the same memory layout, it is possible to cast a 10-bit representation to a 16-representation with no loss of precision. It is also possible to cast a 16-bit representation down to a 10-bit representation.と、まあ、P210/P010は10bitYUVを左に6bitシフトして16bitYUVにしたものでした。
たしかにそのほうが色々扱いやすいわけですな。
で、P210もP216と全く同じ計算式でYC48に変換できることになりますので、P210も読めるように変更しました。
P21x_VFW_Reader_for_AviUtl-0.2.0.7z
https://github.com/chikuzen/P216_VFW_Reader_for_AviUtl
P210も読めるのであれば名前がP216 Readerってのもなんかおかしいので、ついでに名前をP21x VFW Readerに変更しましたが、gitレポはP216のままと、だんだんカオスなことに…まあ、いいか。
2012年10月4日木曜日
HBVFWSource.dll
P216 VFW ReaderはAviUtl用ですが、こちらはAviSynth用です。
HighBitDepth_VFWSource-0.1.3.7z
https://github.com/chikuzen/HighBitDepth_VFWSource
P010/P016/P210/P216なクリップをVFW使って読み込みます。
読み込まれたクリップはdither hackのinterleaved formatの状態になります。
色変換の手間が要らないのとplanarフォーマットをサポートしてる分、やっぱAviSynthのほうが書きやすかったです。
追記:
やはり色々まずいところがあったようです。
0.1.3を上げたのですでにDLしてしまった人は差し替えて下さい。
HighBitDepth_VFWSource-0.1.3.7z
https://github.com/chikuzen/HighBitDepth_VFWSource
P010/P016/P210/P216なクリップをVFW使って読み込みます。
読み込まれたクリップはdither hackのinterleaved formatの状態になります。
色変換の手間が要らないのとplanarフォーマットをサポートしてる分、やっぱAviSynthのほうが書きやすかったです。
追記:
やはり色々まずいところがあったようです。
0.1.3を上げたのですでにDLしてしまった人は差し替えて下さい。
P216 VFW Reader for AviUtl
VapourSynthがVFWでP010/P016/P210/P216を出力するようになりました。
これをなるべく高品質でプレビューしたくなったので、AviUtl用の入力プラグインを書きました。
P216_VFW_Reader_for_AviUtl-0.1.0.7z
https://github.com/chikuzen/P216_VFW_Reader_for_AviUtl
使い方はreadmeのほうで。
色変換のコードをいろいろ書くのがメンドイので、P216専用です。
音声もVSが対応してないのでこっちも無視です。
それにしてもVFWって息が長いですね。
最後に仕様が改訂されたのはWindows95の時代ですよ…。
これをなるべく高品質でプレビューしたくなったので、AviUtl用の入力プラグインを書きました。
P216_VFW_Reader_for_AviUtl-0.1.0.7z
https://github.com/chikuzen/P216_VFW_Reader_for_AviUtl
使い方はreadmeのほうで。
色変換のコードをいろいろ書くのがメンドイので、P216専用です。
音声もVSが対応してないのでこっちも無視です。
それにしてもVFWって息が長いですね。
最後に仕様が改訂されたのはWindows95の時代ですよ…。
2012年10月1日月曜日
vsavsreader.dll その3
更新しました。
vsavsreader-4dafb1b.7z
https://github.com/chikuzen/VS_AvsReader
*vsavsreaderで作ったクリップをSplice()で結合出来なかったりしたのを修正
vsavsreader-4dafb1b.7z
https://github.com/chikuzen/VS_AvsReader
*vsavsreaderで作ったクリップをSplice()で結合出来なかったりしたのを修正
2012年9月30日日曜日
VFW module
VapourSynthのr10で新たにVFWモジュールが追加され、Video for Windows(又はDirectShow)を利用してAVIを読み込むソフトウェアでVSのスクリプトを読み込むことが出来るようになりました。
これによりAvsPmodやVirtualDub等でプレビューできるようになったので、この前書いたプレビュー用スクリプトは(Windowsでは)早くも用済みとなった次第です。いや、大変喜ばしい。
この記事はVapourSynth r18までを対象としています。
r19以降では使い方が一部変更されたので、この記事のとおりではうまくいきません。
VFWモジュールの使い方
・VFWモジュールを使う場合、出力先に渡すクリップのインスタンス名は必ず'last'とすること。
'last'以外の名前のクリップは渡せません。
・プラグインやソースファイルの読み込みは、ファイルパスを必ずフルパスで記述すること。
相対パスで扱うのは失敗のもとです。
・VFWで渡せるクリップのフォーマットは8bitのみで、10bitや16bitのものは渡せません。
これはVideo for Windowsが8bit以上のものを扱うことを想定していないことによる制限です。
なお、RGBでもVSのRGB24はplanarフォーマットなので、これも使えません。RGBの場合はCOMPATBGR32に変換する必要があります。
・VFWモジュールを使う際は、クリップのoutputメソッドは使えません。
VirtualDubのメニューから
File -> Open video file
-> 読み込ませるファイルをダイアログで指定 -> 'ファイルの種類'を'AVIFile input driver(compat)(*.avs,*vdr)'に変更 -> '開く’
と、現時点ではちょっと面倒な手順が必要になります。
追記:
こちらの最新テスト版から、vpyを直で開けるようになりました。
ただし、AviUtlですので、クリップのフォーマットはCOMPATYUY2に変換しておきましょう。
なお、vpyになんらかの誤りがあった場合(ファイルパスを相対パスで書いたため、読み込みで不備がおこったとか)、AviUtlが固まってエクスプローラごと落ちて一旦Ctrl+Alt+Delでログオフしなければならなくなったりますので、くれぐれも注意しましょう。
よって、これを利用すればvpyをpipeを使わずに渡すことができます。
10bitYUVとかの入力にも対応してるし。
追記:
2013年3月以降、ffmpeg.exeではこの方法は使えなくなりました(avs読み込みにVFWを使わなくなったため)。
avconv.exeならばまだ使えます。
これにより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'以外の名前のクリップは渡せません。
・プラグインやソースファイルの読み込みは、ファイルパスを必ずフルパスで記述すること。
相対パスで扱うのは失敗のもとです。
これは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と一緒に更新して下さい。
追記:
ちょっとまずいところがあったようなので、修正版に差し替えました。
vsavsreader-10c62ad.7z
https://github.com/chikuzen/VS_AvsReader
更新といっても中身は変わってないのですが、VapourSynthがr9でAPIのバージョンを上げたのでいままでものは使えなくなりました。
いろいろとバグがとれたりしてるようなので、使ってる人はVSと一緒に更新して下さい。
追記:
ちょっとまずいところがあったようなので、修正版に差し替えました。
2012年9月21日金曜日
VapourSynthでプレビュー
とりあえず現時点ではVapourSynthでクリップのプレビューが出来るエディタ等はないので、間に合わせで書いてみました。
使い方
こんな感じで指定したフレーム番号のフレームがプレビューできます。
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の中の人)に色々アドバイス頂いたおかげで随分助かりました。
#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を読み込めるようにするだけなので、勘違いはしないよう注意して下さい。
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次第では)がマルチスレッドで安定して動くあたりを見るに、かなり期待できそうです。
というわけで、試しにこんなのを書いてみました。
for文やif文、リスト内包表記、そして様々な他のPythonモジュール等が使えるあたり、可能性はAviSynthよりも高そうです。
それにPythonですから、avsと違って仕事や学業等にも汎用的に使えます。
憶えて損はないでしょうね。
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
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倍くらい速くなりました。
rawsource_26_dll_20120831.zip
https://github.com/chikuzen/RawSource_2.6x
*読み込み用バッファサイズを最大1フレーム分に拡張しスピードアップ。
これまで1ライン分のデータをファイルから読み込んではメモリに書き出していたのをやめて、なるべくBitBltでまとめて処理するようにしました。
手元の計測では201109版に比べてPlanarフォーマット及びBGR/BGRA/YUY2の場合、4~7倍くらい速くなりました。
2012年8月28日火曜日
あぷこん考
そこのあなた、アプコンやったことありますか?
そう、アニメDVDとかを拡大してからわざわざ再エンコードするあれですよ、あれ。
私? ええ、やったことありますよ。何年前になるのかなぁ、エンコ始めたばっかの頃。
わけも分からずに、やたら糞重たいフィルタを何重にも掛けて、10数時間がかりでCPUぶん回した挙句、途中でクラッシュとかね。
だいたい1週間くらいで飽きてやめたんだけど、あの頃やったのは今でもとってあります。
なんつーか、見返すたびに当時の自分の精神状態を疑いたくなりますな。
で、若気の至り?の残骸を久しぶりに見ながら、「今だったらせめてこうやるよなぁ」みたいなことを考えたのでちょっと書いてみることにします。
DVD素材なら、まあこんな感じでいいでしょう。
リサイザは色々ありますが、スピードとか考えたらSpline36Resizeあたりでいいんじゃないですかね。
あと、周囲に黒ベタがあるなら、それは綺麗に削ります。多少のアス比の狂いなんてキニシナイキニシナイ。
え? 線が太いのがいや? ならWarpSharpで削りますか。
ここまでやると、ある程度エンコ歴のある人は顔をしかめますな。「油絵かよ」って。
WarpSharpは特にエンコ始めたばっかの人に人気のあるフィルタですが、線が細くなる以外に色の変化がキツくなるという作用もあります。ボケた感じの背景に掛けると油絵の具で塗ったみたいになるのです。
そもそもアニメなんてのは、エッジを除けばあとはベタ塗りとグラデーションとボケた背景の塊です。
こういった映像を拡大するなら、SplineやLanczosよりもBilinearResizeのほうが遥かに向いています。
ボケてるものはボケたままに拡大するほうが綺麗です。
じゃあ、どううすればいいかなって考えてみると
これで完璧ってわけにはいきませんが、やらないよりはマシでしょう。
あとは画面が広くなった分バンディングが目立つようになるだろうから、低減フィルタをかければオシマイ。
こんなもんじゃないですかね。
あくまでも考えただけで、実際に何本かやってみようとかは全然思わないんですけど。
そう、アニメDVDとかを拡大してからわざわざ再エンコードするあれですよ、あれ。
私? ええ、やったことありますよ。何年前になるのかなぁ、エンコ始めたばっかの頃。
わけも分からずに、やたら糞重たいフィルタを何重にも掛けて、10数時間がかりでCPUぶん回した挙句、途中でクラッシュとかね。
だいたい1週間くらいで飽きてやめたんだけど、あの頃やったのは今でもとってあります。
なんつーか、見返すたびに当時の自分の精神状態を疑いたくなりますな。
で、若気の至り?の残骸を久しぶりに見ながら、「今だったらせめてこうやるよなぁ」みたいなことを考えたのでちょっと書いてみることにします。
1.まずは素材
拡大するんですからインタレ解除は必須です。DVD素材なら、まあこんな感じでいいでしょう。
MPEG2Source("video.d2v", idct=3, cpu=0) #1pass目 #TFM(d2v="video.d2v", output="matches.txt") #TDecimate(mode=4, output="metrics.txt") #2pass目 TFM(d2v="video.d2v", input="matches.txt") TDecimate(mode=5, hybrid=2, vfrDec=1, input="metrics.txt", tfmIn="matches.txt", \ tcfv1=false, mkvOut="timecodes.txt")ここ数年はDVDでもソフトプルダウンのものが増えましたので、force filmで済むものも多くなりましたな。
2.拡大
DVDサイズ(720x480)を拡大するなら、とりあえず16:9なら1280x720、4:3で960x720くらいが妥当でしょう。それ以上はさすがに無理がある。リサイザは色々ありますが、スピードとか考えたらSpline36Resizeあたりでいいんじゃないですかね。
あと、周囲に黒ベタがあるなら、それは綺麗に削ります。多少のアス比の狂いなんてキニシナイキニシナイ。
src = last resized = src.Spline36Resize(1280, 720, 4, 2, -3, 0) #Crop値は適当です。
3.いろいろ
アプコンする人って、大抵線が濃いほうが好きですよね。まあ、拡大したせいで結構ボケてるでしょうし、それもいいでしょう。resized = resized.FastLineDarkenMod()
え? 線が太いのがいや? ならWarpSharpで削りますか。
resized = resized.WarpSharp()
ここまでやると、ある程度エンコ歴のある人は顔をしかめますな。「油絵かよ」って。
WarpSharpは特にエンコ始めたばっかの人に人気のあるフィルタですが、線が細くなる以外に色の変化がキツくなるという作用もあります。ボケた感じの背景に掛けると油絵の具で塗ったみたいになるのです。
そもそもアニメなんてのは、エッジを除けばあとはベタ塗りとグラデーションとボケた背景の塊です。
こういった映像を拡大するなら、SplineやLanczosよりもBilinearResizeのほうが遥かに向いています。
ボケてるものはボケたままに拡大するほうが綺麗です。
じゃあ、どううすればいいかなって考えてみると
mask = resized.mt_edge().mt_binarize() background = src.BilinearResize(1280, 720, 4, 2, -3, 0) mt_merge(background, resized, mask)つまり、FastLineDarkenやらWarpSharpやらかけたものはエッジだけ使って、その他の部分はBilinearResizeで拡大したものにしてやる。
これで完璧ってわけにはいきませんが、やらないよりはマシでしょう。
あとは画面が広くなった分バンディングが目立つようになるだろうから、低減フィルタをかければオシマイ。
4.まとめ
LoadPlugin("DGDecode.dll") LoadPlugin("mt_masktools-26.dll") LoadPlugin("warpsharp.dll") Import("FastLineDarkenMod.avs") #その他フィルタの読み込み MPEG2Source("video.d2v", idct=3) #インタレ解除 #必要ならデノイズ bg = last.BilinearResize(1280, 720, left, top, right, bottom) edge = last.Spline36Resize(1280, 720, left, top, right, bottom). \ FastLineDarkenMod().WarpSharp() mask = edge.mt_edge().mt_binarize() mt_merge(bg, edge, mask) #バンディング/暗部対策等
こんなもんじゃないですかね。
あくまでも考えただけで、実際に何本かやってみようとかは全然思わないんですけど。
2012年8月26日日曜日
AreaResize
AviSynth用に面積平均法(平均画素法)のリサイザを書きました。
AreaResize-0.1.0.zip
https://github.com/chikuzen/AreaResize
*面積平均法なので縮小専用です。
*YUY2はサポートしてません。
*遅いのは仕様です(SIMDコードなんて書けませんから)。
AreaResize-0.1.0.zip
https://github.com/chikuzen/AreaResize
*面積平均法なので縮小専用です。
*YUY2はサポートしてません。
*遅いのは仕様です(SIMDコードなんて書けませんから)。
2012年8月22日水曜日
BucketMedian その3
前回の記事を書きながら考えたわけですが、そもそもAviSynthは便利な内蔵フィルタを持っているわけですから、画像端の処理をいちいちプラグイン側でやるというのは無駄な分岐を増やして自らスピードを落としているということになります。
gradfun2dbのように画像端の処理をしないのは非常に合理的な選択なのです。
というわけで拙作BucketMedianもこれにならい、画像端は処理しないことにして、かわりにヘルパー関数を用意することにしました。
BucketMedian-0.3.1.zip
*画像端を処理しないようにした。
*BMBorderProc.avsiを追加した。
少しだけど、ホントに速くなったよ…画像端の処理って結構悩んだような覚えがあるんだけど…orz
使い方
LoadPlugin("BucketMedian.dll")
Import("BMBorderProc.avsi")
AVISource("video.avi")
BMBorderProc(clip c, int "r", int "th", int "min", int "max")
r : BucketMedianのradiusと同じ。
th : BucketMedianのthreshと同じ。
min: BucketMedianのminと同じ。
max: BucketMedianのmaxと同じ。
BMBorderProcを使えば、0.2.0と同じ出力が得られます。
追記:
rが奇数の場合、BMBorderProcがエラーになるので修正しました。
gradfun2dbのように画像端の処理をしないのは非常に合理的な選択なのです。
というわけで拙作BucketMedianもこれにならい、画像端は処理しないことにして、かわりにヘルパー関数を用意することにしました。
BucketMedian-0.3.1.zip
*画像端を処理しないようにした。
*BMBorderProc.avsiを追加した。
少しだけど、ホントに速くなったよ…画像端の処理って結構悩んだような覚えがあるんだけど…orz
使い方
LoadPlugin("BucketMedian.dll")
Import("BMBorderProc.avsi")
AVISource("video.avi")
BMBorderProc(clip c, int "r", int "th", int "min", int "max")
r : BucketMedianのradiusと同じ。
th : BucketMedianのthreshと同じ。
min: BucketMedianのminと同じ。
max: BucketMedianのmaxと同じ。
BMBorderProcを使えば、0.2.0と同じ出力が得られます。
追記:
rが奇数の場合、BMBorderProcがエラーになるので修正しました。
2012年8月21日火曜日
FastGradFunkMirror
一見同じようなavsでも書き方一つでパフォーマンスは結構変わっちゃうかもよ、というお話。
GradFunkMirrorという有名なスクリプトがあります。
原理は非常に簡単で、端16pixを処理できないなら周囲に16pix分の鏡像をくっつけてやることで元画像の端まで処理範囲を拡大し、フィルタ後にくっつけた画像をCropしてしまえというもの。
さて、昨日AviSynthの内蔵フィルタのソースを眺めていてふと気づいたので、こう書き直してみました。
違いは「鏡像を作る際に、画像を反転してからCropするか、それともCropしてから反転するか」だけです。
出力されるもの自体は同じですがベンチマークを取ってみると
追記:
ちなみにGradfun2DBModの場合はここに書いたようなロスはなく、GradFunkMirrorがAddBordersで済ませている四隅の部分もしっかり鏡像にしている芸の細かさを見せてくれます。
GradFunkMirrorという有名なスクリプトがあります。
function GradFunkMirror(clip c, float "strength") { strength = default(strength, 1.2) w = c.width() h = c.height() vflip = c.FlipVertical() hflip = c.FlipHorizontal() StackHorizontal(hflip.crop(w-16, 0, 16, h).AddBorders(0, 16, 0, 16), \ stackvertical(vflip.crop(0, h-16, w, 16), c, vflip.Crop(0, 0, w, 16)), \ hflip.Crop( 0, 0, 16, h ).AddBorders(0, 16, 0, 16)) gradfun2db(strength) Crop(16, 16, -16, -16) return last }これはGradFun2DBは上下左右の端16pixの部分を処理しないようになっているので(画像端の処理って面倒ですからねぇ)、それを補うために用意されているスクリプトです。
原理は非常に簡単で、端16pixを処理できないなら周囲に16pix分の鏡像をくっつけてやることで元画像の端まで処理範囲を拡大し、フィルタ後にくっつけた画像をCropしてしまえというもの。
さて、昨日AviSynthの内蔵フィルタのソースを眺めていてふと気づいたので、こう書き直してみました。
function GradFunkMirror2(clip c, float "strength") { strength = default(strength, 1.2) w = c.width() h = c.height() top = c.Crop(0, 0, w, 16).FlipVertical() bottom = c.Crop(0, h-16, w, 16).FlipVertical() left = c.Crop(0, 0, 16, h).FlipHorizontal().AddBorders(0, 16, 0, 16) right = c.Crop(w-16, 0, 16, h).FlipHorizontal().AddBorders(0, 16, 0, 16) StackHorizontal(left, \ StackVertical(top, c, bottom), \ right) gradfun2db(strength) Crop(16, 16, -16, -16) return last }
違いは「鏡像を作る際に、画像を反転してからCropするか、それともCropしてから反転するか」だけです。
出力されるもの自体は同じですがベンチマークを取ってみると
#sample.avs AVISource("1440x1080_ULY0.avi") GradFunkMirror() #GradFunkMirror2() $ for i in {1..3}; do avs2pipemod -benchmark sample.avs; done GradFunkMirror GradFunkMirror2 1st 50.600fps 57.665fps 2nd 50.566fps 58.214fps 3rd 50.308fps 57.566fps --------------------------------------- avg 50.491fps 57.815fps「大きな画像を反転させるよりも小さな画像を反転させるほうがコストは低い」という、まあ当たり前な話なわけですが、結構な差が出るものですな。
追記:
ちなみにGradfun2DBModの場合はここに書いたようなロスはなく、GradFunkMirrorがAddBordersで済ませている四隅の部分もしっかり鏡像にしている芸の細かさを見せてくれます。
2012年5月11日金曜日
Benchmark plugin
AviUtl用のベンチマークプラグインを書きました。
benchmark_for_aviutl-0.1.0.zip
https://github.com/chikuzen/benchmark_for_aviutl
1. 出力プラグインです
2. 基本的な挙動はあじ氏のNULL出力プラグインと似ていますが、ベンチマークの結果をテキストファイルとして出力します。
3. aviutl.exeと同じディレクトリに作られるbenchmark.iniをいじることで、出力色空間と繰り返し回数を指定できます。
例えばbenchmark.iniを
output_format=1
repeat=3
としておけば
なお、出力先のファイルは追記モードで開くようにしています。
benchmark_for_aviutl-0.1.0.zip
https://github.com/chikuzen/benchmark_for_aviutl
1. 出力プラグインです
2. 基本的な挙動はあじ氏のNULL出力プラグインと似ていますが、ベンチマークの結果をテキストファイルとして出力します。
3. aviutl.exeと同じディレクトリに作られるbenchmark.iniをいじることで、出力色空間と繰り返し回数を指定できます。
例えばbenchmark.iniを
output_format=1
repeat=3
としておけば
date : Fri May 11 22:16:45 2012 output colorspace : YUY2 resolution(width x height): 720 x 480 frames : 13805 total proc time(msec) : 45996 average proc rate(fps) : 300.135 date : Fri May 11 22:17:31 2012 output colorspace : YUY2 resolution(width x height): 720 x 480 frames : 13805 total proc time(msec) : 45767 average proc rate(fps) : 301.637 date : Fri May 11 22:18:17 2012 output colorspace : YUY2 resolution(width x height): 720 x 480 frames : 13805 total proc time(msec) : 46080 average proc rate(fps) : 299.588みたいなテキストが出力されます。
なお、出力先のファイルは追記モードで開くようにしています。
2012年5月7日月曜日
AvsReader その9
更新しました。
AvsReader-0.7.1.zip
https://github.com/chikuzen/AvsReader/
* DGDecode.dllのパスの指定を設定に追加。
* DGDecode.dllがオートローディングフォルダになく、パスの指定もない場合は、DGVfapi.vfpと同じ場所を自動で検索するように変更。
* d2v_cpu2のデフォルト値を'指定なし'に変更。
DGDecode.dllの検索に関してmaki-rxrz氏のアイデアを拝借しました。
レジストリのVFAPIプラグイン登録情報を頼りに捜すので、DGIndex.exeのVFAPI登録を無効にしている場合はこれは効きません。
また、DGMPGDecのパッケージ内からDGDecode.dllを動かしている場合も、自動検索はできません。
更新するたびにもうネタ切れだろうと思ってるんですが、けっこう出てくるもんなんだな…。
追記: バグが一つ見つかったので、0.7.1に更新しました。
AvsReader-0.7.1.zip
https://github.com/chikuzen/AvsReader/
* DGDecode.dllのパスの指定を設定に追加。
* DGDecode.dllがオートローディングフォルダになく、パスの指定もない場合は、DGVfapi.vfpと同じ場所を自動で検索するように変更。
* d2v_cpu2のデフォルト値を'指定なし'に変更。
DGDecode.dllの検索に関してmaki-rxrz氏のアイデアを拝借しました。
レジストリのVFAPIプラグイン登録情報を頼りに捜すので、DGIndex.exeのVFAPI登録を無効にしている場合はこれは効きません。
また、DGMPGDecのパッケージ内からDGDecode.dllを動かしている場合も、自動検索はできません。
更新するたびにもうネタ切れだろうと思ってるんですが、けっこう出てくるもんなんだな…。
追記: バグが一つ見つかったので、0.7.1に更新しました。
2012年5月3日木曜日
AvsReader その8
更新しました
AvsReader-0.6.1.zip
https://github.com/chikuzen/AvsReader/
* d2v読み込み時の設定をいろいろ追加
* DVD2AVIのd2vの読み込みを、デフォルトで無効化
maki-rxrz氏が面白そうなブランチを作っていたので取り込んでみました。
d2vを読み込んだ場合は、AviUtlでキーフレームのシークが出来ます。
ただし、あくまでもavisynthを通して読み込んでいるので、MPEG1/2クリップの直接編集が出来るわけではないことに注意して下さい。
あと、DVD2AVIのd2vは弾くようにしました(自環境で試しに使ってみたところ、システム例外発生でMPEG2Dec3が動かなかったため)。
DVD2AVI用のd2v読み込みもコード自体は存在しますので、使ってみたい人は自ビルドしてみてください。
AvsReader-0.6.1.zip
https://github.com/chikuzen/AvsReader/
* d2v読み込み時の設定をいろいろ追加
* DVD2AVIのd2vの読み込みを、デフォルトで無効化
maki-rxrz氏が面白そうなブランチを作っていたので取り込んでみました。
d2vを読み込んだ場合は、AviUtlでキーフレームのシークが出来ます。
ただし、あくまでもavisynthを通して読み込んでいるので、MPEG1/2クリップの直接編集が出来るわけではないことに注意して下さい。
あと、DVD2AVIのd2vは弾くようにしました(自環境で試しに使ってみたところ、システム例外発生でMPEG2Dec3が動かなかったため)。
DVD2AVI用のd2v読み込みもコード自体は存在しますので、使ってみたい人は自ビルドしてみてください。
2012年5月2日水曜日
AvsReader その7
更新しました
AvsReader-0.5.1.zip
https://github.com/chikuzen/AvsReader/
AviUtl0.99lがリリースされ、その4に書いたAviUtl0.99k2のバグが直ったので、こちらも右端のピクセルのコピーを外しました。
AviUtlを0.99lに更新しない場合は、引き続き0.5.0を使って下さい。
AvsReader-0.5.1.zip
https://github.com/chikuzen/AvsReader/
AviUtl0.99lがリリースされ、その4に書いたAviUtl0.99k2のバグが直ったので、こちらも右端のピクセルのコピーを外しました。
AviUtlを0.99lに更新しない場合は、引き続き0.5.0を使って下さい。
2012年5月1日火曜日
AvsReader その6
更新…
AvsReader-0.5.0.zip
https://github.com/chikuzen/AvsReader/
* プラグイン設定に d2v_upconv と yuy2converter を追加。
なんというか、なにか思いつくたびに更新するのはそろそろ控えたほうがいいような気はしますが…。
今回の更新で、DVD2AVIのd2vでもいけるようになりました(要MPEG2Dec3k)。
でも、いまどきあれを使ってる人は、知っている中ではTheRyuu氏くらいだな…。
なんでもDVDエンコにはDGよりもいいんだとかなんとか…ホントかね?
使い方はreadmeを読んで下さい。
読んでもわからない人は、freenodeの#L-SMASH まで来てくれれば、直接いろいろ教えます。
(午後8時以降~0時くらいなら多分います)
AvsReader-0.5.0.zip
https://github.com/chikuzen/AvsReader/
* プラグイン設定に d2v_upconv と yuy2converter を追加。
なんというか、なにか思いつくたびに更新するのはそろそろ控えたほうがいいような気はしますが…。
今回の更新で、DVD2AVIのd2vでもいけるようになりました(要MPEG2Dec3k)。
でも、いまどきあれを使ってる人は、知っている中ではTheRyuu氏くらいだな…。
なんでもDVDエンコにはDGよりもいいんだとかなんとか…ホントかね?
使い方はreadmeを読んで下さい。
読んでもわからない人は、freenodeの#L-SMASH まで来てくれれば、直接いろいろ教えます。
(午後8時以降~0時くらいなら多分います)
2012年4月30日月曜日
AvsReader その5
更新しました。
AvsReader-0.4.1.zip
https://github.com/chikuzen/AvsReader/
*新機能: d2vの読み込みに対応。
だいたい終わりとか言いながら、同じ日に二度目の更新…。
早い話がavsを書かなくてもd2vをそのまま読めるようにしました。
DVD2AVI/MPEG2Dec3はupConvオプションがないので、非対応です。
追記:奇数解像度のRGB入力を壊してたので上げ直しました。
AvsReader-0.4.1.zip
https://github.com/chikuzen/AvsReader/
*新機能: d2vの読み込みに対応。
だいたい終わりとか言いながら、同じ日に二度目の更新…。
早い話がavsを書かなくてもd2vをそのまま読めるようにしました。
DVD2AVI/MPEG2Dec3はupConvオプションがないので、非対応です。
追記:奇数解像度のRGB入力を壊してたので上げ直しました。
AvsReader その4
更新しました。
AvsReader-0.3.0.zip
https://github.com/chikuzen/AvsReader/
* 新機能: adjust_audio_length
自動的に内部でTrim(0, 0)を追加することで、映像と音声の尺を合わせます(デフォルトは有効)。
* widthが奇数なYV24/Y8の読み込みを変更
その2で書いたBT.709での映像崩壊を避けるため、右端のピクセルをコピーして偶数になるようにした。
これで、このプラグインでやれそうなことは、だいたい終わったかな。
追記:
widthが奇数なYC48での問題はAviUtl側の不具合ということでした(KENくん氏のお返事より)。
0.99k3か0.99lで直るそうなので、直ったらもとに戻すつもりです。
AvsReader-0.3.0.zip
https://github.com/chikuzen/AvsReader/
* 新機能: adjust_audio_length
自動的に内部でTrim(0, 0)を追加することで、映像と音声の尺を合わせます(デフォルトは有効)。
* widthが奇数なYV24/Y8の読み込みを変更
その2で書いたBT.709での映像崩壊を避けるため、右端のピクセルをコピーして偶数になるようにした。
これで、このプラグインでやれそうなことは、だいたい終わったかな。
追記:
widthが奇数なYC48での問題はAviUtl側の不具合ということでした(KENくん氏のお返事より)。
0.99k3か0.99lで直るそうなので、直ったらもとに戻すつもりです。
AvsReader その3
更新しました。
AvsReader-0.2.0.zip
https://github.com/chikuzen/AvsReader/
* dither hack(interleaved format/16bit)のサポートを追加
使い方等はreadmeを読んで下さい。
16bitYUV->YC48変換は結構適当ですが、
輝度は4096(16<<8) -> 0、60160(235<<8) -> 4096
色差は4096(16<<8) -> -2048、61440(240<<8) -> 2048
になるようにしています。
AvsReader-0.2.0.zip
https://github.com/chikuzen/AvsReader/
* dither hack(interleaved format/16bit)のサポートを追加
使い方等はreadmeを読んで下さい。
16bitYUV->YC48変換は結構適当ですが、
輝度は4096(16<<8) -> 0、60160(235<<8) -> 4096
色差は4096(16<<8) -> -2048、61440(240<<8) -> 2048
になるようにしています。
2012年4月29日日曜日
AvsReader その2
更新しました。
AvsReader-0.1.1.zip
https://github.com/chikuzen/AvsReader/
* widthが奇数なRGBの読み込みを修正。
* YV24/Y8なクリップはYC48に変換するように変更。
これにより奇数解像度にも対応(したつもり)。
YV24/Y8->YC48はBT.601限定です。
widthが奇数のYV24なクリップを読み込んで、AviUtlの色変換設定の入力をBT.709にすると、何故か表示が崩れます。
入力設定がBT.601だと問題ないので、多分AviUtl側の問題だとは思うのですが…どうなんだろ?
AvsReader-0.1.1.zip
https://github.com/chikuzen/AvsReader/
* widthが奇数なRGBの読み込みを修正。
* YV24/Y8なクリップはYC48に変換するように変更。
これにより奇数解像度にも対応(したつもり)。
YV24/Y8->YC48はBT.601限定です。
widthが奇数のYV24なクリップを読み込んで、AviUtlの色変換設定の入力をBT.709にすると、何故か表示が崩れます。
入力設定がBT.601だと問題ないので、多分AviUtl側の問題だとは思うのですが…どうなんだろ?
2012年4月28日土曜日
AvsReader
AviUtlは0.99k以降、内蔵のAVI File Reader(vfw) でavsを読めるようになりましたが、それとは別に新しく入力プラグインを作ってみました。
AvsReader-0.0.2.zip
https://github.com/chikuzen/AvsReader/
VFWを使わないでavsを読める入力プラグインは他にDirectShow File ReaderとDGMPGDecのD2V/AVS Readerがありますが、avisynth.dllを直接叩くものは多分これだけでしょう。
まあ、中身はavs2pipemodでやってることとたいして変わりませんけど…。
追記
無音のavsを読ませるとAviUtlが固まるのを修正しました。
0.0.1をすでにDLしてしまった物好きな方(5名ほどいるらしい)は、0.0.2を落としなおして下さい。
AvsReader-0.0.2.zip
https://github.com/chikuzen/AvsReader/
VFWを使わないでavsを読める入力プラグインは他にDirectShow File ReaderとDGMPGDecのD2V/AVS Readerがありますが、avisynth.dllを直接叩くものは多分これだけでしょう。
まあ、中身はavs2pipemodでやってることとたいして変わりませんけど…。
追記
無音のavsを読ませるとAviUtlが固まるのを修正しました。
0.0.1をすでにDLしてしまった物好きな方(5名ほどいるらしい)は、0.0.2を落としなおして下さい。
2012年4月8日日曜日
xorshift
アルゴリズムの勉強とかしてると、試しに書いてみたコードを走らせるためにたくさんのサンプルデータが必要になる。
で、標準関数のrand()を使って要素数1000個とか10000個とかの配列をでっち上げたりしていたわけですが、ここで問題にぶち当たりました。
C言語のrand()は0以上RAND_MAX以下の擬似乱数を発生させるわけですが、mingw-gccだとこのRAND_MAXの値が0x7fff(32767)しかありません。
これではもっと大きい数を扱いたい場合に色々と不便なので、「もっとよい乱数生成関数はないかいな」と探してみたところ、xorshiftというのがなかなか良さそうです。
参考:良い乱数・悪い乱数
なんでもやたら速いうえに周期が128bitもあるそうなので、uint64_tな範囲でも問題なく扱えそう。
というわけで書いてみました。
とりあえず10万個程度の乱数を発生させてみてもダブりがひとつも出ないし(当たり前なんだろうけど)、スピードも速いみたい。
素晴らしい!
で、標準関数のrand()を使って要素数1000個とか10000個とかの配列をでっち上げたりしていたわけですが、ここで問題にぶち当たりました。
C言語のrand()は0以上RAND_MAX以下の擬似乱数を発生させるわけですが、mingw-gccだとこのRAND_MAXの値が0x7fff(32767)しかありません。
これではもっと大きい数を扱いたい場合に色々と不便なので、「もっとよい乱数生成関数はないかいな」と探してみたところ、xorshiftというのがなかなか良さそうです。
参考:良い乱数・悪い乱数
なんでもやたら速いうえに周期が128bitもあるそうなので、uint64_tな範囲でも問題なく扱えそう。
というわけで書いてみました。
/* xorshift.h*/ #ifndef XOR_SHIFT_H #define XOR_SHIFT_H #include <stdint.h> uint64_t *srand_xs64(void); uint64_t rand_xs64(uint64_t *x); void close_xs64(uint64_t *x); #endif
/* xor128.c*/ #include <stdlib.h> #include <stdint.h> #include <time.h> #include "xorshift.h" uint64_t *srand_xs64(void) { uint64_t *x = (uint64_t *)malloc(sizeof(uint64_t) * 4); if (!x) return NULL; uint64_t s; do { s = (uint64_t)(time(NULL)); } while (!s); *x = (s << 32) | s; *(x + 1) = (*x << 8) | ((*x & 0xff00000000000000) >> 56); *(x + 2) = (*(x + 1) << 8) | ((*(x + 1) & 0xff00000000000000) >> 56); *(x + 3) = (*(x + 2) << 8) | ((*(x + 2) & 0xff00000000000000) >> 56); return x; } uint64_t rand_xs64(uint64_t *x) { uint64_t t = (*x ^ (*x << 11)); *x = *(x + 1); *(x + 1) = *(x + 2); *(x + 2) = *(x + 3); *(x + 3) = (*(x + 3) ^ (*(x + 3) >> 19)) ^ (t ^ (t >> 8)); return *(x + 3); } void close_xs64(uint64_t *x) { if (x) { free(x); x = NULL; } }
#include <stdio.h> #include <inttypes.h> #include "xorshift.h" int main(void) { uint64_t *seed = srand_xs64(); if (!seed) return -1; for (int i = 0; i < 100000) printf("%"PRIu64"\n", rand_xs64(seed)); close_xs64(seed); return 0; }
とりあえず10万個程度の乱数を発生させてみてもダブりがひとつも出ないし(当たり前なんだろうけど)、スピードも速いみたい。
素晴らしい!
2012年4月7日土曜日
BucketMedian その2
更新。
パラメータを追加しました。
BucketMedian-0.2.0.zip
https://github.com/chikuzen/BucketMedian/
新パラメータ int "thresh"
ただのメディアンフィルタだと、radiusをちょっと高くしただけでも酷いことになるので、しきい値をもう一つ追加しました。
ソースのピクセル値と算出したメディアンの差がこの値以下の場合のみ、ピクセル値をメディアンに変更します。
これを5くらいにしておくと、なんかエッジをぼかさずにゴミがよく取れるようです。
パラメータを追加しました。
BucketMedian-0.2.0.zip
https://github.com/chikuzen/BucketMedian/
新パラメータ int "thresh"
ただのメディアンフィルタだと、radiusをちょっと高くしただけでも酷いことになるので、しきい値をもう一つ追加しました。
ソースのピクセル値と算出したメディアンの差がこの値以下の場合のみ、ピクセル値をメディアンに変更します。
これを5くらいにしておくと、なんかエッジをぼかさずにゴミがよく取れるようです。
2012年4月4日水曜日
BucketMedian
ここ一週間ほど基本的なアルゴリズムとかを勉強していたらなにか書きたくなったので、基本中の基本なメディアンフィルタを書いてみました。
BucketMedian-0.1.0.zip
https://github.com/chikuzen/BucketMedian/
メディアンを求めるのにバケツソートをちょっと応用してみましたが、あまり速くないですな。
使い方:
BucketMedian-0.1.0.zip
https://github.com/chikuzen/BucketMedian/
メディアンを求めるのにバケツソートをちょっと応用してみましたが、あまり速くないですな。
使い方:
AVISource("herpderp.avi") BucketMedian(clip c, int "radius", int "min", int "max")
clip: planar format(YV12,YV16,YV24,YV411,Y8)のみ対応。 処理は輝度のみで、色差はまったくいじりません。 radius (1~255, デフォルト1): 参照する近傍ピクセルの半径。 処理するピクセルを中心として、1だったら3x3、nだったら(2n+1)x(2n+1)の 近傍ピクセルのメディアンを求め、入れ替えます。 大きくすればするほどボケて、遅くなります。 min (0~254, デフォルト0): しきい値の下限。 これよりもピクセルの輝度が低い場合、そのピクセルはメディアンを求めず、そのままコピーします。 max (1から255, デフォルト255): しきい値の上限。 これよりもピクセルの輝度が高い場合、そのピクセルはメディアンを求めず、そのままコピーします。 必要なもの: avisynth2.5.8以降 Microsoft Visual C++ 2010 再頒布可能パッケージ
2012年3月14日水曜日
avs2pipemod その16
更新しました。
avs2pipemod-0.4.1.7z
https://github.com/chikuzen/avs2pipemod/
*'x264raw(tc)'のエラーハンドリングを修正。
たくあん氏からバグ報告いただきました。ありがとうございました。
しかしなんですな
http://k4095-takuan.blogspot.com/2012/03/batbash.html
やっぱ、batって色々と難しすぎると思うのですよ。
コマンドラインが苦手という人の理由の8割は、無理にコマンドプロンプト/batを使おうとしているからだと思います。
avs2pipemod-0.4.1.7z
https://github.com/chikuzen/avs2pipemod/
*'x264raw(tc)'のエラーハンドリングを修正。
たくあん氏からバグ報告いただきました。ありがとうございました。
しかしなんですな
http://k4095-takuan.blogspot.com/2012/03/batbash.html
やっぱ、batって色々と難しすぎると思うのですよ。
コマンドラインが苦手という人の理由の8割は、無理にコマンドプロンプト/batを使おうとしているからだと思います。
2012年3月4日日曜日
avs2pipemod その15
更新しました。
avs2pipemod-0.4.0.7z
https://github.com/chikuzen/avs2pipemod
* 'dumpyuv'を'dumptxt'に変更し、YUY2やRGBに対応。
やっぱ、どうせやるならpacked formatもサポートしとくべきだよなぁとか思ったので。
avs2pipemod-0.4.0.7z
https://github.com/chikuzen/avs2pipemod
* 'dumpyuv'を'dumptxt'に変更し、YUY2やRGBに対応。
やっぱ、どうせやるならpacked formatもサポートしとくべきだよなぁとか思ったので。
2012年2月18日土曜日
avs2pipemod その14
更新しました。
avs2pipemod-0.3.0.7z
https://github.com/chikuzen/avs2pipemod
*新機能 "dumpyuv" を追加
これを読んでたら自分も欲しくなったので、機能を追加しました。
RGBデータを扱いたい場合は
avs2pipemod-0.3.0.7z
https://github.com/chikuzen/avs2pipemod
*新機能 "dumpyuv" を追加
これを読んでたら自分も欲しくなったので、機能を追加しました。
RGBデータを扱いたい場合は
ColorBars() Y=ShowGreen("Y8").ConvertToYV24() U=ShowBlue("Y8") V=ShowRed("Y8") YToUV(U, V, Y)とでもして下さい。
2012年2月16日木曜日
avs2pipemod その13
更新しました。
avs2pipemod-0.2.2.7z
https://github.com/chikuzen/avs2pipemod
*x264raw/x264bdの出力内容に"--frames"を追加
rawvideo出力等で"-trim=*,*"を使っている場合は、こちらも同様にtrimを追加して下さい。
両方で同じ指定をしないと、フレーム数の整合がとれなくなります。
avs2pipemod-0.2.2.7z
https://github.com/chikuzen/avs2pipemod
*x264raw/x264bdの出力内容に"--frames"を追加
rawvideo出力等で"-trim=*,*"を使っている場合は、こちらも同様にtrimを追加して下さい。
両方で同じ指定をしないと、フレーム数の整合がとれなくなります。
2012年2月5日日曜日
Pythonで関数の引数の順序を入れ替える
メモ替わり
L-SMASHのコードで使われている関数のいくつかについて、引数の順序を入れ替える必要が発生した。
こういった作業はIDEを使っていれば簡単にできるのかも知れないが、何かしら書くときはいつもテキストエディタを使い、コンパイルはCLI操作で済ませているので、使い方がいまだにさっぱり分からない。
かといっていちいち関数名で検索しては手作業で修正するのも面倒なので、久々にPythonを書いた。
制限事項:
一つの関数の記述が複数行にまたがる場合
L-SMASHのコードで使われている関数のいくつかについて、引数の順序を入れ替える必要が発生した。
こういった作業はIDEを使っていれば簡単にできるのかも知れないが、何かしら書くときはいつもテキストエディタを使い、コンパイルはCLI操作で済ませているので、使い方がいまだにさっぱり分からない。
かといっていちいち関数名で検索しては手作業で修正するのも面倒なので、久々にPythonを書いた。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/env python | |
# reorder_args.py for Python 2.x | |
# written by Chikuzen | |
import sys | |
import os | |
def usage(): | |
print "usage : reorder_args.py <func name> <num of args> <new order> <filename>\n" | |
print 'example: reorder_args.py "harpderp()" 5 "0,3,2,1,4" "hogehoge.c"\n' | |
print " before : herpderp( foo, bar, fizz, buzz, bleh )\n" | |
print " after : herpderp( foo, buzz, fizz, bar, bleh )\n" | |
sys.exit() | |
argvs = sys.argv | |
if len(argvs) != 5: | |
usage() | |
funcname = argvs[1].rstrip(')') | |
num = int(argvs[2]) | |
order = [int(i) for i in argvs[3].split(',') if 0 <= int(i) < num] | |
if num != len(order): | |
print "error: '%s' and '%s' didn't suit.\n\n" % (argvs[2], argvs[3]) | |
usage() | |
after = "%s_tmp" % argvs[4] | |
file1 = open(argvs[4], 'r') | |
file2 = open(after, 'w') | |
count = 0 | |
for line in file1.readlines(): | |
count += 1 | |
try: | |
if line.find(funcname) != -1: | |
tmp1 = line.split(funcname) | |
for i in xrange(len(tmp1) - 1): | |
tmp2 = tmp1[i + 1].split(')') | |
tmp3 = [j.strip() for j in tmp2[0].split(',')] | |
tmp2[0] = "" | |
for k in xrange(num): | |
tmp2[0] += " %s," % tmp3[order[k]] | |
tmp2[0].rstrip(',') | |
tmp1[i + 1] = ' )'.join(tmp2) | |
line = funcname.join(tmp1) | |
except: | |
print "warning: catch exception line %i in %s\n" % (count, argvs[4]) | |
file2.write(line) | |
file1.close() | |
file2.close() | |
os.remove(argvs[4]) | |
os.rename(after, argvs[4]) |
制限事項:
一つの関数の記述が複数行にまたがる場合
int var = ItIsNoNeedToCareAboutTheLengthOfFunctionNamesBecauseEverybodyUsesIDE(foo, bar, fizz, buzz, bleh, fuck);は処理できないので、warningを頼りに手動で修正すること。
2012年1月30日月曜日
avs2pipemod その12
更新しました。
avs2pipemod-0.2.1.7z
https://github.com/chikuzen/avs2pipemod
*新機能'x264raw','x264rawtc'を追加
最近はdither hackやらx264がRGB圧縮に対応したりやらのおかげで、y4m出力の代りにrawvideo出力を使う頻度が結構高くなりました。
YUV4MPEG2は仕様で「使えるフォーマットは8bitのplanarYUVのみ」と決められているので、これらのためには使えないのです。
で、仕方がないので
使い方
dither packageやflash3kyuu_debandのinterleaved出力を使う場合は、引数でinput-depthを指定するとwidthを1/2にしたコマンドラインが出力されます。
cmd.exeな人の場合は…あいにく筆者はdosコマンドやbatは数年前に憶えることを放棄したので、さっぱりわかりません。
まあ、某ペンギン様も「batを憶えるくらいならPerlをインストールしろ」とか言ってますし、それでいいかと思っています。
avs2pipemod-0.2.1.7z
https://github.com/chikuzen/avs2pipemod
*新機能'x264raw','x264rawtc'を追加
最近はdither hackやらx264がRGB圧縮に対応したりやらのおかげで、y4m出力の代りにrawvideo出力を使う頻度が結構高くなりました。
YUV4MPEG2は仕様で「使えるフォーマットは8bitのplanarYUVのみ」と決められているので、これらのためには使えないのです。
で、仕方がないので
$ avs2pipemod -rawvideo=vflip input.avs | x264_x64 - --demuxer raw --input-csp bgr --input-res 1280x720 --output-csp rgb --fps ...とかやるわけですが、長いコマンドがいい加減めんどうなので省力化することにしました。
使い方
$ avs2pipemod -x264raw 1280x720_30fps_rgb24.avsてな感じのコマンドを実行すると
- --demuxer raw --input-csp bgr --input-depth 8 --input-res 1280x720 --fps 30/1 --output-csp rgbと標準出力に出力されます。
dither packageやflash3kyuu_debandのinterleaved出力を使う場合は、引数でinput-depthを指定するとwidthを1/2にしたコマンドラインが出力されます。
$ avs2pipemod -x264raw=16 2560x719_ntsc-film_16bit_yv24.avs - --demuxer raw --input-csp i444 --input-depth 16 --input-res 1280x719 --fps 24000/1001 --output-csp i444'x264rawtc'は、--tcfile-inを使う場合のためのもので、"--fps fpsnum/fpsden"は出力されません。
$ avs2pipemod -x264rawtc 640x480_yv411.avs - --demuxer lavf --input-fmt rawvideo --input-csp yuv411p --input-depth 8 --input-res 640x480 --output-csp i422筆者のようにCLIにCygwinやMSYSのBash/shell scriptを使っている人なら
$ avs2pipemod -rawvideo input.avs | x264 $(avs2pipemod -x264raw=16 input.avs) --crf 22 --preset slower ...てな感じで、コマンド置換を利用すれば結構ラクになると思います。
cmd.exeな人の場合は…あいにく筆者はdosコマンドやbatは数年前に憶えることを放棄したので、さっぱりわかりません。
まあ、某ペンギン様も「batを憶えるくらいならPerlをインストールしろ」とか言ってますし、それでいいかと思っています。
2012年1月28日土曜日
avs2pipemod その11
更新しました。
avs2pipemod-0.1.2.7z
https://github.com/chikuzen/avs2pipemod
エラーの出るavsを使用した際にクラッシュしていたのを修正。
生まれて初めてバグレポート頂きました。
これまでずっとレポートする側だったので、なんか新鮮な気分です。
avs2pipemod-0.1.2.7z
https://github.com/chikuzen/avs2pipemod
エラーの出るavsを使用した際にクラッシュしていたのを修正。
生まれて初めてバグレポート頂きました。
これまでずっとレポートする側だったので、なんか新鮮な気分です。
2012年1月7日土曜日
ConvertToRGB
avcodecに10bit-AVCデコーダがcommitされて随分経つのにいまだによく解らない人のための乱暴な解説。
まずはこちらの方の解説を読みましょう。
自分が知るかぎりでは、もっともシンプルでわかりやすい説明をされています。
DTVかくし味 - YUVとRGBの比較
特にこの図、
いかに暗部の色数が少ないか、なぜ暗部にシルバーグレインを撒く(=Yの値だけまばら且つ適当に上げる)とマシに見えるようになるかが一発で理解できます。
さて、「YUVはRGBで表現できる範囲をすべてカバーしています。(が、細かい諧調はRGBに分があります。)」とまとめられていますが、これをちょっと具体的に計算してみましょうか。
いやぁ、ほんと色数少ないですね。TrueColorRGBの16,777,216色のうち、最大でも4分の1程度しか使われていません。
バンディングが発生するのも当たり前です。
これが10bitYUV->8bitRGBだとどの程度になるのかは、適当な計算式がとりあえず見当たらなかったのでやってませんが、8bit->10bitでY,U,Vの精度がそれぞれ4倍になることを考えれば、色数もかなり良い感じに増えそうです。
てなわけで、10bitエンコードの力を確認するためにバカ高い業務用モニタ等は別に必要ありません。
民生品でもそこそこの品質があれば違いは確実にわかります(もちろん、良いものであればもっとよく分かるでしょうが)。
つーか、AviUtlのプレビューがやたら綺麗に見える理由って、まさにこれだよね。
まずはこちらの方の解説を読みましょう。
自分が知るかぎりでは、もっともシンプルでわかりやすい説明をされています。
DTVかくし味 - YUVとRGBの比較
特にこの図、
いかに暗部の色数が少ないか、なぜ暗部にシルバーグレインを撒く(=Yの値だけまばら且つ適当に上げる)とマシに見えるようになるかが一発で理解できます。
さて、「YUVはRGBで表現できる範囲をすべてカバーしています。(が、細かい諧調はRGBに分があります。)」とまとめられていますが、これをちょっと具体的に計算してみましょうか。
/* yuv2rgb.c */ #include <stdio.h> #include <stdlib.h> #include <string.h> #define SATURATE(X) X = (X < 0) ? 0 : (X > 255) ? 255 : X int main(void) { const struct { char *name; int coef[6]; } matrix[] = { {"rec601", {76309, 104597, 25675, 53279, 76308, 132201}}, {"pc601", {65536, 91881, 22553, 46801, 65536, 116129}}, {"rec709", {76309, 117504, 13954, 34903, 76308, 138453}}, {"pc709", {65536, 103219, 12257, 30659, 65536, 121621}}, {NULL} }; int count = 256 * 256 * 256; int *rgb = (int*)calloc(count, sizeof(int)); if (!rgb) { fprintf(stderr, "malloc failed\n"); return -1; } for (int m = 0; matrix[m].name; m++) { int coef0 = matrix[m].coef[0], coef1 = matrix[m].coef[1], coef2 = matrix[m].coef[2], coef3 = matrix[m].coef[3], coef4 = matrix[m].coef[4], coef5 = matrix[m].coef[5]; int x = !strncmp(matrix[m].name, "rec", 3) ? 16 : 0; for (int y = 0; y < 256; y++) { for (int u = 0; u < 256; u++) { for (int v = 0; v < 256; v++) { /* 下記計算式は茂木和博氏のm2v.vfpのreadmeより引用しました */ int r = (coef0 * (y - x) + coef1 * (v - 128)) >> 16; int g = (coef0 * (y - x) - coef2 * (u - 128) - coef3 * (v - 128)) >> 16; int b = (coef4 * (y - x) + coef5 * (u - 128)) >> 16; SATURATE(r); SATURATE(g); SATURATE(b); rgb[((r << 16) | (g << 8) | b)]++; } } } int num = 0; for (int i = 0; i < count; i++) { num += !!rgb[i]; rgb[i] = 0; } printf("%s: %d\n", matrix[m].name, num); } free(rgb); return 0; }このコードでBT.601とBT.709で8bitYUV->8bitRGBに変換した際、RGBで使われる色数がわかります。 で、結果は
BT.601 TVレンジ(伸張) 2,956,082色 BT.601 PCレンジ(ストレート) 4,261,687色 BT.709 TVレンジ(伸張) 3,048,157色 BT.709 PCレンジ(ストレート) 4,400,772色となります。
いやぁ、ほんと色数少ないですね。TrueColorRGBの16,777,216色のうち、最大でも4分の1程度しか使われていません。
バンディングが発生するのも当たり前です。
これが10bitYUV->8bitRGBだとどの程度になるのかは、適当な計算式がとりあえず見当たらなかったのでやってませんが、8bit->10bitでY,U,Vの精度がそれぞれ4倍になることを考えれば、色数もかなり良い感じに増えそうです。
てなわけで、10bitエンコードの力を確認するためにバカ高い業務用モニタ等は別に必要ありません。
民生品でもそこそこの品質があれば違いは確実にわかります(もちろん、良いものであればもっとよく分かるでしょうが)。
つーか、AviUtlのプレビューがやたら綺麗に見える理由って、まさにこれだよね。
2012年1月5日木曜日
avs2pipemod その10
更新しました。
avs2pipemod-0.1.1.7z
https://github.com/chikuzen/avs2pipemod
コードの大部分を書き直しました。
* avisynth.libが要らなくなった。
これまではビルドするためにavisynth.libを使う必要がありましたが、これをやめてLoadLibrary()を使うようにしました。
これにより64bit用もビルド出来るようになりました。
* avisynth.dllのバージョンを検出し、挙動を切り替えるようにした。
てなわけでavs2pipe26modはなくなりました。
* おまけ
SetMTModeに応じてDistributor()を自動追加する機能もコードには存在します。
もし、この機能が欲しい人は、make時に'XCFLAGS=-DBLAME_THE_FLUFF'を追加して自ビルドして下さい。
avs2pipemod-0.1.1.7z
https://github.com/chikuzen/avs2pipemod
コードの大部分を書き直しました。
* avisynth.libが要らなくなった。
これまではビルドするためにavisynth.libを使う必要がありましたが、これをやめてLoadLibrary()を使うようにしました。
これにより64bit用もビルド出来るようになりました。
* avisynth.dllのバージョンを検出し、挙動を切り替えるようにした。
てなわけでavs2pipe26modはなくなりました。
* おまけ
SetMTModeに応じてDistributor()を自動追加する機能もコードには存在します。
もし、この機能が欲しい人は、make時に'XCFLAGS=-DBLAME_THE_FLUFF'を追加して自ビルドして下さい。
登録:
投稿 (Atom)