UVC批量传输技术探讨

原创 漫谈嵌入式 2022-09-29 20:26

1.描述符布局

如图为 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 提交给设备,让其以指定的数据格式进行数据采样。

2.2 stream off

关流操作,通过抓包可以看到,通过发送一个clear_halt 请求,来中断流的操作。

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图像能够极大提高帧率。

如果有合适的方式控制流程,欢迎讨论!


漫谈嵌入式 一个爱跑马的程序员。致力于分享嵌入式物联网技术【单片机/MIPS/ARM/Linux/C/C++/Qt等】,探寻底层开发的究竟!
评论
  •  万万没想到!科幻电影中的人形机器人,正在一步步走进我们人类的日常生活中来了。1月17日,乐聚将第100台全尺寸人形机器人交付北汽越野车,再次吹响了人形机器人疯狂进厂打工的号角。无独有尔,银河通用机器人作为一家成立不到两年时间的创业公司,在短短一年多时间内推出革命性的第一代产品Galbot G1,这是一款轮式、双臂、身体可折叠的人形机器人,得到了美团战投、经纬创投、IDG资本等众多投资方的认可。作为一家成立仅仅只有两年多时间的企业,智元机器人也把机器人从梦想带进了现实。2024年8月1
    刘旷 2025-01-21 11:15 390浏览
  • 高速先生成员--黄刚这不马上就要过年了嘛,高速先生就不打算给大家上难度了,整一篇简单但很实用的文章给大伙瞧瞧好了。相信这个标题一出来,尤其对于PCB设计工程师来说,心就立马凉了半截。他们辛辛苦苦进行PCB的过孔设计,高速先生居然说设计多大的过孔他们不关心!另外估计这时候就跳出很多“挑刺”的粉丝了哈,因为翻看很多以往的文章,高速先生都表达了过孔孔径对高速性能的影响是很大的哦!咋滴,今天居然说孔径不关心了?别,别急哈,听高速先生在这篇文章中娓娓道来。首先还是要对各位设计工程师的设计表示肯定,毕竟像我
    一博科技 2025-01-21 16:17 100浏览
  • 现在为止,我们已经完成了Purple Pi OH主板的串口调试和部分配件的连接,接下来,让我们趁热打铁,完成剩余配件的连接!注:配件连接前请断开主板所有供电,避免敏感电路损坏!1.1 耳机接口主板有一路OTMP 标准四节耳机座J6,具备进行音频输出及录音功能,接入耳机后声音将优先从耳机输出,如下图所示:1.21.2 相机接口MIPI CSI 接口如上图所示,支持OV5648 和OV8858 摄像头模组。接入摄像头模组后,使用系统相机软件打开相机拍照和录像,如下图所示:1.3 以太网接口主板有一路
    Industio_触觉智能 2025-01-20 11:04 150浏览
  • Ubuntu20.04默认情况下为root账号自动登录,本文介绍如何取消root账号自动登录,改为通过输入账号密码登录,使用触觉智能EVB3568鸿蒙开发板演示,搭载瑞芯微RK3568,四核A55处理器,主频2.0Ghz,1T算力NPU;支持OpenHarmony5.0及Linux、Android等操作系统,接口丰富,开发评估快人一步!添加新账号1、使用adduser命令来添加新用户,用户名以industio为例,系统会提示设置密码以及其他信息,您可以根据需要填写或跳过,命令如下:root@id
    Industio_触觉智能 2025-01-17 14:14 121浏览
  • 数字隔离芯片是一种实现电气隔离功能的集成电路,在工业自动化、汽车电子、光伏储能与电力通信等领域的电气系统中发挥着至关重要的作用。其不仅可令高、低压系统之间相互独立,提高低压系统的抗干扰能力,同时还可确保高、低压系统之间的安全交互,使系统稳定工作,并避免操作者遭受来自高压系统的电击伤害。典型数字隔离芯片的简化原理图值得一提的是,数字隔离芯片历经多年发展,其应用范围已十分广泛,凡涉及到在高、低压系统之间进行信号传输的场景中基本都需要应用到此种芯片。那么,电气工程师在进行电路设计时到底该如何评估选择一
    华普微HOPERF 2025-01-20 16:50 73浏览
  • 2024年是很平淡的一年,能保住饭碗就是万幸了,公司业绩不好,跳槽又不敢跳,还有一个原因就是老板对我们这些员工还是很好的,碍于人情也不能在公司困难时去雪上加霜。在工作其间遇到的大问题没有,小问题还是有不少,这里就举一两个来说一下。第一个就是,先看下下面的这个封装,你能猜出它的引脚间距是多少吗?这种排线座比较常规的是0.6mm间距(即排线是0.3mm间距)的,而这个规格也是我们用得最多的,所以我们按惯性思维来看的话,就会认为这个座子就是0.6mm间距的,这样往往就不会去细看规格书了,所以这次的运气
    wuliangu 2025-01-21 00:15 183浏览
  •     IPC-2581是基于ODB++标准、结合PCB行业特点而指定的PCB加工文件规范。    IPC-2581旨在替代CAM350格式,成为PCB加工行业的新的工业规范。    有一些免费软件,可以查看(不可修改)IPC-2581数据文件。这些软件典型用途是工艺校核。    1. Vu2581        出品:Downstream     
    电子知识打边炉 2025-01-22 11:12 49浏览
  •  光伏及击穿,都可视之为 复合的逆过程,但是,复合、光伏与击穿,不单是进程的方向相反,偏置状态也不一样,复合的工况,是正偏,光伏是零偏,击穿与漂移则是反偏,光伏的能源是外来的,而击穿消耗的是结区自身和电源的能量,漂移的载流子是 客席载流子,须借外延层才能引入,客席载流子 不受反偏PN结的空乏区阻碍,能漂不能漂,只取决于反偏PN结是否处于外延层的「射程」范围,而穿通的成因,则是因耗尽层的过度扩张,致使跟 端子、外延层或其他空乏区 碰触,当耗尽层融通,耐压 (反向阻断能力) 即告彻底丧失,
    MrCU204 2025-01-17 11:30 182浏览
  • 随着消费者对汽车驾乘体验的要求不断攀升,汽车照明系统作为确保道路安全、提升驾驶体验以及实现车辆与环境交互的重要组成,日益受到业界的高度重视。近日,2024 DVN(上海)国际汽车照明研讨会圆满落幕。作为照明与传感创新的全球领导者,艾迈斯欧司朗受邀参与主题演讲,并现场展示了其多项前沿技术。本届研讨会汇聚来自全球各地400余名汽车、照明、光源及Tier 2供应商的专业人士及专家共聚一堂。在研讨会第一环节中,艾迈斯欧司朗系统解决方案工程副总裁 Joachim Reill以深厚的专业素养,主持该环节多位
    艾迈斯欧司朗 2025-01-16 20:51 195浏览
  • 80,000人到访的国际大展上,艾迈斯欧司朗有哪些亮点?感未来,光无限。近日,在慕尼黑electronica 2024现场,ams OSRAM通过多款创新DEMO展示,以及数场前瞻洞察分享,全面展示自身融合传感器、发射器及集成电路技术,精准捕捉并呈现环境信息的卓越能力。同时,ams OSRAM通过展会期间与客户、用户等行业人士,以及媒体朋友的深度交流,向业界传达其以光电技术为笔、以创新为墨,书写智能未来的深度思考。electronica 2024electronica 2024构建了一个高度国际
    艾迈斯欧司朗 2025-01-16 20:45 423浏览
  • 日前,商务部等部门办公厅印发《手机、平板、智能手表(手环)购新补贴实施方案》明确,个人消费者购买手机、平板、智能手表(手环)3类数码产品(单件销售价格不超过6000元),可享受购新补贴。每人每类可补贴1件,每件补贴比例为减去生产、流通环节及移动运营商所有优惠后最终销售价格的15%,每件最高不超过500元。目前,京东已经做好了承接手机、平板等数码产品国补优惠的落地准备工作,未来随着各省市关于手机、平板等品类的国补开启,京东将第一时间率先上线,满足消费者的换新升级需求。为保障国补的真实有效发放,基于
    华尔街科技眼 2025-01-17 10:44 221浏览
  • 临近春节,各方社交及应酬也变得多起来了,甚至一月份就排满了各式约见。有的是关系好的专业朋友的周末“恳谈会”,基本是关于2025年经济预判的话题,以及如何稳定工作等话题;但更多的预约是来自几个客户老板及副总裁们的见面,他们为今年的经济预判与企业发展焦虑而来。在聊天过程中,我发现今年的聊天有个很有意思的“点”,挺多人尤其关心我到底是怎么成长成现在的多领域风格的,还能掌握一些经济趋势的分析能力,到底学过哪些专业、在企业管过哪些具体事情?单单就这个一个月内,我就重复了数次“为什么”,再辅以我上次写的:《
    牛言喵语 2025-01-22 17:10 41浏览
  • 嘿,咱来聊聊RISC-V MCU技术哈。 这RISC-V MCU技术呢,简单来说就是基于一个叫RISC-V的指令集架构做出的微控制器技术。RISC-V这个啊,2010年的时候,是加州大学伯克利分校的研究团队弄出来的,目的就是想搞个新的、开放的指令集架构,能跟上现代计算的需要。到了2015年,专门成立了个RISC-V基金会,让这个架构更标准,也更好地推广开了。这几年啊,这个RISC-V的生态系统发展得可快了,好多公司和机构都加入了RISC-V International,还推出了不少RISC-V
    丙丁先生 2025-01-21 12:10 111浏览
  • 本文介绍瑞芯微开发板/主板Android配置APK默认开启性能模式方法,开启性能模式后,APK的CPU使用优先级会有所提高。触觉智能RK3562开发板演示,搭载4核A53处理器,主频高达2.0GHz;内置独立1Tops算力NPU,可应用于物联网网关、平板电脑、智能家居、教育电子、工业显示与控制等行业。源码修改修改源码根目录下文件device/rockchip/rk3562/package_performance.xml并添加以下内容,注意"+"号为添加内容,"com.tencent.mm"为AP
    Industio_触觉智能 2025-01-17 14:09 164浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