USB UVC 2-- libuvc

书接上回:USB UVC 1-- 基础-CSDN博客

主页:GitHub - libuvc/libuvc: a cross-platform library for USB video devices

1 概述

libuvc基本上是一个HOST端的库,在windows下是不需要了,在linux下可能用得上。结构是什么样的呢?大概如下:

UVC

USB

OS  <------------------>  Device

libuvc就是在标准的USB协议之上,增加了USB camera的控制功能。从我对USB协议的一些理解,USB和一般协议的区别就是自发现,要实现自发现,就多了一个设备协商,能力协商的过程。先是设备协商,再匹配找到的驱动。然后是能力协商,根据能力选择不同的通道。

还是看看具体的代码把。它的代码里面有两个示例。一个example,一个test,基本上大同小异。不过example.c更完善一丢丢,所以用它看吧。。。

从大的流程来看,是这样的顺序:

uvc_init->uvc_find_device->uvc_open(uvc_print_diag)->uvc_get_stream_ctrl_format_size(uvc_print_stream_ctrl)->uvc_stop_streaming->uvc_close->uvc_unref_device。

2 具体流程

2.1 uvc_init

主要就是调用了libusb_init,对下面的结构的usb_ctx进行了初始化。因为libusb_init没法跟,所以具体也不清楚,应该主要是USB通信的部分。

/** Context within which we communicate with devices */
struct uvc_context {
  /** Underlying context for USB communication */
  struct libusb_context *usb_ctx;
  /** True iff libuvc initialized the underlying USB context */
  uint8_t own_usb_ctx;
  /** List of open devices in this context */
  uvc_device_handle_t *open_devices;
  pthread_t handler_thread;
  int kill_handler_thread;
};

2.2 uvc_find_device

主要是调用了uvc_get_device_list,uvc_get_device_descriptor。首先是获取了所有的USB设备(有分支持热拔插和不支持热拔插),用list组织。里面具体很多内容应该是和USB协议相关的。

判断是看每个设备的interface,一个设备应该是多个interface。判断UVC的话用的下面这个, bInterfaceClass:

查了一下bInterfaceClass这个,说明如下,所以14就是视频设备。

找到UVC数据之后,将信息保存在uvc_device结构中,就是上下文和该usb设备信息。如下:

struct uvc_device {
  struct uvc_context *ctx;
  int ref;
  libusb_device *usb_dev;
};

2.3 uvc_open

这个部分的内容就比较多,首先还是libusb_open,然后uvc_get_device_info,获取设备的具体能力,uvc_claim_if,这里申明UVC的接口。然后就是一套,libusb_get_device_descriptor,libusb_fill_interrupt_transfer,libusb_submit_transfer(是 libusb 库中的一个函数,用于将 USB 传输请求提交给 USB 设备。它的作用是向 USB 设备发送一个传输请求,并在请求完成后通知应用程序)。

整个部分应该是打开设备,准备传输。目前在libusb_open打开的时候报错-3,查了一下是权限问题(Linux下权限问题真的防不胜防啊!!!),运行下面命令可以搞定。

sudo chmod -R 777 /dev/bus/usb/

主要用的函数是int libusb_open(libusb_device *dev, libusb_device_handle **dev_handle)

参数说明:

  • dev:要打开的 USB 设备的指针。
  • dev_handle:用于接收指向表示打开设备的设备句柄的指针的指针。

dev就是在上面打开的dev。dev_handle就是打开之后返回的handle。我理解是类似fope,要进入准备读写的状态。同时加锁。

我用的是PDD买的10块钱包邮的摄像头,打印的信息如下,这些都是UVC中control interface和streaming interface的信息,是比较重要的信息了。

DEVICE CONFIGURATION (18ec:3399/[none]) ---
Status: idle
VideoControl:
        bcdUVC: 0x0100
