Click here to Skip to main content
Click here to Skip to main content

Webcam using DirectShow.NET

By , 26 Apr 2007
 

Screenshot - image003.jpg

Introduction

This article describes how to use DirectShow.NET. DirectShow.NET is a dll to use DirectShow as managed code. I found it hard to find examples for using DirectShow. I still didn't find out how that all works. That is why I translated a C# example of DirectShow.NET to VB.NET code. Here, I show you what the code finally looks like. You all could still help me (and others) to provide a better understanding of what the code means. In the help below, you will only find stuff that I thought was difficult for me to understand. The rest is explained in the code itself.

Background

DirectShow will be dumped for the Windows Presentation Foundation. In the meanwhile, I recommend the book "Programming Microsoft DirectShow for Digital Video and Television", ISBN: 0-7356-1821-6. I also recommend googling for DirectShow.NET and reading their website which is really good.

You have to understand the basics of DirectShow.

Using the code

Please do these things first:

  • Add a reference to DirectShowLib-2005.dll to the project (sometimes it cannot find it).
  • Turn off Enable Application Framework, and choose Directshow.Samples.Form1 as the startup object.
  • Be sure to have NET 2.0 installed.


You should download the code before reading this article.

Step 1

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

Nothing special here. "imports" , does what it says , imports "namespaces" , mostly it is used to not have to type so much.

If you import system.diagnostics , you don't have to type system.diagnostics.blabla everytime.

Step 2

Namespace Capture_The_Webcam Public Class Form1
Inherits System.Windows.Forms.Form
               End Class
End Namespace

