また、MalibHolder の項で説明したとおり、引数で与えるフレームに データを書き込む機能を提供するバーチャル関数 malib_source_write_frame_data()) を持つ。 本クラスのサブクラスがこの関数を実装し、先に説明した一連の動作に よって処理が進むので、malib_holder_increment_frame() と共に 重要な関数である。
ページで説明したように最終的には
frame_infoに対してバーチャル関数
malib_frame_alloc_data_area()が呼び出され、
データ領域の確保が実行される(図3.7)。
なおMalibSourceあるいはMalibFilterのサブクラスにおいて、 実際のデータの書き込みは接続されたMalibHolderの持つデータ領域に対し て行なわれる。frame_infoは実際のデータ領域は持たないので、 処理後の画像データはframe_infoから直接参照される 何らかのデータ領域に対して行なわれるのではないことに注意する(図 3.8)。
この場合、オブジェクトのリンクは次のように生成される(矢印は データ処理の流れを表す。ポインタの参照方向の逆であることに注意)。
MalibBttv → MalibPlainBuf → MalibRgb2Grey → MalibGtkDisplay
ここで、先頭のMalibBttvが生成するデータはRGB画像であり、 MalibRgb2Greyがグレースケール化して 生成するデータはグレースケール画像である。縦横のピクセル数および 色深度が変わらないとすれば、RGBの3値がグレースケールの1値に 縮約されるので、データ量は1/3となる。
さてこのような場合、MalibSourceに続くMalibHolderが
用意するデータ領域はMalibBttvとMalibRgb2Greyで異なることにな
る。したがってこれらの間ではサンプルのフレーム情報を共有することが
できず、それぞれ独自に用意しなければならない(図3.9、
上)。そのために、
MalibFilterの関数malib_filter_set_buffer_with_frame()が
用意されており、画像サイズあるいはデータ形式が変わるようなフィルタを
作成する場合には、バッファ接続時にこちらの関数を用いて新規のサンプル
フレーム情報を設定する必要がある。(MalibFilterの項を参照)。
一方、ビデオキャプチャソースから得た画像に対し、時間的平滑化を行なう フィルタMalibDelayを介し、X Window System のウィンドウとして 画面に表示するようなリンク構造を作成したとすると、 そのオブジェクトのリンクは、次のようになる(MalibDelayは 前段に複数枚のフレームを保持するバッファを要求するので、 MalibPlainBufではなくMalibRingBufを用いなければならない)。
MalibBttv → MalibRingBuf → MalibDelay → MalibGtkDisplay
このケースでは、MalibBttvとMalibDelayは同じサイズ、同じ形式 のデータを生成する。したがって各々が別々のサンプルフレーム情報を持つ必要 はない(図3.9、下)。
なおこのようにサンプルフレーム情報は複数から参照されることがあり得るため、 ライフタイムの管理としてリファレンスカウンタを用いる必要がある。サンプル フレーム情報を消去するときには必ずmalib_object_delete()を利用し なければならない。
ページ)で説明したように、
新規画像の更新の実際の処理はバッファに新規画像を書込む関数
malib_source_write_frame_data()
で実現される。本関数はバーチャル関数として用意されるので、実際には
各サブクラスの実体において実装される個別の関数で、個別の画像処理に
基づくフレームデータの更新が行なわれることになる。
まず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と並行してキャプチャが できると仮定されている。
リファレンスカウンタのチェックには、 マクロ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: }