概要

DirectShowを用い、接続されているカメラの名称と解像度の一覧を取得し、camera.txtファイルに保存します。
下記は、Windows 7でELECOM UCAM-C0220FとBUFFALO BSW32KM03が接続されている環境での実行後のcamera.txtの内容です。
UCAM-C0220F
  640 *   480  30.0fps
  800 *   600  20.0fps
 1280 *   720   9.0fps
 1280 *  1024   8.0fps
 1600 *  1200   4.0fps
  352 *   288  30.0fps
  320 *   240  30.0fps
  176 *   144  30.0fps
  160 *   120  30.0fps
  640 *   480  30.0fps
BUFFALO BSW32KM03 USB PC Camera
  640 *   480  30.0fps
 1280 *   720  20.0fps
 1280 *   800  20.0fps
 1920 *  1080  20.0fps
  352 *   288  30.0fps
  320 *   240  30.0fps
  176 *   144  30.0fps
  160 *   120  30.0fps
 2016 *  1512  15.0fps
Windows XPで試したところ、USBビデオデバイスと表示されました。
COMは文字コードをUNICODEで表しますので、コンパイル時の文字セットはUNICODEとしてください。マルチバイトでコンパイルはできますが、実行するとデバイス名の1文字目しか表示されません。これは、UNICODEは2byteで1文字を表しており、英数字の場合は1byte目がANSIと同じコード、2バイト目が0なので、マルチバイトでは2バイト目がNULL文字となり文字の終了と判断されるからです。
マルチバイトでコンパイルしたい場合は、Readメンバ関数で取得したUNICODE文字列をマルチバイトに変換するコードを追加してください。

テスト環境

コンパイラ

Visual C++ 2008 Express(32bit)/Standard(32/64bit)
Visual C++ 2013 Express 32bit/64bit

実行環境

Windows 7 32/64bit

プログラムソースの概要

_tWinMain

DirectShowはCOMを使用しているので、CoInitializeでCOMの初期化を行います。
cameraList関数によりカメラの種類と解像度の一覧を取得します。

cameraList

この関数はカメラの一覧を取得しcameraのvectorコンテナに格納します。
CoCreateInstanceによりデバイスの列挙子(オブジェクト)へのポインタを取得します。
取得したオブジェクトのCreateClassEnumeratorメンバ関数によりビデオ・キャプチャ・デバイスの列挙子(オブジェクト)へのポインタを取得します。
引数CLSID_VideoInputDeviceCategoryがビデオ・キャプチャ・デバイスを示しています。
CLSID_AudioInputDeviceCategoryを指定するとオーディオ・キャプチャ・デバイスが指定されます。
取得したオブジェクトのNextメンバ関数により順番にデバイスのモニカを取得します。
モニカのメンバ関数であるBindToStorageによりIPropertyBagインターフェースを取得します。
IPropertyBagインターフェースのReadメンバー関数に文字列FriendlyNameを与えて呼び出すとデバイス名が取得できます。
VariantClearによりデイバス名が保存されているメモリを解放します。
BindToObjectメンバ関数によりモニカをフィルタオブジェクトにバインドし、resList関数を呼び出し、解像度の一覧を取得します。
Releaseによりモニカを解放します。
Nextメンバー関数がS_OK以外を返すまで繰り返します。
Nextメンバー関数がS_OK以外を返した場合、デバイスの列挙が終了したので、列挙子のメモリを開放します。

resList

CoCreateInstance関数によりキャプチャグラフを作成します。
FindInterface関数によりビデオフォーマットを示すポインタを取得します。
GetNumberOfCapabilitiesによりサポートしているピン数と構造体のサイズを取得しVIDEO_STREAM_CONFIG_CAPS構造体であれば、解像度が取得できます。
GetStreamCaps関数によりフォーマット機能のセットを取得し有効なものであれば、res_fput関数を呼び出し解像度をファイルに保存します。

res_fput

解像度をファイルに保存します。

ソースコード

// Direct Show カメラの一覧と解像度を表示

#include <windows.h>
#include <tchar.h>
#include <dshow.h>
#include <stdio.h>
#include <conio.h>

#pragma comment(lib, "strmiids.lib")

int cameraMax=0;	//	カメラ数

//	カメラ一覧を取得
int cameraList(FILE* fp);

//	サポートしている解像度・フレームレートを取得する
void resList(IBaseFilter *pbf , FILE* fp);

//	解像度の情報をファイルに出力
void res_fput(FILE* fp,VIDEOINFOHEADER* video);


