CodeVis VidCapture (v0.30)
Simplified Video Capture for Web Cameras.
Copyright © 2003-2004 by Michael Ellison (mike@codevis.com).
Table of Contents
^Top
Overview
VidCapture provides a simple interface to capture images from web cameras or other supported video capture devices. All you have to do is initialize it, choose a device, and start capturing - no confusing filter graphs, input pins, or IUnknowns to deal with. VidCapture also returns the images in an easy to use but lightweight class so you can process them efficiently.
It is geared towards computer vision and image processing applications. As such, it does not directly provide support for previewing, capturing the video as an AVI, streaming the video to a VHS recorder while adding subtitles, or any of the multitude of other things people might want to do with video capture that make DirectShow so much fun to work with.
VidCapture just gives you the image data in the format you want as quickly and as painlessly as possible.
VidCapture may be used in commercial and non-commercial programs provided that you read and abide by the license agreement found at the end of this documentation.
If you need support for VidCapture, please first check the documentation, then check the project page on SourceForge to see if any information is available in the forums or documentation there. There may also be information available on the CodeVis Public Forums. If you can't find a solution in the above places, feel free to email me. If you'd like VidCapture integrated into an existing system or need any sort of vision system designed and built, I may be available for contracting or hire.
For the latest released version of VidCapture, click here. For the latest development version, you can use CVS to grab it directly from SourceForge. For help grabbing the source from CVS, click here.
Features at a glance
^Top
Including VidCapture in a Project
Originally (version 0.1), VidCapture was distributed as a set of C++ files that you added to your project. You can still do that - just grab the files from the ./Source/VidCapture directory from the install and you're ready to go.
Now, however, the recommend method for C++ programmers is to use the static library included with the install - VidCapLib.lib. This will give you the most control over the video capture library without having to recompile all the time.
For other languages, there is now a .DLL available (VidCapDll.dll) that you can use that has a C-style interface. The symbols in the DLL are undecorated and it uses Pascal (standard Windows API) calling conventions, so it should be useable from just about any serious language available on Windows. Instructions for using the DLL library are further down the page.
If you're using the files directly or compiling the static lib, you may define CVRES_VIDCAP_OFFSET to offset all of the result codes if you wish to use it alongside a similar error system without collisions. See CVRes.h for details. HOWEVER... If you're using the DLL, I'd recommend against this - if you do offset the error codes, you can not use future default releases of the DLL and your program may conflict with others using the VidCapDLL.
VidCapture is setup so that documentation can automatically be generated. To generate the documentation from the source, you'll need doxygen installed. Open a command prompt and go to the ./Project directory of the VidCapture install, then run:
doxygen Doxyfile.cfg
The output is placed in the ./Build/Docs/html folder.
Including the C++ Static Library...
This overview details using the static library (VidCapLib.lib) in a C++ project. If you want to use the .DLL, go here.
DirectX SDK
First, you'll need the latest DirectX SDK installed in order to compile. I've been using DirectX 9 for development. Make sure your #include directories are set up to let the SDK take precedent over any older versions you may have.
Multithreaded Runtime
You will need to use multithreaded runtime libraries when compiling.
In Visual Studio 6.0:
-
Go to Project->Settings on the menu bar.
-
Make sure your project is selected under Settings For.
-
Select the C++ tab
-
Select Code Generation from the Category pull down.
-
Select Win32 Debug from the Settings For: pull down.
-
Select Debug Multithreaded for the debug runtime library.
-
Select Win32 Release from the Settings For: pull down.
-
Select Multithreaded for the release mode runtime library.
Required Link Libraries
Required link libraries:
-
VidCapLib.lib ( or VidCapLib_db.lib for debugging )
-
kernel32.lib
-
ole32.lib
-
oleaut32.lib
-
Strmiids.lib
-
Quartz.lib
-
and whatever multithreaded C++ runtime libraries your compiler uses...
(tested with Visual C++ 6.0)
For Visual C++ 6.0, these are set in the Project->Settings menu under the Link tab in the Object/Library modules box.
Includes
All of the necessary headers for using the VidCapture are included by the VidCapture.h header file. Just add the line:
#include "VidCapture.h"
at the top of your .cpp and you should be set. You may need to add the path to the file to your preprocessor's #include directories.
^Top
Using the VidCapture Library (VidCapLib.lib)
You may want to check out the Example.cpp sample program for a simple example of how to use the VidCapture library - most of the functionality is covered in it.
Steps required to capture video
-
Acquire a CVVidCapture object by calling CVPlatform::AcquireVideoCapture().
To do this, use the code:
CVVidCapture* vidCap = CVPlatform::GetPlatform()->AcquireVideoCapture();
You can also just instantiate a CVVidCaptureDSWin32 object, but using the platform manager will make it easier to modify later on.
-
Call CVVidCapture::Init() to initialize the video capture subsystem.
-
Call CVVidCapture::GetNumDevices() to retrieve the number of devices available. Then call CVVidCapture::GetDeviceInfo() to retrieve the information for each device.
-
Call CVVidCapture::Connect() with the desired device name.
-
Call CVVidCapture::GetNumSupportedModes() to retrieve the number of video modes that are supported on the connected device. Then call CVVidCapture::GetModeInfo() for each index value to get information about the nodes.
-
Select the desired video mode by calling SetMode().
-
Call CVVidCapture::GetPropertyInfo() with the properties from CVVidCapture::CAMERA_PROPERTY to retrieve information about the properties the camera supports such as brightness, contrast, and hue. You can also modify the properties while capturing.
-
Set any properties you want to change by calling CVVidCapture::SetProperty().
-
Start capturing video by calling CVVidCapture::StartImageCap(). You'll need to supply it with a callback to be called on each frame - see CVVidCapture::CVVIDCAP_CALLBACK for the callback definition.
-
On each callback, first check the status code passed in. If it's an error, (e.g. CVSUCCESS(status) yields a false result), then you'll probably need to notify your main thread that it's halted so you can do an orderly shutdown on the capture (e.g. call CVVidCapture::Stop() and CVVidCapture::Disconnect() ), figure out what went wrong, and try again.
You still most certainly need to call CVVidCapture::Stop() from the main thread - NOT from the callback. Calling it from the callback will result in a deadlock!
Usually, if you get an error here, what's happened is that the camera's USB cable got yanked (status will be CVRES_VIDCAP_CAPTURE_DEVICE_DISCONNECTED in this case). Other possibilities include low memory conditions and hardware failure.
-
Process images as desired within the callback. By default, the CVImage object that the callback receives will be released when the callback exits. However, you can call CVImage::AddRef() on the image and keep it around for later processing outside of the callback - just make sure to call CVImage::ReleaseImage() on it when you are done.
-
Stop capturing by calling CVVidCapture::Stop().
-
Disconnect the capture device by calling CVVidCapture::Disconnect().
-
Uninitialize the video capture subsystem by calling CVVidCapture::Uninit().
-
Free the CVVidCapture object.
If you allocated it with CVPlatform as recommended in step 1, then call:
CVPlatform::GetPlatform()->Release(vidCap);
If you constructed a CVVidCaptureDSWin32 object directly, just delete it.
Some things to watch out for...
-
VidCapture uses COM (Common Object Model) to talk to DirectX. The CVVidCapture::Init() function initializes COM with CoInitializeEx(0, COINIT_MULTITHREADED). If you are using apartment mode, you may want to change this. See the MSDN documentation for CoInitializeEx() for more information.
-
VidCapture is currently set up to only have one thread using a specific CVVidCapture object at a time. If you want to call into an object from multiple threads, I'd suggest serializing the calls. Calls into a single CVImage object should be serialized as well. In practice, I wouldn't expect either to be a problem, which is why the classes themselves aren't serialized.
-
Check the result codes! There are lots of them, and they'll probably help quite a bit if you encounter an error. The CVRES result codes are defined in CVRes.h, and result codes for the various subsystems are enumerated in CVResFile.h, CVResImage.h, and CVResVidCap.h.
-
Try not to put a lot of heavy processing or other lengthy code in the callback. If you need to take a lot of time for each image, create a thread-safe queue, call CVImage::AddRef() on the images in the callback and add them to the queue. Then pull them from the queue as you are ready for them from another thread. Remember to call CVImage::ReleaseImage() on the images when you're done with them if you use this method so you don't create a huge memory leak.
Also, you'll probably want to place a size limit on your queue if your processing is slower than the capture speed and drop frames once you've hit your limit to avoid filling up all available memory with images.
Alternatively, you can just use CVImage::Save() to save the images to disk and load them back in for processing later at your leisure.
-
Do NOT call CVVidCapture::Stop() from within a capture callback to stop the image capture - it will cause a deadlock. Instead, just return 'false' from the callback and the capture will be stopped. You still need to call CVVidCapture::Stop() from another thread (not the capture callback) to free up the resources.
Using the VidCapture DLL (VidCapDll.dll)
The VidCapture DLL has a slightly different interface, as it is written to be used from C and other non-object oriented languages.
You may want to check out the VidCapDllTest.c sample program for a simple example of how to use the VidCapture DLL - most of the functionality is covered in it.
If you're using the DLL from C or C++, you'll want to link to the VidCapDll.lib (or VidCapDll_db.lib for debugging) library in your project. This will cause the DLL to implicitly load when you run your program.
You may also load the library manually using LoadLibrary() and retrieve the address of each function from the DLL by calling GetProcAddress() if you wish. If you do this - none of the functions names are decorated, and they do NOT have a preceding underscore (_). However, while this method is preferable in some cases it is otherwise beyond the scope of this documentation.
Steps required to capture video with the DLL
-
Load the DLL. If you linked against VidCapDLL.lib, this is automatic.
-
Acquire a video capture system handle (CVVIDCAPSYSTEM) by calling CVAcquireVidCap().
-
Get the number of devices available with CVGetNumDevices(), then find the one you want by calling CVGetDeviceName(). Remember to set the nameBufLen to the full size of the name buffer for each call to CVGetDeviceName(), as when it returns it will be set to the actual length of the last name returned.
-
Connect to the desired device by calling CVDevConnect() with the device name.
-
Retrieve parameters for any properties you may wish to modify with CVDevGetProperty(), and set them with CVDevSetProperty(). Note that this may also be done during video capture.
-
Get the number of available modes with CVDevGetNumModes(), then retrieve information about each mode by calling CVDevGetModeInfo().
-
Begin a grab by calling CVDevStartCap() with the desired mode index. Keep the capture handle it returns! This will begin a capture on a seperate thread - your callback will be called each time an image becomes available.
-
Process the images in your callback as it is called for each frame (see CVIMAGESTRUCT). The CVIMAGESTRUCT structures and their associated image data are ONLY valid during the callback. If you need to perform any processing that is too slow to place in the callback, you MUST copy the data out. Unlike the C++ VidCapLib, the DLL does not currently offer reference counting on images.
-
During the grab, you may prematurely terminate the capture from the callback by returning FALSE. However, you'll still need to call CVDevStopCap() to clean up.
-
Call CVDevStopCap() when you're finished grabbing images. This halts the capture if it is still going, then cleans up any memory or objects used by the capture.
-
Disconnect from the connected device by calling CVDevDisconnect().
-
Free the video capture system handle with CVReleaseVidCap().
Some things to watch out for...
^Top
VidCapture History
Version 0.30 (3/01/04)
-
Added support for additional input video formats (YUV, I420, etc.)
-
Changed enumeration/allocation of devices to allow use of multiple identical devices.
-
Added framerate estimation to mode information
-
Fixed disconnection bug that could cause a failure on reconnect.
-
Added a GUI test project.
Version 0.21 (2/08/04)
No code changes, but now hosted on SourceForge! http://sourceforge.net/projects/vidcapture/ Version 0.21 (1/30/04)
-
Fixed crash that could occur if no devices were attached.
Thanks to John Janecek for finding it!
-
Added this history to documentation.
Version 0.20 (1/26/04)
Version 0.10
-
Initial Release of C++ code
^Top
Future Directions...
I can't (and won't) make any promises about any future upgrades, support, or anything else regarding VidCapture. However, there are some directions I'm currently hoping to take it.
WARNING: In future versions the interface may change dramatically.
As of version 0.2, VidCapture also includes a .DLL version with a C-style interface. So at least one of the wishlist features is done :)
I'm still hoping to make it available as an ActiveX control and possibly as a .NET control as well - it all depends on my 'free' time.
At a later date, I hope to make a more complete CVImage library with image processing support similar to the ones I wrote for the 3D Scanner project. In fact, a large part of the reason I wrote VidCapture was to replace the old code used there. I also plan to make the library multiplatform, supporting at least Mac OSX and Linux. For now, if you want to do image processing using the images (beyond just capturing them) you might want to take a look at the CVImage::GetMaxPixel() function to see how it templates and handles the image processing generically while supporting the offsets and widths of sub images.
If you have any comments, suggestions, or want to lend a hand in the development, please email me at mike@codevis.com.
^Top
Credits
Many thanks to Blair MacIntyre of Georgia Tech for providing equipment and helpful suggestions!
I want to thank Dimitri van Heesch for writing an excellent documentation tool called doxygen. It is what has made the documentation you are reading possible, and I couldn't recommend it more highly for documenting new projects.
For installation of VidCapture, I'm using NullSoft's Scriptable Install System (NSIS).
The reference material used for developing VidCapture came mostly from MSDN and Microsoft's DirectShow Documentation.
Programming DirectShow for Digital Video and Television by Mark D. Pesce was also very helpful on a lot of the basic concepts for interfacing with DirectShow.
CodeVis VidCapture was written by Michael Ellison, mike@codevis.com.
^Top
License Agreement
CodeVis's Free License
www.codevis.com
Copyright (c) 2003-2004 by Michael Ellison (mike@codevis.com).
All Rights Reserved.
| You may use this software in source and/or binary form, with or without modification, for commercial or non-commercial purposes, provided that you comply with the following conditions:
-
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
-
Redistributions of modified source must be clearly marked as modified, and due notice must be placed in the modified source indicating the type of modification(s) and the name(s) of the person(s) performing said modification(s).
This software is provided by the copyright holders and contributors "as is" and any express or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall the copyright owner or contributors be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage.
|
^Top |