Now we create our own namespace (maybe we want to import our VB in a different project or something later.

Inside we create our program in public class Form 1. Public means that outside this namespace , this class is still reachable. Inherits means something like in MSDN : causes the current class or interface to inherit the attributes, variables, properties, procedures, and events from another class or set of interfaces. So, go and let this class feel like system.windows.forms.form.

Step 3

Inside the class, there are four parts:

  1. Setting variables / objects to use in this class
  2. Our main program loop
  3. The main functions / routines we use
  4. Helper functions

Step 4A: Setting variables

Enum PlayState

     Stopped = 0
     Paused = 1
     Running = 2
     Init = 3
End Enum
Dim currentState As PlayState = PlayState.Stopped 

So what does this do ? Let's give a example :

If Me.CurrentState = PlayState.Paused
Then Me.CurrentState = PlayState.Running 

This looks a lot nicer than:

If Me.CurrentState = 0 Then Me.CurrentState = 3
Dim D As Integer = Convert.ToInt32("0X8000", 16)
Public WM_GRAPHNOTIFY As Integer = D + 1

What I think happens here is that we want to let WM_GRAPHNOTIFY create a ordinary windows message holder in the format of a string. And that it has to start in place 0X8000, because that place is where the filtergraph events start. Filtergraph events are events that DirectShow gives you when you use inputs, filters and outputs.

Dim videoWindow As IVideoWindow = Nothing

What you do here is create an object with the format of a videowindow that starts out empty (with nothing in it). Generally, this is a video renderer that draws the video onto a window on the display.

Dim mediaControl As IMediaControl = Nothing

This creates an empty object/interface that function likes tape-deck buttons. The filter graph exposes the IMediaControl interface to allow applications to control the streaming of media through the filters in the graph. The interface provides methods for running, pausing, and stopping the streaming of data.

Dim mediaEventEx As IMediaEventEx = Nothing

This creates a empty object for event messages.

"This interface derives from IMediaEvent and adds a method that allows registration of a window to receive messages when events occur. This interface is used by applications to receive notification that an event has occurred. Applications can then avoid using a separate thread that waits until an event is set."

This means that you can receive events without the rest of your program stopping to wait for a new message..

Dim graphBuilder As IGraphBuilder = Nothing

This is our main object that will create filters. It will put the input filter (webcam), through a conversion filter, so that it can show it on a Ivideowindow.This interface provides methods that enable an application to build a filter graph. The Filter Graph Manager implements this interface.

Dim captureGraphBuilder As ICaptureGraphBuilder2 = Nothing

This is a object that we create to help us out with building stuff that has to do with capturing of video and/or audio. (That's called a helper object)

Dim rot As DsROTEntry = Nothing

This makes a helper object for the program "graphedit" . When you start up "graphedit" you can make a connection with your program!

What you can do to see this is the following:

  1. Debug the program.
  2. Start graphedit.exe and go to File->Connect to remote graph.

What would happen is that graphedit makes a graphical representation of how it creates your filters to show "the webcam capture device" to the "render video window".

Step 4B: Our main program loop

This is a short one:

<STAThread()> Shared Sub <place w:st="on">Main</place>()
   Application.Run(New Form1)
End Sub

What STAThread does is protect our program against using objects at the same time in our program. That's rather handy , because streaming can be rather more complicated if you can't think about this step by step. Think about what could happen between the window and the capture preview if they both live their own life. Then moving the main window could leave your capture preview behind because the capture preview is still busy with its own "message solving".

Sub main is the main/head sub-routine that will start when we write code..

Shared Sub Main means that if our class is used multiple times in a new program/object, we still only use one Sub Main that will be shared by all. There are no extra copies of the sub main in memory for each instance, there is only one.

Application.Run() starts an application , a "New Form1" .. (Form1 is our class code, see paragraph 2)…

Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) 
                                Handles Me.Load
   InitializeComponent()
   CaptureVideo()
End Sub

When we do application.run, it automatically tries to find the "load" sub routine , and starts it (handles me.load is pointing in this direction).

Private Sub means that this sub routine is not publicly available outside this class.

InitializeComponent() and CaptureVideo are routines that do what they say..

Step 4C: Functions/Routines we use

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

This Sub Routine is also private to this class (private sub).

First we create an object called resources that will have the feel of a resourceManager. This use of the resourceManager gives access to the resource management of the form.
Next interesting line is the Debug.Writeline. It writes a line of text to your debug output. If you don't know where that is , go to the Visual Basic menu, go to debug, and select output. When you test run your program, you will see these messages appearing in this output window.

Public Sub CaptureVideo()
    Dim sourceFilter As IBaseFilter = Nothing
    Try
      Big chunk of code
    Catch ex As Exception
        MessageBox.Show("An unrecoverable error has occurred.With error : " &
                                ex.ToString)
    End Try
End Sub

Dim hr As Integer = 0

A try / catch thing is really handy.

We will try to implement the code "you write" , but when there is an "exception error", we will show a "messageBox" which will translate the exception code (ex) to normal readable text.
A exception error could be all kinds of errors we create. When an error occurs, either the system or the currently executing application reports it by throwing an exception containing information about the error. "hr" is a placeholder for (mainly error) messages. It will keep them as numbers. So you have to use a error number translator. I have shown how to do this later in the code.

Next we create an object that works like a "DirectShow filter object" . These objects have a input-pin and output-pin, and do filtering in between. DirectShow graphs are (in the most simplest way) a chain of filter-objects , each doing their own type of conversion or filtering. So all in all a "chain of filters" always has a source and a target. Now we use this filter object creation to create the source (our webcam). Filter objects do more, but I won't tell you now to keep it simple. So, what is in the "Big chunk of code" ? Let's check it out.

GetInterfaces()

This means we will start a subroutine to create the building blocks of our interface. Here is what "getinterfaces()" says : "hr" is for keeping the error code. "Me" is used to point out that we are talking about our own created objects , not stuff made by something else.
CTYPE is a function to convert a object type to another object type.

Me.graphBuilder = CType(New FilterGraph, IGraphBuilder) 

Lets fill the "graphBuilder"-object with a new FilterGraph object, (a type of "Igraphbuilder").The FilterGraph is our chain of filters that we will build.

Me.captureGraphBuilder = CType(New CaptureGraphBuilder2, ICaptureGraphBuilder2

Let's fill the "CaptureGraphBuilder" object with a CaptureGraphBuilder2 object(a type of "ICaptureGraphBuilder2").We use this to help us build the FilterGraph (helper-object).

Me.mediaControl = CType(Me.graphBuilder, IMediaControl)

Let's fill the "mediaControl" object with a mediaControl object, and we use the just created "graphBuilder" object for this to decide how this mediaControl type looks/feels like.

Me.videoWindow = CType(Me.graphBuilder, IVideoWindow)

Let's fill the "videoWindow" object with a videoWindow object , using our graphBuilder object .

Me.mediaEventEx = CType(Me.graphBuilder, IMediaEventEx)

Let's fill the "mediaEventeX" (message) object with messaging capabilities , using our graphBuilder object .

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. Variable "hr" gets a number back for this.
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))

I already explained what this does before.

Now that getinterfaces() has been completed, let us go back to our try-code. Remember that when there is an error , the "dserror" code will throw an exception that directly starts up the catch code to tell us we had a error.

hr = Me.CaptureGraphBuilder.SetFiltergraph(Me.GraphBuilder)
Debug.WriteLine("Attach the filter graph to the capture graph : " &
                    DsError.GetErrorText(hr))
DsError.ThrowExceptionForHR(hr)

We use the "CaptureGraphBuilder" (helper) object to "set up" the "GraphBuilder" – Filtergraph. When there is an error we throw a exception.

sourceFilter = FindCaptureDevice()

What this code does is to use the system device enumerator and class enumerator to find a video capture/preview device, such as a desktop USB video camera. Let's look at the function "FindCaptureDevice()" code:

Debug.WriteLine("Start   the Sub FindCaptureDevice")
Dim hr As Integer = 0

Easy to understand by now.

Dim classEnum As IEnumMoniker = Nothing
Dim moniker As IMoniker() = New IMoniker(0) {}

