Xvfbというコマンドをご存知でしょうか?
通常、Xサーバはディスプレイに表示するものですが、Xvfbはディスプレイに表示を行わず、メモリ上に仮想的に表示を行うXサーバです。
Xvfbの、vは仮想(Virtual)、fbはフレームバッファ(Frame Buffer)というわけです。画面を持たないサーバマシンで画像を扱うときに使われることがあります。
ちなみに、そもそも「Xサーバとは?」という方はこちらを参考にしてください。
今回、一つのPC上で、複数の仮想ディスプレイに表示した画面をひとつのディスプレイに出力するものを作っていたのですが、この「複数の仮想ディスプレイ」を実現させるため、Xvfbを使用しました。
- 動作確認で使用した環境
Ubuntu 10.04 DesktopおよびUbuntu 11.04 Desktop
Xvfbの出力はメモリ上に行われるのですが、その出力されたイメージを実際に取り出すには、vncサーバなどのプログラムを使う(XWindowプロトコルを使う)のが通常と思います。
しかし、Xvfbにはスクリーンショットを撮るために、メモリ上のイメージをファイル(メモリマップドファイル)に出力する機能があり、そのファイルを参照することで、その時点の出力イメージを取り出すことができます。
今回は仮想ディスプレイ上に表示された内容をマウスなどで操作する必要はないため、vncサーバを使用せずにこのスクリーンショットを撮る機能を使って目的のシステムを作ります。
Xvfbのmanにもあるように、”-fbdir”を付けて起動すれば、そのディレクトリにスクリーンショットを撮るための画像ファイルが生成されます。
例えば、ディスプレイ番号1として仮想ディスプレイを起動し、そこにxclockを表示し、そのスクリーンショットを画面に表示するには以下のようにします。
$ mkdir /tmp/clock1 $ Xvfb :1 -fbdir /tmp/clock1 & $ DISPLAY=:1 xclock & $ xwud -in /tmp/clock1/Xvfb_screen0
このXvb_screen0というファイル、常に更新されているので(メモリマップドファイルなので当たり前ですが)、連続で読み込んで表示すればスクリーンショットが動画っぽくなりそうです。
しかし残念ながら、xwudには再読み込みし続けるような機能はありません。
何回もxwudの起動終了を繰り返せば動画っぽくなりそうですが、よりスムーズに表示するため、ソースコードを改造して、自動的に表示更新するようにしてみました。
事前準備
以下のようにして必要なパッケージをインストールしておいてください。
sudo apt-get install xvfb sudo apt-get install libx11-dev
xwud改造手順
- 元のソースコードを取ってくる
- パッチファイルを取得
- パッチをあてる
- コンパイル
$ wget 'http://cvsweb.xfree86.org/cvsweb/*checkout*/xc/programs/xwud/xwud.c'
$ wget -O xwud.patch https://blog.bitmeister.jp/wp-content/uploads/2011/07/xwud.patch.txt
$ patch xwud.c xwud.patch
※いちおう、パッチ適用済みのxwud.cも置いておきます。
$ gcc -g -Wall -lX11 -o xwud xwud.c
動かす
この表示更新機能、実は問題があって、CPU負荷が重いのはもちろん、Xvfbの色深度(depth)と表示する画面の色深度が24の時以外では表示更新できないようです。
私が確認した環境は以下のとおりです。
項目 | 値 | 確認方法 |
---|---|---|
xwudの出力先画面の色深度(depth) | 24 | “xwininfo -root”でDepthの値を確認 |
Xvfbの仮想ディスプレイの色深度(depth) | 24 | Xvfb起動時に-screenオプションで指定 |
動作例(すでにXvfbが起動中なら、”killall Xvfb”などとして終了させておいてください。)
$ mkdir /tmp/clock1 $ Xvfb :1 -screen 0 200x200x24 -fbdir /tmp/clock1 & $ DISPLAY=:1 xclock & $ ./xwud -in /tmp/clock1/Xvfb_screen0 -new
※xwudに-newオプションを付けないとうまくいきません。
おそらく、もう少し大胆に変更すれば改善すると思いますが、私の用事は片付いたので、必要な方はソースを眺めてトライしてみてください。
たくさん実行する例(すでにXvfbが起動中なら、”killall Xvfb”などとして終了させておいてください。)
$ for num in 1 2 3 > do > mkdir /tmp/disp$num > Xvfb :$num -screen 0 200x200x24 -fbdir /tmp/disp$num & > done $ for num in 1 2 3 > do > export DISPLAY=:$num > xclock & > xmessage -buttons "" Display $num & > done $ export DISPLAY=:0 $ ./xwud -in /tmp/disp1/Xvfb_screen0 -new -geometry 200x200+50+50 & $ ./xwud -in /tmp/disp2/Xvfb_screen0 -new -geometry 200x200+250+50 & $ ./xwud -in /tmp/disp3/Xvfb_screen0 -new -geometry 200x200+50+250 &
上記で実行したものをまとめて終了する
$ killall Xvfb
補足
今回の改造では表示が変わっていないところも書き換えているので、大きな画面を表示すると必ずCPU負荷が上がってしまいます。
そこで、更新があったところだけを書き換える、といった動作をさせようかとも思ったのですが、vncの再実装にもなりかねないのでやめました。
もし今回のxwud.cの改造版をさらに改造しようという(奇特な)方がいらっしゃいましたら、既存のvncなどとの組み合わせで解決できない問題かどうかをいったん考えてから取り組んでみてください。
お久しぶりです。
最近人とふれあってない人恋しさからしゃしゃり出て参りました。
XvfbがXのスクリーンを作るなら、ffmpegがXのスクリーンを入力に指定出来るので、動画に変換出来そうです。
ここらへん
http://ffmpeg.org/ffmpeg-doc.html#SEC17
そんでもってffserver使ってWebブラウザで見ることも出来るので、(ffmpeg+ffserver)×4で、見る側はブラウザだけで出来たりしないかな~って、ちょこっと思いました。(4つのffserverへのimgタグを持つhtmlファイルを用意)
でもffmpeg+ffserverはすごくCPU負荷が高いから問題外かも・・
お久しぶりです&コメントありがとうございます。
ffmpegは使ったことがないので、そういう機能があることを知りませんでした。vlcにはデスクトップの動画を保存する機能があるのは知っていましたが。
後でffmpeg+ffserverで実験してみますね。
貴重な情報ありがとうございました。