UVC 批量传输技术探讨

简介: UVC 批量传输技术探讨

1.描述符布局


image.png


如图为 bulk 传输描述符布局,相对于同步传输,批量传输只有一个可选择的配置,没有备用配置。


  • VideoControl :无变化


  • VideoStream:只有一个 bAlternateSetting(删除alt=1描述符)。同时支持bulk in 端点。


需要修改的地方:


static struct usb_interface_descriptor uvc_streaming_intf_alt0 = {
 .bLength  = USB_DT_INTERFACE_SIZE,
 .bDescriptorType = USB_DT_INTERFACE,
 .bInterfaceNumber = UVC_INTF_VIDEO_STREAMING,
 .bAlternateSetting = 0,
 .bNumEndpoints  = 1,            /* alt0 挂一个bulk 端点*/
 .bInterfaceClass = USB_CLASS_VIDEO,
 .bInterfaceSubClass = UVC_SC_VIDEOSTREAMING,
 .bInterfaceProtocol = 0x00,
 .iInterface  = 0,
};


端点描述符:


static struct usb_endpoint_descriptor uvc_hs_streaming_ep = {
 .bLength  = USB_DT_ENDPOINT_SIZE,
 .bDescriptorType = USB_DT_ENDPOINT,
 .bEndpointAddress = USB_DIR_IN,
 .bmAttributes  = USB_ENDPOINT_XFER_BULK,
    .wMaxPacketSize = 512,
    .bInterval = 0,
};


2. 控制流程


根据USB规范可知,同步传输方式是只要带中带有同步端点的接口,系统会定时从设备中读取数据,无论设备中是否有数据。而如要停止数据的传输,只需要选中不带有同步端点的接口即可。


USB同步传输这种灵活的数据传输方式是依靠视频流接口的转换接口即我们常说的备份接口实现的。在默认情况下数据不传输时,视频数据流接口和备份接口ID为0,其它的备份接口是可根据视频数据传输的大小可按需选择。


我们知道,批量传输只有一个可选择的altsetting ,那么如何知道设备控制设备的开流和关流动作呢?


2.1 stream on


使用视频流接口的VS_COMMIT_CONTROL 提交给设备,让其以指定的数据格式进行数据采样。


image.png


2.2 stream off


关流操作,通过发送一个clear_halt 请求,来中断流的操作。


image.png


2.3 代码分析


基于 linux 4.14.281 内核版本:分析host 端uvc 开关流流程


  • drivers/media/usb/uvc/uvc_queue.c


开流操作:uvc_start_streaming


static int uvc_start_streaming(struct vb2_queue *vq, unsigned int count)
{
 struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
 struct uvc_streaming *stream = uvc_queue_to_stream(queue);
 unsigned long flags;
 int ret;
 queue->buf_used = 0;
 ret = uvc_video_enable(stream, 1);
 if (ret == 0)
  return 0;
 spin_lock_irqsave(&queue->irqlock, flags);
 uvc_queue_return_buffers(queue, UVC_BUF_STATE_QUEUED);
 spin_unlock_irqrestore(&queue->irqlock, flags);
 return ret;
}


关流操作:uvc_stop_streaming


static void uvc_stop_streaming(struct vb2_queue *vq)
{
 struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
 struct uvc_streaming *stream = uvc_queue_to_stream(queue);
 unsigned long flags;
 uvc_video_enable(stream, 0);
 spin_lock_irqsave(&queue->irqlock, flags);
 uvc_queue_return_buffers(queue, UVC_BUF_STATE_ERROR);
 spin_unlock_irqrestore(&queue->irqlock, flags);
}


重点关注:uvc_video_enable


/*
 * Enable or disable the video stream.
 */
