V4L2学习笔记
+ -

Linux源码分析UVC摄像头的初始化流程分析

2021-04-01 2040 0

UVC摄像头的初始化发生在硬件被接入USB集线器中,设备初USB驱动识别为摄像头的后续初始化流程。
和Windows的AddDevice驱动函数一样,Linux设备的创建和侦测是通过int uvc_probe函数实现的。其函数的调用关系如下:

//linux/v5.11.11/source/drivers/media/usb/uvc/uvc_driver.c#L2098
uvc_probe
    uvc_register_chains
        uvc_register_terms
            uvc_register_video_device
                uvc_register_video
                    uvc_video_init

uvc_video_init的代码如下:

int uvc_video_init(struct uvc_streaming *stream)
{
    struct uvc_streaming_control *probe = &stream->ctrl;
    struct uvc_format *format = NULL;
    struct uvc_frame *frame = NULL;
    struct uvc_urb *uvc_urb;
    unsigned int i;
    int ret;

    if (stream->nformats == 0) {
        uvc_printk(KERN_INFO, "No supported video formats found.\n");
        return -EINVAL;
    }

    atomic_set(&stream->active, 0);

    /* Alternate setting 0 should be the default, yet the XBox Live Vision
     * Cam (and possibly other devices) crash or otherwise misbehave if
     * they don't receive a SET_INTERFACE request before any other video
     * control request.
     */
    usb_set_interface(stream->dev->udev, stream->intfnum, 0);

    /* Set the streaming probe control with default streaming parameters
     * retrieved from the device. Webcams that don't support GET_DEF
     * requests on the probe control will just keep their current streaming
     * parameters.
     */
    if (uvc_get_video_ctrl(stream, probe, 1, UVC_GET_DEF) == 0)
        uvc_set_video_ctrl(stream, probe, 1);

    /* Initialize the streaming parameters with the probe control current
     * value. This makes sure SET_CUR requests on the streaming commit
     * control will always use values retrieved from a successful GET_CUR
     * request on the probe control, as required by the UVC specification.
     */
    ret = uvc_get_video_ctrl(stream, probe, 1, UVC_GET_CUR);
    if (ret < 0)
        return ret;

    /* Check if the default format descriptor exists. Use the first
     * available format otherwise.
     */
    for (i = stream->nformats; i > 0; --i) {
        format = &stream->format[i-1];
        if (format->index == probe->bFormatIndex)
            break;
    }

    if (format->nframes == 0) {
        uvc_printk(KERN_INFO, "No frame descriptor found for the "
            "default format.\n");
        return -EINVAL;
    }

    /* Zero bFrameIndex might be correct. Stream-based formats (including
     * MPEG-2 TS and DV) do not support frames but have a dummy frame
     * descriptor with bFrameIndex set to zero. If the default frame
     * descriptor is not found, use the first available frame.
     */
    for (i = format->nframes; i > 0; --i) {
        frame = &format->frame[i-1];
        if (frame->bFrameIndex == probe->bFrameIndex)
            break;
    }

    probe->bFormatIndex = format->index;
    probe->bFrameIndex = frame->bFrameIndex;

    stream->def_format = format;
    stream->cur_format = format;
    stream->cur_frame = frame;

    /* Select the video decoding function */
    if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
        if (stream->dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT)
            stream->decode = uvc_video_decode_isight;
        else if (stream->intf->num_altsetting > 1)
            stream->decode = uvc_video_decode_isoc;
        else
            stream->decode = uvc_video_decode_bulk;
    } else {
        if (stream->intf->num_altsetting == 1)
            stream->decode = uvc_video_encode_bulk;
        else {
            uvc_printk(KERN_INFO, "Isochronous endpoints are not "
                "supported for video output devices.\n");
            return -EINVAL;
        }
    }

    /* Prepare asynchronous work items. */
    for_each_uvc_urb(uvc_urb, stream)
        INIT_WORK(&uvc_urb->work, uvc_video_copy_data_work);

    return 0;
}

