Multiple webcam example

Jim
2010-02-09
2012-10-29
  • Jim

    Jim - 2010-02-09

    Anyone have a working Directshow example of previewing multiple webcams
    simultaneously in the same window that they are willing to share? I'm not
    necessarily looking for a polished piece of code, just one that I can use as a
    base for my app.

    Regards,
    Jim

     
  • snarfle

    snarfle - 2010-02-09

    How about just using several borderless controls next to each other?

     
  • Jim

    Jim - 2010-02-09

    snarfle,

    Thanks for the input.

    Actually I'm not as concerned with the display layout as I am with managing
    and setting up of the cameras.

    This is a small part of a much larger project and is becoming a bit of an
    annoyance.

    If I could just get an example of the multi-camera management and setup part
    then I can probably handle the rest. Hey, if the display part was also there
    that would be nice.

    Anyway, after almost 50 years of doing this stuff, I would hope I could do the
    rest.

    It also doesn't help that I'm working in 4 different programming languages
    right now so any examples are appreciated.

    Regards,
    Jim

     
  • snarfle

    snarfle - 2010-02-10

    I'm afraid we don't have any sample such as you describe. I can however, point
    you at the key components. Note that the code below is being composed while
    typing on a webpage, so it probably won't compile as is (and needs error
    checking, etc), but it should point you in the right direction:

    1) Get the list of capture devices:

    DsDevice capDevices;
    capDevices = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);

    2) For each device (or for as many as you want to show), you are going to
    build a graph for them

    DsDevice dev = capDevices;

    // Get the graphbuilder object
    m_FilterGraph = new FilterGraph() as IFilterGraph2;

    // add the video input device to the graph

    hr = m_FilterGraph.AddSourceFilterForMoniker(dev.Mon, null, dev.Name, out
    capFilter);

    // Auto build the rest of the graph
    ICaptureGraphBuilder2 capGraph = null;
    capGraph = (ICaptureGraphBuilder2) new CaptureGraphBuilder2();

    hr = capGraph.SetFiltergraph( m_FilterGraph );

    hr = capGraph.RenderStream( null, null, capFilter, null, null);

    // Tie the graph to a particular window
    (see ConfigVideoWindow() in the Samples\Capture\DxSnap\capture.cs)

    // Start the graph
    IMediaControl mediaCtrl = m_FilterGraph as IMediaControl;
    hr = mediaCtrl.Run();

     
  • Jim

    Jim - 2010-02-10

    snarfle,

    Thanks for the outline of the components needed.

    I will use this and the JavaDoc and any other doc I can find (any thought on
    that?) to try to build what I need.

    As an aside, I have frequently found that the mainline code is the easy part,
    the error checking and the obscure behavior is the hard part. Of course, doing
    that part right is what make good code and a reliable product.

    If I may, I would like to reserve the right for follow-up questions.

    Regards,
    Jim

     
  • snarfle

    snarfle - 2010-02-10

    JavaDoc? You mean MSDN? http://msdn.microsoft.com/en-
    us/library/dd375454%28VS.85%29.aspx

    I would think MSDN is going to be your best starting place for DirectShow
    info.

    As for the error handling, as you can see, the interface methods all return
    HRESULTs (just what a c program would expect). We have a handy function
    (DsError.ThrowExceptionForHR) that check the HRESULT, and throws an exception
    if it contains an error if you prefer exception based error handing.

     
  • Jim

    Jim - 2010-02-11

    OK, I found a sample that displays the first camera it finds. The routine that
    finds the camera is:

            private IBaseFilter FindCaptureDevice() {
                UCOMIEnumMoniker classEnum = null;
                UCOMIMoniker[] moniker = new UCOMIMoniker[1];
                object source = null;
    
                ICreateDevEnum devEnum = (ICreateDevEnum)(new CreateDevEnum());
                int hr = devEnum.CreateClassEnumerator(FilterCategory.VideoInputDevice, out classEnum, CDef.None);
                DsError.ThrowExceptionForHR(hr);
                Marshal.ReleaseComObject(devEnum);
    
                if (classEnum == null) {
                    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\\nto be installed and working properly.  The sample will now close.");
                }
    
                int none = 0;
    
                if (classEnum.Next(moniker.Length, moniker, out none) == 0) {
                    Guid iid = typeof(IBaseFilter).GUID;
                    moniker[0].BindToObject(null, null, ref iid, out source);
                } else {
                    throw new ApplicationException("Unable to access video capture device!");
                }
    
                Marshal.ReleaseComObject(moniker[0]);
                Marshal.ReleaseComObject(classEnum);
    
                return (IBaseFilter)source;
            }
    

    If I may act like a "wet behind the ears" newbie programmer, how would I
    modify this so that if I passed it an integer (0-3) it would return either the
    IBaseFilter for that camera or null if there was no "Nth" camera?

    Regards,
    Jim

     
  • Jim

    Jim - 2010-02-11

    Sorry about the Javadoc reference but I said I have been working in 4
    languages. You should have seen the C# routine I wrote today with 4 lines of
    Java code right in the middle. Anyway, thanks for the MSDN reference and the
    DSError reference.

    Regards,
    Jim

     
  • snarfle

    snarfle - 2010-02-11

    Well, to start with, I wouldn't (modify this so that if I passed it an
    integer...). I would instead use the routine I mentioned before
    (DsDevice.GetDevicesOfCat), which loads the entire list of capture devices
    into an array. Then I would just index into the array. This seems a much more
    efficient approach than repeatedly calling a routine like this to build and
    walk the device list.

    Second off, I won't use UCOMIEnumMoniker because it is a deprecated interface
    (http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.ucomi
    enummoniker%28VS.85%29.aspx
    ).

    However, if you really feel you must, check out the members of this interface,
    paying particular attention to the Skip method.

    It might also be educational to read the source code for GetDevicesOfCat. You
    will find it in DsUtils.cs in the src directory.

     
  • Jim

    Jim - 2010-02-11

    I have started the research you suggest and believe I am beginning to
    understand the component parts. So let me ask some basic program organization
    questions.

    I plan to have a main program that owns the main window. I then plan a class
    which handles all of the functions for a given camera. It will be instantiated
    for each available camera by the main program.

    In the case of the main program, do I have to instantiate the camera class in
    a separate thread for each camera?

    In the case of the camera class, it will present a preview of the camera
    continuously. It will also provide the functionality to take a snapshot, start
    and stop recording to a file, and switch a camera to "full screen" when
    requested all of which can occur while the preview is being presented. It
    appears from my research that preview, snapshot, and recording use different
    filters. Can they all exist at once or do I have this part wrong? The camera
    class will be instantiated with the camera device, camera preview window
    location, and frame rate as input parameters.

    Does this structure look sound?

    Regards,
    Jim

     
  • snarfle

    snarfle - 2010-02-11

    Sounds like a sensible approach. It is, however, a much bigger project than I
    understood from your original post. Rather than simply previewing video from
    multiple cameras, this sounds like the outline of a full blown video
    surveillance system.

    As just one sample of issues you haven't even identified yet, do you want to
    be able to play video from files while you are still recording? Many video
    formats don't support that. To accomplish all the things you have outlined
    (plus the ones yet to be discovered), you aren't going to just be able to call
    a couple of quick functions and have it all work. You are going to need to
    become very familiar with the workings of DS.

    You describe this as "a small part of a much larger project", however such a
    system could easily be a project unto itself. You really need to take a minute
    to re-evaluate just how much effort this is going to take.

    To respond to some of your other questions:

    1) The FilterGraph object creates its own thread. I cannot immediately think
    of a benefit to creating additional ones yourself in this context.

    2) For being able to preview and record, I would start by using code from the
    GMFPreview sample. It shows you one method for splitting a video stream in
    two.

    3) I haven't ever tried to create a "switch to fullscreen" capability. If I
    wanted to do this, I'd probably be experimenting with the
    IVideoWindow::put_Owner to switch where DS draws its video between a small
    window and a large one.

    4) There are a variety of ways to take snapshots. The one I've used most often
    is to add the SampleGrabber filter to a graph. You can see it being used in
    DxSnap.

     
  • Jim

    Jim - 2010-02-12

    snarfle,

    I really appreciate you taking the time to answer my questions.

    Let me briefly outline what I am doing. The camera support is part of an RV
    support system that includes a navigation system (3rd party), merged databases
    of numerous things one might look for while traveling with a purpose built
    specialized search engine, an RV consumables monitoring system (tank levels,
    electrical readings, etc), and the camera system to name several. The 4
    cameras are rear, right side, left side, and forward. The side cameras are
    tied to the turn signals to switch to full screen and back. The rear is to
    continually observe what is behind me and the front is to record "neat stuff"
    along the route. All cameras have infrared capabilities for night travel. Much
    of it is running.

    I have tried 4 or 5 third party camera packages but none did a complete job of
    what I want, so I decided to write my own support.

    I've already tried several Java and C++ solutions with little success (most
    are "dead" projects, incomplete, no support, or lack good device support). The
    DS Lib package appears the best so far but I must admit that the longer I keep
    doing this stuff the more obscure some of the terminology becomes. So I'll
    just try things to see what happens.

    My only plan for recording is as archives of a trip with no concurrency except
    with preview/record.

    Since I wrote the email this morning, I have looked at some of the samples you
    mentioned as well as some of the documentation.

    This is the type of project I did for most of my career, making things work
    together that were never meant to work together. It's a lot of fun but can be
    very annoying at times.

    Again thanks for the help and I will probably be back but for now it's time to
    "just do it".

    Regards,
    Jim

     
  • snarfle

    snarfle - 2010-02-12

    Good luck then.

    I guess just one last thought here. Something about the way you phrased your
    description of "the ds lib" package makes me wonder if you are clear on just
    what it does.

    In summary, we just provide a c# mapping layer on top of Microsoft's
    DirectShow. When MS wrote DS, c# didn't really exist, and they never really
    got around to providing a .Net interface for it. So, everything you can do
    with this library (and more) can also be done in c++. So, if c++ is your
    preferred environment, you might consider calling MS's interfaces directly.

    Just a thought.

     
  • Jim

    Jim - 2010-02-12

    snarfle,

    Thanks for the comment on "... ds lib...". I do fully understand the purpose
    of the lib and very much appreciate the work the authors have done.

    And with no intent to start a "techno-religious" debate, I have generally
    found C++ syntactically and grammatically someone's bad dream. I once taught
    both C++ and object technology and truely disliked C++. Java was more
    consistant with OO concepts and once the Java/VB wars were over, MS produced
    C# which, even more than Java, is more inline with OO even if it is more MS
    oriented than Java. I tend to use the latter for anything cross-platform with
    JNI to do system specific stuff when necessary.

    I have now seriously violated discussions that I wouldn't allow my staff to
    enter into. Rather I insisted on "right tool for the job".

    Regards,
    Jim

    P.S. - Great progress tonight - 4 cameras up and running sharing one window
    using the outline you provided. Now it's off to recording, snapshots, full
    screen, and windows stuff. Many thanks.

     
  • Olivier

    Olivier - 2011-01-07

    P.S. - Great progress tonight - 4 cameras up and running

    Can you help me to make 2 webcams running.

    I can run the sample by putting 0 to access the first one, and with 1 to
    access the 2nd. But if I initialize 2 in the same time (one with 0 and one
    with 1), the first display the picture and the second stays black. I have no
    Errro message and no exception.

    Thank you.

     
  • Elisa Le

    Elisa Le - 2012-06-01

    Hey!! I'm totally a newbie to the directshow NET. I need to take pictures from
    6 webcams of the same type for my final thesis. Right now, I want to make a
    try with only 2 webcams. I try to modify the code line: const int VIDEODEVICE
    = 0 to 1 but it didnt work at all!! Anyone can help me clear out this point!!
    Thanks a lot!!

     

Log in to post a comment.

Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:





No, thanks