• (4 Pages)
  • +
  • 1
  • 2
  • 3
  • Last »

Win32 WebCam Program Displays a Webcam Picture, Saves it as a .bmp file Rate Topic: ***** 4 Votes

#1 snoopy11  Icon User is offline

  • Engineering ● Software
  • member icon

Reputation: 762
  • View blog
  • Posts: 2,214
  • Joined: 20-March 10

Posted 04 October 2010 - 09:11 PM

*
POPULAR

WebCam Tutorial.

This WebCam Tutorial will guide you through connecting a webcam in Microsoft Windows and grabbing a frame from the camera so we can later
save it to a bitmap file called "Frame.bmp".
First of all this is a c++ win32 Tutorial so create an empty Win32 application.

1. Setting up some defines.

First of all we need to set up some defines that we need to connect to a webcam. If you are using Microsoft’s Visual Studio Pro edition you wont need them as they are included in Microsoft’s version of vfw.h, if you are
using something else like Code::Blocks as I am then you will need them.
I recommend storing them in a header but I will put them in the main .cpp.
They are basically just values.
#define WM_CAP_START  0x0400
#define WM_CAP_DRIVER_CONNECT  (WM_CAP_START + 10)
#define WM_CAP_DRIVER_DISCONNECT  (WM_CAP_START + 11)
#define WM_CAP_EDIT_COPY (WM_CAP_START + 30)
#define WM_CAP_GRAB_FRAME (WM_CAP_START + 60)
#define WM_CAP_SET_SCALE (WM_CAP_START + 53)
#define WM_CAP_SET_PREVIEWRATE (WM_CAP_START + 52)
#define WM_CAP_SET_PREVIEW (WM_CAP_START + 50)
#define WM_CAP_DLG_VIDEOSOURCE  (WM_CAP_START + 42)
#define WM_CAP_STOP (WM_CAP_START+ 68)



2. Include Files.

We need to include two header files the first is windows.h
which is just the standard windows header. The other is vfw.h
which stands for video for windows and is where the webcam stuff is.
You will need to link to vfw32 Library in your projects linker settings.

For Code::Blocks this is done through Project -> Build Options ->
Linker Settings and click the add button and type -> vfw32.
At the same time you might as well add gdi32 as well.

For Microsofts Visual C++ Pro or Express Edition
its Project -> properties or Alt+F7.
Configuration Properties -> Linker -> Input -> Additional Dependencies
type in Vfw32.lib; and check to make sure gdi32.lib; is also there
in the dependencies.

If you are using the express Edition you will have to download the
windows sdk. Found here at ->

Link to SDK

It requires Windows XP SP3 and above.

Click the link to download it.
And open up windows explorer and go to ->
Program Files\Microsoft SDKs\Windows\v7.0A

there you should see a bin folder, a lib folder and an include folder.
Open the include folder and select Edit -> Select All and then Edit -> Copy.

Then go to your compilers include folder typically Program Files ->
Microsoft Visual Studio 10.0-> VC
there you should see another include folder open it and paste what you have copied into it.
This will copy the Header required for this program and all other headers
which you might like to have into it.

Go back to Program Files\Microsoft SDKs\Windows\v7.0A
and open the lib folder, select Edit -> Select All and then Edit -> Copy.

Go to Program Files\ Microsoft Visual Studio 10.0\ VC
and open the lib folder and paste what you have copied into it.

This will copy a host of very good libraries one of which is called
Vfw32.lib. Which we will use in our Webcam Program.

If you are using Microsoft Visual C++ Pro or Express Edition
there is one more thing you will have to do because this code is not
a unicode build.

Go to Project -> Properties-> Configuration Properties -> General
click on Character Set and change it to use Multi-Byte Character Set.


#include <windows.h>
#include <vfw.h>






3. Procedures.

We will use 3 procedures the first is WindowProc.
The second is CreateBitmapInfoStruct which is a PBITMAPINFO
structure which contains information on color and dimension in a windows based DIB.
The third and last procedure is CreateBMPFile which creates and saves
the bitmap as a .bmp file.

LRESULT CALLBACK WindowProc (HWND, UINT, WPARAM, LPARAM);
PBITMAPINFO CreateBitmapInfoStruct(HWND hwnd, HBITMAP hBmp);
void CreateBMPFile(HWND hwnd, LPTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC);




4. Setting up the window.

Next we need to setup some variables and a window itself.

char szAppName [] = TEXT("WebCam");
HWND camhwnd;
HDC hdc ;
HDC hdcMem;
PAINTSTRUCT ps;
HBITMAP hbm;
RECT rc;

