win32 摄像头捕获系统vfw

//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;
}

你可能感兴趣的:(C/C++/C#,Win32,sdk,VC,6.0/MFC)