uvc攝像頭代碼解析4

7.uvc_parse_format
7.1 uvc格式描述符
[cpp]  
struct uvc_format_desc { //uvc格式描述符  
char *name; //uvc格式描述符名字  
__u8 guid[16];//全局唯一ID  
__u32 fcc; //壓縮格式  
};  
7.2 uvc解析1個格式描述符
[cpp] 
static int uvc_parse_format(struct uvc_device *dev,struct uvc_streaming *streaming, struct uvc_format *format,__u32 **intervals, unsigned char *buffer, int buflen)  
{  
    struct usb_interface *intf = streaming->intf;    //獲取usb接口  
    struct usb_host_interface *alts = intf->cur_altsetting;  //獲取usb_host_interface  
    struct uvc_format_desc *fmtdesc;    //uvc格式描述符  
    struct uvc_frame *frame;    //uvc幀  
    const unsigned char *start = buffer;  
    unsigned int interval;  
    unsigned int i, n;  
    __u8 ftype;  
  
    format->type = buffer[2];    //uvc格式類型  
    format->index = buffer[3];   //uvc格式索引  
    switch (buffer[2]) {    //uvc格式類型  
    case UVC_VS_FORMAT_UNCOMPRESSED:  
 
[cpp]  
case UVC_VS_FORMAT_FRAME_BASED:  
 
[cpp]  
    n = buffer[2] == UVC_VS_FORMAT_UNCOMPRESSED ? 27 : 28;  //獲取描述符大小  
    if (buflen < n) {    //檢驗buflen大小  
        uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface %d FORMAT error\n",dev->udev->devnum,alts->desc.bInterfaceNumber);  
        return -EINVAL;  
    }  
    /* Find the format descriptor from its GUID. */  
    fmtdesc = uvc_format_by_guid(&buffer[5]);   //獲取uvc格式描述符  
    if (fmtdesc != NULL) {  //設置uvc格式編碼格式名字  
        strlcpy(format->name, fmtdesc->name,sizeof format->name);  
        format->fcc = fmtdesc->fcc;   //設置uvc格式的fcc(壓縮格式)  
    }   
    else {  //不能識別的格式  
        uvc_printk(KERN_INFO, "Unknown video format %pUl\n",&buffer[5]);  
        snprintf(format->name, sizeof(format->name), "%pUl\n",&buffer[5]);  
        format->fcc = 0;  
    }  
    format->bpp = buffer[21];    //設置uvc格式bpp(每像素多少位)  
    if (buffer[2] == UVC_VS_FORMAT_UNCOMPRESSED) {  
        ftype = UVC_VS_FRAME_UNCOMPRESSED;  //設置ftype(frame type)  
    }   
 else {  
        ftype = UVC_VS_FRAME_FRAME_BASED;   //設置ftype(frame type)  
        if (buffer[27])  
            format->flags = UVC_FMT_FLAG_COMPRESSED; //設置uvc格式標誌(壓縮的)  
    }  
    break;  
case UVC_VS_FORMAT_MJPEG:  
 
[cpp] 
    if (buflen < 11) {   //檢驗buflen大小  
        uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface %d FORMAT error\n",dev->udev->devnum,alts->desc.bInterfaceNumber);  
        return -EINVAL;  
    }  
    strlcpy(format->name, "MJPEG", sizeof format->name);  //設置uvc格式編碼格式名字“MJPEG”  
    format->fcc = V4L2_PIX_FMT_MJPEG;    //設置uvc格式的fcc(壓縮格式)  
    format->flags = UVC_FMT_FLAG_COMPRESSED; //設置uvc格式標誌(壓縮的)  
    format->bpp = 0; //設置uvc格式bpp(每像素多少位)  
    ftype = UVC_VS_FRAME_MJPEG; //設置ftype(frame type)  
    break;  
case UVC_VS_FORMAT_DV:  
 
[cpp]  
        if (buflen < 9) {    //檢驗buflen大小  
            uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface %d FORMAT error\n",dev->udev->devnum,alts->desc.bInterfaceNumber);  
            return -EINVAL;  
        }  
        switch (buffer[8] & 0x7f) { //bFormatType格式類型  
        case 0: //設置uvc格式編碼格式名字 "SD-DV"  
            strlcpy(format->name, "SD-DV", sizeof format->name);  
            break;  
        case 1: //設置uvc格式編碼格式名字 "SDL-DV"  
            strlcpy(format->name, "SDL-DV", sizeof format->name);  
            break;  
        case 2: //設置uvc格式編碼格式名字 "HD-DV"  
            strlcpy(format->name, "HD-DV", sizeof format->name);  
            break;  
        default:  
            uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface %d: unknown DV format %u\n",dev->udev->devnum,alts->desc.bInterfaceNumber, buffer[8]);  
            return -EINVAL;  
        }  
        strlcat(format->name, buffer[8] & (1 << 7) ? " 60Hz" : " 50Hz",sizeof format->name);    //掃描格式eg("HD-DV 60Hz")  
        format->fcc = V4L2_PIX_FMT_DV;   //設置uvc格式的fcc(壓縮格式)  
        format->flags = UVC_FMT_FLAG_COMPRESSED | UVC_FMT_FLAG_STREAM;   //設置uvc格式標誌(壓縮的|數據流)  
        format->bpp = 0; //設置uvc格式bpp(每像素多少位)  
        ftype = 0;  //設置ftype(frame type)  
        /* Create a dummy frame descriptor. 創建插入一個幀描述符*/  
        frame = &format->frame[0];   //獲取uvc格式的第一個幀地址  
        memset(&format->frame[0], 0, sizeof format->frame[0]);    //初始化uvc幀  
        frame->bFrameIntervalType = 1;   //uvc幀間隔類型  
        frame->dwDefaultFrameInterval = 1;   //uvc幀默認間隔  
        frame->dwFrameInterval = *intervals; //uvc幀間隔  
        *(*intervals)++ = 1;    //添加間隔  
        format->nframes = 1; //uvc格式的幀個數設置爲1  
        break;  
    case UVC_VS_FORMAT_MPEG2TS:  
    case UVC_VS_FORMAT_STREAM_BASED:  
        /* Not supported yet. */  
    default:  
        uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface %d unsupported format %u\n",dev->udev->devnum, alts->desc.bInterfaceNumber,buffer[2]);  
        return -EINVAL;  
    }  
    uvc_trace(UVC_TRACE_DESCR, "Found format %s.\n", format->name);  
    buflen -= buffer[0];  
    buffer += buffer[0];    //下一個描述符(uvc幀描述符)  
    /* Parse the frame descriptors. Only uncompressed, MJPEG and frame based formats have frame descriptors.*/  
    while (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE && buffer[2] == ftype) {   //buffer[2]=bDescriptorSubtype==frame type?  
        frame = &format->frame[format->nframes];  //獲取第二個uvc格式的uvc幀指針  
//UVC_VS_FRAME_FRAME_BASED參看USB_Video_Payload_Frame_Based_1.5.pdf  P15  
        if (ftype != UVC_VS_FRAME_FRAME_BASED)  //獲取支持的不連續幀間隔數/連續幀間隔  
            n = buflen > 25 ? buffer[25] : 0;  
        else  
            n = buflen > 21 ? buffer[21] : 0;      
        n = n ? n : 3;  //支持不連續幀間隔?支持不連續幀間隔間隔數:連續幀間隔  
        if (buflen < 26 + 4*n) { //檢驗buflen大小  
            uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface %d FRAME error\n", dev->udev->devnum,alts->desc.bInterfaceNumber);  
            return -EINVAL;  
        }  
        frame->bFrameIndex = buffer[3];  //獲取uvc幀索引  
        frame->bmCapabilities = buffer[4];   //獲取uvc幀兼容性  
        frame->wWidth = get_unaligned_le16(&buffer[5]);  //解碼uvc視頻寬度  
        frame->wHeight = get_unaligned_le16(&buffer[7]); //解碼uvc視頻高度  
        frame->dwMinBitRate = get_unaligned_le32(&buffer[9]);    //解碼uvc視頻最小位流  
        frame->dwMaxBitRate = get_unaligned_le32(&buffer[13]);   //解碼uvc視頻最大位流  
        if (ftype != UVC_VS_FRAME_FRAME_BASED) {  
            frame->dwMaxVideoFrameBufferSize =get_unaligned_le32(&buffer[17]);   //uvc最大視頻幀緩衝區大小  
            frame->dwDefaultFrameInterval =get_unaligned_le32(&buffer[21]);  //uvc默認幀間隔  
            frame->bFrameIntervalType = buffer[25];  //uvc幀間隔類型  
        }   
        else {  
            frame->dwMaxVideoFrameBufferSize = 0;    //uvc最大視頻幀緩衝區大小  
            frame->dwDefaultFrameInterval =get_unaligned_le32(&buffer[17]);  //uvc默認幀間隔  
            frame->bFrameIntervalType = buffer[21];  //uvc幀間隔類型  
        }  
        frame->dwFrameInterval = *intervals; //設置uvc幀間隔指針  
        if (!(format->flags & UVC_FMT_FLAG_COMPRESSED))  //uvc格式標誌(壓縮的)  
            frame->dwMaxVideoFrameBufferSize = format->bpp * frame->wWidth * frame->wHeight / 8;    //計算uvc幀最大視頻格式緩衝去大小(byte)  
        for (i = 0; i < n; ++i) {  
            interval = get_unaligned_le32(&buffer[26+4*i]); //獲取uvc幀間隔  
            *(*intervals)++ = interval ? interval : 1;  //調整uvc幀間隔大小  
        }  
        /* Make sure that the default frame interval stays between the boundaries.*/  
        n -= frame->bFrameIntervalType ? 1 : 2;  //uvc幀間隔邊界調整  
        frame->dwDefaultFrameInterval = min(frame->dwFrameInterval[n], max(frame->dwFrameInterval[0],frame->dwDefaultFrameInterval));  
        if (dev->quirks & UVC_QUIRK_RESTRICT_FRAME_RATE) {  
            frame->bFrameIntervalType = 1;  
            frame->dwFrameInterval[0] = frame->dwDefaultFrameInterval;  
        }  
        uvc_trace(UVC_TRACE_DESCR, "- %ux%u (%u.%u fps)\n",frame->wWidth, frame->wHeight,10000000/frame->dwDefaultFrameInterval,(100000000/frame->dwDefaultFrameInterval)%10);  
        format->nframes++;   //調整uvc格式幀數  
        buflen -= buffer[0];  
        buffer += buffer[0];    //指向下一個描述符(uvc幀描述符)  
    }  
    if (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE && buffer[2] == UVC_VS_STILL_IMAGE_FRAME) {   //靜態圖像幀  
        buflen -= buffer[0];  
        buffer += buffer[0];    //跳過指向下一個描述符  
    }  
    if (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE && buffer[2] == UVC_VS_COLORFORMAT) { //顏色格式幀  
        if (buflen < 6) {  
            uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface %d COLORFORMAT error\n",dev->udev->devnum,alts->desc.bInterfaceNumber);  
            return -EINVAL;  
        }  
        format->colorspace = uvc_colorspace(buffer[3]);  //buffer[3]=bColorPrimaries 設置顏色空間  
        buflen -= buffer[0];  
        buffer += buffer[0];    //指向下一描述符  
    }  
    return buffer - start;  //返回解析了的uvc格式描述符+所含的uvc幀描述符長度  
}  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章