コールバック関数を使用する

ここではGrabberListenerクラスライブラリリファレンス>クラス>GrabberListenerから派生するコールバックハンドラによってイベントを処理をする方法について説明します。

このプログラムはディレクトリ%TOPLEVEL%\Samples\VCx\Callbackにございます。
たとえばVC2010++では%TOPLEVEL%\Samples\VC10となり、VC8では%TOPLEVEL%\Samples\VC8です。
プログラムを実行するため、ディレクトリ内のソリューションファイルVidNormFormat.slnを開き メニューからビルド -> ビルド Callbackと選択します。
そこからデバッグ -> スタートと選択することでプログラムを実行することができます。

概要

この例ではsetupDeviceFromFileという関数を使用します。

そのソースコードは%TOPLEVEL%\Samples\VC71\Common\CmdHelper.h内にございます。この関数はユーザーにデバイス、ビデオ規格、ビデオフォーマット、入力チャンネルの選択を求めるものです。選択された設定は保存できるため、プログラムを実行するたびに選択をする必要はありません。
次のコードはキャプチャされた画像を受け取るMemBufferCollectionクラスライブラリリファレンス>クラス>MemBufferCollectionを含むFrameHandlerSinkクラスライブラリリファレンス>クラス>FrameHandlerSinkをセットアップする方法です。

// 利用可能なカラーフォーマットを表すFrameTypeInfoArray構造体を作成
FrameTypeInfoArray acceptedTypes = FrameTypeInfoArray::createRGBArray();

// Frame Handler Sinkを作成
smart_ptr pSink = FrameHandlerSink::create( acceptedTypes, NUM_BUFFERS );

// Snap Mode(以前のtFrameGrabberMode::eSNAP)を有効化
pSink->setSnapMode( true );

// sinkをgrabberに適用
grabber.setSinkType( pSink );

プログラムは基底クラスGrabberListenerクラスライブラリリファレンス>クラス>GrabberListenerより"CListener"というクラスを引き出します。そのクラスの実装はサンプルのディレクトリ内の"Listener.h" や "Listener.cpp"で見つけることができます。

CListenerクラスはGrabberListener::overlayCallbackクラスライブラリリファレンス>クラス>GrabberListener>GrabberListener::overlayCallback MethodGrabberListener::frameReadyクラスライブラリリファレンス>クラス>GrabberListener>GrabberListener::frameReady Methodイベント用に登録されます。

// frame readyと overlay callback イベント用に pListenerを登録する
grabber.addListener( pListener, GrabberListener::eFRAMEREADY|
                GrabberListener::eOVERLAYCALLBACK );

GrabberListener::overlayCallbackクラスライブラリリファレンス>クラス>GrabberListener>GrabberListener::overlayCallback Method メソッドではライブ画像上にフレーム数カウンターが描画されます。

/////////////////////////////////////////////////////////////////////////
/*! overlayCallback()メソッドが現在のフレーム数を描画
  frame countはGrabberによってoverlayCallback()に渡されるtsMediaSampleDesc構造体のメンバ
*/
void    CListener::overlayCallback( Grabber& caller, smart_ptr<OverlayBitmap> pBitmap,
                 const tsMediaSampleDesc& MediaSampleDesc)
{
  char szText[25];
  if( pBitmap->getEnable() == true ) // オーバーレイビットマップが有効であれば描画
  {
    sprintf( szText,"%04d ", MediaSampleDesc.FrameNumber);
    pBitmap->drawText( RGB(255,0,0), 0, 0, szText );
  }
}

GrabberListener::frameReadyクラスライブラリリファレンス>クラス>GrabberListener>GrabberListener::frameReady Method メソッドでは指定するバッファがCListener::saveImageメソッドの呼び出しによってBMPファイルに保存されます。

//////////////////////////////////////////////////////////////////////////
/*! frameReady()メソッドがsaveImage メソッドを呼び出しイメージバッファがディスクに保存される
*/
void    CListener::frameReady( Grabber& caller, smart_ptr<MemBuffer> pBuffer, DWORD currFrame)
{
  std::cout << "Buffer " << currFrame << " processed in CListener::frameReady()." << std::endl;

  saveImage( pBuffer, currFrame ); // バッファ処理を行う

  ::Sleep(250); // 長時間の処理をシュミレート
}

パブリックメソッドCListener::saveImageは指定したバッファをBMPファイルとして保存します。どのバッファがディスクに保存されたかをブール配列にマークします。またSleep(250)は長時間の処理業務をシュミレートするのに使用されます。よってGrabberListener::frameReadyクラスライブラリリファレンス>クラス>GrabberListener>GrabberListener::frameReady Methodメソッドがキャプチャされた全てのバッファ用に呼び出されることはありません。

//////////////////////////////////////////////////////////////////////////
/*! MemBufferポインタから渡された画像はBMPファイルに保存される
*/
void    CListener::saveImage( smart_ptr<MemBuffer> pBuffer, DWORD currFrame)
{
  char filename[MAX_PATH];
  if( currFrame < m_BufferWritten.size() )
  {
    sprintf( filename, "image%02i.bmp", currFrame );

    saveToFileBMP( *pBuffer, filename );

    m_BufferWritten.at( currFrame ) = true;
  }
}

サンプルのmain()関数はCListenerのブール配列を使い、コールバックメソッドGrabberListener::frameReadyクラスライブラリリファレンス>クラス>GrabberListener>GrabberListener::frameReady Methodでどのキャプチャ済みバッファが処理されなかったかをチェックしています。
未処理のバッファについては、メソッドCListener::saveImage が処理のために呼び出されます。これによってコールバックメソッドが全てのバッファに対してコールされなくてもバッファが失われることはないというのを表しています。

// CListener::frameReady()が呼び出されなかったバッファを保存
// Sleep(250)がコールされるため、CListener::frameReady()が全てのバッファに対して
// 呼び出されることはない。それでも全バッファがMemBufferCollectionにコピーされる
for( size_t i = 0; i < pListener->m_BufferWritten.size(); i++ )
{
  if( !pListener->m_BufferWritten[i] )
  {
    std::cout << "Buffer " << i << " processed in main()." << std::endl;
    pListener->saveImage( pSink->getMemBufferCollection()->getBuffer( i ), i);
  }
}