横着プログラミング 第4回: ttyrec: 端末を録画再生するツール

最終更新日: 2002-06-18 (公開日: 2002-06-18)

Unix Magazine 誌に 2002年1月号から 2003年2月号にかけて連載し ていた記事の元の原稿です。


他人のコードを進んで読もう。次に、自分のコードを書こう。
そして、自分のコードを他人にレビューしてもらおう。 -- Bill Gates

*1

プログラミングに上達する最良の方法は他人のコードを読むことだ、 という主張をよく耳にする。実際、私が知っている優秀なプログラ マは皆コードを読むのが趣味のようである。中でも優秀な一人は、 「プログラミングの本など 1冊しかまともに読んだことがない。後 はすべて人のコードを読んで覚えた」という*2

プログラミングの上達という目的はさしおいても、他人のコードを 読んで、それにほんの少しだけ手を加えることによって自分の目的 を達せられることは多い。今回はそのようにして私が開発したソフ トウェア ttyrec を紹介する。

Unixと端末

Unixの世界では伝統的に文字ベースの端末および端末エミュレータ (以下、端末に統一) が広く用いられている。古くは VT100 をはじ めとする専用の端末、グラフィカルなウィンドウシステムが普及し た現在では xterm や kterm をはじめとする端末など、時代を問わ ず端末は Unixには欠かせない存在となっている。Unix が得意とす るコマンドライン指向のテキスト処理との相性のよさが、これほど 端末が広く用いられている理由といえる。

kterm (端末エミュレータ)
kterm (端末エミュレータ)

端末の表現力は、基本的に文字しか出せないという低いものだが (線画を描ける特殊な端末も存在する)、テキスト処理には十分であ り、Emacsのようなテキストエディタも端末の制御コードを用いて 端末内で実行できる。このため、端末さえあれば Unixでの大抵の 作業はこなすことができる。

私の場合、Unixに初めて触れた頃に、 telnet でリモートの計算機 にログインして同じ端末でそのまま作業を続けられる、ということ を知ってずいぶん感銘を受けた。計算機室の奥に置かれている実際 には見たこともない Unixのホストに手元の計算機からログインし て作業する、という感覚にしびれたのである。私が Unix を好きになっ たきっかけはこの体験によるところが大きい。

ttyrec

ttyrec は端末を録画再生するツールである。端末上での作業は emacs でも vi でも w3m でも、端末上で動くプログラムなら何で も録画できる。録画したデータは付属のttyplay コマンドで再生が 可能である。ttyrec は ttyrec のWebサイト *3 から入手できる。

ttyrecの使い方

ttyrec と ttyplay コマンドの使い方は簡単である。基本的には

録画

% ttyrec foo.tty
(シェルが立ち上がるので、自由に作業してから exit)

再生

% ttyplay foo.tty

だけである。録画データは foo.tty ファイルに保存される。 ttyplay で倍速の再生を行うには

% ttyplay -s 2 foo.tty

のようにコマンドラインオプションを渡して速度を指定する。 ttyplayが端末の録画データを再生しているところを見て、録画中 に実行されたコマンドが実際に再実行されているものと勘違いする 人がいるが、ttyplay は録画データを端末に出力しているだけであ り、コマンドの再実行は一切行っていない。

なお、ttyrecは端末への出力のみを記録するため、telnetなどで入 力したパスワードは端末上に出力されないかぎり ttyrec の録画デー タに残ることはない。

覗き見モード

ttyplayコマンドには覗き見モードという機能がある。これは、 ttyrec が録画している端末を別の端末からリアルタイムに覗き見 する機能である。ttyplay の覗き見モードを利用するには次のよう にコマンドラインから実行すればいい。

% ttyplay -p foo.tty

次の図に並んでいる 2つの端末はどちらも同じように見えるが、実 際に作業を行っているのは左の端末で、右の端末は左の端末で動か している ttyrec の録画データを覗き見しているだけである。

覗き見モード
覗き見モード

