http://www.mlb.co.jp/picpom/v4lapi_ja.html より

"#"で始まる行は翻訳者のコメントです。

デバイスファイル

Video4Linux には次のデバイスファイルがあります。 これらはキャラクタ型のデバイスであり、"/dev/bttv" として知られていますが、普通 /dev/bttv は /dev/video0 へのシンボリックリンクになっています。
# bttv,bttv?, bttv-fm, bttv-fm?, bttv-vbi, bttv-vbi? は過去の名前です
# 現在これらは互換性の為に残っています。

デバイスファイル名 マイナー番号の範囲 機能
/dev/video 0-63 ビデオキャプチャのためのデバイス
/dev/radio 64-127 AM/FM ラジオ
/dev/vtx 192-223 Teletext チップ
/dev/vbi 224-239 VBIの生データ(Intercast/Teletext)
#Teletext とは文字放送です
#Intercastは Intel が提唱しているVBIを利用した、 TVとインターネットを融合させたシステムです
#VBI とは Vertical Blanking Interval の略で、テレビ信号の垂直帰線消去期間の部分です。
#つまり画面には見えない部分ですが、 この部分を利用してデジタルデータが放送されています。
#日本では、文字放送、Adams, BitCast等がVBIを利用した放送です。

Video4Linuxを利用するプログラムは、まずデバイスファイルをオープンし、 利用したい機能を探し出します。機能の検索で各インターフェースが何をサポートしているのかが分かります。 このAPIはビデオキャプチャーカードのためだけに定義されました。 ラジオカードの場合に ヘこのサブセットが用いられます。 Teletextのインターフェースには既に定義されているVTX APIを利用します。

機能の検索のIoctl

ビデオデバイスがサポートする機能に関する情報を得るにはVIDIOCGCAP ioctl を使います。 struct video_capability を ioctl に渡すと中身を埋めて返してくれます。struct video_capabilityには以下にあげる項目が含まれています。

struct video_capability {
char name[32] このデバイスの本来の名前
int type デバイスのタイプ
int channels radio/tv の入力ソースの数 if appropriate
int audios オーディオデバイスの数 if appropriate
int maxwidth 最大のキャプチャ幅(単位:ピクセル)
int maxheight 最大のキャプチャ高さ(単位:ピクセル)
int minwidth 最小のキャプチャ幅(単位:ピクセル)
int minheight 最小のキャプチャ高さ(単位:ピクセル)
};

type の項目はデバイスの機能に関する情報がフラグとして列記されています。 これには次のものがあります。
#つまり以下の値の論理和で表されます。

名前 説明
VID_TYPE_CAPTURE メモリ上にキャプチャする機能がある
VID_TYPE_TUNER なんらかの形式のチュナーがある
VID_TYPE_TELETEXT teletextの機能がある
VID_TYPE_OVERLAY フレームバッファ上にイメージをオーバーレイする機能がある
VID_TYPE_CHROMAKEY クロマキーでオーバーレイする機能がある
VID_TYPE_CLIPPING オーバーレイのクリッピングをする機能がある
VID_TYPE_FRAMERAM オーバーレイはフレームバッファのメモリを上書きする機能がある
VID_TYPE_SCALES イメージのスケーリングをする機能がある
VID_TYPE_MONOCHROME キャプチャはグレースケールのみである
VID_TYPE_SUBCAPTURE イメージの一部分のみをキャプチャできる

キャプチャーデバイスが返して来る最小と最大のサイズは、 その範囲内で組合せ可能な全ての高さと幅の割合やサイズが 使えるわけではありません。 キャプチャーサイズを設定する場合、 要求されたサイズを越えない範囲で可能な最大のサイズに設定されます。例えば quickcam では 3つの固定的な設定しか出来ません。
#取り込み領域は、NTSCとかPAL等のTVの入力信号のタイプによっても変わります。
#後述の ioctl で TV信号のタイプを変更する場合には注意して下さい。

フレームバッファ

キャプチャーカードから直接フレームバッファにデータを書かせるためには、 フレームバッファのベースアドレス、サイズ、構造を デバイスドライバに教えておかなくてはなりません。 これは特権モードの ioctl であり、本当は Xサーバ自身が設定するべきものです。

VIDIOCSFBUF ioctl でキャプチャーデバイスのためにフレームバッファのパラメータを設定します。 キャプチャカードがフレームバッファへの直接の書き込みをサポートしていない場合、 この ioctl は利用できません。 VIDIOCGFBUF ioctl は現在設定されているパラメータを返します。どちらの場合でも struct video_buffer を使ってパラメータを受渡しします。