int WINAPI _tWinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, TCHAR* CmdLine, int nCmdShow){
	// COMの初期化
	if(FAILED(CoInitialize(NULL))){
		MessageBox(0,_TEXT("COMの初期化に失敗しました"),_TEXT("エラー"),MB_OK);
		return 1;
	}
	FILE* fp;
	if (_tfopen_s(&fp, _TEXT("camera.txt"), _TEXT("w"))){
		MessageBox(0, _TEXT("ログファイルが作成できませんでした"), _TEXT("エラー"), MB_OK);
		return 1;
	}
	::cameraMax=cameraList(fp);
	if(::cameraMax==0){
		_ftprintf(fp,_TEXT("カメラは見つかりませんでした。\n"));
	}
	CoUninitialize(); // COMを終了
	return 0;
}

//	カメラ一覧を取得

int cameraList(FILE* fp){

	// システムデバイス列挙子の作成
	ICreateDevEnum *pDevEnum = NULL;
	CoCreateInstance(CLSID_SystemDeviceEnum, 
	NULL, CLSCTX_INPROC, IID_ICreateDevEnum, (void **)&pDevEnum);

	// 列挙子の取得
	IEnumMoniker *pClassEnum = NULL;
	pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pClassEnum, 0);
	if(pClassEnum == NULL){
		pDevEnum->Release();
		return 0;
	}

	ULONG cFetched;
	IMoniker *pMoniker = NULL;
	IBaseFilter *pbf = NULL;
	int n=0;
	while(pClassEnum->Next(1, &pMoniker, &cFetched) == S_OK){
		IPropertyBag *pP = NULL;
		VARIANT var;

		pMoniker->BindToStorage(0,0,IID_IPropertyBag,(void**)&pP);
		var.vt=VT_BSTR;
		pP->Read(_TEXT("FriendlyName"),&var,0);
		//	デバイス名をファイルへ書き込み
		_ftprintf(fp,_TEXT("%s\n"),var.bstrVal);
		VariantClear(&var);

		pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pbf); // モニカをフィルタオブジェクトにバインド
		resList(pbf,fp);

		pMoniker->Release();
		++n;
	}	
	pDevEnum->Release(); // 以後に不要なメモリーをリリース
	pClassEnum->Release();
	return n;
}

//	サポートしている解像度・フレームレートを取得する

void resList(IBaseFilter *pbf , FILE* fp){
	HRESULT hr;

	// キャプチャグラフ作成
	ICaptureGraphBuilder2 *pCapture = NULL;
	CoCreateInstance(CLSID_CaptureGraphBuilder2, 
	NULL, CLSCTX_INPROC, IID_ICaptureGraphBuilder2, (void **) &pCapture);

	// ビデオフォーマットの取得
	IAMStreamConfig *pConfig = NULL;
	hr = pCapture->FindInterface(&PIN_CATEGORY_CAPTURE, 
	0, pbf, IID_IAMStreamConfig, (void**)&pConfig); // インターフェイスのポインタを取得

	int iCount=0;
	int	iSize=0;
	hr = pConfig->GetNumberOfCapabilities(&iCount, &iSize);
	if(iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS)){// VIDEO_STREAM_CONFIG_CAPS構造体かサイズを確認
		for(int iFormat=0; iFormat<iCount; iFormat++){
			VIDEO_STREAM_CONFIG_CAPS scc;
			AM_MEDIA_TYPE *pmtConfig;
			hr = pConfig->GetStreamCaps(iFormat, &pmtConfig, (BYTE*)&scc);
			VIDEOINFOHEADER *pVih2;
			if(SUCCEEDED(hr)){
				if((pmtConfig->majortype == MEDIATYPE_Video)
					&& (pmtConfig->formattype == FORMAT_VideoInfo)
					&& (pmtConfig->cbFormat >= sizeof(VIDEOINFOHEADER))
					&& (pmtConfig->pbFormat != NULL)){

					pVih2 = (VIDEOINFOHEADER*)pmtConfig->pbFormat;
					res_fput(fp,pVih2);
				}
			}
		}
	}
	pConfig->Release();
	pCapture->Release();
}

//	解像度の情報をファイルに出力

void res_fput(FILE* fp,VIDEOINFOHEADER* video){
	double ns=100*1.0e-9;
	double frame=1/(double(video->AvgTimePerFrame)*ns);
	_ftprintf(fp,_TEXT("%5d * %5d %5.1ffps\n"), video->bmiHeader.biWidth , video->bmiHeader.biHeight, frame );
}

実行ファイルとソースファイルのダウンロード(camerainfo.zip)