//WinMain -- Main Window
int WINAPI WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow )
{

HWND hwnd;
MSG msg;

WNDCLASS wc;
wc.style = CS_HREDRAW|CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(GetModuleHandle(NULL), IDI_APPLICATION);
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = szAppName;

RegisterClass (&wc);

// Create the window
hwnd = CreateWindow (szAppName,szAppName,WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX,CW_USEDEFAULT,CW_USEDEFAULT,300,600,0,0,hInstance,0);

ShowWindow (hwnd,SW_SHOW);
UpdateWindow (hwnd);

while (GetMessage(&msg,0,0,0))
{
if(!IsDialogMessage(hwnd, &msg))
{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
}
return msg.wParam;
}



5. WindowProc.

First of all we need to set up three buttons.
These are
1. A start camera button.
2. A stop camera button.
3. A button to grab a frame from the camera.

Secondly we need to set up a Camera window
this is called camhwnd and is created by using
the capCreateCaptureWindow command this must include
the Window style WS_CHILD.

Third we need to pick a webcam from the Video source Dialog
WM_CAP_DLG_VIDEOSOURCE.
We do this by sending a message to our camera window camhwnd.

SendMessage(camhwnd,WM_CAP_DRIVER_CONNECT,0,0);
SendMessage(camhwnd,WM_CAP_DLG_VIDEOSOURCE,0,0);


There is another way to do this by enumerating all webcam drivers
on the system but for simplicity I wont be doing this in this tutorial
I may write another tutorial on how to do this at a later date.

Fourth come the Window Message Commands

1. Case 1
This connects and shows our webcam picture.
WM_CAP_SET_SCALE is set to true to enable the webcam
picture to be resized to the dimensions of our camera window.
WM_CAP_SET_PREVIEWRATE is set to 66 frames per second.
To provide a reasonable moving picture without too much demand on resources.
WM_CAP_SET_PREVIEW is set to true so a picture will be drawn on the camera window camhwnd.

2. Case 2
Calls WM_CAP_DRIVER_DISCONNECT to amazingly enough
disconnect the webcam.

3. Case 3
This grabs the frame and saves it to a .bmp file called "Frame.bmp"
WM_CAP_GRAB_FRAME does the frame grabbing this freezes the camera output so we will need to restart it later on.
WM_CAP_EDIT_COPY copies our grabbed frame to the clipboard.
Then we copy the clipboard image data to a HBITMAP object called
‘hbm’.
We then create and save the bitmap file itself using ‘hbm’ and the function call CreateBMPFile(hwnd, "Frame.bmp", pbi, hbm, hdcMem);

.

4. Case WM_DESTROY
Its important we disconnect the webcam if the user closes the window.

//Main Window Procedure WindowProc
LRESULT CALLBACK WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HINSTANCE hInstance = GetModuleHandle(NULL);

//some buttons
HWND hButtStartCam;
HWND hButtStopCam;
HWND hButtGrabFrame;

switch (message)                  /* handle the messages */
{

case WM_CTLCOLORSTATIC:
SetBkMode(hdc,TRANSPARENT);
return (LRESULT)CreateSolidBrush(0xFFFFFF);

case WM_CREATE:
{
hButtStartCam = CreateWindowEx(0,"BUTTON","Start Camera",WS_CHILD | WS_VISIBLE,
				0,0,100,20,hwnd,(HMENU)1,hInstance, 0);
hButtStopCam = CreateWindowEx(0,"BUTTON","Stop Camera",WS_CHILD | WS_VISIBLE,
				0,25,100,20,hwnd,(HMENU)2,hInstance, 0);
hButtGrabFrame = CreateWindowEx(0,"BUTTON","Grab Frame",WS_CHILD | WS_VISIBLE,
				0,50,100,20,hwnd,(HMENU)3,hInstance, 0);

camhwnd = capCreateCaptureWindow ("camera window", WS_CHILD , 0, 100, 300, 300, hwnd, 0);
SendMessage(camhwnd,WM_CAP_DRIVER_CONNECT,0,0);
SendMessage(camhwnd,WM_CAP_DLG_VIDEOSOURCE,0,0);

break;
}

case WM_COMMAND:
{
switch(LOWORD(wParam))
{

case 1:
{
ShowWindow(camhwnd,SW_SHOW);
SendMessage(camhwnd,WM_CAP_DRIVER_CONNECT,0,0);
SendMessage(camhwnd, WM_CAP_SET_SCALE, true , 0);
SendMessage(camhwnd, WM_CAP_SET_PREVIEWRATE, 66, 0);
SendMessage(camhwnd, WM_CAP_SET_PREVIEW, true , 0);
break;
}

case 2:
{
ShowWindow(camhwnd,SW_HIDE);
SendMessage(camhwnd, WM_CAP_DRIVER_DISCONNECT, 0, 0);
break;
}

case 3:
{
//Grab a Frame
SendMessage(camhwnd, WM_CAP_GRAB_FRAME, 0, 0);
//Copy the frame we have just grabbed to the clipboard
SendMessage(camhwnd, WM_CAP_EDIT_COPY,0,0);

//Copy the clipboard image data to a HBITMAP object called hbm
hdc = BeginPaint(camhwnd, &ps);
hdcMem = CreateCompatibleDC(hdc);
if (hdcMem != NULL)
{
	if (OpenClipboard(camhwnd))
	{
     hbm = (HBITMAP) GetClipboardData(CF_BITMAP);
     SelectObject(hdcMem, hbm);
     GetClientRect(camhwnd, &rc);
     CloseClipboard();
	}
}
//Save hbm to a .bmp file called Frame.bmp
PBITMAPINFO pbi = CreateBitmapInfoStruct(hwnd, hbm);
CreateBMPFile(hwnd, "Frame.bmp", pbi, hbm, hdcMem);

SendMessage(camhwnd,WM_CAP_DRIVER_CONNECT,0,0);
SendMessage(camhwnd, WM_CAP_SET_SCALE, true , 0);
SendMessage(camhwnd, WM_CAP_SET_PREVIEWRATE, 66, 0);
SendMessage(camhwnd, WM_CAP_SET_PREVIEW, true , 0);
break;
}
}
break;
}

case WM_DESTROY:
{
SendMessage(camhwnd, WM_CAP_DRIVER_DISCONNECT, 0, 0);
PostQuitMessage(0);   /* send a WM_QUIT to the message queue */
break;
}

default:              /* for messages that we don't deal with */
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}



6. Procedures to Create and Save a Bitmap.

First up is CreateBitmapInfoStruct
which creates a PBITMAPINFO structure it takes two
arguments HWND and an HBITMAP object.

A DIB consists of two distinct parts: a BITMAPINFO structure describing the dimensions and colors of the bitmap, and an array of bytes defining the pixels of the bitmap. The bits in the array are packed together, but each scan line must be padded with zeroes to end on a LONG data-type boundary. If the height of the bitmap is positive, the bitmap is a bottom-up DIB and its origin is the lower-left corner. If the height is negative, the bitmap is a top-down DIB and its origin is the upper left corner.

A bitmap is packed when the bitmap array immediately follows the BITMAPINFO header. Packed bitmaps are referenced by a single pointer. For packed bitmaps, the biClrUsed member must be set to an even number when using the BI_RGB mode . BI_RGB means that the bitmap is uncompressed.

Secondly we use CreateBMPFile to save the bitmap
it takes 5 arguments the hwnd which owns the bitmap, the filename
in this case "Frame.bmp" a PBITMAPINFO structure which we have just went over, a HBITMAP object and a HDC, handle to device context.
First of all is pbih which is a PBITMAPINFOHEADER
this structure contains information about the dimensions and color format of a DIB.
lpBits contains the size, in bytes, of the image and we allocate some memory for it. Next up we use GetDIBits to retrieve the color table and the bits from the DIB. This function retrieves the bits of the specified compatible bitmap and copies them into a buffer as a DIB using the specified format.
In this case DIB_RGB_COLORS.

Next we create the file using CreateFile the CREATE_ALWAYS
parameter Creates a new file, always.

If the specified file exists and is writable, the function overwrites the file, the function succeeds, and last-error code is set to ERROR_ALREADY_EXISTS.

Next up is the BITMAPFILEHEADER hdr.
It is important to note that hdr.bfType has to have the ‘BM’ designator in it which is made up of 0x4d42 which is B = 0x42 and M = 0x4d.

The bfSize member specifies the size, in bytes, of the bitmap file.

hdr.bfReserved1and hdr.bfReserved2 must always be set to zero.

BfOffBits Specifies the offset, in bytes, from the BITMAPFILEHEADER structure to the bitmap bits.

Next we copy the BITMAPFILEHEADER into the .BMP file
with WriteFile
Next we copy the BITMAPINFOHEADER and RGBQUAD array into the file.
With WriteFile

Next we copy the array of color indices into the .BMP file
with WriteFile

Last of all we close the .BMP file with CloseHandle
and free the memory we allocated for lpbits
void CreateBMPFile(HWND hwnd, LPTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC)
{
    HANDLE hf;                  // file handle
    BITMAPFILEHEADER hdr;       // bitmap file-header
    PBITMAPINFOHEADER pbih;     // bitmap info-header
    LPBYTE lpBits;              // memory pointer
    DWORD dwTotal;              // total count of bytes
    DWORD cb;                   // incremental count of bytes
    BYTE *hp;                   // byte pointer
    DWORD dwTmp;

pbih = (PBITMAPINFOHEADER) pbi;
lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih->biSizeImage);

if (!lpBits)
{
MessageBox(hwnd,"GlobalAlloc","Error", MB_OK );
}
// Retrieve the color table (RGBQUAD array) and the bits
// (array of palette indices) from the DIB.
if (!GetDIBits(hDC, hBMP, 0, (WORD) pbih->biHeight, lpBits, pbi,DIB_RGB_COLORS))
{
MessageBox(hwnd,"GetDIBits","Error",MB_OK );
}
// Create the .BMP file.
hf = CreateFile(pszFile,GENERIC_READ | GENERIC_WRITE,(DWORD) 0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,(HANDLE) NULL);
if (hf == INVALID_HANDLE_VALUE)
{
MessageBox( hwnd,"CreateFile","Error", MB_OK);
}

hdr.bfType = 0x4d42;  // File type designator "BM" 0x42 = "B" 0x4d = "M"
// Compute the size of the entire file.
hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) + pbih->biSize + pbih->biClrUsed * sizeof(RGBQUAD) + pbih->biSizeImage);
hdr.bfReserved1 = 0;
hdr.bfReserved2 = 0;
// Compute the offset to the array of color indices.
hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) + pbih->biSize + pbih->biClrUsed * sizeof (RGBQUAD);
// Copy the BITMAPFILEHEADER into the .BMP file.
if (!WriteFile(hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER), (LPDWORD) &dwTmp,  NULL) )
{
 MessageBox(hwnd,"WriteFileHeader","Error",MB_OK );
}
// Copy the BITMAPINFOHEADER and RGBQUAD array into the file.
if (!WriteFile(hf, (LPVOID) pbih, sizeof(BITMAPINFOHEADER) + pbih->biClrUsed * sizeof (RGBQUAD), (LPDWORD) &dwTmp, NULL))
{
MessageBox(hwnd,"WriteInfoHeader","Error",MB_OK );
}
// Copy the array of color indices into the .BMP file.
dwTotal = cb = pbih->biSizeImage;
hp = lpBits;
if (!WriteFile(hf, (LPSTR) hp, (int) cb, (LPDWORD) &dwTmp,NULL))
{
MessageBox(hwnd,"WriteFile","Error",MB_OK );
}
// Close the .BMP file.
if (!CloseHandle(hf))
{
MessageBox(hwnd,"CloseHandle","Error",MB_OK );
}

