ビデオキャプチャ
パソコンのキャプチャカード、およびUSBカメラから、ビデオデータをキャプチャする。
ビデオ圧縮ファイルの作成、インターネットストリーミング、等。
オペレーテイングシステムに依存し、専用の API 群が用意されている。
| Windows | |
| Video for Windows | Media Control Interface ファミリ |
| DirectShow | DirectX ファミリ (準備中) |
| Linux | |
| Video4Linux | (準備中) |
以下は、キャプチャデバイスからのコールバックに合わせてビデオ信号をキャプチャし、ファイルに書き出すプログラムである。
Video for Windows 版: capXXX 関数群の使用、リンクオプションに vfw32.lib を加える。一連の手順として、
|
|
Video for Windows の初期化とコールバック関数の指定 |
|
|
コールバック関数を介したビデオキャプチャ (下記の例では FrameCallbackProc 関数) |
|
|
Video for Windows の終了処理 |
を基本とする。また、GUI 経由でビデオフォーマット、ビデオソースの指定、キャプチャの開始と終了を制御する。個々の cap 関数の意味は Help (MSDN) を参考のこと。
main.c (GUIプログラム 参照)
#include <stdio.h> #include <windows.h> #include <vfw.h> #include "resource.h" /************************************************************/ // 各種宣言 /************************************************************/ #define MAX_XSIZE 720 #define MAX_YSIZE 480 // ビデオキャプチャ関数 BOOL initVideo(HWND hWnd); BOOL closeVideo(); // Video for Windows パラメータ HWND hWndVideo; CAPSTATUS gCapStatus; CAPTUREPARMS gCapParms; // RGB データ格納用バッファ unsigned char *pRGB; unsigned char *pRed; unsigned char *pGreen; unsigned char *pBlue; // ファイル、制御フラグ FILE* fp; char* pFileName = "sample.rgb"; BOOL bCapture = FALSE; /************************************************************/
// ウィンドウプログラム
/************************************************************/
// -------------------------------------------
// イベント処理
// -------------------------------------------
LRESULT APIENTRY
WndProc (HWND hWnd, UINT msg, UINT wParam, LONG lParam)
{
HMENU hMenu;
RECT rMenu;
// イベントに応じて処理を実行
switch (msg) {
case WM_CREATE:
// 開始
initVideo(hWnd);
PostMessage(hWnd, WM_SIZE, 0, 0);
return 0;
case WM_CLOSE:
// 終了
closeVideo();
DestroyWindow(hWnd);
return 0;
case WM_DESTROY:
PostQuitMessage (0);
break;
case WM_MOVE:
case WM_SIZE:
// ウィンドウ調整
capGetStatus(hWndVideo, &gCapStatus, sizeof(CAPSTATUS));
hMenu = GetMenu(hWnd);
GetMenuItemRect(hWndVideo, hMenu, 0, &rMenu);
SetWindowPos(hWnd, NULL, 0, 0,
gCapStatus.uiImageWidth + 6,
gCapStatus.uiImageHeight + 25 + rMenu.bottom - rMenu.top,
SWP_NOZORDER | SWP_NOMOVE);
SetWindowPos(hWndVideo, NULL, 0, 0,
gCapStatus.uiImageWidth,
gCapStatus.uiImageHeight,
SWP_NOZORDER | SWP_NOMOVE);
return 0;
case WM_COMMAND:
// コマンド処理
switch (LOWORD(wParam)) {
case ID_END:
// 終了
PostMessage(hWnd, WM_CLOSE, 0, 0);
break;
case ID_FORMAT:
// ビデオフォーマット
capDlgVideoFormat(hWndVideo);
PostMessage(hWnd, WM_SIZE, 0, 0);
break;
case ID_SOURCE:
// ビデオソース
capDlgVideoSource(hWndVideo);
break;
case ID_CAPTURE_START:
// キャプチャ開始
fp = fopen(pFileName, "wb");
if(fp == NULL) {
MessageBox(hWnd, "ファイルオープンエラー", "ファイルオープンエラー", MB_OK);
PostMessage(hWnd, WM_CLOSE, 0, 0);
bCapture = FALSE;
break;
}
MessageBox(hWnd, "キャプチャを開始します", "キャプチャ開始", MB_OK);
bCapture = TRUE;
break;
case ID_CAPTURE_END:
// キャプチャ終了
bCapture = FALSE;
fclose(fp);
MessageBox(hWnd, "キャプチャを終了しました", "キャプチャ終了", MB_OK);
break;
}
return 0;
}
return DefWindowProc (hWnd, msg, wParam, lParam);
}
// -------------------------------------------
// メイン制御部
// -------------------------------------------
int PASCAL
WinMain(HINSTANCE hInst, HINSTANCE hDummy, LPSTR lpStr, int nShowCmd)
{
WNDCLASS wc;
MSG msg;
HWND hWnd;
// ウィンドウクラスの定義
wc.lpfnWndProc = WndProc;
wc.hInstance = hInst;
wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
wc.lpszClassName = "Capture";
wc.hbrBackground = GetStockObject(WHITE_BRUSH);
wc.style = 0;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);
RegisterClass (&wc);
// メインウィンドウの生成
hWnd = CreateWindow(
wc.lpszClassName,
"Video Capture Sample",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
256,
256,
0,
0,
hInst,
0
);
if (hWnd == NULL) ExitThread (1);
ShowWindow (hWnd, SW_SHOWNOACTIVATE);
UpdateWindow (hWnd);
// 無限ループ (イベントが発生するたびに WndProc を呼び出す)
while (GetMessage (&(msg), NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage (&msg);
}
return msg.wParam;
}
/************************************************************/
// Video for Windows プログラム
/************************************************************/
// -------------------------------------------
// FrameCallbackProc
// -------------------------------------------
LRESULT PASCAL
FrameCallbackProc(HWND hWnd, LPVIDEOHDR lpVHdr) {
BITMAPINFOHEADER nFormat;
DWORD dwFormatSize;
int nWidth, nHeight, nBitCount;
int i, j;
unsigned char *rgb;
unsigned char *r, *g, *b;
// フラグ制御
if(bCapture == FALSE) return TRUE;
// ピクチャパラメータの取得
dwFormatSize = capGetVideoFormatSize(hWndVideo);
if( !capGetVideoFormat(hWndVideo, &nFormat, dwFormatSize) ) {
DestroyWindow(hWndVideo);
return FALSE;
}
nWidth = nFormat.biWidth;
nHeight = nFormat.biHeight;
nBitCount = nFormat.biBitCount;
if(nWidth > MAX_XSIZE || nHeight > MAX_YSIZE) {
MessageBox(hWnd, "サイズが大きすぎます", "キャプチャエラー", MB_OK);
bCapture = FALSE;
return FALSE ;
}
// (width, height) を 16 の倍数に変換
if(nWidth % 16 != 0) nWidth = (nWidth / 16 + 1) * 16;
if(nHeight % 16 != 0) nHeight = (nHeight / 16 + 1) * 16;
// キャプチャ実行
switch (nFormat.biCompression) {
case BI_RGB:
// RGB 24 ビットキャプチャのみサポート
switch(nBitCount) {
case 24:
// キャプチャカードからメモリにコピー
memcpy(pRGB, lpVHdr->lpData, lpVHdr->dwBufferLength);
// RGB データの並び替え(BMP フォーマットは上下反転してるため)
r = pRed;
g = pGreen;
b = pBlue;
for(j=0; j<nHeight; j++) for(i=0; i<nWidth; i++) {
rgb = pRGB + 3*((nHeight-1-j)*nWidth+i);
*(r++) = *(rgb+2);
*(g++) = *(rgb+1);
*(b++) = *(rgb+0);
}
// キャプチャデータのファイル書出し
fwrite(pRed, 1, nWidth*nHeight, fp);
fwrite(pGreen, 1, nWidth*nHeight, fp);
fwrite(pBlue, 1, nWidth*nHeight, fp);
break;
default:
MessageBox(hWnd, "24bit RGB しかキャプチャできません", "キャプチャエラー", MB_OK);
bCapture = FALSE;
return FALSE ;
}
break;
default:
MessageBox(hWnd, "24bit RGB しかキャプチャできません", "キャプチャエラー", MB_OK);
bCapture = FALSE;
return FALSE ;
}
return TRUE ;
}
// -------------------------------------------
// ErrorCallbackProc
// -------------------------------------------
LRESULT CALLBACK
ErrorCallbackProc(HWND hWnd, int nErrID, LPSTR lpErrorTxt)
{
char szText[256];
if (nErrID == 0) return TRUE;
if (nErrID == IDS_CAP_DRIVER_ERROR) {
// 起動時のエラー
MessageBeep(MB_ICONEXCLAMATION);
MessageBox(hWnd, "初期化エラー", "初期化エラー", MB_OK | MB_ICONEXCLAMATION);
PostMessage(hWndVideo, WM_CLOSE, 0, 0);
} else {
// その他のエラー
wsprintf(szText, "%s(%d)", lpErrorTxt, nErrID);
MessageBeep(MB_ICONEXCLAMATION);
MessageBox(hWndVideo, szText, "キャプチャエラー", MB_OK | MB_ICONEXCLAMATION);
}
return TRUE;
}
// -------------------------------------------
// 初期設定
// -------------------------------------------
int
initVideo(HWND hWnd)
{
char achDeviceName[80];
char achDeviceVersion[80];
WORD wDriverCount = 0;
WORD wIndex;
BITMAPINFOHEADER nFormat;
DWORD dwFormatSize;
int nWidth, nHeight;
// メモリ領域の確保
pRGB = (unsigned char *) malloc(MAX_XSIZE * MAX_YSIZE * 3);
pRed = (unsigned char *) malloc(MAX_XSIZE * MAX_YSIZE);
pGreen = (unsigned char *) malloc(MAX_XSIZE * MAX_YSIZE);
pBlue = (unsigned char *) malloc(MAX_XSIZE * MAX_YSIZE);
if(pRGB == NULL || pRed == NULL || pGreen == NULL || pBlue == NULL) return FALSE;
// キャプチャウィンドウの生成
hWndVideo = capCreateCaptureWindow("Capture",
WS_CHILD | WS_VISIBLE, 0, 0, 160, 120, (HWND) hWnd, (int) 0);
if(hWndVideo == NULL) return FALSE;
// コールバック関数の設定
capSetCallbackOnError(hWndVideo, ErrorCallbackProc);
capSetCallbackOnFrame(hWndVideo, FrameCallbackProc);
// ドライバの常駐
for (wIndex = 0; wIndex < 10; wIndex++) {
if (capGetDriverDescription(wIndex,
(LPSTR) achDeviceName,
sizeof(achDeviceName),
(LPSTR) achDeviceVersion,
sizeof(achDeviceVersion))) {
if (wDriverCount++ == 0) capDriverConnect(hWndVideo, wIndex);
}
}
// ピクチャフォーマットの取得
dwFormatSize = capGetVideoFormatSize(hWndVideo);
if( !capGetVideoFormat(hWndVideo, &nFormat, dwFormatSize) ) {
DestroyWindow(hWndVideo);
return FALSE;
}
nWidth = nFormat.biWidth;
nHeight = nFormat.biHeight;
if(nWidth > MAX_XSIZE || nHeight > MAX_YSIZE) {
MessageBox(hWnd, "サイズが大きすぎます", "キャプチャエラー", MB_OK);
return FALSE ;
}
if(nFormat.biCompression != BI_RGB || nFormat.biBitCount != 24) {
MessageBox(hWnd, "24bit RGB しかキャプチャできません", "キャプチャエラー", MB_OK);
return FALSE;
}
// 各種キャプチャパラメータの取得と設定
capCaptureGetSetup(hWndVideo, &gCapParms, sizeof(CAPTUREPARMS));
gCapParms.dwRequestMicroSecPerFrame = (DWORD)1000000 / 15;
gCapParms.fMakeUserHitOKToCapture = TRUE;
gCapParms.wPercentDropForError = 100;
gCapParms.fYield = FALSE;
gCapParms.fLimitEnabled = TRUE;
gCapParms.wTimeLimit = 10;
gCapParms.fCaptureAudio = FALSE;
gCapParms.fUsingDOSMemory = FALSE;
gCapParms.vKeyAbort = VK_ESCAPE;
gCapParms.fAbortLeftMouse = TRUE;
gCapParms.fAbortRightMouse = TRUE;
gCapParms.fMCIControl = FALSE;
gCapParms.fStepMCIDevice = FALSE;
capPreviewRate(hWndVideo, 66);
capPreview(hWndVideo, TRUE);
capOverlay(hWndVideo, TRUE);
capCaptureSetSetup(hWndVideo, &gCapParms, sizeof(CAPTUREPARMS));
return TRUE;
}
// -------------------------------------------
// 終了処理
// -------------------------------------------
BOOL
closeVideo(void) {
// コールバック関数の解放
capSetCallbackOnError(hWndVideo, NULL);
capSetCallbackOnFrame(hWndVideo, NULL);
// メモリ領域の解放
free(pRGB);
free(pRed);
free(pGreen);
free(pBlue);
// キャプチャウィンドウの終了
DestroyWindow(hWndVideo);
return TRUE;
}
|
resource.rc: ウィンドウにGUI コンポーネント (リソース) を被せるためにプロジェクトに組み込むスクリプトファイル。実際は、VisualC++ 上でリソースエディタを使うことで、グラフィカルに編集できる。また、このとき、resource.h が自動生成される。
//Microsoft Developer Studio generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "afxres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // 日本語 resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_JPN) #ifdef _WIN32 LANGUAGE LANG_JAPANESE, SUBLANG_DEFAULT #pragma code_page(932) #endif //_WIN32 ///////////////////////////////////////////////////////////////////////////// // // Menu // IDR_MENU1 MENU DISCARDABLE BEGIN POPUP "ファイル" BEGIN MENUITEM "終了", ID_END END POPUP "設定" BEGIN MENUITEM "ビデオフォーマット", ID_FORMAT MENUITEM "ビデオソース", ID_SOURCE END POPUP "キャプチャ" BEGIN MENUITEM "開始", ID_CAPTURE_START MENUITEM "終了", ID_CAPTURE_END END END #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE DISCARDABLE BEGIN "resource.h\0" END 2 TEXTINCLUDE DISCARDABLE BEGIN "#include ""afxres.h""\r\n" "\0" END 3 TEXTINCLUDE DISCARDABLE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED #endif // 日本語 resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED
|
Windows DirectShow 版: 準備中
Linux Video4Linux 版: 準備中