next up previous
Next: MalibBuffer Up: 各クラスの概要 Previous: MalibHolder

Subsections

   
MalibSource

3.4において、ホルダクラスへの入力ソースを定義するための 抽象クラスである。ソースクラス MalibSource は、そのクラスが生成する データを格納すべきフレームの情報として、サンプルフレームをメンバ変数に持つ。

また、MalibHolder の項で説明したとおり、引数で与えるフレームに データを書き込む機能を提供するバーチャル関数 malib_source_write_frame_data()) を持つ。 本クラスのサブクラスがこの関数を実装し、先に説明した一連の動作に よって処理が進むので、malib_holder_increment_frame() と共に 重要な関数である。

サンプルフレーム情報

MalibSourceに接続されるMalibHolderでは、必要なデータ領域を確 保するために前段のMalibSourceがどれだけの大きさ、どのような形式の 画像データを生成するかを知らなければならない。そのためにMalibSource が保持する情報が、メンバframe_infoで参照されるサンプルフレーム情報 である。

frame_info の利用

サンプルフレーム情報は、基本的にMalibSource(およびそのサブクラス) とMalibHolder(およびそのサブクラス)の接続時に参照され、 次のような目的で利用される。 とくに前者に関しては malib_holder_alloc_data_area() においてデータ領域を確保する際に重要な役割を担い、 [*]ページで説明したように最終的には frame_infoに対してバーチャル関数 malib_frame_alloc_data_area()が呼び出され、 データ領域の確保が実行される(図3.7)。
  
Figure 3.7: サンプルフレーム情報の利用
\includegraphics{images/useframeinfo.eps}

なおMalibSourceあるいはMalibFilterのサブクラスにおいて、 実際のデータの書き込みは接続されたMalibHolderの持つデータ領域に対し て行なわれる。frame_infoは実際のデータ領域は持たないので、 処理後の画像データはframe_infoから直接参照される 何らかのデータ領域に対して行なわれるのではないことに注意する(図 3.8)。


  
Figure 3.8: サンプルフレームは実データを持たない
\includegraphics{images/notuseframeinfo.eps}

frame_info の共有

例えば、ビデオキャプチャソース(MalibBttv)から得たカラー画像に対し、 グレースケールに変換するフィルタ(MalibRgb2Grey)を介し、 X Window System のウィンドウとして画面に表示する (MalibGtkDisplay)ようなリンク構造を作成することとする。

この場合、オブジェクトのリンクは次のように生成される(矢印は データ処理の流れを表す。ポインタの参照方向の逆であることに注意)。

MalibBttv → MalibPlainBuf → MalibRgb2Grey → MalibGtkDisplay

ここで、先頭のMalibBttvが生成するデータはRGB画像であり、 MalibRgb2Greyがグレースケール化して 生成するデータはグレースケール画像である。縦横のピクセル数および 色深度が変わらないとすれば、RGBの3値がグレースケールの1値に 縮約されるので、データ量は1/3となる。

さてこのような場合、MalibSourceに続くMalibHolderが 用意するデータ領域はMalibBttvMalibRgb2Greyで異なることにな る。したがってこれらの間ではサンプルのフレーム情報を共有することが できず、それぞれ独自に用意しなければならない(図3.9、 上)。そのために、 MalibFilterの関数malib_filter_set_buffer_with_frame()が 用意されており、画像サイズあるいはデータ形式が変わるようなフィルタを 作成する場合には、バッファ接続時にこちらの関数を用いて新規のサンプル フレーム情報を設定する必要がある。(MalibFilterの項を参照)。

  
Figure 3.9: サンプルフレーム情報の共有
\includegraphics{images/shareframeinfo.eps}

一方、ビデオキャプチャソースから得た画像に対し、時間的平滑化を行なう フィルタMalibDelayを介し、X Window System のウィンドウとして 画面に表示するようなリンク構造を作成したとすると、 そのオブジェクトのリンクは、次のようになる(MalibDelayは 前段に複数枚のフレームを保持するバッファを要求するので、 MalibPlainBufではなくMalibRingBufを用いなければならない)。

MalibBttv → MalibRingBuf → MalibDelay → MalibGtkDisplay

このケースでは、MalibBttvMalibDelayは同じサイズ、同じ形式 のデータを生成する。したがって各々が別々のサンプルフレーム情報を持つ必要 はない(図3.9、下)。

なおこのようにサンプルフレーム情報は複数から参照されることがあり得るため、 ライフタイムの管理としてリファレンスカウンタを用いる必要がある。サンプル フレーム情報を消去するときには必ずmalib_object_delete()を利用し なければならない。

フレームデータの更新