// Free memory.
GlobalFree((HGLOBAL)lpBits);
}

PBITMAPINFO CreateBitmapInfoStruct(HWND hwnd, HBITMAP hBmp)
{
BITMAP bmp;
PBITMAPINFO pbmi;
WORD cClrBits;
// Retrieve the bitmap color format, width, and height.
if (!GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bmp))
{
MessageBox(hwnd,"GetObject","Error",MB_OK );
}
// Convert the color format to a count of bits.
cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel);
if (cClrBits == 1)
 cClrBits = 1;
else if (cClrBits <= 4)
 cClrBits = 4;
else if (cClrBits <= 8)
 cClrBits = 8;
else if (cClrBits <= 16)
 cClrBits = 16;
else if (cClrBits <= 24)
 cClrBits = 24;
else cClrBits = 32;

// Allocate memory for the BITMAPINFO structure. (This structure
// contains a BITMAPINFOHEADER structure and an array of RGBQUAD
// data structures.)

if (cClrBits != 24)
{
 pbmi = (PBITMAPINFO) LocalAlloc(LPTR,sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1<< cClrBits));
}
// There is no RGBQUAD array for the 24-bit-per-pixel format.
else
 pbmi = (PBITMAPINFO) LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER));

// Initialize the fields in the BITMAPINFO structure.
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biWidth = bmp.bmWidth;
pbmi->bmiHeader.biHeight = bmp.bmHeight;
pbmi->bmiHeader.biPlanes = bmp.bmPlanes;
pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel;
if (cClrBits < 24)
{
 pbmi->bmiHeader.biClrUsed = (1<<cClrBits);
}
// If the bitmap is not compressed, set the BI_RGB flag.
pbmi->bmiHeader.biCompression = BI_RGB;