覗き見は ttyrec の録画データを経由して行うため、ファイルさえ 読めれば他人の端末をリアルタイムに覗き見することができる。録 画中の端末を他人に覗き見されたくないときは

% chmod go-r foo.tty

のように実行して、他人がファイルを読めないようにしておく必要 がある。

ttyrecを用いたファイル転送

ttyrec には端末を介してファイル転送を行うという、一風変わっ た機能がある。たとえば、次の図のようにログインしているときに、 ホストDのファイルを手元のホストAに転送するのは大変である。

ttyrecによるファイル転送
ttyrecによるファイル転送

そこで、ttyrec を -u オプションつきで動かしておくと、このよ うな状況でのファイル転送が簡単に行える。

ファイル転送の方法は簡単である。ホストDでは次のように uuencodeコマンドを実行して転送したいファイルを端末に垂れ流す。

% uuencode foo.zip foo.zip

すると、ホストAで動いている ttyrec が begin 664 foo.zip という uuencode のヘッダを見つけて、手元にファイルを作成する。この ように、ファイル転送は端末への出力を介して行われる。

ttyrec によるファイル転送は、連載第 1回に登場した山下達雄氏 が考案したアイディアに基づいている。氏は、ファイアウォールの 内側の計算機からファイルを転送しようとした際に困難に直面し、 端末上で見えているファイルが簡単に手元に転送できないのはおか しい、と強い不満を感じた。

氏がまず試みたのは、kterm のフォントをunreadable に設定して *4、端末 いっぱいに表示した文字列をマウスでコピーアンドペーストすると いう手法である。解像度にもよるが、unreadableフォントの kterm を最大化 すると、一画面に 200-900 KB 程度の文字が出せる。

unreadableなkterm
unreadableなkterm

これはこれでおもしろい手法だが、便利とはいい難い。そこで、次 に氏が思いついたのが ttyrec を用いたファイル転送である。さっ そく私はこのアイディアを ttyrec に実装して画期的な発明だと喜 んでいたのだが、端末をファイル転送のメディアとして用いる手法 は古くから存在することがわかった。

たとえば、パソコン通信の通信文を常に監視して、メッセージに含 まれるish *5 フォーマットのテキストを裏で検出して復号するというrish *6 というツールがある。これは、ttyrec -u が行っている処理とほぼ 同様である。つまり、ttyrecによるファイル転送は画期的なアイディ アでも何でもなく、大昔からある手法の一種に過ぎなかったのであ る。

ttyrecの問題点

ttyrec の録画データには、端末の大きさに関する情報が含まれな いという問題がある。再生は録画したときと同じ大きさの端末で行 う必要があるが、録画したときの端末の大きさは録画データから知 ることができない。そこで、後述する tty mania では、端末の大 きさを80桁×24行に限定して、録画データを配布している。

録画データに端末の大きさに関する情報を残すことも考えたが、録 画中に端末の大きさが変わったときや、再生時に端末の大きさを変 更する処理が複雑になると想定されたため、実現は見送った。

tty mania

ttyrec を公開してしばらくすると、 ttyrec をソフトウェアのプ ロモーションビデオの作成に使おうという動きが現れた。Emacsの愛 好家である大和正武氏は、土屋雅稔氏が開発した emacs-w3m *7 という Emacs 上の Webブ ラウザ向けのプロモーションビデオを作成し、不可解なアジテーショ ンとともに、その宣伝活動を行った。次にその檄文の一部を抜粋す る。

最近特に開発が盛んなemacs-w3mが動作している様を撮影し,Emacs
Video計画の第一段として,世に問うことにした.すでにS式中毒に
consされている同志諸君においては,このVideoに対する忌憚のな
い意見を聞かせて欲しい.またおのおの,育て上げてきた自慢のラ
イブラリの動作やshare/lispを漁って身に付けた秘密の技術を撮影
し,広く公表することにより,この計画に参入してくれることを希
望する.すべてのソフトウェアの設定ファイルのフォーマットが S
式であるという素晴しい世界を実現しようではないか.

emacs-w3m
emacs-w3m
emacs-w3m
emacs-w3m
emacs-w3m
emacs-w3m
emacs-w3m
emacs-w3m

