How to Interface to a Video Device and Capture Video and Images
Whilst not painlessly straightforward, interfacing to a webcam and capturing images is relatively easy. Image capture only requires you to load avicap32.dll and send messages into the device's window; the trick is in knowing what messages to send.
At the end of this article you will find a download for the source code an application that will interface into video devices and capture a video stream. The code also shows you how to save a captured bitmap image to a file on disk.
Walkthrough
Enumerating Devices
Device enumeration is important if you have more than one streaming video device or if you don't know what device number you want to connect to. Enumeration may not be needed for experimental code but it will be required if you don't intend to confuse and confound your users.
avicap32.dll exposes a method called capGetDriverDescription that can be used to obtain the names and versions of the installed capture devices. capGetDriverDescription takes four parameters, which consists of two buffer pointers and two size pointers. 128 bytes was chosen In the example below, but you can use any reasonable number for the buffers. If the device data won't fit into the buffers that you supply to to the method then the data will merely be truncated. You must also pre-fill the buffers to the correct size, and call the enumeration routine before exposing any functions to the user.
The code below enumerates capture devices and fills a ComboBox with device names. The device number directly corresponds to the item's index in the ComboBox so there is no need to create a list of device numbers:
' http://msdn.microsoft.com/en-us/library/ms708473.aspx
Declare Function capGetDriverDescriptionA Lib "avicap32.dll" ( _
ByVal wDriver As Short, _
ByVal lpszName As String, _
ByVal cbName As Integer, _
ByVal lpszVer As String, _
ByVal cbVer As Integer) As Boolean
Private Sub EnumerateCaptureDevices()
Dim DeviceName As String = Space(128) ' Device name buffer. 128 is a guesstimate.
Dim DeviceVersion As String = Space(128) ' Device version buffer.
Dim iDevice As Integer = 0 ' Device number, zero-based
Dim bHaveDevice As Boolean
Do
bHaveDevice = capGetDriverDescriptionA(iDevice, DeviceName, 128, _
DeviceVersion, 128)
If bHaveDevice Then
' ComboBoxDevices is a DropDownList on the default form
ComboBoxDevices.Items.Add(DeviceName.Trim)
End If
iDevice += 1
Loop Until bHaveDevice = False
If ComboBoxDevices.Items.Count <> 0 Then
ComboBoxDevices.SelectedIndex = 0
ButtonStart.Enabled = True
Else
ComboBoxDevices.Items.Add("No capture devices found")
End If
End Sub
Start Capture
To begin capturing output from the streaming video device, call capCreateCaptureWindow and pass the device number, window parameters and a handle to the display window. If the device is ready it will return a handle to its output window, at which point you connect to the driver, scale the output and set your desired preview rate. The PictureBox should display the video stream:
' http://msdn.microsoft.com/en-us/library/ms707853.aspx
Declare Function capCreateCaptureWindow Lib "avicap32.dll" Alias _
"capCreateCaptureWindowA" (ByVal a As String, _
ByVal b As Long, _
ByVal c As Integer, _
ByVal d As Integer, _
ByVal e As Integer, _
ByVal f As Integer, _
ByVal g As Long, _
ByVal h As Integer) As Long
'
' Window Styles
' http://msdn.microsoft.com/en-us/library/czada357(VS.80).aspx
Private Const WS_CHILD As Integer = &H40000000
Private Const WS_VISIBLE As Integer = &H10000000
'
' Windows User Interface Services
' http://msdn.microsoft.com/en-us/library/ms961540.aspx
Private Const SWP_NOMOVE As Short = &H2S
Private Const SWP_NOZORDER As Short = &H4S
Private Const HWND_BOTTOM As Short = 1
'
' Video capture messages
' http://msdn.microsoft.com/en-us/library/ms713480(VS.85).aspx
Private Const WM_CAP_DLG_VIDEOFORMAT As Integer = &H429
Private Const WM_CAP_DRIVER_CONNECT As Integer = &H40A
Private Const WM_CAP_DRIVER_DISCONNECT As Integer = &H40B
Private Const WM_CAP_EDIT_COPY As Integer = &H41E
Private Const WM_CAP_DRIVER_CONNECT As Integer = &H40A
Private Const WM_CAP_SET_PREVIEW As Integer = &H432
Private Const WM_CAP_SET_PREVIEWRATE As Integer = &H434
Private Const WM_CAP_SET_SCALE As Integer = &H435
'
' Preview window handle
Private hHwnd As Integer
Private Sub StartCapture()
hHwnd = capCreateCaptureWindow(ComboBoxDevices.SelectedIndex, _
WS_CHILD Or WS_VISIBLE, 0, 0, 320, 240, _
PictureBoxCapture.Handle.ToInt32, 0)
If (hHwnd <> 0) Then
' These calls to SendMessage return integer results but we are ignoring them.
' ComboBoxDevices is a DropDownList on the default form, populated by
' a call to EnumerateCaptureDevices
Call SendMessage(hHwnd, WM_CAP_DRIVER_CONNECT, ComboBoxDevices.SelectedIndex, 0&)
' Scale
Call SendMessage(hHwnd, WM_CAP_SET_SCALE, True, 0&)
' Preview rate in milliseconds
Call SendMessage(hHwnd, WM_CAP_SET_PREVIEWRATE, 30&, 0&)
' Begin preview
Call SendMessage(hHwnd, WM_CAP_SET_PREVIEW, 1&, 0&)
' PictureBoxCapture is a PictureBox on the default form
' Resize the device output window to fit inside PictureBoxCapture
Call SetWindowPos(hHwnd, HWND_BOTTOM, 0%, 0%, PictureBoxCapture.Width, _
PictureBoxCapture.Height, SWP_NOMOVE Or SWP_NOZORDER)
Else
MsgBox("No capture devices found")
End If
End Sub
Cleaning Up
Once the video stream is no longer needed, send a WM_CAP_DRIVER_DISCONNECT message to the device window then destroy the device window itself:
Private Sub Finished()
' Disconnect from the video stream
SendMessage(hHwnd, WM_CAP_DRIVER_DISCONNECT, ComboBoxDevices.SelectedIndex, 0&)
' Destroy the output window
DestroyWindow(hHwnd)
' Exit, close the default form
Me.Close()
End Sub
Download Sample Project
All code examples on this site have been developed for .Net Framework 3.5 | |||