// Compute the number of bytes in the array of color
// indices and store the result in biSizeImage.
// For Windows NT, the width must be DWORD aligned unless
// the bitmap is RLE compressed. This example shows this.
// For Windows 95/98/Me, the width must be WORD aligned unless the
// bitmap is RLE compressed.
pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) /8 * pbmi->bmiHeader.biHeight;
// Set biClrImportant to 0, indicating that all of the
// device colors are important.
pbmi->bmiHeader.biClrImportant = 0;

return pbmi; //return BITMAPINFO
}



And Finally here is the full code for connecting a webcam in windows
and grabbing a frame and saving it to the hard drive.

//Setup some defines you need to connect to a webcam
//You can put these in a header
//If you are using Microsoft Visual Studio you wont need them as they
//Are included in Microsoft's version of vfw.h
#define WM_CAP_START  0x0400
#define WM_CAP_DRIVER_CONNECT  (WM_CAP_START + 10)
#define WM_CAP_DRIVER_DISCONNECT  (WM_CAP_START + 11)
#define WM_CAP_EDIT_COPY (WM_CAP_START + 30)
#define WM_CAP_GRAB_FRAME (WM_CAP_START + 60)
#define WM_CAP_SET_SCALE (WM_CAP_START + 53)
#define WM_CAP_SET_PREVIEWRATE (WM_CAP_START + 52)
#define WM_CAP_SET_PREVIEW (WM_CAP_START + 50)
#define WM_CAP_DLG_VIDEOSOURCE  (WM_CAP_START + 42)
#define WM_CAP_STOP (WM_CAP_START+ 68)
//End of defines