struct video_buffer {
void* base バッファの物理ベースアドレス
int height フレームバッファの高さ
int width フレームバッファの幅
int depth フレームバッファのデプス
int bytesperline 次の同じ横位置までのメモリ上でのバイト数
};

これらの値はフレームバッファの物理的なレイアウトを 反映させなければいけないことに注意して下さい。 実際に表示されている領域は実際のフレームバッファより小さい事もあります。 実際、XFree86 ではこれは普通の事です。 XFree86 の DGAエクステンションで、この ioctl で設定するパラメータを得ることが出来ます。ベースアドレスをNULLに設定する事で、 フレームバッファへアクセスをする方法が無い事を示せます。
# XFree86 DGA は プログラムが、X サーバ経由ではなく、直接フレームバッファ
# に描画するのをサポートするために加えられた拡張機能です。

Capture Windows

キャプチャする領域は struct video_window を使って設定します。この構造体はキャプチャする領域と、 必要ならばクリッピングする領域を設定します。 VIDIOCGWIN ioctl で現在の設定を取得でき、 VIDIOCSWIN で新しい値を設定できます。 VIDIOCSWIN の ioctl に成功した場合、これは要求されたパラメータに合わせた、 より良いパラメータを設定した事を意味し、 要求されたパラメータ通りに正確に設定したという意味ではありません。 ユーザプログラムは、VIDIOCGWIN を使って、実際に設定されたパラメータを確認する必要があります。 struct video_window には次のような項目があります。

struct video_window {
__u32 x Xウインドウでの X 座標
__u32 y Xウインドウでの Y 座標
__u32 width キャプチャする幅
__u32 height キャプチャする高さ
__u32 chromakey クロマキーの値(ホストオーダでのRGB32の値)
__u32 flags 追加キャプチャーフラグ
struct video_clip * clips クリッピングする長方形のリスト(設定のみ)
int clipcount クリッピング長方形の数(設定のみ)
};

クリッピング長方形は配列で渡します。クリッピング長方形の各要素には 次の項目があります。

struct video_clip {
__s32 x スキップする長方形のX座標
__s32 y スキップする長方形のY座標
__s32 width スキップする長方形の幅
__s32 height スキップする長方形の高さ
#struct video_clip * next アプリケーション側で自由に使って構いません、 設定しても、しなくても影響はありません
};

単にキャプチャ領域を設定しただけでは、キャプチャリングは有効になりません。 VIDIOCCAPTURE ioctl で1を設定することにより、 オーバーレイキャプチャリングを始めます。 そして0を設定することにより、止める事ができます。

キャプチャーデバイスによっては、 実際に見えている領域の一部をキャプチャできるものもあります。 この場合、VIDEO_TYPE_SUBCAPTURE が設定されています。 video_capture構造体で、 取り込みの領域とレートを指定します。 video_capture構造体には次の項目があります。

struct video_capture {
__u32 x 取り込みの領域のX座標
__u32 y 取り込みの領域のY座標
__u32 width 取り込みの領域の幅
__u32 height 取り込みの領域の高さ
__u16 decimation 取り込みレート
__u16 flags 取り込むときのフラグ
};

取り込むときのフラグ(flags)には次のものがあります

名前 説明
VIDEO_CAPTURE_ODD 奇数フレームのみをキャプチャーする
VIDEO_CAPTURE_EVEN 偶数フレームのみをキャプチャーする
#decimation には、 1秒間にスキップするフレーム数を指定します。(多分)
#現在 video_capture 構造体および、VIDIOCGCAPTURE、VIDIOCSCAPTURE ioctlは使われていません。

ビデオソース

それぞれのvideo4linuxのビデオやオーディオドライバは 1つもしくは複数のソース チャンネルからキャプチャーします。 それぞれのチャンネルに関する情報はVIDIOCGCHAN ioctl を使って得られます。 このioctlを使う前に、呼出側は情報を得たいチャンネルの番号を channelの項目に設定しなくてはなりません。 このioctlに成功した場合、struct video_channel に、そのチャンネル自身についての情報が埋められます。

