C# WebCam User Control Source


Some people have asked if they could take a look at the source for the WebCam Vista Sidebar gadget. After a little bit of cleaning up, I’m posting it now for you to take a look at. Here are some things worth mentioning:

1. Uses the DirectShow.NET library

2. I found some source in VB.NET and used that as a baseline (performed the conversion and cleaned up stuff that really wasn’t needed)

3. I am in no way a DirectX/DirectShow expert. Any questions sent my way will likely result in a blank stare back at you 🙂 (though fwiw, I do pick up things quickly and might be able to at least get you started on the correct path)

4. If you look at the source, you might think “I thought this was a Vista Sidebar Gadget. Where is the gadget source?” That’s the easy part. At the bottom of this post is a link to my .NET Gadget Creator application that I wrote (with instructions on how to use it with the WebCam control). That application will allow you to take any .NET UserControl and convert it into a Vista Sidebar Gadget. Just compile the WebCamControl2 control, and use the .NET Gadget Creator to create an instant Vista Sidebar gadget.

5. You may receive an error when you run the provided test application saying something along the lines of “invalid argument”. This is a known issue and is happens when more than one application tries to access the same camera. I haven’t looked into fixing this so if someone wants to take a stab at it, clue me in on how to fix it.

When looking through the source (there isn’t that much to it) pay attention to the 2 primary methods. The first is the GetInterfaces method which creates all the necessary DirectShow interfaces and then creates the connection between DirectShow and your UserControl window (events are passed to the control via Window messages).

The FindCaptureDevice method enumerates through your devices looking for the 1st video device it finds that provides an input (FilterCategory.InputDevice). This is done by creating a device class enumerator. Currently, the source will just grab the first device that it sees. If anyone is interested in knowing how to present the user with a list of all input devices, I can write some code to do that as well. Just let me know.

  103 UCOMIEnumMoniker classEnum = null;

  104 UCOMIMoniker[] moniker = new UCOMIMoniker[1];

  105 object source = null;

  106 

  107 ICreateDevEnum devEnum = (ICreateDevEnum)(new CreateDevEnum());

  108 int hr = devEnum.CreateClassEnumerator(FilterCategory.VideoInputDevice, out classEnum, CDef.None);

  109 DsError.ThrowExceptionForHR(hr);

  110 Marshal.ReleaseComObject(devEnum);

Once the class enumerator is created, I just grab the first one that was found (assuming one was found) and bind it to an IBaseFilter object which I then return.

  117 int none = 0;

  118 

  119 if (classEnum.Next(moniker.Length, moniker, out none) == 0)

  120 {

  121     Guid iid = typeof(IBaseFilter).GUID;

  122     moniker[0].BindToObject(null, null, ref iid, out source);

  123 }

  124 else

  125 {

  126     throw new ApplicationException(“Unable to access video capture device!”);

  127 }

  128 

  129 Marshal.ReleaseComObject(moniker[0]);

  130 Marshal.ReleaseComObject(classEnum);

  131 

  132 return (IBaseFilter)source;

Once the video input device is found and we have our base filter, we associate it with an ICaptureGraphBuilder2 object by telling it render a video stream through the preview pin of the input device(line 68 below of the CaptureVideo method).

   51 private void CaptureVideo()

   52 {

   53     int hr = 0;

   54     IBaseFilter sourceFilter = null;

   55     try

   56     {

   57         // create the necessary DirectShow interfaces

   58         GetInterfaces();

   59 

   60         hr = this.captureGraphBuilder.SetFiltergraph(this.graphBuilder);

   61         DsError.ThrowExceptionForHR(hr);

   62 

   63         sourceFilter = FindCaptureDevice();

   64 

   65         hr = this.graphBuilder.AddFilter(sourceFilter, “WebCamControl Video”);

   66         DsError.ThrowExceptionForHR(hr);

   67 

   68         hr = this.captureGraphBuilder.RenderStream(PinCategory.Preview, MediaType.Video, sourceFilter, null, null);

   69         Debug.WriteLine(DsError.GetErrorText(hr));

   70         DsError.ThrowExceptionForHR(hr);

   71 

   72         Marshal.ReleaseComObject(sourceFilter);

   73 

   74         SetupVideoWindow();

   75 

   76         hr = this.mediaControl.Run();

   77         DsError.ThrowExceptionForHR(hr);

   78 

   79         this.CurrentState = PlayState.Running;

   80     }

   81     catch (Exception ex)

   82     {

   83         MessageBox.Show(“An unrecoverable error has occurred.\r\n” + ex.ToString());

   84     }

   85 }