#include <windows.h>
#include <vfw.h>
//Remember to Link to vfw32 Library, gdi32 Library




LRESULT CALLBACK WindowProc (HWND, UINT, WPARAM, LPARAM);
PBITMAPINFO CreateBitmapInfoStruct(HWND hwnd, HBITMAP hBmp);
void CreateBMPFile(HWND hwnd, LPTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC);

char szAppName [] = TEXT("WebCam");
HWND camhwnd;
HDC hdc ;
HDC hdcMem;
PAINTSTRUCT ps;
HBITMAP hbm;
RECT rc;

//WinMain -- Main Window
int WINAPI WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance,
                     LPSTR lpCmdLine, int nCmdShow )
{

    HWND hwnd;
    MSG msg;

    WNDCLASS wc;
    wc.style = CS_HREDRAW|CS_VREDRAW;
    wc.lpfnWndProc = WindowProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon(GetModuleHandle(NULL), IDI_APPLICATION);
    wc.hCursor = LoadCursor (NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH) (COLOR_WINDOW+1);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = szAppName;

    RegisterClass (&wc);

// Create the window
    hwnd = CreateWindow (szAppName,szAppName,WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX,CW_USEDEFAULT,CW_USEDEFAULT,300,600,0,0,hInstance,0);

    ShowWindow (hwnd,SW_SHOW);
    UpdateWindow (hwnd);

    while (GetMessage(&msg,0,0,0))
    {
        if (!IsDialogMessage(hwnd, &msg))
        {
            TranslateMessage (&msg);
            DispatchMessage (&msg);
        }
    }
    return msg.wParam;
}

//Main Window Procedure WindowProc
LRESULT CALLBACK WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    HINSTANCE hInstance = GetModuleHandle(NULL);

//some buttons
    HWND hButtStartCam;
    HWND hButtStopCam;
    HWND hButtGrabFrame;

    switch (message)                  /* handle the messages */
    {

    case WM_CTLCOLORSTATIC:
        SetBkMode(hdc,TRANSPARENT);
        return (LRESULT)CreateSolidBrush(0xFFFFFF);

    case WM_CREATE:
    {
        hButtStartCam = CreateWindowEx(0,"BUTTON","Start Camera",WS_CHILD | WS_VISIBLE,
                                       0,0,100,20,hwnd,(HMENU)1,hInstance, 0);
        hButtStopCam = CreateWindowEx(0,"BUTTON","Stop Camera",WS_CHILD | WS_VISIBLE,
                                      0,25,100,20,hwnd,(HMENU)2,hInstance, 0);
        hButtGrabFrame = CreateWindowEx(0,"BUTTON","Grab Frame",WS_CHILD | WS_VISIBLE,
                                        0,50,100,20,hwnd,(HMENU)3,hInstance, 0);

        camhwnd = capCreateCaptureWindow ("camera window", WS_CHILD , 0, 100, 300, 300, hwnd, 0);
        SendMessage(camhwnd,WM_CAP_DRIVER_CONNECT,0,0);
        SendMessage(camhwnd,WM_CAP_DLG_VIDEOSOURCE,0,0);

        break;
    }

    case WM_COMMAND:
    {
        switch (LOWORD(wParam))
        {

        case 1:
        {
            ShowWindow(camhwnd,SW_SHOW);
            SendMessage(camhwnd,WM_CAP_DRIVER_CONNECT,0,0);
            SendMessage(camhwnd, WM_CAP_SET_SCALE, true , 0);
            SendMessage(camhwnd, WM_CAP_SET_PREVIEWRATE, 66, 0);
            SendMessage(camhwnd, WM_CAP_SET_PREVIEW, true , 0);
            break;
        }

        case 2:
        {
            ShowWindow(camhwnd,SW_HIDE);
            SendMessage(camhwnd, WM_CAP_DRIVER_DISCONNECT, 0, 0);
            break;
        }

        case 3:
        {
//Grab a Frame
            SendMessage(camhwnd, WM_CAP_GRAB_FRAME, 0, 0);
//Copy the frame we have just grabbed to the clipboard
            SendMessage(camhwnd, WM_CAP_EDIT_COPY,0,0);

//Copy the clipboard image data to a HBITMAP object called hbm
            hdc = BeginPaint(camhwnd, &ps);
            hdcMem = CreateCompatibleDC(hdc);
            if (hdcMem != NULL)
            {
                if (OpenClipboard(camhwnd))
                {
                    hbm = (HBITMAP) GetClipboardData(CF_BITMAP);
                    SelectObject(hdcMem, hbm);
                    GetClientRect(camhwnd, &rc);
                    CloseClipboard();
                }
            }
//Save hbm to a .bmp file called Frame.bmp
            PBITMAPINFO pbi = CreateBitmapInfoStruct(hwnd, hbm);
            CreateBMPFile(hwnd, "Frame.bmp", pbi, hbm, hdcMem);

            SendMessage(camhwnd,WM_CAP_DRIVER_CONNECT,0,0);
            SendMessage(camhwnd, WM_CAP_SET_SCALE, true , 0);
            SendMessage(camhwnd, WM_CAP_SET_PREVIEWRATE, 66, 0);
            SendMessage(camhwnd, WM_CAP_SET_PREVIEW, true , 0);
            break;
        }
        }
        break;
    }

    case WM_DESTROY:
    {
        SendMessage(camhwnd, WM_CAP_DRIVER_DISCONNECT, 0, 0);
        PostQuitMessage(0);   /* send a WM_QUIT to the message queue */
        break;
    }

    default:              /* for messages that we don't deal with */
        return DefWindowProc(hwnd, message, wParam, lParam);
    }
    return 0;
}

