14.1. アプリケーションでカメラデバイスを扱う方法
ここではカメラデバイスを制御するアプリケーションを実装する方法について、C言語で実装されている既存のソースコードをサンプルに、カメラデバイスの初期化方法やデータの取得方法などについて説明します。
Linuxカーネルのカメラドライバは、Video for Linux Two(V4L2)というビデオキャプチャAPIとして実装するのが一般的です。Armadillo-810 カメラモジュール01 (Bコネクタ用)のデバイスドライバもV4L2デバイスとして実装されているため、ユーザーアプリケーションからは、このV4L2 APIで扱うことができます。
Video for Linux Two(V4L2)についての詳しい情報は、「LINUX MEDIA INFRASTRUCTURE API」の「Video for Linux Two API Specification」やLinuxの解説書籍などをご覧ください。
14.1.1. カメラデバイスを制御するシステムコール
カメラデバイスを制御するには、通常のファイルを操作する場合と同様にシステムコールを介して行われます。カメラデバイスを制御する場合に利用するシステムコールについて説明します。
システムコールのマニュアルを参照するには、次のようにします。
ユーザーアプリケーションからV4L2 APIでカメラデバイスを制御するには、ビデオデバイスファイル(/dev/videoN)を通して行われます。デバイスファイルに対してアクションを行う場合は、通常のファイルと同様にopen()システムコールを使いファイルディスクリプタを取得します。
"flags"には、必ず O_RDWR (読み込み/書き込み許可)が含まれるように指定します。このフラグを指定せずにopen()した場合、ioctl()が失敗するなどの意図しない挙動となってしまう場合があります。
open()の戻り値がファイルディスクリプタとなります。open()でエラーが発生した場合は、戻り値が"-1"となります。
アプリケーションがカメラデバイスを開放する場合には、open()で取得したファイルディスクリプタを開放します。ファイルディスクリプタの開放には、close()システムコールを使います。
V4L2 APIを使用してカメラドライバにアクションを行うには、ioctl()システムコールを利用します。
"request"には、V4L2のリクエストコードを指定します。ほとんどの場合、リクエストコードに渡すデータを第3引数に指定します。
代表的なV4L2リクエストコードを表14.1「画像キャプチャーで利用する代表的なV4L2リクエストコード」に示します。
表14.1 画像キャプチャーで利用する代表的なV4L2リクエストコード リクエストコード | 説明 |
---|
VIDIOC_QUERYCAP |
カメラデバイスに保有する機能を問い合わせます。
アプリケーションが利用したい機能を保有しているかどうかを確認するために行います。 | VIDIOC_S_FMT VIDIOC_G_FMT |
カメラデバイスに画像データのフォーマットを設定・取得します。
PixelFormatを指定する場合は、表14.2「Armadillo-810 カメラモジュール01 (Bコネクタ用)で対応可能なPixelFormat」を参照してください。
| VIDIOC_REQBUFS | 画像データ用のバッファを要求します。 | VIDIOC_QUERYBUF | VIDIOC_REQBUFSで要求したバッファの情報を受けとります。 | VIDIOC_QBUF VIDIOC_DQBUF | バッファをストリーミングキューに繋いだり、外したりします。 | VIDIOC_STREAMON VIDIOC_STREAMOFF | ストリーミングを開始・停止します。開始されるとストリーミングキューに繋がれている空のバッファに画像データが書き込まれます。 | VIDIOC_G_CTRL VIDIOC_S_CTRL | コントロールの設定・取得を行います。主にホワイトバランスや色合いなどの調整に用います。[] |
表14.2 Armadillo-810 カメラモジュール01 (Bコネクタ用)で対応可能なPixelFormat PixelFromat | 説明 |
---|
V4L2_PIX_FMT_YUYV V4L2_PIX_FMT_UYVY | 1ピクセルが16bit長のYUVデータ | V4L2_PIX_FMT_NV12 V4L2_PIX_FMT_NV21 | 1ピクセルが12bit長で輝度データと色差データが分離されたYUVデータ | V4L2_PIX_FMT_NV16 V4L2_PIX_FMT_NV61 | 1ピクセルが16bit長で輝度データと色差データが分離されたYUVデータ | V4L2_PIX_FMT_RGB565 | 1ピクセルが16bit長のRGBデータ |
カメラドライバが確保した画像データ用のバッファを利用する場合、アプリケーションからアクセスできるメモリ空間にマッピングしなおす必要があります。この操作には、mmap()システムコールを利用します。
mmap()したメモリ空間が不要となった場合は、munmap()システムコールを使用してメモリ空間をアンマッピングします。
カメラドライバが画像データの準備を完了するまでアプリケーションをウェイトさせておくには、select()システムコールを利用します。
ここでは、カメラモデル開発セット付属のDVDに収録されているV4L2サンプルコードを例にとって説明します。ソースコード(v4l2-sample-[version].tar.gz)は、DVDの/sample/ディレクトリに収録されています。また、アットマークテクノ ダウンロードサイトからも取得することができます。
まずはじめに、カメラデバイスをオープンしています。カメラデバイスを扱う場合は、このオープン処理が第一歩となります。Armadillo-810 カメラモジュール01 (Bコネクタ用)のデバイスファイルは、"/dev/video1"[](CAMERA_DEV)となります。
次にキャプチャーする画像データのフォーマットを指定しています。640x480のVGAサイズ(CAMERA_WIDTH, CAMERA_HEIGHT)で、PixelFormatにはYUYV(V4L2_PIX_FMT_YUYV)を指定しています。ioctl(VIDIOC_S_FMT)が成功(ret == 0)した場合でも、指定したフォーマットがカメラドライバで未対応であった場合には、fmt内のデータが対応可能なフォーマットに書き換わっている場合があります。意図していないフォーマットで動作するのを防止するために、ioctl(VIDIOC_S_FMT)の後にfmt内のデータを確認しています。
| |
---|
このサンプルではioctl()のシグナルに対する使い勝手の悪さを克服するために、xioctl()という関数を実装しています。ioctl()の処理の最中にシグナルを受けた場合はエラー終了してしまいますが、エラー要因がシグナル受信(EINTR)だった場合に自動的にioctl()を再試行してくれるラッパー関数となっています。
|
続いて、カメラドライバに対して画像データ用のバッファを要求しています。メモリマップ用(V4L2_MEMORY_MMAP)のバッファを2面(MMAP_COUNT)としてioctl(VIDIOC_REQBUFS)を呼び出しています。
カメラドライバがioctl(VIDIOC_REQBUFS)を受けとると、ioctl(VIDIOC_S_FMT)で指定された画像サイズのバッファをメモリ空間から確保します。この場合に、画像サイズ × 面数の合計があまりにも大きな場合はioctl(VIDIOC_REQBUFS)はエラーとなってしまいます。アプリケーションで最低限必要な面数を指定するのがベストでしょう。
ioctl(VIDIOC_REQBUFS)で要求したバッファを面数分取得し、アプリケーションがアクセスできるようにバッファ用のメモリをユーザー空間にマッピング(mmap)しています。
V4L2のキャプチャー処理の基本的な流れは、下記の工程を繰り返します。
ビデオストリームに空の画像バッファをエンキュー(enqueue) ビデオドライバが空の画像バッファをフィル(fill) ビデオストリームからフィルされたバッファをデキュー(dequeue)
(I.) と (III.)はアプリケーションがioctl()を用いて行う工程です。(II.) はビデオドライバが担う工程となっています。バッファをエンキュー後、どのタイミングでデキューすればいいのか?と疑問を持たれるかもしれないのですが、これはselect()を利用することでデキューのタイミングを測ることができます。サンプルコードでもselect()を利用してデキューのタイミングを測っています。
初めてビデオストリームにエンキューする箇所です。ここではキャプチャーが開始されていないため(後述)エンキューされたとしてもフィルされることはありません。キャプチャー開始に備えてあらかじめエンキューしています。
デキューの処理部分は次のコードです。
前述した(I.)〜(III.)の工程を処理しているのが次のコードです。
ビデオストリームにエンキューした画像バッファをフィルするには、キャプチャーを開始しなくてはなりません。キャプチャーを開始すると空の画像バッファがなくなるまで順次フィルを行います。
キャプチャーは停止することができます。
ioctl(VIDIOC_S_FMT)でPixelFormatにV4L2_PIX_FMT_YUYVを設定しているため、取得できる画像データはYUYVフォーマットとなっています。
サンプルコードでは、取得した画像データからPPM(Portable Pix Map)ファイル(.ppm)を作成しています。PPMファイルは、RGB24ビットカラーを表現するフォーマットとなります。取得した画像データはYUYVフォーマットのためPPMファイルを作成するためには、YUYV to RGB24フォーマット変換をする必要があります。サンプルコードでは、yuyv_to_rgb()関数で行っています。
RGB24フォーマットに変換された画像データからPPMファイルを作成しているのは、ppm_writefile()関数です。
14.1.3. サンプルコードをArmadilloで動かしてみる
ここでは、サンプルコードを実際にArmadillo-810で動作させる手順を紹介します。サンプルコードの動作を確認したり、改変して挙動を確認したりする場合などに利用してください。
サンプルコードには、Armadillo-810に最適化してビルドすることができるMakefileが付属しています。makeコマンドを用いて簡単にビルドすることができます。
14.1.3.2. v4l2-sampleをArmadillo-810上で実行させる
ビルドしてできあがったv4l2-sampleをArmadillo-810上で実行させてみましょう。Armadillo-810にファイルを転送する方法はいくつかありますが、ここではFTPを利用します。また、v4l2-sampleは、libnetpbmという共有ライブラリを必要とします。一緒に転送しておきます。
FTPでArmadillo-810にファイルを転送すると/home/ftp/pubにファイルが作成されています。
実行する前に、デフォルトイメージで動作しているuvc-gadgetを停止させます。uvc-gadgetは、カメラデバイスを利用しているためv4l2-sampleがカメラデバイスを利用することができない状態となっています。
続いてv4l2-sample実行してみます。転送したライブラリを利用できるように、ライブラリのサーチパスにカレントディレクトリを指定しています。
作成されたPPMファイルを参照するにはATDEにインストールされている"eog"というイメージビューワーを利用します。PPMファイルはFTPを利用して転送します。
| |
|