emacs-w3m
emacs-w3m
emacs-w3m
emacs-w3m
emacs-w3m
emacs-w3m
emacs-w3m
emacs-w3m

tty mania*8 は、このようにして各 方面に飛び火したプロモーションビデオ作成熱が高じて出来上がっ た Webサイトである。くだんのビデオをはじめとして、各種のプロ モーションビデオが公開されている。

また、tty mania では単に ttyrec で録画したデータをファイルと して置くだけではなく、 ttyplayサーバによる動画配信サービスも 行っている。 ttyplayサーバは、クライアント側に telnet コマン ドさえあれば簡単に接続できるという点で優れている。クライアン ト側では ttyrec をインストールする必要はなく、emacs-w3m のビ デオを見るためには端末から telnet コマンドを使って次のように 実行するだけでいい。

% telnet tty.namazu.org 12345

ttyplay サーバ

ttyplayサーバの実現方法は北目拓郎氏によって考案された。といっ ても、単に /etc/inetd.conf に次のような設定を加えるだけであ る。

12345 stream tcp nowait root ttyplay /somewhere/emacs-w3m.tty

この設定を加えれば

% telnet tty.namazu.org 12345

のように別の計算機から ttyplayサーバに接続して /somewhere/emacs-w3m.tty を再生することができる。

さらに、ttyplay の覗き見モードを利用すれば、リアルタイムのス トリーミングが行えることがわかった。この場合は /etc/inetd.conf に

23456 stream tcp nowait root ttyplay -p /somewhere/realtime.tty

のように -p オプションをつける。このストリーミングの仕掛けに より、自分が行っている作業を遠隔地の人間にリアルタイムで伝え ることができる。ごく狭い仲間内で行われたストリーミング実験で は、特に意味のあることをしたわけでもないのに、 IRC*9 によるチャット と連動して大いに盛り上がった。

このように、新たなコードを何も書かずに、既存の inetd という ツールと組み合わせるだけで、ttyplay サーバが実現できたのは Unix のツールボックスアプローチの賜物といえる。ポート番号で コンテンツを切り替えるという安直なサーバではあるが、動くこと には違いない。労少なくして功多しである。

tty mania のコンテンツ

tty mania に登録されているコンテンツの中でも最もインパクトが あるのは小松弘幸氏が投稿したラジオ体操ビデオである。これは、 氏が踊っている姿をビデオカメラで撮影し、 aatv *10 でその映像をアスキーアート に変換したものである。実際に ttyplay で再生すると、非常にな めらかに動く。

体操
体操
体操
体操
体操
体操
体操
体操

体操
体操
体操
体操
体操
体操
体操
体操

一方、旧世代Unixハッカーの面目躍如たる森本淳氏は xterm の Tektronix互換モードを生かし、グラフィック表示を ttyrec で録 画することに成功した。当初、ttyrec は文字ベースの情報しか扱 えないと思われていたが、Tektronix互換モードを活用することに よりグラフィック表示の録画再生という新たな可能性が生まれた。

Tektronix
Tektronix
Tektronix
Tektronix
Tektronix
Tektronix

tty mania は運営が開始されるとともに、すぐさま新しいもの好き の間で話題にのぼり、tty.namazu.org のトップページへの初日の アクセスは約 800件に達した。

ところで、tty mania と同様のアプローチのサイトとして Kevin On Demand! *11 がある。 このサイトでは、Kevin Mitonick 氏が Tsutomu Shimomura 氏の計 算機に不正侵入する様子を、 tty mania と同様にtelnet コマンド だけで見ることができる。通常の端末の出力に加えて経過時間を表 示するなど、非常によくできているが、残念ながら Kevin On Demand! を実現するソフトウェアは公開されていない。Webサイト の説明によると、この録画データはtcpdump *12 の改良版の出力から再構成した そうである。

ttyrecの開発

ttyrecの開発にあたってまず目をつけたのが script コマンドであ る。scriptコマンドは端末に出力されたすべての文字 (制御文字を 含む) をファイルに保存する。scriptコマンドについては 2002年3 月号の本紙連載『プログラミング・テクニック』に詳しい。