VIDIOCSCHAN ioctl は int の引数を渡す事により、キャプチャする入力を切替えます。 色の設定や、チューニングに関する設定は同時には渡せません。 呼出側で、チャンネル毎にこれらを管理し設定し直して下さい。 (ビデオ入力毎に別々の設定を保存するのは理にかなっています。)
#すこし間違ってます 。VIDIOCSCHANの引数は int ではなく、struct video_channel* です。
#channel と、norm を正しく設定してVIDIOCSCHAN ioctl を呼んで下さい
#struct video_pictureは全体で一つしかありません。
#ユーザプログラムの方でビデオソース毎に管理した方がよいでしょう。

struct video_channel には次の項目があります。

struct video_channel {
int channel チャンネル番号
char name 入力の名前 - カードの入力ラベルが反映されるのが望ましい。
int tuners この入力につながっているチュナーの数
__u32 flags チュナーの設定
__u16 type 入力のタイプ(もし分かっている場合のみ)
__u16 norm このチャンネルのTV信号のモード
};

flagsの値は、

VIDEO_VC_TUNER チャンネルにはチュナーがある
VIDEO_VC_AUDIO チャンネルにはオーディオがある
VIDEO_VC_NORM チャンネルにはTV信号のモードの設定がある

types の値は

VIDEO_TYPE_TV 入力はTVである
VIDEO_TYPE_CAMERA 入力はカメラである

イメージ属性の設定

取り込み画像のイメージ属性はVIDIOCGPICT ioctlを使えば、 struct video_pictureに得られます。 VIDIOCSPICT ioctl を使ってこれらの値を変更できます。 paletteを除く全ての値は0-65535の間の値にスケーリングします。

struct video_picture には次の項目があります。

struct video_picture {
__u16 brightness 明るさ
__u16 hue 色合い(カラーの場合のみ)
__u16 colour 色の濃さ(カラーの場合のみ)
__u16 contrast コントラスト
__u16 whiteness ホワイトネス (グレースケールの場合のみ)
__u16 depth キャプチャーデプス(フレームバッファのデプスと合わせる必要があるでしょう)
__u16 palette パレット
};

パレットの値には次のものがあります

VIDEO_PALETTE_GREY グレイスケール(255が白).
VIDEO_PALETTE_HI240 BT848の 8bitカラー
VIDEO_PALETTE_RGB565 RGB565 を16 bitにパック
VIDEO_PALETTE_RGB555 RGB555 を16 bitにパック、一番上のビットは未定義
VIDEO_PALETTE_RGB24 RGB888 を 24bitにパック
VIDEO_PALETTE_RGB32 RGB888 を 下位3バイトにいれた32bit. 一番上のバイトは未定義
VIDEO_PALETTE_YUV422 YUV422のビデオのフォーマット - 4bits を Y, 2bits を U, 2bits を Vに割り当てた 8bits
VIDEO_PALETTE_YUYV Describe me
VIDEO_PALETTE_UYVY Describe me
VIDEO_PALETTE_YUV420 YUV420 capture
VIDEO_PALETTE_YUV411 YUV411 capture
VIDEO_PALETTE_RAW RAW capture (BT848)
VIDEO_PALETTE_YUV422P YUV 4:2:2 Planar
VIDEO_PALETTE_YUV411P YUV 4:1:1 Planar

チューニング

それぞれのビデオ入力チャンネルには 複数のチュナーがつながってもよい事になっています。 多くのデバイスはチュナーを持っていませんが、 TVカードや、ラジオカードにはいくつかのチュナーが付いているでしょう。
#しかし、現在のドライバは1つ目 オかアクセス出来ません。

チュナーについての情報はVIDIOCGTUNER ioctlを使って struct video_tunerに得る事が出来ます。チュナーの番号を設定して ioctl を出せば、中身を埋めてきます。チュナーの切替えは VIDIOCSTUNERで使いたいチュナーの番号(int)の引数を与える事で出来ます。
#VIDIOCSTUNERの引数は int ではなく、struct video_tuner* です。
#tuner と、mode を正しく設定して VIDIOCSTUNER ioctl を呼んで下さい
#また、VIDIOCSCHANで設定してからでないと VIDIOCGTUNERに失敗します。

struct video_tunerには次の項目があります。

struct video_tuner {
int tuner チュナーの番号
char name チュナーの本来の名前 (例 FM/AM/TV)
ulong rangelow 設定可能な最低周波数
ulong rangehigh 設定可能な最高周波数
__u32 flags チュナーのフラグ
__u16 mode TV信号のモード(関連する場合のみ)
__u16 signal 信号の強度(分かる場合) - 0-65535の間
};

flagsには次のものがあります

