oday, a webcam is a common peripheral, used most often for video conferencing, that most people can easily afford. But what can you do with your webcam besides video conferencing? If you are a developer, the answer is plenty; you will be glad to know that integrating a webcam with an application is not as difficult as you might imagine.
Using the AVICap window class available in the Windows operating system, you can easily incorporate video capture capabilities into your Windows application. The uses of this functionality are endless but in particular you can easily populate employee and other person databases with mug shots taken directly from the users’ terminal.
The AVICap class (located in the avicap32.dll file) contains message-based interfaces to access video and waveform-audio acquisition hardware and provides the ability to capture streaming video to disk. The only downside to the AVICap class is that it is an API and is thus not exposed as a managed class to the .NET developer. Hence, as a .NET developer you’ll need to use Platform Invoke (P/Invoke) to make use of the API.
In this article, I will show you how to incorporate video capabilities into your .NET Windows applications. In particular, you will learn how to:
- preview video input (within your Windows application) from your Webcam
- record streaming video
- capture images using your webcam.
In addition, I will develop a Windows application that puts the new video capability to good use. You will see how you can use the techniques discussed to take photos of new users in a registration system.
Using the AVICap Class
To show how to use the AVICap class for integrating video into your Windows application, I’ll use Visual Studio 2005 to create a new Windows application project. I’ll name the project C:VideoCapture. The application that you will build will list all the video sources available on your computer. You can then select a video source (in this case, your webcam) and preview its content. You will also learn how to record a video stream to file.
First, populate the default Windows Form using the controls shown in Figure 1. You will need a ListBox control for displaying the video sources on your computer, a PictureBox control, with which to preview the video captures, and three Button controls to start and stop the video recording as well as to stop the selected camera.
|Figure 1. Proper Form: The screen shot shows the placement of each control you’ll need to put on the default Windows Form in order to create the functionality for the sample application.|
Switch to the code-behind of the form and import the following namespace (required for P/Invoke):
Within the Form1 class, declare the constants used by the AVICap class:
Const WM_CAP_START = &H400S Const WS_CHILD = &H40000000 Const WS_VISIBLE = &H10000000 Const WM_CAP_DRIVER_CONNECT = WM_CAP_START + 10 Const WM_CAP_DRIVER_DISCONNECT = WM_CAP_START + 11 Const WM_CAP_EDIT_COPY = WM_CAP_START + 30 Const WM_CAP_SEQUENCE = WM_CAP_START + 62 Const WM_CAP_FILE_SAVEAS = WM_CAP_START + 23 Const WM_CAP_SET_SCALE = WM_CAP_START + 53 Const WM_CAP_SET_PREVIEWRATE = WM_CAP_START + 52 Const WM_CAP_SET_PREVIEW = WM_CAP_START + 50 Const SWP_NOMOVE = &H2S Const SWP_NOSIZE = 1 Const SWP_NOZORDER = &H4S Const HWND_BOTTOM = 1
|Author’s Note: The use of each of the constants listed above can be found in the Windows Multimedia SDK Help Reference at: ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.WIN32COM.v10.en/multimed/htm/_win32_video_capture_reference.htm. You can view the help files using the Help system that comes installed with Visual Studio 2005.|
After declaring the constants, you need to declare the functions. The first two functions are needed for video capturing purposes and can be found in the avicap32.dll library, while the next three functions (found in user32.dll) are used for manipulating the various windows.
'--The capGetDriverDescription function retrieves the version ' description of the capture driver--Declare Function capGetDriverDescriptionA Lib "avicap32.dll" _ (ByVal wDriverIndex As Short, _ ByVal lpszName As String, ByVal cbName As Integer, _ ByVal lpszVer As String, _ ByVal cbVer As Integer) As Boolean'--The capCreateCaptureWindow function creates a capture window--Declare Function capCreateCaptureWindowA Lib "avicap32.dll" _ (ByVal lpszWindowName As String, ByVal dwStyle As Integer, _ ByVal x As Integer, ByVal y As Integer, ByVal nWidth As Integer, _ ByVal nHeight As Short, ByVal hWnd As Integer, _ ByVal nID As Integer) As Integer'--This function sends the specified message to a window or windows--Declare Function SendMessage Lib "user32" Alias "SendMessageA" _ (ByVal hwnd As Integer, ByVal Msg As Integer, _ ByVal wParam As Integer, _
ByVal lParam As Object) As Integer'--Sets the position of the window relative to the screen buffer--Declare Function SetWindowPos Lib "user32" Alias "SetWindowPos" _ (ByVal hwnd As Integer, _ ByVal hWndInsertAfter As Integer, ByVal x As Integer, _ ByVal y As Integer, _ ByVal cx As Integer, ByVal cy As Integer, _ ByVal wFlags As Integer) As Integer'--This function destroys the specified window--Declare Function DestroyWindow Lib "user32" _ (ByVal hndw As Integer) As Boolean
Also declare the following member variables:
'---used to identify the video source--- Dim VideoSource As Integer '---used as a window handle--- Dim hWnd As Integer
When the form is loaded for the first time, all the video sources connected to your computer will be listed in the ListBox control. This task is accomplished by the ListVideoSources() subroutine:
Private Sub Form1_Load( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load btnStartRecording.Enabled = True btnStopRecording.Enabled = False '---list all the video sources--- ListVideoSources() End Sub
The ListVideoSources() subroutine calls the capGetDriverDescriptionA() function and lists all the video sources in the ListBox control. Up to 10 video sources are supported:
'---list all the various video sources--- Private Sub ListVideoSources() Dim DriverName As String = Space(80) Dim DriverVersion As String = Space(80) For i As Integer = 0 To 9 If capGetDriverDescriptionA(i, DriverName, 80, _ DriverVersion, 80) Then lstVideoSources.Items.Add(DriverName.Trim) End If Next End Sub
Figure 2 shows the ListBox control showing a video source connected to my computer when the form is loaded.
|Figure 2. Video Options: The ListBox control displays a list of the list of video sources from your computer.|
Users can view a video source by selecting it in the ListBox control. To allow the user to do that, double-click on the ListBox control and code the following:
'---list all the video sources--- Private Sub lstVideoSources_SelectedIndexChanged( _ ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles lstVideoSources.SelectedIndexChanged '---check which video source is selected--- VideoSource = lstVideoSources.SelectedIndex '---preview the selected video source PreviewVideo(PictureBox1) End Sub
The previous event basically identifies the selected video source and then calls the PreviewVideo() subroutine to preview the video, which is shown below:
'---preview the selected video source--- Private Sub PreviewVideo(ByVal pbCtrl As PictureBox) hWnd = capCreateCaptureWindowA(VideoSource, _ WS_VISIBLE Or WS_CHILD, 0, 0, 0, _ 0, pbCtrl.Handle.ToInt32, 0) If SendMessage( _ hWnd, WM_CAP_DRIVER_CONNECT, _ VideoSource, 0) Then '---set the preview scale--- SendMessage(hWnd, WM_CAP_SET_SCALE, True, 0) '---set the preview rate (ms)--- SendMessage(hWnd, WM_CAP_SET_PREVIEWRATE, 30, 0) '---start previewing the image--- SendMessage(hWnd, WM_CAP_SET_PREVIEW, True, 0) '---resize window to fit in PictureBox control--- SetWindowPos(hWnd, HWND_BOTTOM, 0, 0, _ pbCtrl.Width, pbCtrl.Height, _ SWP_NOMOVE Or SWP_NOZORDER) Else '--error connecting to video source--- DestroyWindow(hWnd) End If End Sub
The Stop Camera button calls the StopPreviewWindow() subroutine to destroy the current window showing the video preview:
'---stop the preview window--- Private Sub btnStopCamera_Click( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles btnStopCamera.Click StopPreviewWindow() End Sub
The StopPreviewWindow() subroutine is as follows:
'--disconnect from video source--- Private Sub StopPreviewWindow() SendMessage(hWnd, WM_CAP_DRIVER_DISCONNECT, VideoSource, 0) DestroyWindow(hWnd) End Sub
The Start Recording button allows you to start capturing the selected video source:
'---Start recording the video--- Private Sub btnStartRecording_Click( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles btnStartRecording.Click btnStartRecording.Enabled = False btnStopRecording.Enabled = True '---start recording--- SendMessage(hWnd, WM_CAP_SEQUENCE, 0, 0) End Sub
When the Stop Recording button is clicked, the video stream is saved as an .avi file:
'---stop recording and save it on file--- Private Sub btnStopRecording_Click( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles btnStopRecording.Click btnStartRecording.Enabled = True btnStopRecording.Enabled = False '---save the recording to file--- SendMessage(hWnd, WM_CAP_FILE_SAVEAS, 0, _ "C:RecordedVideo.avi") End Sub
That?s it! You can now test the application by pressing F5. Make sure you have a video source (e.g. webcam) connected to your computer. You should see an item in the ListBox control (see Figure 3). Click the video source and you should see an image shown up in the PictureBox control. To start recording, click the Start Recording button and then click the Stop Recording button to save the video to file. The Stop Camera will disconnect the selected video source from the PictureBox control.
Using Video Capability in a Business Application
Now that I have managed to integrate video into my Windows application, I’ll consider a practical use of it. In this section, I will use data-binding to display some records from the Employees table in the Northwind database (one of the sample databases that comes with SQL Server 2000).
If you are familiar with the Northwind database, you know that in the Employees table there is a field known as Photo. This field is used to store employees? photographs. In a real-life application, it would be much easier to add in an employee?s photo if you can take a snapshot of him using a webcam and then directly add the record to the database. In this section, I will show you how to do that.
First, add a new data source to the project. You can do so using the Data->Add New Data Source? menu (see Figure 5).
Enter the name of the SQL Server containing the Northwind database. For my example, it is located on the same machine running Visual Studio 2005 and hence I entered “(local).” Select the Northwind database and then click OK (see Figure 6). Click Next when you are back to the previous window.
In the next window, you will choose the tables to use. Check the fields as shown in Figure 7. Click Finish to complete the process. The fields selected are: EmployeeID, LastName, FirstName, Title, and Photo. The Photo field is of the image data type, which contains images of employee. You will bind the Photo field to a PictureBox control on the windows form.
The Employees table should now look like Figure 9.
If you test the application now (by pressing F5), you will be able to view the records in the Employees table (see Figure 11.). You can add a record by clicking the Add New button, entering the value for each field, and then clicking the Save Data button to save the changes.
Double-click the Add New button so that when the user adds a new record, the video source is now bound to the PhotoPictureBox control:
Private Sub BindingNavigatorAddNewItem_Click( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles BindingNavigatorAddNewItem.Click StopPreviewWindow() PreviewVideo(PhotoPictureBox) End Sub
When the user clicks on the Capture Photo button, you will call the CaptureImage subroutine to freeze the photo:
Private Sub btnCapturePhoto_Click( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles btnCapturePhoto.Click CaptureImage() End Sub
The CaptureImage() subroutine copies the image from the video source onto the clipboard. You then display the image using the PhotoPictureBox control:
'---save the image--- Private Sub CaptureImage() Dim data As IDataObject Dim bmap As Image '---copy the image to the clipboard--- SendMessage(hWnd, WM_CAP_EDIT_COPY, 0, 0) '---retrieve the image from clipboard and convert it ' to the bitmap format data = Clipboard.GetDataObject() If data.GetDataPresent(GetType(System.Drawing.Bitmap)) Then bmap = _ CType(data.GetData(GetType(System.Drawing.Bitmap)), _ Image) PhotoPictureBox.Image = bmap StopPreviewWindow() End If End Sub
|Figure 13. Adding the Author: In this screen shot I’m taking a photo of myself to create a new record in the employee database.|
That’s it! Press F5 to test the application. When the form loads, click on the Add New button to add a new record. Enter the details as shown in Figure 13 and then position the webcam to take a nice snapshot of yourself. Smile and then click the Capture Photo button.
Finally, click the Save Data button to save the new record onto the database. You can verify that the photo is saved by restarting the application and then viewing the records again.
In this article, you have seen how to use the AVICap class to integrate video into your Windows application. While I have only showed you one particular usage, there are in fact many uses for video: you can build a video surveillance system using the techniques described in this article or you can build your own video conferencing application. The possibilities are endless and please let me know if you have an innovative application built using the techniques described in this article.