libuvc是一个用于USB视频设备的跨平台库,构建在libusb之上,编译libuvc时需要依赖libusb。libuvc的License为BSD,最新发布版本为0.0.6,源码地址: https://github.com/libuvc/libuvc
libuvc支持在非windows系统上直接编译,因为libuvc源码中会include pthread.h等头文件,因此在windows上并不能直接进行编译。
libuvc支持对导出标准USB视频类(USB Video Class, UVC)接口的USB视频设备进行细粒度控制,使开发人员能够为以前不受支持的设备编写驱动程序,或仅以通用方式访问UVC设备。
关于libusb的介绍可以参考:https://blog.csdn.net/fengbingchun/article/details/105712776
在linux上插入同一厂家两个相同型号的摄像头时,通过lsusb命令获取的两个摄像头设备信息是一样的,不能做出区分,此时可以通过libuvc来获取摄像头设备较为详细的信息,从此信息可以分辨出具体是从哪个摄像头上获取到的视频数据。
以下是测试代码,参考 https://ken.tossell.net/libuvc/doc/
namespace {
void cb(uvc_frame_t* frame, void* ptr)
{
// We'll convert the image from YUV/JPEG to BGR, so allocate space
uvc_frame_t* bgr = uvc_allocate_frame(frame->width * frame->height * 3);
if (!bgr) {
printf("unable to allocate bgr frame!\n");
return;
}
// Do the BGR conversion
uvc_error_t ret = uvc_any2bgr(frame, bgr);
if (ret) {
uvc_perror(ret, "uvc_any2bgr");
uvc_free_frame(bgr);
return;
}
/* 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);
}
} // namespace
int test_libuvc_get_webcam_info()
{
// reference: https://ken.tossell.net/libuvc/doc/
// 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.
uvc_context_t* ctx = nullptr;
uvc_error_t res = uvc_init(&ctx, nullptr);
if (res < 0) {
uvc_perror(res, "uvc_init");
return res;
}
fprintf(stdout, "UVC initialized\n");
// Locates the first attached UVC device, stores in dev
uvc_device_t* dev = nullptr;
uvc_device_handle_t* devh = nullptr;
res = uvc_find_device(ctx, &dev, 0, 0, nullptr); // filter devices: vendor_id, product_id, "serial_num"
if (res < 0) {
uvc_perror(res, "uvc_find_device"); // no devices found
} else {
fprintf(stdout, "Device found\n");
// 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 {
fprintf(stdout, "Device opened\n");
// Print out a message containing all the information that libuvc knows about the device
uvc_print_diag(devh, stderr);
// Try to negotiate a 640x480 30 fps YUYV stream profile
uvc_stream_ctrl_t ctrl;
res = uvc_get_stream_ctrl_format_size(
devh, &ctrl, /* result stored in ctrl */
UVC_FRAME_FORMAT_YUYV, /* YUV 422, aka YUV 4:2:2. try _COMPRESSED */
640, 480, 30 /* 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
return res;
} else {
// Start the video stream. The library will call user function cb: cb(frame, (void*) 12345)
void* user_ptr = nullptr;
res = uvc_start_streaming(devh, &ctrl, cb, user_ptr, 0);
if (res < 0) {
uvc_perror(res, "start_streaming"); // unable to start stream
} else {
fprintf(stdout, "Streaming...\n");
uvc_set_ae_mode(devh, 1); // e.g., turn on auto exposure
std::this_thread::sleep_for(std::chrono::seconds(1)); // stream for 1 seconds
// End the stream. Blocks until last callback is serviced
uvc_stop_streaming(devh);
fprintf(stdout, "Done streaming.\n");
}
}
// Release our handle on the device
uvc_close(devh);
fprintf(stdout, "Device closed\n");
}
// 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);
fprintf(stdout, "UVC exited\n");
return 0;
}
执行结果如下:
GitHub:https://github.com/fengbingchun/OpenCV_Test