UVC摄像头技术笔记
+ -

Linux源码分析UVC摄像头的打开流程及抓包分析

2021-04-01 1376 0

和关闭摄像头类似,Linux使用uvc_video_start_streaming函数打开摄像头

int uvc_video_start_streaming(struct uvc_streaming *stream)
{
    int ret;

    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_video_start_transfer(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;
}

从代码来看,首先要据当前的的配置使用选择子VS_COMMIT_CONTROL提交参数,后续就是开始传输。
开始传输的部分代码解释可参见前几节关于wMaxVideoFrameSize和dwMaxPayloadTransferSize参数的关系分析。这里只列出代码。
可以看到,这里区分了是同步传输还是批量传输。如果是同步传输,是需要根据dwMaxPayloadTransferSize选择合适的视频流端点的,如果是批量传输,则直接校验断该批量端点地址,后续就是分配相关的URB数据内存。

static int uvc_video_start_transfer(struct uvc_streaming *stream,
                    gfp_t gfp_flags)
{
    struct usb_interface *intf = stream->intf;
    struct usb_host_endpoint *ep;
    struct uvc_urb *uvc_urb;
    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 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;

        ret = uvc_init_video_bulk(stream, ep, gfp_flags);
    }

    if (ret < 0)
        return ret;

    /* Submit the URBs. */
    for_each_uvc_urb(uvc_urb, stream) {
        ret = usb_submit_urb(uvc_urb->urb, gfp_flags);
        if (ret < 0) {
            uvc_printk(KERN_ERR, "Failed to submit URB %u (%d).\n",
                   uvc_urb_index(uvc_urb), ret);
            uvc_video_stop_transfer(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;
}

UVC摄像头同步传输的打开

其抓包分析内容如下:

Device  Length    Phase  Data
------  --------  -----  ----------------------------------------------------- -------------
  47.0            CTL    a1 81 00 01  01 00 1a 00                              GET CUR      
  47.0        26  IN     01 00 01 03  15 16 05 00  00 00 00 00  00 00 00 00    .............
  47.0            CTL    21 01 00 01  01 00 1a 00                              SET CUR      
  47.0        26  OUT    01 00 01 03  15 16 05 00  00 00 00 00  00 00 00 00    .............
  47.0            CTL    a1 81 00 01  01 00 1a 00                              GET CUR      
  47.0        26  IN     01 00 01 03  15 16 05 00  00 00 00 00  00 00 00 00    .............
  47.0            CTL    a1 83 00 01  01 00 1a 00                              GET MAX      
  47.0        26  IN     00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00    .............
  47.0            CTL    a1 82 00 01  01 00 1a 00                              GET MIN      
  47.0        26  IN     00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00    .............
  47.0            CTL    21 01 00 01  01 00 1a 00                              SET CUR      
  47.0        26  OUT    01 00 01 03  15 16 05 00  00 00 00 00  00 00 00 00    .............
  47.0            CTL    a1 81 00 01  01 00 1a 00                              GET CUR      
  47.0        26  IN     01 00 01 03  15 16 05 00  00 00 00 00  00 00 00 00    .............
  47.0            CTL    21 01 00 02  01 00 1a 00                              SET CUR      
  47.0        26  OUT    01 00 01 03  15 16 05 00  00 00 00 00  00 00 00 00    .............
  47.0            CTL    01 0b 01 00  01 00 00 00                              SET INTERFACE

具体的分析过程可详见 UVC 打开UVC摄像头(特定类请求)数据分析

UVC摄像头批量传输的打开

Device   Length    Phase  Data            
44.0               CTL    a1 81 00 01  02 00 22 00                              GET CUR      
44.0       34      IN     01 00 01 01  15 16 05 00  00 00 00 00  00 00 00 00    .............
44.0               CTL    21 01 00 01  02 00 22 00                              SET CUR      
44.0       34      OUT    01 00 01 01  15 16 05 00  00 00 00 00  00 00 00 00    .............
44.0               CTL    a1 81 00 01  02 00 22 00                              GET CUR      
44.0       34      IN     01 00 01 01  15 16 05 00  00 00 00 00  00 00 00 00    .............
44.0               CTL    a1 83 00 01  02 00 22 00                              GET MAX      
44.0       34      IN     01 00 01 01  15 16 05 00  00 00 00 00  00 00 00 00    .............
44.0               CTL    a1 82 00 01  02 00 22 00                              GET MIN      
44.0       34      IN     01 00 01 01  15 16 05 00  00 00 00 00  00 00 00 00    .............
44.0               CTL    21 01 00 02  02 00 22 00                              SET CUR      
44.0       34      OUT    01 00 01 01  15 16 05 00  00 00 00 00  00 00 00 00    .............
44.0               CTL    01 0b 00 00  02 00 00 00                              SET INTERFACE
HID人机交互QQ群:564808376    UAC音频QQ群:218581009    UVC相机QQ群:331552032    BOT&UASP大容量存储QQ群:258159197    STC-USB单片机QQ群:315457461    USB技术交流QQ群2:580684376    USB技术交流QQ群:952873936   

0 篇笔记 写笔记

USB音箱 工作抓包分析
USB音响打开Length Phase Data -------- ----- ------------------------------ -------------- CTL ......
Linux V4L2 UVC摄像头框架浅析
V4L2 :video for linux version 2 ,是 Linux 里一套标准的视频驱动,它支持 UVC 标准的摄像头。本文来分析一下它的核心框架。整个v4l2的框架分为三层:在应用层,我们可以在 /dev 目录发现 video0 类似的设备节点,上层的摄像头程序打开设备节点进行......
linux下UsbMon-WireShark之USB协议抓取分析
usbmon配置使用usbmon抓包分的,是需要 内核开启CONFIG_USB_MON=m, 重新编译内核, 编译ko :make ARCH=arm64 CROSS_COMPILE=aarch64-himix100-linux- CONFIG_USB_MON=m M=./drivers/usb/ ......
打开UVC摄像头(特定类请求)数据分析
通过上节可以知道,设备支持4种的视频格式,且每种格式如下:MPJPG数据格式bFormatIndexbFrameIndex分辩率及及帧率11640x480x(30,15,10)121280x720x(30,15,10)131920x1080x(30,15......
UVC摄像头扩展单元功能的开发步骤是什么?
写在扩展单元的题外话本人在开发支持UVC扩展单元的directShow应用时,必现并不需要注册接口,只需要在其源过滤器参照后续的代码枚举相关的接口如IKsControl,IKsTopologyInfo定位到指定的扩展单元接口后,直接使用其对应的IKsControl::KsProperty即可实现扩展......
UVC摄像头的延迟reduce latency
一般的ISP,200W30帧来说,sensor进来缓存一帧就是33ms+vpu处理时间大概10ms+jpeg编码时间16ms+USB传输时间200KB大概7、8ms,最后就是windows上的显示延迟时间,如果JPEG编码出来缓存不止一帧,时间就更长了,所以一般会超过100多ms另外,网络传输如使......
UVC Windows下UVC摄像头数据分析
这里我们分析一款UVC摄像头来进行数据分析。环境:win10 x64工具:bushound,usbviewer将摄像头插入PC后,打开usbviewer工具,可以看到关于此摄像头的相关信息。可以看到,这个摄像头其实是一个USB复合设备,所以其对应的系统驱动为USBCCGP,然后再由USB复合设......
简易摄像头playcap工程代码及应用程序
playcap是一个小巧的UVC摄像头测试工具,使用的是DirectShow,本人之前装饰部分代码发布到此网址:http://www.usbzh.com/article/detail-553.html但经常有人说编译不过,其实这都是工程配置问题引起的。现将工程代码及编译好的应用程序提供详细的下载地......
Linux支持的UVC视频格式
Linux支持的UVC视频格式位于linux-5.6.11linux-5.6.11driversmediausbuvcuvc_driver.c文件下:其数组结构定义如下:static struct uvc_format_desc uvc_fmts[] = { { .n......
Windows下UVC虚拟摄像头的实现
最近在Windows10 x64环境下,开发了一个虚拟UVC摄像头驱动。确切的来说这不是摄像头驱动,而是一个虚拟USB总线驱动。使用该虚拟总线驱动使用应用软件通过IOCTL控制总线子设备的创建与卸载。驱动安装完成后,是一个单纯的USB虚拟总线。应用软件通过发送自定义IOCTL码IOCTL_BUSEN......
UVC摄像头的关闭流程及抓包分析
通过UVC协议规范可以知道,UVC的数据传输支持USB四种传输中的批量传输和同步传输,所以对于UVC摄像头,当我们在摄像头正在工作时,需要停止摄像头工作,执行的操作是不同的。在Linux的源代码中,摄像头的流关闭是由函数uvc_video_stop_streaming完成的。代码比较简单,我们直接给......
UVC摄像头批量传输的StreamOn和StreamOff
在UVC规范中,UVC摄像头视频数据的传输方式支持两种,分别为批量传输和同步传输。UVC摄像头数据传输的格式按负载数据头的方式按帧进行打包传输。根据USB规范可知,同步传输方式是只要带中带有同步端点的接口,系统会定时从设备中读取数据,无论设备中是否有数据。而如要要停止数据的传输,只需要选中不带有同步......
Linux源码分析UVC摄像头的初始化流程分析
UVC摄像头的初始化发生在硬件被接入USB集线器中,设备初USB驱动识别为摄像头的后续初始化流程。和Windows的AddDevice驱动函数一样,Linux设备的创建和侦测是通过int uvc_probe函数实现的。其函数的调用关系如下://linux/v5.11.11/source/drive......
Windows对红外相机摄像头的支持
从Windows10的1607版本开始,USB视频类(UVC)驱动程序支持产生红外(IR)流的摄像头。红外摄像头相机捕捉场景的亮度值,并通过USB以未压缩格式或压缩格式传输帧。这些相机及其流通过媒体捕获管道(pipeline)导出给应用程序。红外UVC摄像头相机帧类型红外UVC摄像头相机支持的格......
ubuntu下使用usbmon进行usb抓包
开发或者调试USB设备相关的工具或者驱动,一个调试的利器就是usbmon抓包。 在ubuntu下使用步骤如下:1 运行命令 sudo mount -t debugfs none /sys/kernel/debug ,如果提示已经挂载,则下次抓包就可以不运行这个命令了。表示系统默认会挂载。 2 ......
关注公众号
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

您的支持,是我们前进的动力!