そこで、script コマンドにマイクロ秒単位で時刻情報を埋め込む 機能を追加すれば、端末の録画を簡単に実現できると思いついた。 script コマンドの man を読むと、HISTORY の節から BSD 由来の コマンドであることがわかる。

HISTORY
     The script command appeared in 3.0BSD.

script コマンドに手を加えるにあたって、まずは手元の Red Hat Linux で使われている script コマンドのソースコードを入手する ことから始めた。rpm コマンドを使って次のように実行すると、 script コマンドを含む RPM パッケージがわかる。

% rpm -qf /usr/bin/script
util-linux-2.10s-12

パッケージ名がわかれば、Red Hat Linux のソースコードパッケー ジ (SRPM) から目的のソースコードが得られる。なお、util-linux の最新版は kernel.org*13 から入手できる。

ソースコードが入手できれば、後は、時刻情報を埋め込むように script コマンドに手を入れて ttyrec を作り、再生用の ttyplay コマンドを新たに作るだけである。ttyrec および ttyplay の開発 はものの半日で完了した。

ttyrecコマンドの実装

ttyrec コマンドは基本的には script.c の dooutput 関数のループ

for (;;) {
        cc = read(master, obuf, sizeof (obuf));
        if (cc <= 0)
                break;
        (void) write(1, obuf, cc);
        (void) fwrite(obuf, 1, cc, fscript);
        if (fflg)
                (void) fflush(fscript);
}

for (;;) {
        Header h;

        cc = read(master, obuf, BUFSIZ);
        if (cc <= 0)
                break;
        if (uflg)
            check_output(obuf, cc);
        h.len = cc;
        gettimeofday(&h.tv, NULL);
        (void) write(1, obuf, cc);
        (void) write_header(fscript, &h);
        (void) fwrite(obuf, 1, cc, fscript);
}

のように修正するだけで出来上がった。元の script のループでは バッファ obuf に端末に出力されたバイト列を格納し、それをファ イルに書き出している。一方、ttyrec はこのバイト列の固まりの 先頭に時刻情報と、バイト列の長さを埋め込んでひとかたまりのデー タとしている。ttyrecが書き出すファイルはこのひとかたまりのデー タを数珠繋ぎに連結したものである。

├─    へッダ情報      ─┤
┌────┬───────┬────────────┐
│時刻情報│バイト列の長さ│バイト列……………………│
└────┴───────┴────────────┘

Header という型は時刻情報と、文字列の固まりの長さを格納する ための構造体である。具体的には次のように定義されている。

typedef struct header {
    struct timeval tv;
    int len;
} Header;

Header構造体のデータをそのままファイルに書き出すと、エンディ アン*14の異なる計算機 で録画データを共有できないという問題が生じる。このため、 write_header 関数ではリトルエンディアンに統一してからへッダ 情報の保存を行っている。エンディアンの変換を行う関数 htonl, ntohl も存在するが、ここでは汎用性の次の高いマクロを用いてい る。

#define SWAP_ENDIAN(val) ((unsigned int) ( \
    (((unsigned int) (val) & (unsigned int) 0x000000ffU) << 24) | \
    (((unsigned int) (val) & (unsigned int) 0x0000ff00U) <<  8) | \
    (((unsigned int) (val) & (unsigned int) 0x00ff0000U) >>  8) | \
    (((unsigned int) (val) & (unsigned int) 0xff000000U) >> 24)))

前述のファイル転送の機能は、 uuencode されたデータの開始を示 す begin 644 foo.zip のような行を見つけた時点で popen 関数で uudecode コマンドを呼び出し、データの終了を示す end 行を見つ けるまで uudecode コマンドにデータを渡し続けることによって実 現している。

