uvc摄像头代码解析3

来源:互联网 发布:传奇数据库增加新的怪 编辑:程序博客网 时间:2024/05/17 03:00
6.uvc解析uvc视频流
6.1 重要结构体
6.1.1 uvc数据流
[cpp]  
struct uvc_streaming {  
    struct list_head list;  //uvc视频流链表头  
    struct uvc_device *dev; //uvc设备  
    struct video_device *vdev;  //V4L2视频设备  
    struct uvc_video_chain *chain;  //uvc视频链  
    atomic_t active;  
    struct usb_interface *intf; //usb接口设备  
    int intfnum;    //usb接口号  
    __u16 maxpsize; //最大包尺寸  
    struct uvc_streaming_header header; //uvc视频流头部  
    enum v4l2_buf_type type;    //V4L2缓冲区类型 输入/输出  
    unsigned int nformats;  //uvc格式个数  
    struct uvc_format *format;  //uvc格式指针  
    struct uvc_streaming_control ctrl;  //uvc数据流控制  
    struct uvc_format *cur_format;  //当前uvc格式指针  
    struct uvc_frame *cur_frame;    //当前uvc帧指针  
    struct mutex mutex;  
    unsigned int frozen : 1;  
    struct uvc_video_queue queue;   //uvc视频队列  
    void (*decode) (struct urb *urb, struct uvc_streaming *video,struct uvc_buffer *buf);//解码函数  
    struct {  
        __u8 header[256];  
        unsigned int header_size;  
        int skip_payload;  
        __u32 payload_size;  
        __u32 max_payload_size;  
    } bulk;  
    struct urb *urb[UVC_URBS];//urb数组  
    char *urb_buffer[UVC_URBS]; //urb缓冲区  
    dma_addr_t urb_dma[UVC_URBS];//urb DMA缓冲区  
    unsigned int urb_size;    
    __u32 sequence;  
    __u8 last_fid;  
};  
 
6.1.2 uvc格式
[cpp]  
struct uvc_format { //uvc格式  
    __u8 type;  //类型  
    __u8 index; //索引  
    __u8 bpp;   //bits per pixel 每像素位数  
    __u8 colorspace;    //颜色空间  
    __u32 fcc;  //压缩格式  
    __u32 flags;    //标记  
    char name[32];  //名字  
    unsigned int nframes;   //所含uvc帧个数  
    struct uvc_frame *frame;    //uvc帧指针  
};  
 
6.1.3 uvc帧
[cpp] 
struct uvc_frame {  //uvc帧  
    __u8  bFrameIndex;  //帧索引号  
    __u8  bmCapabilities;   //uvc帧兼容性  
    __u16 wWidth;   //宽度  
    __u16 wHeight;  //高度  
    __u32 dwMinBitRate; //最新位流  
    __u32 dwMaxBitRate; //最大位流  
    __u32 dwMaxVideoFrameBufferSize;    //最大视频帧缓冲区  
    __u8  bFrameIntervalType;   //间隙类型  
    __u32 dwDefaultFrameInterval;   //默认帧间隙  
    __u32 *dwFrameInterval; //帧间隙指针  
};  
 
