Programmers Guide¶
In this guide we will create a very simple program that lists the available capture devices, then lists the capabilities of a device. Once we found a capability that we want to use we open the device and start captureing. Then in a loop we will flush the buffers of the capture device and let it call our callback function. Before we start we explain a couple of concepts that we use in Video Capture.
Concepts used in Video Capture¶
In Video Capture we use a couple of concepts which are shared among most SDKs/APIs we found on OSX, Linux and Windows.
- Device
- We use the term Device to represent something like a webcam. This Device can capture video in a specific pixel format.
- Pixel format
- A pixel format describes how the bytes of a video frame are stored. Common pixel formats for Video Capture are YUYV422, UYVV422 and YUV420P. Some OSes can convert between pixel formats (Mac). See [libyuvs](https://code.google.com/p/libyuv/wiki/Formats) documentation for some more info on format mappings..
- Output formats
- Some SDKs have optimized solutions to decode a video stream you get from a capture device. For example on Mac you can use the OS to convert a raw YUV stream into a RGB24 stream. Some OSes even have support to decode H264, so the output formats are also related to codecs and not only pixel formats.
- Capability
- A capability describes a couple of things related to what a device can give you. These are things like the dimensions of the video frames you receive, the framerate and the pixel format. Video Capture supports querying the available capabilities of a device on Windows, Mac and Linux.
- Settings
- Video Capture uses a settings object when you want to open a device. The
Settings object stores information like, what device you want to use,
what capability and what pixel format you want to use. A settings object
is passed into the
open()
method of the cature class. - Frame
- A frame is a helper type we created which gives you information about
a pixel format. If necessary you can use a
Frame
object to get information about strides, widths, heights, offsets etc.. for planar or non-planar pixel formats. See the opengl example where we use a Frame to get offets into the YUV420P data on windows.
Getting information about a device¶
Before we open a capture device we have to inspect the capabilities
of the capture device. Do detect if we found your capture device you can
use the listDevices()
function of the Capture
class.
Note that all types of the Video Capture library are using the ca
namespace.
The example below creates a Capture
instance which is the interface to your
capture device.
using namespace ca;
Capture capture(fc,NULL);
if(capture.listDevices() < 0) {
printf("Error: cannot list devices.\n");
::exit(EXIT_FAILURE);
}
if(capture.listCapabilities(0) < 0) {
printf("Error: cannot list capabilities for devices 0.\n");
::exit(EXIT_FAILURE);
}
listDevices()
will log all the found capture devices to stdout. Each
device has a unique number that you will need to use when opening a device.
When a function fails it will return a negative error code, so make sure
to check if the result is < 0
as shown above.
The listCapabilities()
function will list all the capabilities of the
capture device. A capability describes the width, height, framerate and
pixel format. From this list, pick the capability number that you want to use.
The Video Capture library also provides a findCapability()
function
that you can use to find a specific capability for a device. This function will
return the index number of the found capability or a negative value if not
found.
Some SDKs can convert a pixel format from the capture device into another,
maybe more easy to use one. For example Mac gives you a way to convert from a
YUV pixel format to RGB format. Although this is very handy, it’s not recommended
because converting will mostly be done on the CPU (maybe with SIMD) which means
you loose some processing power for other parts of your application. Use the
listOutputFormats()
to inspect what output formats are supported.
Opening a device¶
Once you’ve found what device, capability and output format you want to
use you need to create a Settings
object that describes how you want to
use the device. Below we show how to create a Settings
object and how to
set what capability, device and format we want to use.
using namespace ca;
Settings settings;
settings.device = 0; // Use number 0 from the device list (see listDevices())
settings.capability = 15; // Use number 15 from the capability list (see listCapabilities())
settings.format = -1 // We're not using any output format conversion (see listOutputFormats())
Once we have this Settings
object we pass it into the open()
function
of the Capture
instance. This will open the device and set the capability.
Make sure to check the return values from open()
, when it’s negative an error
occured.
using namespace ca;
Capture capture(fc, NULL);
Settings settings;
settings.device = 0;
settings.capability = 15;
settings.format = -1
if(capture.open(settings) < 0)) {
printf("Error: cannot open the capture device.\n");
:exit(EXIT_FAILURE);
}
Captureing frames¶
After opening the capture device we can start receiving frames. Video Capture uses a callback function that is called whenever a new frame arrives. Two things are important about this callback function:
- This function may be called from another thread
- This function must return before a new frame arrives
The callback function is passed to the constructor of the Capture
class.
The interface of this callback function is:
void on_frame(void* bytes, int nbytes, void* user)
- bytes is a pointer to the frame data from the capture device. This maybe be a pointer to planar video data when e.g. using YUV420P. See the opengl example where we use YUV420P (on Windows).
- nbytes the number of bytes in the frame.
- user a pointer to user data. This is the second parameter to the
Capture
constructor.
To capture frames you use:
if(capture.start() < 0) {
printf("Error: cannot start captureing.\n");
::exit(EXIT_FAILURE);
}
while(must_capture) {
capture.update();
}
if(capture.stop() < 0) {
printf("Error: cannot stop the capture process.\n");
}
Make sure to call update()
at at least the same rate of the used frame rate. Some
capture SDKs don’t use async callbacks for which we need to process any pending frames.
Closing a device¶
Once you’re done make sure to correctly cleanup and shutdown the capture device. Closing a device will make sure that all allocated memory gets freed and the device is correctly shutdown. Note: when you don’t close a device on Linux, it will continue to be in opened state and can’t be used anymore, before you correctly close it.
if(capture.close() < 0) {
printf("Error: cannot close the capture device.\n");
}