This is what I think it means :

  • A moniker creates a object that connects a Global Unique Identifier (GUID) to a name.
  • A sermonizer creates a "enumeration" object that makes it easy to use objects that have a name and id number.
  • Enumerations provide a convenient way to work with sets of related constants and to associate constant values with names. For example, you can declare an enumeration for a set of integer constants associated with the days of the week, and then use the names of the days rather than their integer values in your code. Enumerations most often count objects in the most abstract way possible. An enumerator is an object that iterates through its associated collection. It can be thought of as a movable pointer to any element in the collection.
Dim source As Object = Nothing

Create a empty object called "source".

Dim devEnum As ICreateDevEnum = CType(New CreateDevEnum, ICreateDevEnum)

The ICreateDevEnum interface creates an enumerator for a category of filters, such as video capture devices or audio capture devices. It puts them in devEnum.

hr = devEnum.CreateClassEnumerator(FilterCategory.VideoInputDevice, classEnum,
0) Debug.WriteLine("Create an enumerator for the video capture devices : " & 
                            DsError.GetErrorText(hr))
DsError.ThrowExceptionForHR(hr)

Create an enumeration for the video capture devices .The CreateClassEnumerator method creates an enumerator for a specified device category meaning that we are going to fill classEnum with VideoInputDevices. The zero at the end means that we will check up every sort of filter (to find VideoInputDevices).

Marshal.ReleaseComObject(devEnum)

The device enumerator is no more needed so we dump it. Marshal provides a collection of methods for allocating unmanaged memory, copying unmanaged memory blocks, and converting managed to unmanaged types, as well as other miscellaneous methods used when interacting with unmanaged code.

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

I think it is clear to understand that when a enumeration goes well , it doesn't mean we have a device in the enumeration list. So, let's check if we have one, otherwise we don't have a webcam.

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

Let's go to the first line. An "if then else" function is easy to understand. Imonkier.next(a,b,c) retrieves a specified number of items in the enumeration sequence.

  • a = number of elements requested
  • b = the array of elements requested will be given back to b
  • c = if c is null, we want only one element back , if c is some other integer we want that total amount back in b.

So Classenum.next let moniker fill with only one element of classenum (that will be the first videoinputdevice). And if this classenum gives back a value 0 , then…
By the way if it returns 0 (S_OK) it means that there is a moniker. If it returns 1 (S_False) it means that there is no moniker.

So if there is a videocapturedevice then :

Dim iid As Guid = GetType(IBaseFilter).GUID

Let "iid" be a global unique identifier , based on IbaseFilter.

moniker(0).BindToObject(Nothing, Nothing, iid, source)

Use the reference to the capturedevice as the source, and give it a global unique identifier.

Marshal.ReleaseComObject(moniker(0))
Marshal.ReleaseComObject(classEnum)  

Dump the objects…

Return CType(source, IBaseFilter)

Return "Source" to the asker who started this "FindCaptureDevice" function, but let it feel like a IbaseFilter.

Ok, so everything went fine in finding a capture device, and now that we have a source-filter inside "Sourcefilter", we go back to the CaptureVideo() code.

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

This means that we add the sourcefilter (the videocapturedevice) to our filtergraph by letting the filtergraph know it's a "Video Capture" filter

'Render the preview pin on the video capture filter use this instead of 
'me.graphBuilder.RenderFile
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)

This means that we use the helper object "CaptureGraphBuilder" to finish the rest of our filtergraph. We let it build the rest of our filtergraph for us.
There are five variables as you see.

  • var 1 = here we choose in what mode the graph will be, now we let it render in preview mode (instead of a capture-mode)
  • var 2 = we choose what kind of media type the result will be in
  • var 3 = the starting filter we will use
  • var 4 = points to a compression filter to use , we don't use none, so we give nothing
  • var 5 = points to a target to use, we don't give one, so it will revert to default render target (a window)
Marshal.ReleaseComObject(sourceFilter)

The "sourceFilter" has been added to the filtergraph and has been used to build the rest of the filtergraph automatically , so we release the reference to the "sourcefilter".

SetupVideoWindow()

Let's check that sub routine out….

Public Sub SetupVideoWindow()
    Dim hr As Integer = 0
    hr = Me.VideoWindow.put_Owner(Me.Handle)
    DsError.ThrowExceptionForHR(hr)
    hr = Me.VideoWindow.put_WindowStyle(
        WindowStyle.Child Or WindowStyle.ClipChildren)
    DsError.ThrowExceptionForHR(hr)
    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
  • Put_Owner : Sets the owning parent window for the video playback window.
  • Meaning : set the video window to be a child of the main window.
  • Put_WindowStyle : Set the style of the window to be a child of the form , and clip over any children of the form.
  • ResizeVideoWindow : we check that out later.
  • Put_Visible : make the directShow window visible or not (using a Boolean true or not).

