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プラグインに仕上げました。
#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);
}
view raw jpeg2yuv.c hosted with ❤ by GitHub

0 件のコメント:

コメントを投稿