libuvc与webcam的开发(二) - UVCCamera中的libuvc

libuvc是github上一个开源项目,用于实现uvc基础协议,目前的源码实现支持到UVC1.1版本。UVCCamera中包含有完整的libuvc,它针对安卓系统进行了部分改进,同时增加了对UVC1.5版本的支持,不过目前看还不支持H.264协议。这里准备以UVCCamera项目中的libuvc为例进行流程分析,不光是因为其改进部分,而且UVCCamera中也带有完整的libusb源码库,这个对于分析某些接口函数是很有帮助的。

标准版 libuvc

地址:
https://github.com/ktossell/libuvc
文档:
https://int80k.com/libuvc/doc/

下面是libuvc在GitHub上的文件结构,并不复杂,主要的代码也都放在src文件夹中,从更新历史上看,这个项目更新频率不算太高,主体部分大致也有三年没有改过了,毕竟uvc1.5协议从2012年推出后,USB.org再未有新的协议更新:


下面是主要源代码的文件结构,文件不多,其中example.c和test.c是样例代码和验证代码,因此实际有效的文件也就不到十个,是一个小而美的经典项目,难怪Android官方也推荐它:


source code

libuvc由下面几个主要功能模块构成:


module

其中,

模块名 对应的文件 功能描述
Video capture and processing controls ctrl-gen.c & ctrl.c 读取或更新设备相关配置,比如自动曝光、对焦、白平衡等参数
Device handling and enumeration device.c 设备相关操作,包括发现设备、打开设备、释放设备等
Diagnostics diag.c 一些打印函数,用于输出诊断信息
Frame processing frame.c & frame-mjepg.c 帧处理相关函数,用于管理帧缓冲区以及图像格式转换
Library initialization/deinitialization init.c 建立UVC访问上下文
Streaming control functions stream.c 视频流数据的相关处理函数
misc.c 一些辅助函数可以放在这里

除了功能函数,还有一些重要的数据结构:


Data Structure

这里列两个比较常用的,剩下的可自行参考手册:

uvc_device_descriptor


uvc_frame_desc

可以通过example.c中的例子去学习如何使用libuvc:

#include "libuvc/libuvc.h"
#include 
/* 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;
  /* 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!");
    return;
  }
  /* Do the BGR conversion */
  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);
}
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);
      /* Try to negotiate a 640x480 30 fps YUYV stream profile */
      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 */
      } else {
        /* Start the video stream. The library will call user function cb:
         *   cb(frame, (void*) 12345)
         */
        res = uvc_start_streaming(devh, &ctrl, cb, 12345, 0);
        if (res < 0) {
          uvc_perror(res, "start_streaming"); /* unable to start stream */
        } else {
          puts("Streaming...");
          uvc_set_ae_mode(devh, 1); /* e.g., turn on auto exposure */
          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;
}

UVCCamera中的libuvc

你可能感兴趣的:(libuvc与webcam的开发(二) - UVCCamera中的libuvc)