void CreateBMPFile(HWND hwnd, LPTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC)
{
    HANDLE hf;                  // file handle
    BITMAPFILEHEADER hdr;       // bitmap file-header
    PBITMAPINFOHEADER pbih;     // bitmap info-header
    LPBYTE lpBits;              // memory pointer
    DWORD dwTotal;              // total count of bytes
    DWORD cb;                   // incremental count of bytes
    BYTE *hp;                   // byte pointer
    DWORD dwTmp;

    pbih = (PBITMAPINFOHEADER) pbi;
    lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih->biSizeImage);

    if (!lpBits)
    {
        MessageBox(hwnd,"GlobalAlloc","Error", MB_OK );
    }
// Retrieve the color table (RGBQUAD array) and the bits
// (array of palette indices) from the DIB.
    if (!GetDIBits(hDC, hBMP, 0, (WORD) pbih->biHeight, lpBits, pbi,DIB_RGB_COLORS))
    {
        MessageBox(hwnd,"GetDIBits","Error",MB_OK );
    }
// Create the .BMP file.
    hf = CreateFile(pszFile,GENERIC_READ | GENERIC_WRITE,(DWORD) 0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,(HANDLE) NULL);
    if (hf == INVALID_HANDLE_VALUE)
    {
        MessageBox( hwnd,"CreateFile","Error", MB_OK);
    }

    hdr.bfType = 0x4d42;  // File type designator "BM" 0x42 = "B" 0x4d = "M"
// Compute the size of the entire file.
    hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) + pbih->biSize + pbih->biClrUsed * sizeof(RGBQUAD) + pbih->biSizeImage);
    hdr.bfReserved1 = 0;
    hdr.bfReserved2 = 0;
// Compute the offset to the array of color indices.
    hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) + pbih->biSize + pbih->biClrUsed * sizeof (RGBQUAD);
// Copy the BITMAPFILEHEADER into the .BMP file.
    if (!WriteFile(hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER), (LPDWORD) &dwTmp,  NULL) )
    {
        MessageBox(hwnd,"WriteFileHeader","Error",MB_OK );
    }
// Copy the BITMAPINFOHEADER and RGBQUAD array into the file.
    if (!WriteFile(hf, (LPVOID) pbih, sizeof(BITMAPINFOHEADER) + pbih->biClrUsed * sizeof (RGBQUAD), (LPDWORD) &dwTmp, NULL))
    {
        MessageBox(hwnd,"WriteInfoHeader","Error",MB_OK );
    }
// Copy the array of color indices into the .BMP file.
    dwTotal = cb = pbih->biSizeImage;
    hp = lpBits;
    if (!WriteFile(hf, (LPSTR) hp, (int) cb, (LPDWORD) &dwTmp,NULL))
    {
        MessageBox(hwnd,"WriteFile","Error",MB_OK );
    }
// Close the .BMP file.
    if (!CloseHandle(hf))
    {
        MessageBox(hwnd,"CloseHandle","Error",MB_OK );
    }

// Free memory.
    GlobalFree((HGLOBAL)lpBits);
}

PBITMAPINFO CreateBitmapInfoStruct(HWND hwnd, HBITMAP hBmp)
{
    BITMAP bmp;
    PBITMAPINFO pbmi;
    WORD cClrBits;
// Retrieve the bitmap color format, width, and height.
    if (!GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bmp))
    {
        MessageBox(hwnd,"GetObject","Error",MB_OK );
    }