void
check_line (const char *line)
{
    static int uuencode_mode = 0;
    static FILE *uudecode;

    if (uuencode_mode == 1) {
        fprintf(uudecode, "%s", line);
        if (strcmp(line, "end\n") == 0) { /* uuencodeデータ終了 */
            pclose(uudecode);
            uuencode_mode = 0;
        }
    } else {
        int dummy; char dummy2[BUFSIZ];
        if (sscanf(line, "begin %o %s", &dummy, dummy2) == 2) {
            /*
             * uuencodeの行が見つかった
             */
            uudecode = popen("uudecode", "w");
            fprintf(uudecode, "%s", line);
            uuencode_mode = 1;
        }
    }
}

ttyplayコマンドの実装

ttyplay コマンドはファイルに記録されたバイト列と時刻情報を元 に録画データを再生する。基本的にはそれだけのコマンドだが、コ マンドラインオプションによって次のように挙動が変わる。

再生速度の設定は単純に変数の値を書き換えるだけでいいが、通常 の再生モード、ウェイトなしモード、覗き見モードはそれぞれ挙動 の性質が少しづつ異なるため、プログラミングに工夫が必要である。 単純に

if (playback_mode) {        /* 通常の再生モード */
   ...
} else if (no_wait_mode) {  /* ウェイトなしモード */
   ...
} else if (peek_mode) {     /* 覗き見モード */
   ...
}

のようにごちゃごちゃと if 文を書いてモードごとの処理を分岐さ せる方法があるが、このような if 文がプログラム全体に分散する とコードが醜くなり保守が難しくなる。そこで、ttyplay では関数 ポインタを用いて、コマンドラインオプションを解析する時点でプ ログラムの挙動を決定づけ、後から if文によるモードごとの処理 の分岐が起きないようにしている。ttyplay.c の main 関数を次に 示す。

int
main (int argc, char **argv)
{
    double speed = 1.0;
    ReadFunc read_func  = ttyread;
    WaitFunc wait_func  = ttywait;
    ProcessFunc process = ttyplayback;
    FILE *input = stdin;

    while (1) {
        int ch = getopt(argc, argv, "s:np");
        if (ch == EOF) {
            break;
        }
        switch (ch) {
        case 's':
            if (optarg == NULL) {
                perror("-s option requires an argument");
                exit(EXIT_FAILURE);
            }
            sscanf(optarg, "%lf", &speed);
            break;
        case 'n':
            wait_func = ttynowait;
            break;
        case 'p':
            process = ttypeek;
            break;
        default:
            usage();
        }
    }

    if (optind < argc) {
        input = efopen(argv[optind], "r");
    }

    process(input, speed, read_func, wait_func);

    return 0;
}

関数ポインタを用いると、関数のポインタを変数に格納して、後か らその変数を介して関数を呼ぶことができる。変数 read_func, wait_func, process が関数ポインタである。変数 process は通常 の再生時には ttyplayback 関数を、覗き見モードには ttypeek 関 数のポインタを格納し、最後のprocess(input, speed, read_func, wait_func) で、どちらか適切な関数を呼ぶ。

変数 wait_func は通常は ttywait 関数のポインタを格納するが、 ウェイトなしモードのときには ttynowait 関数のポインタに差し 換わる。ttywait はマイクロ秒単位でウェイトを行うための関数 である。usleep 関数を持たない Unix が存在するため、select シ ステムコールを用いた汎用性の高い手法でウェイトを実現している。

void
ttywait (struct timeval prev, struct timeval cur, double speed)
{
    struct timeval diff = timeval_diff(prev, cur);
    assert(speed != 0);
    diff.tv_sec  /= speed;
    diff.tv_usec /= speed;
    select(0, NULL, NULL, NULL, &diff);
}

一方、 ttynowait 関数は名前が示す通り、ウェイト処理を一切 行わない。実際にはただの何も行わない空っぽの関数である。

void
ttynowait (struct timeval prev, struct timeval cur, double speed)
{
    /* do nothing */
}

再生を担当する ttyplay 関数は引数として read_func, write_func, wait_func の 3つの関数ポインタを受け取る。

