ビデオキャプチャ
パソコンのキャプチャカード、および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 版: 準備中