//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 <Windows.h> #include <STRING> #include <vfw.h> #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; }