Lets go back to the "CaptureVideo()" code..

rot = New DsROTEntry(Me.GraphBuilder)

This will add our graph to the running object table, which will allow the GraphEdit application to "spy" on our graph.

Or said differently , we fill our helper object Rot with the our filtergraph, so the external GraphEdit application can read it.

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

Start previewing video data! We use the "mediacontrol" helper object to start our filtergraph.

Me.CurrentState = PlayState.Running
Debug.WriteLine("The   currentstate : " & Me.CurrentState.ToString)  
Now we tell our program that because we are previewing video data , the "currentstate" is "playstaterunning.

Step 4D: Helper Functions

Lets start out with:

Public Sub ResizeVideoWindow()
    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

If the videowindow is not nothing, then resize the videopreviewwindow to match owner window size: left, top, width, height.

But what to do when the form resizes ?

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

If the form resizes, there will be different situations. For us, it is interesting what to do when the form is minimized or normal. Because the state of the directshow preview could better change in those situations. That's why we start out a function called ChangePreviewState(). The code of ResizeVideoWindow is already explained above.

I will not explain ChangePreviewState() because it is really simple.

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

The "protected overloads sub" means that we also want to have control over something. That something is WndProc, the message interface so that we can see messages that we need to know for our program.
It is used byRef because we make a reference to that message.
In case the message is a WM_Graphnotify one, we will handle this.

WM_Graphnotify was the holder of directshow messages. But if it is not the case, we want to restore the message and sent it back to where it belongs. That's what the rest means.

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

If Me.MediaEventEx Is Nothing Then
Return

End If

First we check if MediaEventEx message queue has something to say, otherwise it is no use to start the rest:

While Me.MediaEventEx.GetEvent(evCode, evParam1, evParam2, 0) = 0
End While

Otherwise we use a while loop. As long as the while loop condition is still true we do another loop. The .GetEvent method retrieves the next event notification from the event queue from MediaEventEx. It fills efCode, EvParam2 and evParam2 with info about that. The 0 means that we wait infinitely for that message.

As said before , if the result is 0 (meaning S_OK), there is a message. So as long there are messages in the queue, execute this while loop.

hr = Me.MediaEventEx.FreeEventParams(evCode, evParam1, evParam2) 
DsError.ThrowExceptionForHR(hr)

We fill "hr" with this message and directly clean this message in the queue.
If Hr gives a bad value, we will give a exception.

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

Like the routine above , we also want to have some control in ending our program, because we use references in memory that cannot be killed automatically by itself. You could keep crap in memory. Like for me, if I don't stop the program correctly (pressing stop using the debugger stop button), I cannot use the webcam the second time.

So if disposing is true, then start the subroutine closeinterfaces(), after this , do closing stuff that is normally done by the program itself.

   Public Sub closeinterfaces()

Also closeinterfaces() is now is easy to understand.

So that's it. Hope you liked this stuff. If you see errors or have any questions/hints/corrections, please post them here.

Points of Interest

If I stop the program using the debugger instead of closing the form itself, the filtergraph doesn't close properly and the webcam does not become useable anymore.

History

  • This code is in version 1.0.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)

About the Author

Jarno Burger

Netherlands Netherlands
Jarno Burger
i am videojockey for festivals.
i am getting fed up with the vj programs at the moment , so i am trying to go and write my own one.
 
if you wanna read some more stuff about directshow.net , then you can read some chunks of info on my blog , with some extra handy links to more articles and forums.
 
http://jarnoburger.blogspot.com/

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Questioncapture image from webcam and show in Picture BoxmemberPriyanka Jain7-May-13 23:25 
hello sir,
Thanks for your code.its working properly.but i want to capture image from webcam and show in picture box.how to do this.please give me solution..
thanks in advance..
Priyanka Jain

QuestionresolutionmemberMember 98816444-Mar-13 1:12 
hello,
 
i am wondering if you know how to change the resolution in vb.net. ik used this code to view the camera feed and i built it out so i can save a picture. the only problem is that i don't know how to change the resolution.
 
thanks in advance,
 
Jasper de Vries
QuestionHow to detect webcam plug / unplug ?membergxdata27-Aug-12 16:39 
I would like a simple and elegant way to detect if the sample application starts with the USB webcam not plugged in, and also the situation where it is removed and re-inserted (this can happen!).
 
Does someone have suggestions for this? All my solutions have been very clunky.
AnswerRe: How to detect webcam plug / unplug ?memberJarno Burger25-Feb-13 0:51 
I also would like that.. Did you find a answer yet ?
Jarno Burger
Video Jockey

QuestionWon't Compile with Option Strict Onmember_Matt_Wilkinson_3-May-12 4:43 
Thanks for this it is very useful but the sample won't compile with option strict on. This line fails:
hr = devEnum.CreateClassEnumerator(FilterCategory.VideoInputDevice, classEnum, 0)
 