从代码来看,UVC设备的初始化的第一步是选择视频流的接口,通过函数usb_set_interface实现。

usb_set_interface(stream->dev->udev, stream->intfnum, 0);

然后使用VS_PROBE_CONTROL选择子和GET_DEF请求类型获取默认的视频帧格式类型,然后设置当前SET_CUR的属性信息。
后续的代码就相对简单,是对获取的默认视频编码格式和帧格式进行校验,校验完成后就保存当前的状态信息。

Windows下的UVC相机初始化

本人手中有一UVC摄像头,其UVC控制接口(ID=1)中有相机终端描述符(ID=1),处理单元描述符(ID=2)输出终端描述符(ID=3)和一个扩展单元描述符(ID=0x0b).

为什么这个摄像头的UVC控制接口ID=1?这是因为本人手中的这个相机摄像头是一个复合设备,接口描述符ID=0的是一个HID设备。

现将设备插入电脑的枚举过程抓包显示如下:(只抓了前面少部分字节)

Device  Length    Phase  Data                                                          
------  --------  -----  ---------------------------------------------------- ---------
  44.0            CTL    80 06 00 01  00 00 12 00                             GET DESCR
  44.0        18  IN     12 01 00 02  ef 02 01 40  6b 1d 00 01  09 04 04 0a   .......@k
  44.0            CTL    80 06 00 02  00 00 09 00                             GET DESCR
  44.0         9  IN     09 02 bb 00  02 01 07 80  fa                         .........
  44.0            CTL    80 06 00 02  00 00 bb 00                             GET DESCR
  44.0       187  IN     09 02 bb 00  02 01 07 80  fa 09 04 01  00 01 0e 01   .........
  44.0            CTL    00 09 01 00  00 00 00 00                             SET CONFI
  44.0            CTL    01 0b 00 00  02 00 00 00                             SET INTER

//参见相机终端描述符    先择子为CT_ZOOM_ABSOLUTE_CONTROL                                               
  44.0            CTL    a1 86 00 0b  01 01 01 00                             GET INFO 
  44.0         1  IN     13                                                   .        
  44.0            CTL    a1 82 00 0b  01 01 02 00                             GET MIN  
  44.0         2  IN     00 00                                                ..       
  44.0            CTL    a1 83 00 0b  01 01 02 00                             GET MAX  
  44.0         2  IN     d0 02                                                ..       
  44.0            CTL    a1 84 00 0b  01 01 02 00                             GET RES  
  44.0         2  IN     01 00                                                ..       
  44.0            CTL    a1 87 00 0b  01 01 02 00                             GET DEF  
  44.0         2  IN     00 00                                                ..       

//CT_ZOOM_RELATIVE_CONTROL                                                         
  44.0            CTL    a1 86 00 0c  01 01 01 00                             GET INFO 
  44.0         1  IN     03                                                   .        
  44.0            CTL    a1 82 00 0c  01 01 03 00                             GET MIN  
  44.0         3  IN     00 00 00                                             ...      
  44.0            CTL    a1 83 00 0c  01 01 03 00                             GET MAX  
  44.0         3  IN     00 00 01                                             ...      
  44.0            CTL    a1 84 00 0c  01 01 03 00                             GET RES  
  44.0         3  IN     00 00 01                                             ...      
  44.0            CTL    a1 87 00 0c  01 01 03 00                             GET DEF  
  44.0         3  IN     00 00 01                                             ...      

//CT_PANTILT_ABSOLUTE_CONTROL                                                             
  44.0            CTL    a1 86 00 0d  01 01 01 00                             GET INFO 
  44.0         1  IN     13                                                   .        
  44.0            CTL    a1 82 00 0d  01 01 08 00                             GET MIN  
  44.0         8  IN     80 39 ec ff  60 e7 f4 ff                             
  44.0            CTL    a1 83 00 0d  01 01 08 00                             GET MAX  
  44.0         8  IN     80 c6 13 00  a0 18 0b 00                             ........ 
  44.0            CTL    a1 84 00 0d  01 01 08 00                             GET RES  
  44.0         8  IN     10 0e 00 00  10 0e 00 00                             ........ 
  44.0            CTL    a1 87 00 0d  01 01 08 00                             GET DEF  
  44.0         8  IN     00 00 00 00  00 00 00 00                             ........ 
  44.0            CTL    a1 86 00 0e  01 01 01 00                             GET INFO 
  44.0         1  IN     03                                                   .        

