libuvc: a cross-platform library for USB video devices

libuvc is a library that supports enumeration, control and streaming for USB Video Class (UVC) devices, such as consumer webcams.

# Features

- UVC device discovery and management API
- Video streaming (device to host) with asynchronous/callback and synchronous/polling modes
- Read/write access to standard device settings
- Conversion between various formats: RGB, YUV, JPEG, etc.
- Tested on Mac and Linux, portable to Windows and some BSDs

# Roadmap

- Bulk-mode image capture
- One-shot image capture
- Improved support for standard settings
- Support for "extended" (vendor-defined) settings

# Misc.

`The` source code can be found at https://github.com/libuvc/libuvc/. To build the library, install libusb 1.0+ and run:

$ git clone https://github.com/libuvc/libuvc.git
$ cd libuvc
$ mkdir build
$ cd build
$ cmake -DCMAKE_BUILD_TYPE=Release ..
$ make && make install

# Example

In this example, libuvc is used to acquire images in a 30 fps, 640x480 YUV stream from a UVC device such as a standard webcam.

#include "libuvc/libuvc.h"
#include <stdio.h>
#include <unistd.h>
/* This callback function runs once per frame. Use it to perform any
* quick processing you need, or have it put the frame into your application's
* input queue. If this function takes too long, you'll start losing frames. */
void cb(uvc_frame_t *frame, void *ptr) {
uvc_frame_t *bgr;
uvc_error_t ret;
enum uvc_frame_format *frame_format = (enum uvc_frame_format *)ptr;
/* FILE *fp;
* static int jpeg_count = 0;
* static const char *H264_FILE = "iOSDevLog.h264";
* static const char *MJPEG_FILE = ".jpeg";
* char filename[16]; */
/* We'll convert the image from YUV/JPEG to BGR, so allocate space */
bgr = uvc_allocate_frame(frame->width * frame->height * 3);
if (!bgr) {
printf("unable to allocate bgr frame!\n");
return;
}
printf("callback! frame_format = %d, width = %d, height = %d, length = %lu, ptr = %p\n",
frame->frame_format, frame->width, frame->height, frame->data_bytes, ptr);
switch (frame->frame_format) {
case UVC_FRAME_FORMAT_H264:
/* use `ffplay H264_FILE` to play */
/* fp = fopen(H264_FILE, "a");
* fwrite(frame->data, 1, frame->data_bytes, fp);
* fclose(fp); */
break;
case UVC_COLOR_FORMAT_MJPEG:
/* sprintf(filename, "%d%s", jpeg_count++, MJPEG_FILE);
* fp = fopen(filename, "w");
* fwrite(frame->data, 1, frame->data_bytes, fp);
* fclose(fp); */
break;
case UVC_COLOR_FORMAT_YUYV:
/* Do the BGR conversion */
ret = uvc_any2bgr(frame, bgr);
if (ret) {
uvc_perror(ret, "uvc_any2bgr");
uvc_free_frame(bgr);
return;
}
break;
default:
break;
}
if (frame->sequence % 30 == 0) {
printf(" * got image %u\n", frame->sequence);
}
/* Call a user function:
*
* my_type *my_obj = (*my_type) ptr;
* my_user_function(ptr, bgr);
* my_other_function(ptr, bgr->data, bgr->width, bgr->height);
*/
/* Call a C++ method:
*
* my_type *my_obj = (*my_type) ptr;
* my_obj->my_func(bgr);
*/
/* Use opencv.highgui to display the image:
*
* cvImg = cvCreateImageHeader(
* cvSize(bgr->width, bgr->height),
* IPL_DEPTH_8U,
* 3);
*
* cvSetData(cvImg, bgr->data, bgr->width * 3);
*
* cvNamedWindow("Test", CV_WINDOW_AUTOSIZE);
* cvShowImage("Test", cvImg);
* cvWaitKey(10);
*
* cvReleaseImageHeader(&cvImg);
*/
uvc_free_frame(bgr);
}
int main(int argc, char **argv) {
uvc_context_t *ctx;
uvc_device_t *dev;
uvc_device_handle_t *devh;
uvc_stream_ctrl_t ctrl;
uvc_error_t res;
/* Initialize a UVC service context. Libuvc will set up its own libusb
* context. Replace NULL with a libusb_context pointer to run libuvc
* from an existing libusb context. */
res = uvc_init(&ctx, NULL);
if (res < 0) {
uvc_perror(res, "uvc_init");
return res;
}
puts("UVC initialized");
/* Locates the first attached UVC device, stores in dev */
res = uvc_find_device(
ctx, &dev,
0, 0, NULL); /* filter devices: vendor_id, product_id, "serial_num" */
if (res < 0) {
uvc_perror(res, "uvc_find_device"); /* no devices found */
} else {
puts("Device found");
/* Try to open the device: requires exclusive access */
res = uvc_open(dev, &devh);
if (res < 0) {
uvc_perror(res, "uvc_open"); /* unable to open device */
} else {
puts("Device opened");
/* Print out a message containing all the information that libuvc
* knows about the device */
uvc_print_diag(devh, stderr);
const uvc_format_desc_t *format_desc = uvc_get_format_descs(devh);
const uvc_frame_desc_t *frame_desc = format_desc->frame_descs;
enum uvc_frame_format frame_format;
int width = 640;
int height = 480;
int fps = 30;
switch (format_desc->bDescriptorSubtype) {
case UVC_VS_FORMAT_MJPEG:
frame_format = UVC_COLOR_FORMAT_MJPEG;
break;
case UVC_VS_FORMAT_FRAME_BASED:
frame_format = UVC_FRAME_FORMAT_H264;
break;
default:
frame_format = UVC_FRAME_FORMAT_YUYV;
break;
}
if (frame_desc) {
width = frame_desc->wWidth;
height = frame_desc->wHeight;
fps = 10000000 / frame_desc->dwDefaultFrameInterval;
}
printf("\nFirst format: (%4s) %dx%d %dfps\n", format_desc->fourccFormat, width, height, fps);
/* Try to negotiate first stream profile */
res = uvc_get_stream_ctrl_format_size(
devh, &ctrl, /* result stored in ctrl */
frame_format,
width, height, fps /* width, height, fps */
);
/* Print out the result */
uvc_print_stream_ctrl(&ctrl, stderr);
if (res < 0) {
uvc_perror(res, "get_mode"); /* device doesn't provide a matching stream */
} else {
/* Start the video stream. The library will call user function cb:
* cb(frame, (void *) 12345)
*/
res = uvc_start_streaming(devh, &ctrl, cb, (void *) 12345, 0);
if (res < 0) {
uvc_perror(res, "start_streaming"); /* unable to start stream */
} else {
puts("Streaming...");
/* enable auto exposure - see uvc_set_ae_mode documentation */
puts("Enabling auto exposure ...");
const uint8_t UVC_AUTO_EXPOSURE_MODE_AUTO = 2;
res = uvc_set_ae_mode(devh, UVC_AUTO_EXPOSURE_MODE_AUTO);
if (res == UVC_SUCCESS) {
puts(" ... enabled auto exposure");
} else if (res == UVC_ERROR_PIPE) {
/* this error indicates that the camera does not support the full AE mode;
* try again, using aperture priority mode (fixed aperture, variable exposure time) */
puts(" ... full AE not supported, trying aperture priority mode");
const uint8_t UVC_AUTO_EXPOSURE_MODE_APERTURE_PRIORITY = 8;
res = uvc_set_ae_mode(devh, UVC_AUTO_EXPOSURE_MODE_APERTURE_PRIORITY);
if (res < 0) {
uvc_perror(res, " ... uvc_set_ae_mode failed to enable aperture priority mode");
} else {
puts(" ... enabled aperture priority auto exposure mode");
}
} else {
uvc_perror(res, " ... uvc_set_ae_mode failed to enable auto exposure mode");
}
sleep(10); /* stream for 10 seconds */
/* End the stream. Blocks until last callback is serviced */
uvc_stop_streaming(devh);
puts("Done streaming.");
}
}
/* Release our handle on the device */
uvc_close(devh);
puts("Device closed");
}
/* Release the device descriptor */
uvc_unref_device(dev);
}
/* Close the UVC context. This closes and cleans up any existing device handles,
* and it closes the libusb context if one was not provided. */
uvc_exit(ctx);
puts("UVC exited");
return 0;
}
uvc_set_ae_mode
uvc_error_t uvc_set_ae_mode(uvc_device_handle_t *devh, uint8_t mode)
Sets camera's auto-exposure mode.
Definition ctrl-gen.c:105
uvc_find_device
uvc_error_t uvc_find_device(uvc_context_t *ctx, uvc_device_t **dev, int vid, int pid, const char *sn)
Finds a camera identified by vendor, product and/or serial number.
Definition device.c:128
uvc_close
void uvc_close(uvc_device_handle_t *devh)
Close a device.
Definition device.c:1721
uvc_open
uvc_error_t uvc_open(uvc_device_t *dev, uvc_device_handle_t **devh)
Open a UVC device.
Definition device.c:316
uvc_error_t
enum uvc_error uvc_error_t
UVC error types, based on libusb errors.
uvc_print_diag
void uvc_print_diag(uvc_device_handle_t *devh, FILE *stream)
Print camera capabilities and configuration.
Definition diag.c:143
uvc_print_stream_ctrl
void uvc_print_stream_ctrl(uvc_stream_ctrl_t *ctrl, FILE *stream)
Print the values in a stream control block.
Definition diag.c:106
uvc_perror
void uvc_perror(uvc_error_t err, const char *msg)
Print a message explaining an error in the UVC driver.
Definition diag.c:73
UVC_ERROR_PIPE
@ UVC_ERROR_PIPE
Pipe error.
Definition libuvc.h:39
UVC_SUCCESS
@ UVC_SUCCESS
Success (no error)
Definition libuvc.h:21
uvc_free_frame
void uvc_free_frame(uvc_frame_t *frame)
Free a frame structure.
Definition frame.c:92
uvc_allocate_frame
uvc_frame_t * uvc_allocate_frame(size_t data_bytes)
Allocate a frame structure.
Definition frame.c:64
uvc_any2bgr
uvc_error_t uvc_any2bgr(uvc_frame_t *in, uvc_frame_t *out)
Convert a frame to BGR.
Definition frame.c:464
uvc_init
uvc_error_t uvc_init(uvc_context_t **pctx, struct libusb_context *usb_ctx)
Initializes the UVC context.
Definition init.c:104
uvc_exit
void uvc_exit(uvc_context_t *ctx)
Closes the UVC context, shutting down any active cameras.
Definition init.c:138
uvc_start_streaming
uvc_error_t uvc_start_streaming(uvc_device_handle_t *devh, uvc_stream_ctrl_t *ctrl, uvc_frame_callback_t *cb, void *user_ptr, uint8_t flags)
Begin streaming video from the camera into the callback function.
Definition stream.c:931
uvc_stop_streaming
void uvc_stop_streaming(uvc_device_handle_t *devh)
Stop streaming video.
Definition stream.c:1477
uvc_frame_format
uvc_frame_format
Color coding of stream, transport-independent.
Definition libuvc.h:59
uvc_get_stream_ctrl_format_size
uvc_error_t uvc_get_stream_ctrl_format_size(uvc_device_handle_t *devh, uvc_stream_ctrl_t *ctrl, enum uvc_frame_format cf, int width, int height, int fps)
Get a negotiated streaming control block for some common parameters.
Definition stream.c:470
UVC_FRAME_FORMAT_YUYV
@ UVC_FRAME_FORMAT_YUYV
YUYV/YUV2/YUV422: YUV encoding with one luminance value per pixel and one UV (chrominance) pair for e...
Definition libuvc.h:68
uvc_format_desc
Format descriptor.
Definition libuvc.h:196
uvc_format_desc::frame_descs
struct uvc_frame_desc * frame_descs
Available frame specifications for this format.
Definition libuvc.h:224
uvc_format_desc::bDescriptorSubtype
enum uvc_vs_desc_subtype bDescriptorSubtype
Type of image stream, such as JPEG or uncompressed.
Definition libuvc.h:200
uvc_frame_desc
Frame descriptor.
Definition libuvc.h:157
uvc_frame_desc::wWidth
uint16_t wWidth
Image width.
Definition libuvc.h:166
uvc_frame_desc::wHeight
uint16_t wHeight
Image height.
Definition libuvc.h:168
uvc_frame_desc::dwDefaultFrameInterval
uint32_t dwDefaultFrameInterval
Default frame interval (in 100ns units)
Definition libuvc.h:176
uvc_frame
An image frame received from the UVC device.
Definition libuvc.h:455
uvc_frame::frame_format
enum uvc_frame_format frame_format
Pixel data format.
Definition libuvc.h:465
uvc_frame::data_bytes
size_t data_bytes
Size of image data buffer.
Definition libuvc.h:459
uvc_frame::width
uint32_t width
Width of image in pixels.
Definition libuvc.h:461
uvc_frame::height
uint32_t height
Height of image in pixels.
Definition libuvc.h:463
uvc_frame::sequence
uint32_t sequence
Frame number (may skip, but is strictly monotonically increasing)
Definition libuvc.h:469
uvc_stream_ctrl
Streaming mode, includes all information needed to select stream.
Definition libuvc.h:498