ようこそゲストさん

無能日記

メッセージ欄

2006年9月の日記

一覧で表示する

2006/09/18(月) DCT-MTVP1

はてブ 2007/04/09 13:18 R&D (streaming)poti
クロッサムと連携して、webからいろいろ遊んでやろうネタです。
ビデオの入出を取り込みたいのでキャプチャーカードが必要になってきました。
でもソフトウェアエンコードだとCPUに常に負荷がかかることになってしまうため、 よろしくない。
ということで、ハードウェアエンコードの物を探す。
でも、linuxで動くハードウェアエンコードのキャプチャーカードは、conexantのcx23416を使ったものだけのよう。
以前NECのチップをつんだキャプチャカードを買ってきたのだが使えない。orz
探してみると、GV-MVP/RX2系が使えそうだがどれもすでに生産終了。
秋葉にいってみるもどこにもなさげ、。。。
あきらめきれず、ivtv 0.7のドライバを落として、ChangeLogを見てみると
DCT-MTVP1をサポートしたとかいてるので、ぐぐってみると売ってそうな気配
もう一度秋葉に行ってみるとTWOTOPにハケーン!(大陸志向。。。)
買って帰って早速試す。

まず、ivtvのドライバをReadme.installに沿ってインストール
途中、なにやら
5. unload any old drivers
と書いてるのがよくわからない(wikiのhowtoに詳細が書いてた)が無視してインスト
modprobe ivtv すると
ivtv: Unknown symbol tveeprom_read
ivtv: Unknown symbol tveeprom_hauppauge_analog
となる

どうやらカーネルで関数が定義されていない模様。。。