with the error:
Option Strict On disallows implicit conversions from System.Runtime.InteropServices.ComTypes.IEnumMoniker to System.Runtime.InteropServices.UCOMIEnumMoniker
 
Any ideas how I can solve this?
AnswerRe: Won't Compile with Option Strict OnmemberJarno Burger25-Feb-13 0:52 
Hmmz.. Its a long time ago that i checked this project out.. I am into c# in the last 4 years.. I can look at that again.. Maybe tonight i'll do that.
Jarno Burger
Video Jockey

QuestionSAVING VIDEOmemberMember 82049723-Apr-12 3:34 
hello, is there any way to save the video captured?
 
Thanks a lot.
AnswerRe: SAVING VIDEOmemberJarno Burger25-Feb-13 0:53 
Yeah you could use the filewriter.
http://msdn.microsoft.com/en-us/library/windows/desktop/dd375644(v=vs.85).aspx[^]
Jarno Burger
Video Jockey

QuestionCommercial use?memberMember 44023214-Oct-11 5:42 
Hello,
may we use this code for a shareware application? It's free to download but costs money for better service.
AnswerRe: Commercial use?memberJarno Burger25-Feb-13 0:53 
Cool ! Yeah go ahead, and show me your result !
Jarno Burger
Video Jockey

QuestionHow to select multiple image sourcesmembersettorezero18-Apr-11 0:39 
On my computer I've a webcam ad an USB capture device (the Syntek EasyCap). If Easycap is attached, video starts from this device (but doesn't operate well 'cause I cannot select acquisition source from EasyCap that have 3 inputs). If EasyCap isn't attached, video starts from webcam. How can I solve those problems?
AnswerRe: How to select multiple image sourcesmemberJarno Burger25-Feb-13 0:54 
Maybe you need that crossfilter thingie in between..
http://msdn.microsoft.com/en-us/library/windows/desktop/dd390991(v=vs.85).aspx[^]
Jarno Burger
Video Jockey

GeneralGrab Image while viewingmemberCreamboy4-Apr-11 3:29 
Hey Jarno,
Nice article. But how do you capture an image, or is this just to open a camera?
He who goes for revenge must first dig two graves.

GeneralRe: Grab Image while viewingmemberJarno Burger25-Feb-13 0:56 
create a class that implements http://msdn.microsoft.com/en-us/library/windows/desktop/dd376985(v=vs.85).aspx[^] and hook it up.
Jarno Burger
Video Jockey

QuestionUnable to connect filtersmemberSaquib Kamran6-Dec-10 1:27 
Thanks in advance
 
I am developing an application that will display channels using a TV card
 
I have developed a graph for it using Graph edit. It works fine for me.
 
When i am coding on that graph exception occurs when i try to connect DEMUX video pin to Decoder Input pin.
 
"Value does not fall within the expected range".
 

IPin demuxpinv = GetPin(mpeg2Demux, "Video");
IPin decoderpin = GetPin(pMPEG2VideoDecoderHD, "MPEG In");
 

AMMediaType mediacon = new AMMediaType();
mediacon.majorType = MediaType.Video;
mediacon.subType = MediaSubType.Mpeg2Video;
mediacon.formatType = FormatType.Mpeg2Video;
 
hr = m_FilterGraph.ConnectDirect(demuxpinv,decoderpin , mediacon);
Marshal.ThrowExceptionForHR(hr);
 

Waiting for your response....
AnswerRe: Unable to connect filtersmemberJarno Burger25-Feb-13 0:59 
you can try to use the dsrotentry trick.
it 'opens up' your filtergraph, making it possible to view its current state in graphedit.
http://msdn.microsoft.com/en-us/library/dd390650(VS.85).aspx[^]
then you can see what is going wrong.
 
what i always do , is to go line by line trough the debug process, while refreshing graphedit.
you see every filter popup like you are a magician. and you understand visually what happening.
Jarno Burger
Video Jockey

GeneralTrigger Change in Image [modified]membercds toecutter11-Sep-10 18:25 
Hi,
 
Excellent work, i got it to work with a IR Camera and Reviver Kit i purchased from Jaycar.
 
Is it possible to catch a event when the image changes?
 
In other words, since i am using it to monitor entry to my courtyard, i would like to be able to capture a event when there is movement, eg if someone was to walk into the view of the camera the forms image would change thus trigger a event in the code.
 
I placed a break point at the beginning of every sub/routing but nothing was caught by the break point.
 
regards
toe
 
ps, i will also need to rotate the image as my camera doesn't have a option to rotate Cool | :cool:

modified on Sunday, September 12, 2010 12:47 AM

GeneralRe: Trigger Change in ImagememberJarno Burger13-Oct-10 22:21 
I think you have to compare pictures.
And i think you have to implement a custom sample grabber.
Jarno Burger
Video Jockey

