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
|