ivtvドライバとかぶらない上のエラーが出た関数を使ってるドライバを
make menuconfigで追加してやることに
grep -r tveeprom_ drivers/*
するとbt848のドライバが使っているようだったので、
とりあえず、いいやということで入れてみる

再度modprobe ivtv すると
upd64031a, upd64083, saa7115モジュールがロードできねーよといわれた

(ログなくなちゃった。。。)

make menuconfigで上の3つのドライバモジュールを選択

再度modprobe ivtvすると
なんかきちんと読み込まれているみたい。
でもあきらかに、違うデバイスとして認識されてる予感。。。
ぐぐってみると
ivtvをmodprobeする際のパラメータで変更できるみたい。
ivtvのソースコードから
grep -ir cowboy * とやって番号を探してみると
18っぽいぞ!

というわけで、以下の設定を書いて
/etc/module.conf
alias char-major-81 videodev
alias char-major-81-0 ivtv
options ivtv ntsc=j cardtype=18

再度modprobe ivtv
キターーー!
ivtv:  ==================== START INIT IVTV ====================
ivtv:  version 0.7.0 (tagged release) loading
ivtv:  Linux version: 2.6.17.13 SMP mod_unload PENTIUM4 REGPARM 4KSTACKS gcc-3.4
ivtv:  In case of problems please include the debug info between
ivtv:  the START INIT IVTV and END INIT IVTV lines, along with
ivtv:  any module options, when mailing the ivtv-users mailinglist.
ivtv0: User specified Digital Cowboy DCT-MTVP1 card (detected cx23416 based chip)
ACPI: PCI Interrupt 0000:02:00.0[A] -> GSI 18 (level, low) -> IRQ 16
tuner 1-0060: All bytes are equal. It is not a TEA5767
tuner 1-0060: chip found @ 0xc0 (ivtv i2c driver #0)
tda9887 1-0043: chip found @ 0x86 (ivtv i2c driver #0)
saa7115 1-0021: saa7115 found @ 0x42 (ivtv i2c driver #0)
upd64031a 1-0012: chip found @ 0x24 (ivtv i2c driver #0)
upd64083 1-005c: chip found @ 0xb8 (ivtv i2c driver #0)
ivtv0: loaded v4l-cx2341x-enc.fw firmware (262144 bytes)
ivtv0: Encoder revision: 0x02050032
ivtv0: Allocate DMA encoder MPEG stream: 128 x 32768 buffers (4096KB total)
ivtv0: Allocate DMA encoder YUV stream: 194 x 10800 buffers (2048KB total)
ivtv0: Allocate DMA encoder VBI stream: 120 x 17472 buffers (2048KB total)
ivtv0: Allocate DMA encoder PCM audio stream: 455 x 4608 buffers (2048KB total)
tuner 1-0060: type set to 53 (Philips FQ1286)
ivtv0: Initialized Digital Cowboy DCT-MTVP1, card #0
ivtv:  ====================  END INIT IVTV  ====================
テレビのチャンネルは
ivtv-tune -t japan-bcast -c
でかえれるようだ

ライン入力もしらべなきゃ
調べてみたところ、驚愕の事実発見
外部入力がtunerの映像しかでない?!
これじゃぜんぜんだめじゃんーー

次はこの問題を解決させよう。

2006/09/18(月) ストリーミングしてみよう

はてブ 2007/04/09 13:11 R&D (streaming)poti
前回コンポジットの入力はうけつけられなかったのだけれども、
コンポジットとS−端子を変換するアダプタを買ってきてS端子の入力を
試してみたところ、うまく映りました。(近場で売ってなかったので秋葉まで行くことに)

とりあえず、ストリーミングをしようと思い、探してみると
nc (netcat)
vlc (video lan)
helix server+producer
でできそうでした。
最終的にはmedia plyerやrealone serverでうごかせるところにもって行きたいと思ってはみる。
とりあえずは、vlcで映像がきちんと見れることを確認しようとおもい。
HTTPでアクセスできるようにしてみました。

さくっと、無事視聴できました。
次は、他のでも再生できる簡単な方法でもさがして、webからみれるようにしよう。

/dev/video0の出力がすでにエンコードされているので、
helix producerでエンコードするの無駄なきがするんだけど、
helix serverだけでどうにかできるのだろうか?。。。

2006/09/17(日) クロッサム2+USB

はてブ 2007/04/09 13:03 R&D (remote)poti
以前買ってきたクロッサム2+USBで遊ぶ

USBシリアルとして認識(カーネル再構築必要)させた後、
/dev/ttyU00とかという名前で見えるようになるので、
普通にたたいてあげる。

ただ、何故かレスポンスが返ってこないのがあったりした。
(仕様書には、レスポンスが返ってくるように書かれているが実は帰ってこない?!)

以下ソースコードです。
結構適当です。(SLEEP長すぎ!)
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <errno.h>

#define DEVNAME "/dev/ttyUSB0"
#define DEVNAMBUFF 256
#define LINEBUFF 256

#define INITCMD "\r/c\r"
#define INITCMDLEN strlen("\r/c\r")

#define RESPONSE_TIMEOUT 10
#define COMMAND_SLEEP 1

#define GetDial(c) (c/41)
#define GetKey(c) (c%41)
#define GetCode(d,k) (d*41 +k)

unsigned char PatchData[] = {
        0xA2,0x10,0xBD,0x23,0x10,0x9D,0x00,0x01,    /* 0 */
        0xCA,0x10,0xF7,0xA2,0x40,0xBD,0x33,0x10,
        0x9D,0x00,0x0B,0xCA,0x10,0xF7,0x3C,0x00,    /* 1 */
        0x2B,0x3C,0x00,0x2C,0x3C,0x32,0x06,0x58,
        0x4C,0x00,0x0B,0x7F,0xD7,0x3C,0x80,0xDF,    /* 2 */
        0x8F,0xDE,0x42,0xEA,0x20,0x58,0xC4,0x4C,
        0x15,0x0B,0x00,0x4F,0xFE,0x6F,0xFF,0x8F,    /* 3 */
        0xFE,0x3C,0x00,0xDA,0xCF,0xDA,0x64,0x06,
        0xD0,0x05,0x6F,0xFE,0x4C,0x00,0x01,0xC2,    /* 4 */
        0x9F,0xFE,0x7F,0xFF,0x20,0xEE,0xC0,0x20,
        0xC8,0xC5,0x9F,0xFC,0x20,0x2A,0x0B,0xA5,    /* 5 */
        0x25,0xD0,0xED,0x80,0xD6,0xA7,0x23,0x01,
        0x60,0xBF,0x23,0x3C,0x00,0x2A,0xA2,0x00,    /* 6 */
        0x20,0x44,0xCD,0xC9,0x2F,0xD0,0xF1,0xE8,
        0x4C,0x9E,0xC9,0xFF,0xFF,0xFF,0xFF,0xFF,    /* 7 */
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
};