void
ttyplay (FILE *fp, double speed, ReadFunc read_func,
         WriteFunc write_func, WaitFunc wait_func)
{
    int first_time = 1;
    struct timeval prev;

    setbuf(stdout, NULL);
    setbuf(fp, NULL);

    while (1) {
        char *buf;
        Header h;

        if (read_func(fp, &h, &buf) == 0) {
            break;
        }

        if (!first_time) {
            wait_func(prev, h.tv, speed);
        }
        first_time = 0;

        write_func(buf, h.len);
        prev = h.tv;
        free(buf);
    }
}

通常の再生モードでは、この ttyplay 関数に引数として ttyread 関数、ttywrite 関数、および、ウェイトのあるなしに応じて ttywait 関数または ttynowait 関数のポインタが渡される。 ttyread は録画データひとかたまりの読み込み、ttywrite は読み 込んだ録画データを端末に出力するための関数である。

/* 通常の再生モード */
void
ttyplayback (FILE *fp, double speed,
                  ReadFunc read_func, WaitFunc wait_func)
{
    ttyplay(fp, speed, ttyread, ttywrite, wait_func);
}

覗き見モードでは、録画が進行中のデータをリアルタイムに再生す るために、現時点までの録画データをすべて読み飛ばす前処理が必 要である。そのため ttypeek 関数では ttyplay 関数を呼ぶ前に ttyskipall 関数で録画データの読み飛ばしを行っている。

/* 覗き見モード */
void
ttypeek (FILE *fp, double speed,
              ReadFunc read_func, WaitFunc wait_func)
{
    ttyskipall(fp);
    ttyplay(fp, speed, ttypread, ttywrite, ttynowait);
}

void ttyskipall (FILE *fp)
{
    ttyplay(fp, 0, ttyread, ttynowrite, ttynowait);
}

void
ttynowrite (char *buf, int len)
{
    /* do nothing */
}

ttyskipall 関数では、読み込んだ録画データを端末に出力せずに そのまま捨てるために、ttynowrite という空の関数を ttyplay 関 数に渡して、録画データの読み飛ばしを行っている。ttypeek 関数 で使われている ttypread 関数は tail -f コマンドの挙動と同様 に、ファイルの末尾まで読み込みが終了してもしつこく読み込みを 続ける関数である。select システムコールで 0.25秒待ってから clearerr 関数でファイルポインタの状態をリセットして再読み込 みを試みる、というループで実現している。

int
ttypread (FILE *fp, Header *h, char **buf)
{
    while (ttyread(fp, h, buf) == 0) { /* ファイルの末尾にいる */
        struct timeval w = {0, 250000};
        select(0, NULL, NULL, NULL, &w);
        clearerr(fp);
    }
    return 1;
}

ttyplay コマンドではこのように関数ポインタを積極的に利用する ことによって、if文によるモードごとの条件分岐を排除して、プロ グラムの構造を簡潔にまとめている。とはいうものの、関数ポイン タの差し換えのおかげでプログラムの見通しが悪くなっていると感 じる人も少なくないようである。ごちゃごちゃした if 文の方が見 た目は悪くても何が行われるか明白でいいという。確かにこの主張 にも一理あるが、関数ポインタを利用する今回の方法の方がプログ ラムの抽象化という点で私は気に入っている。

ところで、私が関数ポインタが好きなのは Scheme というプログラ ミング言語 *15 の影響が 大きい。Schemeでは「関数に関数と関数を渡してその関数と関数を 合成した関数を関数の返り値として返す」といったプログラミング 手法が一般的に用いられる。

関連ソフトウェア

ここでは ttyrec に関連するソフトウェアを紹介する。

Joey Hess 氏の Debianパッチ

ttyrec が公開される 4 か月ほど前に Joey Hess氏が script コマ ンドの拡張という形で同様のツールを Debian GNU/Linux 向けに開 発していたことが ttyrec の公開後に判明した。アプローチはほぼ 同様だが、Hess 氏の作には次のような特長がある。

