|
-
Dec 26th, 2012, 02:00 AM
#1
Thread Starter
Fanatic Member
2 web cameras and .net
Hi All,
I need help once again, I have tried searching all day with no luck.
Im making a camera/video capture app for my shinny new windows tablet (win 7 ultimate). I have tried a few apps but all are really crap and not what im after.
From searching I found the avicap32.dll method which on my dev computer works perfect, on my tablet however it doesnt.
The reason for this is the tablet has 2 webcams, front and back, both use the very same driver so show as 1 source on the tablet. when i select the source it gives me the option of picking abc usb cam or cba usb cam but still doesnt work.
I have no idea how to get around this 
also skype can list the name of the webcams and display perfectly as can the trialed apps.
Please see below code
Code:
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
'--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, _
<MarshalAs(UnmanagedType.AsAny)> 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
'---used to identify the video source---
Dim VideoSource As Integer
'---used as a window handle---
Dim hWnd As Integer
Private Sub btnSave_Click(sender As System.Object, e As System.EventArgs) Handles btnSave.Click
Dim path As String
path = "C:\data\"
Dim number As Integer
number = System.IO.Directory.GetFiles(path).Length
SendMessage(hWnd, WM_CAP_EDIT_COPY, 0, 0)
Dim loData As IDataObject = Clipboard.GetDataObject()
If loData.GetDataPresent(GetType(System.Drawing.Bitmap)) Then
Using loBitmap As Image = CType(loData.GetData(GetType(System.Drawing.Bitmap)), Image)
loBitmap.Save(path & "image" & number & ".jpg", Imaging.ImageFormat.Jpeg)
PictureBox2.Image = Image.FromFile(path & "image" & number & ".jpg")
PictureBox2.SizeMode = PictureBoxSizeMode.StretchImage
End Using
End If
End Sub
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
System.IO.Directory.CreateDirectory("C:\data")
ListVideoSources()
End Sub
'---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
'---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(picCapture)
End Sub
'---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
'---stop the preview window---
Private Sub btnStopCamera_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs)
StopPreviewWindow()
End Sub
'--disconnect from video source---
Private Sub StopPreviewWindow()
SendMessage(hWnd, WM_CAP_DRIVER_DISCONNECT, VideoSource, 0)
DestroyWindow(hWnd)
End Sub
'---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
'---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
so basically the listbox on the form fills with driver details, i would then select it and the preview would appear in the picture box, on the tablet this doesnt happen, both webcams are listed under same driver, select it and windows asks which camera but never loads the preview (ideally i would like that windows pop up to not show as well i have the camera names if that helps).
I did look into some other options like directshow.net and even webcamlib.dll (which looks simple but cant even load the dll).
EDIT**** I added a msgbox to the area that errors on connecting and it ran so it seems like a connection error, seeing as it connects using driver and both have same driver it must not know which one to use. stil any help appriciated**
any and all help is appriciated, i thought this would be easy and is was, until 2 webcams came into it
Last edited by bensonsearch; Dec 26th, 2012 at 02:09 AM.
-
Dec 26th, 2012, 11:55 AM
#2
Re: 2 web cameras and .net
avicap32.dll is almost certainly (actually, scrap 'almost') NOT the method used by any of the applications that work with the tablet. It is, like, so last century. You'll need something considerably more sophisticated such as DirectShow
As the 6-dimensional mathematics professor said to the brain surgeon, "It ain't Rocket Science!"
Reviews: "dunfiddlin likes his DataTables" - jmcilhinney
Please be aware that whilst I will read private messages (one day!) I am unlikely to reply to anything that does not contain offers of cash, fame or marriage!
-
Dec 26th, 2012, 09:38 PM
#3
Thread Starter
Fanatic Member
Re: 2 web cameras and .net
Thanx dunfiddlin
I have gone down the directshow road and have hit a wall, the only thing left is to be able to select which camera to use, the code I have below will always bring up the first video device. I have tried playing around with things in the findcapturedevice sub but to no avail. Any ideas how I could select which camera to use?
cheers for the help
Code:
Imports DirectShowLib
Imports System
Imports System.Diagnostics
Imports System.Drawing
Imports System.Runtime.InteropServices
Imports System.Windows.Forms
Imports System.Runtime.InteropServices.ComTypes
Public Class Form1
Dim D As Integer = Convert.ToInt32("0X8000", 16)
Public WM_GRAPHNOTIFY As Integer = D + 1
Dim VideoWindow As IVideoWindow = Nothing
Dim MediaControl As IMediaControl = Nothing
Dim MediaEventEx As IMediaEventEx = Nothing
Dim GraphBuilder As IGraphBuilder = Nothing
Dim CaptureGraphBuilder As ICaptureGraphBuilder2 = Nothing
Enum PlayState
Stopped
Paused
Running
Init
End Enum
Dim CurrentState As PlayState = PlayState.Stopped
Dim rot As DsROTEntry = Nothing
Private Sub CaptureVideo()
Dim hr As Integer = 0
Dim sourceFilter As IBaseFilter = Nothing
Try
GetInterfaces()
hr = CaptureGraphBuilder.SetFiltergraph(GraphBuilder) 'Specifies filter graph "graphbuilder" for the capture graph builder "captureGraphBuilder" to use.
sourceFilter = FindCaptureDevice()
hr = GraphBuilder.AddFilter(sourceFilter, "Video Capture")
hr = CaptureGraphBuilder.RenderStream(PinCategory.Preview, MediaType.Video, sourceFilter, Nothing, Nothing)
Marshal.ReleaseComObject(sourceFilter)
SetupVideoWindow()
rot = New DsROTEntry(GraphBuilder)
hr = MediaControl.Run()
CurrentState = PlayState.Running
Catch ex As Exception
MessageBox.Show("An unrecoverable error has occurred.With error : " & ex.ToString)
End Try
End Sub
Private Sub GetInterfaces()
Dim hr As Integer = 0
GraphBuilder = CType(New FilterGraph, IGraphBuilder)
CaptureGraphBuilder = CType(New CaptureGraphBuilder2, ICaptureGraphBuilder2)
MediaControl = CType(GraphBuilder, IMediaControl)
VideoWindow = CType(GraphBuilder, IVideoWindow)
MediaEventEx = CType(GraphBuilder, IMediaEventEx)
hr = MediaEventEx.SetNotifyWindow(Me.Handle, WM_GRAPHNOTIFY, IntPtr.Zero) 'This method designates a window as the recipient of messages generated by or sent to the current DirectShow object
End Sub
Public Function FindCaptureDevice() As IBaseFilter
Dim hr As Integer = 0
Dim classEnum As IEnumMoniker = Nothing
Dim moniker As IMoniker() = New IMoniker(0) {}
Dim source As Object = Nothing
Dim devEnum As ICreateDevEnum = CType(New CreateDevEnum, ICreateDevEnum)
hr = devEnum.CreateClassEnumerator(FilterCategory.VideoInputDevice, classEnum, 0)
Marshal.ReleaseComObject(devEnum)
If classEnum Is Nothing Then
Throw New ApplicationException("No video capture device was detected.\r\n\r\n" & _
"This sample requires a video capture device, such as a USB WebCam,\r\n" & _
"to be installed and working properly. The sample will now close.")
End If
If classEnum.Next(moniker.Length, moniker, IntPtr.Zero) = 0 Then
Dim iid As Guid = GetType(IBaseFilter).GUID
moniker(0).BindToObject(Nothing, Nothing, iid, source)
Else
Throw New ApplicationException("Unable to access video capture device!")
End If
Marshal.ReleaseComObject(moniker(0))
Marshal.ReleaseComObject(classEnum)
Return CType(source, IBaseFilter)
End Function
Public Sub SetupVideoWindow()
Dim hr As Integer = 0
'set the video window to be a child of the main window
'putowner : Sets the owning parent window for the video playback window.
hr = VideoWindow.put_Owner(PictureBox1.Handle)
hr = VideoWindow.put_WindowStyle(WindowStyle.Child Or WindowStyle.ClipChildren)
'Use helper function to position video window in client rect of main application window
ResizeVideoWindow()
'Make the video window visible, now that it is properly positioned
'put_visible : This method changes the visibility of the video window.
hr = VideoWindow.put_Visible(OABool.True)
End Sub
Public Sub ResizeVideoWindow()
'Resize the video preview window to match owner window size
'left , top , width , height
If Not (VideoWindow Is Nothing) Then 'if the videopreview is not nothing
VideoWindow.SetWindowPosition(0, 0, Me.Width, Me.ClientSize.Height)
End If
End Sub
Public Sub closeinterfaces()
'//stop previewing data
If Not (Me.MediaControl Is Nothing) Then
Me.MediaControl.StopWhenReady()
End If
Me.CurrentState = PlayState.Stopped
'//stop recieving events
If Not (Me.MediaEventEx Is Nothing) Then
Me.MediaEventEx.SetNotifyWindow(IntPtr.Zero, WM_GRAPHNOTIFY, IntPtr.Zero)
End If
'// Relinquish ownership (IMPORTANT!) of the video window.
'// Failing to call put_Owner can lead to assert failures within
'// the video renderer, as it still assumes that it has a valid
'// parent window.
If Not (Me.VideoWindow Is Nothing) Then
Me.VideoWindow.put_Visible(OABool.False)
Me.VideoWindow.put_Owner(IntPtr.Zero)
End If
' // Remove filter graph from the running object table
If Not (rot Is Nothing) Then
rot.Dispose()
rot = Nothing
End If
'// Release DirectShow interfaces
Marshal.ReleaseComObject(Me.MediaControl) : Me.MediaControl = Nothing
Marshal.ReleaseComObject(Me.MediaEventEx) : Me.MediaEventEx = Nothing
Marshal.ReleaseComObject(Me.VideoWindow) : Me.VideoWindow = Nothing
Marshal.ReleaseComObject(Me.GraphBuilder) : Me.GraphBuilder = Nothing
Marshal.ReleaseComObject(Me.CaptureGraphBuilder) : Me.CaptureGraphBuilder = Nothing
End Sub
-
Dec 27th, 2012, 06:24 AM
#4
Re: 2 web cameras and .net
Just in case you want to try a different approach, I can recommend the Aforge.Net library - http://www.aforgenet.com/aforge/framework/
I too gave up on avicap32.dll because I wanted better support for multiple webcams.
-
Dec 28th, 2012, 01:46 AM
#5
Thread Starter
Fanatic Member
Re: 2 web cameras and .net
thanx paulg4ije, worked like a charm and effortlessly. THANKYOU EVERYONE
-
Dec 8th, 2015, 04:44 PM
#6
New Member
Re: 2 web cameras and .net
Hello,
Could one of you send me a sample VB.Net code showing how to use the AForge.Net lib to select an imaging device as a source for capture ?
Bensonsearch, how did you do exactly ?
Thanks.
-
Dec 8th, 2015, 05:20 PM
#7
Re: 2 web cameras and .net
This is some of my code:
Code:
Imports AForge.Video
Imports AForge.Video.DirectShow
Module modCameras
Public videoDevices As FilterInfoCollection
'Private cam As VideoCaptureDevice
Sub Get_Camera_List(cmb As ComboBox)
' Get list of available video capture devices (webcams) using AForge library
Try
videoDevices = New FilterInfoCollection(FilterCategory.VideoInputDevice)
Dim iCamCount As Integer = videoDevices.Count
If iCamCount > 0 Then
For i As Integer = 0 To iCamCount - 1
cmb.items.add(videoDevices(i).Name)
Next
End If
Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.Information)
End Try
End Sub
End Module
Code:
Private Sub cmbCams_SelectedIndexChanged(sender As System.Object, e As System.EventArgs) Handles cmbCams.SelectedIndexChanged
GsCamName = cmbCams.SelectedItem.ToString
GiCamID = cmbCams.SelectedIndex
End Sub
Private Sub Camera_On()
Try
Dim videoSource As VideoCaptureDevice = New VideoCaptureDevice(videoDevices(GiCamID).MonikerString)
vsp1.VideoSource = videoSource
videoSource.DesiredFrameRate = 10
videoSource.DesiredFrameSize = New Size(640, 480)
vsp1.Start()
cmdGrab.Enabled = True
vsp1.Visible = True
bCameraOn = True
Catch ex As Exception
MsgBox("Failed to connect to chosen webcam.", MsgBoxStyle.Information)
Call Camera_Off()
End Try
End Sub
Private Sub Camera_Off()
Try
chkPreview.Checked = False
cmdGrab.Enabled = False
vsp1.SignalToStop()
vsp1.WaitForStop()
vsp1.Visible = False
bCameraOn = False
Catch
End Try
End Sub
Private Sub cmdGrab_Click(sender As System.Object, e As System.EventArgs) Handles cmdGrab.Click
Call Grab_Image()
End Sub
Private Sub Grab_Image()
If fnGrab_Image() Then
vsp1.Visible = False
vsp1.SignalToStop()
chkPreview.Checked = False
End If
End Sub
You need an Aforge Video Source Player on your form (vsp1 in my code).
Hopefully you can adapt this code to suit your requirements.
-
Dec 9th, 2015, 02:55 AM
#8
Re: 2 web cameras and .net
Forgot this bit:
Code:
Private Function fnGrab_Image() As Boolean
' Grab an image from webcam - Aforge Video Source Player must be running
Try
Dim bm As Bitmap = New Bitmap(640, 480)
bm = vsp1.GetCurrentVideoFrame
If bm.Width <> 640 Or bm.Height <> 480 Then
bm = New Bitmap(bm, New Size(640, 480))
End If
Dim bm2 As Bitmap = New Bitmap(640, 512)
Dim g As Graphics = Graphics.FromImage(bm2)
g.DrawImage(bm, 0, 32)
g.Dispose()
pbTX.Image = fnAdd_Header(bm2, "Greyscale") ' Add 16 line greyscale header
Gbm = CType(bm2.Clone, Bitmap)
If chkStamp.Checked Then pbTX.Image = fnAdd_Date_Time_Stamp(CType(pbTX.Image, Bitmap))
If chkLive.Checked Then pbTX.Image = fnAdd_Live_Webcam_Stamp(CType(pbTX.Image, Bitmap))
If chkCallsign.Checked Then pbTX.Image = fnAdd_Callsign(CType(pbTX.Image, Bitmap))
Return True
Catch
MsgBox("Aforge Video Source Player (webcam) not ready.")
Return False
End Try
End Function
Ignore the "stamps" and "header" - you should be able to adapt this code to do what you want.
Paul.
-
Dec 9th, 2015, 03:25 PM
#9
New Member
Re: 2 web cameras and .net
Thank you, Paul.
It's so simple compared to what it could have been with avicap.
popeau
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|