static int 
serial_open(const char *devname, struct termios *oldtio) {
        struct termios newtio;
        int fd;

        if (devname == NULL) {
                fprintf(stderr, "serial device name is NULL\n");
                return -1;
        }

        if ((fd = open(devname, O_RDWR|O_NOCTTY)) < 0) {
                fprintf(stderr, "can't open device file\n");
                return -1;
        }
 
        if (tcgetattr(fd, oldtio) < 0) {
                fprintf(stderr, "failed tcgetattr()\n");
                return -1;
        }

        memset(&newtio, 0, sizeof(struct termios));

        newtio.c_cflag = B9600 | CS8 | CLOCAL | CREAD;
        newtio.c_iflag = IGNPAR | ICRNL;
        newtio.c_oflag = 0;
        newtio.c_lflag = ICANON;
        cfmakeraw(&newtio);
      newtio.c_cc[VINTR]    = 0;     /* Ctrl-c */ 
        newtio.c_cc[VQUIT]    = 0;     /* Ctrl-\ */
        newtio.c_cc[VERASE]   = 0;     /* del */
        newtio.c_cc[VKILL]    = 0;     /* @ */
        newtio.c_cc[VEOF]     = 4;     /* Ctrl-d */
        newtio.c_cc[VTIME]    = 0;     /* not use charactor timer */
        newtio.c_cc[VMIN]     = 1;     /* block while one charactor */
        newtio.c_cc[VSWTC]    = 0;     /* '\0' */
        newtio.c_cc[VSTART]   = 0;     /* Ctrl-q */ 
        newtio.c_cc[VSTOP]    = 0;     /* Ctrl-s */
        newtio.c_cc[VSUSP]    = 0;     /* Ctrl-z */
        newtio.c_cc[VEOL]     = 0;     /* '\0' */
        newtio.c_cc[VREPRINT] = 0;     /* Ctrl-r */
        newtio.c_cc[VDISCARD] = 0;     /* Ctrl-u */
        newtio.c_cc[VWERASE]  = 0;     /* Ctrl-w */
        newtio.c_cc[VLNEXT]   = 0;     /* Ctrl-v */
        newtio.c_cc[VEOL2]    = 0;     /* '\0' */

        if (tcflush(fd, TCIFLUSH) < 0) {
                fprintf(stderr, "failed tcflush()\n");
                return -1;
        }
        if (tcsetattr(fd,TCSANOW,&newtio) < 0) {
                fprintf(stderr, "failed tcsetattr()\n");
                return -1;
        }

        return fd;
}

static int 
serial_initialize(int fd) {
        unsigned char initdat[LINEBUFF];
        int writelen;
        int i;

        if (fd < 0) {
                fprintf(stderr, "invalid file discriptor\n");
                return 1;
        }

        memset(initdat, 0xFF, LINEBUFF);
        memcpy(initdat, PatchData, sizeof(PatchData)); 

        writelen = write(fd, initdat, LINEBUFF);

        for (i = 0; i < LINEBUFF; i++) {
                if (i % 16 == 0) {
                        printf("\n");
                }
                printf("%02x ", initdat[i]);
        }
        printf("\n");
        printf("write data = %d\n", writelen);

        if (writelen != LINEBUFF) {
                fprintf(stderr, "write failed initial data\n");
                return 1;
        }
        return 0;
}
static int 
serial_close(int fd, struct termios *oldtio) {

        if (fd < 0) {
                fprintf(stderr, "invalid file discriptor\n");
                return 1;
        }

        if (tcsetattr(fd, TCSANOW, oldtio) < 0){
                fprintf(stderr, "failed tcsetattr()\n");
                return 1;
        }

        if (close(fd) < 0){
                fprintf(stderr, "failed close()\n");
                return 1;
        }
        return 0;
}
static int
get_response(int fd, unsigned char *resbuff, int buflen) {
        fd_set rfds;
        int fdmax;
        struct timeval tv;
        int retval;
        int len;
        int i;

        memset(resbuff, 0, buflen);

        FD_ZERO(&rfds);
        FD_SET(fd, &rfds);
        fdmax = fd + 1;

        tv.tv_sec = RESPONSE_TIMEOUT;
        tv.tv_usec = 0;

        retval = select(fdmax, &rfds, NULL, NULL, &tv);
        if (retval < 0) {
                fprintf(stderr, "select error fd = %d errcode = %d\n", 
                    fd, errno);
        } else if (retval) {
                if (FD_ISSET(fd, &rfds)) { 
                        len = read(fd, resbuff, LINEBUFF);
                        resbuff[len] = '\0';
                        fprintf(stderr, "command response <%s>\n", resbuff);
                }
        } else {
                fprintf(stderr, "response timeout\n");
        }
        return 0;
}