// Convert the color format to a count of bits.
    cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel);
    if (cClrBits == 1)
        cClrBits = 1;
    else if (cClrBits <= 4)
        cClrBits = 4;
    else if (cClrBits <= 8)
        cClrBits = 8;
    else if (cClrBits <= 16)
        cClrBits = 16;
    else if (cClrBits <= 24)
        cClrBits = 24;
    else cClrBits = 32;

// Allocate memory for the BITMAPINFO structure. (This structure
// contains a BITMAPINFOHEADER structure and an array of RGBQUAD
// data structures.)

    if (cClrBits != 24)
    {
        pbmi = (PBITMAPINFO) LocalAlloc(LPTR,sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1<< cClrBits));
    }
// There is no RGBQUAD array for the 24-bit-per-pixel format.
    else
        pbmi = (PBITMAPINFO) LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER));

// Initialize the fields in the BITMAPINFO structure.
    pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    pbmi->bmiHeader.biWidth = bmp.bmWidth;
    pbmi->bmiHeader.biHeight = bmp.bmHeight;
    pbmi->bmiHeader.biPlanes = bmp.bmPlanes;
    pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel;
    if (cClrBits < 24)
    {
        pbmi->bmiHeader.biClrUsed = (1<<cClrBits);
    }
// If the bitmap is not compressed, set the BI_RGB flag.
    pbmi->bmiHeader.biCompression = BI_RGB;

// Compute the number of bytes in the array of color
// indices and store the result in biSizeImage.
// For Windows NT, the width must be DWORD aligned unless
// the bitmap is RLE compressed. This example shows this.
// For Windows 95/98/Me, the width must be WORD aligned unless the
// bitmap is RLE compressed.
    pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) /8 * pbmi->bmiHeader.biHeight;
// Set biClrImportant to 0, indicating that all of the
// device colors are important.
    pbmi->bmiHeader.biClrImportant = 0;

    return pbmi; //return BITMAPINFO
}



Is This A Good Question/Topic? 12
  • +

Replies To: Win32 WebCam Program

#2 Aphex19  Icon User is offline

  • Born again Pastafarian.
  • member icon

Reputation: 614
  • View blog
  • Posts: 1,873
  • Joined: 02-August 09

Posted 21 October 2010 - 06:59 AM

Thank you, this is very helpful to me. It's much appreciated.
Was This Post Helpful? 1
  • +
  • -

#3 snoopy11  Icon User is offline

  • Engineering ● Software
  • member icon

Reputation: 762
  • View blog
  • Posts: 2,214
  • Joined: 20-March 10

Posted 21 October 2010 - 12:40 PM

@ Aphex19

Thats ok glad I could be of help.

Thanks for your reply.

Snoopy.
Was This Post Helpful? 1
  • +
  • -

#4 Guest_Footman*


Reputation:

Posted 19 February 2011 - 08:07 AM

View Postsnoopy11, on 21 October 2010 - 12:40 PM, said:

@ Aphex19

Thats ok glad I could be of help.

Thanks for your reply.

Snoopy.

Was This Post Helpful? 1

#5 Guest_Footman*


Reputation:

Posted 19 February 2011 - 08:15 AM

Hello,
Thank you at first for this tutorial. It worked fine for me for 2 weeks, but now i have strange bug : the preview window is black.
Cam is on and i can get some snapshots but i don't see anything in preview screen. Same script works good in VB.Net but not in c++.
I have vc++ pro Edition and Sony Vaio standard webcam. Do you have some solutions for this problem?
Was This Post Helpful? 0

#6 Guest_Marref*


Reputation:

Posted 22 February 2011 - 01:47 PM

1>LINK : fatal error LNK1104: impossible d'ouvrir le fichier 'Vfw32.libkernel32.lib'
What is the probleme ?
how can I resolve it
P.S: I have a windows 64 bits
Was This Post Helpful? 1

#7 snoopy11  Icon User is offline

  • Engineering ● Software
  • member icon

Reputation: 762
  • View blog
  • Posts: 2,214
  • Joined: 20-March 10

Posted 14 March 2011 - 12:45 PM

View PostFootman, on 19 February 2011 - 08:15 AM, said:

Hello,
Thank you at first for this tutorial. It worked fine for me for 2 weeks, but now i have strange bug : the preview window is black.
Cam is on and i can get some snapshots but i don't see anything in preview screen. Same script works good in VB.Net but not in c++.
I have vc++ pro Edition and Sony Vaio standard webcam. Do you have some solutions for this problem?


It sounds like you have a problem with your usb root hub that you have the cam connected to try the following at wikiHow

How to fix a webcam that is displaying a blank screen

