aravis解析 [aravis]
先日コメントをもらって、その気になってしまった。Gen<i>Cam規格カメラのLinux上のドライバであるaravisの中身を見ることにする。
仕事ではそんなことをやってる場合じゃないくて、時間があるならまっ先に書かなきゃいけないアプリケーションとかがあるんだけど、これもいずれは必要になるはずなのでLowest Priorityでやることにする(でも仕事のプライオリティって簡単にひっくり返るからなあ。それに比べて技術進捗の帯域ってずっと狭いもんな)。ちゃんと細部まで解析できればswiftで書き換えてmacOS版のドライバにするところまでいければいいけど、また途中でほったらかすかもしれない。そのときはごめんなさい....
あらためて書くけどGen<i>Cam規格に限らず古いIIDCカメラなんかも含めて無圧縮のデジタルカメラのmacOS用ドライバが書かれることはほとんどなかった。たまにmacOS用のドライバを用意しているメーカもあるけど、たいていはおざなりなもので、Windows版に比べて周回遅れのバージョンだったり、最新のmacOSではそもそも動作しなかったりした。それは今でもそれほど変わっていない。
僕がなぜmacOS版にこだわるかというと、単に僕がmacOSしか知らなくてそのほかのOS、特にWindowsのAPIを理解していないからである。APIがわからなければソフトウェアを書くことはできない。ソフトウェアが書けなければカメラを使うことができない、というわけである(WindowsのAPIを勉強すればいいじゃないか、と言われるかもしれないけど、macOSを追いかけるだけでもひーひー言ってるぐらいなので、とても無理)。
それと、カメラメーカが供給するドライバは同じGen<i>Cam準拠であっても他社のカメラを動かすことはできない。それは製品保証の問題なんかを避けるためのメーカのコンサバな姿勢と、ドライバによるユーザの囲い込みのためであろう。しかしそれぞれのメーカにはそれなりの特徴があり、混在して使える方が便利な場合もある。自分で書けば好きにできる(もちろん、全く同じ動作をするはずの複数のメーカのドライバをすべてリンクすることをダサいと思わなければ、そしてGen<i>Camのtransport層がconflictしなければ、混在は可能である)。
しかし一般論で言えば所詮「車輪の再発明」のようなもので本来無駄な作業である。普通の人はするべきではない。僕固有の必要性と意義と、あとはアナログカメラの時代から30年ずっと自分で書いて自分で使ってきたという、惰性からである。
普通の人は、つまらないことをやってるな、と笑ってスルーして欲しい。
それでは始める。なお、Gen<i>Camそのものに関しては以前詳細をみてきたので、繰り返さない。
しばらく些細な修正程度のコミットしかなかったので集約方向かな、と思ってたんだけどそれがmain contributerのやりかたらしい。僕だったらあっという間に何やってたか忘れてしまうけど。
0.6.2まではlinuxのAutotoolsでmakefileを作っていたけど、これ以降はmesonというビルドシステムに移行するそうである。ということはまだ続ける気を示していると言えそうである。
aravisはCで書かれているけど、オブジェクト指向風の記述になっているため、使うのは簡単である。そのオブジェクト指向システムはGObjectという、Cで記述されCから使うようになっているライブラリを使っている(他言語から呼び出すメカニズムも用意されていて、それもGObjectの目玉のひとつになっているようである)。GObjectの動作をある程度理解しないとaravisは使えないのでGObjectのおさらいをする必要があるが、それはあとにしてGObjectの動作の理解が必要な場合はそれぞれ簡単にReferenceを見るだけにして概観する。
aravisはGObjectを継承したオブジェクトの集合体になっている(GObjectのクラスは基本的にはベースクラスのGObjectを継承する必要がある)。主なオブジェクトとして
などがある。どれもGObjectの流儀に従って、いわゆるopaqueな構造体になっている。とりあえずこれだけ知ってればカメラからの画像を受け取ることができる。
まずカメラオブジェクトを手に入れる。
引数をNULLでarv_camera_new()を呼ぶと一番最初に見つかったカメラを返す。これがNULLでなければ成功である。
次にフレームバッファのサイズを得る。
gintはGObjectでの整数である。
次にストリームオブジェクトを作って、バッファキューを用意する。
サイズを指定してフレームバッファオブジェクトを作って、それをストリームオブジェクトに渡している。この例では50個のバッファをキューにしている。この数はフレームレートや処理のレイテンシなんかを勘案して設定されるべきであろう。
転送を開始する。
そしてデータを受け取る経路を作る。
この例ではコールバック関数を使っている。new_buffer_cb()がコールバック関数で、dataはいわゆるRefConで、呼ばれた時にこのポインタが渡される。
GObjectのclosure/signalというメカニズムを使って行われる。signalはunixのソフトウェア割り込みのことではなく、汎用化された非同期の関数呼び出しのメカニズムらしい。僕のイメージとしてはmacOSのNSNotificationみたいなものなんだけど、僕はちゃんと理解できていない。
そしてこのコールバックが呼ばれるようにしたあと、イベントループを回す。GMainLoopというのはGlibに実装されたイベントループでmacOSのNSRunLoopと基本的な考え方は同じようなものらしい。
このg_main_loop_run()関数はGMainLoopが回っている間ブロックする(returnしてこない)。その間バッファデータはstreamオブジェクトがキューに追加していく。キューに新しく追加されるたびにclosure/signalのメカニズムを経由してコールバックが呼ばれる。コールバックは
の形をしていて、その中で
とする。つまりキューの先頭のバッファをもらって(それがNULLでなければ)表示するなりなんなりした後、使い終わったバッファを捨てずにキューに戻す。pushとpopという言葉を使っているのでスタックかと思うけど、pushがenqueue、popがdequeueのことである。コールバックの中でこの作業をすることで、キューはリングバッファとして動作することになる。
aravisの基本的な使い方はこれだけである。あとはカメラのシャッタやゲインを調整したり、転送を止めたり再開したり、エラー処理をしたり、終了処理をしたり、というchoreが残されている。
次回に続くけど、この調子でやってたら何回かかることやら....
仕事ではそんなことをやってる場合じゃないくて、時間があるならまっ先に書かなきゃいけないアプリケーションとかがあるんだけど、これもいずれは必要になるはずなのでLowest Priorityでやることにする(でも仕事のプライオリティって簡単にひっくり返るからなあ。それに比べて技術進捗の帯域ってずっと狭いもんな)。ちゃんと細部まで解析できればswiftで書き換えてmacOS版のドライバにするところまでいければいいけど、また途中でほったらかすかもしれない。そのときはごめんなさい....
あらためて書くけどGen<i>Cam規格に限らず古いIIDCカメラなんかも含めて無圧縮のデジタルカメラのmacOS用ドライバが書かれることはほとんどなかった。たまにmacOS用のドライバを用意しているメーカもあるけど、たいていはおざなりなもので、Windows版に比べて周回遅れのバージョンだったり、最新のmacOSではそもそも動作しなかったりした。それは今でもそれほど変わっていない。
僕がなぜmacOS版にこだわるかというと、単に僕がmacOSしか知らなくてそのほかのOS、特にWindowsのAPIを理解していないからである。APIがわからなければソフトウェアを書くことはできない。ソフトウェアが書けなければカメラを使うことができない、というわけである(WindowsのAPIを勉強すればいいじゃないか、と言われるかもしれないけど、macOSを追いかけるだけでもひーひー言ってるぐらいなので、とても無理)。
それと、カメラメーカが供給するドライバは同じGen<i>Cam準拠であっても他社のカメラを動かすことはできない。それは製品保証の問題なんかを避けるためのメーカのコンサバな姿勢と、ドライバによるユーザの囲い込みのためであろう。しかしそれぞれのメーカにはそれなりの特徴があり、混在して使える方が便利な場合もある。自分で書けば好きにできる(もちろん、全く同じ動作をするはずの複数のメーカのドライバをすべてリンクすることをダサいと思わなければ、そしてGen<i>Camのtransport層がconflictしなければ、混在は可能である)。
しかし一般論で言えば所詮「車輪の再発明」のようなもので本来無駄な作業である。普通の人はするべきではない。僕固有の必要性と意義と、あとはアナログカメラの時代から30年ずっと自分で書いて自分で使ってきたという、惰性からである。
普通の人は、つまらないことをやってるな、と笑ってスルーして欲しい。
それでは始める。なお、Gen<i>Camそのものに関しては以前詳細をみてきたので、繰り返さない。
2 aravisの概要
aravisはGen<i>Cam規格のカメラ用のLinuxドライバである。GigEとUSB3インターフェイスをサポートしている。現在安定版として0.6.3がポストされている。しばらく些細な修正程度のコミットしかなかったので集約方向かな、と思ってたんだけどそれがmain contributerのやりかたらしい。僕だったらあっという間に何やってたか忘れてしまうけど。
0.6.2まではlinuxのAutotoolsでmakefileを作っていたけど、これ以降はmesonというビルドシステムに移行するそうである。ということはまだ続ける気を示していると言えそうである。
2.1 aravisの使い方
まずaravisはどうやったら使えるか、をざっくりみる。aravisはCで書かれているけど、オブジェクト指向風の記述になっているため、使うのは簡単である。そのオブジェクト指向システムはGObjectという、Cで記述されCから使うようになっているライブラリを使っている(他言語から呼び出すメカニズムも用意されていて、それもGObjectの目玉のひとつになっているようである)。GObjectの動作をある程度理解しないとaravisは使えないのでGObjectのおさらいをする必要があるが、それはあとにしてGObjectの動作の理解が必要な場合はそれぞれ簡単にReferenceを見るだけにして概観する。
aravisはGObjectを継承したオブジェクトの集合体になっている(GObjectのクラスは基本的にはベースクラスのGObjectを継承する必要がある)。主なオブジェクトとして
ArvCamera | カメラオブジェクト |
ArvDevice | カメラのコマンドインターフェイスを表すオブジェクト |
ArvStream | 画像データの転送を制御するオブジェクト |
ArvBuffer | フレームバッファオブジェクト |
などがある。どれもGObjectの流儀に従って、いわゆるopaqueな構造体になっている。とりあえずこれだけ知ってればカメラからの画像を受け取ることができる。
2.1.1 手順
aravisのrefferenceに従って基本的な使い方の手順をまとめる。エラー処理などは当然として省略する。まずカメラオブジェクトを手に入れる。
ArvCamera *camera = arv_camera_new (NULL);
次にフレームバッファのサイズを得る。
gint payload = arv_camera_get_payload (camera);
次にストリームオブジェクトを作って、バッファキューを用意する。
ArvStream *stream = arv_camera_create_stream (camera, NULL, NULL); for (i = 0; i < 50; i++) arv_stream_push_buffer (stream, arv_buffer_new (payload, NULL));
転送を開始する。
arv_camera_start_acquisition (camera);
g_signal_connect (stream, "new-buffer", G_CALLBACK (new_buffer_cb), &data);
GObjectのclosure/signalというメカニズムを使って行われる。signalはunixのソフトウェア割り込みのことではなく、汎用化された非同期の関数呼び出しのメカニズムらしい。僕のイメージとしてはmacOSのNSNotificationみたいなものなんだけど、僕はちゃんと理解できていない。
そしてこのコールバックが呼ばれるようにしたあと、イベントループを回す。GMainLoopというのはGlibに実装されたイベントループでmacOSのNSRunLoopと基本的な考え方は同じようなものらしい。
arv_stream_set_emit_signals (stream, TRUE); GMainLoop *main_loop = g_main_loop_new (NULL, FALSE); g_main_loop_run (main_loop);
static void new_buffer_cb (ArvStream *stream, void *data);
ArvBuffer *buffer = arv_stream_try_pop_buffer (stream); // フレームデータの処理 arv_stream_push_buffer (stream, buffer);
aravisの基本的な使い方はこれだけである。あとはカメラのシャッタやゲインを調整したり、転送を止めたり再開したり、エラー処理をしたり、終了処理をしたり、というchoreが残されている。
次回に続くけど、この調子でやってたら何回かかることやら....
2019-06-15 21:38
nice!(0)
コメント(0)
コメント 0