GeneralMultiple formsmemberhellbundy19-Aug-10 3:06 
Hi, thanks for the code, it works great.
My application contains multiple forms and startup form is different.
Is it possible to change startup form ?
Thanks.
Generalvideo resolutionsmemberjvstewart3-Aug-10 13:09 
Hi
 
I am trying to get a list of video resolutions for my web cam with VB.
 
I have the following code. pconfig is being set properly earlier in the code as far as I know.
it is bombing out on GetStreamCaps
 

Dim i As Integer
Dim hr As Integer
Dim vmType As AMMediaType = Nothing
Dim vmCaps As Byte = Nothing
 

For i = 0 To resolutions - 1
Try
hr = pconfig.GetStreamCaps(i, vmType, vmCaps)
 
Catch
'handle the error
End Try
 
'add the resolution to a list
 
Next
 

Any help would be great.
 
Thanks
 
John
GeneralRe: video resolutionsmemberJarno Burger25-Feb-13 1:02 
i need to see more before i can help you correctly
Jarno Burger
Video Jockey

QuestionCapture for frame processingmemberJ_UAV18-Feb-10 7:49 
by editing this line:
 
hr = Me.CaptureGraphBuilder.RenderStream(PinCategory.Preview, MediaType.Video, ...
 
Can we extract the frames as bitmaps for further processing?
AnswerRe: Capture for frame processingmemberJarno Burger25-Feb-13 1:03 
you need a implementation of http://msdn.microsoft.com/en-us/library/windows/desktop/dd376985(v=vs.85).aspx[^]
Jarno Burger
Video Jockey

GeneralVideo format not correct, please help!memberStephen Winch15-Oct-09 13:17 
Hi,
 
This code is awesome, thanks Big Grin | :-D , but I'm having a slight problem with the video format.
I am trying to capture the video through an "AVerMedia DVD EZMaker USB Gold" usb capture card but the colour is greyscale and the picture is fuzzy Frown | :(
I am able to get a webcam working perfectly so I'm assuming that the webcam sets up the defualt settings correctly but the capture card doesn't, so is there anyway to over write this?
The capture card also works perfectly with the program that came with it (CyberLink PowerDirector).
The defult setting for the capture card seem to be "MPEG-2 HQ DVD PAL".
Any help would be awesome
 
Steve
GeneralRe: Video format not correct, please help!memberJarno Burger19-Oct-09 0:32 
i think your cap card , doenst init with good settings.
you have to set the properties manually.
just check how a filtergraph is build in graphedit.
if it works in graphedit , you can follow the same steps in your code
 
Jarno Burger
Video Jockey

GeneralRe: Video format not correct, please help!memberStephen Winch19-Oct-09 12:40 
Cheers,
 
It seems the video capture card is setting up as NTSC_M not PAL_B.
Thanks for the help, its saved me a few days Big Grin | :-D
Now I just need to figure out a way to change the format from NTSC to PAL, I'm looking at: DirectShow.NET[^]
at the moment trying to see how the SampleGrabberNET sets up the TVTuner to see if I could adapt that.
If anyone has any other suggestions that would be awesome, I've attached the code if you want to look, but basically I copied Webcam using DirectShow.NET[^]
Big Grin | :-D
private void CaptureVideo()
 
{
            int hr = 0;
 
            try
            {
                GetInterfaces();
 
                hr = this.captureGraphBuilder.SetFiltergraph(this.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 = this.graphBuilder.AddFilter(sourceFilter, "Video Capture");
                Debug.WriteLine("Add capture filter to our graph : " + DsError.GetErrorText(hr));
                DsError.ThrowExceptionForHR(hr);
                              
                Guid VideoType = MediaType.Video;
                                     
                hr = this.captureGraphBuilder.RenderStream(PinCategory.Preview, VideoType, sourceFilter, null, null);
                Debug.WriteLine("Render the preview pin on the video capture filter : " + DsError.GetErrorText(hr));
                DsError.ThrowExceptionForHR(hr);
 
                IFileSinkFilter mux = null;
                IBaseFilter bas = null;
                hr = this.captureGraphBuilder.SetOutputFileName(Media, filename, out bas, out mux);
                if (hr < 0)
                {
                    Marshal.ThrowExceptionForHR(hr);
                }
                hr = this.captureGraphBuilder.RenderStream(PinCategory.Capture, VideoType, sourceFilter, null , bas);
                if (hr < 0)
                {
                    Marshal.ThrowExceptionForHR(hr);
                }
 
                Marshal.ReleaseComObject(sourceFilter);
 
                SetupVideoWindowdow();
                object Filters;
                rot = new DsROTEntry(this.graphBuilder);
                this.mediaControl.get_FilterCollection(out Filters);               
                hr = this.mediaControl.Run();
                
                Debug.WriteLine("Start previewing video data : " + DsError.GetErrorText(hr));
                DsError.ThrowExceptionForHR(hr);
 
                this.currentState = PlayState.Running;
                Debug.WriteLine("The currentstate : " + this.currentState.ToString());
 
            }
            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show("An unrecoverable error has occurred.With error : " + ex.ToString());
            }
        }
 
        private void GetInterfaces()
        {
            int hr = 0;
            this.graphBuilder = (IGraphBuilder)new FilterGraph();
            this.captureGraphBuilder = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();
            this.mediaControl = (IMediaControl)this.graphBuilder;
            this.VideoWindowdow = (IVideoWindow)this.graphBuilder;
            this.mediaEventEx = (IMediaEventEx)this.graphBuilder;
          
            hr = this.mediaEventEx.SetNotifyWindow(this.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));
        }
 
        public IBaseFilter FindCaptureDevice()
        {
            DsDevice dev=null;
            int arraysize=0;
            Debug.WriteLine("Start the Sub FindCaptureDevice");
            IMoniker[] moniker = new IMoniker[1];
            Object source = null;
            ICreateDevEnum devEnum = (ICreateDevEnum)new CreateDevEnum();
 
            ArrayList capDevices = new ArrayList();
            //int index =0;
            DsDevice[] CaptureList = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);
            foreach (DsDevice device in CaptureList)
            {
                capDevices.Add(device);
                arraysize++;
            }
            if (arraysize==1)
            {
                dev = CaptureList[0];
                
 
            }
            else if (arraysize>1)
            {
 
                DeviceSelector deviceSelect = new DeviceSelector(capDevices);
                deviceSelect.ShowDialog(this);
                dev = deviceSelect.SelectedDevice;
                //MessageBox.Show(dev.Name.ToString());
            }
            else
            {
                MessageBox.Show("No video device connected");
                CameraConnected = false;
                Application.Exit();
                //throw new ApplicationException("Unable to access video capture device!");
            } 
            if (dev != null)
            {
                moniker[0] = (IMoniker)dev.Mon;
                Guid iid = typeof(IBaseFilter).GUID;
                moniker[0].BindToObject(null, null, ref iid, out source);
            }
 
            Marshal.ReleaseComObject(moniker[0]);
            //Marshal.ReleaseComObject(dev);
            Marshal.ReleaseComObject(devEnum);
            return (IBaseFilter)source;
        }