6.2 uvc_parse_streaming函数
[cpp]  
static int uvc_parse_streaming(struct uvc_device *dev,struct usb_interface *intf)  
{  
    struct uvc_streaming *streaming = NULL; //uvc数据流  
    struct uvc_format *format;  //uvc格式  
    struct uvc_frame *frame;    //uvc帧  
    struct usb_host_interface *alts = &intf->altsetting[0];  //获取usb接口第一个usb_host_interface (Alt.Setting 0)  
    unsigned char *_buffer, *buffer = alts->extra;   //获取额外描述符  
    int _buflen, buflen = alts->extralen;    //获取额外描述符长度  
    unsigned int nformats = 0, nframes = 0, nintervals = 0;  
    unsigned int size, i, n, p;  
    __u32 *interval;  
    __u16 psize;  
    int ret = -EINVAL;  
    if (intf->cur_altsetting->desc.bInterfaceSubClass != UVC_SC_VIDEOSTREAMING) { //判读usb接口描述符子类是否为视频数据流接口子类  
        uvc_trace(UVC_TRACE_DESCR, "device %d interface %d isn't a video streaming interface\n", dev->udev->devnum,intf->altsetting[0].desc.bInterfaceNumber);  
        return -EINVAL;  
    }  
    if (usb_driver_claim_interface(&uvc_driver.driver, intf, dev)) {    //绑定uvc设备的usb驱动和usb接口  
        uvc_trace(UVC_TRACE_DESCR, "device %d interface %d is already claimed\n", dev->udev->devnum,intf->altsetting[0].desc.bInterfaceNumber);  
        return -EINVAL;  
    }  
    streaming = kzalloc(sizeof *streaming, GFP_KERNEL); //分配uvc数据流内存  
    if (streaming == NULL) {  
        usb_driver_release_interface(&uvc_driver.driver, intf);  
        return -EINVAL;  
    }  
    mutex_init(&streaming->mutex);  
    streaming->dev = dev;    //uvc数据流和uvc设备捆绑  
    streaming->intf = usb_get_intf(intf);    //uvc数据流和usb接口捆绑,并增加引用计数  
    streaming->intfnum = intf->cur_altsetting->desc.bInterfaceNumber;  //设置接口号  
    /* The Pico iMage webcam has its class-specific interface descriptors after the endpoint descriptors. */  
    if (buflen == 0) {  //Pico iMage webcam 特殊处理  
        for (i = 0; i < alts->desc.bNumEndpoints; ++i) {  
            struct usb_host_endpoint *ep = &alts->endpoint[i];  
            if (ep->extralen == 0)  
                continue;  
            if (ep->extralen > 2 && ep->extra[1] == USB_DT_CS_INTERFACE) {  
                uvc_trace(UVC_TRACE_DESCR, "trying extra data from endpoint %u.\n", i);  
                buffer = alts->endpoint[i].extra;  
                buflen = alts->endpoint[i].extralen;  
                break;  
            }  
        }  
    }  
    /* Skip the standard interface descriptors. 跳过标准的接口描述符*/  
    while (buflen > 2 && buffer[1] != USB_DT_CS_INTERFACE) {   
        buflen -= buffer[0];  
        buffer += buffer[0];  
    }  
    if (buflen <= 2) {  
        uvc_trace(UVC_TRACE_DESCR, "no class-specific streaming interface descriptors found.\n");  
        goto error;  
    }  
    /* Parse the header descriptor. 解析header描述符*/   //Class-specific VS Interface Input Header Descriptor  
    switch (buffer[2]) {    //bDescriptorSubtype  
    case UVC_VS_OUTPUT_HEADER:  //输出类型的视频流  
        streaming->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;    //设置为V4L2视频buf输出  
        size = 9;  
        break;  
    case UVC_VS_INPUT_HEADER:   //输入类型的视频流  
        streaming->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;   //设置为V4L2视频buf输入  
        size = 13;  
        break;  
    default:  
        uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface %d HEADER descriptor not found.\n", dev->udev->devnum,alts->desc.bInterfaceNumber);  
        goto error;  
    }  
    p = buflen >= 4 ? buffer[3] : 0; //bNumFormats uvc格式format个数  
    n = buflen >= size ? buffer[size-1] : 0; //bControlSize 控制位域大小  
    if (buflen < size + p*n) {       //检测buflen长度是否合适  
        uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface %d HEADER descriptor is invalid.\n",dev->udev->devnum, alts->desc.bInterfaceNumber);  
        goto error;  
    }  
    //初始化uvc视频流头部  
    streaming->header.bNumFormats = p;   //uvc格式format格式个数  
    streaming->header.bEndpointAddress = buffer[6];  //端点地址  
    if (buffer[2] == UVC_VS_INPUT_HEADER) { //输入的视频流  
        streaming->header.bmInfo = buffer[7];            //信息位图(兼容性)  
        streaming->header.bTerminalLink = buffer[8]; //连接到的输出Terminal ID号  
        streaming->header.bStillCaptureMethod = buffer[9];   //静态图像捕捉方法(Method 1、Method 2、Method 3)  
        streaming->header.bTriggerSupport = buffer[10];  //硬件触发支持  
        streaming->header.bTriggerUsage = buffer[11];    //触发用例  
    }   
    else {  
        streaming->header.bTerminalLink = buffer[7]; //连接到的输入Terminal ID号  
    }  
    streaming->header.bControlSize = n;  //控制位域大小  
    streaming->header.bmaControls = kmemdup(&buffer[size], p * n,GFP_KERNEL);    //初始化bmaControls(x)位图(大小=帧数*位域大小)  
    if (streaming->header.bmaControls == NULL) {  
        ret = -ENOMEM;  
        goto error;  
    }  
    buflen -= buffer[0];  
    buffer += buffer[0];    //指向下一个描述符  
    _buffer = buffer;  
    _buflen = buflen;   //指向同一个描述符  
解析完vs header后解析剩下的vs描述符
第一次解析描述符 统计uvc帧、uvc格式、间隔,并分配内存
[cpp]  
/* Count the format and frame descriptors. 计算格式描述符和帧描述符个数*/  
    while (_buflen > 2 && _buffer[1] == USB_DT_CS_INTERFACE) {  
        switch (_buffer[2]) {  
        case UVC_VS_FORMAT_UNCOMPRESSED:  
        case UVC_VS_FORMAT_MJPEG:  
        case UVC_VS_FORMAT_FRAME_BASED:  
            nformats++;  
            break;  
        case UVC_VS_FORMAT_DV:  
            /* DV format has no frame descriptor. We will create a dummy frame descriptor with a dummy frame interval. */  
            nformats++;  
            nframes++;  
            nintervals++;  
            break;  
        case UVC_VS_FORMAT_MPEG2TS:  
        case UVC_VS_FORMAT_STREAM_BASED:  
            uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface %d FORMAT %u is not supported.\n",dev->udev->devnum,alts->desc.bInterfaceNumber, _buffer[2]);  
            break;  
        case UVC_VS_FRAME_UNCOMPRESSED:  
        case UVC_VS_FRAME_MJPEG:  
            nframes++;  
            if (_buflen > 25)  
                nintervals += _buffer[25] ? _buffer[25] : 3;  
            break;  
        case UVC_VS_FRAME_FRAME_BASED:  
            nframes++;  
            if (_buflen > 21)  
                nintervals += _buffer[21] ? _buffer[21] : 3;  
            break;  
        }   //计算uvc帧和uvc格式的个数及间隔个数  
        _buflen -= _buffer[0];    
        _buffer += _buffer[0];  //跳到下一个描述符  
    }  
    if (nformats == 0) {  
        uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface %d has no supported formats defined.\n",dev->udev->devnum, alts->desc.bInterfaceNumber);  
        goto error;  
    }  
    //    uvc格式数 * uvc格式大小    + uvc帧   * uvc帧大小    + 间隔数     * 间隔大小  
    size = nformats * sizeof *format + nframes * sizeof *frame+ nintervals * sizeof *interval;  
    format = kzalloc(size, GFP_KERNEL); //分配uvc格式和uvc帧的内存  
    if (format == NULL) {  
        ret = -ENOMEM;  
        goto error;  
    }  
    frame = (struct uvc_frame *)&format[nformats];  //uvc帧存放在uvc格式数组后面  
    interval = (__u32 *)&frame[nframes];    //间隔放在帧后面  
    streaming->format = format;  //uvc视频流捆绑uvc格式结构体  
    streaming->nformats = nformats;  //uvc格式个数  
第二次解析描述符
[cpp]  
/* Parse the format descriptors.解析格式描述符 */  
while (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE) {  
    switch (buffer[2]) {    //bDescriptorSubtype描述符类型  
    case UVC_VS_FORMAT_UNCOMPRESSED:  
    case UVC_VS_FORMAT_MJPEG:  
    case UVC_VS_FORMAT_DV:  
    case UVC_VS_FORMAT_FRAME_BASED:  
        format->frame = frame;   //uvc格式的帧指针 指向uvc帧地址  
        ret = uvc_parse_format(dev, streaming, format,&interval, buffer, buflen);   //7.解析uvc格式描述符  
        if (ret < 0)  
            goto error;  
        frame += format->nframes;    //uvc帧地址指向下一个uvc格式所属的uvc帧地址  
        format++;   //指向下一个uvc格式  
        buflen -= ret;    
        buffer += ret;  //指向下一个uvc格式描述符  
        continue;  
原创粉丝点击