天天看點

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 <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,  

        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);  

        }  

    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  

            450, 75, BUTTONSIZE, BUTTONSIZE,  

            (HMENU)MINIMIZE,  

        hwndHelp = CreateWindow("button",    // 建立一個按鈕,更多如BUTTON,COMBOBOX,LISTBOX  

            "?",    // button text  

            WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON/*|BS_CENTER|BS_VCENTER*/,  

            430, 75, BUTTONSIZE, BUTTONSIZE,  

            (HMENU)HELP,  

        hwndPhoto = CreateWindow("button",  

            "照 相",  

            WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,  

            150, 410, 50, 20,  

            (HMENU)PHOTO,  

        SendMessage(hwndPhoto, WM_SETFONT, (WPARAM)hFont, 1);  // 設定按鈕字型為系統預設字型  

        hwndRecord = CreateWindow("button",  

            "錄 像",  

            WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|BS_VCENTER|BS_CENTER,  

            220, 410, 50, 20,  

            (HMENU)RECORDVIDEO,  

        SendMessage(hwndRecord, WM_SETFONT, (WPARAM)hFont, 1);// 設定按鈕字型為系統預設字型  

        hwndBtnExit = CreateWindow("button",   // 退出按鈕  

            "退 出",  

            400, 410, 50, 20,  

        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();  

    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);  

        case HELP:  // 幫助按鈕  

            SendMessage(hMain, WM_SYSCOMMAND, SC_CONTEXTHELP, 0);  

        case RESOURCE: // 視訊源選項  

            if (capDrvCaps.fHasDlgVideoSource)  

            {  

                capDlgVideoSource(hwndVideo);  

            }  

        case FORMAT:  // 視訊格式選項  

            if (capDrvCaps.fHasDlgVideoFormat)  

                capDlgVideoFormat(hwndVideo);  

        case CONNECT:  

        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);  

        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;  

                }  

        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);     

                        }  

                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);  

                }     

    case WM_DESTROY:  

        capSetCallbackOnError(hwndVideo, NULL);  

        capPreview(hwndVideo, FALSE); // 停止預覽  

        capCaptureAbort(hwndVideo);  // 停止捕獲  

        capDriverDisconnect(hwndVideo); // 斷開驅動連接配接  

        PostQuitMessage(0);  

    default:  

    return 0;  

LRESULT WINAPI SelCapDrcProc( HWND hMian, UINT msg, WPARAM wParam, LPARAM lParam )  

//  ShowWindow(hwndSelCapDrvDlg, SW_SHOW);  

    case WM_INITDIALOG:  

        return TRUE;  

        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;  

    case WM_CLOSE:  

        DestroyWindow(hwndSelCapDrvDlg);  

    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);  

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);  

繼續閱讀