MalibHolderの項([*]ページ)で説明したように、 新規画像の更新の実際の処理はバッファに新規画像を書込む関数 malib_source_write_frame_data() で実現される。本関数はバーチャル関数として用意されるので、実際には 各サブクラスの実体において実装される個別の関数で、個別の画像処理に 基づくフレームデータの更新が行なわれることになる。

ビデオキャプチャソースの例

malib_source_write_frame_data()の実体に相当する個別の 関数の実装にあたっては、 リファレンスカウンタを用いたフレーム同期の確保のために若干の工夫を しなければならない。ここでは、MalibBttv の新規フレームキャプチャを 実施する関数malib_bttv_capture_next_frame()を例に説明する。

まずmalib_bttv_capture_next_frame()の目的を理解するために、 リファレンスカウンタの操作、およびコメントとエラー処理を省略して 本質的な箇所を抽出すると次のようになる。

static void
malib_bttv_capture_next_frame (MalibBttv* bttv, MalibFrame* frame)
{
  ioctl (bttv->fd, VIDIOCMCAPTURE, &bttv->vmmap);
  bttv->vmmap.frame = (bttv->vmmap.frame == 0) ? 1 : 0;
  ioctl (bttv->fd, VIDIOCSYNC, &bttv->vmmap.frame);
  malib_bttv_write_frame_data (bttv, frame);
}

本関数で行なう操作は以下のとおりである。なおキャプチャデバイスは 2枚のフレームを持ちダブルバッファリングによりCPUと並行してキャプチャが できると仮定されている。

1.
VIDIOCMCAPTUREにより、新規のキャプチャ指示を出す。
2.
対象とするフレームを入れ替える。
3.
VIDIOSYNCによりキャプチャ同期を待つ。入れ替えられた フレームに対するキャプチャ開始指示は、前回の malib_bttv_capture_next_frame()、もしくは 最初のキャプチャであれば、本関数の呼び出し前に必ず呼ぶ必要のある malib_bttv_start_capture()で発効されている。 ここでキャプチャしたデータはbttvが持つフレームバッファに 格納される。
4.
関数malib_bttv_write_frame_data ()により、 引数frameで参照されるフレームデータにキャプチャ データを書き出す。

リファレンスカウンタを用いた同期の確保

上記の手順のみではリファレンスカウンタの機能を用いていないため、 関数が呼び出されるたびにフレームの内容を新たなキャプチャ画像に 更新してしまう。そこで上記リストの4行めから6行めまでの処理は、 refcount == refvarが真である場合のみに実行されるように 記述しなければならない。

リファレンスカウンタのチェックには、 マクロMALIB_OBJECT_COUNT_REFERENCE()を用いるとよい (object.hで定義される)。 このマクロは引数として、リファレンスカウンタチェックの対象とする オブジェクトへのポインタとチェックの結果を返すint型の変数をとる。 またこのマクロではチェックを行なうと同時にテンポラリリファレンス カウンタであるrefvarの値の更新も行なう。

下記に挙げるリストはmalib_bttv_capture_next_frame()の全体 である(説明のため行番号を付加しておく)。

次のリストでは、refcount == refvarが真であるかどうかを 11行めで判断し、その結果を利用して新たにキャプチャ動作を行なうか 否かを分岐させている(13行め〜36行め)。

 1: static void
 2: malib_bttv_capture_next_frame (MalibBttv* bttv, MalibFrame* frame)
 3: {
 4:   int capture_next = 0;
 5: 
 6:   g_return_if_fail (bttv && frame);
 7: 
 8:   /* check and decrement temporary reference counter.
 9:      if temporary ref_counter (refvar) equals to zero, the flag 
10:      'capture_next' becomes true. */
11:   MALIB_OBJECT_COUNT_REFERENCES (bttv, capture_next);
12: 
13:   if (capture_next)
14:     {
15:       /* restart capturing, capture next frame ... */
16:       if (ioctl (bttv->fd, VIDIOCMCAPTURE, &bttv->vmmap) < 0)
17:         {
18:           g_error ("MalibBttv: VIDIOCMCAPTURE");
19:         }
20:       
21:       /* change target buffer 0 <-> 1 */
22:       bttv->vmmap.frame = (bttv->vmmap.frame == 0) ? 1 : 0;
23: 
24:       /* wait until capturing one frame is completed */
25:       if (ioctl (bttv->fd, VIDIOCSYNC, &bttv->vmmap.frame) < 0)
26:         {
27:           g_error ("MalibBttv: VIDIOCSYNC");
28:         }
29: 
30:       /* hook func, if the caputuring hook function is assigned
31:          ex. malib_print_fps() ... measuring fps and print it */
32:       if (bttv->capture_hook) 
33:         {
34:           bttv->capture_hook (bttv->capture_hook_arg);
35:         }
36:     }
37:
38:   malib_bttv_write_frame_data (bttv, frame);
39: }



Jun IIO
2001-06-14