VideoStreaming(1):
        bEndpointAddress: 131
        Formats:
        UncompressedFormat(1)
                  bits per pixel: 16
                  GUID: 5955593200001000800000aa00389b71 (YUY2)
                  default frame: 1
                  aspect ratio: 0x0
                  interlace flags: 00
                  copy protect: 00
                        FrameDescriptor(1)
                          capabilities: 00
                          size: 640x480
                          bit rate: 24576000-147456000
                          max frame size: 614400
                          default interval: 1/30
                          interval[0]: 1/30
                          interval[1]: 1/15
                          interval[2]: 1/10
                          interval[3]: 1/5
                        FrameDescriptor(2)
                          capabilities: 00
                          size: 160x120
                          bit rate: 24576000-147456000
                          max frame size: 38400
                          default interval: 1/30
                          interval[0]: 1/30
                          interval[1]: 1/15
                          interval[2]: 1/10
                          interval[3]: 1/5
                        FrameDescriptor(3)
                          capabilities: 00
                          size: 176x144
                          bit rate: 24576000-147456000
                          max frame size: 50688
                          default interval: 1/30
                          interval[0]: 1/30
                          interval[1]: 1/15
                          interval[2]: 1/10
                          interval[3]: 1/5
                        FrameDescriptor(4)
                          capabilities: 00
                          size: 320x240
                          bit rate: 24576000-147456000
                          max frame size: 153600
                          default interval: 1/30
                          interval[0]: 1/30
                          interval[1]: 1/15
                          interval[2]: 1/10
                          interval[3]: 1/5
                        FrameDescriptor(5)
                          capabilities: 00
                          size: 352x288
                          bit rate: 24576000-147456000
                          max frame size: 202752
                          default interval: 1/30
                          interval[0]: 1/30
                          interval[1]: 1/15
                          interval[2]: 1/10
                          interval[3]: 1/5
                        StillFrameDescriptor
                          bEndPointAddress: 00
                          wWidth(1) = 640
                          wHeight(1) = 480
                          wWidth(2) = 160
                          wHeight(2) = 120
                          wWidth(3) = 176
                          wHeight(3) = 144
                          wWidth(4) = 320
                          wHeight(4) = 240
                          wWidth(5) = 352
                          wHeight(5) = 288
END DEVICE CONFIGURATION

2.4 uvc_get_stream_ctrl_format_size

这部分是协商传输的格式和尺寸,用设置的尺寸,帧率等,去轮询匹配streaming interface的规格。视频类独有。完了输出匹配的结果。

First format: (YUY2) 640x480 30fps
bmHint: 0001
bFormatIndex: 1
bFrameIndex: 1
dwFrameInterval: 333333
wKeyFrameRate: 0
wPFrameRate: 0
wCompQuality: 0
wCompWindowSize: 0
wDelay: 0
dwMaxVideoFrameSize: 614400
dwMaxPayloadTransferSize: 3000
bInterfaceNumber: 1
2.5 uvc_start_streaming

开始传输。这个是stream的核心数据结构,操作都是围绕着这个来的。

struct uvc_stream_handle {
  struct uvc_device_handle *devh;
  struct uvc_stream_handle *prev, *next;
  struct uvc_streaming_interface *stream_if;

  /** if true, stream is running (streaming video to host) */
  uint8_t running;
  /** Current control block */
  struct uvc_stream_ctrl cur_ctrl;

  /* listeners may only access hold*, and only when holding a
   * lock on cb_mutex (probably signaled with cb_cond) */
  uint8_t fid;
  uint32_t seq, hold_seq;
  uint32_t pts, hold_pts;
  uint32_t last_scr, hold_last_scr;
  size_t got_bytes, hold_bytes;
  uint8_t *outbuf, *holdbuf;
  pthread_mutex_t cb_mutex;
  pthread_cond_t cb_cond;
  pthread_t cb_thread;
  uint32_t last_polled_seq;
  uvc_frame_callback_t *user_cb;
  void *user_ptr;
  struct libusb_transfer *transfers[LIBUVC_NUM_TRANSFER_BUFS];
  uint8_t *transfer_bufs[LIBUVC_NUM_TRANSFER_BUFS];
  struct uvc_frame frame;
  enum uvc_frame_format frame_format;
  struct timespec capture_time_finished;

  /* raw metadata buffer if available */
  uint8_t *meta_outbuf, *meta_holdbuf;
  size_t meta_got_bytes, meta_hold_bytes;
};

在这里,使用了两个buf,一个out_buffer,一个hold_buf。之前好像是在哪看到过这种双缓冲的机制。之后就是生产者消费者的常规操作。

pthread_mutex_init(&strmh->cb_mutex, NULL);
pthread_cond_init(&strmh->cb_cond, NULL);

之后的传输要看是同步还是非同步。如果是非同步,那还比较简单。libusb_alloc_transfer和libusb_fill_bulk_transfer就行了。

同步看起来是设置了最大帧长度,还有备份端口,在有多个备用端口的时候使用同步传输isochronous transfers,具体空了再看吧。。。

最后调用libusb_submit_transfer发送数据。

2.6 uvc_stop_streaming

主要调用的是libusb_cancel_transfer,就是停掉生产者消费者,停掉usb的传输,然后清除内存,关闭端口。

2.7 uvc_close

这个相对就简单点,直接调用的libusb_close,关闭interface,还有清掉usb引用。

2.8 uvc_set_ae_mode

中途修改属性,这里是自动曝光,其实就是直接组一个usb包就可以了。。

  ret = libusb_control_transfer(
    devh->usb_devh,
    REQ_TYPE_SET, UVC_SET_CUR,
    UVC_CT_AE_MODE_CONTROL << 8,
    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
    data,
    sizeof(data),
    0);

跟了一阵代码,发觉还是要对libusb,还有USB协议要有一定了解才行,空了再说吧。。。

参考:

libusb API学习笔记-2 - 简书

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值