int uvc_video_enable(struct uvc_streaming *stream, int enable)
{
 int ret;
 if (!enable) {
  uvc_uninit_video(stream, 1);
  if (stream->intf->num_altsetting > 1) {
   usb_set_interface(stream->dev->udev,
       stream->intfnum, 0);
  } else {
   /* UVC doesn't specify how to inform a bulk-based device
    * when the video stream is stopped. Windows sends a
    * CLEAR_FEATURE(HALT) request to the video streaming
    * bulk endpoint, mimic the same behaviour.
    */
   unsigned int epnum = stream->header.bEndpointAddress
        & USB_ENDPOINT_NUMBER_MASK;
   unsigned int dir = stream->header.bEndpointAddress
      & USB_ENDPOINT_DIR_MASK;
   unsigned int pipe;
   pipe = usb_sndbulkpipe(stream->dev->udev, epnum) | dir;
   usb_clear_halt(stream->dev->udev, pipe);
  }
  uvc_video_clock_cleanup(stream);
  return 0;
 }
 ret = uvc_video_clock_init(stream);
 if (ret < 0)
  return ret;
 /* Commit the streaming parameters. */
 ret = uvc_commit_video(stream, &stream->ctrl);
 if (ret < 0)
  goto error_commit;
 ret = uvc_init_video(stream, GFP_KERNEL);
 if (ret < 0)
  goto error_video;
 return 0;
error_video:
 usb_set_interface(stream->dev->udev, stream->intfnum, 0);
error_commit:
 uvc_video_clock_cleanup(stream);
 return ret;
}


分析代码可知:


  • 首先判断是否关流操作;


  • 如果是,判断接口的可选配置是否大于1,如果大于1,发送usb_set_interface(intfnum,0) 关流,否则发送usb_clear_halt 请求;


  • 如果是开流操作,发送commit 请求


  • 然后初始化 video


/*
 * Initialize isochronous/bulk URBs and allocate transfer buffers.
 */
static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
{
 struct usb_interface *intf = stream->intf;
 struct usb_host_endpoint *ep;
 unsigned int i;
 int ret;
 stream->sequence = -1;
 stream->last_fid = -1;
 stream->bulk.header_size = 0;
 stream->bulk.skip_payload = 0;
 stream->bulk.payload_size = 0;
 uvc_video_stats_start(stream);
 if (intf->num_altsetting > 1) {
  struct usb_host_endpoint *best_ep = NULL;
  unsigned int best_psize = UINT_MAX;
  unsigned int bandwidth;
  unsigned int uninitialized_var(altsetting);
  int intfnum = stream->intfnum;
  /* Isochronous endpoint, select the alternate setting. */
  bandwidth = stream->ctrl.dwMaxPayloadTransferSize;
  if (bandwidth == 0) {
   uvc_trace(UVC_TRACE_VIDEO, "Device requested null "
    "bandwidth, defaulting to lowest.\n");
   bandwidth = 1;
  } else {
   uvc_trace(UVC_TRACE_VIDEO, "Device requested %u "
    "B/frame bandwidth.\n", bandwidth);
  }
  for (i = 0; i < intf->num_altsetting; ++i) {
   struct usb_host_interface *alts;
   unsigned int psize;
   alts = &intf->altsetting[i];
   ep = uvc_find_endpoint(alts,
    stream->header.bEndpointAddress);
   if (ep == NULL)
    continue;
   /* Check if the bandwidth is high enough. */
   psize = uvc_endpoint_max_bpi(stream->dev->udev, ep);
   if (psize >= bandwidth && psize <= best_psize) {
    altsetting = alts->desc.bAlternateSetting;
    best_psize = psize;
    best_ep = ep;
   }
  }
  if (best_ep == NULL) {
   uvc_trace(UVC_TRACE_VIDEO, "No fast enough alt setting "
    "for requested bandwidth.\n");
   return -EIO;
  }
  uvc_trace(UVC_TRACE_VIDEO, "Selecting alternate setting %u "
   "(%u B/frame bandwidth).\n", altsetting, best_psize);
  ret = usb_set_interface(stream->dev->udev, intfnum, altsetting);
  if (ret < 0)
   return ret;
  ret = uvc_init_video_isoc(stream, best_ep, gfp_flags);
 } else {
  /* Bulk endpoint, proceed to URB initialization. */
  ep = uvc_find_endpoint(&intf->altsetting[0],
    stream->header.bEndpointAddress);
  if (ep == NULL)
   return -EIO;
  /* Reject broken descriptors. */
  if (usb_endpoint_maxp(&ep->desc) == 0)
   return -EIO;
  ret = uvc_init_video_bulk(stream, ep, gfp_flags);
 }
 if (ret < 0)
  return ret;
 /* Submit the URBs. */
 for (i = 0; i < UVC_URBS; ++i) {
  ret = usb_submit_urb(stream->urb[i], gfp_flags);
  if (ret < 0) {
   uvc_printk(KERN_ERR, "Failed to submit URB %u "
     "(%d).\n", i, ret);
   uvc_uninit_video(stream, 1);
   return ret;
  }
 }
 /* The Logitech C920 temporarily forgets that it should not be adjusting
  * Exposure Absolute during init so restore controls to stored values.
  */
 if (stream->dev->quirks & UVC_QUIRK_RESTORE_CTRLS_ON_INIT)
  uvc_ctrl_restore_values(stream->dev);
 return 0;
}