北目拓郎氏が ttyrec の Debianパッケージの作成を提案すると、 Hess氏は、自分の拡張を script コマンドに適用する方がいいし、 本家のscript に修正を反映させるのが好ましい、と主張した。もっ とな主張のような気もするが、今さら本家の script に修正を反映 させてそれを普及させるのは難しい気がする。それに、ttyrec を 公開した後で Hess氏のパッチの存在に気づいたのはタイミングが 悪い。おそらく script に手を加えてttyrec と同様の改良を行っ た人は過去に他にもいたのではないかと思われる。

x11rec

ttyrecによって端末の録画が実現されると、今度は任意の Xのアプ リケーションを録画するツールが欲しくなった。調べると、GTK+ *16 のアプリケーションの操作を記録・ 再生する Gerd *17というツー ルが見つかったが、対象が GTK+に限定されることと、出力ではな く操作を記録するために再生時に実際に GTK+アプリケーションが 動かされるという点が不便である。そこで、 X 上のアプリケーショ ンを録画するツールx11rec *18を開発した。これは、 xwd コマンドを連続的に実行して、最後に ImageMagick *19と Gifsicle *20 を用いてMNG またはアニメーションGIFのフォーマットで動画ファイルを作成す るという素朴な代物である。しかし、このような力技なやり方であ るにも関わらず、実用的な性能で動く。 実際、Pentium III 700 MHz の計算機では gnomine を 14.5 fps で録画することができた。

gnomine
gnomine
gnomine
gnomine
gnomine
gnomine
gnomine
gnomine

gnomine
gnomine
gnomine
gnomine
gnomine
gnomine
gnomine
gnomine

x11rec は極めて素朴な手法によって実現されているため、マウス カーソルをキャプチャできない、録画のフレームレートが正確では ない、遅い計算機では使い物にならない、などの多くの欠点を抱え ている。一方、林芳樹氏の vncrec *21は vnc の描画プロ トコルを元に録画を行うため、スクリーンを連続的にビットマップ 画像としてキャプチャするのではなく、一連の描画イベントを記録 する。vnc*22を経由し ているため、マウスカーソルのキャプチャも可能である。さらに、 x11rec が完成してしばらくすると、Rasca 氏による XVidCap *23が見つかった。 これはスクリーンを動画としてキャプチャする GUI つきのツール である。

XVidCap
XVidCap

vncrec や XVidCap と比べると x11rec はずいぶんと素朴なツール である。実際のところ、 x11rec の利点は、Ruby でたった 100行 程度で実現されているという単純さくらいしか残っていない。

ttytv

前述のラジオ体操ビデオは aatv でアスキーアートへの変換を行っ ているが、aatv は白黒の出力しか行えないという制限がある。一 方、日台健一氏による ttytv *24 は動画をカ ラーのアスキーアートとして出力できる。ttytv のサイトに置かれ ている ttytv-demo.tty を ttyplay コマンドで再生すれば ttytv のプロモーションビデオを見ることができる。

バルーン写真
バルーン写真
ttyなバルーン
ttyなバルーン

ttytv と ttyrec を組み合わせれば、テレビ番組をアスキーアート としてハードディスクに録画するといった遊びが楽しめる。なお、 ttytv には PPM形式の画像ファイルをアスキーアートに変換するコ マンド ttyview も付属している。

ttyrecの誕生

ttyrec を作るきっかけは、ビデオカメラを常に装着して人生のあ らゆる場面を録画しよう、という話を聞いたことによる。いわく、 あらゆる場面を録画しておけば、何かものをなくしたときにビデオ を巻き戻して目的のものを簡単に探したり、動画の検索技術の進歩 によって、ある人と最後に会ったのはいつだったかといった記憶も 取り戻せるという。いわば万能記憶力である。

第1回の記事でも述べたように、私の記憶力はすこぶる悪い。そん なわけだから、上のような万能記憶力のコンセプトには強く引かれ るものがある。ウェアラブルコンピューティングの発明者といわれ るトロント大学の Steve Mann教授 *25 は 70年代からカメ ラ付きのウェアラブルコンピュータの装着を実践していたという。 70年代にごっついカメラを額に装着して頭の上から 2本のアンテナ を立てていたのだから、ただ者ではない *26 。最近では映画にまで 出演している *27

