複数のアナログ入力があるデバイスを扱う(2)

キャプチャボードやTVチューナーデバイスには、複数のアナログ入力端子が存在するものがあります。 それらの入力デバイスを扱っているとアナログ入力から得られるデータのパス(もしくは経路、もしくはRoute)を設定したくなると思います。 directshowでは、IAMCrossbarを利用することによりそれらの制御が行えます。 ここでは、まず最初の一歩としてキャプチャボードやTVチューナーデバイスなどのアナログ入力に関する情報を取得する方法を説明したいと思います。 (注意)ここの例では、サンプルを簡潔にするためにエラー処理を書いていません。

とりあえず、コードを書いてみる

まず、何も考えずに以下のコードを書いてみましょう。 このコードは、発見したビデオ入力デバイスからIAMCrossbarインターフェースを取得しようとします。 IAMCrossbarが取得できるとそこから得られる情報を表示します。 前述したサンプルでは入力や出力の種類が数値でしたが、今度はデバイスの種類を人間にわかりやすい名前で表示してみました。 前述したサンプルとの違いはそこだけです。


#include <stdio.h>

#include <dshow.h>

const char *
GetPhysicalPinName(long lType)
{
 switch (lType) {
   case PhysConn_Video_Tuner:
	   return "Video Tuner";
   case PhysConn_Video_Composite:
	   return "Video Composite";
   case PhysConn_Video_SVideo:
	   return "S-Video";
   case PhysConn_Video_RGB:
	   return "Video RGB";
   case PhysConn_Video_YRYBY:
	   return "Video YRYBY";
   case PhysConn_Video_SerialDigital:
	   return "Video Serial Digital";
   case PhysConn_Video_ParallelDigital:
	   return "Video Parallel Digital"; 
   case PhysConn_Video_SCSI:
	   return "Video SCSI";
   case PhysConn_Video_AUX:
	   return "Video AUX";
   case PhysConn_Video_1394:
	   return "Video 1394";
   case PhysConn_Video_USB:
	   return "Video USB";
   case PhysConn_Video_VideoDecoder:
	   return "Video Decoder";
   case PhysConn_Video_VideoEncoder:
	   return "Video Encoder";
       
   case PhysConn_Audio_Tuner:
	   return "Audio Tuner";
   case PhysConn_Audio_Line:
	   return "Audio Line";
   case PhysConn_Audio_Mic:
	   return "Audio Microphone";
   case PhysConn_Audio_AESDigital:
	   return "Audio AES/EBU Digital";
   case PhysConn_Audio_SPDIFDigital:
	   return "Audio S/PDIF";
   case PhysConn_Audio_SCSI:
	   return "Audio SCSI";
   case PhysConn_Audio_AUX:
	   return "Audio AUX";
   case PhysConn_Audio_1394:
	   return "Audio 1394";
   case PhysConn_Audio_USB:
	   return "Audio USB";
   case PhysConn_Audio_AudioDecoder:
	   return "Audio Decoder";
        
   default:
	   return "Unknown Type";
 }    
}

int
main()
{
 IGraphBuilder *pGraphBuilder;
 ICaptureGraphBuilder2 *pCaptureGraphBuilder2;

 // 補足情報)英単語の日本語訳
 //   Enumerate : 列挙、一覧
 //   Moniker   : あだ名
 ICreateDevEnum *pCreateDevEnum = NULL;
 IEnumMoniker *pEnumMoniker = NULL;
 IMoniker *pMoniker = NULL;

 ULONG nFetched = 0;
 IBaseFilter *pDeviceFilter;

 // COMを初期化
 CoInitialize(NULL);

 // FilterGraphを生成
 CoCreateInstance(CLSID_FilterGraph,
	NULL,
	CLSCTX_INPROC,
	IID_IGraphBuilder,
	(LPVOID *)&pGraphBuilder);

 // CaptureGraphBuilder2というキャプチャ用GraphBuilderを生成する
 CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC, 
   IID_ICaptureGraphBuilder2, 
   (LPVOID *)&pCaptureGraphBuilder2);

 // FilterGraphをセットする
 pCaptureGraphBuilder2->SetFiltergraph(pGraphBuilder);

 // デバイスを列挙するためのCreateDevEnumを生成
 CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, 
   IID_ICreateDevEnum, (PVOID *)&pCreateDevEnum);
    
 // VideoInputDeviceを列挙するためのEnumMonikerを生成 
 pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,
   &pEnumMoniker, 0);
 if (pEnumMoniker == NULL) {
   // 接続された映像入力デバイスが一つも無い場合にはこのif文に入ります
   printf("no device\n");
   return 0;
 }

 // EnumMonikerをResetする
 // Resetすると、先頭から数えなおします
 pEnumMoniker->Reset();

 // 最初のMonikerを取得
 pEnumMoniker->Next(1, &pMoniker, &nFetched);

 // MonkierをFilterにBindする
 pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pDeviceFilter );

 // FilterGraphにデバイスフィルタを追加する
 pGraphBuilder->AddFilter(pDeviceFilter, L"Device Filter");

 // この時点でMonkier系、Enumerator系は用済み
 pMoniker->Release();
 pEnumMoniker->Release();
 pCreateDevEnum->Release();

 /*
  * IAMCrossbarを利用して入力情報を取得
  */
 HRESULT hr;
 IAMCrossbar *pCrossbar;

 // Graph内からIAMCrossbarを取得。
 // 2つ以上のCrossbarがある場合には、
 // もう一度FindInterfaceを繰り返す必要あり。
 hr = pCaptureGraphBuilder2->FindInterface(&LOOK_UPSTREAM_ONLY,
	    NULL, pDeviceFilter,
        IID_IAMCrossbar, (LPVOID *)&pCrossbar);
 if (hr != S_OK) {
   printf("could not get crossbar\n");
   return 1;
 }

 // PINの数を取得
 long nOutput = -1, nInput = -1;
 pCrossbar->get_PinCounts(&nOutput, &nInput);

 // 出力PIN情報を表示
 printf("Output PINs : %d\n", nOutput);
 for (long i = 0; i < nOutput; i++) {
   long type = -1;
   long related = -1;
   pCrossbar->get_CrossbarPinInfo(FALSE,
                                  i, &related, &type);
   printf("%d: related=%d type=%s\n",
          i, related, GetPhysicalPinName(type));
 }
 printf("\n");

 // 入力PIN情報を表示
 printf("Input PINs : %d\n", nInput);
 for (long i = 0; i < nInput; i++) {
   long type = -1;
   long related = -1;
   pCrossbar->get_CrossbarPinInfo(TRUE,
                                  i, &related, &type);
    printf("%d: related=%d type=%s\n",
          i, related, GetPhysicalPinName(type));
 }

 // 資源を解放
 pCrossbar->Release();

 pCaptureGraphBuilder2->Release();
 pGraphBuilder->Release();

 // COM終了
 CoUninitialize();

 return 0;
}


このサンプルでは、最初に発見したキャプチャデバイスからIAMCrossbarを取得しようとしています。 そのため、キャプチャデバイスが複数存在する環境では不十分です。 キャプチャデバイスが複数ある環境では、まず、適切なキャプチャデバイスに関連するフィルタを選択しなくてはなりません。 キャプチャデバイスフィルタの選択方法は、こちらをご覧下さい。

このサンプルはIAMCrossbarから取得したPIN情報だけを表示しています。 ただ、実際に入力PINと出力PINの経路(Route)を設定しないと使い物になりません。 それらの方法は後述したいと思います。