let me know how you get on.

View PostMarref, on 22 February 2011 - 01:47 PM, said:

1>LINK : fatal error LNK1104: impossible d'ouvrir le fichier 'Vfw32.libkernel32.lib'
What is the probleme ?
how can I resolve it
P.S: I have a windows 64 bits


you have to link to vfw32.lib and kernel32.lib for this program to work refer
to you compiler instructions on how to link to libraries.
Was This Post Helpful? 0
  • +
  • -

#8 ryanmills  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 19-April 11

Posted 19 April 2011 - 12:30 AM

Error in VC++ 2010 Express (sdk installed) Windows 7

------ Build started: Project: CameraTest, Configuration: Debug Win32 ------
MSVCRTD.lib(crtexe.obj) : error LNK2019: unresolved external symbol _main referenced in function ___tmainCRTStartup
C:\Users\ryan\documents\visual studio 2010\Projects\CameraTest\Debug\CameraTest.exe : fatal error LNK1120: 1 unresolved externals
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========


Thoughts
Was This Post Helpful? 0
  • +
  • -

#9 snoopy11  Icon User is offline

  • Engineering ● Software
  • member icon

Reputation: 762
  • View blog
  • Posts: 2,214
  • Joined: 20-March 10

Posted 17 May 2011 - 12:12 AM

It sounds like you are trying to build this as a console application
this is a windows application so try building it as a Win32 project !!
Was This Post Helpful? 0
  • +
  • -

#10 tau_neutrino  Icon User is offline

  • New D.I.C Head

Reputation: -3
  • View blog
  • Posts: 3
  • Joined: 24-June 11

Posted 24 June 2011 - 06:32 AM

snoopy11, thank you for the article!
Why don't you use WM_CAP_FILE_SAVEDIB? It will save a file in a single call, won't it?

My problem with this code is that using clipboard is very annoying. Is there any other way to get the frames grabbed? Thanks!
Was This Post Helpful? 0
  • +
  • -

#11 Deca  Icon User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 7
  • Joined: 09-July 11

Posted 09 July 2011 - 02:36 PM

nice artical
Was This Post Helpful? 0
  • +
  • -

#12 snoopy11  Icon User is offline

  • Engineering ● Software
  • member icon

Reputation: 762
  • View blog
  • Posts: 2,214
  • Joined: 20-March 10

Posted 20 July 2011 - 10:54 PM

View Posttau_neutrino, on 24 June 2011 - 06:32 AM, said:

snoopy11, thank you for the article!
Why don't you use WM_CAP_FILE_SAVEDIB? It will save a file in a single call, won't it?

My problem with this code is that using clipboard is very annoying. Is there any other way to get the frames grabbed? Thanks!



Yes it will my reasons for doing it this way was simply to write
my own .bmp saving routine which i was interested in doing at the time....

if you are not using microsoft visual c++

then you will need to add this define.

#define WM_CAP_FILE_SAVEDIB           (WM_CAP_START+  25)



then ammend case 3 inside WM_COMMAND to look like this

case 3:
        {

//Save to a .bmp file called MyCapture.bmp
            
            LPSTR filename =(LPSTR)"MyCapture.bmp";
            SendMessage(camhwnd,WM_CAP_FILE_SAVEDIB, 0, (LPARAM) filename);
            SendMessage(camhwnd,WM_CAP_DRIVER_CONNECT,0,0);
            SendMessage(camhwnd, WM_CAP_SET_SCALE, true , 0);
            SendMessage(camhwnd, WM_CAP_SET_PREVIEWRATE, 66, 0);
            SendMessage(camhwnd, WM_CAP_SET_PREVIEW, true , 0);
            break;
        }



You can delete the overhead functions
void CreateBMPFile
and
PBITMAPINFO CreateBitmapInfoStruct

Best Wishes Snoopy
Was This Post Helpful? 0
  • +
  • -

#13 lamaabed  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 2
  • Joined: 11-December 11

Posted 11 December 2011 - 03:58 PM

How i can record the video that is anable from webcam?
Was This Post Helpful? 0
  • +
  • -

#14 snoopy11  Icon User is offline

  • Engineering ● Software
  • member icon

Reputation: 762
  • View blog
  • Posts: 2,214
  • Joined: 20-March 10

Posted 11 December 2011 - 07:01 PM

search the snippets section of DIC

I cover this there.


Best Wishes

Snoopy.
Was This Post Helpful? 0
  • +
  • -

#15 lamaabed  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 2
  • Joined: 11-December 11

Posted 12 December 2011 - 08:56 AM

excuse me .. i want to ask that i want to enable the camera when the program running without the button start camera.. could u tell me how i can do this?
Was This Post Helpful? 0
  • +
  • -

  • (4 Pages)
  • +
  • 1
  • 2
  • 3
  • Last »