山本ワールド
Windowsプログラミング
アルゴリズム Vitual C++ 2008/2013によるWin32/Win64 APIレベルのプログラム 基礎 Vitual C++ 2008/2013によるAPIレベルのプログラム(32/64bit) Wix3でインストーラーを作る Visual C++ 2008 Standard Editonによるフォームアプリケーションのプログラム(32/64bit) Vitual C++ 2008 Standard EditonによるAPIレベルのプログラム(32/64bit) Windows 7対応 Visual C++ 2008 ExpressによるAPIレベルのプログラム Visual C++ 2005 ExpressによるAPIレベルのプログラム Visual C++ Versiosn 5 BORLAND C++ Windowsプログラム全般 Excel VBA その他DirectShowを使用してカメラ名と解像度の一覧を取得する
概要
DirectShowを用い、接続されているカメラの名称と解像度の一覧を取得し、camera.txtファイルに保存します。
下記は、Windows 7でELECOM UCAM-C0220FとBUFFALO BSW32KM03が接続されている環境での実行後のcamera.txtの内容です。
COMは文字コードをUNICODEで表しますので、コンパイル時の文字セットはUNICODEとしてください。マルチバイトでコンパイルはできますが、実行するとデバイス名の1文字目しか表示されません。これは、UNICODEは2byteで1文字を表しており、英数字の場合は1byte目がANSIと同じコード、2バイト目が0なので、マルチバイトでは2バイト目がNULL文字となり文字の終了と判断されるからです。
マルチバイトでコンパイルしたい場合は、Readメンバ関数で取得したUNICODE文字列をマルチバイトに変換するコードを追加してください。
下記は、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 );
}
Copyright (C) 2012 山本ワールド All Rights Reserved.