GeneralRe: Video format not correct, please help!memberJarno Burger25-Feb-13 1:05 
it could be a specific property of the capture device..
every capture device has its own driver, and that driver can have its own configurable window.
directshow will never know what is in that window..
 
so you have to choose :
- use pointers to that specific window , and use a pointer to that specific selection box.
- popup that specific window, to let the use configure that.
Jarno Burger
Video Jockey

GeneralIs directshow for Licencemembereg_Anubhava24-Aug-09 2:26 
Hello Jarno,
 
Actually i want to know that is Directshow dll can use for Development without purchasing any license.
 
If you can think then I Can.

GeneralRe: Is directshow for LicencememberThingyOtus6-Jun-10 23:06 
http://directshownet.sourceforge.net/faq.html
 
And
http://www.gnu.org/licenses/lgpl.html
 
And like in the first link the answer is "If you want legal advice concerning the LGPL, you would probably do better speaking with a lawyer than a programmer" might be the best answer.
GeneralRe: Is directshow for LicencememberJarno Burger25-Feb-13 1:06 
thnks thingyOtus for pointing that out.
Jarno Burger
Video Jockey

QuestionCode not being cleaned up properly?memberXenomech10-Aug-09 0:52 
I think there's a problem with the interface cleanup at the end of the program. Here's what I did to discover the problem: I created a second form in your project and made it the new startup form. On this new form I added a button which creates an instance of your form and shows it. This works fine the first time I press the button, but after dismissing your form and recreating it a second time, the SetupGraph methods errors out on the call to capGraph.RenderStream, with an error code of -2147024809 and I get the message "value does not fall within the expected range".
 
Any ideas what might be happening here?
AnswerRe: Code not being cleaned up properly?memberXenomech28-Aug-09 2:37 
It turns out I only get this error with certain webcams. I have two different Logitech webcames: one works repeated with the example described above, while the other throws the aforementioned exception when you try to run SetupGraph a second time.
QuestionRe: Code not being cleaned up properly?memberLCCVR8-Dec-10 11:06 
Have you found any workaround for this issue?
 
I'm having the same problem here.
AnswerRe: Code not being cleaned up properly?memberJarno Burger25-Feb-13 1:07 
Hmmz.. i created this in the old days, while i was still learning how to do these things.
Maybe i can check out tonight if everything gets disposed properly.
Jarno Burger
Video Jockey

GeneralCapture video from WebpagememberMember 27661043-Aug-09 6:12 
Hi,
 
it's possible to capture a video from my aspx page?
 
I have an web application, and i want to capture video of my computer from a application page, can i?
 
Best regards,
 
