2012年10月29日月曜日

vstgareader

結局libtgaをそのまま使うのは諦めて、コードを一部流用するほかは全部自分で書くことにしました。
まあ、そのほうがビルドしやすいし、使いやすいですからね。

vstgareader-0.1.0.7z
https://github.com/chikuzen/vstgareader

さて、これでBMP,JPEG,PNG,TGAとだいたい揃ってきたので、これらをなんとか一つに統合したいところですが…どうしようかなぁ。

2012年10月25日木曜日

libtga

PNGもなんとかなったので今度はTGAに挑戦です。

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に差し替えてみたらあっさりと動きました…。

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で読めるし。

2012年10月16日火曜日

vsjpgreader その2

更新しました。

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プラグインに仕上げました。

2012年10月12日金曜日

HBVFWSource.dll その3

更新しました。

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氏が音信不通なので、相談相手がおりません。

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が少し速くなりました。

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は完全にさようならです。

2012年10月5日金曜日

vsavsreader.dll その4

vsavsreaderは最初からdither hackのinterleaved formatに対応していたわけですが、readmeにはそのことについては何も書いていませんでした。
これは単にreadmeに書くのが非常にめんどかったので放置していただけなわけですが、この度Doom9のほうで奇特にも書いてくれた人がいましたので追加しました。

vsavsreader-8c6c94a.7z
http://github.com/chikuzen/VS_AvsReader

いやはや、ありがたいことです。

P216改めP21x VFW Reader for AviUtl

HBVFWSourceのほうをいろいろいじっているうちに、P210やP010といったフォーマットについて誤解していたことに気づきました。
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してしまった人は差し替えて下さい。

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の時代ですよ…。

2012年10月1日月曜日

vsavsreader.dll その3

更新しました。

vsavsreader-4dafb1b.7z
https://github.com/chikuzen/VS_AvsReader

*vsavsreaderで作ったクリップをSplice()で結合出来なかったりしたのを修正