VIDEO_TUNER_PAL PAL を受信する機能がある
VIDEO_TUNER_NTSC NTSC を受信する機能がある
VIDEO_TUNER_SECAM SECAM を受信する機能がある
VIDEO_TUNER_LOW 周波数の設定は詳細モードである
VIDEO_TUNER_NORM TV信号のモードを設定できる
VIDEO_TUNER_STEREO_ON チュナーのオーディオがステレオになっている

mode には次のものがあります。

VIDEO_MODE_PAL PAL のモードになっている
VIDEO_MODE_NTSC NTSC のモードになっている
VIDEO_MODE_SECAM SECAM のモードになっている
VIDEO_MODE_AUTO 自動的にスイッチするモードかモードが設定できない場合

チュナーに設定する周波数は、unsigned の 32bit の値で、実際の周波数の 1/16 MHz の値です。 ただし、 VIDEO_TUNER_LOW のフラグが設定されている場合には、実際の周波数の 1/16 KHzの値です。現在の周波数は unsigned long で管理されていて、 VIDIOCGFREQ ioctl で取り出せ、VIDIOCSFREQ ioctl で設定できます。

オーディオ

TVとラジオデバイスは 複数のオーディオチャンネルを持っている場合があります。 オーディオの設定はVIDIOCGAUDIO ioctl にstruct video_audio を渡すことで得られます。 また。VIDIOCSAUDIO ioctl で設定できます。

struct video_audioには次の項目があります。

struct video_audio {
int audio チャンネル番号
__u16 volume ボリューム
__u16 bass bass
__u16 treble treble
__u32 flags オーディオチャンネルの設定
char name[16] 本来の名前
__u16 mode オーディオ入力のモード
__u16 balance 左右のバランス
__u16 step ハードウエアで設定可能な最小ステップ
};

オーディオチャンネルの設定の flags には次のものがあります

VIDEO_AUDIO_MUTE ミュートされている
VIDEO_AUDIO_MUTABLE ミュートの出来る
VIDEO_AUDIO_VOLUME ボリュームのコントロールが出来る
VIDEO_AUDIO_BASS bassのコントロールが出来る
VIDEO_AUDIO_TREBLE trebleのコントロールが出来る
VIDEO_AUDIO_BALANCE バランスのコントロールが出来る

オーディオ入力のモード

VIDEO_SOUND_MONO モノラルの信号
VIDEO_SOUND_STEREO ステレオの信号(NICAM for TV)
VIDEO_SOUND_LANG1 European TV alternate language 1
VIDEO_SOUND_LANG2 European TV alternate language 2

イメージの取り込み

readのシステムコールから かえって来るたびに、デバイスから次のイ メージが取り込めます。 フォーマットの設定や、正しいサイズのバッファを用意するのは呼出側の 責任です。全てのデバイスが read のシステムコールをサポートしている わけではありません。

別の方法の取り込み方として、デバイスがサポートしていれば、 mmap システムコールを経由した取り込みが行えます。 mmap システムコールを経由して取り込むにはまず最初に、取り込み領域やデプスを設定し、 VIDIOCGMBUF ioctlを使います。この ioctl は、mmap するべきバッファのサイズとフレーム毎のオフセットを答えてくれます。 サポートされるフレームの数はデバイスによりますが、 大抵の場合は1フレームのみでしょう。

video_mbuf structure には次の項目があります。

size マップするバイト数
frames フレームの数
offsets フレーム毎のオフセットバイト数

mmap を行ったら、VIDIOCMCAPTURE ioctl で、取り込みたいイメージのサイズを設定します(この領域は、 最初に行った設定と同じか、小さくなくてはいけません)。 設定が終るとメモリマップドされたバッファにキャプチャが始まります。 ユーザプログラムがバッファを読み終ったら、VIDIOCSYNC ioctl を呼んで、そのフレームをフリーし、キャプチャを続けさせなければいけません。 メモ:VIDIOCSYNC はフリーしたいフレーム番号を引数にとります。バッファが unmap されるか、全てのバッファが埋まると、キャプチャリングは止まります。 ドライバにメモリと画面の両方にキャプチャする用設定した場合、 ドライバは出来る限りの事をします。つまり、 メモリマップされた領域にキャプチャ出来なかったフレームが画面に表示されます。

最後に紹介するioctlは、一つのデバイスが複数のデバイスドライバを 使っている時に、同じデバイスにつながっているデバイスを知るためのものです。 (例えば、video0 は、vbi0 にいつも関連があるとは限りませんので、 intercast の表示プログラムは混乱するかもしれません) VIDIOCGUNIT ioctl は、関連のあるデバイスがある場合に そのマイナー番号 を教えてくれます。 video_unit 構造体には次の項目があります