从这段代码可以看出,如果altsetting 大于1 走同步传输,发送usb_set_interface(intfnum, altsetting) ,选择合适带宽配置。然后初始化同步传输管道。


否则,初始化 同步传输管道,提交传输。


3. 其他注意点


对比同步传输和批量传输我们可以发现,对于uvc 批量传输, 由于没有同步传输类似的多个可选配置,所以没法灵活控制开流关流操作。特别是在linux 平台下,要切换不同的格式和分辨率的时候没有同步传输方便。


故,笔者觉得同步传输适合传固定数据,或者对usb camera 做中转使用比较合适。


对于批量传输如果能充分发送usb 吞吐量,(USB2.0)一个微帧传输13个packet,理论带宽将近50MB/s, 笔者实际测试能达到47MB/s,对于YUYV图像能够极大提高帧率。

相关文章
|
3月前
|
NoSQL 算法 Linux
OpenOCD下载安装保姆级教程(附安装包,非常详细)
OpenOCD是一款开源片上调试工具,支持JTAG/SWD接口,提供GDB Server、TCL脚本自动化等功能,可实现断点调试、Flash烧录、FPGA编程等,广泛应用于嵌入式开发与量产测试,被誉为“穷人的Lauterbach”。跨平台且免费,配置灵活但稍复杂,是嵌入式工程师的高效调试利器。
|
开发者
在代码维护中,Qwen-coder可以通过多种方式提升编程效率和代码质量
Qwen-coder在代码维护中发挥着重要作用,帮助开发者提高代码质量,减少错误,提升开发效率。这些功能使得Qwen-coder成为代码维护和开发过程中的有力助手。
631 52
|
机器学习/深度学习 自动驾驶 机器人
深度学习之3D场景重建
基于深度学习的3D场景重建是通过深度学习技术从多视角图像或视频数据中重建三维场景结构的过程。它在计算机视觉、增强现实、虚拟现实、机器人导航和自动驾驶等多个领域具有广泛应用。
836 4
|
Ubuntu 安全 网络协议
|
编解码 Linux 计算机视觉
python 调用ffmpeg使用usb摄像头录制视频,输出h264格式,自动获取摄像头的最佳帧率和最大画面尺寸
使用 Python 调用 FFmpeg 进行 USB 摄像头视频录制,需先确保安装 FFmpeg 和 Python 的 `subprocess` 模块。代码示例展示了如何自动获取摄像头的最佳帧率和最大分辨率,然后录制视频。首先通过 FFmpeg 列出摄像头格式获取信息,解析出帧率和分辨率,选择最优值。之后调用 FFmpeg 命令录制视频,设置帧率、分辨率等参数。注意 `/dev/video0` 是 Linux 的摄像头设备路径,Windows 系统需相应调整。代码中未直接实现自动获取最佳参数,通常需要借助其他库如 OpenCV。
|
Ubuntu Linux Shell
【linux】PetaLinux 2024.1安装笔记
【linux】PetaLinux 2024.1安装笔记
2217 0
|
传感器 编解码 Linux
V4L2框架 | MIPI Camera指令调试笔记
V4L2框架 | MIPI Camera指令调试笔记
8401 2
|
编解码 C++ 索引
UVC 基础学习(5):VideoStream Interface 描述符介绍
今天我们继续学习UVC的接口描述符:VideoStream 。 VideoStream 接口描述符是整个UVC设备最重要的组成之一,和VideoControl一样,其也包含标准接口和特殊类接口。
1752 0
|
安全 Linux API
Keystore、Key attestation
Keystore、Key attestation
910 0
Keystore、Key attestation
|
开发工具 C语言 git
libusb + libuvc 环境搭建
libusb + libuvc 环境搭建
2758 0

热门文章

最新文章