static int
cmd_loop(int fd) {
        int end = 0;
        int len;
        unsigned char reqcmd[LINEBUFF];
        unsigned char makecmd[LINEBUFF];
        unsigned char resbuff[LINEBUFF];
        int i;

        if (fd < 0) {
                fprintf(stderr, "invalid file discriptor\n");
                return 1;
        }

        while (end == 0) {
                printf(">");
                fgets(reqcmd, LINEBUFF, stdin);
                len = strlen(reqcmd);
                reqcmd[len - 1] = '\0';
                if (len < 2) {
                        fprintf(stderr, "invalid command %s\n", reqcmd);
                        continue;
                }
                if (strncmp(reqcmd, "/C", 2) == 0) {
                        write(fd, INITCMD, INITCMDLEN);
                        sleep(COMMAND_SLEEP);
                        continue;
                } else if (strncmp(reqcmd, "/I", 2) == 0) {
                        get_response(fd, resbuff, LINEBUFF);
                        serial_initialize(fd);
                        sleep(COMMAND_SLEEP);
                        continue;
                } else if (strncmp(reqcmd, "/q", 2) == 0) {
                        end = 1;
                        continue;
                } else if(strncmp(reqcmd, "/c", 2) != 0 && 
                    strncmp(reqcmd, "/t", 2) != 0 && 
                    strncmp(reqcmd, "/k", 2) != 0 && 
                    strncmp(reqcmd, "/i", 2) != 0 && 
                    strncmp(reqcmd, "/p", 2) != 0 && 
                    strncmp(reqcmd, "/r", 2) != 0) { 
                        fprintf(stderr, "unexpected command\n");
                        continue;
                }

                fprintf(stderr, "try send clear command \n");
                write(fd, INITCMD, INITCMDLEN);
                sleep(COMMAND_SLEEP);
                write(fd, INITCMD, INITCMDLEN);
                sleep(COMMAND_SLEEP);
                get_response(fd, resbuff, LINEBUFF);
                if (strncmp(resbuff, "Ok\r\n", 4) != 0) {
                        continue;
                } else {
                        fprintf(stderr, "response is \"Ok\"\n");
                }

                fprintf(stderr, "try send command <%s> (%d)\n", 
                    reqcmd, strlen(reqcmd));

                snprintf(makecmd, LINEBUFF, "\r%s\r", reqcmd);

                write(fd, makecmd, strlen(makecmd));
                sleep(COMMAND_SLEEP);

        }
        return 0;
}int main(int argc, char **argv) {
        int fd = -1;
        int len;
        unsigned char devname[DEVNAMBUFF];
        unsigned char readbuff[LINEBUFF];
        struct termios oldtio;
        int ch;
        int init = 0;

        strcpy(devname, DEVNAME);

        while ((ch = getopt(argc, argv, "id:")) != -1){
                switch (ch){
                case 'i':
                        init = 1;
                        break;
                case 'd':
                        strcpy(devname, optarg);
                        break;
                default:
                        fprintf(stderr, "%s -i -d <devname>\n", argv[0]);
                        exit(1);
                }
        }

        if ((fd = serial_open(devname, &oldtio)) < 0) {
                fprintf(stderr, "can't open serial\n");
                return 1;
        }

        if (init) {
                printf("please init\n");
                if ((len = read(fd, readbuff, LINEBUFF)) < 0) {
                        fprintf(stderr, "fatal command handling\n");
                        return 1;
                }
                readbuff[len] = '\0';
                printf("response %s\n", readbuff); 

                if (serial_initialize(fd)) {
                        fprintf(stderr, "can't nitialize serial\n");
                        return 1;
                }
        }
        if (cmd_loop(fd)) {
                fprintf(stderr, "fatal command handling\n");
                return 1;
        }

        if (serial_close(fd, &oldtio)) {
                fprintf(stderr, "can't close serial\n");
                return 1;
        }
        return 0;
}
/t3,3とかやったりするとチャンネルが変えれます
だからなんだ。。。。
近いうちにCGI化します。じゃないと意味なさそう。