Now, if you want to use that control in the Vista Sidebar, just download and install the following application:

When you launch the application and click Next it will ask you to add .NET assemblies. Click the Add button, navigate to the WebCamTest or WebCamControl2 bin directory and select the WebCamControl2.dll AND the DirectShowLib.dll assemblies as shown below.

image

Click Next twice to get to the “Select UserControl to Embed”. Select the WebCamControl2.WebCamControl2 type and click Next. The next screen allows you to enter the information about the gadget. I provided an icon for you in the WebCamTest base directory. After you fill in the information, keep clicking Next and the gadget will be built for you. Go into the output directory you specified and you’ll see the .gadget file. Simply double click on this and if all goes well, you should be looking at your webcam in the Vista Sidebar. Also, since you used the .NET Gadget Creator application, your gadget will uninstall successfully even while it is running (see .NET Sidebar Gadget Creator Update #2 for more information).

Without further ado, here’s the link to the WebCamControl source code.

image

Comments (48)

  1. I got a webcam for doing conferencing at work and wanted to do some development with it. I had the problem

  2. Mark Schmidt’s Abode : C# WebCam User Control Source

  3. You’ve been kicked (a good thing) – Trackback from DotNetKicks.com

  4. Coding4Fun says:

    If you’re not sure what you need for this holiday season, look no further. After a year of coding and

  5. Cool Cat says:

    I want to process whats on the video. How would I be able to do that? I want to be able to process still images every T seconds.

  6. Cool Cat says:

    I want to process whats on the video. How would I be able to do that? I want to be able to process still images every T seconds.

  7. mansoor says:

    Hi, great article, helped me a lot, however would you mind guiding me a bit more , if i want to set video stream size (640×480) and capture just one frame(picture in the same size) ?

    ill be really glad

  8. randomguy says:

    thank you this code is very helpful

  9. Chankaman says:

    How can i play video from the composite video input of a tv card?

    I succesfully played tv using webcam component from

    http://www.codeproject.com/KB/game/

    //Some code

    VidTextureClassWebcamApp.aspx

    private void SetupGraph(DsDevice dev)

           {

               try

               {

                   int hr;

                   // 1. Start building the graph, using FilterGraph and CaptureGraphBuilder2

                   IFilterGraph2 graphBuilder = (IFilterGraph2)new FilterGraph();

                   ICaptureGraphBuilder2 builder = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();

                   hr = builder.SetFiltergraph(graphBuilder);

                   DsError.ThrowExceptionForHR(hr);

                   // 2. Add the source filter for video device input.

                   IBaseFilter sourceFilter = null;

                   hr = graphBuilder.AddSourceFilterForMoniker(dev.Mon, null, "Video Input Filter", out sourceFilter);

                   DsError.ThrowExceptionForHR(hr);

                   // 3. Get the SampleGrabber interface, configure it, and add it to the graph.

                   ISampleGrabber sampGrabber = (ISampleGrabber)new SampleGrabber();

                   ConfigureSampleGrabber(sampGrabber);

                   hr = graphBuilder.AddFilter((IBaseFilter)sampGrabber, "SampleGrabber");

                   DsError.ThrowExceptionForHR(hr);

                   // 4. Add the null renderer (since we don’t want to render in a seperate window.)

                   IBaseFilter nullRenderer = (IBaseFilter)new NullRenderer();

                   hr = graphBuilder.AddFilter(nullRenderer, "Null Renderer");

                   DsError.ThrowExceptionForHR(hr);

                   // 5. Configure the render stream.

                   hr = builder.RenderStream(PinCategory.Capture, MediaType.Video, sourceFilter, (IBaseFilter)sampGrabber, nullRenderer);

                   DsError.ThrowExceptionForHR(hr);

                   // 6. Now that everthing is configured and set up, save the width, height, stride information for use later.

                   SaveSizeInfo(sampGrabber);

                   // 7. Obtain the interfaces that we will use to control the execution of the filter graph.

                   this.mediaControl = graphBuilder as IMediaControl;

                   this.mediaEventEx = graphBuilder as IMediaEventEx;

                   this.mediaSeeking = graphBuilder as IMediaSeeking;

               }

               catch (Exception ex)

               {

                   Console.WriteLine(ex.Message);

               }

           }

  10. chankaman says:

    sorry real url is:

    http://www.codeproject.com/KB/game!VidTextureClassWebcamApp.aspx

  11. Giovanni says:

    Hi,

    >>> If anyone is interested in knowing how to present the user with a list of all input devices, I can write some code to do that as well. Just let me know.

    Yes, I’d really like it!

    can you post it please?

    thanks in advance

    Giovanni

  12. chrisstorm says:

    great example thanks you, was looking around for a while and found out it is realy hard to find something good for directshow and c# .net

    yes, would be a good thing to have a list of all devices. is it also possible to connect to ip-cams? and capture a frame on request (click a button) and save it

  13. Gary Lo says:

    I’d also like to see the code to allow the user to select the device to use 🙂

    Thanks, great post!

  14. Gary Lo says:

    I’m also trying to change the code to support capturing single frame when user clicks a button (via ISampleGrabberCB)..

    BTW, ReleaseInterfaces() is private and not used. CurrentState is private and assigned only but not used.

  15. ike_x says:

    Has anyone been able to catch frame by frame

    i tried to use DrawToBitmap() but it throws an exception

  16. bis says:

    Hye Mark !

    During search for getting help in my problem ,I saw ur page. My problem is that i want to capture the video to the disk, grab the frames for sum processing and preview the video as well, all of these simultaneously and here lies the problem. I get the error in RenderStream Method which returns -tive value.

    Can u suggest me any way to solve my problem or tell me how can i make my graph so that it doesnt give error?

  17. espinete says:

    Hi misters, How can i play video from the composite video input of a tv card?

    any solution about it ??

    Thanks, regards

  18. Shaun says:

    How do i display a list of conencted webcams in a combo box for users to select?? All i am getting now is avicap32.dll inside my combo box.

  19. Rodney says:

    How can I use the same code and add a button to capture and image?

  20. Lefteris says:

    i would like to now how to connect my camera with visual C++…and take fotos with visuall c++

  21. Coding4Fun says:

    With every year, the Coding4Fun team has come up with a small army of gift ideas.  If anyone wants,

  22. This Week on Channel 9, Brian and Dan discuss: – Oxite : The open source ASP.NET MVC Content Management

  23. rusu says:

    Actually I am totally a newbie in this part. Sorry, if my question sounds too kiddish. The question is: In case, when we have a directx game running on our monitor. What would be the input device for video-caputure in this case? I guess it’s monitor. Now how do we list this input device ?

  24. thanksvisa says:

    WebCamControl2.dll. is not in either folder (Can locate DirectShowLib.dll ok though). Anyone know where it’s hiding?  

  25. Tausseef says:

    I have problem…i need to use to webcams simutaneously in c#.net..the webcams are of same brand (A4 tech Live worrior)… i even tried running two instances of my programe in c#.the 2nd instance shows an option to seletect one the webcams but gives the output of the webcam that is already running in the 1st instance…plz help me out… im working on stereo vision

  26. Опубликовано 6 декабря 08 12:31:00 | Coding4Fun Каждый год команда Coding4Fun предлагает свои идеи по

  27. Dave says:

    It’s very cool that there are people like you willing to share their code (and insights) to make life easier for the rest of us. Thanks.

  28. max says:

    hello, my question is the same with others that read this code. Im sure its possible but i dnt know how to get every frame as an image so we can alter it and display the altered image. Any help will be appreciated.

  29. chris says:

    Can you put together something to get a list of video device please

    Thanks

    Chris

  30. Francis Esmonde-White says:

    Hi Mark,

    Great tutorial. I’m trying to grab video from an external webcam/industrial vision camera and display it (and later I’d like to capture frames for making a photo-mosaic). I’m automating a microscope in our lab to capture video, drive the motorized stage, and capture Raman spectra. The camera and spectrograph have really clunky interfaces in Matlab, but the C interfaces are well developed.

    I’ll be working with a single type of camera (Thorlabs DCC1645C), so I’m not sure that I need to display the camera list, just search through and select the one of interest. I’m not familiar with the built-in classes for capturing and displaying video in windows using c++ or c#, but I have handled streaming video in Matlab in the past. Could you give me a starting point for where to look?

    Thanks,

    Francis

  31. arm2n@hotmail.com says:

    Okay than you… i can’t follow you … cry 22222

    please teach me for

    create video conference with c# .Net

    and if have camera component for web application

    it’s so very thank you ….

    (i’m thai peaple)  best regard …. 🙂

  32. Jalil Abdollahi says:

    I have Problems !!!!

    Why I cannot access and take pictures from a method call from another class?

    I cannot take pictures if the picture box is hidden !!!

    tell me what to do… pleaaaseeee

  33. giri says:

    hi please i need to capture the picture in jsp page through webcam,

    please please any one can help by sending the code to

    kgirish10@gmail.com

    thanks in advance

  34. Zach says:

    When I tried o make the gadget I cant find this WebCamControl2.dll

  35. Jesse Chunn says:

    I would like to see an example of enumerating capture devices.

  36. jay says:

    How can i play video from the composite video input of a tv card?

  37. atish says:

    how i can capture an image and save it with directshow?

    please answer

  38. Shuai says:

    >>>>If anyone is interested in knowing how to present the user with a list of all input devices, I can write some code to do that as well. Just let me know.

    I’m very interested to know how to do that, can you post the code of doing that please?

    Many thanks!

    Shuai

  39. LEty says:

    Hola buenas tardes, estoy realizando un proyecto que incluye webcam control,el artículo me sirvio mucho,ahora mi problema esta en que no se como guardar la imagen que toma la camara con el control, alguien puede ayudarme?se lo agradeceria mucho

  40. Don Cross says:

    I found a minor issue when running this code on 64-bit Windows 7: I got an integer overflow exception on this line of code in the WndProc function inside WebCamControl2.cs:

    this.videoWindow.NotifyOwnerMessage (m.HWnd, m.Msg, m.WParam.ToInt32 (), m.LParam.ToInt32 ());

    I had to change it to this to get the error to go away.  It appears to work now:

    this.videoWindow.NotifyOwnerMessage (m.HWnd, m.Msg, (int) (m.WParam.ToInt64 ()), (int) (m.LParam.ToInt64 ()));

    I hope this helps other people trying to use this code in Win64.

    – Don

  41. wpfRookie says:

    Does anybody have this code made running in a wpf window?

    Tnx!

  42. Mike says:

    Take a look at this article – it points out way more easier and "natural" approach for C# developers: http://www.codeproject.com/…/webcam_c_sharp.aspx

  43. applepuff says:

    thanks to the author of this code. much appreciated. 😉

    but i would like to ask furtherer on how to modify this code using wireless camera.

    its really difficult for me to understand this because i'm just a beginner on c#.

    i need your help. thanks. 😉

  44. sami says:

    thanks to the author of this code. much appreciated. 😉

    http://www.uobabylon.edu.iq

  45. Bulldog says:

    Hi, i am a university stduent in korea. i want to learn sending webcam data using C# Language from you. please leave some comments to me T.T help me.

  46. Ankur Dixit says:

    Can Anyone Tell me how to capture a Image from web cam using this Control ???

    its very urgent Please Help me

  47. Manish says:

    this.videoWindow.NotifyOwnerMessage(m.HWnd, m.Msg, m.WParam.ToInt32(), m.LParam.ToInt32());

    exception : Arithmetic operation resulted in an overflow.