Marco Delgado
GeneralRe: Capture video from WebpagememberJarno Burger7-Aug-09 2:03 
err i dont know
 
Jarno Burger
Video Jockey

QuestionCode in C#?memberatifmuzaffar12-Jul-09 9:45 
Hi,
 
Do you have same code in C#, as i am a csharp developer and for me it difficult to convert a VB project in to C#. If you can supply me with the C# code, i shall be very greatful to you.
 
Thanks,
 
Atif
AnswerRe: Code in C#?memberBrandon T. H.1-Feb-12 12:44 
Try using a VB.net to C# converter,
 
A google search like this, has some interesting results, including the Tangible language-to-language converter. It's free so you have some limitations, using only 100 lines of code at a time, so you have to convert 100 lines of code after the other, like I do.
GeneralRe: Code in C#?memberJarno Burger25-Feb-13 1:08 
The Directshow.Net sdk has some nice examples already.
Just download them Smile | :)
 
http://sourceforge.net/projects/directshownet/files/[^]
Jarno Burger
Video Jockey

Questionplease help on capturing image from cammemberdeoganesh_00714-Jun-09 13:37 
hello,
 
I was wondering if you could provide a code snippet in current project to capture image from webcam at certain time.
I saw the FilterGrap class but i was not able to find anymethod grabimage in that.
Any help in this matter would be greatly appreciated
AnswerRe: please help on capturing image from cammemberJarno Burger15-Jun-09 7:44 
i think that will make my example more complex.
try to fora , or the directshow.net libary.
 
Jarno Burger
Video Jockey

GeneralRe: please help on capturing image from cammemberdeoganesh_00715-Jun-09 9:14 
hello,
 
I got a dll which can extract image from video file
but there is only 1 problem, where the webcam is storing the video ?
could u please tell me how to save the video in file until i close the form?
I appreciate your time.
GeneralRe: please help on capturing image from cammemberJarno Burger7-Aug-09 2:03 
and also this one , i can't know..
 
Jarno Burger
Video Jockey

GeneralNo video capture devices found!memberGiridhar Honnekere10-Jun-09 4:21 
Hi,
 
I am working Hauppauge make WinTV-NEXUS hardware(this is TV satellite receiver) to receive DVB-S signal. I tried your code, but seems like some libraries missing.
 
I am just using a C# code available from CodeProject(written by NETMaster) to acquire the basic streams from hardware. When I try to run the peace of code, it throws an error "No video capture devices found!".
 
This is the how GUID is assigned to VideoInputDevice in the code.
 
public static readonly Guid VideoInputDevice = new Guid( 0x860BB310,0x5D01,0x11d0,0xBD,0x3B,0x00,0xA0,0xC9,0x11,0xCE,0x86 );
 
I am not sure why this GUID is assigned to VideoInputDevice. Can you help me to detect my hardware.
 
I have sample application provided by the hardware vendor, which runs well and I am able to see TV in my PC. So there is no problem with the driver. I found that there is no Hardware specific APIs available from vendor side and they claim the drivers are written as per the Microsoft BDA specification.
 
I got struck with identifying the hardware, can you please help me to overcome this problem?
 
Thanks in advance and appreciate your time.
GeneralRe: No video capture devices found!memberJarno Burger15-Jun-09 8:12 
the directshow.net libary has to be downloaded fisrt.
think you have to ask this question on the directshow.net forum..
 
Jarno Burger
Video Jockey

Questionhow to run in background and capture the video?memberkeatlck6-Jun-09 20:01 
hi, it work pretty good! Thanks!
can come out a version that run in background and won't show out the preview box?
and also can capture the video. Smile | :)
AnswerRe: how to run in background and capture the video?memberJarno Burger8-Jun-09 1:11 
ouch , you have to ask on a forum , or by a directshow book , sorry Frown | :(
 
Jarno Burger
Video Jockey

GeneralGreat boilerplate but errors on startup and no image from webcammemberToeStumper5-Apr-09 0:25 
This application seems great and is just what I am looking for to build on. Thanks!
 
One problem that I have is that I am not getting any webcam output. After RenderStream is called, I get:
 
   Render the preview pin on the video capture filter : 
      There was no preview pin available, so the capture pin 
      output is being split to provide both capture and preview.
 
And then the HRESULT from MediaControl.Run() gives:
 
Start previewing video data : Incorrect function.
 
Does this make sense?
GeneralRe: Great boilerplate but errors on startup and no image from webcammemberJarno Burger6-Apr-09 0:14 
looks like some part of the filters is not build right.
try to build a graph in graphedit , that would do the same trick.
 
Jarno Burger
Video Jockey

Questioncan u tell me about how to capture audio not to a file but memory streammemberKhurram Shakoor1-Apr-09 23:58 
can u tell me about how to capture audio not to a file but memory stream

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130617.1 | Last Updated 26 Apr 2007
Article Copyright 2007 by Jarno Burger
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid