//win32 摄像头捕获系统vfw
// VideoRecord.h
/// 用于定义一些资源ID
#include "resource.h"
//#define EXIT 104
#define HELP 105
#define MINIMIZE 106
//#define DISPLAY 107
#define BUTTONSIZE 15
#define PHOTO 108
#define RECORDVIDEO 109
// #define RESOURCE 110
// #define FORMAT 111
#define CONNECT 112
#include
#include
#include
#include "VideoRecord.h"
#pragma comment(lib, "vfw32.lib")
LRESULT WINAPI MainWndProc( HWND, UINT, WPARAM, LPARAM );
LRESULT WINAPI SelCapDrcProc( HWND, UINT, WPARAM, LPARAM );
int EnumCapDrv();
VOID APIENTRY HandlePopupMenu(HWND, POINT); // 右键弹出菜单回调函数
WORD WINAPI VideoThreadProc( LPVOID lParam); // 视频捕捉线程函数
////////////////全局变量
HANDLE ghInstance; // 应用程序实例
HWND hwndMain; // 主窗口句柄
HWND hwndVideo; // 视频捕捉窗口句柄
HWND hwndSelCapDrvDlg; // 选择捕捉驱动对话框句柄
HWND hwndSelCapDrvLBox; // 选择驱动对话框列举驱动名称列表框句柄
HWND hwndExit;
HWND hwndMin;
HWND hwndHelp;
HWND hwndPhoto;
HWND hwndRecord;
HWND hwndBtnExit;
HWND hwndSource;
HWND hwndFormat;
HWND hwndConnect;
HANDLE hVideoTread; // 视频采集线程
HRGN hRoundRgn; // 窗口修正区域
CAPDRIVERCAPS capDrvCaps; // 驱动性能
bool bRecordFileOpen = false; // 录像开始标志
bool bPhotoFileOpen = false; // 照相开始标志
bool bRecording = false; // 判断是否正在录像
bool bThreadEnd = false; // 判断视频线程是否终止
char recordFile[260]; //保持录像标志
char photoFile[260]; // 保持照相标志
char gachBuffer[260]; // 保存错误信息
//////////////////////////////////////////////////////////////////////////////
// ErrorCallbackProc: 错误回调函数,过capSetCallbackOnError宏来注册回调
// hWnd: 捕获窗口句柄
// nErrID: 错误代码
// lpErrorText: 关于错误的文本信息
///////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK ErrorCallbackProc(HWND hWnd,int nErrID,LPSTR lpErrorText)
{
if(!hwndMain)
return FALSE;
if(nErrID==0)
return TRUE;//清除旧的错误
wsprintf(gachBuffer,"Error# %d",nErrID);//显示错误标识和文本
MessageBox(hWnd, lpErrorText, gachBuffer,MB_OK | MB_ICONEXCLAMATION);
return (LRESULT) TRUE;
}
/////////////////////////////////////
int PASCAL WinMain( IN HINSTANCE hInstance,
IN HINSTANCE hPrevInstance,
IN LPSTR lpCmdLine,
IN int nShowCmd )
{
WNDCLASS wndClass;
MSG msg;
char className[] = "VideoClass";
// 如果不是前实例
if (!hPrevInstance)
{
wndClass.lpszClassName = className;
wndClass.lpfnWndProc = MainWndProc;
wndClass.style = CS_HREDRAW|CS_VREDRAW|CS_OWNDC;
wndClass.hInstance = hInstance;
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndClass.hbrBackground = CreateSolidBrush( RGB(200,200,100) );
wndClass.lpszMenuName = NULL;
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
RegisterClass( &wndClass );
}
ghInstance = hInstance;
// 创建主窗口
hwndMain = CreateWindow(className,
"视频监控系统",
WS_POPUP|WS_OVERLAPPED,
GetSystemMetrics(SM_CXFULLSCREEN)/2 - 600/2,
GetSystemMetrics(SM_CYFULLSCREEN)/2-600/2,
600, 600,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hwndMain, nShowCmd);
// 设定主窗口主要区域
SetWindowRgn(hwndMain, hRoundRgn, 1);
while( GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);//该函数将虚拟键消息转换为字符消息。
//字符消息被寄送到调用线程的消息队列里,当下一次线程调用函数GetMessage或PeekMessage时被读出
DispatchMessage(&msg);//该函数调度一个消息给窗口程序。
//通常调度从GetMessage取得的消息。消息被调度到的窗口程序即是MainProc()函数
}
return msg.wParam;
}
LRESULT CALLBACK MainWndProc( HWND hMain, UINT msg, WPARAM wParam, LPARAM lParam )
{
HDC hdc = GetDC(hMain);
RECT rc; // 客户区
POINT pt; // 鼠标位置
HFONT hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
switch(msg)
{
case WM_LBUTTONDBLCLK:
SetFocus(hMain);
break;
case WM_RBUTTONDOWN:
GetClientRect(hMain, (LPRECT)&rc);
pt.y = HIWORD(lParam);
pt.x = LOWORD(lParam);
if ( PtInRect(&rc, pt) )
{
HandlePopupMenu(hMain, pt);
}
break;
case WM_PAINT:
RECT helpRect, minRect, exitRect;
HRGN helpRgn, minRgn, exitRgn;
FrameRgn(hdc, hRoundRgn, CreateSolidBrush(RGB(0,0,0)), 2, 2);
BringWindowToTop(hwndSelCapDrvDlg);
return DefWindowProc(hMain, msg, wParam, lParam);
case WM_CREATE:
// 注册错误提示回调函数
capSetCallbackOnError(hwndVideo, (FARPROC)ErrorCallbackProc);
// 主窗口主要圆角矩形区域
hRoundRgn = CreateRoundRectRgn(100, 70, 500, 460, 20, 20);
// 捕捉视频区域s
hwndVideo = capCreateCaptureWindow((LPSTR)"My Capture Window",
WS_CHILD|WS_VISIBLE,
140, 100, 320, 280,
(HWND)hMain,
(int)1);
hwndExit = CreateWindow("button", // 建立一个按钮,更多如BUTTON,COMBOBOX,LISTBOX
"x", // button text
WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON|BS_CENTER|BS_VCENTER,
470, 75, BUTTONSIZE, BUTTONSIZE,
hMain,
(HMENU)EXIT,
(HINSTANCE)ghInstance,
(LPVOID)NULL );
hwndMin = CreateWindow("button", // 建立一个按钮,更多如BUTTON,COMBOBOX,LISTBOX
"-", // button text
WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON|BS_CENTER|BS_VCENTER,
450, 75, BUTTONSIZE, BUTTONSIZE,
hMain,
(HMENU)MINIMIZE,
(HINSTANCE)ghInstance,
(LPVOID)NULL );
hwndHelp = CreateWindow("button", // 建立一个按钮,更多如BUTTON,COMBOBOX,LISTBOX
"?", // button text
WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON/*|BS_CENTER|BS_VCENTER*/,
430, 75, BUTTONSIZE, BUTTONSIZE,
hMain,
(HMENU)HELP,
(HINSTANCE)ghInstance,
(LPVOID)NULL );
hwndPhoto = CreateWindow("button",
"照 相",
WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
150, 410, 50, 20,
hMain,
(HMENU)PHOTO,
(HINSTANCE)ghInstance,
(LPVOID)NULL );
SendMessage(hwndPhoto, WM_SETFONT, (WPARAM)hFont, 1); // 设置按钮字体为系统默认字体
hwndRecord = CreateWindow("button",
"录 像",
WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|BS_VCENTER|BS_CENTER,
220, 410, 50, 20,
hMain,
(HMENU)RECORDVIDEO,
(HINSTANCE)ghInstance,
(LPVOID)NULL );
SendMessage(hwndRecord, WM_SETFONT, (WPARAM)hFont, 1);// 设置按钮字体为系统默认字体
hwndBtnExit = CreateWindow("button", // 退出按钮
"退 出",
WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|BS_VCENTER|BS_CENTER,
400, 410, 50, 20,
hMain,
(HMENU)EXIT,
(HINSTANCE)ghInstance,
(LPVOID)NULL );
SendMessage(hwndBtnExit, WM_SETFONT, (WPARAM)hFont, 1);
// 设置按钮区域
GetClientRect(hwndHelp, &helpRect);
GetClientRect(hwndMin, &minRect);
GetClientRect(hwndExit, &exitRect);
helpRgn = CreateEllipticRgnIndirect(&helpRect);
minRgn = CreateEllipticRgnIndirect(&minRect);
exitRgn = CreateEllipticRgnIndirect(&exitRect);
SetWindowRgn(hwndExit,exitRgn,1);
SetWindowRgn(hwndMin,minRgn,1);
SetWindowRgn(hwndHelp,helpRgn,1);
// 创建选择驱动对话框
hwndSelCapDrvDlg = CreateDialog((HINSTANCE)ghInstance,
MAKEINTRESOURCE(DLG_SELCAPDRIVER),
0, (DLGPROC)SelCapDrcProc);
hwndSelCapDrvLBox = GetDlgItem(hwndSelCapDrvDlg, LISTBOX_SELCAPDRIVER);
EnumCapDrv();
break;
case WM_COMMAND:
CAPSTATUS capStatus;
switch(wParam)
{
case EXIT: // 退出系统
SendMessage(hMain, WM_SYSCOMMAND, SC_CLOSE, 0);
break;
case MINIMIZE: // 最小化
SendMessage(hMain, WM_SYSCOMMAND, SC_MINIMIZE, 0);
break;
case HELP: // 帮助按钮
SendMessage(hMain, WM_SYSCOMMAND, SC_CONTEXTHELP, 0);
break;
case RESOURCE: // 视频源选项
if (capDrvCaps.fHasDlgVideoSource)
{
capDlgVideoSource(hwndVideo);
}
break;
case FORMAT: // 视频格式选项
if (capDrvCaps.fHasDlgVideoFormat)
{
capDlgVideoFormat(hwndVideo);
}
break;
case CONNECT:
break;
case DISPLAY: // 视频显示选项
if (capDrvCaps.fHasDlgVideoDisplay)
{
capDlgVideoDisplay(hMain);
capGetStatus(hwndVideo, &capStatus, sizeof(CAPSTATUS));// 得到当前捕获窗口的状态
SetWindowPos(hwndVideo, NULL, 0, 0, capStatus.uiImageWidth, capStatus.uiImageHeight, SWP_NOZORDER|SWP_NOMOVE);
}
break;
case PHOTO: // 抓取图片
if ( capFileSaveDIB(hwndVideo, "test.bmp") ){
MessageBox(hMain, "Save Bmp File Succeeded!", "photo save", MB_OK|MB_ICONINFORMATION);
}
else break;
if (!bPhotoFileOpen)
{
OPENFILENAME ofnp; // open file name structure
ZeroMemory(&ofnp, sizeof(OPENFILENAME));
ofnp.lStructSize = sizeof(OPENFILENAME);
ofnp.hwndOwner = hMain;
ofnp.lpstrFile = photoFile;
ofnp.lpstrFilter = "*.bmp";
ofnp.nMaxFile = sizeof(photoFile);
ofnp.nFilterIndex = 1;
ofnp.nMaxFileTitle = 0;
ofnp.lpstrInitialDir = NULL;
ofnp.Flags = OFN_PATHMUSTEXIST|OFN_FILEMUSTEXIST;
// 显示保存文件对话框
if (GetSaveFileName(&ofnp) == TRUE)
{
bPhotoFileOpen = TRUE;
strcpy(photoFile, ofnp.lpstrFile);
strcat(photoFile, ".bmp");
capDriverConnect(hwndPhoto, 0); // 与驱动连接
capOverlay(hwndPhoto, TRUE); // //使用 hardware overlay
//使 video input directlyinto framebuffer,使不用 CPU
capPreview(hwndVideo, TRUE); // 抓取图像显示在视窗
capPreviewScale(hwndVideo, TRUE); // 使图像延伸到所设定的视窗大小
capPreviewRate(hwndVideo, 1000/30); // 每秒图像变化张数
capPreview(hwndVideo, TRUE); // 预览图像显示
capGrabFrameNoStop(hwndVideo);
capEditCopy(hwndVideo);
if (capFileSaveDIB(hwndVideo, photoFile)){
MessageBox(hMain, "Save Bmp File Succeeded!", "photo save", MB_OK|MB_ICONINFORMATION);
}
break;
}
}
break;
case RECORDVIDEO: // 录制视频
if (HIWORD(wParam) == BN_CLICKED && (HWND)lParam == hwndRecord)
{
OPENFILENAME ofnp;
if (!bRecordFileOpen)
{
ZeroMemory(&ofnp, sizeof(OPENFILENAME));
ofnp.lStructSize = sizeof(OPENFILENAME);
ofnp.nMaxFile = sizeof(recordFile);
ofnp.hwndOwner = hMain;
ofnp.lpstrFile = recordFile;
ofnp.lpstrFilter = "*.avi";
ofnp.lpstrInitialDir = NULL;
ofnp.nFilterIndex = 1;
ofnp.lpstrFileTitle = NULL;
ofnp.nMaxFileTitle = 0;
ofnp.Flags = OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST;
// 显示保存文件对话框
if (GetSaveFileName(&ofnp) == TRUE)
{
strcpy(recordFile, ofnp.lpstrFile);
strcat(recordFile, ".avi");
bRecordFileOpen = TRUE;
// 创建视频采集线程
DWORD id;
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
hVideoTread = CreateThread(&sa,
(ULONG)0,
(LPTHREAD_START_ROUTINE)VideoThreadProc,
(LPVOID)(ULONG)0,
0,
&id);
// 如果创建线程失败,弹出提示对话框
if (hVideoTread == NULL)
{
MessageBox(NULL, "Video Thread Create Failure!", "Thread", MB_OK|MB_ICONINFORMATION);
}
}
break;
}
if (bRecordFileOpen) // 已经打开一个选择对话框
{
if (bRecording) // 已经在录制视频中
{
bThreadEnd = true;
// 结束录制,并保存
if ( capFileSaveAs(hwndVideo, recordFile) ){
MessageBox(NULL, "Save Avi File Succeeded!", "RecordVideo", MB_OK|MB_ICONINFORMATION);
}
SetWindowText(hwndRecord, "录 像");
bRecording = false;
break;
}
else // 没有录像但是选择了一个文件
{
int rt = 0;
rt = MessageBox(hMain, "Do you want write over that file?", "系统提示", MB_YESNO|MB_ICONINFORMATION);
if (rt == IDYES) // 继续录制,覆盖当前文件
{
if (capCaptureSequence(hwndRecord))
{
bRecording = true;
SetWindowText(hwndRecord, "停 止");
}
}
else
{
bRecordFileOpen = false;
SendMessage(hMain, WM_COMMAND, MAKEWPARAM(RECORDVIDEO, BN_CLICKED), (LPARAM)hwndRecord);
}
break;
}
break;
}
}
}
break;
case WM_DESTROY:
capSetCallbackOnError(hwndVideo, NULL);
capPreview(hwndVideo, FALSE); // 停止预览
capCaptureAbort(hwndVideo); // 停止捕获
capDriverDisconnect(hwndVideo); // 断开驱动连接
PostQuitMessage(0);
break;
default:
return DefWindowProc(hMain, msg, wParam, lParam);
}
return 0;
}
LRESULT WINAPI SelCapDrcProc( HWND hMian, UINT msg, WPARAM wParam, LPARAM lParam )
{
// ShowWindow(hwndSelCapDrvDlg, SW_SHOW);
switch(msg)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
switch(wParam)
{
case BTN_SEL:
int sel = 0;
SendMessage(hwndSelCapDrvLBox, LB_GETSELITEMS, 1, sel ); // 获取选择的驱动
SendMessage(hwndVideo, WM_CAP_DRIVER_CONNECT, sel, 0L); // 连接驱动
SendMessage(hwndSelCapDrvDlg, WM_CLOSE, 0, 0); // 关闭对话框
SendMessage(hwndVideo, WM_CAP_DRIVER_GET_CAPS, sizeof(CAPDRIVERCAPS), (long)(LPVOID)&capDrvCaps); // 更新驱动的能力
if (capDrvCaps.fHasOverlay)
{
capOverlay(hwndVideo, TRUE);
}
capPreviewRate(hwndVideo, 66); //设置视频捕获速率提高到66 miliseconds
if ( !capPreview(hwndVideo, TRUE)) //用CapPreview启动预览功能
{
MessageBox(NULL, "预览启动失败", "提示", MB_OK|MB_ICONINFORMATION);
SendMessage(hMian, WM_COMMAND, EXIT, 0);
return FALSE;
}
}
return TRUE;
case WM_CLOSE:
DestroyWindow(hwndSelCapDrvDlg);
return TRUE;
}
return (0L);
}
int EnumCapDrv()
{
char drvName[100];
char drvVesion[100];
char drvStr[200];
for (int i = 0; i < 5; i++) // 扫面获取驱动信息
{
if ( capGetDriverDescription(i, drvName, sizeof(drvName), drvVesion, sizeof(drvVesion)) )
{
strcpy(drvStr, drvName);
strcat(drvStr, " ");
strcat(drvStr, drvVesion);
SendMessage(hwndSelCapDrvLBox, LB_ADDSTRING, 0, (LPARAM)drvStr); // 向列表框增加字符串
SendMessage(hwndSelCapDrvLBox, LB_SETITEMDATA, i, (LPARAM)i);
}
}
return 0;
}
VOID APIENTRY HandlePopupMenu( HWND hwnd, POINT pt )
{
HMENU hmenu;
HMENU hPopupMenu;
hmenu = LoadMenu((HINSTANCE)ghInstance, MAKEINTRESOURCE(IDR_POPUPMENU));
if(hmenu == NULL) return;
// 获取子菜单
hPopupMenu = GetSubMenu(hmenu, 0);
// 弹出菜单使用屏幕坐标,所以转换鼠标点击坐标到屏幕坐标
ClientToScreen(hwnd, &pt);
TrackPopupMenu(hPopupMenu, TPM_LEFTALIGN|TPM_LEFTBUTTON, pt.x, pt.y, 0, hwnd, NULL);
DestroyMenu(hmenu); // 销毁指定菜单,并释放此菜单占用的内存
}
WORD WINAPI VideoThreadProc( LPVOID lParam )
{
// 捕获视频
if( capCaptureSequence(hwndVideo) ) //该函数调控启动流视频和音频捕获到一个文件,你能使用这个功能发送消息
{
SetWindowText(hwndRecord, "停 止");
MessageBox(NULL, "Start to capture video.", "提示", MB_OK|MB_ICONINFORMATION);
bRecording = true;
}
while(!bThreadEnd);
MessageBox(NULL, "Leaving Record Thread", "Thread",NULL);
return 0;
}