//CT_PANTILT_RELATIVE_CONTROL                                                             
  44.0            CTL    a1 82 00 0e  01 01 04 00                             GET MIN  
  44.0         4  IN     00 01 00 01                                          ....     
  44.0            CTL    a1 83 00 0e  01 01 04 00                             GET MAX  
  44.0         4  IN     00 01 00 01                                          ....     
  44.0            CTL    a1 84 00 0e  01 01 04 00                             GET RES  
  44.0         4  IN     00 01 00 01                                          ....     
  44.0            CTL    a1 87 00 0e  01 01 04 00                             GET DEF  
  44.0         4  IN     00 01 00 01                                          ....     
  44.0            CTL    a1 85 00 01  01 0b 02 00                             GET LEN  
  44.0         2  IN     01 00                                                ..       


//参见扩展单元描述符 ,支持1-5的选择子                                                                
  44.0            CTL    a1 86 00 01  01 0b 01 00                             GET INFO 
  44.0         1  IN     02                                                   .        
  44.0            CTL    a1 82 00 01  01 0b 01 00                             GET MIN  
  44.0         1  IN     00                                                   .        
  44.0            CTL    a1 83 00 01  01 0b 01 00                             GET MAX  
  44.0         1  IN     ff                                                   .        
  44.0            CTL    a1 84 00 01  01 0b 01 00                             GET RES  
  44.0         1  IN     01                                                   .        
  44.0            CTL    a1 87 00 01  01 0b 01 00                             GET DEF  
  44.0         1  IN     00                                                   .        
  44.0            CTL    a1 85 00 02  01 0b 02 00                             GET LEN  
  44.0         2  IN     01 00                                                ..       
  44.0            CTL    a1 86 00 02  01 0b 01 00                             GET INFO 
  44.0         1  IN     02                                                   .        
  44.0            CTL    a1 82 00 02  01 0b 01 00                             GET MIN  
  44.0         1  IN     00                                                   .        
  44.0            CTL    a1 83 00 02  01 0b 01 00                             GET MAX  
  44.0         1  IN     ff                                                   .        
  44.0            CTL    a1 84 00 02  01 0b 01 00                             GET RES  
  44.0         1  IN     01                                                   .        
  44.0            CTL    a1 87 00 02  01 0b 01 00                             GET DEF  
  44.0         1  IN     00                                                   .        
  44.0            CTL    a1 85 00 03  01 0b 02 00                             GET LEN  
  44.0         2  IN     01 00                                                ..       
  44.0            CTL    a1 86 00 03  01 0b 01 00                             GET INFO 
  44.0         1  IN     02                                                   .        
  44.0            CTL    a1 82 00 03  01 0b 01 00                             GET MIN  
  44.0         1  IN     00                                                   .        
  44.0            CTL    a1 83 00 03  01 0b 01 00                             GET MAX  
  44.0         1  IN     ff                                                   .        
  44.0            CTL    a1 84 00 03  01 0b 01 00                             GET RES  
  44.0         1  IN     01                                                   .        
  44.0            CTL    a1 87 00 03  01 0b 01 00                             GET DEF  
  44.0         1  IN     00                                                   .        
  44.0            CTL    a1 85 00 04  01 0b 02 00                             GET LEN  
  44.0         2  IN     01 00                                                ..       
  44.0            CTL    a1 86 00 04  01 0b 01 00                             GET INFO 
  44.0         1  IN     02                                                   .        
  44.0            CTL    a1 82 00 04  01 0b 01 00                             GET MIN  
  44.0         1  IN     00                                                   .        
  44.0            CTL    a1 83 00 04  01 0b 01 00                             GET MAX  
  44.0         1  IN     ff                                                   .        
  44.0            CTL    a1 84 00 04  01 0b 01 00                             GET RES  
  44.0         1  IN     01                                                   .        
  44.0            CTL    a1 87 00 04  01 0b 01 00                             GET DEF  
  44.0         1  IN     00                                                   .        
  44.0            CTL    a1 85 00 05  01 0b 02 00                             GET LEN  
  44.0         2  IN     01 00                                                ..       
  44.0            CTL    a1 86 00 05  01 0b 01 00                             GET INFO 
  44.0         1  IN     02                                                   .        
  44.0            CTL    a1 82 00 05  01 0b 01 00                             GET MIN  
  44.0         1  IN     00                                                   .        
  44.0            CTL    a1 83 00 05  01 0b 01 00                             GET MAX  
  44.0         1  IN     ff                                                   .        
  44.0            CTL    a1 84 00 05  01 0b 01 00                             GET RES  
  44.0         1  IN     01                                                   .        
  44.0            CTL    a1 87 00 05  01 0b 01 00                             GET DEF  
  44.0         1  IN     00                                                   .