しかしながら、額にカメラを装着したり頭からアンテナを立てるの はやはり抵抗がある。そこで、まずは身近なところから行動の記録 をしようとして思いついたのが ttyrec である。

ttyrecの開発が完了すると、さっそくログインシェルの設定ファイ ルに細工をして端末上のすべての行動を ttyrec で記録することに した。私はシェルに zsh *28 を使って いるので~/.zshrc の先頭に次のような設定を加えた*29

if test -z "$TTYRECLOG"; then
    export TTYRECLOG=$HOME/var/log/ttyrec/`date +"%Y-%m-%d"`-$$
    ttyrec $TTYRECLOG
    exit
fi

1か月ほど端末上の全作業を ttyrec で録画したところ、 ~/var/log/ttyrec には 36 MB の録画データが溜まった。 溜まった録画データは後から検索して活用する予定だったが、前回 の記事で紹介したシェルの履歴で十分であることに気づき、端末上 の全作業を録画するという試みはあえなく中止することにした。

おわりに

ttyrec はソフトウェア単体としてみるとたわいもない代物である し、実際にも大したことはできないのだが、どういうわけか「これ を使えばいろいろなことができそうだ」という幻想を物好きな人た ちに与える効果を持っていた。半日で作ったようなソフトウェアで 多くの人を楽しませることができたのは嬉しいかぎりである (とは いっても狭い世界での話だが)。

素朴なアイディアとシンプルな実装が取り柄の ttyrec であるが、 そのコンセプトを発展させて ttyrec を内蔵した端末があればおも しろいのではないかと考えている。これは、GUIのスライダーを使っ て自由自在に過去に遡ったり、過去の作業履歴を動的に検索したり できるという端末である。といっても形を作っただけで実際にはま だ動かない。

ttyrec terminal
ttyrec terminal

端末はUnixを使う上で欠かせない存在だが、その割には進歩がない ようである。もっとゴージャスな端末があってもいいんじゃないか と思っている。


Satoru Takabayashi

*1Robert Slater『Portraits in Silicon』
*2その1冊というのが Harold Abelson, Gerald Sussman, Julie Sussman の『計算機プロ グラムの構造と解釈』という極めつけのプログラミングの教科書な のだが。
*3<http://0xcc.net/ttyrec/>
*4 Ctrl + 右クリックのメニューで unreadable を選択
*5<http://www.vector.co.jp/soft/dos/util/se003700.html>
*6<http://www.vector.co.jp/soft/dos/util/se003678.html>
*7<http://emacs-w3m.namazu.org/>
*8<http://tty.namazu.org/>
*9Internet Relay Chat のこと。詳しくは <http://irc.kyoto-u.ac.jp/> を参照のこと。
*10<http://n00n.free.fr/aatv/>
*11<http://www.takedown.com/evidence/transcripts/>
*12<http://www.tcpdump.org/>
*13<http://www.kernel.org/pub/linux/utils/util-linux/>
*14メモリに値を格納するときの順序。CPUのアーキテクチャに よって異なる。バイトオーダーとも呼ばれる。
*15<http://www.sci.toyama-u.ac.jp/~iwao/Scheme/>
*16<http://www.gtk.org/>
*17<http://www.gtk.org/~timj/gerd/>
*18<http://0xcc.net/x11rec/>
*19<http://www.imagemagick.org/>
*20<http://www.lcdf.org/~eddietwo/gifsicle/>
*21<http://www.sodan.org/~penny/vncrec/>
*22<http://www.uk.research.att.com/vnc/>
*23<http://www.udk-berlin.de/~rasca/xvidcap/>
*24<http://www.nmn.jp/~hidai/software/ttytv/>
*25<http://www.eecg.toronto.edu/~mann/>
*26<http://wearcam.org/historical/>
*27<http://www.cbc.ca/cyberman/>
*28<http://www.zsh.org/>
*29~/.zshrc は自分のホームディレクトリの下の .zshrc ファイルである。私の 場合は/home/satoru/.zshrc。