uvc摄像头代码解析3

来源:互联网 发布:经济学研究生知乎 编辑:程序博客网 时间:2024/04/29 20:03

6.uvc解析uvc视频流

6.1 重要结构体

6.1.1 uvc数据流

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格式

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帧

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函数

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 Descriptorswitch (buffer[2]) {//bDescriptorSubtypecase 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格式、间隔,并分配内存

/* 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格式个数

第二次解析描述符

/* 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;

default:break;}

buflen -= buffer[0];buffer += buffer[0];//指向下一个描述符}if (buflen)uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface %d has %u bytes of trailing descriptor garbage.\n",dev->udev->devnum, alts->desc.bInterfaceNumber, buflen);/* Parse the alternate settings to find the maximum bandwidth. 解析设置并查找最大带宽*/for (i = 0; i < intf->num_altsetting; ++i) {struct usb_host_endpoint *ep;//声明usb_host_endpoint 指针alts = &intf->altsetting[i];//获取usb_host_interface数组ep = uvc_find_endpoint(alts,streaming->header.bEndpointAddress);//查找对应usb_host_endpoint if (ep == NULL)continue;psize = le16_to_cpu(ep->desc.wMaxPacketSize);//获取最大包尺寸psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));//换算if (psize > streaming->maxpsize)streaming->maxpsize = psize;//设置uvc视频流最大包尺寸对象}list_add_tail(&streaming->list, &dev->streams);//添加到uvc设备视频流链表return 0;error:usb_driver_release_interface(&uvc_driver.driver, intf);usb_put_intf(intf);kfree(streaming->format);kfree(streaming->header.bmaControls);kfree(streaming);return ret;}
6.3 添加uvc视频流到uvc设备视频流链表
list_add_tail(&streaming->list, &dev->streams);







原创粉丝点击