struct video_unit {
int video ビデオキャプチャデバイス
int vbi VBI キャプチャデバイス
int radio ラジオデバイス
int audio オーディオミキサ
int teletext Teletextデバイス
};

======================================================================
http://www.mlb.co.jp/picpom/Programming-FAQ.html

現在の bttv ではほぼこんな感じです...


初期化
======

bt848 のチップが同期を取れないと、キャプチャーは出来ません。
この場合、errno == EAGAIN が返ります。
(オーバーレイは動きますが、砂の嵐です)
次のことを確認して下さい:

  * 正しいビデオ入力に設定してあるか(VIDIOCSCHAN)
  * 正しいTV信号規格を選択してあるか(VIDIOCSCHAN,VIDIOCSTUNER)
  * 入力がTV場合: チューナが正しく選局されているか。

VIDIOCGCHAN を使って設定可能な入力のチャンネルと、情報を得ることが出来ます。


mmap を使った簡単なキャプチャ
=============================

bttv では bttv のメモリをmmap()で来ます。そこには2フレーム分の
場所があります。ですから、2*BTTV_MAX_FBUF バイト分 mmap 出来ます。

        fd = open("/dev/video", ...);
        /* ... 初期化 ... */
        map = mmap(0,BTTV_MAX_FBUF*2,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);

フレーム 0 はmapした所から始まります, フレーム 1 は map+BTTV_MAX_FBUF から
です。

準備は終りました。キャプチャを始めましょう。struct video_mmapの
各パラメータ(size, format, frame) を埋めて、次のようにしましょう。

        ioctl(fd,VIDIOCMCAPTURE,&video_mmap);

このioctlでドライバーはキャプチャーを始めます。このioctlはすぐに
返ってきますが、ドライバーは非同期に動作しています。
結果を得るには、次のioctlを使って終るのを待たなければいけません。

        ioctl(fd,VIDIOCSYNC,&video_mmap.frame);

まだ取り込みが終っていない場合、このioctlは終了するまで、ブロック
され、終っていれば返って来ます。これだけで、mmap された領域に
結果が取り込めています。


Advanced grabbing
=================

先に述べたやりかたでは、1毎のフレームの場合ではうまくいきます。
フルフレームレート(PALの場合25 fps)で続けて読み続けたい場合には、
これほど簡単ではありません。先程述べたように、ドライバには、
2フレーム分の場所を持っていますが、2つのリクエストを保存する
場所もあります。

フルスピードで正しく動かすための基本的な考え方は、bttv のドライバと
アプリケーションを並行して働かせる事です。
片方のフレームをアプリケーションが処理している間に、ドライバーは
もう一つのフレームに次の画像を取り込みます。
この方法でうまくいくはずです:

        /* ... 初期化 ... */

        ioctl(capture frame 0)

loop:
        ioctl(capture frame 1)
        ioctl(sync    frame 0)
        /*
         * この sync は最初のリクエスト(フレーム0)が終った時に返って来ます。
         * アプリケーションがフレーム0を処理している間も、
         * ドライバーは次のフレーム(フレーム1)を続けて取り込みます。
         * アプリケーションがフレーム0を使い終ったら、フレーム0を
         * 次のリクエストの為に再利用します。
         */
        ioctl(capture frame 0)
        ioctl(sync    frame 1)
        /*
         * 同じ事をします。ただし、ドライバはここで、フレーム0を処理し、
         * アプリケーションはフレーム1を処理します。
         */
        goto loop;


注意
====

video4linuxはまだ現在開発中のものです。デザイン上のバグで、現在でも
時と共に、インターフェースを変更しています。

一つの問題点は、TV信号の規格(PAL/NTSC/...)が、struct video_channel
ではなく、struct video_tunerにある事です。これは、チュナーのついて
いないカードで、PALのビデオレコーダを Composite1 につなげて、
NTSC のカメラを Composite2 につなげたりすると困ってしまいます。
これを直すには、両方の構造体と、VIDIOCSCHAN ioctlを変更する事に
なります。

別の問題としては、VIDIOCSYNC ioctl が引数を取らない事です。
新しいバージョンでは、フレーム番号を引数に取る様になります。
新しいやりかたでは、より安定する事でしょう。

Happy hacking,

   Gerd

--
Gerd Knorr