7 Replies - 11612 Views - Last Post: 03 September 2015 - 11:46 AM Rate Topic: ***** 1 Votes

#1 Bluezap   User is offline

  • D.I.C Regular

Reputation: 1
  • View blog
  • Posts: 440
  • Joined: 19-January 12

Capture an image using DirectShow via webcam

Posted 17 June 2015 - 08:34 AM

So I'm using this project to get a webcam stream on my form. I want to capture a frame and save it now. How could I do this. Any help would be appreciated.

I want to get the stream on to a picturebox, that will make it much easier.

Imports System
Imports System.Diagnostics
Imports System.Drawing
Imports System.Runtime.InteropServices
Imports System.Windows.Forms
Imports DirectShowLib
Imports System.Runtime.InteropServices.ComTypes

Namespace Capture_The_Webcam
    Public Class Form1
        Inherits System.Windows.Forms.Form
        Enum PlayState
            Stopped
            Paused
            Running
            Init
        End Enum
        Dim CurrentState As PlayState = PlayState.Stopped

        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

        Dim rot As DsROTEntry = Nothing

        <STAThread()> Shared Sub Main()
            Application.Run(New Form1)
        End Sub
        Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            InitializeComponent()
            CaptureVideo()
        End Sub

        Private Sub InitializeComponent()
            Dim resources As System.Resources.ResourceManager = New System.Resources.ResourceManager(GetType(Form1))
            Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
            Me.ClientSize = New System.Drawing.Size(320, 320)
            Me.Icon = CType((resources.GetObject("$this.Icon")), System.Drawing.Icon)
            Me.Name = "Form1"
            Me.Text = "Video Capture Previewer (PlayCap)"
            Debug.WriteLine("I started Sub InitializeComponent")
        End Sub
        Private Sub CaptureVideo()
            Dim hr As Integer = 0
            Dim sourceFilter As IBaseFilter = Nothing
            Try
                GetInterfaces()

                hr = Me.CaptureGraphBuilder.SetFiltergraph(Me.GraphBuilder) 'Specifies filter graph "graphbuilder" for the capture graph builder "captureGraphBuilder" to use.
                Debug.WriteLine("Attach the filter graph to the capture graph : " & DsError.GetErrorText(hr))
                DsError.ThrowExceptionForHR(hr)

                sourceFilter = FindCaptureDevice()

                hr = Me.GraphBuilder.AddFilter(sourceFilter, "Video Capture")
                Debug.WriteLine("Add capture filter to our graph : " & DsError.GetErrorText(hr))
                DsError.ThrowExceptionForHR(hr)

                hr = Me.CaptureGraphBuilder.RenderStream(PinCategory.Preview, MediaType.Video, sourceFilter, Nothing, Nothing)
                Debug.WriteLine("Render the preview pin on the video capture filter : " & DsError.GetErrorText(hr))
                DsError.ThrowExceptionForHR(hr)

                Marshal.ReleaseComObject(sourceFilter)

                SetupVideoWindow()

                rot = New DsROTEntry(Me.GraphBuilder)

                hr = Me.MediaControl.Run()
                Debug.WriteLine("Start previewing video data : " & DsError.GetErrorText(hr))
                DsError.ThrowExceptionForHR(hr)

                Me.CurrentState = PlayState.Running
                Debug.WriteLine("The currentstate : " & Me.CurrentState.ToString)

            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
            Me.GraphBuilder = CType(New FilterGraph, IGraphBuilder)
            Me.CaptureGraphBuilder = CType(New CaptureGraphBuilder2, ICaptureGraphBuilder2)
            Me.MediaControl = CType(Me.GraphBuilder, IMediaControl)
            Me.VideoWindow = CType(Me.GraphBuilder, IVideoWindow)
            Me.MediaEventEx = CType(Me.GraphBuilder, IMediaEventEx)
            hr = Me.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
            DsError.ThrowExceptionForHR(hr) 'ThrowExceptionForHR is a wrapper for Marshal.ThrowExceptionForHR, but additionally provides descriptions for any DirectShow specific error messages.If the hr value is not a fatal error, no exception will be thrown:
            Debug.WriteLine("I started Sub Get interfaces , the result is : " & DsError.GetErrorText(hr))
        End Sub
        Public Function FindCaptureDevice() As IBaseFilter
            Debug.WriteLine("Start the Sub FindCaptureDevice")
            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)
            Debug.WriteLine("Create an enumerator for the video capture devices : " & DsError.GetErrorText(hr))
            DsError.ThrowExceptionForHR(hr)
            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 = Me.Videowindow.put_Owner(Me.Handle)
            DsError.ThrowExceptionForHR(hr)

            hr = Me.Videowindow.put_WindowStyle(WindowStyle.Child Or WindowStyle.ClipChildren)
            DsError.ThrowExceptionForHR(hr)

            '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 = Me.Videowindow.put_Visible(OABool.True)
            DsError.ThrowExceptionForHR(hr)
        End Sub

        Protected Overloads Sub WndProc(ByRef m As Message)
            Select Case m.Msg
                Case WM_GRAPHNOTIFY
                    HandleGraphEvent()
            End Select
            If Not (Me.VideoWindow Is Nothing) Then
                Me.Videowindow.NotifyOwnerMessage(m.HWnd, m.Msg, m.WParam.ToInt32, m.LParam.ToInt32)
            End If
            MyBase.WndProc(m)
        End Sub
        Public Sub HandleGraphEvent()
            Dim hr As Integer = 0
            Dim evCode As EventCode
            Dim evParam1 As Integer
            Dim evParam2 As Integer
            If Me.MediaEventEx Is Nothing Then
                Return
            End If
            While Me.MediaEventEx.GetEvent(evCode, evParam1, evParam2, 0) = 0
                '// Free event parameters to prevent memory leaks associated with
                '// event parameter data.  While this application is not interested
                '// in the received events, applications should always process them.
                hr = Me.MediaEventEx.FreeEventParams(evCode, evParam1, evParam2)
                DsError.ThrowExceptionForHR(hr)

                '// Insert event processing code here, if desired
            End While
        End Sub

        Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
            If disposing Then
                '// Stop capturing and release interfaces
                closeinterfaces()
            End If
            MyBase.Dispose(disposing)
        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

        Private Sub Form1_Resize1(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Resize
            If Me.WindowState = FormWindowState.Minimized Then
                ChangePreviewState(False)
            End If
            If Me.WindowState = FormWindowState.Normal Then
                ChangePreviewState(True)
            End If
            ResizeVideoWindow()
        End Sub
        Public Sub ChangePreviewState(ByVal showVideo As Boolean)
            Dim hr As Integer = 0
            '// If the media control interface isn't ready, don't call it
            If Me.MediaControl Is Nothing Then
                Debug.WriteLine("MediaControl is nothing")
                Return
            End If
            If showVideo = True Then
                If Not (Me.CurrentState = PlayState.Running) Then
                    Debug.WriteLine("Start previewing video data")
                    hr = Me.MediaControl.Run
                    Me.CurrentState = PlayState.Running
                End If
            Else
                Debug.WriteLine("Stop previewing video data")
                hr = Me.MediaControl.StopWhenReady
                Me.CurrentState = PlayState.Stopped
            End If
        End Sub
        Public Sub ResizeVideoWindow()
            'Resize the video preview window to match owner window size
            'left , top , width , height
            If Not (Me.VideoWindow Is Nothing) Then 'if the videopreview is not nothing
                Me.Videowindow.SetWindowPosition(0, 0, Me.Width, Me.ClientSize.Height)
            End If
        End Sub
    End Class
End Namespace


Project link - [url]http://www.codeproject.com/Articles/18511/Webcam-using-DirectShow-NET[/url]

Is This A Good Question/Topic? 0
  • +

Replies To: Capture an image using DirectShow via webcam

#2 Bluezap   User is offline

  • D.I.C Regular

Reputation: 1
  • View blog
  • Posts: 440
  • Joined: 19-January 12

Re: Capture an image using DirectShow via webcam

Posted 17 June 2015 - 10:07 AM

I heard you can do this with ISampleGrabberCB but I don't know how to integrate it
Was This Post Helpful? 0
  • +
  • -

#3 IronRazer   User is offline

  • Custom Control Freak
  • member icon

Reputation: 1492
  • View blog
  • Posts: 3,786
  • Joined: 01-February 13

Re: Capture an image using DirectShow via webcam

Posted 17 June 2015 - 04:28 PM

Well, i know this is not really an answer to your question of how to use your current code to capture a webcam image with DirectShow but, i have a wrapper class i wrote a few years back that you can add to your Form project that uses DirectShow to capture images from a webcam. There is also a Form example with code to show how to use the class to capture images.

It is the example that is marked as the answer. I explain how to add the class to a Form project and add a reference to the directshow dll.

How do i use attached webcams to take still image in my application

This post has been edited by IronRazer: 17 June 2015 - 04:32 PM

Was This Post Helpful? 1
  • +
  • -

#4 Bluezap   User is offline

  • D.I.C Regular

Reputation: 1
  • View blog
  • Posts: 440
  • Joined: 19-January 12

Re: Capture an image using DirectShow via webcam

Posted 17 June 2015 - 10:20 PM

IronRazerThank you so much for that, is there any way to pick any of the available cam sources without listing them in a combobox? The project I used above does that. The reason I'm using direct show is to avoid the video source dialog. I want the first available cam source to start running immediately
Was This Post Helpful? 0
  • +
  • -

#5 IronRazer   User is offline

  • Custom Control Freak
  • member icon

Reputation: 1492
  • View blog
  • Posts: 3,786
  • Joined: 01-February 13

Re: Capture an image using DirectShow via webcam

Posted 18 June 2015 - 04:23 AM

Yes you can make it connect to the first webcam that is detected instead of having to choose one. If you look at the Form example code at that link you see that the Button_Connect code uses the first parameter of the ConnectToDevice function from the DSCamCapture class to connect to the webcam device that is at the index of the chosen webcam in the combobox.

So, to set it to connect to the first webcam that is found you would use 0 (zero) instead of the ComboBox_Devices.SelectedIndex for the first parameter of the ConnectToDevice function.

Here is a real simple code example of a Form with 1 PictureBox and 2 Buttons that will use the first webcam found. One button is used to connect and disconnect the first webcam found and the second button is to save the current frame as a .jpg image.

If you do not want to use a button to connect and disconnect the webcam and want it to connect automatically when your app is started then you can move the code from the Connect button to the Form.Load or Form.Shown events. Just don`t forget to disconnect it when your app is closing. I did that in the Form.Closing event.

I tried to comment the code a little to help understand what is happening. Hope it helps. 8)

Public Class Form1
    Private WithEvents cam As New DSCamCapture 'create the new instance of the DSCamCapture class

    'this is the path to the directory that the images will be saved in. I used the My Pictures folder.
    Private MyPicturesFolder As String = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures)

    Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
        cam.Dispose() 'disconnects from the webcam when form is closing
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Button_Save.Enabled = False
    End Sub

    Private Sub Button_Connect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button_Connect.Click
        'check if the webcam is already connected before trying to connect to it
        If Not cam.IsConnected Then

            'make sure there is at least 1 webcam detected before trying to connect to the first one found
            If cam.GetCaptureDevices.Length > 0 Then
                If cam.ConnectToDevice(0, 15, PictureBox1.ClientSize, DSCamCapture.FrameSizes.s640x480, PictureBox1.Handle) Then
                    cam.Start()
                    Button_Connect.Text = "Disconnect"
                End If
            Else
                MessageBox.Show("No Capture Devices where detected.")
            End If

        Else

            'if the webcam is already connected then we want to disconnect from it
            cam.Dispose() 'disconnects from the webcam
            Button_Connect.Text = "Connect"
        End If
        Button_Save.Enabled = cam.IsConnected
    End Sub

    Private Sub Button_Save_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button_Save.Click
        'make sure the directory exists that we want to save the images in
        If Not IO.Directory.Exists(MyPicturesFolder) Then IO.Directory.CreateDirectory(MyPicturesFolder)

        'modify the current Date and Time to remove illegal characters from it so we can use it for the
        'image name.  Then combine the directory and filename into one string (SaveAs).
        Dim fName As String = Now.ToString.Replace("/", "-").Replace(":", "-").Replace(" ", "_") & ".jpg"
        Dim SaveAs As String = IO.Path.Combine(MyPicturesFolder, fName)

        'save the image using the .jpg format
        cam.SaveCurrentFrame(SaveAs, Imaging.ImageFormat.Jpeg)
    End Sub

    Private Sub PictureBox1_SizeChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles PictureBox1.SizeChanged
        'if the picturebox is resized with the Form then we need to resize the capture window too
        cam.ResizeWindow(0, 0, PictureBox1.ClientSize.Width, PictureBox1.ClientSize.Height)
    End Sub
End Class


Was This Post Helpful? 1
  • +
  • -

#6 Bluezap   User is offline

  • D.I.C Regular

Reputation: 1
  • View blog
  • Posts: 440
  • Joined: 19-January 12

Re: Capture an image using DirectShow via webcam

Posted 18 June 2015 - 07:46 AM

IronRazer Thank you so much man. This is more than I could have ever asked for. This is just amazing, I have been searching for this for months.
Was This Post Helpful? 0
  • +
  • -

#7 AresDraco   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 03-September 15

Re: Capture an image using DirectShow via webcam

Posted 03 September 2015 - 05:26 AM

View PostIronRazer, on 17 June 2015 - 04:28 PM, said:

Well, i know this is not really an answer to your question of how to use your current code to capture a webcam image with DirectShow but, i have a wrapper class i wrote a few years back that you can add to your Form project that uses DirectShow to capture images from a webcam. There is also a Form example with code to show how to use the class to capture images.

It is the example that is marked as the answer. I explain how to add the class to a Form project and add a reference to the directshow dll.

How do i use attached webcams to take still image in my application


I just wanted to Thank you for the great soul you have helping us :), it works flawlessly after been stuck for 3 days, this works with all the webcams and architectures, really ty very much buddy :)
Was This Post Helpful? 0
  • +
  • -

#8 IronRazer   User is offline

  • Custom Control Freak
  • member icon

Reputation: 1492
  • View blog
  • Posts: 3,786
  • Joined: 01-February 13

Re: Capture an image using DirectShow via webcam

Posted 03 September 2015 - 11:46 AM

@ AresDraco,
You`re Welcome. I`m glad it helped. 8)
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1