2006/09/06(水) blog新設

はてブ 2007/04/09 12:54 R&D (blog)poti
ModBlosxom.pmとmod_persisteperlでblogを建ててみました。
通常のCGIのパフォーマンスと比較するパフォーマンスは改善されているようです。
以下その結果です。

初期状態で、通常のCGIを利用する場合

Concurrency Level: 1
Time taken for tests: 59.192166 seconds
Complete requests: 500
Failed requests: 0
Write errors: 0
Total transferred: 268500 bytes
HTML transferred: 192500 bytes
Requests per second: 8.45 [#/sec] (mean)
Time per request: 118.384 [ms] (mean)
Time per request: 118.384 [ms] (mean, across all concurrent requests)
Transfer rate: 4.43 [Kbytes/sec] received

Document Path: /cgibench/mod_perperl/blosxom.cgi
Document Length: 2 bytes

初期状態でModBlosxom.pmとmod_persistperlを使った場合

Concurrency Level: 1
Time taken for tests: 1.580610 seconds
Complete requests: 500
Failed requests: 0
Write errors: 0
Total transferred: 84500 bytes
HTML transferred: 1000 bytes
Requests per second: 316.33 [#/sec] (mean)
Time per request: 3.161 [ms] (mean)
Time per request: 3.161 [ms] (mean, across all concurrent requests)
Transfer rate: 51.88 [Kbytes/sec] received

Document Path: /blog/blosxom.cgi
Document Length: 4640 bytes

ModBlosxom.pmとmod_persistperlでpluginsなどの用いてとりあえず使える状態にした場合

Concurrency Level: 1
Time taken for tests: 5.823000 seconds
Complete requests: 500
Failed requests: 0
Write errors: 0
Total transferred: 2404500 bytes
HTML transferred: 2320000 bytes
Requests per second: 85.87 [#/sec] (mean)
Time per request: 11.646 [ms] (mean)
Time per request: 11.646 [ms] (mean, across all concurrent requests)
Transfer rate: 403.23 [Kbytes/sec] received

なんだかんだいって、ロードするモジュールとかが増えてくるとだいぶパフォーマンスはさがるのかな?
# でも、WikiEditishがうまく動かない。。。。


今回、blogを立ち上げるにあたって、パフォーマンスについてだいぶ考慮してみました。
いろいろ調べてみると、apacheを想定した場合mod_XXX系だと
  • mod_perl
  • mod_php
  • mod_persistentperl
  • mod_fcgid
  • mod_fastcgi
あたりが早いらしい。

java系は
  • resin
  • tomcat
がある。

mod_perl registryは通常のperlスクリプトを動かすとき書き直すのは手間がかかるため、
やるなら手間的にはmod_persistentperlのほうがよいと思う。
その点、mod_phpは実は手ごろなんじゃないかと思えてきたがPHP書けないので、もとい書く気ないので。。。
また、resinはmod_perl並みのパフォーマンスをだせるようです。tomcatはちょっと遅いらしい。

で、今回のblog立ち上げを振り返ってい見ると、お手軽にさくっと使えるブログ系なものとして
MT (mod_perl registryで動かすとパフォーマンス改善)
wordpress (mod_php)
blosxom (mod_perl perlrunで動かすのがよさげ)
ModBlosxom.pm (なんかさくっと使えなし、モジュルーがー。。。ってかんじだけど。mod_perl registryでも動作できる。)
adiary (開発途中。mod_perl registryでも動くように最初から作られてる、リリースされたらこれに切り替えよう)
tdiart (動かすとしたら mod_ruby 可能なのか?)
chalow (異色。これで遊ぶとおもしろいかも)
blrojosom (resinで動かせたら面白いかも)
pbble (同上)
などがあるようです。

パフォーマンスがでそうなものを取り上げてみると
MTは実はmod_perl registryでいけるらしい、意外です。
blojsomとpbbleはjava系なのでこれらをresinで動かせればかなりのパフォーマンスが出るような気がする。
また、mod_php仕様のwordpressもパフォーマンスが期待でそう。
上の3つはいつかやってみたいと思う。

実際は、それぞれの実装にも左右されると思う。
個人的には、最終的にはadiary。。。。だめ?