而在打开摄像头的时候,才进行相关参数的获取.这也许是Windows和Linux的区别吧。

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 
`

0 篇笔记 写笔记

Linux V4L2 UVC摄像头框架浅析
V4L2 :video for linux version 2 ,是 Linux 里一套标准的视频驱动,它支持 UVC 标准的摄像头。本文来分析一下它的核心框架。整个v4l2的框架分为三层:在应用层,我们可以在 /dev 目录发现 video0 类似的设备节点,上层的摄像头程序打开设备节点进行......
打开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复合设......
华为UAC耳机的工作过程数据分析
华为UAC耳机工作时,首先需要打开设备,然后读取数据,播放过程后,需要关闭设备。这里我们使用BusHound抓包(省略掉重复的数据包:由于这些特定类请求是发给UAC音频控制终端/实体或接口的,所以我们先回顾一下UAC音频控制单元的一些ID,然后对照其选择子进行分析。UAC音频控制接口头描述符ID描述......
简易摄像头playcap工程代码及应用程序
playcap是一个小巧的UVC摄像头测试工具,使用的是DirectShow,本人之前装饰部分代码发布到此网址:http://www.usbzh.com/article/detail-553.html但经常有人说编译不过,其实这都是工程配置问题引起的。现将工程代码及编译好的应用程序提供详细的下载地......
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摄像头相机支持的格......
华为UAC麦克风的工作过程数据分析
看完了耳机的数据分析,再来分析麦克风,就相对来说很简单了,这是因为:第一:麦克风没有音频控制特效单元描述符,所以少了很多特定类请求。第二:麦克风只有一个音频流转换接口,且只支持采样率为48000HZ 16位。具体的过程见下:Length Phase Data-------- --......
UVC 输入终端描述符
输入终端描述符用于向主机报告视频数据输入终端的相关信息。输入终端描述符使用bTerminalID描述输入终端的ID,且这个ID是惟一的。输入终端描述符位于视频控制接口中。输入终端描述符结构体定义如下:// Input Terminal Descriptortypedef struct _USB......
USB兼容驱动Composite层级引起的摄像头灯问题
跌跌撞撞,搞了快一个星期。一个定制厂商用的UVC摄像头指示搞了几天,今天算是可以蒙混过关了。关于调试过程中的一部分细节,可见本人的另一篇文章:关于UVC摄像头指示灯的调试过程总结 http://www.usbzh.com/article/detail-430.html在这里,可能只能算是总结二吧,没......
关注公众号
  • HID人机交互
  • Linux&USB
  • UAC音频
  • TYPE-C
  • USB规范
  • USB大容量存储
  • USB百科
  • USB周边
  • UVC摄像头
  • Windows系统USB
  • 音视频博客
  • 取消
    感谢您的支持,我会继续努力的!
    扫码支持
    扫码打赏,你说多少就多少

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

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